diff --git a/cmd/ateapi/internal/store/atepg/atepg.go b/cmd/ateapi/internal/store/atepg/atepg.go
new file mode 100644
index 000000000..28497c837
--- /dev/null
+++ b/cmd/ateapi/internal/store/atepg/atepg.go
@@ -0,0 +1,928 @@
+// Copyright 2026 Google LLC
+//
+// 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 atepg is an ate storage backend built on PostgreSQL.
+//
+// Each table holds native SQL columns for fields SQL must operate on
+// (primary keys, versions, timestamps, pagination, update/delete
+// preconditions) plus the complete protobuf message, binary-encoded, in a
+// BYTEA column. TLS is configured entirely through the connection string
+// passed to Connect (standard libpq sslmode/sslrootcert/sslcert/sslkey
+// parameters); no bespoke TLS plumbing is needed.
+package atepg
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"log/slog"
+	"time"
+
+	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store"
+	"github.com/agent-substrate/substrate/internal/resources"
+	"github.com/agent-substrate/substrate/pkg/proto/ateapipb"
+	"github.com/google/uuid"
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+	"github.com/jackc/pgx/v5/pgxpool"
+	"google.golang.org/protobuf/encoding/protojson"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/types/known/timestamppb"
+)
+
+// Persistence is a service that stores ate state in PostgreSQL.
+type Persistence struct {
+	pool    *pgxpool.Pool
+	lockTTL time.Duration
+}
+
+var _ store.Interface = (*Persistence)(nil)
+
+// Connect opens a pgxpool against dsn, verifies connectivity, and applies the
+// embedded schema. Startup fails if the database cannot be reached.
+func Connect(ctx context.Context, dsn string) (*Persistence, error) {
+	pool, err := pgxpool.New(ctx, dsn)
+	if err != nil {
+		return nil, fmt.Errorf("opening PostgreSQL pool: %w", err)
+	}
+	if err := pool.Ping(ctx); err != nil {
+		pool.Close()
+		return nil, fmt.Errorf("pinging PostgreSQL: %w", err)
+	}
+	p, err := NewPersistence(ctx, pool)
+	if err != nil {
+		pool.Close()
+		return nil, err
+	}
+	return p, nil
+}
+
+// NewPersistence wraps an already-open pool, applying the idempotent schema.
+// Callers that already hold a pool (e.g. tests using
+// testcontainers) use this directly instead of Connect.
+func NewPersistence(ctx context.Context, pool *pgxpool.Pool) (*Persistence, error) {
+	if err := applySchema(ctx, pool); err != nil {
+		return nil, err
+	}
+	return &Persistence{pool: pool, lockTTL: defaultLockTTL}, nil
+}
+
+// querier is satisfied by both *pgxpool.Pool and pgx.Tx, letting read helpers
+// run either directly against the pool or inside an in-flight transaction.
+type querier interface {
+	QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
+	Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
+	Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
+}
+
+func newCreateMetadata(atespace, name string) *ateapipb.ResourceMetadata {
+	now := timestamppb.Now()
+	return &ateapipb.ResourceMetadata{
+		Atespace:   atespace,
+		Name:       name,
+		Uid:        uuid.NewString(),
+		Version:    1,
+		CreateTime: now,
+		UpdateTime: now,
+	}
+}
+
+func newUpdateMetadata(current *ateapipb.ResourceMetadata) *ateapipb.ResourceMetadata {
+	metadata := proto.Clone(current).(*ateapipb.ResourceMetadata)
+	metadata.Version++
+	metadata.UpdateTime = timestamppb.Now()
+	return metadata
+}
+
+func isUniqueViolation(err error) bool { return pgErrCode(err) == "23505" }
+
+// isForeignKeyViolation matches both the insert/update-side violation
+// (23503, foreign_key_violation) and the delete-side violation PostgreSQL 18
+// split out into its own code (23001, restrict_violation, for ON DELETE
+// RESTRICT); older PostgreSQL versions report 23503 for both cases.
+func isForeignKeyViolation(err error) bool {
+	switch pgErrCode(err) {
+	case "23503", "23001":
+		return true
+	default:
+		return false
+	}
+}
+
+func pgErrCode(err error) string {
+	var pgErr *pgconn.PgError
+	if errors.As(err, &pgErr) {
+		return pgErr.Code
+	}
+	return ""
+}
+
+// --- Atespaces ---
+
+func (p *Persistence) CreateAtespace(ctx context.Context, atespace *ateapipb.Atespace) (*ateapipb.Atespace, error) {
+	name := atespace.GetMetadata().GetName()
+
+	dbAtespace := proto.Clone(atespace).(*ateapipb.Atespace)
+	dbAtespace.Metadata = newCreateMetadata("", name)
+
+	protoBytes, err := proto.Marshal(dbAtespace)
+	if err != nil {
+		return nil, fmt.Errorf("marshaling atespace: %w", err)
+	}
+
+	meta := dbAtespace.GetMetadata()
+	_, err = p.pool.Exec(ctx, `
+		INSERT INTO atespaces (name, uid, version, create_time, update_time, proto)
+		VALUES ($1, $2, $3, $4, $5, $6)`,
+		name, meta.GetUid(), meta.GetVersion(), meta.GetCreateTime().AsTime(), meta.GetUpdateTime().AsTime(), protoBytes)
+	if err != nil {
+		if isUniqueViolation(err) {
+			return nil, store.ErrAlreadyExists
+		}
+		return nil, fmt.Errorf("inserting atespace %q: %w", name, err)
+	}
+	return dbAtespace, nil
+}
+
+func getAtespaceRow(ctx context.Context, q querier, name string) (*ateapipb.Atespace, error) {
+	var protoBytes []byte
+	err := q.QueryRow(ctx, `SELECT proto FROM atespaces WHERE name = $1`, name).Scan(&protoBytes)
+	if err != nil {
+		if errors.Is(err, pgx.ErrNoRows) {
+			return nil, store.ErrNotFound
+		}
+		return nil, fmt.Errorf("getting atespace %q: %w", name, err)
+	}
+	out := &ateapipb.Atespace{}
+	if err := proto.Unmarshal(protoBytes, out); err != nil {
+		return nil, fmt.Errorf("unmarshaling atespace: %w", err)
+	}
+	return out, nil
+}
+
+func (p *Persistence) GetAtespace(ctx context.Context, name string) (*ateapipb.Atespace, error) {
+	return getAtespaceRow(ctx, p.pool, name)
+}
+
+func (p *Persistence) AtespaceExists(ctx context.Context, name string) (bool, error) {
+	var exists bool
+	if err := p.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM atespaces WHERE name = $1)`, name).Scan(&exists); err != nil {
+		return false, fmt.Errorf("checking atespace existence: %w", err)
+	}
+	return exists, nil
+}
+
+func (p *Persistence) ListAtespaces(ctx context.Context, pageSize int32, pageTokenStr string) ([]*ateapipb.Atespace, string, error) {
+	token, err := decodePageToken(pageTokenStr, kindAtespace, "", 1)
+	if err != nil {
+		return nil, "", err
+	}
+	var last *string
+	if len(token.Last) > 0 {
+		last = &token.Last[0]
+	}
+
+	rows, err := p.pool.Query(ctx, `
+		SELECT name, proto FROM atespaces
+		WHERE $1::text IS NULL OR name > $1
+		ORDER BY name
+		LIMIT $2`, last, int64(pageSize)+1)
+	if err != nil {
+		return nil, "", fmt.Errorf("listing atespaces: %w", err)
+	}
+	defer rows.Close()
+
+	var names []string
+	var result []*ateapipb.Atespace
+	for rows.Next() {
+		var name string
+		var protoBytes []byte
+		if err := rows.Scan(&name, &protoBytes); err != nil {
+			return nil, "", fmt.Errorf("scanning atespace row: %w", err)
+		}
+		a := &ateapipb.Atespace{}
+		if err := proto.Unmarshal(protoBytes, a); err != nil {
+			return nil, "", fmt.Errorf("unmarshaling atespace: %w", err)
+		}
+		result = append(result, a)
+		names = append(names, name)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, "", fmt.Errorf("listing atespaces: %w", err)
+	}
+
+	var nextToken string
+	if len(result) > int(pageSize) {
+		result = result[:pageSize]
+		nextToken = encodePageToken(kindAtespace, "", []string{names[pageSize-1]})
+	}
+	return result, nextToken, nil
+}
+
+func (p *Persistence) DeleteAtespace(ctx context.Context, name string) (*ateapipb.Atespace, error) {
+	var protoBytes []byte
+	err := p.pool.QueryRow(ctx, `DELETE FROM atespaces WHERE name = $1 RETURNING proto`, name).Scan(&protoBytes)
+	if err != nil {
+		if isForeignKeyViolation(err) {
+			return nil, store.ErrFailedPrecondition
+		}
+		if errors.Is(err, pgx.ErrNoRows) {
+			return nil, store.ErrNotFound
+		}
+		return nil, fmt.Errorf("deleting atespace %q: %w", name, err)
+	}
+	out := &ateapipb.Atespace{}
+	if err := proto.Unmarshal(protoBytes, out); err != nil {
+		return nil, fmt.Errorf("unmarshaling deleted atespace: %w", err)
+	}
+	return out, nil
+}
+
+// --- Actors ---
+
+func (p *Persistence) CreateActor(ctx context.Context, actor *ateapipb.Actor) (*ateapipb.Actor, error) {
+	atespace := actor.GetMetadata().GetAtespace()
+	name := actor.GetMetadata().GetName()
+
+	dbActor := proto.Clone(actor).(*ateapipb.Actor)
+	dbActor.Metadata = newCreateMetadata(atespace, name)
+
+	protoBytes, err := proto.Marshal(dbActor)
+	if err != nil {
+		return nil, fmt.Errorf("marshaling actor: %w", err)
+	}
+
+	meta := dbActor.GetMetadata()
+	_, err = p.pool.Exec(ctx, `
+		INSERT INTO actors (atespace, name, uid, version, status, actor_template_namespace, actor_template_name, create_time, update_time, proto)
+		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
+		atespace, name, meta.GetUid(), meta.GetVersion(), int32(dbActor.GetStatus()),
+		dbActor.GetActorTemplateNamespace(), dbActor.GetActorTemplateName(),
+		meta.GetCreateTime().AsTime(), meta.GetUpdateTime().AsTime(), protoBytes)
+	if err != nil {
+		if isUniqueViolation(err) {
+			return nil, store.ErrAlreadyExists
+		}
+		if isForeignKeyViolation(err) {
+			// The atespace referenced by this actor doesn't exist (or was
+			// deleted concurrently with the control API's own pre-check).
+			return nil, store.ErrFailedPrecondition
+		}
+		return nil, fmt.Errorf("inserting actor %s/%s: %w", atespace, name, err)
+	}
+	return dbActor, nil
+}
+
+func getActorRow(ctx context.Context, q querier, atespace, name string) (*ateapipb.Actor, error) {
+	var protoBytes []byte
+	err := q.QueryRow(ctx, `SELECT proto FROM actors WHERE atespace = $1 AND name = $2`, atespace, name).Scan(&protoBytes)
+	if err != nil {
+		if errors.Is(err, pgx.ErrNoRows) {
+			return nil, store.ErrNotFound
+		}
+		return nil, fmt.Errorf("getting actor %s/%s: %w", atespace, name, err)
+	}
+	out := &ateapipb.Actor{}
+	if err := proto.Unmarshal(protoBytes, out); err != nil {
+		return nil, fmt.Errorf("unmarshaling actor: %w", err)
+	}
+	return out, nil
+}
+
+func (p *Persistence) GetActor(ctx context.Context, actorRef resources.ActorRef) (*ateapipb.Actor, error) {
+	return getActorRow(ctx, p.pool, actorRef.Atespace, actorRef.Name)
+}
+
+func (p *Persistence) UpdateActor(ctx context.Context, actor *ateapipb.Actor, expectedVersion int64) (*ateapipb.Actor, error) {
+	atespace := actor.GetMetadata().GetAtespace()
+	name := actor.GetMetadata().GetName()
+
+	tx, err := p.pool.Begin(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("beginning actor update: %w", err)
+	}
+	defer tx.Rollback(ctx) //nolint:errcheck // no-op once committed
+
+	current, err := getActorRow(ctx, tx, atespace, name)
+	if err != nil {
+		return nil, err
+	}
+	if current.GetMetadata().GetVersion() != expectedVersion {
+		return nil, store.ErrVersionConflict
+	}
+	if current.GetActorTemplateNamespace() != actor.GetActorTemplateNamespace() {
+		return nil, fmt.Errorf("actor_template_namespace is immutable")
+	}
+	if current.GetActorTemplateName() != actor.GetActorTemplateName() {
+		return nil, fmt.Errorf("actor_template_name is immutable")
+	}
+
+	dbActor := proto.Clone(actor).(*ateapipb.Actor)
+	// UID, identity, create time, and current version are server-owned. Derive
+	// the new metadata from the stored resource rather than trusting fields
+	// supplied by the caller.
+	dbActor.Metadata = newUpdateMetadata(current.GetMetadata())
+
+	protoBytes, err := proto.Marshal(dbActor)
+	if err != nil {
+		return nil, fmt.Errorf("marshaling actor: %w", err)
+	}
+
+	var returnedProto []byte
+	err = tx.QueryRow(ctx, `
+		UPDATE actors
+		SET version = $1, status = $2, update_time = $3, proto = $4
+		WHERE atespace = $5 AND name = $6 AND version = $7
+		RETURNING proto`,
+		dbActor.GetMetadata().GetVersion(), int32(dbActor.GetStatus()), dbActor.GetMetadata().GetUpdateTime().AsTime(), protoBytes,
+		atespace, name, expectedVersion,
+	).Scan(&returnedProto)
+	if err != nil && !errors.Is(err, pgx.ErrNoRows) {
+		return nil, fmt.Errorf("updating actor %s/%s: %w", atespace, name, err)
+	}
+	if errors.Is(err, pgx.ErrNoRows) {
+		// A concurrent update or delete won after the point read.
+		if _, getErr := getActorRow(ctx, tx, atespace, name); getErr != nil {
+			return nil, getErr
+		}
+		return nil, store.ErrVersionConflict
+	}
+
+	if err := tx.Commit(ctx); err != nil {
+		return nil, fmt.Errorf("committing actor update: %w", err)
+	}
+	return dbActor, nil
+}
+
+func (p *Persistence) DeleteActor(ctx context.Context, actorRef resources.ActorRef) (*ateapipb.Actor, error) {
+	atespace, name := actorRef.Atespace, actorRef.Name
+	var protoBytes []byte
+	err := p.pool.QueryRow(ctx, `
+		DELETE FROM actors
+		WHERE atespace = $1 AND name = $2 AND status IN ($3, $4)
+		RETURNING proto`,
+		atespace, name, int32(ateapipb.Actor_STATUS_SUSPENDED), int32(ateapipb.Actor_STATUS_CRASHED),
+	).Scan(&protoBytes)
+	if err == nil {
+		out := &ateapipb.Actor{}
+		if err := proto.Unmarshal(protoBytes, out); err != nil {
+			return nil, fmt.Errorf("unmarshaling deleted actor: %w", err)
+		}
+		return out, nil
+	}
+	if !errors.Is(err, pgx.ErrNoRows) {
+		return nil, fmt.Errorf("deleting actor %s/%s: %w", atespace, name, err)
+	}
+
+	// No row matched; distinguish missing from a status that forbids deletion.
+	if _, getErr := getActorRow(ctx, p.pool, atespace, name); getErr != nil {
+		return nil, getErr
+	}
+	return nil, store.ErrFailedPrecondition
+}
+
+func (p *Persistence) ListActors(ctx context.Context, atespace string, pageSize int32, pageTokenStr string) ([]*ateapipb.Actor, string, error) {
+	if atespace != "" {
+		return p.listActorsScoped(ctx, atespace, pageSize, pageTokenStr)
+	}
+	return p.listActorsGlobal(ctx, pageSize, pageTokenStr)
+}
+
+func (p *Persistence) listActorsScoped(ctx context.Context, atespace string, pageSize int32, pageTokenStr string) ([]*ateapipb.Actor, string, error) {
+	token, err := decodePageToken(pageTokenStr, kindActor, atespace, 1)
+	if err != nil {
+		return nil, "", err
+	}
+	var last *string
+	if len(token.Last) > 0 {
+		last = &token.Last[0]
+	}
+
+	rows, err := p.pool.Query(ctx, `
+		SELECT name, proto FROM actors
+		WHERE atespace = $1 AND ($2::text IS NULL OR name > $2)
+		ORDER BY name
+		LIMIT $3`, atespace, last, int64(pageSize)+1)
+	if err != nil {
+		return nil, "", fmt.Errorf("listing actors in %q: %w", atespace, err)
+	}
+	defer rows.Close()
+
+	var names []string
+	var result []*ateapipb.Actor
+	for rows.Next() {
+		var name string
+		var protoBytes []byte
+		if err := rows.Scan(&name, &protoBytes); err != nil {
+			return nil, "", fmt.Errorf("scanning actor row: %w", err)
+		}
+		a := &ateapipb.Actor{}
+		if err := proto.Unmarshal(protoBytes, a); err != nil {
+			return nil, "", fmt.Errorf("unmarshaling actor: %w", err)
+		}
+		result = append(result, a)
+		names = append(names, name)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, "", fmt.Errorf("listing actors in %q: %w", atespace, err)
+	}
+
+	var nextToken string
+	if len(result) > int(pageSize) {
+		result = result[:pageSize]
+		nextToken = encodePageToken(kindActor, atespace, []string{names[pageSize-1]})
+	}
+	return result, nextToken, nil
+}
+
+func (p *Persistence) listActorsGlobal(ctx context.Context, pageSize int32, pageTokenStr string) ([]*ateapipb.Actor, string, error) {
+	token, err := decodePageToken(pageTokenStr, kindActor, "", 2)
+	if err != nil {
+		return nil, "", err
+	}
+	var lastAtespace, lastName *string
+	if len(token.Last) == 2 {
+		lastAtespace, lastName = &token.Last[0], &token.Last[1]
+	}
+
+	rows, err := p.pool.Query(ctx, `
+		SELECT atespace, name, proto FROM actors
+		WHERE $1::text IS NULL OR (atespace, name) > ($1, $2)
+		ORDER BY atespace, name
+		LIMIT $3`, lastAtespace, lastName, int64(pageSize)+1)
+	if err != nil {
+		return nil, "", fmt.Errorf("listing actors: %w", err)
+	}
+	defer rows.Close()
+
+	type key struct{ atespace, name string }
+	var keys []key
+	var result []*ateapipb.Actor
+	for rows.Next() {
+		var k key
+		var protoBytes []byte
+		if err := rows.Scan(&k.atespace, &k.name, &protoBytes); err != nil {
+			return nil, "", fmt.Errorf("scanning actor row: %w", err)
+		}
+		a := &ateapipb.Actor{}
+		if err := proto.Unmarshal(protoBytes, a); err != nil {
+			return nil, "", fmt.Errorf("unmarshaling actor: %w", err)
+		}
+		result = append(result, a)
+		keys = append(keys, k)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, "", fmt.Errorf("listing actors: %w", err)
+	}
+
+	var nextToken string
+	if len(result) > int(pageSize) {
+		result = result[:pageSize]
+		last := keys[pageSize-1]
+		nextToken = encodePageToken(kindActor, "", []string{last.atespace, last.name})
+	}
+	return result, nextToken, nil
+}
+
+// --- Workers ---
+
+const (
+	// workerChangeChannel is the fixed LISTEN/NOTIFY channel for worker changes.
+	workerChangeChannel = "worker_changes"
+	// maxNotifyPayloadBytes reflects PostgreSQL's NOTIFY payload size limit.
+	// Writes fail rather than silently omit a notification if exceeded.
+	maxNotifyPayloadBytes = 8000
+)
+
+type workerEventEnvelope struct {
+	Type   int    `json:"t"`
+	Worker string `json:"w"` // protojson-encoded Worker
+}
+
+func marshalWorkerEvent(eventType store.WorkerEventType, worker *ateapipb.Worker) ([]byte, error) {
+	workerJSON, err := protojson.Marshal(worker)
+	if err != nil {
+		return nil, fmt.Errorf("in protojson.Marshal: %w", err)
+	}
+	msg, err := json.Marshal(workerEventEnvelope{Type: int(eventType), Worker: string(workerJSON)})
+	if err != nil {
+		return nil, fmt.Errorf("in json.Marshal: %w", err)
+	}
+	return msg, nil
+}
+
+func unmarshalWorkerEvent(payload string) (store.WorkerEvent, error) {
+	var env workerEventEnvelope
+	if err := json.Unmarshal([]byte(payload), &env); err != nil {
+		return store.WorkerEvent{}, fmt.Errorf("in json.Unmarshal: %w", err)
+	}
+	worker := &ateapipb.Worker{}
+	if err := protojson.Unmarshal([]byte(env.Worker), worker); err != nil {
+		return store.WorkerEvent{}, fmt.Errorf("in protojson.Unmarshal: %w", err)
+	}
+	return store.WorkerEvent{Type: store.WorkerEventType(env.Type), Worker: worker}, nil
+}
+
+// writeAndNotify runs fn inside a transaction, then--only if fn reports a
+// change worth notifying--calls pg_notify in the same transaction so
+// delivery happens if and only if the transaction commits.
+func (p *Persistence) writeAndNotify(ctx context.Context, eventType store.WorkerEventType, worker *ateapipb.Worker, fn func(ctx context.Context, tx pgx.Tx) (notify bool, err error)) error {
+	tx, err := p.pool.Begin(ctx)
+	if err != nil {
+		return fmt.Errorf("beginning transaction: %w", err)
+	}
+	defer tx.Rollback(ctx) //nolint:errcheck // no-op once committed
+
+	notify, err := fn(ctx, tx)
+	if err != nil {
+		return err
+	}
+
+	if notify {
+		payload, err := marshalWorkerEvent(eventType, worker)
+		if err != nil {
+			return fmt.Errorf("marshaling worker event: %w", err)
+		}
+		if len(payload) > maxNotifyPayloadBytes {
+			return fmt.Errorf("worker event payload of %d bytes exceeds PostgreSQL NOTIFY limit of %d bytes", len(payload), maxNotifyPayloadBytes)
+		}
+		if _, err := tx.Exec(ctx, `SELECT pg_notify($1, $2)`, workerChangeChannel, string(payload)); err != nil {
+			return fmt.Errorf("notifying worker change: %w", err)
+		}
+	}
+
+	if err := tx.Commit(ctx); err != nil {
+		return fmt.Errorf("committing transaction: %w", err)
+	}
+	return nil
+}
+
+func (p *Persistence) CreateWorker(ctx context.Context, worker *ateapipb.Worker) error {
+	dbWorker := proto.Clone(worker).(*ateapipb.Worker)
+	dbWorker.Version = 1
+
+	protoBytes, err := proto.Marshal(dbWorker)
+	if err != nil {
+		return fmt.Errorf("marshaling worker: %w", err)
+	}
+
+	err = p.writeAndNotify(ctx, store.WorkerEventCreated, dbWorker, func(ctx context.Context, tx pgx.Tx) (bool, error) {
+		_, err := tx.Exec(ctx, `
+			INSERT INTO workers (worker_namespace, worker_pool, worker_pod, ip, version, proto)
+			VALUES ($1, $2, $3, $4, $5, $6)`,
+			dbWorker.GetWorkerNamespace(), dbWorker.GetWorkerPool(), dbWorker.GetWorkerPod(), dbWorker.GetIp(), dbWorker.GetVersion(), protoBytes)
+		if err != nil {
+			return false, err
+		}
+		return true, nil
+	})
+	if err != nil {
+		if isUniqueViolation(err) {
+			return store.ErrAlreadyExists
+		}
+		return fmt.Errorf("creating worker: %w", err)
+	}
+	return nil
+}
+
+func getWorkerRow(ctx context.Context, q querier, namespace, poolName, pod string) (*ateapipb.Worker, error) {
+	var protoBytes []byte
+	err := q.QueryRow(ctx, `SELECT proto FROM workers WHERE worker_namespace = $1 AND worker_pool = $2 AND worker_pod = $3`,
+		namespace, poolName, pod).Scan(&protoBytes)
+	if err != nil {
+		if errors.Is(err, pgx.ErrNoRows) {
+			return nil, store.ErrNotFound
+		}
+		return nil, fmt.Errorf("getting worker %s/%s/%s: %w", namespace, poolName, pod, err)
+	}
+	out := &ateapipb.Worker{}
+	if err := proto.Unmarshal(protoBytes, out); err != nil {
+		return nil, fmt.Errorf("unmarshaling worker: %w", err)
+	}
+	return out, nil
+}
+
+func (p *Persistence) GetWorker(ctx context.Context, namespace, poolName, pod string) (*ateapipb.Worker, error) {
+	return getWorkerRow(ctx, p.pool, namespace, poolName, pod)
+}
+
+func (p *Persistence) UpdateWorker(ctx context.Context, worker *ateapipb.Worker, expectedVersion int64) error {
+	namespace, poolName, pod := worker.GetWorkerNamespace(), worker.GetWorkerPool(), worker.GetWorkerPod()
+
+	dbWorker := proto.Clone(worker).(*ateapipb.Worker)
+	dbWorker.Version = expectedVersion + 1
+
+	protoBytes, err := proto.Marshal(dbWorker)
+	if err != nil {
+		return fmt.Errorf("marshaling worker: %w", err)
+	}
+
+	return p.writeAndNotify(ctx, store.WorkerEventUpdated, dbWorker, func(ctx context.Context, tx pgx.Tx) (bool, error) {
+		var returned []byte
+		err := tx.QueryRow(ctx, `
+			UPDATE workers
+			SET version = $1, proto = $2
+			WHERE worker_namespace = $3 AND worker_pool = $4 AND worker_pod = $5
+			  AND version = $6 AND ip = $7
+			RETURNING proto`,
+			dbWorker.GetVersion(), protoBytes, namespace, poolName, pod, expectedVersion, dbWorker.GetIp(),
+		).Scan(&returned)
+		if err == nil {
+			return true, nil
+		}
+		if !errors.Is(err, pgx.ErrNoRows) {
+			return false, fmt.Errorf("updating worker %s/%s/%s: %w", namespace, poolName, pod, err)
+		}
+
+		current, getErr := getWorkerRow(ctx, tx, namespace, poolName, pod)
+		if getErr != nil {
+			return false, getErr
+		}
+		if current.GetVersion() != expectedVersion {
+			return false, store.ErrVersionConflict
+		}
+		if current.GetIp() != dbWorker.GetIp() {
+			return false, fmt.Errorf("ip is immutable")
+		}
+		return false, fmt.Errorf("update worker %s/%s/%s: no row matched but current state is otherwise consistent", namespace, poolName, pod)
+	})
+}
+
+func (p *Persistence) DeleteWorker(ctx context.Context, namespace, poolName, pod string) error {
+	deletedEvent := &ateapipb.Worker{WorkerNamespace: namespace, WorkerPod: pod}
+	return p.writeAndNotify(ctx, store.WorkerEventDeleted, deletedEvent, func(ctx context.Context, tx pgx.Tx) (bool, error) {
+		var protoBytes []byte
+		err := tx.QueryRow(ctx, `
+			DELETE FROM workers
+			WHERE worker_namespace = $1 AND worker_pool = $2 AND worker_pod = $3
+			RETURNING proto`, namespace, poolName, pod).Scan(&protoBytes)
+		if err != nil {
+			if errors.Is(err, pgx.ErrNoRows) {
+				// Idempotent: nothing existed, so nothing to notify either.
+				return false, nil
+			}
+			return false, fmt.Errorf("deleting worker %s/%s/%s: %w", namespace, poolName, pod, err)
+		}
+		return true, nil
+	})
+}
+
+func (p *Persistence) ListWorkers(ctx context.Context, pageSize int32, pageTokenStr string) ([]*ateapipb.Worker, string, error) {
+	token, err := decodePageToken(pageTokenStr, kindWorker, "", 3)
+	if err != nil {
+		return nil, "", err
+	}
+	var lastNS, lastPool, lastPod *string
+	if len(token.Last) == 3 {
+		lastNS, lastPool, lastPod = &token.Last[0], &token.Last[1], &token.Last[2]
+	}
+
+	rows, err := p.pool.Query(ctx, `
+		SELECT worker_namespace, worker_pool, worker_pod, proto FROM workers
+		WHERE $1::text IS NULL OR (worker_namespace, worker_pool, worker_pod) > ($1, $2, $3)
+		ORDER BY worker_namespace, worker_pool, worker_pod
+		LIMIT $4`, lastNS, lastPool, lastPod, int64(pageSize)+1)
+	if err != nil {
+		return nil, "", fmt.Errorf("listing workers: %w", err)
+	}
+	defer rows.Close()
+
+	type key struct{ namespace, pool, pod string }
+	var keys []key
+	var result []*ateapipb.Worker
+	for rows.Next() {
+		var k key
+		var protoBytes []byte
+		if err := rows.Scan(&k.namespace, &k.pool, &k.pod, &protoBytes); err != nil {
+			return nil, "", fmt.Errorf("scanning worker row: %w", err)
+		}
+		w := &ateapipb.Worker{}
+		if err := proto.Unmarshal(protoBytes, w); err != nil {
+			return nil, "", fmt.Errorf("unmarshaling worker: %w", err)
+		}
+		result = append(result, w)
+		keys = append(keys, k)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, "", fmt.Errorf("listing workers: %w", err)
+	}
+
+	var nextToken string
+	if len(result) > int(pageSize) {
+		result = result[:pageSize]
+		last := keys[pageSize-1]
+		nextToken = encodePageToken(kindWorker, "", []string{last.namespace, last.pool, last.pod})
+	}
+	return result, nextToken, nil
+}
+
+// WatchWorkers acquires a dedicated connection (hijacked out of the pool, so
+// it's never handed back for unrelated queries), LISTENs on the fixed
+// worker-change channel, and forwards decoded notifications until the
+// context is cancelled or the caller closes the watch.
+func (p *Persistence) WatchWorkers(ctx context.Context) (*store.WorkerWatch, error) {
+	watchCtx, cancel := context.WithCancel(ctx)
+
+	poolConn, err := p.pool.Acquire(watchCtx)
+	if err != nil {
+		cancel()
+		return nil, fmt.Errorf("acquiring watch connection: %w", err)
+	}
+	conn := poolConn.Hijack()
+
+	if _, err := conn.Exec(watchCtx, "LISTEN "+workerChangeChannel); err != nil {
+		conn.Close(watchCtx) //nolint:errcheck
+		cancel()
+		return nil, fmt.Errorf("listening for worker changes: %w", err)
+	}
+
+	ch := make(chan store.WorkerEvent, 128)
+	go func() {
+		defer close(ch)
+		defer conn.Close(context.Background()) //nolint:errcheck
+		for {
+			notification, err := conn.WaitForNotification(watchCtx)
+			if err != nil {
+				// Context cancelled (caller closed the watch) or the
+				// connection was lost. Either way, the caller must
+				// re-subscribe; matches ateredis's WatchWorkers contract.
+				return
+			}
+			event, err := unmarshalWorkerEvent(notification.Payload)
+			if err != nil {
+				slog.ErrorContext(ctx, "worker event unmarshal failed", slog.Any("err", err))
+				continue
+			}
+			select {
+			case ch <- event:
+			case <-watchCtx.Done():
+				return
+			}
+		}
+	}()
+	return store.NewWorkerWatch(ch, cancel), nil
+}
+
+// --- Workflow locks ---
+
+// defaultLockTTL is how long a lock may go unrenewed before another client
+// can reclaim it.
+const defaultLockTTL = 30 * time.Second
+
+func (p *Persistence) AcquireLock(ctx context.Context, key string) (*store.Lock, error) {
+	ttl := p.lockTTL
+	token := uuid.NewString()
+
+	acquired, err := p.acquireLease(ctx, key, token, ttl)
+	if err != nil {
+		return nil, err
+	}
+	if !acquired {
+		return nil, store.ErrLockConflict
+	}
+
+	leaseCtx, cancel := context.WithCancel(ctx)
+	renewalDone := make(chan struct{})
+	go func() {
+		defer close(renewalDone)
+		defer cancel()
+		p.renewLockLoop(leaseCtx, key, token, ttl)
+	}()
+
+	closeFn := func() {
+		cancel()
+		<-renewalDone
+
+		releaseCtx, releaseCancel := context.WithTimeout(context.Background(), 5*time.Second)
+		defer releaseCancel()
+		if err := p.releaseLease(releaseCtx, key, token); err != nil {
+			slog.WarnContext(releaseCtx, "failed to release PostgreSQL lock, relying on TTL to reclaim it", "key", key, "error", err)
+		}
+	}
+	return store.NewLock(leaseCtx, closeFn), nil
+}
+
+func (p *Persistence) acquireLease(ctx context.Context, key, token string, ttl time.Duration) (bool, error) {
+	var returnedKey string
+	err := p.pool.QueryRow(ctx, `
+		INSERT INTO leases (key, token, expires_at)
+		VALUES ($1, $2, clock_timestamp() + make_interval(secs => $3))
+		ON CONFLICT (key) DO UPDATE
+		SET token = EXCLUDED.token,
+		    expires_at = EXCLUDED.expires_at
+		WHERE leases.expires_at <= clock_timestamp()
+		RETURNING key`, key, token, ttl.Seconds()).Scan(&returnedKey)
+	if err != nil {
+		if errors.Is(err, pgx.ErrNoRows) {
+			return false, nil
+		}
+		return false, fmt.Errorf("acquiring lock for %q: %w", key, err)
+	}
+	return true, nil
+}
+
+const (
+	renewIntervalDivisor    = 3
+	renewRetryPeriodDivisor = 10
+	renewDeadlineFraction   = 2.0 / 3.0
+)
+
+func (p *Persistence) renewLockLoop(ctx context.Context, key, token string, ttl time.Duration) {
+	interval := ttl / renewIntervalDivisor
+	renewDeadline := time.Duration(float64(ttl) * renewDeadlineFraction)
+
+	lastRenewed := time.Now()
+	timer := time.NewTimer(interval)
+	defer timer.Stop()
+
+	for {
+		select {
+		case <-ctx.Done():
+			return
+		case <-timer.C:
+			renewCtx, cancel := context.WithDeadline(ctx, lastRenewed.Add(renewDeadline))
+			renewed := p.tryRenewLease(renewCtx, key, token, ttl)
+			cancel()
+			if !renewed {
+				return
+			}
+			lastRenewed = time.Now()
+			timer.Reset(interval)
+		}
+	}
+}
+
+func (p *Persistence) tryRenewLease(ctx context.Context, key, token string, ttl time.Duration) bool {
+	retryPeriod := ttl / renewRetryPeriodDivisor
+	retry := time.NewTimer(0)
+	defer retry.Stop()
+
+	for {
+		select {
+		case <-ctx.Done():
+			if errors.Is(ctx.Err(), context.DeadlineExceeded) {
+				slog.WarnContext(ctx, "failed to renew PostgreSQL lock before its deadline", "key", key)
+			}
+			return false
+		case <-retry.C:
+			renewed, err := p.renewLease(ctx, key, token, ttl)
+			if ctx.Err() != nil {
+				return false
+			}
+			switch {
+			case err == nil && renewed:
+				return true
+			case err == nil:
+				slog.WarnContext(ctx, "PostgreSQL lock renewal found lease no longer owned", "key", key)
+				return false
+			default:
+				slog.WarnContext(ctx, "failed to renew PostgreSQL lock, retrying", "key", key, "error", err)
+				retry.Reset(retryPeriod)
+			}
+		}
+	}
+}
+
+func (p *Persistence) renewLease(ctx context.Context, key, token string, ttl time.Duration) (bool, error) {
+	var returnedKey string
+	err := p.pool.QueryRow(ctx, `
+		UPDATE leases
+		SET expires_at = clock_timestamp() + make_interval(secs => $3)
+		WHERE key = $1 AND token = $2 AND expires_at > clock_timestamp()
+		RETURNING key`, key, token, ttl.Seconds()).Scan(&returnedKey)
+	if err != nil {
+		if errors.Is(err, pgx.ErrNoRows) {
+			return false, nil
+		}
+		return false, fmt.Errorf("renewing lock for %q: %w", key, err)
+	}
+	return true, nil
+}
+
+func (p *Persistence) releaseLease(ctx context.Context, key, token string) error {
+	if _, err := p.pool.Exec(ctx, `DELETE FROM leases WHERE key = $1 AND token = $2`, key, token); err != nil {
+		return fmt.Errorf("releasing lock for %q: %w", key, err)
+	}
+	return nil
+}
+
+// --- Debug ---
+
+func (p *Persistence) DebugClearAll(ctx context.Context) error {
+	if _, err := p.pool.Exec(ctx, `TRUNCATE atespaces, actors, workers, leases`); err != nil {
+		return fmt.Errorf("truncating tables: %w", err)
+	}
+	return nil
+}
diff --git a/cmd/ateapi/internal/store/atepg/atepg_test.go b/cmd/ateapi/internal/store/atepg/atepg_test.go
new file mode 100644
index 000000000..f234d983e
--- /dev/null
+++ b/cmd/ateapi/internal/store/atepg/atepg_test.go
@@ -0,0 +1,349 @@
+// Copyright 2026 Google LLC
+//
+// 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 atepg
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"os"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/jackc/pgx/v5/pgxpool"
+	"github.com/testcontainers/testcontainers-go/modules/postgres"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/testing/protocmp"
+
+	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store"
+	"github.com/agent-substrate/substrate/pkg/proto/ateapipb"
+)
+
+// One Postgres container serves every test in this package; each test gets
+// isolation via DebugClearAll rather than a fresh container, which would be
+// far slower. Tests in this package are not safe to run with -parallel.
+var (
+	containerOnce sync.Once
+	containerPool *pgxpool.Pool
+	containerPG   *postgres.PostgresContainer
+	containerErr  error
+)
+
+func TestMain(m *testing.M) {
+	code := m.Run()
+	if containerPool != nil {
+		containerPool.Close()
+	}
+	if containerPG != nil {
+		if err := containerPG.Terminate(context.Background()); err != nil {
+			fmt.Fprintf(os.Stderr, "terminating PostgreSQL testcontainer: %v\n", err)
+			if code == 0 {
+				code = 1
+			}
+		}
+	}
+	os.Exit(code)
+}
+
+func requirePool(t *testing.T) *pgxpool.Pool {
+	t.Helper()
+	containerOnce.Do(func() {
+		ctx := context.Background()
+		pgContainer, err := postgres.Run(ctx, "postgres:18-alpine",
+			postgres.WithDatabase("atepg"),
+			postgres.WithUsername("atepg"),
+			postgres.WithPassword("atepg"),
+		)
+		if err != nil {
+			containerErr = err
+			return
+		}
+		containerPG = pgContainer
+		dsn, err := pgContainer.ConnectionString(ctx, "sslmode=disable")
+		if err != nil {
+			containerErr = err
+			return
+		}
+		pool, err := pgxpool.New(ctx, dsn)
+		if err != nil {
+			containerErr = err
+			return
+		}
+		// The official postgres image restarts its server process once after
+		// initdb; the port accepts (and briefly resets) connections during
+		// that window, so ping with retries rather than failing on the first
+		// attempt.
+		var pingErr error
+		for i := 0; i < 30; i++ {
+			pingErr = pool.Ping(ctx)
+			if pingErr == nil {
+				break
+			}
+			time.Sleep(500 * time.Millisecond)
+		}
+		if pingErr != nil {
+			containerErr = fmt.Errorf("pinging PostgreSQL testcontainer after retries: %w", pingErr)
+			return
+		}
+		containerPool = pool
+	})
+	if containerErr != nil {
+		t.Skipf("PostgreSQL testcontainer unavailable (requires Docker): %v", containerErr)
+	}
+	return containerPool
+}
+
+func setupPostgresPersistence(t *testing.T) *Persistence {
+	t.Helper()
+	ctx := context.Background()
+	p, err := NewPersistence(ctx, requirePool(t))
+	if err != nil {
+		t.Fatalf("NewPersistence failed: %v", err)
+	}
+	if err := p.DebugClearAll(ctx); err != nil {
+		t.Fatalf("DebugClearAll failed: %v", err)
+	}
+	return p
+}
+
+func setupPostgresStore(t *testing.T) store.Interface {
+	t.Helper()
+	return setupPostgresPersistence(t)
+}
+
+func newTestAtespace(name string) *ateapipb.Atespace {
+	return &ateapipb.Atespace{Metadata: &ateapipb.ResourceMetadata{Name: name}}
+}
+
+// TestCreateActor_MissingAtespace_FailedPrecondition exercises the
+// foreign-key race the doc calls out: CreateActor rejects an actor whose
+// atespace doesn't exist (including a concurrently-deleted one), closing the
+// TOCTOU window ateredis's separate existence check leaves open.
+func TestCreateActor_MissingAtespace_FailedPrecondition(t *testing.T) {
+	s := setupPostgresStore(t).(*Persistence)
+	ctx := context.Background()
+
+	actor := &ateapipb.Actor{
+		Metadata:               &ateapipb.ResourceMetadata{Name: "id1", Atespace: "no-such-atespace"},
+		ActorTemplateNamespace: "ns1",
+		ActorTemplateName:      "tmpl1",
+		Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+	}
+	if _, err := s.CreateActor(ctx, actor); !errors.Is(err, store.ErrFailedPrecondition) {
+		t.Errorf("CreateActor with missing atespace = %v, want ErrFailedPrecondition", err)
+	}
+}
+
+// TestWorkerNotification_OnlyAfterCommit proves the doc's atomicity claim: a
+// worker write's pg_notify shares the write's transaction, so a rolled-back
+// write never notifies, while a committed write always does.
+func TestWorkerNotification_OnlyAfterCommit(t *testing.T) {
+	s := setupPostgresStore(t).(*Persistence)
+	ctx := context.Background()
+
+	watch, err := s.WatchWorkers(ctx)
+	if err != nil {
+		t.Fatalf("WatchWorkers failed: %v", err)
+	}
+	defer watch.Close()
+
+	worker := &ateapipb.Worker{WorkerNamespace: "ns", WorkerPool: "pool", WorkerPod: "pod"}
+	protoBytes, err := proto.Marshal(worker)
+	if err != nil {
+		t.Fatalf("marshaling worker: %v", err)
+	}
+
+	// Write the row and roll back instead of committing: no notification
+	// should ever arrive, proving pg_notify's effect is undone with the rest
+	// of the transaction.
+	tx, err := s.pool.Begin(ctx)
+	if err != nil {
+		t.Fatalf("Begin failed: %v", err)
+	}
+	if _, err := tx.Exec(ctx, `
+		INSERT INTO workers (worker_namespace, worker_pool, worker_pod, ip, version, proto)
+		VALUES ($1, $2, $3, $4, $5, $6)`,
+		worker.GetWorkerNamespace(), worker.GetWorkerPool(), worker.GetWorkerPod(), worker.GetIp(), int64(1), protoBytes); err != nil {
+		t.Fatalf("insert failed: %v", err)
+	}
+	if _, err := tx.Exec(ctx, `SELECT pg_notify($1, $2)`, workerChangeChannel, "rolled-back-payload"); err != nil {
+		t.Fatalf("pg_notify failed: %v", err)
+	}
+	if err := tx.Rollback(ctx); err != nil {
+		t.Fatalf("Rollback failed: %v", err)
+	}
+
+	select {
+	case event := <-watch.Events:
+		t.Fatalf("received event %+v from a rolled-back transaction; NOTIFY should not survive rollback", event)
+	case <-time.After(500 * time.Millisecond):
+		// Expected: nothing arrives.
+	}
+
+	// The equivalent committed write must notify.
+	if err := s.CreateWorker(ctx, worker); err != nil {
+		t.Fatalf("CreateWorker failed: %v", err)
+	}
+	select {
+	case event := <-watch.Events:
+		if event.Type != store.WorkerEventCreated {
+			t.Errorf("expected WorkerEventCreated, got %v", event.Type)
+		}
+		worker.Version = 1 // CreateWorker assigns version 1 server-side.
+		if diff := cmp.Diff(worker, event.Worker, protocmp.Transform()); diff != "" {
+			t.Errorf("event worker mismatch (-want +got):\n%s", diff)
+		}
+	case <-time.After(2 * time.Second):
+		t.Fatal("timed out waiting for event from a committed write")
+	}
+}
+
+func TestListActors_InvalidPageToken(t *testing.T) {
+	s := setupPostgresStore(t).(*Persistence)
+	ctx := context.Background()
+
+	if _, _, err := s.ListActors(ctx, "", 10, "not-valid-base64!!"); err == nil {
+		t.Errorf("ListActors with malformed page token = nil error, want an error")
+	}
+}
+
+func TestDecodePageTokenRejectsWrongKeyShape(t *testing.T) {
+	token := encodePageToken(kindActor, "", []string{"only-an-atespace"})
+	if _, err := decodePageToken(token, kindActor, "", 2); err == nil {
+		t.Fatal("decodePageToken() accepted a global actor token with only one key part")
+	}
+}
+
+func TestListActors_CrossScopePageToken(t *testing.T) {
+	s := setupPostgresStore(t).(*Persistence)
+	ctx := context.Background()
+
+	if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil {
+		t.Fatalf("CreateAtespace(team-a) failed: %v", err)
+	}
+	if _, err := s.CreateAtespace(ctx, newTestAtespace("team-b")); err != nil {
+		t.Fatalf("CreateAtespace(team-b) failed: %v", err)
+	}
+	for _, name := range []string{"a1", "a2"} {
+		if _, err := s.CreateActor(ctx, &ateapipb.Actor{Metadata: &ateapipb.ResourceMetadata{Name: name, Atespace: "team-a"}, Status: ateapipb.Actor_STATUS_SUSPENDED}); err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+	}
+
+	_, nextToken, err := s.ListActors(ctx, "team-a", 1, "")
+	if err != nil {
+		t.Fatalf("ListActors(team-a) failed: %v", err)
+	}
+	if nextToken == "" {
+		t.Fatalf("expected a next page token")
+	}
+
+	// A token minted for team-a must be rejected when replayed against team-b
+	// or against the unscoped (global) listing.
+	if _, _, err := s.ListActors(ctx, "team-b", 1, nextToken); err == nil {
+		t.Errorf("ListActors(team-b) with team-a's token = nil error, want an error")
+	}
+	if _, _, err := s.ListActors(ctx, "", 1, nextToken); err == nil {
+		t.Errorf("ListActors(all) with team-a's token = nil error, want an error")
+	}
+
+	// A worker-list token must be rejected by ListAtespaces (different kind).
+	_, workerToken, err := s.ListWorkers(ctx, 1, "")
+	if err != nil {
+		t.Fatalf("ListWorkers failed: %v", err)
+	}
+	if workerToken != "" {
+		if _, _, err := s.ListAtespaces(ctx, 1, workerToken); err == nil {
+			t.Errorf("ListAtespaces with a worker page token = nil error, want an error")
+		}
+	}
+}
+
+func TestAcquireLock_ExpiresAfterHolderStops(t *testing.T) {
+	s := setupPostgresPersistence(t)
+	s.lockTTL = 200 * time.Millisecond
+	holderCtx, cancelHolder := context.WithCancel(context.Background())
+	lock, err := s.AcquireLock(holderCtx, "test-lock")
+	if err != nil {
+		t.Fatalf("AcquireLock failed: %v", err)
+	}
+	cancelHolder()
+	select {
+	case <-lock.Context().Done():
+	case <-time.After(time.Second):
+		t.Fatal("lock context was not cancelled with its holder")
+	}
+
+	// Cancelling the holder stops renewal without calling Close, modeling a
+	// process that disappeared and left its lease to expire.
+	time.Sleep(s.lockTTL + 500*time.Millisecond)
+
+	newLock, err := s.AcquireLock(context.Background(), "test-lock")
+	if err != nil {
+		t.Fatalf("AcquireLock after lease expiration failed: %v", err)
+	}
+	newLock.Close()
+}
+
+// TestAcquireLock_ConcurrentTakeover races many goroutines to acquire an
+// already-expired lease against the real database, and asserts exactly one
+// wins -- the property the doc's conditional-upsert SQL is meant to
+// guarantee under real concurrency, which a single-connection unit test
+// can't exercise.
+func TestAcquireLock_ConcurrentTakeover(t *testing.T) {
+	s := setupPostgresPersistence(t)
+	s.lockTTL = time.Millisecond
+	holderCtx, cancelHolder := context.WithCancel(context.Background())
+	initial, err := s.AcquireLock(holderCtx, "contested-lock")
+	if err != nil {
+		t.Fatalf("seeding initial lease failed: %v", err)
+	}
+	cancelHolder()
+	<-initial.Context().Done()
+	time.Sleep(50 * time.Millisecond) // let the 1ms lease expire.
+	s.lockTTL = 10 * time.Second
+
+	const numRacers = 20
+	winners := make(chan *store.Lock, numRacers)
+	var wg sync.WaitGroup
+	for i := 0; i < numRacers; i++ {
+		wg.Add(1)
+		go func(i int) {
+			defer wg.Done()
+			lock, err := s.AcquireLock(context.Background(), "contested-lock")
+			if err != nil {
+				if !errors.Is(err, store.ErrLockConflict) {
+					t.Errorf("AcquireLock racer %d failed: %v", i, err)
+				}
+				return
+			}
+			// Keep the winning lease held until every racer has attempted
+			// acquisition. Releasing it here would let later racers win
+			// sequentially rather than testing concurrent takeover.
+			winners <- lock
+		}(i)
+	}
+	wg.Wait()
+	close(winners)
+
+	if got := len(winners); got != 1 {
+		t.Errorf("expected exactly 1 racer to win the expired lease, got %d", got)
+	}
+	for lock := range winners {
+		lock.Close()
+	}
+}
diff --git a/cmd/ateapi/internal/store/atepg/contract_test.go b/cmd/ateapi/internal/store/atepg/contract_test.go
new file mode 100644
index 000000000..520199ec7
--- /dev/null
+++ b/cmd/ateapi/internal/store/atepg/contract_test.go
@@ -0,0 +1,27 @@
+// Copyright 2026 Google LLC
+//
+// 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 atepg
+
+import (
+	"testing"
+
+	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store/storecontract"
+)
+
+// TestContractSuite runs the backend-neutral store.Interface assertions
+// against a real PostgreSQL instance.
+func TestContractSuite(t *testing.T) {
+	storecontract.RunContractTests(t, setupPostgresStore)
+}
diff --git a/cmd/ateapi/internal/store/atepg/pagetoken.go b/cmd/ateapi/internal/store/atepg/pagetoken.go
new file mode 100644
index 000000000..b78bb226f
--- /dev/null
+++ b/cmd/ateapi/internal/store/atepg/pagetoken.go
@@ -0,0 +1,80 @@
+// Copyright 2026 Google LLC
+//
+// 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 atepg
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+)
+
+// pageTokenVersion guards against decoding a token produced by an incompatible
+// future token format.
+const pageTokenVersion = 1
+
+// resourceKind identifies which List method a page token belongs to, so a
+// token can't be replayed against the wrong method.
+type resourceKind string
+
+const (
+	kindAtespace resourceKind = "atespace"
+	kindActor    resourceKind = "actor"
+	kindWorker   resourceKind = "worker"
+)
+
+// pageToken is PostgreSQL's opaque keyset page token. Unlike ateredis's
+// shard/cursor token, it carries no database topology: just enough to resume
+// an ORDER BY ... WHERE (cols) > (last) scan.
+type pageToken struct {
+	Version int          `json:"v"`
+	Kind    resourceKind `json:"kind"`
+	Scope   string       `json:"scope"` // atespace name for scoped actor listing; empty otherwise.
+	Last    []string     `json:"last"`  // last row's ordering-column values, in order.
+}
+
+func encodePageToken(kind resourceKind, scope string, last []string) string {
+	b, _ := json.Marshal(pageToken{Version: pageTokenVersion, Kind: kind, Scope: scope, Last: last})
+	return base64.StdEncoding.EncodeToString(b)
+}
+
+// decodePageToken decodes tokenStr and validates it was issued for the same
+// method/scope it's now being presented to. An empty tokenStr decodes to a
+// zero-value (start of list) token.
+func decodePageToken(tokenStr string, wantKind resourceKind, wantScope string, wantKeyParts int) (pageToken, error) {
+	if tokenStr == "" {
+		return pageToken{Version: pageTokenVersion, Kind: wantKind, Scope: wantScope}, nil
+	}
+	b, err := base64.StdEncoding.DecodeString(tokenStr)
+	if err != nil {
+		return pageToken{}, fmt.Errorf("invalid page token: %w", err)
+	}
+	var token pageToken
+	if err := json.Unmarshal(b, &token); err != nil {
+		return pageToken{}, fmt.Errorf("invalid page token: %w", err)
+	}
+	if token.Version != pageTokenVersion {
+		return pageToken{}, fmt.Errorf("invalid page token: unsupported version %d", token.Version)
+	}
+	if token.Kind != wantKind {
+		return pageToken{}, fmt.Errorf("invalid page token: for %q, used with %q", token.Kind, wantKind)
+	}
+	if token.Scope != wantScope {
+		return pageToken{}, fmt.Errorf("invalid page token: for scope %q, used with scope %q", token.Scope, wantScope)
+	}
+	if len(token.Last) != wantKeyParts {
+		return pageToken{}, fmt.Errorf("invalid page token: got %d key parts, want %d", len(token.Last), wantKeyParts)
+	}
+	return token, nil
+}
diff --git a/cmd/ateapi/internal/store/atepg/schema.go b/cmd/ateapi/internal/store/atepg/schema.go
new file mode 100644
index 000000000..1fd184be1
--- /dev/null
+++ b/cmd/ateapi/internal/store/atepg/schema.go
@@ -0,0 +1,88 @@
+// Copyright 2026 Google LLC
+//
+// 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 atepg
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/jackc/pgx/v5/pgxpool"
+)
+
+// schema is atepg's idempotent embedded schema.
+const schema = `
+CREATE TABLE IF NOT EXISTS atespaces (
+    name         text PRIMARY KEY,
+    uid          uuid NOT NULL UNIQUE,
+    version      bigint NOT NULL,
+    create_time  timestamptz NOT NULL,
+    update_time  timestamptz NOT NULL,
+    proto        bytea NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS actors (
+    atespace                     text NOT NULL
+        REFERENCES atespaces(name) ON DELETE RESTRICT,
+    name                         text NOT NULL,
+    uid                          uuid NOT NULL UNIQUE,
+    version                      bigint NOT NULL,
+    status                       integer NOT NULL,
+    actor_template_namespace     text NOT NULL,
+    actor_template_name          text NOT NULL,
+    create_time                  timestamptz NOT NULL,
+    update_time                  timestamptz NOT NULL,
+    proto                        bytea NOT NULL,
+    PRIMARY KEY (atespace, name)
+);
+
+CREATE TABLE IF NOT EXISTS workers (
+    worker_namespace  text NOT NULL,
+    worker_pool       text NOT NULL,
+    worker_pod        text NOT NULL,
+    ip                text NOT NULL,
+    version           bigint NOT NULL,
+    proto             bytea NOT NULL,
+    PRIMARY KEY (worker_namespace, worker_pool, worker_pod)
+);
+
+CREATE TABLE IF NOT EXISTS leases (
+    key         text PRIMARY KEY,
+    token       text NOT NULL,
+    expires_at  timestamptz NOT NULL
+);
+`
+
+// applySchema idempotently creates atepg's tables.
+func applySchema(ctx context.Context, pool *pgxpool.Pool) error {
+	tx, err := pool.Begin(ctx)
+	if err != nil {
+		return fmt.Errorf("beginning atepg schema transaction: %w", err)
+	}
+	defer tx.Rollback(ctx) //nolint:errcheck // no-op once committed
+
+	// Multiple ateapi replicas can start against an empty database together.
+	// PostgreSQL's IF NOT EXISTS does not eliminate every concurrent-DDL race,
+	// so serialize schema application with a transaction-scoped advisory lock.
+	if _, err := tx.Exec(ctx, `SELECT pg_advisory_xact_lock(hashtext('agent-substrate-atepg-schema'))`); err != nil {
+		return fmt.Errorf("locking atepg schema: %w", err)
+	}
+	if _, err := tx.Exec(ctx, schema); err != nil {
+		return fmt.Errorf("applying atepg schema: %w", err)
+	}
+	if err := tx.Commit(ctx); err != nil {
+		return fmt.Errorf("committing atepg schema: %w", err)
+	}
+	return nil
+}
diff --git a/cmd/ateapi/internal/store/ateredis/ateredis_test.go b/cmd/ateapi/internal/store/ateredis/ateredis_test.go
index 87959a153..514a0668e 100644
--- a/cmd/ateapi/internal/store/ateredis/ateredis_test.go
+++ b/cmd/ateapi/internal/store/ateredis/ateredis_test.go
@@ -47,6 +47,7 @@ func setupTest(t *testing.T) (*miniredis.Miniredis, *Persistence, context.Contex
 	rdb := redis.NewClusterClient(&redis.ClusterOptions{
 		Addrs: []string{mr.Addr()},
 	})
+	t.Cleanup(func() { rdb.Close() })
 	return mr, NewPersistence(rdb), t.Context()
 }
 
diff --git a/cmd/ateapi/internal/store/ateredis/contract_test.go b/cmd/ateapi/internal/store/ateredis/contract_test.go
new file mode 100644
index 000000000..3b9df0054
--- /dev/null
+++ b/cmd/ateapi/internal/store/ateredis/contract_test.go
@@ -0,0 +1,31 @@
+// Copyright 2026 Google LLC
+//
+// 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 ateredis
+
+import (
+	"testing"
+
+	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store"
+	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store/storecontract"
+)
+
+// TestContractSuite runs the backend-neutral store.Interface assertions
+// against a miniredis-backed Persistence.
+func TestContractSuite(t *testing.T) {
+	storecontract.RunContractTests(t, func(t *testing.T) store.Interface {
+		_, persistence, _ := setupTest(t)
+		return persistence
+	})
+}
diff --git a/cmd/ateapi/internal/store/storecontract/contract.go b/cmd/ateapi/internal/store/storecontract/contract.go
new file mode 100644
index 000000000..42b0f3860
--- /dev/null
+++ b/cmd/ateapi/internal/store/storecontract/contract.go
@@ -0,0 +1,1147 @@
+// Copyright 2026 Google LLC
+//
+// 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 storecontract provides backend-neutral assertions for store.Interface
+// implementations.
+package storecontract
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/testing/protocmp"
+	"google.golang.org/protobuf/types/known/timestamppb"
+
+	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store"
+	"github.com/agent-substrate/substrate/internal/resources"
+	"github.com/agent-substrate/substrate/pkg/proto/ateapipb"
+)
+
+// testAtespace is the atespace used by tests that create a single actor.
+const testAtespace = "test-atespace"
+
+// Atomic cmp options to skip individual server-owned ResourceMetadata fields
+// in proto diffs.
+var (
+	ignoreUID        = protocmp.IgnoreFields(&ateapipb.ResourceMetadata{}, "uid")
+	ignoreVersion    = protocmp.IgnoreFields(&ateapipb.ResourceMetadata{}, "version")
+	ignoreTimestamps = protocmp.IgnoreFields(&ateapipb.ResourceMetadata{}, "create_time", "update_time")
+)
+
+func newTestAtespace(name string) *ateapipb.Atespace {
+	return &ateapipb.Atespace{Metadata: &ateapipb.ResourceMetadata{Name: name}}
+}
+
+// mustCreateAtespace creates the atespace an actor test is about to populate.
+// Backends that enforce the actor->atespace foreign key (atepg) reject
+// CreateActor for a nonexistent atespace, so every actor test needs a real
+// parent atespace even though ateredis doesn't check.
+func mustCreateAtespace(t *testing.T, s store.Interface, name string) {
+	t.Helper()
+	if _, err := s.CreateAtespace(context.Background(), newTestAtespace(name)); err != nil {
+		t.Fatalf("CreateAtespace(%q) failed: %v", name, err)
+	}
+}
+
+func actorNameSet(actors []*ateapipb.Actor) map[string]bool {
+	set := make(map[string]bool, len(actors))
+	for _, a := range actors {
+		set[a.GetMetadata().GetName()] = true
+	}
+	return set
+}
+
+func receiveEvent(t *testing.T, ch <-chan store.WorkerEvent) store.WorkerEvent {
+	t.Helper()
+	select {
+	case event, ok := <-ch:
+		if !ok {
+			t.Fatal("watch channel closed unexpectedly")
+		}
+		return event
+	case <-time.After(2 * time.Second):
+		t.Fatal("timed out waiting for worker event")
+		return store.WorkerEvent{} // unreachable
+	}
+}
+
+// RunContractTests runs the backend-neutral store.Interface assertions
+// against a fresh store.Interface built by setup for each subtest. setup is
+// responsible for its own cleanup (e.g. via t.Cleanup).
+//
+// Backend-specific behavior (e.g. ateredis's multi-shard pagination, atepg's
+// foreign-key races and transactional notifications) is NOT covered here; see
+// each backend's own test file for that.
+func RunContractTests(t *testing.T, setup func(t *testing.T) store.Interface) {
+	t.Helper()
+
+	t.Run("GetActor_NotFound", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		_, err := s.GetActor(ctx, resources.ActorRef{Atespace: testAtespace, Name: "non-existent"})
+		if !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("expected ErrNotFound, got %v", err)
+		}
+	})
+
+	t.Run("CreateActor_Success", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+		mustCreateAtespace(t, s, testAtespace)
+
+		actor := &ateapipb.Actor{
+			Metadata:               &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace},
+			ActorTemplateNamespace: "default",
+			ActorTemplateName:      "test-template",
+			Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+		}
+
+		created, err := s.CreateActor(ctx, actor)
+		if err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+
+		if created.GetMetadata().GetUid() == "" {
+			t.Errorf("CreateActor returned empty uid; want server-assigned uid")
+		}
+		if created.GetMetadata().GetVersion() != 1 {
+			t.Errorf("CreateActor returned version %d, want 1", created.GetMetadata().GetVersion())
+		}
+		if created.GetMetadata().GetCreateTime() == nil || created.GetMetadata().GetUpdateTime() == nil {
+			t.Errorf("CreateActor returned unset create/update time")
+		}
+
+		if actor.GetMetadata().GetUid() != "" || actor.GetMetadata().GetVersion() != 0 {
+			t.Errorf("CreateActor must not mutate its input, got metadata %v", actor.GetMetadata())
+		}
+
+		got, err := s.GetActor(ctx, resources.ActorRefFromActor(actor))
+		if err != nil {
+			t.Fatalf("GetActor failed: %v", err)
+		}
+		if diff := cmp.Diff(created, got, protocmp.Transform()); diff != "" {
+			t.Errorf("CreateActor return does not match stored state (-created +got):\n%s", diff)
+		}
+
+		expected := proto.Clone(actor).(*ateapipb.Actor)
+		expected.Metadata.Version = 1
+		if diff := cmp.Diff(expected, created, protocmp.Transform(), ignoreUID, ignoreTimestamps); diff != "" {
+			t.Errorf("CreateActor returned unexpected actor (-want +got):\n%s", diff)
+		}
+	})
+
+	t.Run("CreateActor_AlreadyExists", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+		mustCreateAtespace(t, s, testAtespace)
+
+		actor := &ateapipb.Actor{
+			Metadata:               &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace},
+			ActorTemplateNamespace: "default",
+			ActorTemplateName:      "test-template",
+			Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+		}
+
+		if _, err := s.CreateActor(ctx, actor); err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+		if _, err := s.CreateActor(ctx, actor); !errors.Is(err, store.ErrAlreadyExists) {
+			t.Errorf("expected ErrAlreadyExists, got %v", err)
+		}
+	})
+
+	t.Run("UpdateActor_Success", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+		mustCreateAtespace(t, s, testAtespace)
+
+		actor := &ateapipb.Actor{
+			Metadata:               &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace},
+			ActorTemplateNamespace: "default",
+			ActorTemplateName:      "test-template",
+			Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+		}
+
+		created, err := s.CreateActor(ctx, actor)
+		if err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+
+		toUpdate := proto.Clone(created).(*ateapipb.Actor)
+		toUpdate.Status = ateapipb.Actor_STATUS_RUNNING
+		// Server-owned metadata must be derived from the stored resource, not
+		// accepted from an update payload.
+		toUpdate.Metadata.Uid = "client-supplied-uid"
+		toUpdate.Metadata.CreateTime = timestamppb.New(time.Unix(1, 0))
+		updated, err := s.UpdateActor(ctx, toUpdate, created.GetMetadata().GetVersion())
+		if err != nil {
+			t.Fatalf("UpdateActor failed: %v", err)
+		}
+
+		if updated.GetStatus() != ateapipb.Actor_STATUS_RUNNING {
+			t.Errorf("UpdateActor returned status %v, want RUNNING", updated.GetStatus())
+		}
+		if updated.GetMetadata().GetVersion() != 2 {
+			t.Errorf("UpdateActor returned version %d, want 2", updated.GetMetadata().GetVersion())
+		}
+		if updated.GetMetadata().GetUid() != created.GetMetadata().GetUid() {
+			t.Errorf("uid changed on update: got %q, want %q", updated.GetMetadata().GetUid(), created.GetMetadata().GetUid())
+		}
+		if !updated.GetMetadata().GetCreateTime().AsTime().Equal(created.GetMetadata().GetCreateTime().AsTime()) {
+			t.Errorf("create_time changed on update: got %v, want %v", updated.GetMetadata().GetCreateTime().AsTime(), created.GetMetadata().GetCreateTime().AsTime())
+		}
+
+		if toUpdate.GetMetadata().GetVersion() != created.GetMetadata().GetVersion() {
+			t.Errorf("UpdateActor must not mutate its input; version changed to %d", toUpdate.GetMetadata().GetVersion())
+		}
+
+		got, err := s.GetActor(ctx, resources.ActorRefFromActor(actor))
+		if err != nil {
+			t.Fatalf("GetActor failed: %v", err)
+		}
+		if diff := cmp.Diff(updated, got, protocmp.Transform()); diff != "" {
+			t.Errorf("UpdateActor return does not match stored state (-updated +got):\n%s", diff)
+		}
+	})
+
+	t.Run("UpdateActor_Conflict", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+		mustCreateAtespace(t, s, testAtespace)
+
+		actor := &ateapipb.Actor{
+			Metadata:               &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace},
+			ActorTemplateNamespace: "default",
+			ActorTemplateName:      "test-template",
+			Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+		}
+
+		if _, err := s.CreateActor(ctx, actor); err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+
+		actor1, err := s.GetActor(ctx, resources.ActorRefFromActor(actor))
+		if err != nil {
+			t.Fatalf("GetActor failed: %v", err)
+		}
+		actor2, err := s.GetActor(ctx, resources.ActorRefFromActor(actor))
+		if err != nil {
+			t.Fatalf("GetActor failed: %v", err)
+		}
+
+		actor1.Status = ateapipb.Actor_STATUS_RUNNING
+		if _, err := s.UpdateActor(ctx, actor1, actor1.GetMetadata().GetVersion()); err != nil {
+			t.Fatalf("UpdateActor failed: %v", err)
+		}
+
+		actor2.Status = ateapipb.Actor_STATUS_SUSPENDED
+		_, err = s.UpdateActor(ctx, actor2, actor2.GetMetadata().GetVersion())
+		if !errors.Is(err, store.ErrVersionConflict) {
+			t.Errorf("expected ErrVersionConflict, got %v", err)
+		}
+	})
+
+	t.Run("UpdateActor_ImmutableFields", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+		mustCreateAtespace(t, s, testAtespace)
+
+		actor := &ateapipb.Actor{
+			Metadata:               &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace},
+			ActorTemplateNamespace: "default",
+			ActorTemplateName:      "test-template",
+			Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+		}
+		created, err := s.CreateActor(ctx, actor)
+		if err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+
+		toUpdate := proto.Clone(created).(*ateapipb.Actor)
+		toUpdate.ActorTemplateName = "other-template"
+		if _, err := s.UpdateActor(ctx, toUpdate, created.GetMetadata().GetVersion()); err == nil {
+			t.Errorf("expected error updating actor_template_name, got nil")
+		} else if errors.Is(err, store.ErrVersionConflict) || errors.Is(err, store.ErrNotFound) {
+			t.Errorf("expected a plain immutable-field error, got sentinel %v", err)
+		}
+	})
+
+	t.Run("GetWorker_NotFound", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		_, err := s.GetWorker(ctx, "default", "pool-1", "non-existent")
+		if !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("expected ErrNotFound, got %v", err)
+		}
+	})
+
+	t.Run("CreateWorker_Success", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		watch, err := s.WatchWorkers(ctx)
+		if err != nil {
+			t.Fatalf("WatchWorkers failed: %v", err)
+		}
+		defer watch.Close()
+
+		worker := &ateapipb.Worker{
+			WorkerNamespace: "default",
+			WorkerPool:      "pool-1",
+			WorkerPod:       "pod-1",
+		}
+
+		if err := s.CreateWorker(ctx, worker); err != nil {
+			t.Fatalf("CreateWorker failed: %v", err)
+		}
+
+		got, err := s.GetWorker(ctx, "default", "pool-1", "pod-1")
+		if err != nil {
+			t.Fatalf("GetWorker failed: %v", err)
+		}
+		if got.Version != 1 {
+			t.Errorf("expected version 1, got %d", got.Version)
+		}
+
+		worker.Version = 1
+		if diff := cmp.Diff(worker, got, protocmp.Transform()); diff != "" {
+			t.Errorf("GetWorker returned unexpected worker (-want +got):\n%s", diff)
+		}
+
+		event := receiveEvent(t, watch.Events)
+		if event.Type != store.WorkerEventCreated {
+			t.Errorf("expected WorkerEventCreated, got %v", event.Type)
+		}
+		if diff := cmp.Diff(worker, event.Worker, protocmp.Transform()); diff != "" {
+			t.Errorf("created event worker mismatch (-want +got):\n%s", diff)
+		}
+	})
+
+	t.Run("CreateWorker_AlreadyExists", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		worker := &ateapipb.Worker{WorkerNamespace: "default", WorkerPool: "pool-1", WorkerPod: "pod-1"}
+		if err := s.CreateWorker(ctx, worker); err != nil {
+			t.Fatalf("CreateWorker failed: %v", err)
+		}
+		if err := s.CreateWorker(ctx, worker); !errors.Is(err, store.ErrAlreadyExists) {
+			t.Errorf("expected ErrAlreadyExists, got %v", err)
+		}
+	})
+
+	t.Run("UpdateWorker_Success", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		worker := &ateapipb.Worker{WorkerNamespace: "default", WorkerPool: "pool-1", WorkerPod: "pod-1"}
+		if err := s.CreateWorker(ctx, worker); err != nil {
+			t.Fatalf("CreateWorker failed: %v", err)
+		}
+
+		// Subscribe after create so the create event doesn't pollute the channel.
+		watch, err := s.WatchWorkers(ctx)
+		if err != nil {
+			t.Fatalf("WatchWorkers failed: %v", err)
+		}
+		defer watch.Close()
+
+		worker.Assignment = &ateapipb.Assignment{
+			ActorTemplate: &ateapipb.KubeNamespacedObjectRef{Namespace: "default", Name: "test-template"},
+			Actor:         &ateapipb.ObjectRef{Name: "session-1"},
+		}
+		if err := s.UpdateWorker(ctx, worker, 1); err != nil {
+			t.Fatalf("UpdateWorker failed: %v", err)
+		}
+
+		got, err := s.GetWorker(ctx, "default", "pool-1", "pod-1")
+		if err != nil {
+			t.Fatalf("GetWorker failed: %v", err)
+		}
+		if got.Version != 2 {
+			t.Errorf("expected version 2, got %d", got.Version)
+		}
+
+		worker.Version = 2
+		if diff := cmp.Diff(worker, got, protocmp.Transform()); diff != "" {
+			t.Errorf("UpdateWorker yielded unexpected state in DB (-want +got):\n%s", diff)
+		}
+
+		event := receiveEvent(t, watch.Events)
+		if event.Type != store.WorkerEventUpdated {
+			t.Errorf("expected WorkerEventUpdated, got %v", event.Type)
+		}
+		if diff := cmp.Diff(worker, event.Worker, protocmp.Transform()); diff != "" {
+			t.Errorf("updated event worker mismatch (-want +got):\n%s", diff)
+		}
+	})
+
+	t.Run("UpdateWorker_Conflict", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		worker := &ateapipb.Worker{WorkerNamespace: "default", WorkerPool: "pool-1", WorkerPod: "pod-1"}
+		if err := s.CreateWorker(ctx, worker); err != nil {
+			t.Fatalf("CreateWorker failed: %v", err)
+		}
+
+		worker1, err := s.GetWorker(ctx, "default", "pool-1", "pod-1")
+		if err != nil {
+			t.Fatalf("GetWorker failed: %v", err)
+		}
+		worker2, err := s.GetWorker(ctx, "default", "pool-1", "pod-1")
+		if err != nil {
+			t.Fatalf("GetWorker failed: %v", err)
+		}
+
+		worker1.Assignment = &ateapipb.Assignment{Actor: &ateapipb.ObjectRef{Name: "session-1"}}
+		if err := s.UpdateWorker(ctx, worker1, worker1.Version); err != nil {
+			t.Fatalf("UpdateWorker failed: %v", err)
+		}
+
+		worker2.Assignment = &ateapipb.Assignment{Actor: &ateapipb.ObjectRef{Name: "session-2"}}
+		err = s.UpdateWorker(ctx, worker2, worker2.Version)
+		if !errors.Is(err, store.ErrVersionConflict) {
+			t.Errorf("expected ErrVersionConflict, got %v", err)
+		}
+	})
+
+	t.Run("UpdateWorker_ImmutableIP", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		worker := &ateapipb.Worker{WorkerNamespace: "default", WorkerPool: "pool-1", WorkerPod: "pod-1", Ip: "10.0.0.1"}
+		if err := s.CreateWorker(ctx, worker); err != nil {
+			t.Fatalf("CreateWorker failed: %v", err)
+		}
+		worker.Version = 1
+		worker.Ip = "10.0.0.2"
+		if err := s.UpdateWorker(ctx, worker, 1); err == nil {
+			t.Errorf("expected error updating immutable ip, got nil")
+		} else if errors.Is(err, store.ErrVersionConflict) || errors.Is(err, store.ErrNotFound) {
+			t.Errorf("expected a plain immutable-field error, got sentinel %v", err)
+		}
+	})
+
+	t.Run("DeleteWorker", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		worker := &ateapipb.Worker{WorkerNamespace: "default", WorkerPool: "pool-1", WorkerPod: "pod-1"}
+		if err := s.CreateWorker(ctx, worker); err != nil {
+			t.Fatalf("CreateWorker failed: %v", err)
+		}
+
+		watch, err := s.WatchWorkers(ctx)
+		if err != nil {
+			t.Fatalf("WatchWorkers failed: %v", err)
+		}
+		defer watch.Close()
+
+		if err := s.DeleteWorker(ctx, "default", "pool-1", "pod-1"); err != nil {
+			t.Fatalf("DeleteWorker failed: %v", err)
+		}
+		if _, err := s.GetWorker(ctx, "default", "pool-1", "pod-1"); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("expected ErrNotFound after delete, got %v", err)
+		}
+
+		event := receiveEvent(t, watch.Events)
+		if event.Type != store.WorkerEventDeleted {
+			t.Errorf("expected WorkerEventDeleted, got %v", event.Type)
+		}
+	})
+
+	t.Run("DeleteWorker_Idempotent", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if err := s.DeleteWorker(ctx, "default", "pool-1", "non-existent"); err != nil {
+			t.Errorf("DeleteWorker of a missing worker should be a no-op, got %v", err)
+		}
+	})
+
+	t.Run("WatchWorkers_ClosedOnClose", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		watch, err := s.WatchWorkers(ctx)
+		if err != nil {
+			t.Fatalf("WatchWorkers failed: %v", err)
+		}
+		watch.Close()
+
+		select {
+		case _, ok := <-watch.Events:
+			if ok {
+				t.Errorf("expected Events to be closed after Close, got an event")
+			}
+		case <-time.After(2 * time.Second):
+			t.Fatal("timed out waiting for Events to close after Close")
+		}
+	})
+
+	t.Run("DeleteActor", func(t *testing.T) {
+		tests := []struct {
+			name    string
+			status  ateapipb.Actor_Status
+			wantErr error
+		}{
+			{name: "suspended", status: ateapipb.Actor_STATUS_SUSPENDED},
+			{name: "crashed", status: ateapipb.Actor_STATUS_CRASHED},
+			{name: "running", status: ateapipb.Actor_STATUS_RUNNING, wantErr: store.ErrFailedPrecondition},
+			{name: "paused", status: ateapipb.Actor_STATUS_PAUSED, wantErr: store.ErrFailedPrecondition},
+		}
+
+		for _, tt := range tests {
+			t.Run(tt.name, func(t *testing.T) {
+				s := setup(t)
+				ctx := context.Background()
+				mustCreateAtespace(t, s, testAtespace)
+
+				actor := &ateapipb.Actor{
+					Metadata:               &ateapipb.ResourceMetadata{Name: "session-1", Atespace: testAtespace},
+					ActorTemplateNamespace: "default",
+					ActorTemplateName:      "test-template",
+					Status:                 tt.status,
+				}
+				if _, err := s.CreateActor(ctx, actor); err != nil {
+					t.Fatalf("CreateActor failed: %v", err)
+				}
+
+				deleted, err := s.DeleteActor(ctx, resources.ActorRef{Atespace: testAtespace, Name: "session-1"})
+				if tt.wantErr != nil {
+					if !errors.Is(err, tt.wantErr) {
+						t.Errorf("DeleteActor: expected %v, got %v", tt.wantErr, err)
+					}
+					return
+				}
+				if err != nil {
+					t.Fatalf("DeleteActor failed: %v", err)
+				}
+				if got := deleted.GetMetadata().GetName(); got != "session-1" {
+					t.Errorf("deleted actor name = %q, want session-1", got)
+				}
+				if _, err := s.GetActor(ctx, resources.ActorRef{Atespace: testAtespace, Name: "session-1"}); !errors.Is(err, store.ErrNotFound) {
+					t.Errorf("expected ErrNotFound after delete, got %v", err)
+				}
+			})
+		}
+	})
+
+	t.Run("DeleteActor_NotFound", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.DeleteActor(ctx, resources.ActorRef{Atespace: testAtespace, Name: "non-existent"}); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("expected ErrNotFound deleting non-existent actor, got %v", err)
+		}
+	})
+
+	t.Run("ListWorkers", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		worker1 := &ateapipb.Worker{WorkerNamespace: "ns1", WorkerPool: "pool1", WorkerPod: "pod1"}
+		worker2 := &ateapipb.Worker{WorkerNamespace: "ns1", WorkerPool: "pool1", WorkerPod: "pod2"}
+		if err := s.CreateWorker(ctx, worker1); err != nil {
+			t.Fatalf("failed to create worker1: %v", err)
+		}
+		if err := s.CreateWorker(ctx, worker2); err != nil {
+			t.Fatalf("failed to create worker2: %v", err)
+		}
+
+		workers, _, err := s.ListWorkers(ctx, 1000, "")
+		if err != nil {
+			t.Fatalf("ListWorkers failed: %v", err)
+		}
+		if len(workers) != 2 {
+			t.Errorf("expected 2 workers, got %d", len(workers))
+		}
+
+		found1, found2 := false, false
+		for _, w := range workers {
+			if w.GetWorkerPod() == "pod1" {
+				found1 = true
+			}
+			if w.GetWorkerPod() == "pod2" {
+				found2 = true
+			}
+		}
+		if !found1 || !found2 {
+			t.Errorf("did not find all workers: found1=%t, found2=%t", found1, found2)
+		}
+	})
+
+	t.Run("ListWorkers_Empty", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		workers, _, err := s.ListWorkers(ctx, 1000, "")
+		if err != nil {
+			t.Fatalf("ListWorkers failed: %v", err)
+		}
+		if len(workers) != 0 {
+			t.Errorf("expected 0 workers, got %d", len(workers))
+		}
+	})
+
+	t.Run("ListWorkers_Pagination", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		for i := 0; i < 5; i++ {
+			worker := &ateapipb.Worker{WorkerNamespace: "ns1", WorkerPool: "pool1", WorkerPod: fmt.Sprintf("pod%d", i)}
+			if err := s.CreateWorker(ctx, worker); err != nil {
+				t.Fatalf("failed to create worker %d: %v", i, err)
+			}
+		}
+
+		var allWorkers []*ateapipb.Worker
+		pageToken := ""
+		for {
+			workers, nextToken, err := s.ListWorkers(ctx, 2, pageToken)
+			if err != nil {
+				t.Fatalf("ListWorkers failed: %v", err)
+			}
+			allWorkers = append(allWorkers, workers...)
+			pageToken = nextToken
+			if pageToken == "" {
+				break
+			}
+		}
+
+		if len(allWorkers) != 5 {
+			t.Fatalf("expected 5 workers total, got %d", len(allWorkers))
+		}
+		seen := make(map[string]bool)
+		for _, w := range allWorkers {
+			if seen[w.GetWorkerPod()] {
+				t.Errorf("duplicate worker found in paginated results: %s", w.GetWorkerPod())
+			}
+			seen[w.GetWorkerPod()] = true
+		}
+	})
+
+	t.Run("ListAtespaces_Pagination", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		for i := 0; i < 5; i++ {
+			if _, err := s.CreateAtespace(ctx, newTestAtespace(fmt.Sprintf("team-%d", i))); err != nil {
+				t.Fatalf("failed to create atespace %d: %v", i, err)
+			}
+		}
+
+		var allAtespaces []*ateapipb.Atespace
+		pageToken := ""
+		for {
+			atespaces, nextToken, err := s.ListAtespaces(ctx, 2, pageToken)
+			if err != nil {
+				t.Fatalf("ListAtespaces failed: %v", err)
+			}
+			allAtespaces = append(allAtespaces, atespaces...)
+			pageToken = nextToken
+			if pageToken == "" {
+				break
+			}
+		}
+
+		if len(allAtespaces) != 5 {
+			t.Fatalf("expected 5 atespaces total, got %d", len(allAtespaces))
+		}
+		seen := make(map[string]bool)
+		for _, a := range allAtespaces {
+			if seen[a.GetMetadata().GetName()] {
+				t.Errorf("duplicate atespace found in paginated results: %s", a.GetMetadata().GetName())
+			}
+			seen[a.GetMetadata().GetName()] = true
+		}
+	})
+
+	t.Run("ListActors_Empty", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		actors, _, err := s.ListActors(ctx, "", 1000, "")
+		if err != nil {
+			t.Fatalf("ListActors failed: %v", err)
+		}
+		if len(actors) != 0 {
+			t.Errorf("expected 0 actors, got %d", len(actors))
+		}
+	})
+
+	t.Run("ListActors", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+		mustCreateAtespace(t, s, testAtespace)
+
+		actor1 := &ateapipb.Actor{
+			Metadata:               &ateapipb.ResourceMetadata{Name: "id1", Atespace: testAtespace},
+			ActorTemplateNamespace: "ns1",
+			ActorTemplateName:      "tmpl1",
+			Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+			LatestSnapshotInfo: &ateapipb.SnapshotInfo{
+				Data: &ateapipb.SnapshotInfo_External{External: &ateapipb.ExternalSnapshotInfo{SnapshotUriPrefix: "gs://b1/f1"}},
+			},
+		}
+		actor2 := &ateapipb.Actor{
+			Metadata:               &ateapipb.ResourceMetadata{Name: "id2", Atespace: testAtespace},
+			ActorTemplateNamespace: "ns1",
+			ActorTemplateName:      "tmpl1",
+			Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+			LatestSnapshotInfo: &ateapipb.SnapshotInfo{
+				Data: &ateapipb.SnapshotInfo_External{External: &ateapipb.ExternalSnapshotInfo{SnapshotUriPrefix: "gs://b1/f2"}},
+			},
+		}
+		if _, err := s.CreateActor(ctx, actor1); err != nil {
+			t.Fatalf("failed to create actor1: %v", err)
+		}
+		if _, err := s.CreateActor(ctx, actor2); err != nil {
+			t.Fatalf("failed to create actor2: %v", err)
+		}
+
+		actors, _, err := s.ListActors(ctx, "", 1000, "")
+		if err != nil {
+			t.Fatalf("ListActors failed: %v", err)
+		}
+		if len(actors) != 2 {
+			t.Errorf("expected 2 actors, got %d", len(actors))
+		}
+		if got := actorNameSet(actors); !got["id1"] || !got["id2"] {
+			t.Errorf("did not find all actors: %v", got)
+		}
+	})
+
+	t.Run("ListActors_Pagination", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+		mustCreateAtespace(t, s, testAtespace)
+
+		for i := 0; i < 5; i++ {
+			actor := &ateapipb.Actor{
+				Metadata:               &ateapipb.ResourceMetadata{Name: fmt.Sprintf("name%d", i), Atespace: testAtespace},
+				ActorTemplateNamespace: "ns1",
+				ActorTemplateName:      "tmpl1",
+				Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+			}
+			if _, err := s.CreateActor(ctx, actor); err != nil {
+				t.Fatalf("failed to create actor %d: %v", i, err)
+			}
+		}
+
+		var allActors []*ateapipb.Actor
+		pageToken := ""
+		for {
+			actors, nextToken, err := s.ListActors(ctx, "", 2, pageToken)
+			if err != nil {
+				t.Fatalf("ListActors failed: %v", err)
+			}
+			allActors = append(allActors, actors...)
+			pageToken = nextToken
+			if pageToken == "" {
+				break
+			}
+		}
+
+		if len(allActors) != 5 {
+			t.Fatalf("expected 5 actors total, got %d", len(allActors))
+		}
+		seen := make(map[string]bool)
+		for _, a := range allActors {
+			if seen[a.GetMetadata().GetName()] {
+				t.Errorf("duplicate actor found in paginated results: %s", a.GetMetadata().GetName())
+			}
+			seen[a.GetMetadata().GetName()] = true
+		}
+	})
+
+	t.Run("ListActors_ScopedByAtespace", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+		mustCreateAtespace(t, s, "team-a")
+		mustCreateAtespace(t, s, "team-b")
+
+		mkActor := func(atespace, name string) *ateapipb.Actor {
+			return &ateapipb.Actor{
+				Metadata:               &ateapipb.ResourceMetadata{Name: name, Atespace: atespace},
+				ActorTemplateNamespace: "ns1",
+				ActorTemplateName:      "tmpl1",
+				Status:                 ateapipb.Actor_STATUS_SUSPENDED,
+			}
+		}
+		for _, a := range []*ateapipb.Actor{mkActor("team-a", "a1"), mkActor("team-a", "a2"), mkActor("team-b", "b1")} {
+			if _, err := s.CreateActor(ctx, a); err != nil {
+				t.Fatalf("CreateActor(%s/%s) failed: %v", a.GetMetadata().GetAtespace(), a.GetMetadata().GetName(), err)
+			}
+		}
+
+		teamA, _, err := s.ListActors(ctx, "team-a", 1000, "")
+		if err != nil {
+			t.Fatalf("ListActors(team-a) failed: %v", err)
+		}
+		if got := actorNameSet(teamA); !got["a1"] || !got["a2"] || got["b1"] || len(got) != 2 {
+			t.Errorf("ListActors(team-a) = %v, want exactly {a1, a2}", got)
+		}
+
+		teamB, _, err := s.ListActors(ctx, "team-b", 1000, "")
+		if err != nil {
+			t.Fatalf("ListActors(team-b) failed: %v", err)
+		}
+		if got := actorNameSet(teamB); !got["b1"] || got["a1"] || len(got) != 1 {
+			t.Errorf("ListActors(team-b) = %v, want exactly {b1}", got)
+		}
+
+		all, _, err := s.ListActors(ctx, "", 1000, "")
+		if err != nil {
+			t.Fatalf("ListActors(all) failed: %v", err)
+		}
+		if got := actorNameSet(all); !got["a1"] || !got["a2"] || !got["b1"] || len(got) != 3 {
+			t.Errorf("ListActors(all) = %v, want exactly {a1, a2, b1}", got)
+		}
+
+		if _, err := s.GetActor(ctx, resources.ActorRef{Atespace: "team-a", Name: "a1"}); err != nil {
+			t.Errorf("GetActor(team-a, a1) failed: %v", err)
+		}
+		if _, err := s.GetActor(ctx, resources.ActorRef{Atespace: "team-b", Name: "a1"}); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("GetActor(team-b, a1) = %v, want ErrNotFound", err)
+		}
+		if _, err := s.GetActor(ctx, resources.ActorRef{Name: "a1"}); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("GetActor(empty, a1) = %v, want ErrNotFound", err)
+		}
+	})
+
+	t.Run("AcquireLock_Success", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		lock, err := s.AcquireLock(ctx, "test-lock")
+		if err != nil {
+			t.Fatalf("AcquireLock failed: %v", err)
+		}
+		if lock == nil {
+			t.Fatal("AcquireLock returned a nil lock")
+		}
+		if err := lock.Context().Err(); err != nil {
+			t.Errorf("new lock context is already done: %v", err)
+		}
+		lock.Close()
+	})
+
+	t.Run("AcquireLock_Conflict", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		lock, err := s.AcquireLock(ctx, "test-lock")
+		if err != nil {
+			t.Fatalf("first AcquireLock failed: %v", err)
+		}
+		defer lock.Close()
+
+		if _, err := s.AcquireLock(ctx, "test-lock"); !errors.Is(err, store.ErrLockConflict) {
+			t.Errorf("second AcquireLock error = %v, want ErrLockConflict", err)
+		}
+	})
+
+	t.Run("AcquireLock_NonReentry", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		lock, err := s.AcquireLock(ctx, "test-lock")
+		if err != nil {
+			t.Fatalf("first AcquireLock failed: %v", err)
+		}
+		defer lock.Close()
+
+		if _, err := s.AcquireLock(ctx, "test-lock"); !errors.Is(err, store.ErrLockConflict) {
+			t.Errorf("reentrant AcquireLock error = %v, want ErrLockConflict", err)
+		}
+	})
+
+	t.Run("Lock_Close_Releases", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		lock, err := s.AcquireLock(ctx, "test-lock")
+		if err != nil {
+			t.Fatalf("AcquireLock failed: %v", err)
+		}
+		lock.Close()
+
+		newLock, err := s.AcquireLock(ctx, "test-lock")
+		if err != nil {
+			t.Fatalf("AcquireLock after Close failed: %v", err)
+		}
+		newLock.Close()
+	})
+
+	t.Run("Lock_Close_Idempotent", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		lock, err := s.AcquireLock(ctx, "test-lock")
+		if err != nil {
+			t.Fatalf("AcquireLock failed: %v", err)
+		}
+		lock.Close()
+		lock.Close()
+	})
+
+	t.Run("DebugClearAll", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil {
+			t.Fatalf("CreateAtespace failed: %v", err)
+		}
+		if _, err := s.CreateActor(ctx, &ateapipb.Actor{
+			Metadata: &ateapipb.ResourceMetadata{Name: "id1", Atespace: "team-a"},
+			Status:   ateapipb.Actor_STATUS_SUSPENDED,
+		}); err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+		if err := s.CreateWorker(ctx, &ateapipb.Worker{WorkerNamespace: "ns", WorkerPool: "pool", WorkerPod: "pod"}); err != nil {
+			t.Fatalf("CreateWorker failed: %v", err)
+		}
+		lock, err := s.AcquireLock(ctx, "lock-1")
+		if err != nil {
+			t.Fatalf("AcquireLock failed: %v", err)
+		}
+		defer lock.Close()
+
+		if err := s.DebugClearAll(ctx); err != nil {
+			t.Fatalf("DebugClearAll failed: %v", err)
+		}
+
+		if _, err := s.GetAtespace(ctx, "team-a"); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("atespace survived DebugClearAll: %v", err)
+		}
+		if actors, _, err := s.ListActors(ctx, "", 1000, ""); err != nil || len(actors) != 0 {
+			t.Errorf("actors survived DebugClearAll: actors=%v err=%v", actors, err)
+		}
+		if workers, _, err := s.ListWorkers(ctx, 1000, ""); err != nil || len(workers) != 0 {
+			t.Errorf("workers survived DebugClearAll: workers=%v err=%v", workers, err)
+		}
+		reacquired, err := s.AcquireLock(ctx, "lock-1")
+		if err != nil {
+			t.Errorf("lock survived DebugClearAll: %v", err)
+		} else {
+			reacquired.Close()
+		}
+	})
+
+	t.Run("CreateAtespace_Success", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		want := newTestAtespace("team-a")
+		created, err := s.CreateAtespace(ctx, want)
+		if err != nil {
+			t.Fatalf("CreateAtespace failed: %v", err)
+		}
+		if created.GetMetadata().GetUid() == "" {
+			t.Errorf("CreateAtespace returned empty uid; want server-assigned uid")
+		}
+		if created.GetMetadata().GetVersion() != 1 {
+			t.Errorf("CreateAtespace returned version %d, want 1", created.GetMetadata().GetVersion())
+		}
+
+		got, err := s.GetAtespace(ctx, "team-a")
+		if err != nil {
+			t.Fatalf("GetAtespace failed: %v", err)
+		}
+		if diff := cmp.Diff(created, got, protocmp.Transform()); diff != "" {
+			t.Errorf("CreateAtespace return does not match stored state (-created +got):\n%s", diff)
+		}
+		if diff := cmp.Diff(want, created, protocmp.Transform(), ignoreUID, ignoreTimestamps, ignoreVersion); diff != "" {
+			t.Errorf("CreateAtespace returned unexpected atespace (-want +got):\n%s", diff)
+		}
+	})
+
+	t.Run("CreateAtespace_AlreadyExists", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil {
+			t.Fatalf("first CreateAtespace failed: %v", err)
+		}
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); !errors.Is(err, store.ErrAlreadyExists) {
+			t.Errorf("expected ErrAlreadyExists, got %v", err)
+		}
+	})
+
+	t.Run("GetAtespace_NotFound", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.GetAtespace(ctx, "nope"); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("expected ErrNotFound, got %v", err)
+		}
+	})
+
+	t.Run("AtespaceExists", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if ok, err := s.AtespaceExists(ctx, "team-a"); err != nil || ok {
+			t.Fatalf("AtespaceExists before create = (%v, %v), want (false, nil)", ok, err)
+		}
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil {
+			t.Fatalf("CreateAtespace failed: %v", err)
+		}
+		if ok, err := s.AtespaceExists(ctx, "team-a"); err != nil || !ok {
+			t.Fatalf("AtespaceExists after create = (%v, %v), want (true, nil)", ok, err)
+		}
+	})
+
+	t.Run("ListAtespaces", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		names := []string{"team-a", "team-b", "team-c"}
+		for _, n := range names {
+			if _, err := s.CreateAtespace(ctx, newTestAtespace(n)); err != nil {
+				t.Fatalf("CreateAtespace(%s) failed: %v", n, err)
+			}
+		}
+		got, _, err := s.ListAtespaces(ctx, 1000, "")
+		if err != nil {
+			t.Fatalf("ListAtespaces failed: %v", err)
+		}
+		if len(got) != len(names) {
+			t.Fatalf("ListAtespaces returned %d atespaces, want %d", len(got), len(names))
+		}
+		gotNames := map[string]bool{}
+		for _, a := range got {
+			gotNames[a.GetMetadata().GetName()] = true
+		}
+		for _, n := range names {
+			if !gotNames[n] {
+				t.Errorf("ListAtespaces missing %q; got %v", n, gotNames)
+			}
+		}
+	})
+
+	t.Run("ListAtespaces_Empty", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		got, _, err := s.ListAtespaces(ctx, 1000, "")
+		if err != nil {
+			t.Fatalf("ListAtespaces failed: %v", err)
+		}
+		if len(got) != 0 {
+			t.Errorf("ListAtespaces on empty store = %v, want empty", got)
+		}
+	})
+
+	t.Run("DeleteAtespace_Empty", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil {
+			t.Fatalf("CreateAtespace failed: %v", err)
+		}
+		deleted, err := s.DeleteAtespace(ctx, "team-a")
+		if err != nil {
+			t.Fatalf("DeleteAtespace failed: %v", err)
+		}
+		if got := deleted.GetMetadata().GetName(); got != "team-a" {
+			t.Errorf("deleted atespace name = %q, want team-a", got)
+		}
+		if _, err := s.GetAtespace(ctx, "team-a"); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("after delete, GetAtespace = %v, want ErrNotFound", err)
+		}
+	})
+
+	t.Run("DeleteAtespace_NotFound", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.DeleteAtespace(ctx, "nope"); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("expected ErrNotFound, got %v", err)
+		}
+	})
+
+	t.Run("DeleteAtespace_NonEmpty_Rejected", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil {
+			t.Fatalf("CreateAtespace failed: %v", err)
+		}
+		if _, err := s.CreateActor(ctx, &ateapipb.Actor{Metadata: &ateapipb.ResourceMetadata{Name: "id1", Atespace: "team-a"}, Status: ateapipb.Actor_STATUS_SUSPENDED}); err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+		if _, err := s.DeleteAtespace(ctx, "team-a"); !errors.Is(err, store.ErrFailedPrecondition) {
+			t.Errorf("DeleteAtespace on non-empty = %v, want ErrFailedPrecondition", err)
+		}
+		if _, err := s.GetAtespace(ctx, "team-a"); err != nil {
+			t.Errorf("atespace should still exist after rejected delete, got %v", err)
+		}
+	})
+
+	t.Run("DeleteAtespace_EmptyAfterActorsRemoved", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil {
+			t.Fatalf("CreateAtespace failed: %v", err)
+		}
+		if _, err := s.CreateActor(ctx, &ateapipb.Actor{Metadata: &ateapipb.ResourceMetadata{Name: "id1", Atespace: "team-a"}, Status: ateapipb.Actor_STATUS_SUSPENDED}); err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+		if _, err := s.DeleteAtespace(ctx, "team-a"); !errors.Is(err, store.ErrFailedPrecondition) {
+			t.Fatalf("expected rejection while non-empty, got %v", err)
+		}
+		if _, err := s.DeleteActor(ctx, resources.ActorRef{Atespace: "team-a", Name: "id1"}); err != nil {
+			t.Fatalf("DeleteActor failed: %v", err)
+		}
+		if _, err := s.DeleteAtespace(ctx, "team-a"); err != nil {
+			t.Errorf("DeleteAtespace after actor removed = %v, want nil", err)
+		}
+	})
+
+	t.Run("DeleteAtespace_EmptyWhileOtherAtespaceNonEmpty", func(t *testing.T) {
+		s := setup(t)
+		ctx := context.Background()
+
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil {
+			t.Fatalf("CreateAtespace(team-a) failed: %v", err)
+		}
+		if _, err := s.CreateAtespace(ctx, newTestAtespace("team-b")); err != nil {
+			t.Fatalf("CreateAtespace(team-b) failed: %v", err)
+		}
+		if _, err := s.CreateActor(ctx, &ateapipb.Actor{Metadata: &ateapipb.ResourceMetadata{Name: "id1", Atespace: "team-b"}, Status: ateapipb.Actor_STATUS_SUSPENDED}); err != nil {
+			t.Fatalf("CreateActor failed: %v", err)
+		}
+
+		if _, err := s.DeleteAtespace(ctx, "team-a"); err != nil {
+			t.Errorf("DeleteAtespace(team-a, empty) = %v, want nil (must not be blocked by team-b's actor)", err)
+		}
+		if _, err := s.GetAtespace(ctx, "team-a"); !errors.Is(err, store.ErrNotFound) {
+			t.Errorf("after delete, GetAtespace(team-a) = %v, want ErrNotFound", err)
+		}
+		if _, err := s.DeleteAtespace(ctx, "team-b"); !errors.Is(err, store.ErrFailedPrecondition) {
+			t.Errorf("DeleteAtespace(team-b, non-empty) = %v, want ErrFailedPrecondition", err)
+		}
+	})
+}
diff --git a/cmd/ateapi/main.go b/cmd/ateapi/main.go
index 0db329e1f..b752304f9 100644
--- a/cmd/ateapi/main.go
+++ b/cmd/ateapi/main.go
@@ -33,6 +33,8 @@ import (
 	"github.com/agent-substrate/substrate/cmd/ateapi/internal/controlapi"
 	"github.com/agent-substrate/substrate/cmd/ateapi/internal/debugapi"
 	"github.com/agent-substrate/substrate/cmd/ateapi/internal/k8sjwt"
+	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store"
+	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store/atepg"
 	"github.com/agent-substrate/substrate/cmd/ateapi/internal/store/ateredis"
 	"github.com/agent-substrate/substrate/cmd/ateapi/internal/workercache"
 	"github.com/agent-substrate/substrate/internal/ateapiauth"
@@ -71,6 +73,9 @@ var (
 	redisTLSServerName  = pflag.String("redis-tls-server-name", "", "The ServerName to use for Redis TLS hostname verification.")
 	redisClientCert     = pflag.String("redis-client-cert", "", "The file containing client TLS certificate/key credential bundle for Redis/Valkey.")
 
+	storeBackend             = pflag.String("store-backend", "redis", "The persistence backend to use: redis|postgres.")
+	postgresConnectionString = pflag.String("postgres-connection-string", "", "PostgreSQL connection string (libpq DSN or URI), used when --store-backend=postgres.")
+
 	clientJWTIssuer    = pflag.String("client-jwt-issuer", "", "The expected issuer URL for client JWTs.")
 	clientJWTAudience  = pflag.String("client-jwt-audience", "", "The expected audience for client JWTs.")
 	actorIDJWTPoolFile = pflag.String("actor-id-jwt-pool", "", "The file that contains the serialized JWT authority pool for signing actor JWTs")
@@ -119,9 +124,9 @@ func main() {
 	loadFlagsFromEnv()
 	logFlagValues(ctx)
 
-	redisClient, err := connectRedis(ctx)
+	persistence, err := connectStore(ctx)
 	if err != nil {
-		serverboot.Fatal(ctx, "Failed to set up Redis/Valkey", err)
+		serverboot.Fatal(ctx, "Failed to set up persistence backend", err)
 	}
 
 	clientset, ateClient, err := newKubeClients()
@@ -134,9 +139,7 @@ func main() {
 		serverboot.Fatal(ctx, "Failed to build server credentials", err)
 	}
 
-	redisPersistence := ateredis.NewPersistence(redisClient)
-
-	workerCache := workercache.New(redisPersistence, 5*time.Minute)
+	workerCache := workercache.New(persistence, 5*time.Minute)
 	if err := workerCache.Start(ctx); err != nil {
 		serverboot.Fatal(ctx, "Failed to seed worker cache", err)
 	}
@@ -149,7 +152,7 @@ func main() {
 	workerPodInformerFactory, workerPodInformer := controlapi.WorkerPodInformer(clientset)
 	ateletPodInformerFactory, ateletPodInformer := controlapi.AteletInformer(clientset)
 
-	syncer := controlapi.NewWorkerPoolSyncer(redisPersistence, workerPodInformer, workerPoolLister)
+	syncer := controlapi.NewWorkerPoolSyncer(persistence, workerPodInformer, workerPoolLister)
 	syncer.Start(ctx)
 
 	stopCh := make(chan struct{})
@@ -166,13 +169,13 @@ func main() {
 		serverboot.Fatal(ctx, "Failed to register worker-count metric", err)
 	}
 
-	ateletDialer := controlapi.NewAteletDialer(workerPodInformer.GetIndexer(), ateletPodInformer.GetIndexer(), *ateletClientCredBundle, *podIdentityCACerts)
-	sm := controlapi.NewService(redisPersistence, workerCache, actorTemplateLister, workerPoolLister, sandboxConfigLister, ateletDialer, clientset)
+	dialer := controlapi.NewAteletDialer(workerPodInformer.GetIndexer(), ateletPodInformer.GetIndexer(), *ateletClientCredBundle, *podIdentityCACerts)
+	sm := controlapi.NewService(persistence, workerCache, actorTemplateLister, workerPoolLister, sandboxConfigLister, dialer, clientset)
 
 	jwtIssuerDiscoveryClient := buildK8sServiceAccountIssuerDiscoveryClient(ctx, *clientJWTCAFile, *clientJWTIssuer)
 
 	actorIdentitySrv := actoridentity.New(*clientJWTIssuer, *clientJWTAudience, *actorIDJWTPoolFile, *actorIDCAPoolFile, *podIdentityCACerts, jwtIssuerDiscoveryClient)
-	debugSrv := debugapi.NewService(redisPersistence)
+	debugSrv := debugapi.NewService(persistence)
 
 	lisCfg := &net.ListenConfig{}
 	lis, err := lisCfg.Listen(ctx, "tcp", *listenAddr)
@@ -278,6 +281,8 @@ func loadFlagsFromEnv() {
 		{redisUseIAMAuth, "ATE_API_REDIS_USE_IAM_AUTH"},
 		{redisTLSServerName, "ATE_API_REDIS_TLS_SERVER_NAME"},
 		{redisClientCert, "ATE_API_REDIS_CLIENT_CERT"},
+		{storeBackend, "ATE_API_STORE_BACKEND"},
+		{postgresConnectionString, "ATE_API_POSTGRES_CONNECTION_STRING"},
 	}
 	for _, o := range overrides {
 		if *o.flag == "@env" {
@@ -295,6 +300,7 @@ func logFlagValues(ctx context.Context) {
 		slog.String("redis-use-iam-auth", *redisUseIAMAuth),
 		slog.String("redis-tls-server-name", *redisTLSServerName),
 		slog.String("redis-client-cert", *redisClientCert),
+		slog.String("store-backend", *storeBackend),
 		slog.String("client-jwt-issuer", *clientJWTIssuer),
 		slog.String("client-jwt-audience", *clientJWTAudience),
 		slog.String("actor-id-jwt-pool", *actorIDJWTPoolFile),
@@ -306,6 +312,31 @@ func logFlagValues(ctx context.Context) {
 	)
 }
 
+// connectStore builds the store.Interface for the selected --store-backend.
+// Startup fails if the selected backend's configuration is missing or the
+// database can't be reached.
+func connectStore(ctx context.Context) (store.Interface, error) {
+	switch *storeBackend {
+	case "redis":
+		redisClient, err := connectRedis(ctx)
+		if err != nil {
+			return nil, fmt.Errorf("setting up Redis/Valkey: %w", err)
+		}
+		return ateredis.NewPersistence(redisClient), nil
+	case "postgres":
+		if *postgresConnectionString == "" {
+			return nil, fmt.Errorf("--store-backend=postgres requires --postgres-connection-string")
+		}
+		persistence, err := atepg.Connect(ctx, *postgresConnectionString)
+		if err != nil {
+			return nil, fmt.Errorf("setting up PostgreSQL: %w", err)
+		}
+		return persistence, nil
+	default:
+		return nil, fmt.Errorf("unknown --store-backend %q (want redis|postgres)", *storeBackend)
+	}
+}
+
 // connectRedis builds the Redis/Valkey TLS config, plumbs IAM auth if
 // requested, opens the cluster client, and pings with retries.
 func connectRedis(ctx context.Context) (*redis.ClusterClient, error) {
diff --git a/cmd/ateapi/main_test.go b/cmd/ateapi/main_test.go
index 30e702d77..867fd7b90 100644
--- a/cmd/ateapi/main_test.go
+++ b/cmd/ateapi/main_test.go
@@ -15,9 +15,11 @@
 package main
 
 import (
+	"context"
 	"io"
 	"net/http"
 	"os"
+	"strings"
 	"testing"
 )
 
@@ -199,3 +201,29 @@ type roundTripFunc func(*http.Request) (*http.Response, error)
 func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
 	return f(req)
 }
+
+func TestConnectStoreRejectsUnknownBackend(t *testing.T) {
+	oldBackend := *storeBackend
+	t.Cleanup(func() { *storeBackend = oldBackend })
+	*storeBackend = "unknown"
+
+	_, err := connectStore(context.Background())
+	if err == nil || !strings.Contains(err.Error(), `unknown --store-backend "unknown"`) {
+		t.Fatalf("connectStore() error = %v, want unknown-backend error", err)
+	}
+}
+
+func TestConnectStoreRequiresPostgresConnectionString(t *testing.T) {
+	oldBackend, oldDSN := *storeBackend, *postgresConnectionString
+	t.Cleanup(func() {
+		*storeBackend = oldBackend
+		*postgresConnectionString = oldDSN
+	})
+	*storeBackend = "postgres"
+	*postgresConnectionString = ""
+
+	_, err := connectStore(context.Background())
+	if err == nil || !strings.Contains(err.Error(), "requires --postgres-connection-string") {
+		t.Fatalf("connectStore() error = %v, want missing-connection-string error", err)
+	}
+}
diff --git a/go.mod b/go.mod
index 047932c6a..08ef4dab0 100644
--- a/go.mod
+++ b/go.mod
@@ -22,6 +22,7 @@ require (
 	github.com/google/nftables v0.3.0
 	github.com/google/uuid v1.6.0
 	github.com/hashicorp/go-reap v0.0.0-20260220095743-4e27870b4f51
+	github.com/jackc/pgx/v5 v5.10.0
 	github.com/klauspost/compress v1.18.6
 	github.com/myzhan/boomer v1.6.1-0.20250711115830-8a2c7ce4c7b1
 	github.com/myzhan/gomq/zmtp v0.0.0-20220926014711-4eea0d4a1e75
@@ -32,6 +33,7 @@ require (
 	github.com/spf13/cobra v1.10.2
 	github.com/spf13/pflag v1.0.10
 	github.com/spiffe/go-spiffe/v2 v2.6.0
+	github.com/testcontainers/testcontainers-go/modules/postgres v0.43.0
 	github.com/vishvananda/netlink v1.3.1
 	github.com/vishvananda/netns v0.0.5
 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0
@@ -67,9 +69,12 @@ require (
 	cloud.google.com/go/auth v0.19.0 // indirect
 	cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
 	cloud.google.com/go/longrunning v0.9.0 // indirect
+	dario.cat/mergo v1.0.2 // indirect
+	github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
 	github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 // indirect
 	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect
 	github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect
+	github.com/Microsoft/go-winio v0.6.2 // indirect
 	github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef // indirect
 	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10 // indirect
 	github.com/aws/aws-sdk-go-v2/credentials v1.19.16 // indirect
@@ -87,15 +92,24 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect
 	github.com/aws/smithy-go v1.25.1 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
 	github.com/cenkalti/backoff/v5 v5.0.3 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
 	github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect
+	github.com/containerd/errdefs v1.0.0 // indirect
+	github.com/containerd/errdefs/pkg v0.3.0 // indirect
 	github.com/containerd/log v0.1.0 // indirect
+	github.com/containerd/platforms v0.2.1 // indirect
+	github.com/cpuguy83/dockercfg v0.3.2 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+	github.com/distribution/reference v0.6.0 // indirect
 	github.com/docker/cli v29.5.3+incompatible // indirect
 	github.com/docker/docker-credential-helpers v0.9.3 // indirect
+	github.com/docker/go-connections v0.7.0 // indirect
+	github.com/docker/go-units v0.5.0 // indirect
+	github.com/ebitengine/purego v0.10.0 // indirect
 	github.com/emicklei/go-restful/v3 v3.13.0 // indirect
 	github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 // indirect
 	github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect
@@ -131,13 +145,27 @@ require (
 	github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
+	github.com/jackc/pgpassfile v1.0.0 // indirect
+	github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
+	github.com/jackc/puddle/v2 v2.2.2 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
+	github.com/magiconair/properties v1.8.10 // indirect
 	github.com/mattn/go-colorable v0.1.14 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-runewidth v0.0.19 // indirect
 	github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
 	github.com/mdlayher/socket v0.5.0 // indirect
+	github.com/moby/docker-image-spec v1.3.1 // indirect
+	github.com/moby/go-archive v0.2.0 // indirect
+	github.com/moby/moby/api v1.54.2 // indirect
+	github.com/moby/moby/client v0.4.1 // indirect
+	github.com/moby/patternmatcher v0.6.1 // indirect
 	github.com/moby/spdystream v0.5.1 // indirect
+	github.com/moby/sys/sequential v0.6.0 // indirect
+	github.com/moby/sys/user v0.4.0 // indirect
+	github.com/moby/sys/userns v0.1.0 // indirect
+	github.com/moby/term v0.5.2 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -150,13 +178,17 @@ require (
 	github.com/opencontainers/image-spec v1.1.1 // indirect
 	github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
 	github.com/prometheus/client_model v0.6.2 // indirect
 	github.com/prometheus/common v0.67.5 // indirect
 	github.com/prometheus/otlptranslator v1.0.0 // indirect
 	github.com/prometheus/procfs v0.20.1 // indirect
 	github.com/rivo/uniseg v0.2.0 // indirect
 	github.com/shirou/gopsutil v3.21.11+incompatible // indirect
+	github.com/shirou/gopsutil/v4 v4.26.5 // indirect
 	github.com/sirupsen/logrus v1.9.4 // indirect
+	github.com/stretchr/testify v1.11.1 // indirect
+	github.com/testcontainers/testcontainers-go v0.43.0 // indirect
 	github.com/tklauser/go-sysconf v0.4.0 // indirect
 	github.com/tklauser/numcpus v0.12.0 // indirect
 	github.com/ugorji/go/codec v1.3.1 // indirect
@@ -183,7 +215,7 @@ require (
 	google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
-	gotest.tools/v3 v3.5.2 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/klog/v2 v2.140.0 // indirect
 	k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
 	k8s.io/streaming v0.36.1 // indirect
diff --git a/go.sum b/go.sum
index 012e307a1..1f040e407 100644
--- a/go.sum
+++ b/go.sum
@@ -26,6 +26,12 @@ cloud.google.com/go/storage v1.62.1 h1:Os0G3XbUbjZumkpDUf2Y0rLoXJTCF1kU2kWUujKYX
 cloud.google.com/go/storage v1.62.1/go.mod h1:cpYz/kRVZ+UQAF1uHeea10/9ewcRbxGoGNKsS9daSXA=
 cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U=
 cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s=
+dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
+dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 h1:rIkQfkCOVKc1OiRCNcSDD8ml5RJlZbH/Xsq7lbpynwc=
 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0/go.mod h1:RD2SsorTmYhF6HkTmDw7KmPYQk8OBYwTkuasChwv7R4=
 github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8=
@@ -36,6 +42,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp
 github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=
 github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
 github.com/alicebob/miniredis/v2 v2.37.0 h1:RheObYW32G1aiJIj81XVt78ZHJpHonHLHW7OLIshq68=
 github.com/alicebob/miniredis/v2 v2.37.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
@@ -84,6 +92,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
 github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
 github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
 github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
 github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
@@ -92,21 +102,39 @@ github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoK
 github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
 github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=
 github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=
+github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
+github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
+github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
+github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
 github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
 github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
+github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
 github.com/containerd/ttrpc v1.2.8 h1:xbVu6D4qF2jihdh9rDVOKqUMiFBQk6YctTdo1zk087Y=
 github.com/containerd/ttrpc v1.2.8/go.mod h1:wyZW2K79t4Hfcxl+GUvkZqRBzJlqFFvgEeeWXa42tyE=
+github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
+github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
 github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
+github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 github.com/docker/cli v29.5.3+incompatible h1:nbEFfz774vBwQ5KRYv7c/AghjReqnGISvrRhzjV0evs=
 github.com/docker/cli v29.5.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
 github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
+github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
+github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
+github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
 github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
 github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
 github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
@@ -181,6 +209,7 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
 github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
 github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 github.com/google/go-containerregistry v0.21.7 h1:/vPFuVXDjtFREsVArW+0h1CIl5urnOhzei4X2DMW9IU=
@@ -210,6 +239,14 @@ github.com/hashicorp/go-reap v0.0.0-20260220095743-4e27870b4f51 h1:MpKgm7VEcOAD3
 github.com/hashicorp/go-reap v0.0.0-20260220095743-4e27870b4f51/go.mod h1:qIFzeFcJU3OIFk/7JreWXcUjFmcCaeHTH9KoNyHYVCs=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
+github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
+github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
+github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
@@ -222,18 +259,44 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
+github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
+github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
 github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
 github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
 github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI=
+github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o=
 github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg=
 github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o=
 github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
 github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
+github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
+github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg=
+github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
+github.com/moby/moby/client v0.4.1 h1:DMQgisVoMkmMs7fp3ROSdiBnoAu8+vo3GggFl06M/wY=
+github.com/moby/moby/client v0.4.1/go.mod h1:z52C9O2POPOsnxZAy//WtKcQ32P+jT/NGeXu/7nfjGQ=
+github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
+github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
 github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y=
 github.com/moby/spdystream v0.5.1/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
+github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
+github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
+github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
+github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
+github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
+github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
+github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
+github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -275,6 +338,8 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
+github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
 github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
 github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
 github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
@@ -294,6 +359,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
 github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil/v4 v4.26.5 h1:RPcBXkpz7kOj9PqGFQOlBPZHsyaPvPVQc098y9RmCNM=
+github.com/shirou/gopsutil/v4 v4.26.5/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
 github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
 github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
 github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
@@ -304,11 +371,16 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A
 github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
 github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
+github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
 github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/testcontainers/testcontainers-go v0.43.0 h1:oEQx5MW2DGd9z3AeEQfB2lPM0eLs7ztyaGRu75bFo5A=
+github.com/testcontainers/testcontainers-go v0.43.0/go.mod h1:+VxkT2NQnKOZPKi6praMuMKYHYyOGXr0XSBSlSMCzFo=
+github.com/testcontainers/testcontainers-go/modules/postgres v0.43.0 h1:ShNOFYAF4lKHvdIG258hi69bSxC88uXnxJkJvNs/IVs=
+github.com/testcontainers/testcontainers-go/modules/postgres v0.43.0/go.mod h1:vdq5/RqmGfWeefzyfcVI/pID1rzmc1TDvqXa15bPJks=
 github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU=
 github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI=
 github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4=
@@ -382,6 +454,8 @@ golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7
 golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
 golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -395,6 +469,7 @@ golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
 golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
 golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
 golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
 gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
@@ -418,6 +493,7 @@ gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnf
 gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
@@ -440,6 +516,8 @@ k8s.io/streaming v0.36.1 h1:L+K68n4Gg940BGNNYtUBvL1WTLL0YnKT3s+P1MNAmR4=
 k8s.io/streaming v0.36.1/go.mod h1:z6fV3D+NVkoeqRMtWwlUZK6U17SY/LqNzOxWL6GyR/s=
 k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM=
 k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
+pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
+pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
 sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4=
 sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw=
 sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
diff --git a/hack/install-ate.sh b/hack/install-ate.sh
index 871350a0e..eab6fdf91 100755
--- a/hack/install-ate.sh
+++ b/hack/install-ate.sh
@@ -64,7 +64,8 @@ function usage() {
   echo "  --deploy-ate-system                    Deploy core system (CRDs, atelet, apiserver)"
   echo "  --delete-ate-system                    Delete core system"
   echo "  --delete-all                           Delete core system and all registered demos"
-  echo "  --ateapi-client-auth=cert|token               Select how in-cluster clients authenticate to ateapi for --deploy-ate-system (default: cert; the server always accepts both)"
+  echo "  --ateapi-client-auth=cert|token        Select how in-cluster clients authenticate to ateapi for --deploy-ate-system (default: cert; the server always accepts both)"
+  echo "  --store-backend=redis|postgres         Configure the ateapi store backend (default: redis)"
   echo ""
   echo "Infrastructure components:"
   echo ""
@@ -78,9 +79,14 @@ function usage() {
   echo "  --create-jwt-authority-pool-secret     Create JWT authority pool secret"
   echo "  --create-actor-id-ca-pool-secret       Create actor ID CA pool secret"
   echo "  --create-podcertificate-controller-cas Create podcertificate controller CAs"
-  echo "  --create-valkey-ca-certs-secret        Create Valkey CA certs secret"
+  echo "  --create-valkey-ca-certs-secret        Create Valkey's combined client/server CA bundle"
   echo "  --create-api-server-env-vars           Create ate-api-server env vars"
   echo ""
+  echo "PostgreSQL store (standalone operations; normally select it with"
+  echo "--deploy-ate-system --store-backend=postgres):"
+  echo ""
+  echo "  --deploy-postgres                      Deploy the single-replica PostgreSQL StatefulSet"
+  echo ""
   echo "Benchmarks (see benchmarking/README.md for details and customization):"
   echo ""
   echo "  --deploy-benchmarks                    Deploy workloads + locust load test stack"
@@ -145,6 +151,23 @@ ateapi_client_auth() {
   esac
 }
 
+store_backend() {
+  local backend="${ATE_INSTALL_STORE_BACKEND:-${ATE_API_STORE_BACKEND:-redis}}"
+  case "${backend}" in
+    redis|postgres)
+      echo "${backend}"
+      ;;
+    *)
+      echo "Error: store backend must be redis or postgres, got '${backend}'" >&2
+      exit 1
+      ;;
+  esac
+}
+
+default_postgres_connection_string() {
+  echo "postgresql://postgres@postgres.ate-system.svc:5432/atepg?sslmode=verify-full&sslrootcert=/run/servicedns.podcert.ate.dev/trust-bundle.pem&sslcert=/run/podidentity.podcert.ate.dev/credential-bundle.pem&sslkey=/run/podidentity.podcert.ate.dev/credential-bundle.pem"
+}
+
 render_ate_system_manifests() {
   local client_auth=""
   client_auth="$(ateapi_client_auth)"
@@ -179,11 +202,9 @@ ca_pool_root_pem() {
 
 create_valkey_ca_certs_secret() {
   log_step "create_valkey_ca_certs_secret"
-  # valkey requires a single tls-ca-cert-file to verify client and server certs it sees,
-  # so it needs both CAs:
-  #   - servicedns CA: verifies valkey peers' server certs.
-  #   - podidentity CA: verifies the client certs that connect to valkey
-  #     (apiserver, the init job, and peers acting as clients).
+  # Valkey uses one CA file to verify certificates in both directions:
+  #   - servicedns CA: verifies Valkey peers.
+  #   - podidentity CA: verifies clients such as ateapi and Valkey's init job.
   # Extract each root into its own variable: errexit cannot see a substitution
   # failing inside printf's argument list, which would silently produce a CA
   # file with a missing root.
@@ -205,6 +226,27 @@ create_valkey_ca_certs_secret() {
     | run_kubectl apply -f -
 }
 
+# deploy_postgres deploys only the experimental single-replica PostgreSQL
+# StatefulSet. Full-system installs select it with --store-backend=postgres.
+deploy_postgres() {
+  log_step "deploy_postgres"
+  run_kubectl apply -f manifests/ate-install/ate-system-namespace.yaml \
+    && run_kubectl wait --for=jsonpath='{.status.phase}'=Active namespace/ate-system --timeout=60s
+  run_kubectl get secret -n podcertificate-controller-system service-dns-ca-pool >/dev/null 2>&1 \
+    || create_podcertificate_controller_cas
+  run_kubectl get secret -n podcertificate-controller-system pod-identity-ca-pool >/dev/null 2>&1 \
+    || create_podcertificate_controller_cas
+  # The StatefulSet's projected serving certificate is issued by this
+  # controller. Applying it here makes --deploy-postgres usable on a fresh
+  # cluster as well as after --deploy-ate-system.
+  run_ko apply -f manifests/ate-install/pod-certificate-controller.yaml
+  run_kubectl rollout status deployment/podcertificate-controller \
+    -n podcertificate-controller-system --timeout=120s
+  wait_for_podcertificate_trust_bundles
+  run_kubectl apply -f manifests/ate-install/postgres.yaml
+  run_kubectl rollout status statefulset/postgres -n ate-system --timeout=120s
+}
+
 create_jwt_authority_pool_secret() {
   log_step "create_jwt_authority_pool_secret"
   run_kubectl_ate admin make-jwt-pool \
@@ -234,15 +276,31 @@ create_podcertificate_controller_cas() {
     --secret-namespace=podcertificate-controller-system
 }
 
+wait_for_podcertificate_trust_bundles() {
+  echo "Waiting for podcertificate ClusterTrustBundles to be ready..."
+  until run_kubectl get clustertrustbundles podidentity.podcert.ate.dev:identity:primary-bundle >/dev/null 2>&1; do
+    sleep 1
+  done
+  until run_kubectl get clustertrustbundles servicedns.podcert.ate.dev:identity:primary-bundle >/dev/null 2>&1; do
+    sleep 1
+  done
+}
+
 create_api_server_env_vars() {
   log_step "create_api_server_env_vars"
   run_kubectl create namespace ate-system --dry-run=client -o yaml \
     | run_kubectl apply -f -
 
+  local backend=""
   local redis_address=""
   local use_iam_auth="true"
   local tls_server_name=""
   local client_cert=""
+  local postgres_connection_string="${ATE_API_POSTGRES_CONNECTION_STRING:-}"
+  backend="$(store_backend)"
+  if [[ "${backend}" == "postgres" && -z "${postgres_connection_string}" ]]; then
+    postgres_connection_string="$(default_postgres_connection_string)"
+  fi
   redis_address="valkey-cluster.ate-system.svc:6379"
   use_iam_auth="false"
   tls_server_name="valkey-cluster.ate-system.svc"
@@ -250,7 +308,10 @@ create_api_server_env_vars() {
   # (SPIFFE) client cert rather than a servicedns serving cert.
   client_cert="/run/podidentity.podcert.ate.dev/credential-bundle.pem"
 
-  echo "REDIS_ADDRESS: ${redis_address}"
+  echo "STORE_BACKEND: ${backend}"
+  if [[ "${backend}" == "redis" ]]; then
+    echo "REDIS_ADDRESS: ${redis_address}"
+  fi
 
   local jwt_issuer=""
   if [[ -n "${PROJECT_ID:-}" && -n "${CLUSTER_LOCATION:-}" && -n "${CLUSTER_NAME:-}" ]]; then
@@ -268,6 +329,8 @@ create_api_server_env_vars() {
     --from-literal=ATE_API_REDIS_TLS_SERVER_NAME="${tls_server_name}" \
     --from-literal=ATE_API_REDIS_CLIENT_CERT="${client_cert}" \
     --from-literal=ATE_API_K8SJWT_ISSUER="${jwt_issuer}" \
+    --from-literal=ATE_API_STORE_BACKEND="${backend}" \
+    --from-literal=ATE_API_POSTGRES_CONNECTION_STRING="${postgres_connection_string}" \
     --dry-run=client -o yaml \
     | run_kubectl apply -f -
 }
@@ -310,24 +373,33 @@ deploy_ate_system() {
   run_ko apply -f manifests/ate-install/pod-certificate-controller.yaml
   run_kubectl rollout status deployment/podcertificate-controller -n podcertificate-controller-system --timeout=120s
 
-  # Wait for both ClusterTrustBundles to be created by the controller
-  echo "Waiting for podcertificate ClusterTrustBundles to be ready..."
-  until run_kubectl get clustertrustbundles podidentity.podcert.ate.dev:identity:primary-bundle >/dev/null 2>&1; do
-    sleep 1
-  done
-  until run_kubectl get clustertrustbundles servicedns.podcert.ate.dev:identity:primary-bundle >/dev/null 2>&1; do
-    sleep 1
-  done
+  wait_for_podcertificate_trust_bundles
+
+  # The existing Kind and token-client overlays include Valkey but do not
+  # include the opt-in PostgreSQL manifest. Apply PostgreSQL explicitly when
+  # selected so backend configuration and deployed resources cannot diverge.
+  # Store-specific overlay composition can remove the unused Valkey resources
+  # in a separate change.
+  if [[ "$(store_backend)" == "postgres" ]]; then
+    run_kubectl apply -f manifests/ate-install/postgres.yaml
+  fi
 
   local manifests=""
   manifests="$(render_ate_system_manifests)"
   echo "${manifests}" | run_kubectl apply -f -
 
   log_step "Waiting for ATE system components to be ready..."
+  case "$(store_backend)" in
+    redis)
+      run_kubectl rollout status statefulset/valkey-cluster -n ate-system --timeout=120s
+      ;;
+    postgres)
+      run_kubectl rollout status statefulset/postgres -n ate-system --timeout=120s
+      ;;
+  esac
   run_kubectl rollout status deployment/ate-api-server -n ate-system --timeout=120s
   run_kubectl rollout status deployment/ate-controller -n ate-system --timeout=120s
   run_kubectl rollout status deployment/atenet-router -n ate-system --timeout=120s
-  run_kubectl rollout status statefulset/valkey-cluster -n ate-system --timeout=120s
   run_kubectl rollout status daemonset/atelet -n ate-system --timeout=120s
 }
 
@@ -342,8 +414,9 @@ ensure_apiserver_prerequisites() {
     || create_podcertificate_controller_cas
   run_kubectl get secret -n ate-system valkey-ca-certs >/dev/null 2>&1 \
     || create_valkey_ca_certs_secret
-  run_kubectl get configmap -n ate-system ate-api-server-envvars >/dev/null 2>&1 \
-    || create_api_server_env_vars
+  # This ConfigMap carries the selected store backend, so always reconcile it
+  # to make switching --store-backend update an existing installation.
+  create_api_server_env_vars
 }
 
 # Redeploy only the ate-apiserver
@@ -503,6 +576,8 @@ delete_ate_system() {
   else
     run_kubectl delete --ignore-not-found -f manifests/ate-install
   fi
+  run_kubectl delete --ignore-not-found -f manifests/ate-install/valkey.yaml
+  run_kubectl delete --ignore-not-found -f manifests/ate-install/postgres.yaml
   run_kubectl delete --ignore-not-found -f manifests/ate-install/generated
 }
 
@@ -562,6 +637,14 @@ for ((i = 0; i < ${#prescan_args[@]}; i++)); do
       fi
       ATE_ATEAPI_CLIENT_AUTH="${prescan_args[$((i + 1))]}"
       ;;
+    --store-backend=*) ATE_INSTALL_STORE_BACKEND="${prescan_args[i]#*=}" ;;
+    --store-backend)
+      if (( i + 1 >= ${#prescan_args[@]} )); then
+        echo "Error: --store-backend requires redis or postgres" >&2
+        exit 1
+      fi
+      ATE_INSTALL_STORE_BACKEND="${prescan_args[$((i + 1))]}"
+      ;;
     --benchmark-worker-count)
       BENCHMARK_WORKER_COUNT="${prescan_args[i+1]:-1}"
       ;;
@@ -570,6 +653,7 @@ for ((i = 0; i < ${#prescan_args[@]}; i++)); do
       ;;
   esac
 done
+store_backend >/dev/null
 
 while [[ "$#" -gt 0 ]]; do
   # Run ${demo}_cmdline if it exists. If it returns 0, then we successfully
@@ -594,6 +678,15 @@ while [[ "$#" -gt 0 ]]; do
       fi
       ATE_ATEAPI_CLIENT_AUTH="$1"
       ;;
+    --store-backend=*) ATE_INSTALL_STORE_BACKEND="${1#*=}" ;;
+    --store-backend)
+      shift
+      if [[ "$#" -eq 0 ]]; then
+        echo "Error: --store-backend requires redis or postgres" >&2
+        exit 1
+      fi
+      ATE_INSTALL_STORE_BACKEND="$1"
+      ;;
 
     --deploy-ate-system) deploy_ate_system ;;
     --delete-ate-system) delete_ate_system ;;
@@ -617,6 +710,7 @@ while [[ "$#" -gt 0 ]]; do
     --create-podcertificate-controller-cas) create_podcertificate_controller_cas ;;
     --create-valkey-ca-certs-secret) create_valkey_ca_certs_secret ;;
     --create-api-server-env-vars) create_api_server_env_vars ;;
+    --deploy-postgres) deploy_postgres ;;
 
     *)
       # Invalid option, should usage and exit with an error.
diff --git a/manifests/ate-install/ate-api-server.yaml b/manifests/ate-install/ate-api-server.yaml
index 0bb913c86..3a89d2bcd 100644
--- a/manifests/ate-install/ate-api-server.yaml
+++ b/manifests/ate-install/ate-api-server.yaml
@@ -92,10 +92,12 @@ spec:
           - "--grpc-listen-addr=0.0.0.0:443"
           - "--grpc-server-cred-bundle=/run/servicedns.podcert.ate.dev/credential-bundle.pem"
           - --redis-cluster-address=@env
-          - --redis-ca-certs=/etc/valkey-ca/ca.crt
+          - --redis-ca-certs=/run/servicedns.podcert.ate.dev/trust-bundle.pem
           - --redis-use-iam-auth=@env
           - --redis-tls-server-name=@env
           - --redis-client-cert=@env
+          - --store-backend=@env
+          - --postgres-connection-string=@env
           - --client-jwt-issuer=@env
           - --client-jwt-audience=api.ate-system.svc
           - --actor-id-jwt-pool=/run/actor-id-jwt-pool/pool.json
@@ -135,16 +137,12 @@ spec:
         - name: "servicedns"
           mountPath: "/run/servicedns.podcert.ate.dev"
         # podidentity: the apiserver's client identity (SPIFFE) when it dials
-        # valkey and atelet, plus the trust bundle for verifying atelet's
-        # serving certificate.
+        # the selected store and atelet, plus the trust bundle for verifying
+        # atelet's serving certificate.
         - name: "podidentity"
           mountPath: "/run/podidentity.podcert.ate.dev"
         - name: "actor-id-jwt-pool"
           mountPath: "/run/actor-id-jwt-pool"
-        # Note: See README.md for how to generate this secret.
-        - name: "valkey-ca-certs"
-          mountPath: "/etc/valkey-ca"
-          readOnly: true
         - name: "actor-id-ca-pool"
           mountPath: "/run/actor-id-ca-pool"
           readOnly: true
@@ -176,6 +174,12 @@ spec:
               signerName: servicedns.podcert.ate.dev/identity
               keyType: ECDSAP256
               credentialBundlePath: credential-bundle.pem
+          - clusterTrustBundle:
+              signerName: servicedns.podcert.ate.dev/identity
+              labelSelector:
+                matchLabels:
+                  podcert.ate.dev/canarying: live
+              path: trust-bundle.pem
       - name: "podidentity"
         projected:
           sources:
@@ -197,14 +201,6 @@ spec:
               items:
               - key: "pool"
                 path: "pool.json"
-      - name: "valkey-ca-certs"
-        projected:
-          sources:
-          - secret:
-              name: "valkey-ca-certs"
-              items:
-              - key: "ca.crt"
-                path: "ca.crt"
       - name: "actor-id-ca-pool"
         projected:
           sources:
diff --git a/manifests/ate-install/postgres.yaml b/manifests/ate-install/postgres.yaml
new file mode 100644
index 000000000..d2d0c749b
--- /dev/null
+++ b/manifests/ate-install/postgres.yaml
@@ -0,0 +1,182 @@
+# Copyright 2026 Google LLC
+#
+# 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.
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: postgres-config
+  namespace: ate-system
+data:
+  postgresql.conf: |
+    listen_addresses = '*'
+    ssl = on
+    ssl_cert_file = '/run/tls/credential-bundle.pem'
+    ssl_key_file = '/run/tls/credential-bundle.pem'
+    ssl_ca_file = '/run/podidentity.podcert.ate.dev/trust-bundle.pem'
+    hba_file = '/etc/postgresql/pg_hba.conf'
+  pg_hba.conf: |
+    # Local socket access is limited to processes in this pod and is used by
+    # health checks and the workload's idempotent database bootstrap.
+    local all all trust
+    # Auth mirrors valkey.yaml's model. PostgreSQL does not need its own serving
+    # CA here because it never verifies its own server certificate.
+    hostssl all all all trust clientcert=verify-ca
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: postgres
+  namespace: ate-system
+spec:
+  clusterIP: None
+  selector:
+    app: postgres
+  ports:
+  - name: postgres
+    port: 5432
+    targetPort: 5432
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: postgres
+  namespace: ate-system
+spec:
+  serviceName: postgres
+  replicas: 1
+  selector:
+    matchLabels:
+      app: postgres
+  template:
+    metadata:
+      labels:
+        app: postgres
+    spec:
+      # The official postgres image requires ssl_key_file to contain only a
+      # private key with restrictive (0600) permissions. The projected
+      # podCertificate source is world-readable, so copy it into a writable
+      # emptyDir and fix permissions/ownership before postgres starts
+      # See https://www.postgresql.org/docs/current/ssl-tcp.html#SSL-SETUP
+      initContainers:
+      - name: fix-tls-perms
+        image: postgres:18-alpine@sha256:9a8afca54e7861fd90fab5fdf4c42477a6b1cb7d293595148e674e0a3181de15
+        securityContext:
+          runAsUser: 70
+        command:
+        - /bin/sh
+        - -c
+        - |
+          set -e
+          cp /run/servicedns.podcert.ate.dev/credential-bundle.pem /run/tls/credential-bundle.pem
+          chmod 600 /run/tls/credential-bundle.pem
+        volumeMounts:
+        - name: servicedns
+          mountPath: /run/servicedns.podcert.ate.dev
+        - name: tls
+          mountPath: /run/tls
+      containers:
+      - name: postgres
+        image: postgres:18-alpine@sha256:9a8afca54e7861fd90fab5fdf4c42477a6b1cb7d293595148e674e0a3181de15
+        lifecycle:
+          postStart:
+            exec:
+              command:
+              - /bin/sh
+              - -ec
+              - |
+                until psql -U postgres -d postgres -Atc 'SELECT 1' >/dev/null 2>&1; do
+                  sleep 1
+                done
+                if ! psql -U postgres -d postgres -Atc \
+                  "SELECT 1 FROM pg_database WHERE datname = 'atepg'" | grep -qx 1; then
+                  createdb -U postgres atepg
+                fi
+        env:
+        - name: POSTGRES_DB
+          value: atepg
+        - name: POSTGRES_HOST_AUTH_METHOD
+          value: trust
+        - name: PGDATA
+          value: /var/lib/postgresql/data/pgdata
+        ports:
+        - name: postgres
+          containerPort: 5432
+        readinessProbe:
+          exec:
+            command:
+            - /bin/sh
+            - -ec
+            - psql -U postgres -d atepg -Atc 'SELECT 1' >/dev/null
+          initialDelaySeconds: 2
+          periodSeconds: 2
+        livenessProbe:
+          exec:
+            command:
+            - pg_isready
+            - -U
+            - postgres
+            - -d
+            - postgres
+          initialDelaySeconds: 10
+          periodSeconds: 10
+        args:
+        - -c
+        - config_file=/etc/postgresql/postgresql.conf
+        volumeMounts:
+        - name: config
+          mountPath: /etc/postgresql
+        - name: tls
+          mountPath: /run/tls
+        - name: podidentity-ca
+          mountPath: /run/podidentity.podcert.ate.dev
+          readOnly: true
+        - name: data
+          mountPath: /var/lib/postgresql/data
+        resources:
+          requests:
+            cpu: "1"
+            memory: "1Gi"
+          limits:
+            cpu: "2"
+            memory: "2Gi"
+      volumes:
+      - name: config
+        configMap:
+          name: postgres-config
+      - name: servicedns
+        projected:
+          sources:
+          - podCertificate:
+              signerName: servicedns.podcert.ate.dev/identity
+              keyType: ECDSAP256
+              credentialBundlePath: credential-bundle.pem
+      - name: tls
+        emptyDir: {}
+      - name: podidentity-ca
+        projected:
+          sources:
+          - clusterTrustBundle:
+              signerName: podidentity.podcert.ate.dev/identity
+              labelSelector:
+                matchLabels:
+                  podcert.ate.dev/canarying: live
+              path: trust-bundle.pem
+  volumeClaimTemplates:
+  - metadata:
+      name: data
+    spec:
+      accessModes: [ "ReadWriteOnce" ]
+      resources:
+        requests:
+          storage: 1Gi
diff --git a/vendor/dario.cat/mergo/.deepsource.toml b/vendor/dario.cat/mergo/.deepsource.toml
new file mode 100644
index 000000000..a8bc979e0
--- /dev/null
+++ b/vendor/dario.cat/mergo/.deepsource.toml
@@ -0,0 +1,12 @@
+version = 1
+
+test_patterns = [
+  "*_test.go"
+]
+
+[[analyzers]]
+name = "go"
+enabled = true
+
+  [analyzers.meta]
+  import_path = "dario.cat/mergo"
\ No newline at end of file
diff --git a/vendor/dario.cat/mergo/.gitignore b/vendor/dario.cat/mergo/.gitignore
new file mode 100644
index 000000000..45ad0f1ae
--- /dev/null
+++ b/vendor/dario.cat/mergo/.gitignore
@@ -0,0 +1,36 @@
+#### joe made this: http://goel.io/joe
+
+#### go ####
+# Binaries for programs and plugins
+*.exe
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Golang/Intellij
+.idea
+
+# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
+.glide/
+
+#### vim ####
+# Swap
+[._]*.s[a-v][a-z]
+[._]*.sw[a-p]
+[._]s[a-v][a-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+
+# Temporary
+.netrwhist
+*~
+# Auto-generated tag files
+tags
diff --git a/vendor/dario.cat/mergo/.travis.yml b/vendor/dario.cat/mergo/.travis.yml
new file mode 100644
index 000000000..d324c43ba
--- /dev/null
+++ b/vendor/dario.cat/mergo/.travis.yml
@@ -0,0 +1,12 @@
+language: go
+arch:
+    - amd64
+    - ppc64le
+install:
+  - go get -t
+  - go get golang.org/x/tools/cmd/cover
+  - go get github.com/mattn/goveralls
+script:
+  - go test -race -v ./...
+after_script:
+  - $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN
diff --git a/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..469b44907
--- /dev/null
+++ b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/vendor/dario.cat/mergo/CONTRIBUTING.md b/vendor/dario.cat/mergo/CONTRIBUTING.md
new file mode 100644
index 000000000..0a1ff9f94
--- /dev/null
+++ b/vendor/dario.cat/mergo/CONTRIBUTING.md
@@ -0,0 +1,112 @@
+<!-- omit in toc -->
+# Contributing to mergo
+
+First off, thanks for taking the time to contribute! ❤️
+
+All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
+
+> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
+> - Star the project
+> - Tweet about it
+> - Refer this project in your project's readme
+> - Mention the project at local meetups and tell your friends/colleagues
+
+<!-- omit in toc -->
+## Table of Contents
+
+- [Code of Conduct](#code-of-conduct)
+- [I Have a Question](#i-have-a-question)
+- [I Want To Contribute](#i-want-to-contribute)
+- [Reporting Bugs](#reporting-bugs)
+- [Suggesting Enhancements](#suggesting-enhancements)
+
+## Code of Conduct
+
+This project and everyone participating in it is governed by the
+[mergo Code of Conduct](https://github.com/imdario/mergoblob/master/CODE_OF_CONDUCT.md).
+By participating, you are expected to uphold this code. Please report unacceptable behavior
+to <>.
+
+
+## I Have a Question
+
+> If you want to ask a question, we assume that you have read the available [Documentation](https://pkg.go.dev/github.com/imdario/mergo).
+
+Before you ask a question, it is best to search for existing [Issues](https://github.com/imdario/mergo/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
+
+If you then still feel the need to ask a question and need clarification, we recommend the following:
+
+- Open an [Issue](https://github.com/imdario/mergo/issues/new).
+- Provide as much context as you can about what you're running into.
+- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
+
+We will then take care of the issue as soon as possible.
+
+## I Want To Contribute
+
+> ### Legal Notice <!-- omit in toc -->
+> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
+
+### Reporting Bugs
+
+<!-- omit in toc -->
+#### Before Submitting a Bug Report
+
+A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
+
+- Make sure that you are using the latest version.
+- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](). If you are looking for support, you might want to check [this section](#i-have-a-question)).
+- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/imdario/mergoissues?q=label%3Abug).
+- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
+- Collect information about the bug:
+- Stack trace (Traceback)
+- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
+- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
+- Possibly your input and the output
+- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
+
+<!-- omit in toc -->
+#### How Do I Submit a Good Bug Report?
+
+> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to .
+<!-- You may add a PGP key to allow the messages to be sent encrypted as well. -->
+
+We use GitHub issues to track bugs and errors. If you run into an issue with the project:
+
+- Open an [Issue](https://github.com/imdario/mergo/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
+- Explain the behavior you would expect and the actual behavior.
+- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
+- Provide the information you collected in the previous section.
+
+Once it's filed:
+
+- The project team will label the issue accordingly.
+- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
+- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be implemented by someone.
+
+### Suggesting Enhancements
+
+This section guides you through submitting an enhancement suggestion for mergo, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
+
+<!-- omit in toc -->
+#### Before Submitting an Enhancement
+
+- Make sure that you are using the latest version.
+- Read the [documentation]() carefully and find out if the functionality is already covered, maybe by an individual configuration.
+- Perform a [search](https://github.com/imdario/mergo/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
+- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
+
+<!-- omit in toc -->
+#### How Do I Submit a Good Enhancement Suggestion?
+
+Enhancement suggestions are tracked as [GitHub issues](https://github.com/imdario/mergo/issues).
+
+- Use a **clear and descriptive title** for the issue to identify the suggestion.
+- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
+- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
+- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. <!-- this should only be included if the project has a GUI -->
+- **Explain why this enhancement would be useful** to most mergo users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
+
+<!-- omit in toc -->
+## Attribution
+This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!
diff --git a/vendor/dario.cat/mergo/FUNDING.json b/vendor/dario.cat/mergo/FUNDING.json
new file mode 100644
index 000000000..0585e1fe1
--- /dev/null
+++ b/vendor/dario.cat/mergo/FUNDING.json
@@ -0,0 +1,7 @@
+{
+  "drips": {
+    "ethereum": {
+      "ownedBy": "0x6160020e7102237aC41bdb156e94401692D76930"
+    }
+  }
+}
diff --git a/vendor/dario.cat/mergo/LICENSE b/vendor/dario.cat/mergo/LICENSE
new file mode 100644
index 000000000..686680298
--- /dev/null
+++ b/vendor/dario.cat/mergo/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2013 Dario Castañé. All rights reserved.
+Copyright (c) 2012 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/dario.cat/mergo/README.md b/vendor/dario.cat/mergo/README.md
new file mode 100644
index 000000000..0e4a59afd
--- /dev/null
+++ b/vendor/dario.cat/mergo/README.md
@@ -0,0 +1,253 @@
+# Mergo
+
+[![GitHub release][5]][6]
+[![GoCard][7]][8]
+[![Test status][1]][2]
+[![OpenSSF Scorecard][21]][22]
+[![OpenSSF Best Practices][19]][20]
+[![Coverage status][9]][10]
+[![Sourcegraph][11]][12]
+[![FOSSA status][13]][14]
+
+[![GoDoc][3]][4]
+[![Become my sponsor][15]][16]
+[![Tidelift][17]][18]
+
+[1]: https://github.com/imdario/mergo/workflows/tests/badge.svg?branch=master
+[2]: https://github.com/imdario/mergo/actions/workflows/tests.yml
+[3]: https://godoc.org/github.com/imdario/mergo?status.svg
+[4]: https://godoc.org/github.com/imdario/mergo
+[5]: https://img.shields.io/github/release/imdario/mergo.svg
+[6]: https://github.com/imdario/mergo/releases
+[7]: https://goreportcard.com/badge/imdario/mergo
+[8]: https://goreportcard.com/report/github.com/imdario/mergo
+[9]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
+[10]: https://coveralls.io/github/imdario/mergo?branch=master
+[11]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
+[12]: https://sourcegraph.com/github.com/imdario/mergo?badge
+[13]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield
+[14]: https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield
+[15]: https://img.shields.io/github/sponsors/imdario
+[16]: https://github.com/sponsors/imdario
+[17]: https://tidelift.com/badges/package/go/github.com%2Fimdario%2Fmergo
+[18]: https://tidelift.com/subscription/pkg/go-github.com-imdario-mergo
+[19]: https://bestpractices.coreinfrastructure.org/projects/7177/badge
+[20]: https://bestpractices.coreinfrastructure.org/projects/7177
+[21]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo/badge
+[22]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo
+
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
+
+Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
+
+## Status
+
+Mergo is stable and frozen, ready for production. Check a short list of the projects using at large scale it [here](https://github.com/imdario/mergo#mergo-in-the-wild).
+
+No new features are accepted. They will be considered for a future v2 that improves the implementation and fixes bugs for corner cases.
+
+### Important notes
+
+#### 1.0.0
+
+In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`. No more v1 versions will be released.
+
+If the vanity URL is causing issues in your project due to a dependency pulling Mergo - it isn't a direct dependency in your project - it is recommended to use [replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to pin the version to the last one with the old import URL:
+
+```
+replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
+```
+
+#### 0.3.9
+
+Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds support for go modules.
+
+Keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2), Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). I added an optional/variadic argument so that it won't break the existing code.
+
+If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u dario.cat/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
+
+### Donations
+
+If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
+
+<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
+<a href='https://github.com/sponsors/imdario' target='_blank'><img alt="Become my sponsor" src="https://img.shields.io/github/sponsors/imdario?style=for-the-badge" /></a>
+
+### Mergo in the wild
+
+Mergo is used by [thousands](https://deps.dev/go/dario.cat%2Fmergo/v1.0.0/dependents) [of](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.16/dependents) [projects](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.12), including:
+
+* [containerd/containerd](https://github.com/containerd/containerd)
+* [datadog/datadog-agent](https://github.com/datadog/datadog-agent)
+* [docker/cli/](https://github.com/docker/cli/)
+* [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
+* [go-micro/go-micro](https://github.com/go-micro/go-micro)
+* [grafana/loki](https://github.com/grafana/loki)
+* [masterminds/sprig](github.com/Masterminds/sprig)
+* [moby/moby](https://github.com/moby/moby)
+* [slackhq/nebula](https://github.com/slackhq/nebula)
+* [volcano-sh/volcano](https://github.com/volcano-sh/volcano)
+
+## Install
+
+    go get dario.cat/mergo
+
+    // use in your .go code
+    import (
+        "dario.cat/mergo"
+    )
+
+## Usage
+
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are zero values](https://golang.org/ref/spec#The_zero_value) too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+
+```go
+if err := mergo.Merge(&dst, src); err != nil {
+    // ...
+}
+```
+
+Also, you can merge overwriting values using the transformer `WithOverride`.
+
+```go
+if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
+    // ...
+}
+```
+
+If you need to override pointers, so the source pointer's value is assigned to the destination's pointer, you must use `WithoutDereference`:
+
+```go
+package main
+
+import (
+	"fmt"
+
+	"dario.cat/mergo"
+)
+
+type Foo struct {
+	A *string
+	B int64
+}
+
+func main() {
+	first := "first"
+	second := "second"
+	src := Foo{
+		A: &first,
+		B: 2,
+	}
+
+	dest := Foo{
+		A: &second,
+		B: 1,
+	}
+
+	mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithoutDereference)
+}
+```
+
+Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
+
+```go
+if err := mergo.Map(&dst, srcMap); err != nil {
+    // ...
+}
+```
+
+Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values.
+
+Here is a nice example:
+
+```go
+package main
+
+import (
+	"fmt"
+	"dario.cat/mergo"
+)
+
+type Foo struct {
+	A string
+	B int64
+}
+
+func main() {
+	src := Foo{
+		A: "one",
+		B: 2,
+	}
+	dest := Foo{
+		A: "two",
+	}
+	mergo.Merge(&dest, src)
+	fmt.Println(dest)
+	// Will print
+	// {two 2}
+}
+```
+
+### Transformers
+
+Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`?
+
+```go
+package main
+
+import (
+	"fmt"
+	"dario.cat/mergo"
+    "reflect"
+    "time"
+)
+
+type timeTransformer struct {
+}
+
+func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+	if typ == reflect.TypeOf(time.Time{}) {
+		return func(dst, src reflect.Value) error {
+			if dst.CanSet() {
+				isZero := dst.MethodByName("IsZero")
+				result := isZero.Call([]reflect.Value{})
+				if result[0].Bool() {
+					dst.Set(src)
+				}
+			}
+			return nil
+		}
+	}
+	return nil
+}
+
+type Snapshot struct {
+	Time time.Time
+	// ...
+}
+
+func main() {
+	src := Snapshot{time.Now()}
+	dest := Snapshot{}
+	mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
+	fmt.Println(dest)
+	// Will print
+	// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
+}
+```
+
+## Contact me
+
+If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
+
+## About
+
+Written by [Dario Castañé](http://dario.im).
+
+## License
+
+[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
+
+[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_large)
diff --git a/vendor/dario.cat/mergo/SECURITY.md b/vendor/dario.cat/mergo/SECURITY.md
new file mode 100644
index 000000000..3788fcc1c
--- /dev/null
+++ b/vendor/dario.cat/mergo/SECURITY.md
@@ -0,0 +1,14 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 1.x.x   | :white_check_mark: |
+| < 1.0   | :x:                |
+
+## Security contact information
+
+To report a security vulnerability, please use the
+[Tidelift security contact](https://tidelift.com/security).
+Tidelift will coordinate the fix and disclosure.
diff --git a/vendor/dario.cat/mergo/doc.go b/vendor/dario.cat/mergo/doc.go
new file mode 100644
index 000000000..7d96ec054
--- /dev/null
+++ b/vendor/dario.cat/mergo/doc.go
@@ -0,0 +1,148 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
+
+Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+# Status
+
+It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc.
+
+# Important notes
+
+1.0.0
+
+In 1.0.0 Mergo moves to a vanity URL `dario.cat/mergo`.
+
+0.3.9
+
+Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules.
+
+Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to support transformers. We added an optional/variadic argument so that it won't break the existing code.
+
+If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u dario.cat/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
+
+# Install
+
+Do your usual installation procedure:
+
+	go get dario.cat/mergo
+
+	// use in your .go code
+	import (
+	    "dario.cat/mergo"
+	)
+
+# Usage
+
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+
+	if err := mergo.Merge(&dst, src); err != nil {
+		// ...
+	}
+
+Also, you can merge overwriting values using the transformer WithOverride.
+
+	if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
+		// ...
+	}
+
+Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field.
+
+	if err := mergo.Map(&dst, srcMap); err != nil {
+		// ...
+	}
+
+Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values.
+
+Here is a nice example:
+
+	package main
+
+	import (
+		"fmt"
+		"dario.cat/mergo"
+	)
+
+	type Foo struct {
+		A string
+		B int64
+	}
+
+	func main() {
+		src := Foo{
+			A: "one",
+			B: 2,
+		}
+		dest := Foo{
+			A: "two",
+		}
+		mergo.Merge(&dest, src)
+		fmt.Println(dest)
+		// Will print
+		// {two 2}
+	}
+
+# Transformers
+
+Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time?
+
+	package main
+
+	import (
+		"fmt"
+		"dario.cat/mergo"
+		"reflect"
+		"time"
+	)
+
+	type timeTransformer struct {
+	}
+
+	func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+		if typ == reflect.TypeOf(time.Time{}) {
+			return func(dst, src reflect.Value) error {
+				if dst.CanSet() {
+					isZero := dst.MethodByName("IsZero")
+					result := isZero.Call([]reflect.Value{})
+					if result[0].Bool() {
+						dst.Set(src)
+					}
+				}
+				return nil
+			}
+		}
+		return nil
+	}
+
+	type Snapshot struct {
+		Time time.Time
+		// ...
+	}
+
+	func main() {
+		src := Snapshot{time.Now()}
+		dest := Snapshot{}
+		mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
+		fmt.Println(dest)
+		// Will print
+		// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
+	}
+
+# Contact me
+
+If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario
+
+# About
+
+Written by Dario Castañé: https://da.rio.hn
+
+# License
+
+BSD 3-Clause license, as Go language.
+*/
+package mergo
diff --git a/vendor/dario.cat/mergo/map.go b/vendor/dario.cat/mergo/map.go
new file mode 100644
index 000000000..759b4f74f
--- /dev/null
+++ b/vendor/dario.cat/mergo/map.go
@@ -0,0 +1,178 @@
+// Copyright 2014 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+	"fmt"
+	"reflect"
+	"unicode"
+	"unicode/utf8"
+)
+
+func changeInitialCase(s string, mapper func(rune) rune) string {
+	if s == "" {
+		return s
+	}
+	r, n := utf8.DecodeRuneInString(s)
+	return string(mapper(r)) + s[n:]
+}
+
+func isExported(field reflect.StructField) bool {
+	r, _ := utf8.DecodeRuneInString(field.Name)
+	return r >= 'A' && r <= 'Z'
+}
+
+// Traverses recursively both values, assigning src's fields values to dst.
+// The map argument tracks comparisons that have already been seen, which allows
+// short circuiting on recursive types.
+func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
+	overwrite := config.Overwrite
+	if dst.CanAddr() {
+		addr := dst.UnsafeAddr()
+		h := 17 * addr
+		seen := visited[h]
+		typ := dst.Type()
+		for p := seen; p != nil; p = p.next {
+			if p.ptr == addr && p.typ == typ {
+				return nil
+			}
+		}
+		// Remember, remember...
+		visited[h] = &visit{typ, seen, addr}
+	}
+	zeroValue := reflect.Value{}
+	switch dst.Kind() {
+	case reflect.Map:
+		dstMap := dst.Interface().(map[string]interface{})
+		for i, n := 0, src.NumField(); i < n; i++ {
+			srcType := src.Type()
+			field := srcType.Field(i)
+			if !isExported(field) {
+				continue
+			}
+			fieldName := field.Name
+			fieldName = changeInitialCase(fieldName, unicode.ToLower)
+			if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) || config.overwriteWithEmptyValue {
+				dstMap[fieldName] = src.Field(i).Interface()
+			}
+		}
+	case reflect.Ptr:
+		if dst.IsNil() {
+			v := reflect.New(dst.Type().Elem())
+			dst.Set(v)
+		}
+		dst = dst.Elem()
+		fallthrough
+	case reflect.Struct:
+		srcMap := src.Interface().(map[string]interface{})
+		for key := range srcMap {
+			config.overwriteWithEmptyValue = true
+			srcValue := srcMap[key]
+			fieldName := changeInitialCase(key, unicode.ToUpper)
+			dstElement := dst.FieldByName(fieldName)
+			if dstElement == zeroValue {
+				// We discard it because the field doesn't exist.
+				continue
+			}
+			srcElement := reflect.ValueOf(srcValue)
+			dstKind := dstElement.Kind()
+			srcKind := srcElement.Kind()
+			if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
+				srcElement = srcElement.Elem()
+				srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
+			} else if dstKind == reflect.Ptr {
+				// Can this work? I guess it can't.
+				if srcKind != reflect.Ptr && srcElement.CanAddr() {
+					srcPtr := srcElement.Addr()
+					srcElement = reflect.ValueOf(srcPtr)
+					srcKind = reflect.Ptr
+				}
+			}
+
+			if !srcElement.IsValid() {
+				continue
+			}
+			if srcKind == dstKind {
+				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+					return
+				}
+			} else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
+				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+					return
+				}
+			} else if srcKind == reflect.Map {
+				if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
+					return
+				}
+			} else {
+				return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
+			}
+		}
+	}
+	return
+}
+
+// Map sets fields' values in dst from src.
+// src can be a map with string keys or a struct. dst must be the opposite:
+// if src is a map, dst must be a valid pointer to struct. If src is a struct,
+// dst must be map[string]interface{}.
+// It won't merge unexported (private) fields and will do recursively
+// any exported field.
+// If dst is a map, keys will be src fields' names in lower camel case.
+// Missing key in src that doesn't match a field in dst will be skipped. This
+// doesn't apply if dst is a map.
+// This is separated method from Merge because it is cleaner and it keeps sane
+// semantics: merging equal types, mapping different (restricted) types.
+func Map(dst, src interface{}, opts ...func(*Config)) error {
+	return _map(dst, src, opts...)
+}
+
+// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
+// non-empty src attribute values.
+// Deprecated: Use Map(…) with WithOverride
+func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
+	return _map(dst, src, append(opts, WithOverride)...)
+}
+
+func _map(dst, src interface{}, opts ...func(*Config)) error {
+	if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
+		return ErrNonPointerArgument
+	}
+	var (
+		vDst, vSrc reflect.Value
+		err        error
+	)
+	config := &Config{}
+
+	for _, opt := range opts {
+		opt(config)
+	}
+
+	if vDst, vSrc, err = resolveValues(dst, src); err != nil {
+		return err
+	}
+	// To be friction-less, we redirect equal-type arguments
+	// to deepMerge. Only because arguments can be anything.
+	if vSrc.Kind() == vDst.Kind() {
+		return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+	}
+	switch vSrc.Kind() {
+	case reflect.Struct:
+		if vDst.Kind() != reflect.Map {
+			return ErrExpectedMapAsDestination
+		}
+	case reflect.Map:
+		if vDst.Kind() != reflect.Struct {
+			return ErrExpectedStructAsDestination
+		}
+	default:
+		return ErrNotSupported
+	}
+	return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+}
diff --git a/vendor/dario.cat/mergo/merge.go b/vendor/dario.cat/mergo/merge.go
new file mode 100644
index 000000000..fd47c95b2
--- /dev/null
+++ b/vendor/dario.cat/mergo/merge.go
@@ -0,0 +1,409 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+	"fmt"
+	"reflect"
+)
+
+func hasMergeableFields(dst reflect.Value) (exported bool) {
+	for i, n := 0, dst.NumField(); i < n; i++ {
+		field := dst.Type().Field(i)
+		if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
+			exported = exported || hasMergeableFields(dst.Field(i))
+		} else if isExportedComponent(&field) {
+			exported = exported || len(field.PkgPath) == 0
+		}
+	}
+	return
+}
+
+func isExportedComponent(field *reflect.StructField) bool {
+	pkgPath := field.PkgPath
+	if len(pkgPath) > 0 {
+		return false
+	}
+	c := field.Name[0]
+	if 'a' <= c && c <= 'z' || c == '_' {
+		return false
+	}
+	return true
+}
+
+type Config struct {
+	Transformers                 Transformers
+	Overwrite                    bool
+	ShouldNotDereference         bool
+	AppendSlice                  bool
+	TypeCheck                    bool
+	overwriteWithEmptyValue      bool
+	overwriteSliceWithEmptyValue bool
+	sliceDeepCopy                bool
+	debug                        bool
+}
+
+type Transformers interface {
+	Transformer(reflect.Type) func(dst, src reflect.Value) error
+}
+
+// Traverses recursively both values, assigning src's fields values to dst.
+// The map argument tracks comparisons that have already been seen, which allows
+// short circuiting on recursive types.
+func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
+	overwrite := config.Overwrite
+	typeCheck := config.TypeCheck
+	overwriteWithEmptySrc := config.overwriteWithEmptyValue
+	overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
+	sliceDeepCopy := config.sliceDeepCopy
+
+	if !src.IsValid() {
+		return
+	}
+	if dst.CanAddr() {
+		addr := dst.UnsafeAddr()
+		h := 17 * addr
+		seen := visited[h]
+		typ := dst.Type()
+		for p := seen; p != nil; p = p.next {
+			if p.ptr == addr && p.typ == typ {
+				return nil
+			}
+		}
+		// Remember, remember...
+		visited[h] = &visit{typ, seen, addr}
+	}
+
+	if config.Transformers != nil && !isReflectNil(dst) && dst.IsValid() {
+		if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
+			err = fn(dst, src)
+			return
+		}
+	}
+
+	switch dst.Kind() {
+	case reflect.Struct:
+		if hasMergeableFields(dst) {
+			for i, n := 0, dst.NumField(); i < n; i++ {
+				if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
+					return
+				}
+			}
+		} else {
+			if dst.CanSet() && (isReflectNil(dst) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc) {
+				dst.Set(src)
+			}
+		}
+	case reflect.Map:
+		if dst.IsNil() && !src.IsNil() {
+			if dst.CanSet() {
+				dst.Set(reflect.MakeMap(dst.Type()))
+			} else {
+				dst = src
+				return
+			}
+		}
+
+		if src.Kind() != reflect.Map {
+			if overwrite && dst.CanSet() {
+				dst.Set(src)
+			}
+			return
+		}
+
+		for _, key := range src.MapKeys() {
+			srcElement := src.MapIndex(key)
+			if !srcElement.IsValid() {
+				continue
+			}
+			dstElement := dst.MapIndex(key)
+			switch srcElement.Kind() {
+			case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
+				if srcElement.IsNil() {
+					if overwrite {
+						dst.SetMapIndex(key, srcElement)
+					}
+					continue
+				}
+				fallthrough
+			default:
+				if !srcElement.CanInterface() {
+					continue
+				}
+				switch reflect.TypeOf(srcElement.Interface()).Kind() {
+				case reflect.Struct:
+					fallthrough
+				case reflect.Ptr:
+					fallthrough
+				case reflect.Map:
+					srcMapElm := srcElement
+					dstMapElm := dstElement
+					if srcMapElm.CanInterface() {
+						srcMapElm = reflect.ValueOf(srcMapElm.Interface())
+						if dstMapElm.IsValid() {
+							dstMapElm = reflect.ValueOf(dstMapElm.Interface())
+						}
+					}
+					if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
+						return
+					}
+				case reflect.Slice:
+					srcSlice := reflect.ValueOf(srcElement.Interface())
+
+					var dstSlice reflect.Value
+					if !dstElement.IsValid() || dstElement.IsNil() {
+						dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
+					} else {
+						dstSlice = reflect.ValueOf(dstElement.Interface())
+					}
+
+					if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
+						if typeCheck && srcSlice.Type() != dstSlice.Type() {
+							return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+						}
+						dstSlice = srcSlice
+					} else if config.AppendSlice {
+						if srcSlice.Type() != dstSlice.Type() {
+							return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+						}
+						dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
+					} else if sliceDeepCopy {
+						i := 0
+						for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ {
+							srcElement := srcSlice.Index(i)
+							dstElement := dstSlice.Index(i)
+
+							if srcElement.CanInterface() {
+								srcElement = reflect.ValueOf(srcElement.Interface())
+							}
+							if dstElement.CanInterface() {
+								dstElement = reflect.ValueOf(dstElement.Interface())
+							}
+
+							if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+								return
+							}
+						}
+
+					}
+					dst.SetMapIndex(key, dstSlice)
+				}
+			}
+
+			if dstElement.IsValid() && !isEmptyValue(dstElement, !config.ShouldNotDereference) {
+				if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice {
+					continue
+				}
+				if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map && reflect.TypeOf(dstElement.Interface()).Kind() == reflect.Map {
+					continue
+				}
+			}
+
+			if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement, !config.ShouldNotDereference)) {
+				if dst.IsNil() {
+					dst.Set(reflect.MakeMap(dst.Type()))
+				}
+				dst.SetMapIndex(key, srcElement)
+			}
+		}
+
+		// Ensure that all keys in dst are deleted if they are not in src.
+		if overwriteWithEmptySrc {
+			for _, key := range dst.MapKeys() {
+				srcElement := src.MapIndex(key)
+				if !srcElement.IsValid() {
+					dst.SetMapIndex(key, reflect.Value{})
+				}
+			}
+		}
+	case reflect.Slice:
+		if !dst.CanSet() {
+			break
+		}
+		if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
+			dst.Set(src)
+		} else if config.AppendSlice {
+			if src.Type() != dst.Type() {
+				return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
+			}
+			dst.Set(reflect.AppendSlice(dst, src))
+		} else if sliceDeepCopy {
+			for i := 0; i < src.Len() && i < dst.Len(); i++ {
+				srcElement := src.Index(i)
+				dstElement := dst.Index(i)
+				if srcElement.CanInterface() {
+					srcElement = reflect.ValueOf(srcElement.Interface())
+				}
+				if dstElement.CanInterface() {
+					dstElement = reflect.ValueOf(dstElement.Interface())
+				}
+
+				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+					return
+				}
+			}
+		}
+	case reflect.Ptr:
+		fallthrough
+	case reflect.Interface:
+		if isReflectNil(src) {
+			if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) {
+				dst.Set(src)
+			}
+			break
+		}
+
+		if src.Kind() != reflect.Interface {
+			if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
+				if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
+					dst.Set(src)
+				}
+			} else if src.Kind() == reflect.Ptr {
+				if !config.ShouldNotDereference {
+					if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+						return
+					}
+				} else if src.Elem().Kind() != reflect.Struct {
+					if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
+						dst.Set(src)
+					}
+				}
+			} else if dst.Elem().Type() == src.Type() {
+				if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
+					return
+				}
+			} else {
+				return ErrDifferentArgumentsTypes
+			}
+			break
+		}
+
+		if dst.IsNil() || overwrite {
+			if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
+				dst.Set(src)
+			}
+			break
+		}
+
+		if dst.Elem().Kind() == src.Elem().Kind() {
+			if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+				return
+			}
+			break
+		}
+	default:
+		mustSet := (isEmptyValue(dst, !config.ShouldNotDereference) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc)
+		if mustSet {
+			if dst.CanSet() {
+				dst.Set(src)
+			} else {
+				dst = src
+			}
+		}
+	}
+
+	return
+}
+
+// Merge will fill any empty for value type attributes on the dst struct using corresponding
+// src attributes if they themselves are not empty. dst and src must be valid same-type structs
+// and dst must be a pointer to struct.
+// It won't merge unexported (private) fields and will do recursively any exported field.
+func Merge(dst, src interface{}, opts ...func(*Config)) error {
+	return merge(dst, src, opts...)
+}
+
+// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
+// non-empty src attribute values.
+// Deprecated: use Merge(…) with WithOverride
+func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
+	return merge(dst, src, append(opts, WithOverride)...)
+}
+
+// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
+func WithTransformers(transformers Transformers) func(*Config) {
+	return func(config *Config) {
+		config.Transformers = transformers
+	}
+}
+
+// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
+func WithOverride(config *Config) {
+	config.Overwrite = true
+}
+
+// WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
+func WithOverwriteWithEmptyValue(config *Config) {
+	config.Overwrite = true
+	config.overwriteWithEmptyValue = true
+}
+
+// WithOverrideEmptySlice will make merge override empty dst slice with empty src slice.
+func WithOverrideEmptySlice(config *Config) {
+	config.overwriteSliceWithEmptyValue = true
+}
+
+// WithoutDereference prevents dereferencing pointers when evaluating whether they are empty
+// (i.e. a non-nil pointer is never considered empty).
+func WithoutDereference(config *Config) {
+	config.ShouldNotDereference = true
+}
+
+// WithAppendSlice will make merge append slices instead of overwriting it.
+func WithAppendSlice(config *Config) {
+	config.AppendSlice = true
+}
+
+// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
+func WithTypeCheck(config *Config) {
+	config.TypeCheck = true
+}
+
+// WithSliceDeepCopy will merge slice element one by one with Overwrite flag.
+func WithSliceDeepCopy(config *Config) {
+	config.sliceDeepCopy = true
+	config.Overwrite = true
+}
+
+func merge(dst, src interface{}, opts ...func(*Config)) error {
+	if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
+		return ErrNonPointerArgument
+	}
+	var (
+		vDst, vSrc reflect.Value
+		err        error
+	)
+
+	config := &Config{}
+
+	for _, opt := range opts {
+		opt(config)
+	}
+
+	if vDst, vSrc, err = resolveValues(dst, src); err != nil {
+		return err
+	}
+	if vDst.Type() != vSrc.Type() {
+		return ErrDifferentArgumentsTypes
+	}
+	return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
+}
+
+// IsReflectNil is the reflect value provided nil
+func isReflectNil(v reflect.Value) bool {
+	k := v.Kind()
+	switch k {
+	case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr:
+		// Both interface and slice are nil if first word is 0.
+		// Both are always bigger than a word; assume flagIndir.
+		return v.IsNil()
+	default:
+		return false
+	}
+}
diff --git a/vendor/dario.cat/mergo/mergo.go b/vendor/dario.cat/mergo/mergo.go
new file mode 100644
index 000000000..0a721e2d8
--- /dev/null
+++ b/vendor/dario.cat/mergo/mergo.go
@@ -0,0 +1,81 @@
+// Copyright 2013 Dario Castañé. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on src/pkg/reflect/deepequal.go from official
+// golang's stdlib.
+
+package mergo
+
+import (
+	"errors"
+	"reflect"
+)
+
+// Errors reported by Mergo when it finds invalid arguments.
+var (
+	ErrNilArguments                = errors.New("src and dst must not be nil")
+	ErrDifferentArgumentsTypes     = errors.New("src and dst must be of same type")
+	ErrNotSupported                = errors.New("only structs, maps, and slices are supported")
+	ErrExpectedMapAsDestination    = errors.New("dst was expected to be a map")
+	ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
+	ErrNonPointerArgument          = errors.New("dst must be a pointer")
+)
+
+// During deepMerge, must keep track of checks that are
+// in progress.  The comparison algorithm assumes that all
+// checks in progress are true when it reencounters them.
+// Visited are stored in a map indexed by 17 * a1 + a2;
+type visit struct {
+	typ  reflect.Type
+	next *visit
+	ptr  uintptr
+}
+
+// From src/pkg/encoding/json/encode.go.
+func isEmptyValue(v reflect.Value, shouldDereference bool) bool {
+	switch v.Kind() {
+	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+		return v.Len() == 0
+	case reflect.Bool:
+		return !v.Bool()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+	case reflect.Float32, reflect.Float64:
+		return v.Float() == 0
+	case reflect.Interface, reflect.Ptr:
+		if v.IsNil() {
+			return true
+		}
+		if shouldDereference {
+			return isEmptyValue(v.Elem(), shouldDereference)
+		}
+		return false
+	case reflect.Func:
+		return v.IsNil()
+	case reflect.Invalid:
+		return true
+	}
+	return false
+}
+
+func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
+	if dst == nil || src == nil {
+		err = ErrNilArguments
+		return
+	}
+	vDst = reflect.ValueOf(dst).Elem()
+	if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map && vDst.Kind() != reflect.Slice {
+		err = ErrNotSupported
+		return
+	}
+	vSrc = reflect.ValueOf(src)
+	// We check if vSrc is a pointer to dereference it.
+	if vSrc.Kind() == reflect.Ptr {
+		vSrc = vSrc.Elem()
+	}
+	return
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/LICENSE b/vendor/github.com/Azure/go-ansiterm/LICENSE
new file mode 100644
index 000000000..e3d9a64d1
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Microsoft Corporation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Azure/go-ansiterm/README.md b/vendor/github.com/Azure/go-ansiterm/README.md
new file mode 100644
index 000000000..261c041e7
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/README.md
@@ -0,0 +1,12 @@
+# go-ansiterm
+
+This is a cross platform Ansi Terminal Emulation library.  It reads a stream of Ansi characters and produces the appropriate function calls.  The results of the function calls are platform dependent.
+
+For example the parser might receive "ESC, [, A" as a stream of three characters.  This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU).  The parser then calls the cursor up function (CUU()) on an event handler.  The event handler determines what platform specific work must be done to cause the cursor to move up one position.
+
+The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png).  There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
+
+See parser_test.go for examples exercising the state machine and generating appropriate function calls.
+
+-----
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
diff --git a/vendor/github.com/Azure/go-ansiterm/SECURITY.md b/vendor/github.com/Azure/go-ansiterm/SECURITY.md
new file mode 100644
index 000000000..e138ec5d6
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/SECURITY.md
@@ -0,0 +1,41 @@
+<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->
+
+## Security
+
+Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
+
+If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
+
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+  * Full paths of source file(s) related to the manifestation of the issue
+  * The location of the affected source code (tag/branch/commit or direct URL)
+  * Any special configuration required to reproduce the issue
+  * Step-by-step instructions to reproduce the issue
+  * Proof-of-concept or exploit code (if possible)
+  * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Policy
+
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
+
+<!-- END MICROSOFT SECURITY.MD BLOCK -->
diff --git a/vendor/github.com/Azure/go-ansiterm/constants.go b/vendor/github.com/Azure/go-ansiterm/constants.go
new file mode 100644
index 000000000..96504a33b
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/constants.go
@@ -0,0 +1,188 @@
+package ansiterm
+
+const LogEnv = "DEBUG_TERMINAL"
+
+// ANSI constants
+// References:
+// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
+// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
+// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
+// -- http://en.wikipedia.org/wiki/ANSI_escape_code
+// -- http://vt100.net/emu/dec_ansi_parser
+// -- http://vt100.net/emu/vt500_parser.svg
+// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+// -- http://www.inwap.com/pdp10/ansicode.txt
+const (
+	// ECMA-48 Set Graphics Rendition
+	// Note:
+	// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
+	// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
+	// -- Windows does not expose the per-window cursor (i.e., caret) blink times
+	ANSI_SGR_RESET              = 0
+	ANSI_SGR_BOLD               = 1
+	ANSI_SGR_DIM                = 2
+	_ANSI_SGR_ITALIC            = 3
+	ANSI_SGR_UNDERLINE          = 4
+	_ANSI_SGR_BLINKSLOW         = 5
+	_ANSI_SGR_BLINKFAST         = 6
+	ANSI_SGR_REVERSE            = 7
+	_ANSI_SGR_INVISIBLE         = 8
+	_ANSI_SGR_LINETHROUGH       = 9
+	_ANSI_SGR_FONT_00           = 10
+	_ANSI_SGR_FONT_01           = 11
+	_ANSI_SGR_FONT_02           = 12
+	_ANSI_SGR_FONT_03           = 13
+	_ANSI_SGR_FONT_04           = 14
+	_ANSI_SGR_FONT_05           = 15
+	_ANSI_SGR_FONT_06           = 16
+	_ANSI_SGR_FONT_07           = 17
+	_ANSI_SGR_FONT_08           = 18
+	_ANSI_SGR_FONT_09           = 19
+	_ANSI_SGR_FONT_10           = 20
+	_ANSI_SGR_DOUBLEUNDERLINE   = 21
+	ANSI_SGR_BOLD_DIM_OFF       = 22
+	_ANSI_SGR_ITALIC_OFF        = 23
+	ANSI_SGR_UNDERLINE_OFF      = 24
+	_ANSI_SGR_BLINK_OFF         = 25
+	_ANSI_SGR_RESERVED_00       = 26
+	ANSI_SGR_REVERSE_OFF        = 27
+	_ANSI_SGR_INVISIBLE_OFF     = 28
+	_ANSI_SGR_LINETHROUGH_OFF   = 29
+	ANSI_SGR_FOREGROUND_BLACK   = 30
+	ANSI_SGR_FOREGROUND_RED     = 31
+	ANSI_SGR_FOREGROUND_GREEN   = 32
+	ANSI_SGR_FOREGROUND_YELLOW  = 33
+	ANSI_SGR_FOREGROUND_BLUE    = 34
+	ANSI_SGR_FOREGROUND_MAGENTA = 35
+	ANSI_SGR_FOREGROUND_CYAN    = 36
+	ANSI_SGR_FOREGROUND_WHITE   = 37
+	_ANSI_SGR_RESERVED_01       = 38
+	ANSI_SGR_FOREGROUND_DEFAULT = 39
+	ANSI_SGR_BACKGROUND_BLACK   = 40
+	ANSI_SGR_BACKGROUND_RED     = 41
+	ANSI_SGR_BACKGROUND_GREEN   = 42
+	ANSI_SGR_BACKGROUND_YELLOW  = 43
+	ANSI_SGR_BACKGROUND_BLUE    = 44
+	ANSI_SGR_BACKGROUND_MAGENTA = 45
+	ANSI_SGR_BACKGROUND_CYAN    = 46
+	ANSI_SGR_BACKGROUND_WHITE   = 47
+	_ANSI_SGR_RESERVED_02       = 48
+	ANSI_SGR_BACKGROUND_DEFAULT = 49
+	// 50 - 65: Unsupported
+
+	ANSI_MAX_CMD_LENGTH = 4096
+
+	MAX_INPUT_EVENTS = 128
+	DEFAULT_WIDTH    = 80
+	DEFAULT_HEIGHT   = 24
+
+	ANSI_BEL              = 0x07
+	ANSI_BACKSPACE        = 0x08
+	ANSI_TAB              = 0x09
+	ANSI_LINE_FEED        = 0x0A
+	ANSI_VERTICAL_TAB     = 0x0B
+	ANSI_FORM_FEED        = 0x0C
+	ANSI_CARRIAGE_RETURN  = 0x0D
+	ANSI_ESCAPE_PRIMARY   = 0x1B
+	ANSI_ESCAPE_SECONDARY = 0x5B
+	ANSI_OSC_STRING_ENTRY = 0x5D
+	ANSI_COMMAND_FIRST    = 0x40
+	ANSI_COMMAND_LAST     = 0x7E
+	DCS_ENTRY             = 0x90
+	CSI_ENTRY             = 0x9B
+	OSC_STRING            = 0x9D
+	ANSI_PARAMETER_SEP    = ";"
+	ANSI_CMD_G0           = '('
+	ANSI_CMD_G1           = ')'
+	ANSI_CMD_G2           = '*'
+	ANSI_CMD_G3           = '+'
+	ANSI_CMD_DECPNM       = '>'
+	ANSI_CMD_DECPAM       = '='
+	ANSI_CMD_OSC          = ']'
+	ANSI_CMD_STR_TERM     = '\\'
+
+	KEY_CONTROL_PARAM_2 = ";2"
+	KEY_CONTROL_PARAM_3 = ";3"
+	KEY_CONTROL_PARAM_4 = ";4"
+	KEY_CONTROL_PARAM_5 = ";5"
+	KEY_CONTROL_PARAM_6 = ";6"
+	KEY_CONTROL_PARAM_7 = ";7"
+	KEY_CONTROL_PARAM_8 = ";8"
+	KEY_ESC_CSI         = "\x1B["
+	KEY_ESC_N           = "\x1BN"
+	KEY_ESC_O           = "\x1BO"
+
+	FILL_CHARACTER = ' '
+)
+
+func getByteRange(start byte, end byte) []byte {
+	bytes := make([]byte, 0, 32)
+	for i := start; i <= end; i++ {
+		bytes = append(bytes, byte(i))
+	}
+
+	return bytes
+}
+
+var toGroundBytes = getToGroundBytes()
+var executors = getExecuteBytes()
+
+// SPACE		  20+A0 hex  Always and everywhere a blank space
+// Intermediate	  20-2F hex   !"#$%&'()*+,-./
+var intermeds = getByteRange(0x20, 0x2F)
+
+// Parameters	  30-3F hex  0123456789:;<=>?
+// CSI Parameters 30-39, 3B hex 0123456789;
+var csiParams = getByteRange(0x30, 0x3F)
+
+var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
+
+// Uppercase	  40-5F hex  @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+var upperCase = getByteRange(0x40, 0x5F)
+
+// Lowercase	  60-7E hex  `abcdefghijlkmnopqrstuvwxyz{|}~
+var lowerCase = getByteRange(0x60, 0x7E)
+
+// Alphabetics	  40-7E hex  (all of upper and lower case)
+var alphabetics = append(upperCase, lowerCase...)
+
+var printables = getByteRange(0x20, 0x7F)
+
+var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
+var escapeToGroundBytes = getEscapeToGroundBytes()
+
+// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
+// byte ranges below
+
+func getEscapeToGroundBytes() []byte {
+	escapeToGroundBytes := getByteRange(0x30, 0x4F)
+	escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
+	escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
+	escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
+	escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
+	escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
+	return escapeToGroundBytes
+}
+
+func getExecuteBytes() []byte {
+	executeBytes := getByteRange(0x00, 0x17)
+	executeBytes = append(executeBytes, 0x19)
+	executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
+	return executeBytes
+}
+
+func getToGroundBytes() []byte {
+	groundBytes := []byte{0x18}
+	groundBytes = append(groundBytes, 0x1A)
+	groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
+	groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
+	groundBytes = append(groundBytes, 0x99)
+	groundBytes = append(groundBytes, 0x9A)
+	groundBytes = append(groundBytes, 0x9C)
+	return groundBytes
+}
+
+// Delete		     7F hex  Always and everywhere ignored
+// C1 Control	  80-9F hex  32 additional control characters
+// G1 Displayable A1-FE hex  94 additional displayable characters
+// Special		  A0+FF hex  Same as SPACE and DELETE
diff --git a/vendor/github.com/Azure/go-ansiterm/context.go b/vendor/github.com/Azure/go-ansiterm/context.go
new file mode 100644
index 000000000..8d66e777c
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/context.go
@@ -0,0 +1,7 @@
+package ansiterm
+
+type ansiContext struct {
+	currentChar byte
+	paramBuffer []byte
+	interBuffer []byte
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
new file mode 100644
index 000000000..bcbe00d0c
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
@@ -0,0 +1,49 @@
+package ansiterm
+
+type csiEntryState struct {
+	baseState
+}
+
+func (csiState csiEntryState) Handle(b byte) (s state, e error) {
+	csiState.parser.logf("CsiEntry::Handle %#x", b)
+
+	nextState, err := csiState.baseState.Handle(b)
+	if nextState != nil || err != nil {
+		return nextState, err
+	}
+
+	switch {
+	case sliceContains(alphabetics, b):
+		return csiState.parser.ground, nil
+	case sliceContains(csiCollectables, b):
+		return csiState.parser.csiParam, nil
+	case sliceContains(executors, b):
+		return csiState, csiState.parser.execute()
+	}
+
+	return csiState, nil
+}
+
+func (csiState csiEntryState) Transition(s state) error {
+	csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
+	csiState.baseState.Transition(s)
+
+	switch s {
+	case csiState.parser.ground:
+		return csiState.parser.csiDispatch()
+	case csiState.parser.csiParam:
+		switch {
+		case sliceContains(csiParams, csiState.parser.context.currentChar):
+			csiState.parser.collectParam()
+		case sliceContains(intermeds, csiState.parser.context.currentChar):
+			csiState.parser.collectInter()
+		}
+	}
+
+	return nil
+}
+
+func (csiState csiEntryState) Enter() error {
+	csiState.parser.clear()
+	return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go
new file mode 100644
index 000000000..7ed5e01c3
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go
@@ -0,0 +1,38 @@
+package ansiterm
+
+type csiParamState struct {
+	baseState
+}
+
+func (csiState csiParamState) Handle(b byte) (s state, e error) {
+	csiState.parser.logf("CsiParam::Handle %#x", b)
+
+	nextState, err := csiState.baseState.Handle(b)
+	if nextState != nil || err != nil {
+		return nextState, err
+	}
+
+	switch {
+	case sliceContains(alphabetics, b):
+		return csiState.parser.ground, nil
+	case sliceContains(csiCollectables, b):
+		csiState.parser.collectParam()
+		return csiState, nil
+	case sliceContains(executors, b):
+		return csiState, csiState.parser.execute()
+	}
+
+	return csiState, nil
+}
+
+func (csiState csiParamState) Transition(s state) error {
+	csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
+	csiState.baseState.Transition(s)
+
+	switch s {
+	case csiState.parser.ground:
+		return csiState.parser.csiDispatch()
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
new file mode 100644
index 000000000..1c719db9e
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
@@ -0,0 +1,36 @@
+package ansiterm
+
+type escapeIntermediateState struct {
+	baseState
+}
+
+func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
+	escState.parser.logf("escapeIntermediateState::Handle %#x", b)
+	nextState, err := escState.baseState.Handle(b)
+	if nextState != nil || err != nil {
+		return nextState, err
+	}
+
+	switch {
+	case sliceContains(intermeds, b):
+		return escState, escState.parser.collectInter()
+	case sliceContains(executors, b):
+		return escState, escState.parser.execute()
+	case sliceContains(escapeIntermediateToGroundBytes, b):
+		return escState.parser.ground, nil
+	}
+
+	return escState, nil
+}
+
+func (escState escapeIntermediateState) Transition(s state) error {
+	escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
+	escState.baseState.Transition(s)
+
+	switch s {
+	case escState.parser.ground:
+		return escState.parser.escDispatch()
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go
new file mode 100644
index 000000000..6390abd23
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/escape_state.go
@@ -0,0 +1,47 @@
+package ansiterm
+
+type escapeState struct {
+	baseState
+}
+
+func (escState escapeState) Handle(b byte) (s state, e error) {
+	escState.parser.logf("escapeState::Handle %#x", b)
+	nextState, err := escState.baseState.Handle(b)
+	if nextState != nil || err != nil {
+		return nextState, err
+	}
+
+	switch {
+	case b == ANSI_ESCAPE_SECONDARY:
+		return escState.parser.csiEntry, nil
+	case b == ANSI_OSC_STRING_ENTRY:
+		return escState.parser.oscString, nil
+	case sliceContains(executors, b):
+		return escState, escState.parser.execute()
+	case sliceContains(escapeToGroundBytes, b):
+		return escState.parser.ground, nil
+	case sliceContains(intermeds, b):
+		return escState.parser.escapeIntermediate, nil
+	}
+
+	return escState, nil
+}
+
+func (escState escapeState) Transition(s state) error {
+	escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name())
+	escState.baseState.Transition(s)
+
+	switch s {
+	case escState.parser.ground:
+		return escState.parser.escDispatch()
+	case escState.parser.escapeIntermediate:
+		return escState.parser.collectInter()
+	}
+
+	return nil
+}
+
+func (escState escapeState) Enter() error {
+	escState.parser.clear()
+	return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/event_handler.go b/vendor/github.com/Azure/go-ansiterm/event_handler.go
new file mode 100644
index 000000000..98087b38c
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/event_handler.go
@@ -0,0 +1,90 @@
+package ansiterm
+
+type AnsiEventHandler interface {
+	// Print
+	Print(b byte) error
+
+	// Execute C0 commands
+	Execute(b byte) error
+
+	// CUrsor Up
+	CUU(int) error
+
+	// CUrsor Down
+	CUD(int) error
+
+	// CUrsor Forward
+	CUF(int) error
+
+	// CUrsor Backward
+	CUB(int) error
+
+	// Cursor to Next Line
+	CNL(int) error
+
+	// Cursor to Previous Line
+	CPL(int) error
+
+	// Cursor Horizontal position Absolute
+	CHA(int) error
+
+	// Vertical line Position Absolute
+	VPA(int) error
+
+	// CUrsor Position
+	CUP(int, int) error
+
+	// Horizontal and Vertical Position (depends on PUM)
+	HVP(int, int) error
+
+	// Text Cursor Enable Mode
+	DECTCEM(bool) error
+
+	// Origin Mode
+	DECOM(bool) error
+
+	// 132 Column Mode
+	DECCOLM(bool) error
+
+	// Erase in Display
+	ED(int) error
+
+	// Erase in Line
+	EL(int) error
+
+	// Insert Line
+	IL(int) error
+
+	// Delete Line
+	DL(int) error
+
+	// Insert Character
+	ICH(int) error
+
+	// Delete Character
+	DCH(int) error
+
+	// Set Graphics Rendition
+	SGR([]int) error
+
+	// Pan Down
+	SU(int) error
+
+	// Pan Up
+	SD(int) error
+
+	// Device Attributes
+	DA([]string) error
+
+	// Set Top and Bottom Margins
+	DECSTBM(int, int) error
+
+	// Index
+	IND() error
+
+	// Reverse Index
+	RI() error
+
+	// Flush updates from previous commands
+	Flush() error
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/ground_state.go b/vendor/github.com/Azure/go-ansiterm/ground_state.go
new file mode 100644
index 000000000..52451e946
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/ground_state.go
@@ -0,0 +1,24 @@
+package ansiterm
+
+type groundState struct {
+	baseState
+}
+
+func (gs groundState) Handle(b byte) (s state, e error) {
+	gs.parser.context.currentChar = b
+
+	nextState, err := gs.baseState.Handle(b)
+	if nextState != nil || err != nil {
+		return nextState, err
+	}
+
+	switch {
+	case sliceContains(printables, b):
+		return gs, gs.parser.print()
+
+	case sliceContains(executors, b):
+		return gs, gs.parser.execute()
+	}
+
+	return gs, nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
new file mode 100644
index 000000000..194d5e9c9
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
@@ -0,0 +1,23 @@
+package ansiterm
+
+type oscStringState struct {
+	baseState
+}
+
+func (oscState oscStringState) Handle(b byte) (s state, e error) {
+	oscState.parser.logf("OscString::Handle %#x", b)
+	nextState, err := oscState.baseState.Handle(b)
+	if nextState != nil || err != nil {
+		return nextState, err
+	}
+
+	// There are several control characters and sequences which can
+	// terminate an OSC string. Most of them are handled by the baseState
+	// handler. The ANSI_BEL character is a special case which behaves as a
+	// terminator only for an OSC string.
+	if b == ANSI_BEL {
+		return oscState.parser.ground, nil
+	}
+
+	return oscState, nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go
new file mode 100644
index 000000000..03cec7ada
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser.go
@@ -0,0 +1,151 @@
+package ansiterm
+
+import (
+	"errors"
+	"log"
+	"os"
+)
+
+type AnsiParser struct {
+	currState          state
+	eventHandler       AnsiEventHandler
+	context            *ansiContext
+	csiEntry           state
+	csiParam           state
+	dcsEntry           state
+	escape             state
+	escapeIntermediate state
+	error              state
+	ground             state
+	oscString          state
+	stateMap           []state
+
+	logf func(string, ...interface{})
+}
+
+type Option func(*AnsiParser)
+
+func WithLogf(f func(string, ...interface{})) Option {
+	return func(ap *AnsiParser) {
+		ap.logf = f
+	}
+}
+
+func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
+	ap := &AnsiParser{
+		eventHandler: evtHandler,
+		context:      &ansiContext{},
+	}
+	for _, o := range opts {
+		o(ap)
+	}
+
+	if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
+		logFile, _ := os.Create("ansiParser.log")
+		logger := log.New(logFile, "", log.LstdFlags)
+		if ap.logf != nil {
+			l := ap.logf
+			ap.logf = func(s string, v ...interface{}) {
+				l(s, v...)
+				logger.Printf(s, v...)
+			}
+		} else {
+			ap.logf = logger.Printf
+		}
+	}
+
+	if ap.logf == nil {
+		ap.logf = func(string, ...interface{}) {}
+	}
+
+	ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
+	ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
+	ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
+	ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
+	ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
+	ap.error = errorState{baseState{name: "Error", parser: ap}}
+	ap.ground = groundState{baseState{name: "Ground", parser: ap}}
+	ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
+
+	ap.stateMap = []state{
+		ap.csiEntry,
+		ap.csiParam,
+		ap.dcsEntry,
+		ap.escape,
+		ap.escapeIntermediate,
+		ap.error,
+		ap.ground,
+		ap.oscString,
+	}
+
+	ap.currState = getState(initialState, ap.stateMap)
+
+	ap.logf("CreateParser: parser %p", ap)
+	return ap
+}
+
+func getState(name string, states []state) state {
+	for _, el := range states {
+		if el.Name() == name {
+			return el
+		}
+	}
+
+	return nil
+}
+
+func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
+	for i, b := range bytes {
+		if err := ap.handle(b); err != nil {
+			return i, err
+		}
+	}
+
+	return len(bytes), ap.eventHandler.Flush()
+}
+
+func (ap *AnsiParser) handle(b byte) error {
+	ap.context.currentChar = b
+	newState, err := ap.currState.Handle(b)
+	if err != nil {
+		return err
+	}
+
+	if newState == nil {
+		ap.logf("WARNING: newState is nil")
+		return errors.New("New state of 'nil' is invalid.")
+	}
+
+	if newState != ap.currState {
+		if err := ap.changeState(newState); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (ap *AnsiParser) changeState(newState state) error {
+	ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
+
+	// Exit old state
+	if err := ap.currState.Exit(); err != nil {
+		ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
+		return err
+	}
+
+	// Perform transition action
+	if err := ap.currState.Transition(newState); err != nil {
+		ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
+		return err
+	}
+
+	// Enter new state
+	if err := newState.Enter(); err != nil {
+		ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
+		return err
+	}
+
+	ap.currState = newState
+	return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
new file mode 100644
index 000000000..de0a1f9cd
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
@@ -0,0 +1,99 @@
+package ansiterm
+
+import (
+	"strconv"
+)
+
+func parseParams(bytes []byte) ([]string, error) {
+	paramBuff := make([]byte, 0, 0)
+	params := []string{}
+
+	for _, v := range bytes {
+		if v == ';' {
+			if len(paramBuff) > 0 {
+				// Completed parameter, append it to the list
+				s := string(paramBuff)
+				params = append(params, s)
+				paramBuff = make([]byte, 0, 0)
+			}
+		} else {
+			paramBuff = append(paramBuff, v)
+		}
+	}
+
+	// Last parameter may not be terminated with ';'
+	if len(paramBuff) > 0 {
+		s := string(paramBuff)
+		params = append(params, s)
+	}
+
+	return params, nil
+}
+
+func parseCmd(context ansiContext) (string, error) {
+	return string(context.currentChar), nil
+}
+
+func getInt(params []string, dflt int) int {
+	i := getInts(params, 1, dflt)[0]
+	return i
+}
+
+func getInts(params []string, minCount int, dflt int) []int {
+	ints := []int{}
+
+	for _, v := range params {
+		i, _ := strconv.Atoi(v)
+		// Zero is mapped to the default value in VT100.
+		if i == 0 {
+			i = dflt
+		}
+		ints = append(ints, i)
+	}
+
+	if len(ints) < minCount {
+		remaining := minCount - len(ints)
+		for i := 0; i < remaining; i++ {
+			ints = append(ints, dflt)
+		}
+	}
+
+	return ints
+}
+
+func (ap *AnsiParser) modeDispatch(param string, set bool) error {
+	switch param {
+	case "?3":
+		return ap.eventHandler.DECCOLM(set)
+	case "?6":
+		return ap.eventHandler.DECOM(set)
+	case "?25":
+		return ap.eventHandler.DECTCEM(set)
+	}
+	return nil
+}
+
+func (ap *AnsiParser) hDispatch(params []string) error {
+	if len(params) == 1 {
+		return ap.modeDispatch(params[0], true)
+	}
+
+	return nil
+}
+
+func (ap *AnsiParser) lDispatch(params []string) error {
+	if len(params) == 1 {
+		return ap.modeDispatch(params[0], false)
+	}
+
+	return nil
+}
+
+func getEraseParam(params []string) int {
+	param := getInt(params, 0)
+	if param < 0 || 3 < param {
+		param = 0
+	}
+
+	return param
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go
new file mode 100644
index 000000000..0bb5e51e9
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser_actions.go
@@ -0,0 +1,119 @@
+package ansiterm
+
+func (ap *AnsiParser) collectParam() error {
+	currChar := ap.context.currentChar
+	ap.logf("collectParam %#x", currChar)
+	ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
+	return nil
+}
+
+func (ap *AnsiParser) collectInter() error {
+	currChar := ap.context.currentChar
+	ap.logf("collectInter %#x", currChar)
+	ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
+	return nil
+}
+
+func (ap *AnsiParser) escDispatch() error {
+	cmd, _ := parseCmd(*ap.context)
+	intermeds := ap.context.interBuffer
+	ap.logf("escDispatch currentChar: %#x", ap.context.currentChar)
+	ap.logf("escDispatch: %v(%v)", cmd, intermeds)
+
+	switch cmd {
+	case "D": // IND
+		return ap.eventHandler.IND()
+	case "E": // NEL, equivalent to CRLF
+		err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
+		if err == nil {
+			err = ap.eventHandler.Execute(ANSI_LINE_FEED)
+		}
+		return err
+	case "M": // RI
+		return ap.eventHandler.RI()
+	}
+
+	return nil
+}
+
+func (ap *AnsiParser) csiDispatch() error {
+	cmd, _ := parseCmd(*ap.context)
+	params, _ := parseParams(ap.context.paramBuffer)
+	ap.logf("Parsed params: %v with length: %d", params, len(params))
+
+	ap.logf("csiDispatch: %v(%v)", cmd, params)
+
+	switch cmd {
+	case "@":
+		return ap.eventHandler.ICH(getInt(params, 1))
+	case "A":
+		return ap.eventHandler.CUU(getInt(params, 1))
+	case "B":
+		return ap.eventHandler.CUD(getInt(params, 1))
+	case "C":
+		return ap.eventHandler.CUF(getInt(params, 1))
+	case "D":
+		return ap.eventHandler.CUB(getInt(params, 1))
+	case "E":
+		return ap.eventHandler.CNL(getInt(params, 1))
+	case "F":
+		return ap.eventHandler.CPL(getInt(params, 1))
+	case "G":
+		return ap.eventHandler.CHA(getInt(params, 1))
+	case "H":
+		ints := getInts(params, 2, 1)
+		x, y := ints[0], ints[1]
+		return ap.eventHandler.CUP(x, y)
+	case "J":
+		param := getEraseParam(params)
+		return ap.eventHandler.ED(param)
+	case "K":
+		param := getEraseParam(params)
+		return ap.eventHandler.EL(param)
+	case "L":
+		return ap.eventHandler.IL(getInt(params, 1))
+	case "M":
+		return ap.eventHandler.DL(getInt(params, 1))
+	case "P":
+		return ap.eventHandler.DCH(getInt(params, 1))
+	case "S":
+		return ap.eventHandler.SU(getInt(params, 1))
+	case "T":
+		return ap.eventHandler.SD(getInt(params, 1))
+	case "c":
+		return ap.eventHandler.DA(params)
+	case "d":
+		return ap.eventHandler.VPA(getInt(params, 1))
+	case "f":
+		ints := getInts(params, 2, 1)
+		x, y := ints[0], ints[1]
+		return ap.eventHandler.HVP(x, y)
+	case "h":
+		return ap.hDispatch(params)
+	case "l":
+		return ap.lDispatch(params)
+	case "m":
+		return ap.eventHandler.SGR(getInts(params, 1, 0))
+	case "r":
+		ints := getInts(params, 2, 1)
+		top, bottom := ints[0], ints[1]
+		return ap.eventHandler.DECSTBM(top, bottom)
+	default:
+		ap.logf("ERROR: Unsupported CSI command: '%s', with full context:  %v", cmd, ap.context)
+		return nil
+	}
+
+}
+
+func (ap *AnsiParser) print() error {
+	return ap.eventHandler.Print(ap.context.currentChar)
+}
+
+func (ap *AnsiParser) clear() error {
+	ap.context = &ansiContext{}
+	return nil
+}
+
+func (ap *AnsiParser) execute() error {
+	return ap.eventHandler.Execute(ap.context.currentChar)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go
new file mode 100644
index 000000000..f2ea1fcd1
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/states.go
@@ -0,0 +1,71 @@
+package ansiterm
+
+type stateID int
+
+type state interface {
+	Enter() error
+	Exit() error
+	Handle(byte) (state, error)
+	Name() string
+	Transition(state) error
+}
+
+type baseState struct {
+	name   string
+	parser *AnsiParser
+}
+
+func (base baseState) Enter() error {
+	return nil
+}
+
+func (base baseState) Exit() error {
+	return nil
+}
+
+func (base baseState) Handle(b byte) (s state, e error) {
+
+	switch {
+	case b == CSI_ENTRY:
+		return base.parser.csiEntry, nil
+	case b == DCS_ENTRY:
+		return base.parser.dcsEntry, nil
+	case b == ANSI_ESCAPE_PRIMARY:
+		return base.parser.escape, nil
+	case b == OSC_STRING:
+		return base.parser.oscString, nil
+	case sliceContains(toGroundBytes, b):
+		return base.parser.ground, nil
+	}
+
+	return nil, nil
+}
+
+func (base baseState) Name() string {
+	return base.name
+}
+
+func (base baseState) Transition(s state) error {
+	if s == base.parser.ground {
+		execBytes := []byte{0x18}
+		execBytes = append(execBytes, 0x1A)
+		execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
+		execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
+		execBytes = append(execBytes, 0x99)
+		execBytes = append(execBytes, 0x9A)
+
+		if sliceContains(execBytes, base.parser.context.currentChar) {
+			return base.parser.execute()
+		}
+	}
+
+	return nil
+}
+
+type dcsEntryState struct {
+	baseState
+}
+
+type errorState struct {
+	baseState
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go
new file mode 100644
index 000000000..392114493
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/utilities.go
@@ -0,0 +1,21 @@
+package ansiterm
+
+import (
+	"strconv"
+)
+
+func sliceContains(bytes []byte, b byte) bool {
+	for _, v := range bytes {
+		if v == b {
+			return true
+		}
+	}
+
+	return false
+}
+
+func convertBytesToInteger(bytes []byte) int {
+	s := string(bytes)
+	i, _ := strconv.Atoi(s)
+	return i
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
new file mode 100644
index 000000000..5599082ae
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
@@ -0,0 +1,196 @@
+// +build windows
+
+package winterm
+
+import (
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/Azure/go-ansiterm"
+	windows "golang.org/x/sys/windows"
+)
+
+// Windows keyboard constants
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
+const (
+	VK_PRIOR    = 0x21 // PAGE UP key
+	VK_NEXT     = 0x22 // PAGE DOWN key
+	VK_END      = 0x23 // END key
+	VK_HOME     = 0x24 // HOME key
+	VK_LEFT     = 0x25 // LEFT ARROW key
+	VK_UP       = 0x26 // UP ARROW key
+	VK_RIGHT    = 0x27 // RIGHT ARROW key
+	VK_DOWN     = 0x28 // DOWN ARROW key
+	VK_SELECT   = 0x29 // SELECT key
+	VK_PRINT    = 0x2A // PRINT key
+	VK_EXECUTE  = 0x2B // EXECUTE key
+	VK_SNAPSHOT = 0x2C // PRINT SCREEN key
+	VK_INSERT   = 0x2D // INS key
+	VK_DELETE   = 0x2E // DEL key
+	VK_HELP     = 0x2F // HELP key
+	VK_F1       = 0x70 // F1 key
+	VK_F2       = 0x71 // F2 key
+	VK_F3       = 0x72 // F3 key
+	VK_F4       = 0x73 // F4 key
+	VK_F5       = 0x74 // F5 key
+	VK_F6       = 0x75 // F6 key
+	VK_F7       = 0x76 // F7 key
+	VK_F8       = 0x77 // F8 key
+	VK_F9       = 0x78 // F9 key
+	VK_F10      = 0x79 // F10 key
+	VK_F11      = 0x7A // F11 key
+	VK_F12      = 0x7B // F12 key
+
+	RIGHT_ALT_PRESSED  = 0x0001
+	LEFT_ALT_PRESSED   = 0x0002
+	RIGHT_CTRL_PRESSED = 0x0004
+	LEFT_CTRL_PRESSED  = 0x0008
+	SHIFT_PRESSED      = 0x0010
+	NUMLOCK_ON         = 0x0020
+	SCROLLLOCK_ON      = 0x0040
+	CAPSLOCK_ON        = 0x0080
+	ENHANCED_KEY       = 0x0100
+)
+
+type ansiCommand struct {
+	CommandBytes []byte
+	Command      string
+	Parameters   []string
+	IsSpecial    bool
+}
+
+func newAnsiCommand(command []byte) *ansiCommand {
+
+	if isCharacterSelectionCmdChar(command[1]) {
+		// Is Character Set Selection commands
+		return &ansiCommand{
+			CommandBytes: command,
+			Command:      string(command),
+			IsSpecial:    true,
+		}
+	}
+
+	// last char is command character
+	lastCharIndex := len(command) - 1
+
+	ac := &ansiCommand{
+		CommandBytes: command,
+		Command:      string(command[lastCharIndex]),
+		IsSpecial:    false,
+	}
+
+	// more than a single escape
+	if lastCharIndex != 0 {
+		start := 1
+		// skip if double char escape sequence
+		if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
+			start++
+		}
+		// convert this to GetNextParam method
+		ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
+	}
+
+	return ac
+}
+
+func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
+	if index < 0 || index >= len(ac.Parameters) {
+		return defaultValue
+	}
+
+	param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
+	if err != nil {
+		return defaultValue
+	}
+
+	return int16(param)
+}
+
+func (ac *ansiCommand) String() string {
+	return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
+		bytesToHex(ac.CommandBytes),
+		ac.Command,
+		strings.Join(ac.Parameters, "\",\""))
+}
+
+// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
+// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
+func isAnsiCommandChar(b byte) bool {
+	switch {
+	case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
+		return true
+	case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
+		// non-CSI escape sequence terminator
+		return true
+	case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
+		// String escape sequence terminator
+		return true
+	}
+	return false
+}
+
+func isXtermOscSequence(command []byte, current byte) bool {
+	return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
+}
+
+func isCharacterSelectionCmdChar(b byte) bool {
+	return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
+}
+
+// bytesToHex converts a slice of bytes to a human-readable string.
+func bytesToHex(b []byte) string {
+	hex := make([]string, len(b))
+	for i, ch := range b {
+		hex[i] = fmt.Sprintf("%X", ch)
+	}
+	return strings.Join(hex, "")
+}
+
+// ensureInRange adjusts the passed value, if necessary, to ensure it is within
+// the passed min / max range.
+func ensureInRange(n int16, min int16, max int16) int16 {
+	if n < min {
+		return min
+	} else if n > max {
+		return max
+	} else {
+		return n
+	}
+}
+
+func GetStdFile(nFile int) (*os.File, uintptr) {
+	var file *os.File
+
+	// syscall uses negative numbers
+	// windows package uses very big uint32
+	// Keep these switches split so we don't have to convert ints too much.
+	switch uint32(nFile) {
+	case windows.STD_INPUT_HANDLE:
+		file = os.Stdin
+	case windows.STD_OUTPUT_HANDLE:
+		file = os.Stdout
+	case windows.STD_ERROR_HANDLE:
+		file = os.Stderr
+	default:
+		switch nFile {
+		case syscall.STD_INPUT_HANDLE:
+			file = os.Stdin
+		case syscall.STD_OUTPUT_HANDLE:
+			file = os.Stdout
+		case syscall.STD_ERROR_HANDLE:
+			file = os.Stderr
+		default:
+			panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
+		}
+	}
+
+	fd, err := syscall.GetStdHandle(nFile)
+	if err != nil {
+		panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
+	}
+
+	return file, uintptr(fd)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/api.go b/vendor/github.com/Azure/go-ansiterm/winterm/api.go
new file mode 100644
index 000000000..6055e33b9
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/api.go
@@ -0,0 +1,327 @@
+// +build windows
+
+package winterm
+
+import (
+	"fmt"
+	"syscall"
+	"unsafe"
+)
+
+//===========================================================================================================
+// IMPORTANT NOTE:
+//
+//	The methods below make extensive use of the "unsafe" package to obtain the required pointers.
+//	Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
+//	variables) the pointers reference *before* the API completes.
+//
+//  As a result, in those cases, the code must hint that the variables remain in active by invoking the
+//	dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
+//	require unsafe pointers.
+//
+//	If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
+//	the garbage collector the variables remain in use if:
+//
+//	-- The value is not a pointer (e.g., int32, struct)
+//	-- The value is not referenced by the method after passing the pointer to Windows
+//
+//	See http://golang.org/doc/go1.3.
+//===========================================================================================================
+
+var (
+	kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
+
+	getConsoleCursorInfoProc       = kernel32DLL.NewProc("GetConsoleCursorInfo")
+	setConsoleCursorInfoProc       = kernel32DLL.NewProc("SetConsoleCursorInfo")
+	setConsoleCursorPositionProc   = kernel32DLL.NewProc("SetConsoleCursorPosition")
+	setConsoleModeProc             = kernel32DLL.NewProc("SetConsoleMode")
+	getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
+	setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
+	scrollConsoleScreenBufferProc  = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
+	setConsoleTextAttributeProc    = kernel32DLL.NewProc("SetConsoleTextAttribute")
+	setConsoleWindowInfoProc       = kernel32DLL.NewProc("SetConsoleWindowInfo")
+	writeConsoleOutputProc         = kernel32DLL.NewProc("WriteConsoleOutputW")
+	readConsoleInputProc           = kernel32DLL.NewProc("ReadConsoleInputW")
+	waitForSingleObjectProc        = kernel32DLL.NewProc("WaitForSingleObject")
+)
+
+// Windows Console constants
+const (
+	// Console modes
+	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
+	ENABLE_PROCESSED_INPUT        = 0x0001
+	ENABLE_LINE_INPUT             = 0x0002
+	ENABLE_ECHO_INPUT             = 0x0004
+	ENABLE_WINDOW_INPUT           = 0x0008
+	ENABLE_MOUSE_INPUT            = 0x0010
+	ENABLE_INSERT_MODE            = 0x0020
+	ENABLE_QUICK_EDIT_MODE        = 0x0040
+	ENABLE_EXTENDED_FLAGS         = 0x0080
+	ENABLE_AUTO_POSITION          = 0x0100
+	ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
+
+	ENABLE_PROCESSED_OUTPUT            = 0x0001
+	ENABLE_WRAP_AT_EOL_OUTPUT          = 0x0002
+	ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
+	DISABLE_NEWLINE_AUTO_RETURN        = 0x0008
+	ENABLE_LVB_GRID_WORLDWIDE          = 0x0010
+
+	// Character attributes
+	// Note:
+	// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
+	//    Clearing all foreground or background colors results in black; setting all creates white.
+	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
+	FOREGROUND_BLUE      uint16 = 0x0001
+	FOREGROUND_GREEN     uint16 = 0x0002
+	FOREGROUND_RED       uint16 = 0x0004
+	FOREGROUND_INTENSITY uint16 = 0x0008
+	FOREGROUND_MASK      uint16 = 0x000F
+
+	BACKGROUND_BLUE      uint16 = 0x0010
+	BACKGROUND_GREEN     uint16 = 0x0020
+	BACKGROUND_RED       uint16 = 0x0040
+	BACKGROUND_INTENSITY uint16 = 0x0080
+	BACKGROUND_MASK      uint16 = 0x00F0
+
+	COMMON_LVB_MASK          uint16 = 0xFF00
+	COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
+	COMMON_LVB_UNDERSCORE    uint16 = 0x8000
+
+	// Input event types
+	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
+	KEY_EVENT                = 0x0001
+	MOUSE_EVENT              = 0x0002
+	WINDOW_BUFFER_SIZE_EVENT = 0x0004
+	MENU_EVENT               = 0x0008
+	FOCUS_EVENT              = 0x0010
+
+	// WaitForSingleObject return codes
+	WAIT_ABANDONED = 0x00000080
+	WAIT_FAILED    = 0xFFFFFFFF
+	WAIT_SIGNALED  = 0x0000000
+	WAIT_TIMEOUT   = 0x00000102
+
+	// WaitForSingleObject wait duration
+	WAIT_INFINITE       = 0xFFFFFFFF
+	WAIT_ONE_SECOND     = 1000
+	WAIT_HALF_SECOND    = 500
+	WAIT_QUARTER_SECOND = 250
+)
+
+// Windows API Console types
+// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
+// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
+type (
+	CHAR_INFO struct {
+		UnicodeChar uint16
+		Attributes  uint16
+	}
+
+	CONSOLE_CURSOR_INFO struct {
+		Size    uint32
+		Visible int32
+	}
+
+	CONSOLE_SCREEN_BUFFER_INFO struct {
+		Size              COORD
+		CursorPosition    COORD
+		Attributes        uint16
+		Window            SMALL_RECT
+		MaximumWindowSize COORD
+	}
+
+	COORD struct {
+		X int16
+		Y int16
+	}
+
+	SMALL_RECT struct {
+		Left   int16
+		Top    int16
+		Right  int16
+		Bottom int16
+	}
+
+	// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
+	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
+	INPUT_RECORD struct {
+		EventType uint16
+		KeyEvent  KEY_EVENT_RECORD
+	}
+
+	KEY_EVENT_RECORD struct {
+		KeyDown         int32
+		RepeatCount     uint16
+		VirtualKeyCode  uint16
+		VirtualScanCode uint16
+		UnicodeChar     uint16
+		ControlKeyState uint32
+	}
+
+	WINDOW_BUFFER_SIZE struct {
+		Size COORD
+	}
+)
+
+// boolToBOOL converts a Go bool into a Windows int32.
+func boolToBOOL(f bool) int32 {
+	if f {
+		return int32(1)
+	} else {
+		return int32(0)
+	}
+}
+
+// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
+func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
+	r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
+	return checkError(r1, r2, err)
+}
+
+// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
+func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
+	r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
+	return checkError(r1, r2, err)
+}
+
+// SetConsoleCursorPosition location of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
+func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
+	r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
+	use(coord)
+	return checkError(r1, r2, err)
+}
+
+// GetConsoleMode gets the console mode for given file descriptor
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
+func GetConsoleMode(handle uintptr) (mode uint32, err error) {
+	err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
+	return mode, err
+}
+
+// SetConsoleMode sets the console mode for given file descriptor
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
+func SetConsoleMode(handle uintptr, mode uint32) error {
+	r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
+	use(mode)
+	return checkError(r1, r2, err)
+}
+
+// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
+func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
+	info := CONSOLE_SCREEN_BUFFER_INFO{}
+	err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
+	if err != nil {
+		return nil, err
+	}
+	return &info, nil
+}
+
+func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
+	r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
+	use(scrollRect)
+	use(clipRect)
+	use(destOrigin)
+	use(char)
+	return checkError(r1, r2, err)
+}
+
+// SetConsoleScreenBufferSize sets the size of the console screen buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
+func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
+	r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
+	use(coord)
+	return checkError(r1, r2, err)
+}
+
+// SetConsoleTextAttribute sets the attributes of characters written to the
+// console screen buffer by the WriteFile or WriteConsole function.
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
+func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
+	r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
+	use(attribute)
+	return checkError(r1, r2, err)
+}
+
+// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
+// Note that the size and location must be within and no larger than the backing console screen buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
+func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
+	r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
+	use(isAbsolute)
+	use(rect)
+	return checkError(r1, r2, err)
+}
+
+// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
+func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
+	r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
+	use(buffer)
+	use(bufferSize)
+	use(bufferCoord)
+	return checkError(r1, r2, err)
+}
+
+// ReadConsoleInput reads (and removes) data from the console input buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
+func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
+	r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
+	use(buffer)
+	return checkError(r1, r2, err)
+}
+
+// WaitForSingleObject waits for the passed handle to be signaled.
+// It returns true if the handle was signaled; false otherwise.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
+func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
+	r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
+	switch r1 {
+	case WAIT_ABANDONED, WAIT_TIMEOUT:
+		return false, nil
+	case WAIT_SIGNALED:
+		return true, nil
+	}
+	use(msWait)
+	return false, err
+}
+
+// String helpers
+func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
+	return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
+}
+
+func (coord COORD) String() string {
+	return fmt.Sprintf("%v,%v", coord.X, coord.Y)
+}
+
+func (rect SMALL_RECT) String() string {
+	return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
+}
+
+// checkError evaluates the results of a Windows API call and returns the error if it failed.
+func checkError(r1, r2 uintptr, err error) error {
+	// Windows APIs return non-zero to indicate success
+	if r1 != 0 {
+		return nil
+	}
+
+	// Return the error if provided, otherwise default to EINVAL
+	if err != nil {
+		return err
+	}
+	return syscall.EINVAL
+}
+
+// coordToPointer converts a COORD into a uintptr (by fooling the type system).
+func coordToPointer(c COORD) uintptr {
+	// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
+	return uintptr(*((*uint32)(unsafe.Pointer(&c))))
+}
+
+// use is a no-op, but the compiler cannot see that it is.
+// Calling use(p) ensures that p is kept live until that point.
+func use(p interface{}) {}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
new file mode 100644
index 000000000..cbec8f728
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
@@ -0,0 +1,100 @@
+// +build windows
+
+package winterm
+
+import "github.com/Azure/go-ansiterm"
+
+const (
+	FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
+	BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
+)
+
+// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
+// request represented by the passed ANSI mode.
+func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
+	switch ansiMode {
+
+	// Mode styles
+	case ansiterm.ANSI_SGR_BOLD:
+		windowsMode = windowsMode | FOREGROUND_INTENSITY
+
+	case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
+		windowsMode &^= FOREGROUND_INTENSITY
+
+	case ansiterm.ANSI_SGR_UNDERLINE:
+		windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
+
+	case ansiterm.ANSI_SGR_REVERSE:
+		inverted = true
+
+	case ansiterm.ANSI_SGR_REVERSE_OFF:
+		inverted = false
+
+	case ansiterm.ANSI_SGR_UNDERLINE_OFF:
+		windowsMode &^= COMMON_LVB_UNDERSCORE
+
+		// Foreground colors
+	case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
+		windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
+
+	case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
+		windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
+
+	case ansiterm.ANSI_SGR_FOREGROUND_RED:
+		windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
+
+	case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
+		windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
+
+	case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
+		windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
+
+	case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
+		windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
+
+	case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
+		windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
+
+	case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
+		windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
+
+	case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
+		windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
+
+		// Background colors
+	case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
+		// Black with no intensity
+		windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
+
+	case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
+		windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
+
+	case ansiterm.ANSI_SGR_BACKGROUND_RED:
+		windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
+
+	case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
+		windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
+
+	case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
+		windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
+
+	case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
+		windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
+
+	case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
+		windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
+
+	case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
+		windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
+
+	case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
+		windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
+	}
+
+	return windowsMode, inverted
+}
+
+// invertAttributes inverts the foreground and background colors of a Windows attributes value
+func invertAttributes(windowsMode uint16) uint16 {
+	return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
new file mode 100644
index 000000000..3ee06ea72
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
@@ -0,0 +1,101 @@
+// +build windows
+
+package winterm
+
+const (
+	horizontal = iota
+	vertical
+)
+
+func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
+	if h.originMode {
+		sr := h.effectiveSr(info.Window)
+		return SMALL_RECT{
+			Top:    sr.top,
+			Bottom: sr.bottom,
+			Left:   0,
+			Right:  info.Size.X - 1,
+		}
+	} else {
+		return SMALL_RECT{
+			Top:    info.Window.Top,
+			Bottom: info.Window.Bottom,
+			Left:   0,
+			Right:  info.Size.X - 1,
+		}
+	}
+}
+
+// setCursorPosition sets the cursor to the specified position, bounded to the screen size
+func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
+	position.X = ensureInRange(position.X, window.Left, window.Right)
+	position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
+	err := SetConsoleCursorPosition(h.fd, position)
+	if err != nil {
+		return err
+	}
+	h.logf("Cursor position set: (%d, %d)", position.X, position.Y)
+	return err
+}
+
+func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
+	return h.moveCursor(vertical, param)
+}
+
+func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
+	return h.moveCursor(horizontal, param)
+}
+
+func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	position := info.CursorPosition
+	switch moveMode {
+	case horizontal:
+		position.X += int16(param)
+	case vertical:
+		position.Y += int16(param)
+	}
+
+	if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	position := info.CursorPosition
+	position.X = 0
+	position.Y += int16(param)
+
+	if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	position := info.CursorPosition
+	position.X = int16(param) - 1
+
+	if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
new file mode 100644
index 000000000..244b5fa25
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
@@ -0,0 +1,84 @@
+// +build windows
+
+package winterm
+
+import "github.com/Azure/go-ansiterm"
+
+func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
+	// Ignore an invalid (negative area) request
+	if toCoord.Y < fromCoord.Y {
+		return nil
+	}
+
+	var err error
+
+	var coordStart = COORD{}
+	var coordEnd = COORD{}
+
+	xCurrent, yCurrent := fromCoord.X, fromCoord.Y
+	xEnd, yEnd := toCoord.X, toCoord.Y
+
+	// Clear any partial initial line
+	if xCurrent > 0 {
+		coordStart.X, coordStart.Y = xCurrent, yCurrent
+		coordEnd.X, coordEnd.Y = xEnd, yCurrent
+
+		err = h.clearRect(attributes, coordStart, coordEnd)
+		if err != nil {
+			return err
+		}
+
+		xCurrent = 0
+		yCurrent += 1
+	}
+
+	// Clear intervening rectangular section
+	if yCurrent < yEnd {
+		coordStart.X, coordStart.Y = xCurrent, yCurrent
+		coordEnd.X, coordEnd.Y = xEnd, yEnd-1
+
+		err = h.clearRect(attributes, coordStart, coordEnd)
+		if err != nil {
+			return err
+		}
+
+		xCurrent = 0
+		yCurrent = yEnd
+	}
+
+	// Clear remaining partial ending line
+	coordStart.X, coordStart.Y = xCurrent, yCurrent
+	coordEnd.X, coordEnd.Y = xEnd, yEnd
+
+	err = h.clearRect(attributes, coordStart, coordEnd)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
+	region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
+	width := toCoord.X - fromCoord.X + 1
+	height := toCoord.Y - fromCoord.Y + 1
+	size := uint32(width) * uint32(height)
+
+	if size <= 0 {
+		return nil
+	}
+
+	buffer := make([]CHAR_INFO, size)
+
+	char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
+	for i := 0; i < int(size); i++ {
+		buffer[i] = char
+	}
+
+	err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &region)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
new file mode 100644
index 000000000..2d27fa1d0
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
@@ -0,0 +1,118 @@
+// +build windows
+
+package winterm
+
+// effectiveSr gets the current effective scroll region in buffer coordinates
+func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
+	top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
+	bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
+	if top >= bottom {
+		top = window.Top
+		bottom = window.Bottom
+	}
+	return scrollRegion{top: top, bottom: bottom}
+}
+
+func (h *windowsAnsiEventHandler) scrollUp(param int) error {
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	sr := h.effectiveSr(info.Window)
+	return h.scroll(param, sr, info)
+}
+
+func (h *windowsAnsiEventHandler) scrollDown(param int) error {
+	return h.scrollUp(-param)
+}
+
+func (h *windowsAnsiEventHandler) deleteLines(param int) error {
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	start := info.CursorPosition.Y
+	sr := h.effectiveSr(info.Window)
+	// Lines cannot be inserted or deleted outside the scrolling region.
+	if start >= sr.top && start <= sr.bottom {
+		sr.top = start
+		return h.scroll(param, sr, info)
+	} else {
+		return nil
+	}
+}
+
+func (h *windowsAnsiEventHandler) insertLines(param int) error {
+	return h.deleteLines(-param)
+}
+
+// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
+func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
+	h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
+	h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
+
+	// Copy from and clip to the scroll region (full buffer width)
+	scrollRect := SMALL_RECT{
+		Top:    sr.top,
+		Bottom: sr.bottom,
+		Left:   0,
+		Right:  info.Size.X - 1,
+	}
+
+	// Origin to which area should be copied
+	destOrigin := COORD{
+		X: 0,
+		Y: sr.top - int16(param),
+	}
+
+	char := CHAR_INFO{
+		UnicodeChar: ' ',
+		Attributes:  h.attributes,
+	}
+
+	if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+	return h.scrollLine(param, info.CursorPosition, info)
+}
+
+func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
+	return h.deleteCharacters(-param)
+}
+
+// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
+func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
+	// Copy from and clip to the scroll region (full buffer width)
+	scrollRect := SMALL_RECT{
+		Top:    position.Y,
+		Bottom: position.Y,
+		Left:   position.X,
+		Right:  info.Size.X - 1,
+	}
+
+	// Origin to which area should be copied
+	destOrigin := COORD{
+		X: position.X - int16(columns),
+		Y: position.Y,
+	}
+
+	char := CHAR_INFO{
+		UnicodeChar: ' ',
+		Attributes:  h.attributes,
+	}
+
+	if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
new file mode 100644
index 000000000..afa7635d7
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
@@ -0,0 +1,9 @@
+// +build windows
+
+package winterm
+
+// AddInRange increments a value by the passed quantity while ensuring the values
+// always remain within the supplied min / max range.
+func addInRange(n int16, increment int16, min int16, max int16) int16 {
+	return ensureInRange(n+increment, min, max)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
new file mode 100644
index 000000000..2d40fb75a
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
@@ -0,0 +1,743 @@
+// +build windows
+
+package winterm
+
+import (
+	"bytes"
+	"log"
+	"os"
+	"strconv"
+
+	"github.com/Azure/go-ansiterm"
+)
+
+type windowsAnsiEventHandler struct {
+	fd             uintptr
+	file           *os.File
+	infoReset      *CONSOLE_SCREEN_BUFFER_INFO
+	sr             scrollRegion
+	buffer         bytes.Buffer
+	attributes     uint16
+	inverted       bool
+	wrapNext       bool
+	drewMarginByte bool
+	originMode     bool
+	marginByte     byte
+	curInfo        *CONSOLE_SCREEN_BUFFER_INFO
+	curPos         COORD
+	logf           func(string, ...interface{})
+}
+
+type Option func(*windowsAnsiEventHandler)
+
+func WithLogf(f func(string, ...interface{})) Option {
+	return func(w *windowsAnsiEventHandler) {
+		w.logf = f
+	}
+}
+
+func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
+	infoReset, err := GetConsoleScreenBufferInfo(fd)
+	if err != nil {
+		return nil
+	}
+
+	h := &windowsAnsiEventHandler{
+		fd:         fd,
+		file:       file,
+		infoReset:  infoReset,
+		attributes: infoReset.Attributes,
+	}
+	for _, o := range opts {
+		o(h)
+	}
+
+	if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
+		logFile, _ := os.Create("winEventHandler.log")
+		logger := log.New(logFile, "", log.LstdFlags)
+		if h.logf != nil {
+			l := h.logf
+			h.logf = func(s string, v ...interface{}) {
+				l(s, v...)
+				logger.Printf(s, v...)
+			}
+		} else {
+			h.logf = logger.Printf
+		}
+	}
+
+	if h.logf == nil {
+		h.logf = func(string, ...interface{}) {}
+	}
+
+	return h
+}
+
+type scrollRegion struct {
+	top    int16
+	bottom int16
+}
+
+// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
+// current cursor position and scroll region settings, in which case it returns
+// true. If no special handling is necessary, then it does nothing and returns
+// false.
+//
+// In the false case, the caller should ensure that a carriage return
+// and line feed are inserted or that the text is otherwise wrapped.
+func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
+	if h.wrapNext {
+		if err := h.Flush(); err != nil {
+			return false, err
+		}
+		h.clearWrap()
+	}
+	pos, info, err := h.getCurrentInfo()
+	if err != nil {
+		return false, err
+	}
+	sr := h.effectiveSr(info.Window)
+	if pos.Y == sr.bottom {
+		// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
+		// is the full window.
+		if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
+			if includeCR {
+				pos.X = 0
+				h.updatePos(pos)
+			}
+			return false, nil
+		}
+
+		// A custom scroll region is active. Scroll the window manually to simulate
+		// the LF.
+		if err := h.Flush(); err != nil {
+			return false, err
+		}
+		h.logf("Simulating LF inside scroll region")
+		if err := h.scrollUp(1); err != nil {
+			return false, err
+		}
+		if includeCR {
+			pos.X = 0
+			if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+				return false, err
+			}
+		}
+		return true, nil
+
+	} else if pos.Y < info.Window.Bottom {
+		// Let Windows handle the LF.
+		pos.Y++
+		if includeCR {
+			pos.X = 0
+		}
+		h.updatePos(pos)
+		return false, nil
+	} else {
+		// The cursor is at the bottom of the screen but outside the scroll
+		// region. Skip the LF.
+		h.logf("Simulating LF outside scroll region")
+		if includeCR {
+			if err := h.Flush(); err != nil {
+				return false, err
+			}
+			pos.X = 0
+			if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+				return false, err
+			}
+		}
+		return true, nil
+	}
+}
+
+// executeLF executes a LF without a CR.
+func (h *windowsAnsiEventHandler) executeLF() error {
+	handled, err := h.simulateLF(false)
+	if err != nil {
+		return err
+	}
+	if !handled {
+		// Windows LF will reset the cursor column position. Write the LF
+		// and restore the cursor position.
+		pos, _, err := h.getCurrentInfo()
+		if err != nil {
+			return err
+		}
+		h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
+		if pos.X != 0 {
+			if err := h.Flush(); err != nil {
+				return err
+			}
+			h.logf("Resetting cursor position for LF without CR")
+			if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) Print(b byte) error {
+	if h.wrapNext {
+		h.buffer.WriteByte(h.marginByte)
+		h.clearWrap()
+		if _, err := h.simulateLF(true); err != nil {
+			return err
+		}
+	}
+	pos, info, err := h.getCurrentInfo()
+	if err != nil {
+		return err
+	}
+	if pos.X == info.Size.X-1 {
+		h.wrapNext = true
+		h.marginByte = b
+	} else {
+		pos.X++
+		h.updatePos(pos)
+		h.buffer.WriteByte(b)
+	}
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) Execute(b byte) error {
+	switch b {
+	case ansiterm.ANSI_TAB:
+		h.logf("Execute(TAB)")
+		// Move to the next tab stop, but preserve auto-wrap if already set.
+		if !h.wrapNext {
+			pos, info, err := h.getCurrentInfo()
+			if err != nil {
+				return err
+			}
+			pos.X = (pos.X + 8) - pos.X%8
+			if pos.X >= info.Size.X {
+				pos.X = info.Size.X - 1
+			}
+			if err := h.Flush(); err != nil {
+				return err
+			}
+			if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+				return err
+			}
+		}
+		return nil
+
+	case ansiterm.ANSI_BEL:
+		h.buffer.WriteByte(ansiterm.ANSI_BEL)
+		return nil
+
+	case ansiterm.ANSI_BACKSPACE:
+		if h.wrapNext {
+			if err := h.Flush(); err != nil {
+				return err
+			}
+			h.clearWrap()
+		}
+		pos, _, err := h.getCurrentInfo()
+		if err != nil {
+			return err
+		}
+		if pos.X > 0 {
+			pos.X--
+			h.updatePos(pos)
+			h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
+		}
+		return nil
+
+	case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
+		// Treat as true LF.
+		return h.executeLF()
+
+	case ansiterm.ANSI_LINE_FEED:
+		// Simulate a CR and LF for now since there is no way in go-ansiterm
+		// to tell if the LF should include CR (and more things break when it's
+		// missing than when it's incorrectly added).
+		handled, err := h.simulateLF(true)
+		if handled || err != nil {
+			return err
+		}
+		return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
+
+	case ansiterm.ANSI_CARRIAGE_RETURN:
+		if h.wrapNext {
+			if err := h.Flush(); err != nil {
+				return err
+			}
+			h.clearWrap()
+		}
+		pos, _, err := h.getCurrentInfo()
+		if err != nil {
+			return err
+		}
+		if pos.X != 0 {
+			pos.X = 0
+			h.updatePos(pos)
+			h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
+		}
+		return nil
+
+	default:
+		return nil
+	}
+}
+
+func (h *windowsAnsiEventHandler) CUU(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.moveCursorVertical(-param)
+}
+
+func (h *windowsAnsiEventHandler) CUD(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.moveCursorVertical(param)
+}
+
+func (h *windowsAnsiEventHandler) CUF(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.moveCursorHorizontal(param)
+}
+
+func (h *windowsAnsiEventHandler) CUB(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.moveCursorHorizontal(-param)
+}
+
+func (h *windowsAnsiEventHandler) CNL(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.moveCursorLine(param)
+}
+
+func (h *windowsAnsiEventHandler) CPL(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.moveCursorLine(-param)
+}
+
+func (h *windowsAnsiEventHandler) CHA(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.moveCursorColumn(param)
+}
+
+func (h *windowsAnsiEventHandler) VPA(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("VPA: [[%d]]", param)
+	h.clearWrap()
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+	window := h.getCursorWindow(info)
+	position := info.CursorPosition
+	position.Y = window.Top + int16(param) - 1
+	return h.setCursorPosition(position, window)
+}
+
+func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("CUP: [[%d %d]]", row, col)
+	h.clearWrap()
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	window := h.getCursorWindow(info)
+	position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
+	return h.setCursorPosition(position, window)
+}
+
+func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("HVP: [[%d %d]]", row, col)
+	h.clearWrap()
+	return h.CUP(row, col)
+}
+
+func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
+	h.clearWrap()
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
+	h.clearWrap()
+	h.originMode = enable
+	return h.CUP(1, 1)
+}
+
+func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
+	h.clearWrap()
+	if err := h.ED(2); err != nil {
+		return err
+	}
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+	targetWidth := int16(80)
+	if use132 {
+		targetWidth = 132
+	}
+	if info.Size.X < targetWidth {
+		if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
+			h.logf("set buffer failed: %v", err)
+			return err
+		}
+	}
+	window := info.Window
+	window.Left = 0
+	window.Right = targetWidth - 1
+	if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
+		h.logf("set window failed: %v", err)
+		return err
+	}
+	if info.Size.X > targetWidth {
+		if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
+			h.logf("set buffer failed: %v", err)
+			return err
+		}
+	}
+	return SetConsoleCursorPosition(h.fd, COORD{0, 0})
+}
+
+func (h *windowsAnsiEventHandler) ED(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("ED: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+
+	// [J  -- Erases from the cursor to the end of the screen, including the cursor position.
+	// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
+	// [2J -- Erases the complete display. The cursor does not move.
+	// Notes:
+	// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
+
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	var start COORD
+	var end COORD
+
+	switch param {
+	case 0:
+		start = info.CursorPosition
+		end = COORD{info.Size.X - 1, info.Size.Y - 1}
+
+	case 1:
+		start = COORD{0, 0}
+		end = info.CursorPosition
+
+	case 2:
+		start = COORD{0, 0}
+		end = COORD{info.Size.X - 1, info.Size.Y - 1}
+	}
+
+	err = h.clearRange(h.attributes, start, end)
+	if err != nil {
+		return err
+	}
+
+	// If the whole buffer was cleared, move the window to the top while preserving
+	// the window-relative cursor position.
+	if param == 2 {
+		pos := info.CursorPosition
+		window := info.Window
+		pos.Y -= window.Top
+		window.Bottom -= window.Top
+		window.Top = 0
+		if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+			return err
+		}
+		if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) EL(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("EL: [%v]", strconv.Itoa(param))
+	h.clearWrap()
+
+	// [K  -- Erases from the cursor to the end of the line, including the cursor position.
+	// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
+	// [2K -- Erases the complete line.
+
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	var start COORD
+	var end COORD
+
+	switch param {
+	case 0:
+		start = info.CursorPosition
+		end = COORD{info.Size.X, info.CursorPosition.Y}
+
+	case 1:
+		start = COORD{0, info.CursorPosition.Y}
+		end = info.CursorPosition
+
+	case 2:
+		start = COORD{0, info.CursorPosition.Y}
+		end = COORD{info.Size.X, info.CursorPosition.Y}
+	}
+
+	err = h.clearRange(h.attributes, start, end)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) IL(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("IL: [%v]", strconv.Itoa(param))
+	h.clearWrap()
+	return h.insertLines(param)
+}
+
+func (h *windowsAnsiEventHandler) DL(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("DL: [%v]", strconv.Itoa(param))
+	h.clearWrap()
+	return h.deleteLines(param)
+}
+
+func (h *windowsAnsiEventHandler) ICH(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("ICH: [%v]", strconv.Itoa(param))
+	h.clearWrap()
+	return h.insertCharacters(param)
+}
+
+func (h *windowsAnsiEventHandler) DCH(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("DCH: [%v]", strconv.Itoa(param))
+	h.clearWrap()
+	return h.deleteCharacters(param)
+}
+
+func (h *windowsAnsiEventHandler) SGR(params []int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	strings := []string{}
+	for _, v := range params {
+		strings = append(strings, strconv.Itoa(v))
+	}
+
+	h.logf("SGR: [%v]", strings)
+
+	if len(params) <= 0 {
+		h.attributes = h.infoReset.Attributes
+		h.inverted = false
+	} else {
+		for _, attr := range params {
+
+			if attr == ansiterm.ANSI_SGR_RESET {
+				h.attributes = h.infoReset.Attributes
+				h.inverted = false
+				continue
+			}
+
+			h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
+		}
+	}
+
+	attributes := h.attributes
+	if h.inverted {
+		attributes = invertAttributes(attributes)
+	}
+	err := SetConsoleTextAttribute(h.fd, attributes)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) SU(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("SU: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.scrollUp(param)
+}
+
+func (h *windowsAnsiEventHandler) SD(param int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("SD: [%v]", []string{strconv.Itoa(param)})
+	h.clearWrap()
+	return h.scrollDown(param)
+}
+
+func (h *windowsAnsiEventHandler) DA(params []string) error {
+	h.logf("DA: [%v]", params)
+	// DA cannot be implemented because it must send data on the VT100 input stream,
+	// which is not available to go-ansiterm.
+	return nil
+}
+
+func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("DECSTBM: [%d, %d]", top, bottom)
+
+	// Windows is 0 indexed, Linux is 1 indexed
+	h.sr.top = int16(top - 1)
+	h.sr.bottom = int16(bottom - 1)
+
+	// This command also moves the cursor to the origin.
+	h.clearWrap()
+	return h.CUP(1, 1)
+}
+
+func (h *windowsAnsiEventHandler) RI() error {
+	if err := h.Flush(); err != nil {
+		return err
+	}
+	h.logf("RI: []")
+	h.clearWrap()
+
+	info, err := GetConsoleScreenBufferInfo(h.fd)
+	if err != nil {
+		return err
+	}
+
+	sr := h.effectiveSr(info.Window)
+	if info.CursorPosition.Y == sr.top {
+		return h.scrollDown(1)
+	}
+
+	return h.moveCursorVertical(-1)
+}
+
+func (h *windowsAnsiEventHandler) IND() error {
+	h.logf("IND: []")
+	return h.executeLF()
+}
+
+func (h *windowsAnsiEventHandler) Flush() error {
+	h.curInfo = nil
+	if h.buffer.Len() > 0 {
+		h.logf("Flush: [%s]", h.buffer.Bytes())
+		if _, err := h.buffer.WriteTo(h.file); err != nil {
+			return err
+		}
+	}
+
+	if h.wrapNext && !h.drewMarginByte {
+		h.logf("Flush: drawing margin byte '%c'", h.marginByte)
+
+		info, err := GetConsoleScreenBufferInfo(h.fd)
+		if err != nil {
+			return err
+		}
+
+		charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
+		size := COORD{1, 1}
+		position := COORD{0, 0}
+		region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
+		if err := WriteConsoleOutput(h.fd, charInfo, size, position, &region); err != nil {
+			return err
+		}
+		h.drewMarginByte = true
+	}
+	return nil
+}
+
+// cacheConsoleInfo ensures that the current console screen information has been queried
+// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
+func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
+	if h.curInfo == nil {
+		info, err := GetConsoleScreenBufferInfo(h.fd)
+		if err != nil {
+			return COORD{}, nil, err
+		}
+		h.curInfo = info
+		h.curPos = info.CursorPosition
+	}
+	return h.curPos, h.curInfo, nil
+}
+
+func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
+	if h.curInfo == nil {
+		panic("failed to call getCurrentInfo before calling updatePos")
+	}
+	h.curPos = pos
+}
+
+// clearWrap clears the state where the cursor is in the margin
+// waiting for the next character before wrapping the line. This must
+// be done before most operations that act on the cursor.
+func (h *windowsAnsiEventHandler) clearWrap() {
+	h.wrapNext = false
+	h.drewMarginByte = false
+}
diff --git a/vendor/github.com/Microsoft/go-winio/.gitattributes b/vendor/github.com/Microsoft/go-winio/.gitattributes
new file mode 100644
index 000000000..94f480de9
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
\ No newline at end of file
diff --git a/vendor/github.com/Microsoft/go-winio/.gitignore b/vendor/github.com/Microsoft/go-winio/.gitignore
new file mode 100644
index 000000000..815e20660
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/.gitignore
@@ -0,0 +1,10 @@
+.vscode/
+
+*.exe
+
+# testing
+testdata
+
+# go workspaces
+go.work
+go.work.sum
diff --git a/vendor/github.com/Microsoft/go-winio/.golangci.yml b/vendor/github.com/Microsoft/go-winio/.golangci.yml
new file mode 100644
index 000000000..faedfe937
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/.golangci.yml
@@ -0,0 +1,147 @@
+linters:
+  enable:
+    # style
+    - containedctx # struct contains a context
+    - dupl # duplicate code
+    - errname # erorrs are named correctly
+    - nolintlint # "//nolint" directives are properly explained
+    - revive # golint replacement
+    - unconvert # unnecessary conversions
+    - wastedassign
+
+    # bugs, performance, unused, etc ...
+    - contextcheck # function uses a non-inherited context
+    - errorlint # errors not wrapped for 1.13
+    - exhaustive # check exhaustiveness of enum switch statements
+    - gofmt # files are gofmt'ed
+    - gosec # security
+    - nilerr # returns nil even with non-nil error
+    - thelper #  test helpers without t.Helper()
+    - unparam # unused function params
+
+issues:
+  exclude-dirs:
+    - pkg/etw/sample
+
+  exclude-rules:
+    # err is very often shadowed in nested scopes
+    - linters:
+        - govet
+      text: '^shadow: declaration of "err" shadows declaration'
+
+    # ignore long lines for skip autogen directives
+    - linters:
+        - revive
+      text: "^line-length-limit: "
+      source: "^//(go:generate|sys) "
+
+    #TODO: remove after upgrading to go1.18
+    # ignore comment spacing for nolint and sys directives
+    - linters:
+        - revive
+      text: "^comment-spacings: no space between comment delimiter and comment text"
+      source: "//(cspell:|nolint:|sys |todo)"
+
+    # not on go 1.18 yet, so no any
+    - linters:
+        - revive
+      text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'"
+
+    # allow unjustified ignores of error checks in defer statements
+    - linters:
+        - nolintlint
+      text: "^directive `//nolint:errcheck` should provide explanation"
+      source: '^\s*defer '
+
+    # allow unjustified ignores of error lints for io.EOF
+    - linters:
+        - nolintlint
+      text: "^directive `//nolint:errorlint` should provide explanation"
+      source: '[=|!]= io.EOF'
+
+
+linters-settings:
+  exhaustive:
+    default-signifies-exhaustive: true
+  govet:
+    enable-all: true
+    disable:
+      # struct order is often for Win32 compat
+      # also, ignore pointer bytes/GC issues for now until performance becomes an issue
+      - fieldalignment
+  nolintlint:
+    require-explanation: true
+    require-specific: true
+  revive:
+    # revive is more configurable than static check, so likely the preferred alternative to static-check
+    # (once the perf issue is solved: https://github.com/golangci/golangci-lint/issues/2997)
+    enable-all-rules:
+      true
+      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
+    rules:
+      # rules with required arguments
+      - name: argument-limit
+        disabled: true
+      - name: banned-characters
+        disabled: true
+      - name: cognitive-complexity
+        disabled: true
+      - name: cyclomatic
+        disabled: true
+      - name: file-header
+        disabled: true
+      - name: function-length
+        disabled: true
+      - name: function-result-limit
+        disabled: true
+      - name: max-public-structs
+        disabled: true
+      # geneally annoying rules
+      - name: add-constant # complains about any and all strings and integers
+        disabled: true
+      - name: confusing-naming # we frequently use "Foo()" and "foo()" together
+        disabled: true
+      - name: flag-parameter # excessive, and a common idiom we use
+        disabled: true
+      - name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
+        disabled: true
+      # general config
+      - name: line-length-limit
+        arguments:
+          - 140
+      - name: var-naming
+        arguments:
+          - []
+          - - CID
+            - CRI
+            - CTRD
+            - DACL
+            - DLL
+            - DOS
+            - ETW
+            - FSCTL
+            - GCS
+            - GMSA
+            - HCS
+            - HV
+            - IO
+            - LCOW
+            - LDAP
+            - LPAC
+            - LTSC
+            - MMIO
+            - NT
+            - OCI
+            - PMEM
+            - PWSH
+            - RX
+            - SACl
+            - SID
+            - SMB
+            - TX
+            - VHD
+            - VHDX
+            - VMID
+            - VPCI
+            - WCOW
+            - WIM
diff --git a/vendor/github.com/Microsoft/go-winio/CODEOWNERS b/vendor/github.com/Microsoft/go-winio/CODEOWNERS
new file mode 100644
index 000000000..ae1b4942b
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/CODEOWNERS
@@ -0,0 +1 @@
+  * @microsoft/containerplat
diff --git a/vendor/github.com/Microsoft/go-winio/LICENSE b/vendor/github.com/Microsoft/go-winio/LICENSE
new file mode 100644
index 000000000..b8b569d77
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Microsoft
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/vendor/github.com/Microsoft/go-winio/README.md b/vendor/github.com/Microsoft/go-winio/README.md
new file mode 100644
index 000000000..7474b4f0b
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/README.md
@@ -0,0 +1,89 @@
+# go-winio [![Build Status](https://github.com/microsoft/go-winio/actions/workflows/ci.yml/badge.svg)](https://github.com/microsoft/go-winio/actions/workflows/ci.yml)
+
+This repository contains utilities for efficiently performing Win32 IO operations in
+Go. Currently, this is focused on accessing named pipes and other file handles, and
+for using named pipes as a net transport.
+
+This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go
+to reuse the thread to schedule another goroutine. This limits support to Windows Vista and
+newer operating systems. This is similar to the implementation of network sockets in Go's net
+package.
+
+Please see the LICENSE file for licensing information.
+
+## Contributing
+
+This project welcomes contributions and suggestions.
+Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that
+you have the right to, and actually do, grant us the rights to use your contribution.
+For details, visit [Microsoft CLA](https://cla.microsoft.com).
+
+When you submit a pull request, a CLA-bot will automatically determine whether you need to
+provide a CLA and decorate the PR appropriately (e.g., label, comment).
+Simply follow the instructions provided by the bot.
+You will only need to do this once across all repos using our CLA.
+
+Additionally, the pull request pipeline requires the following steps to be performed before
+mergining.
+
+### Code Sign-Off
+
+We require that contributors sign their commits using [`git commit --signoff`][git-commit-s]
+to certify they either authored the work themselves or otherwise have permission to use it in this project.
+
+A range of commits can be signed off using [`git rebase --signoff`][git-rebase-s].
+
+Please see [the developer certificate](https://developercertificate.org) for more info,
+as well as to make sure that you can attest to the rules listed.
+Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off.
+
+### Linting
+
+Code must pass a linting stage, which uses [`golangci-lint`][lint].
+The linting settings are stored in [`.golangci.yaml`](./.golangci.yaml), and can be run
+automatically with VSCode by adding the following to your workspace or folder settings:
+
+```json
+    "go.lintTool": "golangci-lint",
+    "go.lintOnSave": "package",
+```
+
+Additional editor [integrations options are also available][lint-ide].
+
+Alternatively, `golangci-lint` can be [installed locally][lint-install] and run from the repo root:
+
+```shell
+# use . or specify a path to only lint a package
+# to show all lint errors, use flags "--max-issues-per-linter=0 --max-same-issues=0"
+> golangci-lint run ./...
+```
+
+### Go Generate
+
+The pipeline checks that auto-generated code, via `go generate`, are up to date.
+
+This can be done for the entire repo:
+
+```shell
+> go generate ./...
+```
+
+## Code of Conduct
+
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
+For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
+contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+
+## Special Thanks
+
+Thanks to [natefinch][natefinch] for the inspiration for this library.
+See [npipe](https://github.com/natefinch/npipe) for another named pipe implementation.
+
+[lint]: https://golangci-lint.run/
+[lint-ide]: https://golangci-lint.run/usage/integrations/#editor-integration
+[lint-install]: https://golangci-lint.run/usage/install/#local-installation
+
+[git-commit-s]: https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s
+[git-rebase-s]: https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---signoff
+
+[natefinch]: https://github.com/natefinch
diff --git a/vendor/github.com/Microsoft/go-winio/SECURITY.md b/vendor/github.com/Microsoft/go-winio/SECURITY.md
new file mode 100644
index 000000000..869fdfe2b
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/SECURITY.md
@@ -0,0 +1,41 @@
+<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
+
+## Security
+
+Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
+
+If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
+
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+  * Full paths of source file(s) related to the manifestation of the issue
+  * The location of the affected source code (tag/branch/commit or direct URL)
+  * Any special configuration required to reproduce the issue
+  * Step-by-step instructions to reproduce the issue
+  * Proof-of-concept or exploit code (if possible)
+  * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Policy
+
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
+
+<!-- END MICROSOFT SECURITY.MD BLOCK -->
diff --git a/vendor/github.com/Microsoft/go-winio/backup.go b/vendor/github.com/Microsoft/go-winio/backup.go
new file mode 100644
index 000000000..b54341daa
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/backup.go
@@ -0,0 +1,287 @@
+//go:build windows
+// +build windows
+
+package winio
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"runtime"
+	"unicode/utf16"
+
+	"github.com/Microsoft/go-winio/internal/fs"
+	"golang.org/x/sys/windows"
+)
+
+//sys backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
+//sys backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
+
+const (
+	BackupData = uint32(iota + 1)
+	BackupEaData
+	BackupSecurity
+	BackupAlternateData
+	BackupLink
+	BackupPropertyData
+	BackupObjectId //revive:disable-line:var-naming ID, not Id
+	BackupReparseData
+	BackupSparseBlock
+	BackupTxfsData
+)
+
+const (
+	StreamSparseAttributes = uint32(8)
+)
+
+//nolint:revive // var-naming: ALL_CAPS
+const (
+	WRITE_DAC              = windows.WRITE_DAC
+	WRITE_OWNER            = windows.WRITE_OWNER
+	ACCESS_SYSTEM_SECURITY = windows.ACCESS_SYSTEM_SECURITY
+)
+
+// BackupHeader represents a backup stream of a file.
+type BackupHeader struct {
+	//revive:disable-next-line:var-naming ID, not Id
+	Id         uint32 // The backup stream ID
+	Attributes uint32 // Stream attributes
+	Size       int64  // The size of the stream in bytes
+	Name       string // The name of the stream (for BackupAlternateData only).
+	Offset     int64  // The offset of the stream in the file (for BackupSparseBlock only).
+}
+
+type win32StreamID struct {
+	StreamID   uint32
+	Attributes uint32
+	Size       uint64
+	NameSize   uint32
+}
+
+// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
+// of BackupHeader values.
+type BackupStreamReader struct {
+	r         io.Reader
+	bytesLeft int64
+}
+
+// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
+func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
+	return &BackupStreamReader{r, 0}
+}
+
+// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if
+// it was not completely read.
+func (r *BackupStreamReader) Next() (*BackupHeader, error) {
+	if r.bytesLeft > 0 { //nolint:nestif // todo: flatten this
+		if s, ok := r.r.(io.Seeker); ok {
+			// Make sure Seek on io.SeekCurrent sometimes succeeds
+			// before trying the actual seek.
+			if _, err := s.Seek(0, io.SeekCurrent); err == nil {
+				if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil {
+					return nil, err
+				}
+				r.bytesLeft = 0
+			}
+		}
+		if _, err := io.Copy(io.Discard, r); err != nil {
+			return nil, err
+		}
+	}
+	var wsi win32StreamID
+	if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
+		return nil, err
+	}
+	hdr := &BackupHeader{
+		Id:         wsi.StreamID,
+		Attributes: wsi.Attributes,
+		Size:       int64(wsi.Size),
+	}
+	if wsi.NameSize != 0 {
+		name := make([]uint16, int(wsi.NameSize/2))
+		if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
+			return nil, err
+		}
+		hdr.Name = windows.UTF16ToString(name)
+	}
+	if wsi.StreamID == BackupSparseBlock {
+		if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
+			return nil, err
+		}
+		hdr.Size -= 8
+	}
+	r.bytesLeft = hdr.Size
+	return hdr, nil
+}
+
+// Read reads from the current backup stream.
+func (r *BackupStreamReader) Read(b []byte) (int, error) {
+	if r.bytesLeft == 0 {
+		return 0, io.EOF
+	}
+	if int64(len(b)) > r.bytesLeft {
+		b = b[:r.bytesLeft]
+	}
+	n, err := r.r.Read(b)
+	r.bytesLeft -= int64(n)
+	if err == io.EOF {
+		err = io.ErrUnexpectedEOF
+	} else if r.bytesLeft == 0 && err == nil {
+		err = io.EOF
+	}
+	return n, err
+}
+
+// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
+type BackupStreamWriter struct {
+	w         io.Writer
+	bytesLeft int64
+}
+
+// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
+func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
+	return &BackupStreamWriter{w, 0}
+}
+
+// WriteHeader writes the next backup stream header and prepares for calls to Write().
+func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
+	if w.bytesLeft != 0 {
+		return fmt.Errorf("missing %d bytes", w.bytesLeft)
+	}
+	name := utf16.Encode([]rune(hdr.Name))
+	wsi := win32StreamID{
+		StreamID:   hdr.Id,
+		Attributes: hdr.Attributes,
+		Size:       uint64(hdr.Size),
+		NameSize:   uint32(len(name) * 2),
+	}
+	if hdr.Id == BackupSparseBlock {
+		// Include space for the int64 block offset
+		wsi.Size += 8
+	}
+	if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
+		return err
+	}
+	if len(name) != 0 {
+		if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
+			return err
+		}
+	}
+	if hdr.Id == BackupSparseBlock {
+		if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
+			return err
+		}
+	}
+	w.bytesLeft = hdr.Size
+	return nil
+}
+
+// Write writes to the current backup stream.
+func (w *BackupStreamWriter) Write(b []byte) (int, error) {
+	if w.bytesLeft < int64(len(b)) {
+		return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
+	}
+	n, err := w.w.Write(b)
+	w.bytesLeft -= int64(n)
+	return n, err
+}
+
+// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
+type BackupFileReader struct {
+	f               *os.File
+	includeSecurity bool
+	ctx             uintptr
+}
+
+// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
+// Read will attempt to read the security descriptor of the file.
+func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
+	r := &BackupFileReader{f, includeSecurity, 0}
+	return r
+}
+
+// Read reads a backup stream from the file by calling the Win32 API BackupRead().
+func (r *BackupFileReader) Read(b []byte) (int, error) {
+	var bytesRead uint32
+	err := backupRead(windows.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
+	if err != nil {
+		return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: err}
+	}
+	runtime.KeepAlive(r.f)
+	if bytesRead == 0 {
+		return 0, io.EOF
+	}
+	return int(bytesRead), nil
+}
+
+// Close frees Win32 resources associated with the BackupFileReader. It does not close
+// the underlying file.
+func (r *BackupFileReader) Close() error {
+	if r.ctx != 0 {
+		_ = backupRead(windows.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
+		runtime.KeepAlive(r.f)
+		r.ctx = 0
+	}
+	return nil
+}
+
+// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
+type BackupFileWriter struct {
+	f               *os.File
+	includeSecurity bool
+	ctx             uintptr
+}
+
+// NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true,
+// Write() will attempt to restore the security descriptor from the stream.
+func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
+	w := &BackupFileWriter{f, includeSecurity, 0}
+	return w
+}
+
+// Write restores a portion of the file using the provided backup stream.
+func (w *BackupFileWriter) Write(b []byte) (int, error) {
+	var bytesWritten uint32
+	err := backupWrite(windows.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
+	if err != nil {
+		return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: err}
+	}
+	runtime.KeepAlive(w.f)
+	if int(bytesWritten) != len(b) {
+		return int(bytesWritten), errors.New("not all bytes could be written")
+	}
+	return len(b), nil
+}
+
+// Close frees Win32 resources associated with the BackupFileWriter. It does not
+// close the underlying file.
+func (w *BackupFileWriter) Close() error {
+	if w.ctx != 0 {
+		_ = backupWrite(windows.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
+		runtime.KeepAlive(w.f)
+		w.ctx = 0
+	}
+	return nil
+}
+
+// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
+// or restore privileges have been acquired.
+//
+// If the file opened was a directory, it cannot be used with Readdir().
+func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
+	h, err := fs.CreateFile(path,
+		fs.AccessMask(access),
+		fs.FileShareMode(share),
+		nil,
+		fs.FileCreationDisposition(createmode),
+		fs.FILE_FLAG_BACKUP_SEMANTICS|fs.FILE_FLAG_OPEN_REPARSE_POINT,
+		0,
+	)
+	if err != nil {
+		err = &os.PathError{Op: "open", Path: path, Err: err}
+		return nil, err
+	}
+	return os.NewFile(uintptr(h), path), nil
+}
diff --git a/vendor/github.com/Microsoft/go-winio/doc.go b/vendor/github.com/Microsoft/go-winio/doc.go
new file mode 100644
index 000000000..1f5bfe2d5
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/doc.go
@@ -0,0 +1,22 @@
+// This package provides utilities for efficiently performing Win32 IO operations in Go.
+// Currently, this package is provides support for genreal IO and management of
+//   - named pipes
+//   - files
+//   - [Hyper-V sockets]
+//
+// This code is similar to Go's [net] package, and uses IO completion ports to avoid
+// blocking IO on system threads, allowing Go to reuse the thread to schedule other goroutines.
+//
+// This limits support to Windows Vista and newer operating systems.
+//
+// Additionally, this package provides support for:
+//   - creating and managing GUIDs
+//   - writing to [ETW]
+//   - opening and manageing VHDs
+//   - parsing [Windows Image files]
+//   - auto-generating Win32 API code
+//
+// [Hyper-V sockets]: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service
+// [ETW]: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-
+// [Windows Image files]: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/work-with-windows-images
+package winio
diff --git a/vendor/github.com/Microsoft/go-winio/ea.go b/vendor/github.com/Microsoft/go-winio/ea.go
new file mode 100644
index 000000000..e104dbdfd
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/ea.go
@@ -0,0 +1,137 @@
+package winio
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+)
+
+type fileFullEaInformation struct {
+	NextEntryOffset uint32
+	Flags           uint8
+	NameLength      uint8
+	ValueLength     uint16
+}
+
+var (
+	fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
+
+	errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
+	errEaNameTooLarge  = errors.New("extended attribute name too large")
+	errEaValueTooLarge = errors.New("extended attribute value too large")
+)
+
+// ExtendedAttribute represents a single Windows EA.
+type ExtendedAttribute struct {
+	Name  string
+	Value []byte
+	Flags uint8
+}
+
+func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
+	var info fileFullEaInformation
+	err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
+	if err != nil {
+		err = errInvalidEaBuffer
+		return ea, nb, err
+	}
+
+	nameOffset := fileFullEaInformationSize
+	nameLen := int(info.NameLength)
+	valueOffset := nameOffset + int(info.NameLength) + 1
+	valueLen := int(info.ValueLength)
+	nextOffset := int(info.NextEntryOffset)
+	if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
+		err = errInvalidEaBuffer
+		return ea, nb, err
+	}
+
+	ea.Name = string(b[nameOffset : nameOffset+nameLen])
+	ea.Value = b[valueOffset : valueOffset+valueLen]
+	ea.Flags = info.Flags
+	if info.NextEntryOffset != 0 {
+		nb = b[info.NextEntryOffset:]
+	}
+	return ea, nb, err
+}
+
+// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
+// buffer retrieved from BackupRead, ZwQueryEaFile, etc.
+func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
+	for len(b) != 0 {
+		ea, nb, err := parseEa(b)
+		if err != nil {
+			return nil, err
+		}
+
+		eas = append(eas, ea)
+		b = nb
+	}
+	return eas, err
+}
+
+func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
+	if int(uint8(len(ea.Name))) != len(ea.Name) {
+		return errEaNameTooLarge
+	}
+	if int(uint16(len(ea.Value))) != len(ea.Value) {
+		return errEaValueTooLarge
+	}
+	entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value))
+	withPadding := (entrySize + 3) &^ 3
+	nextOffset := uint32(0)
+	if !last {
+		nextOffset = withPadding
+	}
+	info := fileFullEaInformation{
+		NextEntryOffset: nextOffset,
+		Flags:           ea.Flags,
+		NameLength:      uint8(len(ea.Name)),
+		ValueLength:     uint16(len(ea.Value)),
+	}
+
+	err := binary.Write(buf, binary.LittleEndian, &info)
+	if err != nil {
+		return err
+	}
+
+	_, err = buf.Write([]byte(ea.Name))
+	if err != nil {
+		return err
+	}
+
+	err = buf.WriteByte(0)
+	if err != nil {
+		return err
+	}
+
+	_, err = buf.Write(ea.Value)
+	if err != nil {
+		return err
+	}
+
+	_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
+// buffer for use with BackupWrite, ZwSetEaFile, etc.
+func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
+	var buf bytes.Buffer
+	for i := range eas {
+		last := false
+		if i == len(eas)-1 {
+			last = true
+		}
+
+		err := writeEa(&buf, &eas[i], last)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return buf.Bytes(), nil
+}
diff --git a/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/go-winio/file.go
new file mode 100644
index 000000000..fe82a180d
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/file.go
@@ -0,0 +1,320 @@
+//go:build windows
+// +build windows
+
+package winio
+
+import (
+	"errors"
+	"io"
+	"runtime"
+	"sync"
+	"sync/atomic"
+	"syscall"
+	"time"
+
+	"golang.org/x/sys/windows"
+)
+
+//sys cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) = CancelIoEx
+//sys createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) = CreateIoCompletionPort
+//sys getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
+//sys setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
+//sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
+
+var (
+	ErrFileClosed = errors.New("file has already been closed")
+	ErrTimeout    = &timeoutError{}
+)
+
+type timeoutError struct{}
+
+func (*timeoutError) Error() string   { return "i/o timeout" }
+func (*timeoutError) Timeout() bool   { return true }
+func (*timeoutError) Temporary() bool { return true }
+
+type timeoutChan chan struct{}
+
+var ioInitOnce sync.Once
+var ioCompletionPort windows.Handle
+
+// ioResult contains the result of an asynchronous IO operation.
+type ioResult struct {
+	bytes uint32
+	err   error
+}
+
+// ioOperation represents an outstanding asynchronous Win32 IO.
+type ioOperation struct {
+	o  windows.Overlapped
+	ch chan ioResult
+}
+
+func initIO() {
+	h, err := createIoCompletionPort(windows.InvalidHandle, 0, 0, 0xffffffff)
+	if err != nil {
+		panic(err)
+	}
+	ioCompletionPort = h
+	go ioCompletionProcessor(h)
+}
+
+// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
+// It takes ownership of this handle and will close it if it is garbage collected.
+type win32File struct {
+	handle        windows.Handle
+	wg            sync.WaitGroup
+	wgLock        sync.RWMutex
+	closing       atomic.Bool
+	socket        bool
+	readDeadline  deadlineHandler
+	writeDeadline deadlineHandler
+}
+
+type deadlineHandler struct {
+	setLock     sync.Mutex
+	channel     timeoutChan
+	channelLock sync.RWMutex
+	timer       *time.Timer
+	timedout    atomic.Bool
+}
+
+// makeWin32File makes a new win32File from an existing file handle.
+func makeWin32File(h windows.Handle) (*win32File, error) {
+	f := &win32File{handle: h}
+	ioInitOnce.Do(initIO)
+	_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
+	if err != nil {
+		return nil, err
+	}
+	err = setFileCompletionNotificationModes(h, windows.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS|windows.FILE_SKIP_SET_EVENT_ON_HANDLE)
+	if err != nil {
+		return nil, err
+	}
+	f.readDeadline.channel = make(timeoutChan)
+	f.writeDeadline.channel = make(timeoutChan)
+	return f, nil
+}
+
+// Deprecated: use NewOpenFile instead.
+func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
+	return NewOpenFile(windows.Handle(h))
+}
+
+func NewOpenFile(h windows.Handle) (io.ReadWriteCloser, error) {
+	// If we return the result of makeWin32File directly, it can result in an
+	// interface-wrapped nil, rather than a nil interface value.
+	f, err := makeWin32File(h)
+	if err != nil {
+		return nil, err
+	}
+	return f, nil
+}
+
+// closeHandle closes the resources associated with a Win32 handle.
+func (f *win32File) closeHandle() {
+	f.wgLock.Lock()
+	// Atomically set that we are closing, releasing the resources only once.
+	if !f.closing.Swap(true) {
+		f.wgLock.Unlock()
+		// cancel all IO and wait for it to complete
+		_ = cancelIoEx(f.handle, nil)
+		f.wg.Wait()
+		// at this point, no new IO can start
+		windows.Close(f.handle)
+		f.handle = 0
+	} else {
+		f.wgLock.Unlock()
+	}
+}
+
+// Close closes a win32File.
+func (f *win32File) Close() error {
+	f.closeHandle()
+	return nil
+}
+
+// IsClosed checks if the file has been closed.
+func (f *win32File) IsClosed() bool {
+	return f.closing.Load()
+}
+
+// prepareIO prepares for a new IO operation.
+// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
+func (f *win32File) prepareIO() (*ioOperation, error) {
+	f.wgLock.RLock()
+	if f.closing.Load() {
+		f.wgLock.RUnlock()
+		return nil, ErrFileClosed
+	}
+	f.wg.Add(1)
+	f.wgLock.RUnlock()
+	c := &ioOperation{}
+	c.ch = make(chan ioResult)
+	return c, nil
+}
+
+// ioCompletionProcessor processes completed async IOs forever.
+func ioCompletionProcessor(h windows.Handle) {
+	for {
+		var bytes uint32
+		var key uintptr
+		var op *ioOperation
+		err := getQueuedCompletionStatus(h, &bytes, &key, &op, windows.INFINITE)
+		if op == nil {
+			panic(err)
+		}
+		op.ch <- ioResult{bytes, err}
+	}
+}
+
+// todo: helsaawy - create an asyncIO version that takes a context
+
+// asyncIO processes the return value from ReadFile or WriteFile, blocking until
+// the operation has actually completed.
+func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
+	if err != windows.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
+		return int(bytes), err
+	}
+
+	if f.closing.Load() {
+		_ = cancelIoEx(f.handle, &c.o)
+	}
+
+	var timeout timeoutChan
+	if d != nil {
+		d.channelLock.Lock()
+		timeout = d.channel
+		d.channelLock.Unlock()
+	}
+
+	var r ioResult
+	select {
+	case r = <-c.ch:
+		err = r.err
+		if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
+			if f.closing.Load() {
+				err = ErrFileClosed
+			}
+		} else if err != nil && f.socket {
+			// err is from Win32. Query the overlapped structure to get the winsock error.
+			var bytes, flags uint32
+			err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
+		}
+	case <-timeout:
+		_ = cancelIoEx(f.handle, &c.o)
+		r = <-c.ch
+		err = r.err
+		if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
+			err = ErrTimeout
+		}
+	}
+
+	// runtime.KeepAlive is needed, as c is passed via native
+	// code to ioCompletionProcessor, c must remain alive
+	// until the channel read is complete.
+	// todo: (de)allocate *ioOperation via win32 heap functions, instead of needing to KeepAlive?
+	runtime.KeepAlive(c)
+	return int(r.bytes), err
+}
+
+// Read reads from a file handle.
+func (f *win32File) Read(b []byte) (int, error) {
+	c, err := f.prepareIO()
+	if err != nil {
+		return 0, err
+	}
+	defer f.wg.Done()
+
+	if f.readDeadline.timedout.Load() {
+		return 0, ErrTimeout
+	}
+
+	var bytes uint32
+	err = windows.ReadFile(f.handle, b, &bytes, &c.o)
+	n, err := f.asyncIO(c, &f.readDeadline, bytes, err)
+	runtime.KeepAlive(b)
+
+	// Handle EOF conditions.
+	if err == nil && n == 0 && len(b) != 0 {
+		return 0, io.EOF
+	} else if err == windows.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno
+		return 0, io.EOF
+	}
+	return n, err
+}
+
+// Write writes to a file handle.
+func (f *win32File) Write(b []byte) (int, error) {
+	c, err := f.prepareIO()
+	if err != nil {
+		return 0, err
+	}
+	defer f.wg.Done()
+
+	if f.writeDeadline.timedout.Load() {
+		return 0, ErrTimeout
+	}
+
+	var bytes uint32
+	err = windows.WriteFile(f.handle, b, &bytes, &c.o)
+	n, err := f.asyncIO(c, &f.writeDeadline, bytes, err)
+	runtime.KeepAlive(b)
+	return n, err
+}
+
+func (f *win32File) SetReadDeadline(deadline time.Time) error {
+	return f.readDeadline.set(deadline)
+}
+
+func (f *win32File) SetWriteDeadline(deadline time.Time) error {
+	return f.writeDeadline.set(deadline)
+}
+
+func (f *win32File) Flush() error {
+	return windows.FlushFileBuffers(f.handle)
+}
+
+func (f *win32File) Fd() uintptr {
+	return uintptr(f.handle)
+}
+
+func (d *deadlineHandler) set(deadline time.Time) error {
+	d.setLock.Lock()
+	defer d.setLock.Unlock()
+
+	if d.timer != nil {
+		if !d.timer.Stop() {
+			<-d.channel
+		}
+		d.timer = nil
+	}
+	d.timedout.Store(false)
+
+	select {
+	case <-d.channel:
+		d.channelLock.Lock()
+		d.channel = make(chan struct{})
+		d.channelLock.Unlock()
+	default:
+	}
+
+	if deadline.IsZero() {
+		return nil
+	}
+
+	timeoutIO := func() {
+		d.timedout.Store(true)
+		close(d.channel)
+	}
+
+	now := time.Now()
+	duration := deadline.Sub(now)
+	if deadline.After(now) {
+		// Deadline is in the future, set a timer to wait
+		d.timer = time.AfterFunc(duration, timeoutIO)
+	} else {
+		// Deadline is in the past. Cancel all pending IO now.
+		timeoutIO()
+	}
+	return nil
+}
diff --git a/vendor/github.com/Microsoft/go-winio/fileinfo.go b/vendor/github.com/Microsoft/go-winio/fileinfo.go
new file mode 100644
index 000000000..c860eb991
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/fileinfo.go
@@ -0,0 +1,106 @@
+//go:build windows
+// +build windows
+
+package winio
+
+import (
+	"os"
+	"runtime"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+)
+
+// FileBasicInfo contains file access time and file attributes information.
+type FileBasicInfo struct {
+	CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
+	FileAttributes                                          uint32
+	_                                                       uint32 // padding
+}
+
+// alignedFileBasicInfo is a FileBasicInfo, but aligned to uint64 by containing
+// uint64 rather than windows.Filetime. Filetime contains two uint32s. uint64
+// alignment is necessary to pass this as FILE_BASIC_INFO.
+type alignedFileBasicInfo struct {
+	CreationTime, LastAccessTime, LastWriteTime, ChangeTime uint64
+	FileAttributes                                          uint32
+	_                                                       uint32 // padding
+}
+
+// GetFileBasicInfo retrieves times and attributes for a file.
+func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
+	bi := &alignedFileBasicInfo{}
+	if err := windows.GetFileInformationByHandleEx(
+		windows.Handle(f.Fd()),
+		windows.FileBasicInfo,
+		(*byte)(unsafe.Pointer(bi)),
+		uint32(unsafe.Sizeof(*bi)),
+	); err != nil {
+		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
+	}
+	runtime.KeepAlive(f)
+	// Reinterpret the alignedFileBasicInfo as a FileBasicInfo so it matches the
+	// public API of this module. The data may be unnecessarily aligned.
+	return (*FileBasicInfo)(unsafe.Pointer(bi)), nil
+}
+
+// SetFileBasicInfo sets times and attributes for a file.
+func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
+	// Create an alignedFileBasicInfo based on a FileBasicInfo. The copy is
+	// suitable to pass to GetFileInformationByHandleEx.
+	biAligned := *(*alignedFileBasicInfo)(unsafe.Pointer(bi))
+	if err := windows.SetFileInformationByHandle(
+		windows.Handle(f.Fd()),
+		windows.FileBasicInfo,
+		(*byte)(unsafe.Pointer(&biAligned)),
+		uint32(unsafe.Sizeof(biAligned)),
+	); err != nil {
+		return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
+	}
+	runtime.KeepAlive(f)
+	return nil
+}
+
+// FileStandardInfo contains extended information for the file.
+// FILE_STANDARD_INFO in WinBase.h
+// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_standard_info
+type FileStandardInfo struct {
+	AllocationSize, EndOfFile int64
+	NumberOfLinks             uint32
+	DeletePending, Directory  bool
+}
+
+// GetFileStandardInfo retrieves ended information for the file.
+func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
+	si := &FileStandardInfo{}
+	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()),
+		windows.FileStandardInfo,
+		(*byte)(unsafe.Pointer(si)),
+		uint32(unsafe.Sizeof(*si))); err != nil {
+		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
+	}
+	runtime.KeepAlive(f)
+	return si, nil
+}
+
+// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
+// unique on a system.
+type FileIDInfo struct {
+	VolumeSerialNumber uint64
+	FileID             [16]byte
+}
+
+// GetFileID retrieves the unique (volume, file ID) pair for a file.
+func GetFileID(f *os.File) (*FileIDInfo, error) {
+	fileID := &FileIDInfo{}
+	if err := windows.GetFileInformationByHandleEx(
+		windows.Handle(f.Fd()),
+		windows.FileIdInfo,
+		(*byte)(unsafe.Pointer(fileID)),
+		uint32(unsafe.Sizeof(*fileID)),
+	); err != nil {
+		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
+	}
+	runtime.KeepAlive(f)
+	return fileID, nil
+}
diff --git a/vendor/github.com/Microsoft/go-winio/hvsock.go b/vendor/github.com/Microsoft/go-winio/hvsock.go
new file mode 100644
index 000000000..c4fdd9d4a
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/hvsock.go
@@ -0,0 +1,582 @@
+//go:build windows
+// +build windows
+
+package winio
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"time"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+
+	"github.com/Microsoft/go-winio/internal/socket"
+	"github.com/Microsoft/go-winio/pkg/guid"
+)
+
+const afHVSock = 34 // AF_HYPERV
+
+// Well known Service and VM IDs
+// https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
+
+// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
+func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
+	return guid.GUID{}
+}
+
+// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
+func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffffffffff
+	return guid.GUID{
+		Data1: 0xffffffff,
+		Data2: 0xffff,
+		Data3: 0xffff,
+		Data4: [8]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+	}
+}
+
+// HvsockGUIDLoopback is the Loopback VmId for accepting connections to the same partition as the connector.
+func HvsockGUIDLoopback() guid.GUID { // e0e16197-dd56-4a10-9195-5ee7a155a838
+	return guid.GUID{
+		Data1: 0xe0e16197,
+		Data2: 0xdd56,
+		Data3: 0x4a10,
+		Data4: [8]uint8{0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38},
+	}
+}
+
+// HvsockGUIDSiloHost is the address of a silo's host partition:
+//   - The silo host of a hosted silo is the utility VM.
+//   - The silo host of a silo on a physical host is the physical host.
+func HvsockGUIDSiloHost() guid.GUID { // 36bd0c5c-7276-4223-88ba-7d03b654c568
+	return guid.GUID{
+		Data1: 0x36bd0c5c,
+		Data2: 0x7276,
+		Data3: 0x4223,
+		Data4: [8]byte{0x88, 0xba, 0x7d, 0x03, 0xb6, 0x54, 0xc5, 0x68},
+	}
+}
+
+// HvsockGUIDChildren is the wildcard VmId for accepting connections from the connector's child partitions.
+func HvsockGUIDChildren() guid.GUID { // 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd
+	return guid.GUID{
+		Data1: 0x90db8b89,
+		Data2: 0xd35,
+		Data3: 0x4f79,
+		Data4: [8]uint8{0x8c, 0xe9, 0x49, 0xea, 0xa, 0xc8, 0xb7, 0xcd},
+	}
+}
+
+// HvsockGUIDParent is the wildcard VmId for accepting connections from the connector's parent partition.
+// Listening on this VmId accepts connection from:
+//   - Inside silos: silo host partition.
+//   - Inside hosted silo: host of the VM.
+//   - Inside VM: VM host.
+//   - Physical host: Not supported.
+func HvsockGUIDParent() guid.GUID { // a42e7cda-d03f-480c-9cc2-a4de20abb878
+	return guid.GUID{
+		Data1: 0xa42e7cda,
+		Data2: 0xd03f,
+		Data3: 0x480c,
+		Data4: [8]uint8{0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78},
+	}
+}
+
+// hvsockVsockServiceTemplate is the Service GUID used for the VSOCK protocol.
+func hvsockVsockServiceTemplate() guid.GUID { // 00000000-facb-11e6-bd58-64006a7986d3
+	return guid.GUID{
+		Data2: 0xfacb,
+		Data3: 0x11e6,
+		Data4: [8]uint8{0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3},
+	}
+}
+
+// An HvsockAddr is an address for a AF_HYPERV socket.
+type HvsockAddr struct {
+	VMID      guid.GUID
+	ServiceID guid.GUID
+}
+
+type rawHvsockAddr struct {
+	Family    uint16
+	_         uint16
+	VMID      guid.GUID
+	ServiceID guid.GUID
+}
+
+var _ socket.RawSockaddr = &rawHvsockAddr{}
+
+// Network returns the address's network name, "hvsock".
+func (*HvsockAddr) Network() string {
+	return "hvsock"
+}
+
+func (addr *HvsockAddr) String() string {
+	return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID)
+}
+
+// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
+func VsockServiceID(port uint32) guid.GUID {
+	g := hvsockVsockServiceTemplate() // make a copy
+	g.Data1 = port
+	return g
+}
+
+func (addr *HvsockAddr) raw() rawHvsockAddr {
+	return rawHvsockAddr{
+		Family:    afHVSock,
+		VMID:      addr.VMID,
+		ServiceID: addr.ServiceID,
+	}
+}
+
+func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
+	addr.VMID = raw.VMID
+	addr.ServiceID = raw.ServiceID
+}
+
+// Sockaddr returns a pointer to and the size of this struct.
+//
+// Implements the [socket.RawSockaddr] interface, and allows use in
+// [socket.Bind] and [socket.ConnectEx].
+func (r *rawHvsockAddr) Sockaddr() (unsafe.Pointer, int32, error) {
+	return unsafe.Pointer(r), int32(unsafe.Sizeof(rawHvsockAddr{})), nil
+}
+
+// Sockaddr interface allows use with `sockets.Bind()` and `.ConnectEx()`.
+func (r *rawHvsockAddr) FromBytes(b []byte) error {
+	n := int(unsafe.Sizeof(rawHvsockAddr{}))
+
+	if len(b) < n {
+		return fmt.Errorf("got %d, want %d: %w", len(b), n, socket.ErrBufferSize)
+	}
+
+	copy(unsafe.Slice((*byte)(unsafe.Pointer(r)), n), b[:n])
+	if r.Family != afHVSock {
+		return fmt.Errorf("got %d, want %d: %w", r.Family, afHVSock, socket.ErrAddrFamily)
+	}
+
+	return nil
+}
+
+// HvsockListener is a socket listener for the AF_HYPERV address family.
+type HvsockListener struct {
+	sock *win32File
+	addr HvsockAddr
+}
+
+var _ net.Listener = &HvsockListener{}
+
+// HvsockConn is a connected socket of the AF_HYPERV address family.
+type HvsockConn struct {
+	sock          *win32File
+	local, remote HvsockAddr
+}
+
+var _ net.Conn = &HvsockConn{}
+
+func newHVSocket() (*win32File, error) {
+	fd, err := windows.Socket(afHVSock, windows.SOCK_STREAM, 1)
+	if err != nil {
+		return nil, os.NewSyscallError("socket", err)
+	}
+	f, err := makeWin32File(fd)
+	if err != nil {
+		windows.Close(fd)
+		return nil, err
+	}
+	f.socket = true
+	return f, nil
+}
+
+// ListenHvsock listens for connections on the specified hvsock address.
+func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
+	l := &HvsockListener{addr: *addr}
+
+	var sock *win32File
+	sock, err = newHVSocket()
+	if err != nil {
+		return nil, l.opErr("listen", err)
+	}
+	defer func() {
+		if err != nil {
+			_ = sock.Close()
+		}
+	}()
+
+	sa := addr.raw()
+	err = socket.Bind(sock.handle, &sa)
+	if err != nil {
+		return nil, l.opErr("listen", os.NewSyscallError("socket", err))
+	}
+	err = windows.Listen(sock.handle, 16)
+	if err != nil {
+		return nil, l.opErr("listen", os.NewSyscallError("listen", err))
+	}
+	return &HvsockListener{sock: sock, addr: *addr}, nil
+}
+
+func (l *HvsockListener) opErr(op string, err error) error {
+	return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err}
+}
+
+// Addr returns the listener's network address.
+func (l *HvsockListener) Addr() net.Addr {
+	return &l.addr
+}
+
+// Accept waits for the next connection and returns it.
+func (l *HvsockListener) Accept() (_ net.Conn, err error) {
+	sock, err := newHVSocket()
+	if err != nil {
+		return nil, l.opErr("accept", err)
+	}
+	defer func() {
+		if sock != nil {
+			sock.Close()
+		}
+	}()
+	c, err := l.sock.prepareIO()
+	if err != nil {
+		return nil, l.opErr("accept", err)
+	}
+	defer l.sock.wg.Done()
+
+	// AcceptEx, per documentation, requires an extra 16 bytes per address.
+	//
+	// https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex
+	const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
+	var addrbuf [addrlen * 2]byte
+
+	var bytes uint32
+	err = windows.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o)
+	if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
+		return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
+	}
+
+	conn := &HvsockConn{
+		sock: sock,
+	}
+	// The local address returned in the AcceptEx buffer is the same as the Listener socket's
+	// address. However, the service GUID reported by GetSockName is different from the Listeners
+	// socket, and is sometimes the same as the local address of the socket that dialed the
+	// address, with the service GUID.Data1 incremented, but othertimes is different.
+	// todo: does the local address matter? is the listener's address or the actual address appropriate?
+	conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
+	conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
+
+	// initialize the accepted socket and update its properties with those of the listening socket
+	if err = windows.Setsockopt(sock.handle,
+		windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT,
+		(*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil {
+		return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err))
+	}
+
+	sock = nil
+	return conn, nil
+}
+
+// Close closes the listener, causing any pending Accept calls to fail.
+func (l *HvsockListener) Close() error {
+	return l.sock.Close()
+}
+
+// HvsockDialer configures and dials a Hyper-V Socket (ie, [HvsockConn]).
+type HvsockDialer struct {
+	// Deadline is the time the Dial operation must connect before erroring.
+	Deadline time.Time
+
+	// Retries is the number of additional connects to try if the connection times out, is refused,
+	// or the host is unreachable
+	Retries uint
+
+	// RetryWait is the time to wait after a connection error to retry
+	RetryWait time.Duration
+
+	rt *time.Timer // redial wait timer
+}
+
+// Dial the Hyper-V socket at addr.
+//
+// See [HvsockDialer.Dial] for more information.
+func Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
+	return (&HvsockDialer{}).Dial(ctx, addr)
+}
+
+// Dial attempts to connect to the Hyper-V socket at addr, and returns a connection if successful.
+// Will attempt (HvsockDialer).Retries if dialing fails, waiting (HvsockDialer).RetryWait between
+// retries.
+//
+// Dialing can be cancelled either by providing (HvsockDialer).Deadline, or cancelling ctx.
+func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
+	op := "dial"
+	// create the conn early to use opErr()
+	conn = &HvsockConn{
+		remote: *addr,
+	}
+
+	if !d.Deadline.IsZero() {
+		var cancel context.CancelFunc
+		ctx, cancel = context.WithDeadline(ctx, d.Deadline)
+		defer cancel()
+	}
+
+	// preemptive timeout/cancellation check
+	if err = ctx.Err(); err != nil {
+		return nil, conn.opErr(op, err)
+	}
+
+	sock, err := newHVSocket()
+	if err != nil {
+		return nil, conn.opErr(op, err)
+	}
+	defer func() {
+		if sock != nil {
+			sock.Close()
+		}
+	}()
+
+	sa := addr.raw()
+	err = socket.Bind(sock.handle, &sa)
+	if err != nil {
+		return nil, conn.opErr(op, os.NewSyscallError("bind", err))
+	}
+
+	c, err := sock.prepareIO()
+	if err != nil {
+		return nil, conn.opErr(op, err)
+	}
+	defer sock.wg.Done()
+	var bytes uint32
+	for i := uint(0); i <= d.Retries; i++ {
+		err = socket.ConnectEx(
+			sock.handle,
+			&sa,
+			nil, // sendBuf
+			0,   // sendDataLen
+			&bytes,
+			(*windows.Overlapped)(unsafe.Pointer(&c.o)))
+		_, err = sock.asyncIO(c, nil, bytes, err)
+		if i < d.Retries && canRedial(err) {
+			if err = d.redialWait(ctx); err == nil {
+				continue
+			}
+		}
+		break
+	}
+	if err != nil {
+		return nil, conn.opErr(op, os.NewSyscallError("connectex", err))
+	}
+
+	// update the connection properties, so shutdown can be used
+	if err = windows.Setsockopt(
+		sock.handle,
+		windows.SOL_SOCKET,
+		windows.SO_UPDATE_CONNECT_CONTEXT,
+		nil, // optvalue
+		0,   // optlen
+	); err != nil {
+		return nil, conn.opErr(op, os.NewSyscallError("setsockopt", err))
+	}
+
+	// get the local name
+	var sal rawHvsockAddr
+	err = socket.GetSockName(sock.handle, &sal)
+	if err != nil {
+		return nil, conn.opErr(op, os.NewSyscallError("getsockname", err))
+	}
+	conn.local.fromRaw(&sal)
+
+	// one last check for timeout, since asyncIO doesn't check the context
+	if err = ctx.Err(); err != nil {
+		return nil, conn.opErr(op, err)
+	}
+
+	conn.sock = sock
+	sock = nil
+
+	return conn, nil
+}
+
+// redialWait waits before attempting to redial, resetting the timer as appropriate.
+func (d *HvsockDialer) redialWait(ctx context.Context) (err error) {
+	if d.RetryWait == 0 {
+		return nil
+	}
+
+	if d.rt == nil {
+		d.rt = time.NewTimer(d.RetryWait)
+	} else {
+		// should already be stopped and drained
+		d.rt.Reset(d.RetryWait)
+	}
+
+	select {
+	case <-ctx.Done():
+	case <-d.rt.C:
+		return nil
+	}
+
+	// stop and drain the timer
+	if !d.rt.Stop() {
+		<-d.rt.C
+	}
+	return ctx.Err()
+}
+
+// assumes error is a plain, unwrapped windows.Errno provided by direct syscall.
+func canRedial(err error) bool {
+	//nolint:errorlint // guaranteed to be an Errno
+	switch err {
+	case windows.WSAECONNREFUSED, windows.WSAENETUNREACH, windows.WSAETIMEDOUT,
+		windows.ERROR_CONNECTION_REFUSED, windows.ERROR_CONNECTION_UNAVAIL:
+		return true
+	default:
+		return false
+	}
+}
+
+func (conn *HvsockConn) opErr(op string, err error) error {
+	// translate from "file closed" to "socket closed"
+	if errors.Is(err, ErrFileClosed) {
+		err = socket.ErrSocketClosed
+	}
+	return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
+}
+
+func (conn *HvsockConn) Read(b []byte) (int, error) {
+	c, err := conn.sock.prepareIO()
+	if err != nil {
+		return 0, conn.opErr("read", err)
+	}
+	defer conn.sock.wg.Done()
+	buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
+	var flags, bytes uint32
+	err = windows.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
+	n, err := conn.sock.asyncIO(c, &conn.sock.readDeadline, bytes, err)
+	if err != nil {
+		var eno windows.Errno
+		if errors.As(err, &eno) {
+			err = os.NewSyscallError("wsarecv", eno)
+		}
+		return 0, conn.opErr("read", err)
+	} else if n == 0 {
+		err = io.EOF
+	}
+	return n, err
+}
+
+func (conn *HvsockConn) Write(b []byte) (int, error) {
+	t := 0
+	for len(b) != 0 {
+		n, err := conn.write(b)
+		if err != nil {
+			return t + n, err
+		}
+		t += n
+		b = b[n:]
+	}
+	return t, nil
+}
+
+func (conn *HvsockConn) write(b []byte) (int, error) {
+	c, err := conn.sock.prepareIO()
+	if err != nil {
+		return 0, conn.opErr("write", err)
+	}
+	defer conn.sock.wg.Done()
+	buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
+	var bytes uint32
+	err = windows.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
+	n, err := conn.sock.asyncIO(c, &conn.sock.writeDeadline, bytes, err)
+	if err != nil {
+		var eno windows.Errno
+		if errors.As(err, &eno) {
+			err = os.NewSyscallError("wsasend", eno)
+		}
+		return 0, conn.opErr("write", err)
+	}
+	return n, err
+}
+
+// Close closes the socket connection, failing any pending read or write calls.
+func (conn *HvsockConn) Close() error {
+	return conn.sock.Close()
+}
+
+func (conn *HvsockConn) IsClosed() bool {
+	return conn.sock.IsClosed()
+}
+
+// shutdown disables sending or receiving on a socket.
+func (conn *HvsockConn) shutdown(how int) error {
+	if conn.IsClosed() {
+		return socket.ErrSocketClosed
+	}
+
+	err := windows.Shutdown(conn.sock.handle, how)
+	if err != nil {
+		// If the connection was closed, shutdowns fail with "not connected"
+		if errors.Is(err, windows.WSAENOTCONN) ||
+			errors.Is(err, windows.WSAESHUTDOWN) {
+			err = socket.ErrSocketClosed
+		}
+		return os.NewSyscallError("shutdown", err)
+	}
+	return nil
+}
+
+// CloseRead shuts down the read end of the socket, preventing future read operations.
+func (conn *HvsockConn) CloseRead() error {
+	err := conn.shutdown(windows.SHUT_RD)
+	if err != nil {
+		return conn.opErr("closeread", err)
+	}
+	return nil
+}
+
+// CloseWrite shuts down the write end of the socket, preventing future write operations and
+// notifying the other endpoint that no more data will be written.
+func (conn *HvsockConn) CloseWrite() error {
+	err := conn.shutdown(windows.SHUT_WR)
+	if err != nil {
+		return conn.opErr("closewrite", err)
+	}
+	return nil
+}
+
+// LocalAddr returns the local address of the connection.
+func (conn *HvsockConn) LocalAddr() net.Addr {
+	return &conn.local
+}
+
+// RemoteAddr returns the remote address of the connection.
+func (conn *HvsockConn) RemoteAddr() net.Addr {
+	return &conn.remote
+}
+
+// SetDeadline implements the net.Conn SetDeadline method.
+func (conn *HvsockConn) SetDeadline(t time.Time) error {
+	// todo: implement `SetDeadline` for `win32File`
+	if err := conn.SetReadDeadline(t); err != nil {
+		return fmt.Errorf("set read deadline: %w", err)
+	}
+	if err := conn.SetWriteDeadline(t); err != nil {
+		return fmt.Errorf("set write deadline: %w", err)
+	}
+	return nil
+}
+
+// SetReadDeadline implements the net.Conn SetReadDeadline method.
+func (conn *HvsockConn) SetReadDeadline(t time.Time) error {
+	return conn.sock.SetReadDeadline(t)
+}
+
+// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+func (conn *HvsockConn) SetWriteDeadline(t time.Time) error {
+	return conn.sock.SetWriteDeadline(t)
+}
diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/doc.go b/vendor/github.com/Microsoft/go-winio/internal/fs/doc.go
new file mode 100644
index 000000000..1f6538817
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/internal/fs/doc.go
@@ -0,0 +1,2 @@
+// This package contains Win32 filesystem functionality.
+package fs
diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go b/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go
new file mode 100644
index 000000000..0cd9621df
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/internal/fs/fs.go
@@ -0,0 +1,262 @@
+//go:build windows
+
+package fs
+
+import (
+	"golang.org/x/sys/windows"
+
+	"github.com/Microsoft/go-winio/internal/stringbuffer"
+)
+
+//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
+
+// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
+//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
+
+const NullHandle windows.Handle = 0
+
+// AccessMask defines standard, specific, and generic rights.
+//
+// Used with CreateFile and NtCreateFile (and co.).
+//
+//	Bitmask:
+//	 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+//	 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+//	+---------------+---------------+-------------------------------+
+//	|G|G|G|G|Resvd|A| StandardRights|         SpecificRights        |
+//	|R|W|E|A|     |S|               |                               |
+//	+-+-------------+---------------+-------------------------------+
+//
+//	GR     Generic Read
+//	GW     Generic Write
+//	GE     Generic Exectue
+//	GA     Generic All
+//	Resvd  Reserved
+//	AS     Access Security System
+//
+// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask
+//
+// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
+//
+// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
+type AccessMask = windows.ACCESS_MASK
+
+//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
+const (
+	// Not actually any.
+	//
+	// For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device"
+	// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
+	FILE_ANY_ACCESS AccessMask = 0
+
+	GENERIC_READ           AccessMask = 0x8000_0000
+	GENERIC_WRITE          AccessMask = 0x4000_0000
+	GENERIC_EXECUTE        AccessMask = 0x2000_0000
+	GENERIC_ALL            AccessMask = 0x1000_0000
+	ACCESS_SYSTEM_SECURITY AccessMask = 0x0100_0000
+
+	// Specific Object Access
+	// from ntioapi.h
+
+	FILE_READ_DATA      AccessMask = (0x0001) // file & pipe
+	FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory
+
+	FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe
+	FILE_ADD_FILE   AccessMask = (0x0002) // directory
+
+	FILE_APPEND_DATA          AccessMask = (0x0004) // file
+	FILE_ADD_SUBDIRECTORY     AccessMask = (0x0004) // directory
+	FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe
+
+	FILE_READ_EA         AccessMask = (0x0008) // file & directory
+	FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
+
+	FILE_WRITE_EA         AccessMask = (0x0010) // file & directory
+	FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
+
+	FILE_EXECUTE  AccessMask = (0x0020) // file
+	FILE_TRAVERSE AccessMask = (0x0020) // directory
+
+	FILE_DELETE_CHILD AccessMask = (0x0040) // directory
+
+	FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all
+
+	FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all
+
+	FILE_ALL_ACCESS      AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
+	FILE_GENERIC_READ    AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
+	FILE_GENERIC_WRITE   AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
+	FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
+
+	SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
+
+	// Standard Access
+	// from ntseapi.h
+
+	DELETE       AccessMask = 0x0001_0000
+	READ_CONTROL AccessMask = 0x0002_0000
+	WRITE_DAC    AccessMask = 0x0004_0000
+	WRITE_OWNER  AccessMask = 0x0008_0000
+	SYNCHRONIZE  AccessMask = 0x0010_0000
+
+	STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
+
+	STANDARD_RIGHTS_READ    AccessMask = READ_CONTROL
+	STANDARD_RIGHTS_WRITE   AccessMask = READ_CONTROL
+	STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
+
+	STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
+)
+
+type FileShareMode uint32
+
+//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
+const (
+	FILE_SHARE_NONE        FileShareMode = 0x00
+	FILE_SHARE_READ        FileShareMode = 0x01
+	FILE_SHARE_WRITE       FileShareMode = 0x02
+	FILE_SHARE_DELETE      FileShareMode = 0x04
+	FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
+)
+
+type FileCreationDisposition uint32
+
+//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
+const (
+	// from winbase.h
+
+	CREATE_NEW        FileCreationDisposition = 0x01
+	CREATE_ALWAYS     FileCreationDisposition = 0x02
+	OPEN_EXISTING     FileCreationDisposition = 0x03
+	OPEN_ALWAYS       FileCreationDisposition = 0x04
+	TRUNCATE_EXISTING FileCreationDisposition = 0x05
+)
+
+// Create disposition values for NtCreate*
+type NTFileCreationDisposition uint32
+
+//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
+const (
+	// From ntioapi.h
+
+	FILE_SUPERSEDE           NTFileCreationDisposition = 0x00
+	FILE_OPEN                NTFileCreationDisposition = 0x01
+	FILE_CREATE              NTFileCreationDisposition = 0x02
+	FILE_OPEN_IF             NTFileCreationDisposition = 0x03
+	FILE_OVERWRITE           NTFileCreationDisposition = 0x04
+	FILE_OVERWRITE_IF        NTFileCreationDisposition = 0x05
+	FILE_MAXIMUM_DISPOSITION NTFileCreationDisposition = 0x05
+)
+
+// CreateFile and co. take flags or attributes together as one parameter.
+// Define alias until we can use generics to allow both
+//
+// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
+type FileFlagOrAttribute uint32
+
+//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
+const (
+	// from winnt.h
+
+	FILE_FLAG_WRITE_THROUGH       FileFlagOrAttribute = 0x8000_0000
+	FILE_FLAG_OVERLAPPED          FileFlagOrAttribute = 0x4000_0000
+	FILE_FLAG_NO_BUFFERING        FileFlagOrAttribute = 0x2000_0000
+	FILE_FLAG_RANDOM_ACCESS       FileFlagOrAttribute = 0x1000_0000
+	FILE_FLAG_SEQUENTIAL_SCAN     FileFlagOrAttribute = 0x0800_0000
+	FILE_FLAG_DELETE_ON_CLOSE     FileFlagOrAttribute = 0x0400_0000
+	FILE_FLAG_BACKUP_SEMANTICS    FileFlagOrAttribute = 0x0200_0000
+	FILE_FLAG_POSIX_SEMANTICS     FileFlagOrAttribute = 0x0100_0000
+	FILE_FLAG_OPEN_REPARSE_POINT  FileFlagOrAttribute = 0x0020_0000
+	FILE_FLAG_OPEN_NO_RECALL      FileFlagOrAttribute = 0x0010_0000
+	FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
+)
+
+// NtCreate* functions take a dedicated CreateOptions parameter.
+//
+// https://learn.microsoft.com/en-us/windows/win32/api/Winternl/nf-winternl-ntcreatefile
+//
+// https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-create-named-pipe-file
+type NTCreateOptions uint32
+
+//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
+const (
+	// From ntioapi.h
+
+	FILE_DIRECTORY_FILE            NTCreateOptions = 0x0000_0001
+	FILE_WRITE_THROUGH             NTCreateOptions = 0x0000_0002
+	FILE_SEQUENTIAL_ONLY           NTCreateOptions = 0x0000_0004
+	FILE_NO_INTERMEDIATE_BUFFERING NTCreateOptions = 0x0000_0008
+
+	FILE_SYNCHRONOUS_IO_ALERT    NTCreateOptions = 0x0000_0010
+	FILE_SYNCHRONOUS_IO_NONALERT NTCreateOptions = 0x0000_0020
+	FILE_NON_DIRECTORY_FILE      NTCreateOptions = 0x0000_0040
+	FILE_CREATE_TREE_CONNECTION  NTCreateOptions = 0x0000_0080
+
+	FILE_COMPLETE_IF_OPLOCKED NTCreateOptions = 0x0000_0100
+	FILE_NO_EA_KNOWLEDGE      NTCreateOptions = 0x0000_0200
+	FILE_DISABLE_TUNNELING    NTCreateOptions = 0x0000_0400
+	FILE_RANDOM_ACCESS        NTCreateOptions = 0x0000_0800
+
+	FILE_DELETE_ON_CLOSE        NTCreateOptions = 0x0000_1000
+	FILE_OPEN_BY_FILE_ID        NTCreateOptions = 0x0000_2000
+	FILE_OPEN_FOR_BACKUP_INTENT NTCreateOptions = 0x0000_4000
+	FILE_NO_COMPRESSION         NTCreateOptions = 0x0000_8000
+)
+
+type FileSQSFlag = FileFlagOrAttribute
+
+//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
+const (
+	// from winbase.h
+
+	SECURITY_ANONYMOUS      FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
+	SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
+	SECURITY_IMPERSONATION  FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
+	SECURITY_DELEGATION     FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
+
+	SECURITY_SQOS_PRESENT     FileSQSFlag = 0x0010_0000
+	SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F_0000
+)
+
+// GetFinalPathNameByHandle flags
+//
+// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters
+type GetFinalPathFlag uint32
+
+//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
+const (
+	GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
+
+	FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
+	FILE_NAME_OPENED     GetFinalPathFlag = 0x8
+
+	VOLUME_NAME_DOS  GetFinalPathFlag = 0x0
+	VOLUME_NAME_GUID GetFinalPathFlag = 0x1
+	VOLUME_NAME_NT   GetFinalPathFlag = 0x2
+	VOLUME_NAME_NONE GetFinalPathFlag = 0x4
+)
+
+// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
+// with the given handle and flags. It transparently takes care of creating a buffer of the
+// correct size for the call.
+//
+// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
+func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) {
+	b := stringbuffer.NewWString()
+	//TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n?
+	for {
+		n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags))
+		if err != nil {
+			return "", err
+		}
+		// If the buffer wasn't large enough, n will be the total size needed (including null terminator).
+		// Resize and try again.
+		if n > b.Cap() {
+			b.ResizeTo(n)
+			continue
+		}
+		// If the buffer is large enough, n will be the size not including the null terminator.
+		// Convert to a Go string and return.
+		return b.String(), nil
+	}
+}
diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/security.go b/vendor/github.com/Microsoft/go-winio/internal/fs/security.go
new file mode 100644
index 000000000..81760ac67
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/internal/fs/security.go
@@ -0,0 +1,12 @@
+package fs
+
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
+type SecurityImpersonationLevel int32 // C default enums underlying type is `int`, which is Go `int32`
+
+// Impersonation levels
+const (
+	SecurityAnonymous      SecurityImpersonationLevel = 0
+	SecurityIdentification SecurityImpersonationLevel = 1
+	SecurityImpersonation  SecurityImpersonationLevel = 2
+	SecurityDelegation     SecurityImpersonationLevel = 3
+)
diff --git a/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go
new file mode 100644
index 000000000..a94e234c7
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go
@@ -0,0 +1,61 @@
+//go:build windows
+
+// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
+
+package fs
+
+import (
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+)
+
+var _ unsafe.Pointer
+
+// Do the interface allocations only once for common
+// Errno values.
+const (
+	errnoERROR_IO_PENDING = 997
+)
+
+var (
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+	errERROR_EINVAL     error = syscall.EINVAL
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+	switch e {
+	case 0:
+		return errERROR_EINVAL
+	case errnoERROR_IO_PENDING:
+		return errERROR_IO_PENDING
+	}
+	return e
+}
+
+var (
+	modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+
+	procCreateFileW = modkernel32.NewProc("CreateFileW")
+)
+
+func CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return
+	}
+	return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
+}
+
+func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
+	r0, _, e1 := syscall.SyscallN(procCreateFileW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile))
+	handle = windows.Handle(r0)
+	if handle == windows.InvalidHandle {
+		err = errnoErr(e1)
+	}
+	return
+}
diff --git a/vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go b/vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
new file mode 100644
index 000000000..7e82f9afa
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
@@ -0,0 +1,20 @@
+package socket
+
+import (
+	"unsafe"
+)
+
+// RawSockaddr allows structs to be used with [Bind] and [ConnectEx]. The
+// struct must meet the Win32 sockaddr requirements specified here:
+// https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2
+//
+// Specifically, the struct size must be least larger than an int16 (unsigned short)
+// for the address family.
+type RawSockaddr interface {
+	// Sockaddr returns a pointer to the RawSockaddr and its struct size, allowing
+	// for the RawSockaddr's data to be overwritten by syscalls (if necessary).
+	//
+	// It is the callers responsibility to validate that the values are valid; invalid
+	// pointers or size can cause a panic.
+	Sockaddr() (unsafe.Pointer, int32, error)
+}
diff --git a/vendor/github.com/Microsoft/go-winio/internal/socket/socket.go b/vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
new file mode 100644
index 000000000..88580d974
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
@@ -0,0 +1,177 @@
+//go:build windows
+
+package socket
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"sync"
+	"syscall"
+	"unsafe"
+
+	"github.com/Microsoft/go-winio/pkg/guid"
+	"golang.org/x/sys/windows"
+)
+
+//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go socket.go
+
+//sys getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getsockname
+//sys getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getpeername
+//sys bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
+
+const socketError = uintptr(^uint32(0))
+
+var (
+	// todo(helsaawy): create custom error types to store the desired vs actual size and addr family?
+
+	ErrBufferSize     = errors.New("buffer size")
+	ErrAddrFamily     = errors.New("address family")
+	ErrInvalidPointer = errors.New("invalid pointer")
+	ErrSocketClosed   = fmt.Errorf("socket closed: %w", net.ErrClosed)
+)
+
+// todo(helsaawy): replace these with generics, ie: GetSockName[S RawSockaddr](s windows.Handle) (S, error)
+
+// GetSockName writes the local address of socket s to the [RawSockaddr] rsa.
+// If rsa is not large enough, the [windows.WSAEFAULT] is returned.
+func GetSockName(s windows.Handle, rsa RawSockaddr) error {
+	ptr, l, err := rsa.Sockaddr()
+	if err != nil {
+		return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
+	}
+
+	// although getsockname returns WSAEFAULT if the buffer is too small, it does not set
+	// &l to the correct size, so--apart from doubling the buffer repeatedly--there is no remedy
+	return getsockname(s, ptr, &l)
+}
+
+// GetPeerName returns the remote address the socket is connected to.
+//
+// See [GetSockName] for more information.
+func GetPeerName(s windows.Handle, rsa RawSockaddr) error {
+	ptr, l, err := rsa.Sockaddr()
+	if err != nil {
+		return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
+	}
+
+	return getpeername(s, ptr, &l)
+}
+
+func Bind(s windows.Handle, rsa RawSockaddr) (err error) {
+	ptr, l, err := rsa.Sockaddr()
+	if err != nil {
+		return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
+	}
+
+	return bind(s, ptr, l)
+}
+
+// "golang.org/x/sys/windows".ConnectEx and .Bind only accept internal implementations of the
+// their sockaddr interface, so they cannot be used with HvsockAddr
+// Replicate functionality here from
+// https://cs.opensource.google/go/x/sys/+/master:windows/syscall_windows.go
+
+// The function pointers to `AcceptEx`, `ConnectEx` and `GetAcceptExSockaddrs` must be loaded at
+// runtime via a WSAIoctl call:
+// https://docs.microsoft.com/en-us/windows/win32/api/Mswsock/nc-mswsock-lpfn_connectex#remarks
+
+type runtimeFunc struct {
+	id   guid.GUID
+	once sync.Once
+	addr uintptr
+	err  error
+}
+
+func (f *runtimeFunc) Load() error {
+	f.once.Do(func() {
+		var s windows.Handle
+		s, f.err = windows.Socket(windows.AF_INET, windows.SOCK_STREAM, windows.IPPROTO_TCP)
+		if f.err != nil {
+			return
+		}
+		defer windows.CloseHandle(s) //nolint:errcheck
+
+		var n uint32
+		f.err = windows.WSAIoctl(s,
+			windows.SIO_GET_EXTENSION_FUNCTION_POINTER,
+			(*byte)(unsafe.Pointer(&f.id)),
+			uint32(unsafe.Sizeof(f.id)),
+			(*byte)(unsafe.Pointer(&f.addr)),
+			uint32(unsafe.Sizeof(f.addr)),
+			&n,
+			nil, // overlapped
+			0,   // completionRoutine
+		)
+	})
+	return f.err
+}
+
+var (
+	// todo: add `AcceptEx` and `GetAcceptExSockaddrs`
+	WSAID_CONNECTEX = guid.GUID{ //revive:disable-line:var-naming ALL_CAPS
+		Data1: 0x25a207b9,
+		Data2: 0xddf3,
+		Data3: 0x4660,
+		Data4: [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
+	}
+
+	connectExFunc = runtimeFunc{id: WSAID_CONNECTEX}
+)
+
+func ConnectEx(
+	fd windows.Handle,
+	rsa RawSockaddr,
+	sendBuf *byte,
+	sendDataLen uint32,
+	bytesSent *uint32,
+	overlapped *windows.Overlapped,
+) error {
+	if err := connectExFunc.Load(); err != nil {
+		return fmt.Errorf("failed to load ConnectEx function pointer: %w", err)
+	}
+	ptr, n, err := rsa.Sockaddr()
+	if err != nil {
+		return err
+	}
+	return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
+}
+
+// BOOL LpfnConnectex(
+//   [in]           SOCKET s,
+//   [in]           const sockaddr *name,
+//   [in]           int namelen,
+//   [in, optional] PVOID lpSendBuffer,
+//   [in]           DWORD dwSendDataLength,
+//   [out]          LPDWORD lpdwBytesSent,
+//   [in]           LPOVERLAPPED lpOverlapped
+// )
+
+func connectEx(
+	s windows.Handle,
+	name unsafe.Pointer,
+	namelen int32,
+	sendBuf *byte,
+	sendDataLen uint32,
+	bytesSent *uint32,
+	overlapped *windows.Overlapped,
+) (err error) {
+	r1, _, e1 := syscall.SyscallN(connectExFunc.addr,
+		uintptr(s),
+		uintptr(name),
+		uintptr(namelen),
+		uintptr(unsafe.Pointer(sendBuf)),
+		uintptr(sendDataLen),
+		uintptr(unsafe.Pointer(bytesSent)),
+		uintptr(unsafe.Pointer(overlapped)),
+	)
+
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return err
+}
diff --git a/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
new file mode 100644
index 000000000..e1504126a
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
@@ -0,0 +1,69 @@
+//go:build windows
+
+// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
+
+package socket
+
+import (
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+)
+
+var _ unsafe.Pointer
+
+// Do the interface allocations only once for common
+// Errno values.
+const (
+	errnoERROR_IO_PENDING = 997
+)
+
+var (
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+	errERROR_EINVAL     error = syscall.EINVAL
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+	switch e {
+	case 0:
+		return errERROR_EINVAL
+	case errnoERROR_IO_PENDING:
+		return errERROR_IO_PENDING
+	}
+	return e
+}
+
+var (
+	modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
+
+	procbind        = modws2_32.NewProc("bind")
+	procgetpeername = modws2_32.NewProc("getpeername")
+	procgetsockname = modws2_32.NewProc("getsockname")
+)
+
+func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procbind.Addr(), uintptr(s), uintptr(name), uintptr(namelen))
+	if r1 == socketError {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procgetpeername.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
+	if r1 == socketError {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procgetsockname.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
+	if r1 == socketError {
+		err = errnoErr(e1)
+	}
+	return
+}
diff --git a/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go b/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go
new file mode 100644
index 000000000..42ebc019f
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go
@@ -0,0 +1,132 @@
+package stringbuffer
+
+import (
+	"sync"
+	"unicode/utf16"
+)
+
+// TODO: worth exporting and using in mkwinsyscall?
+
+// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate
+// large path strings:
+// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
+const MinWStringCap = 310
+
+// use *[]uint16 since []uint16 creates an extra allocation where the slice header
+// is copied to heap and then referenced via pointer in the interface header that sync.Pool
+// stores.
+var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly
+	New: func() interface{} {
+		b := make([]uint16, MinWStringCap)
+		return &b
+	},
+}
+
+func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) }
+
+// freeBuffer copies the slice header data, and puts a pointer to that in the pool.
+// This avoids taking a pointer to the slice header in WString, which can be set to nil.
+func freeBuffer(b []uint16) { pathPool.Put(&b) }
+
+// WString is a wide string buffer ([]uint16) meant for storing UTF-16 encoded strings
+// for interacting with Win32 APIs.
+// Sizes are specified as uint32 and not int.
+//
+// It is not thread safe.
+type WString struct {
+	// type-def allows casting to []uint16 directly, use struct to prevent that and allow adding fields in the future.
+
+	// raw buffer
+	b []uint16
+}
+
+// NewWString returns a [WString] allocated from a shared pool with an
+// initial capacity of at least [MinWStringCap].
+// Since the buffer may have been previously used, its contents are not guaranteed to be empty.
+//
+// The buffer should be freed via [WString.Free]
+func NewWString() *WString {
+	return &WString{
+		b: newBuffer(),
+	}
+}
+
+func (b *WString) Free() {
+	if b.empty() {
+		return
+	}
+	freeBuffer(b.b)
+	b.b = nil
+}
+
+// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the
+// previous buffer back into pool.
+func (b *WString) ResizeTo(c uint32) uint32 {
+	// already sufficient (or n is 0)
+	if c <= b.Cap() {
+		return b.Cap()
+	}
+
+	if c <= MinWStringCap {
+		c = MinWStringCap
+	}
+	// allocate at-least double buffer size, as is done in [bytes.Buffer] and other places
+	if c <= 2*b.Cap() {
+		c = 2 * b.Cap()
+	}
+
+	b2 := make([]uint16, c)
+	if !b.empty() {
+		copy(b2, b.b)
+		freeBuffer(b.b)
+	}
+	b.b = b2
+	return c
+}
+
+// Buffer returns the underlying []uint16 buffer.
+func (b *WString) Buffer() []uint16 {
+	if b.empty() {
+		return nil
+	}
+	return b.b
+}
+
+// Pointer returns a pointer to the first uint16 in the buffer.
+// If the [WString.Free] has already been called, the pointer will be nil.
+func (b *WString) Pointer() *uint16 {
+	if b.empty() {
+		return nil
+	}
+	return &b.b[0]
+}
+
+// String returns the returns the UTF-8 encoding of the UTF-16 string in the buffer.
+//
+// It assumes that the data is null-terminated.
+func (b *WString) String() string {
+	// Using [windows.UTF16ToString] would require importing "golang.org/x/sys/windows"
+	// and would make this code Windows-only, which makes no sense.
+	// So copy UTF16ToString code into here.
+	// If other windows-specific code is added, switch to [windows.UTF16ToString]
+
+	s := b.b
+	for i, v := range s {
+		if v == 0 {
+			s = s[:i]
+			break
+		}
+	}
+	return string(utf16.Decode(s))
+}
+
+// Cap returns the underlying buffer capacity.
+func (b *WString) Cap() uint32 {
+	if b.empty() {
+		return 0
+	}
+	return b.cap()
+}
+
+func (b *WString) cap() uint32 { return uint32(cap(b.b)) }
+func (b *WString) empty() bool { return b == nil || b.cap() == 0 }
diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go
new file mode 100644
index 000000000..a2da6639d
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/pipe.go
@@ -0,0 +1,586 @@
+//go:build windows
+// +build windows
+
+package winio
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"runtime"
+	"time"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+
+	"github.com/Microsoft/go-winio/internal/fs"
+)
+
+//sys connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) = ConnectNamedPipe
+//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error)  [failretval==windows.InvalidHandle] = CreateNamedPipeW
+//sys disconnectNamedPipe(pipe windows.Handle) (err error) = DisconnectNamedPipe
+//sys getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
+//sys getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
+//sys ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile
+//sys rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
+//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U
+//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl
+
+type PipeConn interface {
+	net.Conn
+	Disconnect() error
+	Flush() error
+}
+
+// type aliases for mkwinsyscall code
+type (
+	ntAccessMask              = fs.AccessMask
+	ntFileShareMode           = fs.FileShareMode
+	ntFileCreationDisposition = fs.NTFileCreationDisposition
+	ntFileOptions             = fs.NTCreateOptions
+)
+
+type ioStatusBlock struct {
+	Status, Information uintptr
+}
+
+//	typedef struct _OBJECT_ATTRIBUTES {
+//	  ULONG           Length;
+//	  HANDLE          RootDirectory;
+//	  PUNICODE_STRING ObjectName;
+//	  ULONG           Attributes;
+//	  PVOID           SecurityDescriptor;
+//	  PVOID           SecurityQualityOfService;
+//	} OBJECT_ATTRIBUTES;
+//
+// https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes
+type objectAttributes struct {
+	Length             uintptr
+	RootDirectory      uintptr
+	ObjectName         *unicodeString
+	Attributes         uintptr
+	SecurityDescriptor *securityDescriptor
+	SecurityQoS        uintptr
+}
+
+type unicodeString struct {
+	Length        uint16
+	MaximumLength uint16
+	Buffer        uintptr
+}
+
+//	typedef struct _SECURITY_DESCRIPTOR {
+//	  BYTE                        Revision;
+//	  BYTE                        Sbz1;
+//	  SECURITY_DESCRIPTOR_CONTROL Control;
+//	  PSID                        Owner;
+//	  PSID                        Group;
+//	  PACL                        Sacl;
+//	  PACL                        Dacl;
+//	} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
+//
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-security_descriptor
+type securityDescriptor struct {
+	Revision byte
+	Sbz1     byte
+	Control  uint16
+	Owner    uintptr
+	Group    uintptr
+	Sacl     uintptr //revive:disable-line:var-naming SACL, not Sacl
+	Dacl     uintptr //revive:disable-line:var-naming DACL, not Dacl
+}
+
+type ntStatus int32
+
+func (status ntStatus) Err() error {
+	if status >= 0 {
+		return nil
+	}
+	return rtlNtStatusToDosError(status)
+}
+
+var (
+	// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
+	ErrPipeListenerClosed = net.ErrClosed
+
+	errPipeWriteClosed = errors.New("pipe has been closed for write")
+)
+
+type win32Pipe struct {
+	*win32File
+	path string
+}
+
+var _ PipeConn = (*win32Pipe)(nil)
+
+type win32MessageBytePipe struct {
+	win32Pipe
+	writeClosed bool
+	readEOF     bool
+}
+
+type pipeAddress string
+
+func (f *win32Pipe) LocalAddr() net.Addr {
+	return pipeAddress(f.path)
+}
+
+func (f *win32Pipe) RemoteAddr() net.Addr {
+	return pipeAddress(f.path)
+}
+
+func (f *win32Pipe) SetDeadline(t time.Time) error {
+	if err := f.SetReadDeadline(t); err != nil {
+		return err
+	}
+	return f.SetWriteDeadline(t)
+}
+
+func (f *win32Pipe) Disconnect() error {
+	return disconnectNamedPipe(f.win32File.handle)
+}
+
+// CloseWrite closes the write side of a message pipe in byte mode.
+func (f *win32MessageBytePipe) CloseWrite() error {
+	if f.writeClosed {
+		return errPipeWriteClosed
+	}
+	err := f.win32File.Flush()
+	if err != nil {
+		return err
+	}
+	_, err = f.win32File.Write(nil)
+	if err != nil {
+		return err
+	}
+	f.writeClosed = true
+	return nil
+}
+
+// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
+// they are used to implement CloseWrite().
+func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
+	if f.writeClosed {
+		return 0, errPipeWriteClosed
+	}
+	if len(b) == 0 {
+		return 0, nil
+	}
+	return f.win32File.Write(b)
+}
+
+// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
+// mode pipe will return io.EOF, as will all subsequent reads.
+func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
+	if f.readEOF {
+		return 0, io.EOF
+	}
+	n, err := f.win32File.Read(b)
+	if err == io.EOF { //nolint:errorlint
+		// If this was the result of a zero-byte read, then
+		// it is possible that the read was due to a zero-size
+		// message. Since we are simulating CloseWrite with a
+		// zero-byte message, ensure that all future Read() calls
+		// also return EOF.
+		f.readEOF = true
+	} else if err == windows.ERROR_MORE_DATA { //nolint:errorlint // err is Errno
+		// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
+		// and the message still has more bytes. Treat this as a success, since
+		// this package presents all named pipes as byte streams.
+		err = nil
+	}
+	return n, err
+}
+
+func (pipeAddress) Network() string {
+	return "pipe"
+}
+
+func (s pipeAddress) String() string {
+	return string(s)
+}
+
+// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
+func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask, impLevel PipeImpLevel) (windows.Handle, error) {
+	for {
+		select {
+		case <-ctx.Done():
+			return windows.Handle(0), ctx.Err()
+		default:
+			h, err := fs.CreateFile(*path,
+				access,
+				0,   // mode
+				nil, // security attributes
+				fs.OPEN_EXISTING,
+				fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.FileSQSFlag(impLevel),
+				0, // template file handle
+			)
+			if err == nil {
+				return h, nil
+			}
+			if err != windows.ERROR_PIPE_BUSY { //nolint:errorlint // err is Errno
+				return h, &os.PathError{Err: err, Op: "open", Path: *path}
+			}
+			// Wait 10 msec and try again. This is a rather simplistic
+			// view, as we always try each 10 milliseconds.
+			time.Sleep(10 * time.Millisecond)
+		}
+	}
+}
+
+// DialPipe connects to a named pipe by path, timing out if the connection
+// takes longer than the specified duration. If timeout is nil, then we use
+// a default timeout of 2 seconds.  (We do not use WaitNamedPipe.)
+func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
+	var absTimeout time.Time
+	if timeout != nil {
+		absTimeout = time.Now().Add(*timeout)
+	} else {
+		absTimeout = time.Now().Add(2 * time.Second)
+	}
+	ctx, cancel := context.WithDeadline(context.Background(), absTimeout)
+	defer cancel()
+	conn, err := DialPipeContext(ctx, path)
+	if errors.Is(err, context.DeadlineExceeded) {
+		return nil, ErrTimeout
+	}
+	return conn, err
+}
+
+// DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
+// cancellation or timeout.
+func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
+	return DialPipeAccess(ctx, path, uint32(fs.GENERIC_READ|fs.GENERIC_WRITE))
+}
+
+// PipeImpLevel is an enumeration of impersonation levels that may be set
+// when calling DialPipeAccessImpersonation.
+type PipeImpLevel uint32
+
+const (
+	PipeImpLevelAnonymous      = PipeImpLevel(fs.SECURITY_ANONYMOUS)
+	PipeImpLevelIdentification = PipeImpLevel(fs.SECURITY_IDENTIFICATION)
+	PipeImpLevelImpersonation  = PipeImpLevel(fs.SECURITY_IMPERSONATION)
+	PipeImpLevelDelegation     = PipeImpLevel(fs.SECURITY_DELEGATION)
+)
+
+// DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx`
+// cancellation or timeout.
+func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
+	return DialPipeAccessImpLevel(ctx, path, access, PipeImpLevelAnonymous)
+}
+
+// DialPipeAccessImpLevel attempts to connect to a named pipe by `path` with
+// `access` at `impLevel` until `ctx` cancellation or timeout. The other
+// DialPipe* implementations use PipeImpLevelAnonymous.
+func DialPipeAccessImpLevel(ctx context.Context, path string, access uint32, impLevel PipeImpLevel) (net.Conn, error) {
+	var err error
+	var h windows.Handle
+	h, err = tryDialPipe(ctx, &path, fs.AccessMask(access), impLevel)
+	if err != nil {
+		return nil, err
+	}
+
+	var flags uint32
+	err = getNamedPipeInfo(h, &flags, nil, nil, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	f, err := makeWin32File(h)
+	if err != nil {
+		windows.Close(h)
+		return nil, err
+	}
+
+	// If the pipe is in message mode, return a message byte pipe, which
+	// supports CloseWrite().
+	if flags&windows.PIPE_TYPE_MESSAGE != 0 {
+		return &win32MessageBytePipe{
+			win32Pipe: win32Pipe{win32File: f, path: path},
+		}, nil
+	}
+	return &win32Pipe{win32File: f, path: path}, nil
+}
+
+type acceptResponse struct {
+	f   *win32File
+	err error
+}
+
+type win32PipeListener struct {
+	firstHandle windows.Handle
+	path        string
+	config      PipeConfig
+	acceptCh    chan (chan acceptResponse)
+	closeCh     chan int
+	doneCh      chan int
+}
+
+func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (windows.Handle, error) {
+	path16, err := windows.UTF16FromString(path)
+	if err != nil {
+		return 0, &os.PathError{Op: "open", Path: path, Err: err}
+	}
+
+	var oa objectAttributes
+	oa.Length = unsafe.Sizeof(oa)
+
+	var ntPath unicodeString
+	if err := rtlDosPathNameToNtPathName(&path16[0],
+		&ntPath,
+		0,
+		0,
+	).Err(); err != nil {
+		return 0, &os.PathError{Op: "open", Path: path, Err: err}
+	}
+	defer windows.LocalFree(windows.Handle(ntPath.Buffer)) //nolint:errcheck
+	oa.ObjectName = &ntPath
+	oa.Attributes = windows.OBJ_CASE_INSENSITIVE
+
+	// The security descriptor is only needed for the first pipe.
+	if first {
+		if sd != nil {
+			//todo: does `sdb` need to be allocated on the heap, or can go allocate it?
+			l := uint32(len(sd))
+			sdb, err := windows.LocalAlloc(0, l)
+			if err != nil {
+				return 0, fmt.Errorf("LocalAlloc for security descriptor with of length %d: %w", l, err)
+			}
+			defer windows.LocalFree(windows.Handle(sdb)) //nolint:errcheck
+			copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
+			oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
+		} else {
+			// Construct the default named pipe security descriptor.
+			var dacl uintptr
+			if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
+				return 0, fmt.Errorf("getting default named pipe ACL: %w", err)
+			}
+			defer windows.LocalFree(windows.Handle(dacl)) //nolint:errcheck
+
+			sdb := &securityDescriptor{
+				Revision: 1,
+				Control:  windows.SE_DACL_PRESENT,
+				Dacl:     dacl,
+			}
+			oa.SecurityDescriptor = sdb
+		}
+	}
+
+	typ := uint32(windows.FILE_PIPE_REJECT_REMOTE_CLIENTS)
+	if c.MessageMode {
+		typ |= windows.FILE_PIPE_MESSAGE_TYPE
+	}
+
+	disposition := fs.FILE_OPEN
+	access := fs.GENERIC_READ | fs.GENERIC_WRITE | fs.SYNCHRONIZE
+	if first {
+		disposition = fs.FILE_CREATE
+		// By not asking for read or write access, the named pipe file system
+		// will put this pipe into an initially disconnected state, blocking
+		// client connections until the next call with first == false.
+		access = fs.SYNCHRONIZE
+	}
+
+	timeout := int64(-50 * 10000) // 50ms
+
+	var (
+		h    windows.Handle
+		iosb ioStatusBlock
+	)
+	err = ntCreateNamedPipeFile(&h,
+		access,
+		&oa,
+		&iosb,
+		fs.FILE_SHARE_READ|fs.FILE_SHARE_WRITE,
+		disposition,
+		0,
+		typ,
+		0,
+		0,
+		0xffffffff,
+		uint32(c.InputBufferSize),
+		uint32(c.OutputBufferSize),
+		&timeout).Err()
+	if err != nil {
+		return 0, &os.PathError{Op: "open", Path: path, Err: err}
+	}
+
+	runtime.KeepAlive(ntPath)
+	return h, nil
+}
+
+func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
+	h, err := makeServerPipeHandle(l.path, nil, &l.config, false)
+	if err != nil {
+		return nil, err
+	}
+	f, err := makeWin32File(h)
+	if err != nil {
+		windows.Close(h)
+		return nil, err
+	}
+	return f, nil
+}
+
+func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
+	p, err := l.makeServerPipe()
+	if err != nil {
+		return nil, err
+	}
+
+	// Wait for the client to connect.
+	ch := make(chan error)
+	go func(p *win32File) {
+		ch <- connectPipe(p)
+	}(p)
+
+	select {
+	case err = <-ch:
+		if err != nil {
+			p.Close()
+			p = nil
+		}
+	case <-l.closeCh:
+		// Abort the connect request by closing the handle.
+		p.Close()
+		p = nil
+		err = <-ch
+		if err == nil || err == ErrFileClosed { //nolint:errorlint // err is Errno
+			err = ErrPipeListenerClosed
+		}
+	}
+	return p, err
+}
+
+func (l *win32PipeListener) listenerRoutine() {
+	closed := false
+	for !closed {
+		select {
+		case <-l.closeCh:
+			closed = true
+		case responseCh := <-l.acceptCh:
+			var (
+				p   *win32File
+				err error
+			)
+			for {
+				p, err = l.makeConnectedServerPipe()
+				// If the connection was immediately closed by the client, try
+				// again.
+				if err != windows.ERROR_NO_DATA { //nolint:errorlint // err is Errno
+					break
+				}
+			}
+			responseCh <- acceptResponse{p, err}
+			closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
+		}
+	}
+	windows.Close(l.firstHandle)
+	l.firstHandle = 0
+	// Notify Close() and Accept() callers that the handle has been closed.
+	close(l.doneCh)
+}
+
+// PipeConfig contain configuration for the pipe listener.
+type PipeConfig struct {
+	// SecurityDescriptor contains a Windows security descriptor in SDDL format.
+	SecurityDescriptor string
+
+	// MessageMode determines whether the pipe is in byte or message mode. In either
+	// case the pipe is read in byte mode by default. The only practical difference in
+	// this implementation is that CloseWrite() is only supported for message mode pipes;
+	// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only
+	// transferred to the reader (and returned as io.EOF in this implementation)
+	// when the pipe is in message mode.
+	MessageMode bool
+
+	// InputBufferSize specifies the size of the input buffer, in bytes.
+	InputBufferSize int32
+
+	// OutputBufferSize specifies the size of the output buffer, in bytes.
+	OutputBufferSize int32
+}
+
+// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe.
+// The pipe must not already exist.
+func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
+	var (
+		sd  []byte
+		err error
+	)
+	if c == nil {
+		c = &PipeConfig{}
+	}
+	if c.SecurityDescriptor != "" {
+		sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor)
+		if err != nil {
+			return nil, err
+		}
+	}
+	h, err := makeServerPipeHandle(path, sd, c, true)
+	if err != nil {
+		return nil, err
+	}
+	l := &win32PipeListener{
+		firstHandle: h,
+		path:        path,
+		config:      *c,
+		acceptCh:    make(chan (chan acceptResponse)),
+		closeCh:     make(chan int),
+		doneCh:      make(chan int),
+	}
+	go l.listenerRoutine()
+	return l, nil
+}
+
+func connectPipe(p *win32File) error {
+	c, err := p.prepareIO()
+	if err != nil {
+		return err
+	}
+	defer p.wg.Done()
+
+	err = connectNamedPipe(p.handle, &c.o)
+	_, err = p.asyncIO(c, nil, 0, err)
+	if err != nil && err != windows.ERROR_PIPE_CONNECTED { //nolint:errorlint // err is Errno
+		return err
+	}
+	return nil
+}
+
+func (l *win32PipeListener) Accept() (net.Conn, error) {
+	ch := make(chan acceptResponse)
+	select {
+	case l.acceptCh <- ch:
+		response := <-ch
+		err := response.err
+		if err != nil {
+			return nil, err
+		}
+		if l.config.MessageMode {
+			return &win32MessageBytePipe{
+				win32Pipe: win32Pipe{win32File: response.f, path: l.path},
+			}, nil
+		}
+		return &win32Pipe{win32File: response.f, path: l.path}, nil
+	case <-l.doneCh:
+		return nil, ErrPipeListenerClosed
+	}
+}
+
+func (l *win32PipeListener) Close() error {
+	select {
+	case l.closeCh <- 1:
+		<-l.doneCh
+	case <-l.doneCh:
+	}
+	return nil
+}
+
+func (l *win32PipeListener) Addr() net.Addr {
+	return pipeAddress(l.path)
+}
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
new file mode 100644
index 000000000..48ce4e924
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
@@ -0,0 +1,232 @@
+// Package guid provides a GUID type. The backing structure for a GUID is
+// identical to that used by the golang.org/x/sys/windows GUID type.
+// There are two main binary encodings used for a GUID, the big-endian encoding,
+// and the Windows (mixed-endian) encoding. See here for details:
+// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding
+package guid
+
+import (
+	"crypto/rand"
+	"crypto/sha1" //nolint:gosec // not used for secure application
+	"encoding"
+	"encoding/binary"
+	"fmt"
+	"strconv"
+)
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=Variant -trimprefix=Variant -linecomment
+
+// Variant specifies which GUID variant (or "type") of the GUID. It determines
+// how the entirety of the rest of the GUID is interpreted.
+type Variant uint8
+
+// The variants specified by RFC 4122 section 4.1.1.
+const (
+	// VariantUnknown specifies a GUID variant which does not conform to one of
+	// the variant encodings specified in RFC 4122.
+	VariantUnknown Variant = iota
+	VariantNCS
+	VariantRFC4122 // RFC 4122
+	VariantMicrosoft
+	VariantFuture
+)
+
+// Version specifies how the bits in the GUID were generated. For instance, a
+// version 4 GUID is randomly generated, and a version 5 is generated from the
+// hash of an input string.
+type Version uint8
+
+func (v Version) String() string {
+	return strconv.FormatUint(uint64(v), 10)
+}
+
+var _ = (encoding.TextMarshaler)(GUID{})
+var _ = (encoding.TextUnmarshaler)(&GUID{})
+
+// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
+func NewV4() (GUID, error) {
+	var b [16]byte
+	if _, err := rand.Read(b[:]); err != nil {
+		return GUID{}, err
+	}
+
+	g := FromArray(b)
+	g.setVersion(4) // Version 4 means randomly generated.
+	g.setVariant(VariantRFC4122)
+
+	return g, nil
+}
+
+// NewV5 returns a new version 5 (generated from a string via SHA-1 hashing)
+// GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name,
+// and the sample code treats it as a series of bytes, so we do the same here.
+//
+// Some implementations, such as those found on Windows, treat the name as a
+// big-endian UTF16 stream of bytes. If that is desired, the string can be
+// encoded as such before being passed to this function.
+func NewV5(namespace GUID, name []byte) (GUID, error) {
+	b := sha1.New() //nolint:gosec // not used for secure application
+	namespaceBytes := namespace.ToArray()
+	b.Write(namespaceBytes[:])
+	b.Write(name)
+
+	a := [16]byte{}
+	copy(a[:], b.Sum(nil))
+
+	g := FromArray(a)
+	g.setVersion(5) // Version 5 means generated from a string.
+	g.setVariant(VariantRFC4122)
+
+	return g, nil
+}
+
+func fromArray(b [16]byte, order binary.ByteOrder) GUID {
+	var g GUID
+	g.Data1 = order.Uint32(b[0:4])
+	g.Data2 = order.Uint16(b[4:6])
+	g.Data3 = order.Uint16(b[6:8])
+	copy(g.Data4[:], b[8:16])
+	return g
+}
+
+func (g GUID) toArray(order binary.ByteOrder) [16]byte {
+	b := [16]byte{}
+	order.PutUint32(b[0:4], g.Data1)
+	order.PutUint16(b[4:6], g.Data2)
+	order.PutUint16(b[6:8], g.Data3)
+	copy(b[8:16], g.Data4[:])
+	return b
+}
+
+// FromArray constructs a GUID from a big-endian encoding array of 16 bytes.
+func FromArray(b [16]byte) GUID {
+	return fromArray(b, binary.BigEndian)
+}
+
+// ToArray returns an array of 16 bytes representing the GUID in big-endian
+// encoding.
+func (g GUID) ToArray() [16]byte {
+	return g.toArray(binary.BigEndian)
+}
+
+// FromWindowsArray constructs a GUID from a Windows encoding array of bytes.
+func FromWindowsArray(b [16]byte) GUID {
+	return fromArray(b, binary.LittleEndian)
+}
+
+// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows
+// encoding.
+func (g GUID) ToWindowsArray() [16]byte {
+	return g.toArray(binary.LittleEndian)
+}
+
+func (g GUID) String() string {
+	return fmt.Sprintf(
+		"%08x-%04x-%04x-%04x-%012x",
+		g.Data1,
+		g.Data2,
+		g.Data3,
+		g.Data4[:2],
+		g.Data4[2:])
+}
+
+// FromString parses a string containing a GUID and returns the GUID. The only
+// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
+// format.
+func FromString(s string) (GUID, error) {
+	if len(s) != 36 {
+		return GUID{}, fmt.Errorf("invalid GUID %q", s)
+	}
+	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
+		return GUID{}, fmt.Errorf("invalid GUID %q", s)
+	}
+
+	var g GUID
+
+	data1, err := strconv.ParseUint(s[0:8], 16, 32)
+	if err != nil {
+		return GUID{}, fmt.Errorf("invalid GUID %q", s)
+	}
+	g.Data1 = uint32(data1)
+
+	data2, err := strconv.ParseUint(s[9:13], 16, 16)
+	if err != nil {
+		return GUID{}, fmt.Errorf("invalid GUID %q", s)
+	}
+	g.Data2 = uint16(data2)
+
+	data3, err := strconv.ParseUint(s[14:18], 16, 16)
+	if err != nil {
+		return GUID{}, fmt.Errorf("invalid GUID %q", s)
+	}
+	g.Data3 = uint16(data3)
+
+	for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
+		v, err := strconv.ParseUint(s[x:x+2], 16, 8)
+		if err != nil {
+			return GUID{}, fmt.Errorf("invalid GUID %q", s)
+		}
+		g.Data4[i] = uint8(v)
+	}
+
+	return g, nil
+}
+
+func (g *GUID) setVariant(v Variant) {
+	d := g.Data4[0]
+	switch v {
+	case VariantNCS:
+		d = (d & 0x7f)
+	case VariantRFC4122:
+		d = (d & 0x3f) | 0x80
+	case VariantMicrosoft:
+		d = (d & 0x1f) | 0xc0
+	case VariantFuture:
+		d = (d & 0x0f) | 0xe0
+	case VariantUnknown:
+		fallthrough
+	default:
+		panic(fmt.Sprintf("invalid variant: %d", v))
+	}
+	g.Data4[0] = d
+}
+
+// Variant returns the GUID variant, as defined in RFC 4122.
+func (g GUID) Variant() Variant {
+	b := g.Data4[0]
+	if b&0x80 == 0 {
+		return VariantNCS
+	} else if b&0xc0 == 0x80 {
+		return VariantRFC4122
+	} else if b&0xe0 == 0xc0 {
+		return VariantMicrosoft
+	} else if b&0xe0 == 0xe0 {
+		return VariantFuture
+	}
+	return VariantUnknown
+}
+
+func (g *GUID) setVersion(v Version) {
+	g.Data3 = (g.Data3 & 0x0fff) | (uint16(v) << 12)
+}
+
+// Version returns the GUID version, as defined in RFC 4122.
+func (g GUID) Version() Version {
+	return Version((g.Data3 & 0xF000) >> 12)
+}
+
+// MarshalText returns the textual representation of the GUID.
+func (g GUID) MarshalText() ([]byte, error) {
+	return []byte(g.String()), nil
+}
+
+// UnmarshalText takes the textual representation of a GUID, and unmarhals it
+// into this GUID.
+func (g *GUID) UnmarshalText(text []byte) error {
+	g2, err := FromString(string(text))
+	if err != nil {
+		return err
+	}
+	*g = g2
+	return nil
+}
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
new file mode 100644
index 000000000..805bd3548
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
@@ -0,0 +1,16 @@
+//go:build !windows
+// +build !windows
+
+package guid
+
+// GUID represents a GUID/UUID. It has the same structure as
+// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
+// that type. It is defined as its own type as that is only available to builds
+// targeted at `windows`. The representation matches that used by native Windows
+// code.
+type GUID struct {
+	Data1 uint32
+	Data2 uint16
+	Data3 uint16
+	Data4 [8]byte
+}
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
new file mode 100644
index 000000000..27e45ee5c
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
@@ -0,0 +1,13 @@
+//go:build windows
+// +build windows
+
+package guid
+
+import "golang.org/x/sys/windows"
+
+// GUID represents a GUID/UUID. It has the same structure as
+// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
+// that type. It is defined as its own type so that stringification and
+// marshaling can be supported. The representation matches that used by native
+// Windows code.
+type GUID windows.GUID
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
new file mode 100644
index 000000000..4076d3132
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
@@ -0,0 +1,27 @@
+// Code generated by "stringer -type=Variant -trimprefix=Variant -linecomment"; DO NOT EDIT.
+
+package guid
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[VariantUnknown-0]
+	_ = x[VariantNCS-1]
+	_ = x[VariantRFC4122-2]
+	_ = x[VariantMicrosoft-3]
+	_ = x[VariantFuture-4]
+}
+
+const _Variant_name = "UnknownNCSRFC 4122MicrosoftFuture"
+
+var _Variant_index = [...]uint8{0, 7, 10, 18, 27, 33}
+
+func (i Variant) String() string {
+	if i >= Variant(len(_Variant_index)-1) {
+		return "Variant(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _Variant_name[_Variant_index[i]:_Variant_index[i+1]]
+}
diff --git a/vendor/github.com/Microsoft/go-winio/privilege.go b/vendor/github.com/Microsoft/go-winio/privilege.go
new file mode 100644
index 000000000..d9b90b6e8
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/privilege.go
@@ -0,0 +1,196 @@
+//go:build windows
+// +build windows
+
+package winio
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"runtime"
+	"sync"
+	"unicode/utf16"
+
+	"golang.org/x/sys/windows"
+)
+
+//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
+//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
+//sys revertToSelf() (err error) = advapi32.RevertToSelf
+//sys openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
+//sys getCurrentThread() (h windows.Handle) = GetCurrentThread
+//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
+//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
+//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
+
+const (
+	//revive:disable-next-line:var-naming ALL_CAPS
+	SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED
+
+	//revive:disable-next-line:var-naming ALL_CAPS
+	ERROR_NOT_ALL_ASSIGNED windows.Errno = windows.ERROR_NOT_ALL_ASSIGNED
+
+	SeBackupPrivilege   = "SeBackupPrivilege"
+	SeRestorePrivilege  = "SeRestorePrivilege"
+	SeSecurityPrivilege = "SeSecurityPrivilege"
+)
+
+var (
+	privNames     = make(map[string]uint64)
+	privNameMutex sync.Mutex
+)
+
+// PrivilegeError represents an error enabling privileges.
+type PrivilegeError struct {
+	privileges []uint64
+}
+
+func (e *PrivilegeError) Error() string {
+	s := "Could not enable privilege "
+	if len(e.privileges) > 1 {
+		s = "Could not enable privileges "
+	}
+	for i, p := range e.privileges {
+		if i != 0 {
+			s += ", "
+		}
+		s += `"`
+		s += getPrivilegeName(p)
+		s += `"`
+	}
+	return s
+}
+
+// RunWithPrivilege enables a single privilege for a function call.
+func RunWithPrivilege(name string, fn func() error) error {
+	return RunWithPrivileges([]string{name}, fn)
+}
+
+// RunWithPrivileges enables privileges for a function call.
+func RunWithPrivileges(names []string, fn func() error) error {
+	privileges, err := mapPrivileges(names)
+	if err != nil {
+		return err
+	}
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+	token, err := newThreadToken()
+	if err != nil {
+		return err
+	}
+	defer releaseThreadToken(token)
+	err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED)
+	if err != nil {
+		return err
+	}
+	return fn()
+}
+
+func mapPrivileges(names []string) ([]uint64, error) {
+	privileges := make([]uint64, 0, len(names))
+	privNameMutex.Lock()
+	defer privNameMutex.Unlock()
+	for _, name := range names {
+		p, ok := privNames[name]
+		if !ok {
+			err := lookupPrivilegeValue("", name, &p)
+			if err != nil {
+				return nil, err
+			}
+			privNames[name] = p
+		}
+		privileges = append(privileges, p)
+	}
+	return privileges, nil
+}
+
+// EnableProcessPrivileges enables privileges globally for the process.
+func EnableProcessPrivileges(names []string) error {
+	return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED)
+}
+
+// DisableProcessPrivileges disables privileges globally for the process.
+func DisableProcessPrivileges(names []string) error {
+	return enableDisableProcessPrivilege(names, 0)
+}
+
+func enableDisableProcessPrivilege(names []string, action uint32) error {
+	privileges, err := mapPrivileges(names)
+	if err != nil {
+		return err
+	}
+
+	p := windows.CurrentProcess()
+	var token windows.Token
+	err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
+	if err != nil {
+		return err
+	}
+
+	defer token.Close()
+	return adjustPrivileges(token, privileges, action)
+}
+
+func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
+	var b bytes.Buffer
+	_ = binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
+	for _, p := range privileges {
+		_ = binary.Write(&b, binary.LittleEndian, p)
+		_ = binary.Write(&b, binary.LittleEndian, action)
+	}
+	prevState := make([]byte, b.Len())
+	reqSize := uint32(0)
+	success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize)
+	if !success {
+		return err
+	}
+	if err == ERROR_NOT_ALL_ASSIGNED { //nolint:errorlint // err is Errno
+		return &PrivilegeError{privileges}
+	}
+	return nil
+}
+
+func getPrivilegeName(luid uint64) string {
+	var nameBuffer [256]uint16
+	bufSize := uint32(len(nameBuffer))
+	err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
+	if err != nil {
+		return fmt.Sprintf("<unknown privilege %d>", luid)
+	}
+
+	var displayNameBuffer [256]uint16
+	displayBufSize := uint32(len(displayNameBuffer))
+	var langID uint32
+	err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID)
+	if err != nil {
+		return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize])))
+	}
+
+	return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
+}
+
+func newThreadToken() (windows.Token, error) {
+	err := impersonateSelf(windows.SecurityImpersonation)
+	if err != nil {
+		return 0, err
+	}
+
+	var token windows.Token
+	err = openThreadToken(getCurrentThread(), windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, false, &token)
+	if err != nil {
+		rerr := revertToSelf()
+		if rerr != nil {
+			panic(rerr)
+		}
+		return 0, err
+	}
+	return token, nil
+}
+
+func releaseThreadToken(h windows.Token) {
+	err := revertToSelf()
+	if err != nil {
+		panic(err)
+	}
+	h.Close()
+}
diff --git a/vendor/github.com/Microsoft/go-winio/reparse.go b/vendor/github.com/Microsoft/go-winio/reparse.go
new file mode 100644
index 000000000..67d1a104a
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/reparse.go
@@ -0,0 +1,131 @@
+//go:build windows
+// +build windows
+
+package winio
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"strings"
+	"unicode/utf16"
+	"unsafe"
+)
+
+const (
+	reparseTagMountPoint = 0xA0000003
+	reparseTagSymlink    = 0xA000000C
+)
+
+type reparseDataBuffer struct {
+	ReparseTag           uint32
+	ReparseDataLength    uint16
+	Reserved             uint16
+	SubstituteNameOffset uint16
+	SubstituteNameLength uint16
+	PrintNameOffset      uint16
+	PrintNameLength      uint16
+}
+
+// ReparsePoint describes a Win32 symlink or mount point.
+type ReparsePoint struct {
+	Target       string
+	IsMountPoint bool
+}
+
+// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
+// mount point reparse point.
+type UnsupportedReparsePointError struct {
+	Tag uint32
+}
+
+func (e *UnsupportedReparsePointError) Error() string {
+	return fmt.Sprintf("unsupported reparse point %x", e.Tag)
+}
+
+// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
+// or a mount point.
+func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
+	tag := binary.LittleEndian.Uint32(b[0:4])
+	return DecodeReparsePointData(tag, b[8:])
+}
+
+func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) {
+	isMountPoint := false
+	switch tag {
+	case reparseTagMountPoint:
+		isMountPoint = true
+	case reparseTagSymlink:
+	default:
+		return nil, &UnsupportedReparsePointError{tag}
+	}
+	nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6])
+	if !isMountPoint {
+		nameOffset += 4
+	}
+	nameLength := binary.LittleEndian.Uint16(b[6:8])
+	name := make([]uint16, nameLength/2)
+	err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
+	if err != nil {
+		return nil, err
+	}
+	return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
+}
+
+func isDriveLetter(c byte) bool {
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
+// mount point.
+func EncodeReparsePoint(rp *ReparsePoint) []byte {
+	// Generate an NT path and determine if this is a relative path.
+	var ntTarget string
+	relative := false
+	if strings.HasPrefix(rp.Target, `\\?\`) {
+		ntTarget = `\??\` + rp.Target[4:]
+	} else if strings.HasPrefix(rp.Target, `\\`) {
+		ntTarget = `\??\UNC\` + rp.Target[2:]
+	} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
+		ntTarget = `\??\` + rp.Target
+	} else {
+		ntTarget = rp.Target
+		relative = true
+	}
+
+	// The paths must be NUL-terminated even though they are counted strings.
+	target16 := utf16.Encode([]rune(rp.Target + "\x00"))
+	ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
+
+	size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
+	size += len(ntTarget16)*2 + len(target16)*2
+
+	tag := uint32(reparseTagMountPoint)
+	if !rp.IsMountPoint {
+		tag = reparseTagSymlink
+		size += 4 // Add room for symlink flags
+	}
+
+	data := reparseDataBuffer{
+		ReparseTag:           tag,
+		ReparseDataLength:    uint16(size),
+		SubstituteNameOffset: 0,
+		SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
+		PrintNameOffset:      uint16(len(ntTarget16) * 2),
+		PrintNameLength:      uint16((len(target16) - 1) * 2),
+	}
+
+	var b bytes.Buffer
+	_ = binary.Write(&b, binary.LittleEndian, &data)
+	if !rp.IsMountPoint {
+		flags := uint32(0)
+		if relative {
+			flags |= 1
+		}
+		_ = binary.Write(&b, binary.LittleEndian, flags)
+	}
+
+	_ = binary.Write(&b, binary.LittleEndian, ntTarget16)
+	_ = binary.Write(&b, binary.LittleEndian, target16)
+	return b.Bytes()
+}
diff --git a/vendor/github.com/Microsoft/go-winio/sd.go b/vendor/github.com/Microsoft/go-winio/sd.go
new file mode 100644
index 000000000..c3685e98e
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/sd.go
@@ -0,0 +1,133 @@
+//go:build windows
+// +build windows
+
+package winio
+
+import (
+	"errors"
+	"fmt"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+)
+
+//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
+//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW
+//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
+//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW
+
+type AccountLookupError struct {
+	Name string
+	Err  error
+}
+
+func (e *AccountLookupError) Error() string {
+	if e.Name == "" {
+		return "lookup account: empty account name specified"
+	}
+	var s string
+	switch {
+	case errors.Is(e.Err, windows.ERROR_INVALID_SID):
+		s = "the security ID structure is invalid"
+	case errors.Is(e.Err, windows.ERROR_NONE_MAPPED):
+		s = "not found"
+	default:
+		s = e.Err.Error()
+	}
+	return "lookup account " + e.Name + ": " + s
+}
+
+func (e *AccountLookupError) Unwrap() error { return e.Err }
+
+type SddlConversionError struct {
+	Sddl string
+	Err  error
+}
+
+func (e *SddlConversionError) Error() string {
+	return "convert " + e.Sddl + ": " + e.Err.Error()
+}
+
+func (e *SddlConversionError) Unwrap() error { return e.Err }
+
+// LookupSidByName looks up the SID of an account by name
+//
+//revive:disable-next-line:var-naming SID, not Sid
+func LookupSidByName(name string) (sid string, err error) {
+	if name == "" {
+		return "", &AccountLookupError{name, windows.ERROR_NONE_MAPPED}
+	}
+
+	var sidSize, sidNameUse, refDomainSize uint32
+	err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
+	if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
+		return "", &AccountLookupError{name, err}
+	}
+	sidBuffer := make([]byte, sidSize)
+	refDomainBuffer := make([]uint16, refDomainSize)
+	err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
+	if err != nil {
+		return "", &AccountLookupError{name, err}
+	}
+	var strBuffer *uint16
+	err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
+	if err != nil {
+		return "", &AccountLookupError{name, err}
+	}
+	sid = windows.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
+	_, _ = windows.LocalFree(windows.Handle(unsafe.Pointer(strBuffer)))
+	return sid, nil
+}
+
+// LookupNameBySid looks up the name of an account by SID
+//
+//revive:disable-next-line:var-naming SID, not Sid
+func LookupNameBySid(sid string) (name string, err error) {
+	if sid == "" {
+		return "", &AccountLookupError{sid, windows.ERROR_NONE_MAPPED}
+	}
+
+	sidBuffer, err := windows.UTF16PtrFromString(sid)
+	if err != nil {
+		return "", &AccountLookupError{sid, err}
+	}
+
+	var sidPtr *byte
+	if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil {
+		return "", &AccountLookupError{sid, err}
+	}
+	defer windows.LocalFree(windows.Handle(unsafe.Pointer(sidPtr))) //nolint:errcheck
+
+	var nameSize, refDomainSize, sidNameUse uint32
+	err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse)
+	if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
+		return "", &AccountLookupError{sid, err}
+	}
+
+	nameBuffer := make([]uint16, nameSize)
+	refDomainBuffer := make([]uint16, refDomainSize)
+	err = lookupAccountSid(nil, sidPtr, &nameBuffer[0], &nameSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
+	if err != nil {
+		return "", &AccountLookupError{sid, err}
+	}
+
+	name = windows.UTF16ToString(nameBuffer)
+	return name, nil
+}
+
+func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
+	sd, err := windows.SecurityDescriptorFromString(sddl)
+	if err != nil {
+		return nil, &SddlConversionError{Sddl: sddl, Err: err}
+	}
+	b := unsafe.Slice((*byte)(unsafe.Pointer(sd)), sd.Length())
+	return b, nil
+}
+
+func SecurityDescriptorToSddl(sd []byte) (string, error) {
+	if l := int(unsafe.Sizeof(windows.SECURITY_DESCRIPTOR{})); len(sd) < l {
+		return "", fmt.Errorf("SecurityDescriptor (%d) smaller than expected (%d): %w", len(sd), l, windows.ERROR_INCORRECT_SIZE)
+	}
+	s := (*windows.SECURITY_DESCRIPTOR)(unsafe.Pointer(&sd[0]))
+	return s.String(), nil
+}
diff --git a/vendor/github.com/Microsoft/go-winio/syscall.go b/vendor/github.com/Microsoft/go-winio/syscall.go
new file mode 100644
index 000000000..a6ca111b3
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/syscall.go
@@ -0,0 +1,5 @@
+//go:build windows
+
+package winio
+
+//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./*.go
diff --git a/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
new file mode 100644
index 000000000..89b66eda8
--- /dev/null
+++ b/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
@@ -0,0 +1,378 @@
+//go:build windows
+
+// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
+
+package winio
+
+import (
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+)
+
+var _ unsafe.Pointer
+
+// Do the interface allocations only once for common
+// Errno values.
+const (
+	errnoERROR_IO_PENDING = 997
+)
+
+var (
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+	errERROR_EINVAL     error = syscall.EINVAL
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+	switch e {
+	case 0:
+		return errERROR_EINVAL
+	case errnoERROR_IO_PENDING:
+		return errERROR_IO_PENDING
+	}
+	return e
+}
+
+var (
+	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
+	modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+	modntdll    = windows.NewLazySystemDLL("ntdll.dll")
+	modws2_32   = windows.NewLazySystemDLL("ws2_32.dll")
+
+	procAdjustTokenPrivileges              = modadvapi32.NewProc("AdjustTokenPrivileges")
+	procConvertSidToStringSidW             = modadvapi32.NewProc("ConvertSidToStringSidW")
+	procConvertStringSidToSidW             = modadvapi32.NewProc("ConvertStringSidToSidW")
+	procImpersonateSelf                    = modadvapi32.NewProc("ImpersonateSelf")
+	procLookupAccountNameW                 = modadvapi32.NewProc("LookupAccountNameW")
+	procLookupAccountSidW                  = modadvapi32.NewProc("LookupAccountSidW")
+	procLookupPrivilegeDisplayNameW        = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
+	procLookupPrivilegeNameW               = modadvapi32.NewProc("LookupPrivilegeNameW")
+	procLookupPrivilegeValueW              = modadvapi32.NewProc("LookupPrivilegeValueW")
+	procOpenThreadToken                    = modadvapi32.NewProc("OpenThreadToken")
+	procRevertToSelf                       = modadvapi32.NewProc("RevertToSelf")
+	procBackupRead                         = modkernel32.NewProc("BackupRead")
+	procBackupWrite                        = modkernel32.NewProc("BackupWrite")
+	procCancelIoEx                         = modkernel32.NewProc("CancelIoEx")
+	procConnectNamedPipe                   = modkernel32.NewProc("ConnectNamedPipe")
+	procCreateIoCompletionPort             = modkernel32.NewProc("CreateIoCompletionPort")
+	procCreateNamedPipeW                   = modkernel32.NewProc("CreateNamedPipeW")
+	procDisconnectNamedPipe                = modkernel32.NewProc("DisconnectNamedPipe")
+	procGetCurrentThread                   = modkernel32.NewProc("GetCurrentThread")
+	procGetNamedPipeHandleStateW           = modkernel32.NewProc("GetNamedPipeHandleStateW")
+	procGetNamedPipeInfo                   = modkernel32.NewProc("GetNamedPipeInfo")
+	procGetQueuedCompletionStatus          = modkernel32.NewProc("GetQueuedCompletionStatus")
+	procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
+	procNtCreateNamedPipeFile              = modntdll.NewProc("NtCreateNamedPipeFile")
+	procRtlDefaultNpAcl                    = modntdll.NewProc("RtlDefaultNpAcl")
+	procRtlDosPathNameToNtPathName_U       = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
+	procRtlNtStatusToDosErrorNoTeb         = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
+	procWSAGetOverlappedResult             = modws2_32.NewProc("WSAGetOverlappedResult")
+)
+
+func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
+	var _p0 uint32
+	if releaseAll {
+		_p0 = 1
+	}
+	r0, _, e1 := syscall.SyscallN(procAdjustTokenPrivileges.Addr(), uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
+	success = r0 != 0
+	if true {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func convertSidToStringSid(sid *byte, str **uint16) (err error) {
+	r1, _, e1 := syscall.SyscallN(procConvertSidToStringSidW.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func convertStringSidToSid(str *uint16, sid **byte) (err error) {
+	r1, _, e1 := syscall.SyscallN(procConvertStringSidToSidW.Addr(), uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func impersonateSelf(level uint32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procImpersonateSelf.Addr(), uintptr(level))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(accountName)
+	if err != nil {
+		return
+	}
+	return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
+}
+
+func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procLookupAccountNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procLookupAccountSidW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(systemName)
+	if err != nil {
+		return
+	}
+	return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
+}
+
+func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procLookupPrivilegeDisplayNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(systemName)
+	if err != nil {
+		return
+	}
+	return _lookupPrivilegeName(_p0, luid, buffer, size)
+}
+
+func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procLookupPrivilegeNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(systemName)
+	if err != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, err = syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return
+	}
+	return _lookupPrivilegeValue(_p0, _p1, luid)
+}
+
+func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
+	r1, _, e1 := syscall.SyscallN(procLookupPrivilegeValueW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
+	var _p0 uint32
+	if openAsSelf {
+		_p0 = 1
+	}
+	r1, _, e1 := syscall.SyscallN(procOpenThreadToken.Addr(), uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func revertToSelf() (err error) {
+	r1, _, e1 := syscall.SyscallN(procRevertToSelf.Addr())
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
+	var _p0 *byte
+	if len(b) > 0 {
+		_p0 = &b[0]
+	}
+	var _p1 uint32
+	if abort {
+		_p1 = 1
+	}
+	var _p2 uint32
+	if processSecurity {
+		_p2 = 1
+	}
+	r1, _, e1 := syscall.SyscallN(procBackupRead.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
+	var _p0 *byte
+	if len(b) > 0 {
+		_p0 = &b[0]
+	}
+	var _p1 uint32
+	if abort {
+		_p1 = 1
+	}
+	var _p2 uint32
+	if processSecurity {
+		_p2 = 1
+	}
+	r1, _, e1 := syscall.SyscallN(procBackupWrite.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) {
+	r1, _, e1 := syscall.SyscallN(procCancelIoEx.Addr(), uintptr(file), uintptr(unsafe.Pointer(o)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) {
+	r1, _, e1 := syscall.SyscallN(procConnectNamedPipe.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(o)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) {
+	r0, _, e1 := syscall.SyscallN(procCreateIoCompletionPort.Addr(), uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount))
+	newport = windows.Handle(r0)
+	if newport == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return
+	}
+	return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
+}
+
+func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) {
+	r0, _, e1 := syscall.SyscallN(procCreateNamedPipeW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)))
+	handle = windows.Handle(r0)
+	if handle == windows.InvalidHandle {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func disconnectNamedPipe(pipe windows.Handle) (err error) {
+	r1, _, e1 := syscall.SyscallN(procDisconnectNamedPipe.Addr(), uintptr(pipe))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func getCurrentThread() (h windows.Handle) {
+	r0, _, _ := syscall.SyscallN(procGetCurrentThread.Addr())
+	h = windows.Handle(r0)
+	return
+}
+
+func getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procGetNamedPipeHandleStateW.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procGetNamedPipeInfo.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
+	r1, _, e1 := syscall.SyscallN(procGetQueuedCompletionStatus.Addr(), uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) {
+	r1, _, e1 := syscall.SyscallN(procSetFileCompletionNotificationModes.Addr(), uintptr(h), uintptr(flags))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) {
+	r0, _, _ := syscall.SyscallN(procNtCreateNamedPipeFile.Addr(), uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)))
+	status = ntStatus(r0)
+	return
+}
+
+func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) {
+	r0, _, _ := syscall.SyscallN(procRtlDefaultNpAcl.Addr(), uintptr(unsafe.Pointer(dacl)))
+	status = ntStatus(r0)
+	return
+}
+
+func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) {
+	r0, _, _ := syscall.SyscallN(procRtlDosPathNameToNtPathName_U.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved))
+	status = ntStatus(r0)
+	return
+}
+
+func rtlNtStatusToDosError(status ntStatus) (winerr error) {
+	r0, _, _ := syscall.SyscallN(procRtlNtStatusToDosErrorNoTeb.Addr(), uintptr(status))
+	if r0 != 0 {
+		winerr = syscall.Errno(r0)
+	}
+	return
+}
+
+func wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
+	var _p0 uint32
+	if wait {
+		_p0 = 1
+	}
+	r1, _, e1 := syscall.SyscallN(procWSAGetOverlappedResult.Addr(), uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/.gitignore b/vendor/github.com/cenkalti/backoff/v4/.gitignore
new file mode 100644
index 000000000..50d95c548
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/.gitignore
@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+# IDEs
+.idea/
diff --git a/vendor/github.com/cenkalti/backoff/v4/LICENSE b/vendor/github.com/cenkalti/backoff/v4/LICENSE
new file mode 100644
index 000000000..89b817996
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Cenk Altı
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/cenkalti/backoff/v4/README.md b/vendor/github.com/cenkalti/backoff/v4/README.md
new file mode 100644
index 000000000..9433004a2
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/README.md
@@ -0,0 +1,30 @@
+# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Coverage Status][coveralls image]][coveralls]
+
+This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
+
+[Exponential backoff][exponential backoff wiki]
+is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
+in order to gradually find an acceptable rate.
+The retries exponentially increase and stop increasing when a certain threshold is met.
+
+## Usage
+
+Import path is `github.com/cenkalti/backoff/v4`. Please note the version part at the end.
+
+Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
+
+## Contributing
+
+* I would like to keep this library as small as possible.
+* Please don't send a PR without opening an issue and discussing it first.
+* If proposed change is not a common use case, I will probably not accept it.
+
+[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4
+[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
+[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
+[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
+
+[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
+[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
+
+[advanced example]: https://pkg.go.dev/github.com/cenkalti/backoff/v4?tab=doc#pkg-examples
diff --git a/vendor/github.com/cenkalti/backoff/v4/backoff.go b/vendor/github.com/cenkalti/backoff/v4/backoff.go
new file mode 100644
index 000000000..3676ee405
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/backoff.go
@@ -0,0 +1,66 @@
+// Package backoff implements backoff algorithms for retrying operations.
+//
+// Use Retry function for retrying operations that may fail.
+// If Retry does not meet your needs,
+// copy/paste the function into your project and modify as you wish.
+//
+// There is also Ticker type similar to time.Ticker.
+// You can use it if you need to work with channels.
+//
+// See Examples section below for usage examples.
+package backoff
+
+import "time"
+
+// BackOff is a backoff policy for retrying an operation.
+type BackOff interface {
+	// NextBackOff returns the duration to wait before retrying the operation,
+	// or backoff. Stop to indicate that no more retries should be made.
+	//
+	// Example usage:
+	//
+	// 	duration := backoff.NextBackOff();
+	// 	if (duration == backoff.Stop) {
+	// 		// Do not retry operation.
+	// 	} else {
+	// 		// Sleep for duration and retry operation.
+	// 	}
+	//
+	NextBackOff() time.Duration
+
+	// Reset to initial state.
+	Reset()
+}
+
+// Stop indicates that no more retries should be made for use in NextBackOff().
+const Stop time.Duration = -1
+
+// ZeroBackOff is a fixed backoff policy whose backoff time is always zero,
+// meaning that the operation is retried immediately without waiting, indefinitely.
+type ZeroBackOff struct{}
+
+func (b *ZeroBackOff) Reset() {}
+
+func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
+
+// StopBackOff is a fixed backoff policy that always returns backoff.Stop for
+// NextBackOff(), meaning that the operation should never be retried.
+type StopBackOff struct{}
+
+func (b *StopBackOff) Reset() {}
+
+func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
+
+// ConstantBackOff is a backoff policy that always returns the same backoff delay.
+// This is in contrast to an exponential backoff policy,
+// which returns a delay that grows longer as you call NextBackOff() over and over again.
+type ConstantBackOff struct {
+	Interval time.Duration
+}
+
+func (b *ConstantBackOff) Reset()                     {}
+func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval }
+
+func NewConstantBackOff(d time.Duration) *ConstantBackOff {
+	return &ConstantBackOff{Interval: d}
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/context.go b/vendor/github.com/cenkalti/backoff/v4/context.go
new file mode 100644
index 000000000..48482330e
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/context.go
@@ -0,0 +1,62 @@
+package backoff
+
+import (
+	"context"
+	"time"
+)
+
+// BackOffContext is a backoff policy that stops retrying after the context
+// is canceled.
+type BackOffContext interface { // nolint: golint
+	BackOff
+	Context() context.Context
+}
+
+type backOffContext struct {
+	BackOff
+	ctx context.Context
+}
+
+// WithContext returns a BackOffContext with context ctx
+//
+// ctx must not be nil
+func WithContext(b BackOff, ctx context.Context) BackOffContext { // nolint: golint
+	if ctx == nil {
+		panic("nil context")
+	}
+
+	if b, ok := b.(*backOffContext); ok {
+		return &backOffContext{
+			BackOff: b.BackOff,
+			ctx:     ctx,
+		}
+	}
+
+	return &backOffContext{
+		BackOff: b,
+		ctx:     ctx,
+	}
+}
+
+func getContext(b BackOff) context.Context {
+	if cb, ok := b.(BackOffContext); ok {
+		return cb.Context()
+	}
+	if tb, ok := b.(*backOffTries); ok {
+		return getContext(tb.delegate)
+	}
+	return context.Background()
+}
+
+func (b *backOffContext) Context() context.Context {
+	return b.ctx
+}
+
+func (b *backOffContext) NextBackOff() time.Duration {
+	select {
+	case <-b.ctx.Done():
+		return Stop
+	default:
+		return b.BackOff.NextBackOff()
+	}
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/exponential.go b/vendor/github.com/cenkalti/backoff/v4/exponential.go
new file mode 100644
index 000000000..aac99f196
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/exponential.go
@@ -0,0 +1,216 @@
+package backoff
+
+import (
+	"math/rand"
+	"time"
+)
+
+/*
+ExponentialBackOff is a backoff implementation that increases the backoff
+period for each retry attempt using a randomization function that grows exponentially.
+
+NextBackOff() is calculated using the following formula:
+
+ randomized interval =
+     RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
+
+In other words NextBackOff() will range between the randomization factor
+percentage below and above the retry interval.
+
+For example, given the following parameters:
+
+ RetryInterval = 2
+ RandomizationFactor = 0.5
+ Multiplier = 2
+
+the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
+multiplied by the exponential, that is, between 2 and 6 seconds.
+
+Note: MaxInterval caps the RetryInterval and not the randomized interval.
+
+If the time elapsed since an ExponentialBackOff instance is created goes past the
+MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
+
+The elapsed time can be reset by calling Reset().
+
+Example: Given the following default arguments, for 10 tries the sequence will be,
+and assuming we go over the MaxElapsedTime on the 10th try:
+
+ Request #  RetryInterval (seconds)  Randomized Interval (seconds)
+
+  1          0.5                     [0.25,   0.75]
+  2          0.75                    [0.375,  1.125]
+  3          1.125                   [0.562,  1.687]
+  4          1.687                   [0.8435, 2.53]
+  5          2.53                    [1.265,  3.795]
+  6          3.795                   [1.897,  5.692]
+  7          5.692                   [2.846,  8.538]
+  8          8.538                   [4.269, 12.807]
+  9         12.807                   [6.403, 19.210]
+ 10         19.210                   backoff.Stop
+
+Note: Implementation is not thread-safe.
+*/
+type ExponentialBackOff struct {
+	InitialInterval     time.Duration
+	RandomizationFactor float64
+	Multiplier          float64
+	MaxInterval         time.Duration
+	// After MaxElapsedTime the ExponentialBackOff returns Stop.
+	// It never stops if MaxElapsedTime == 0.
+	MaxElapsedTime time.Duration
+	Stop           time.Duration
+	Clock          Clock
+
+	currentInterval time.Duration
+	startTime       time.Time
+}
+
+// Clock is an interface that returns current time for BackOff.
+type Clock interface {
+	Now() time.Time
+}
+
+// ExponentialBackOffOpts is a function type used to configure ExponentialBackOff options.
+type ExponentialBackOffOpts func(*ExponentialBackOff)
+
+// Default values for ExponentialBackOff.
+const (
+	DefaultInitialInterval     = 500 * time.Millisecond
+	DefaultRandomizationFactor = 0.5
+	DefaultMultiplier          = 1.5
+	DefaultMaxInterval         = 60 * time.Second
+	DefaultMaxElapsedTime      = 15 * time.Minute
+)
+
+// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
+func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff {
+	b := &ExponentialBackOff{
+		InitialInterval:     DefaultInitialInterval,
+		RandomizationFactor: DefaultRandomizationFactor,
+		Multiplier:          DefaultMultiplier,
+		MaxInterval:         DefaultMaxInterval,
+		MaxElapsedTime:      DefaultMaxElapsedTime,
+		Stop:                Stop,
+		Clock:               SystemClock,
+	}
+	for _, fn := range opts {
+		fn(b)
+	}
+	b.Reset()
+	return b
+}
+
+// WithInitialInterval sets the initial interval between retries.
+func WithInitialInterval(duration time.Duration) ExponentialBackOffOpts {
+	return func(ebo *ExponentialBackOff) {
+		ebo.InitialInterval = duration
+	}
+}
+
+// WithRandomizationFactor sets the randomization factor to add jitter to intervals.
+func WithRandomizationFactor(randomizationFactor float64) ExponentialBackOffOpts {
+	return func(ebo *ExponentialBackOff) {
+		ebo.RandomizationFactor = randomizationFactor
+	}
+}
+
+// WithMultiplier sets the multiplier for increasing the interval after each retry.
+func WithMultiplier(multiplier float64) ExponentialBackOffOpts {
+	return func(ebo *ExponentialBackOff) {
+		ebo.Multiplier = multiplier
+	}
+}
+
+// WithMaxInterval sets the maximum interval between retries.
+func WithMaxInterval(duration time.Duration) ExponentialBackOffOpts {
+	return func(ebo *ExponentialBackOff) {
+		ebo.MaxInterval = duration
+	}
+}
+
+// WithMaxElapsedTime sets the maximum total time for retries.
+func WithMaxElapsedTime(duration time.Duration) ExponentialBackOffOpts {
+	return func(ebo *ExponentialBackOff) {
+		ebo.MaxElapsedTime = duration
+	}
+}
+
+// WithRetryStopDuration sets the duration after which retries should stop.
+func WithRetryStopDuration(duration time.Duration) ExponentialBackOffOpts {
+	return func(ebo *ExponentialBackOff) {
+		ebo.Stop = duration
+	}
+}
+
+// WithClockProvider sets the clock used to measure time.
+func WithClockProvider(clock Clock) ExponentialBackOffOpts {
+	return func(ebo *ExponentialBackOff) {
+		ebo.Clock = clock
+	}
+}
+
+type systemClock struct{}
+
+func (t systemClock) Now() time.Time {
+	return time.Now()
+}
+
+// SystemClock implements Clock interface that uses time.Now().
+var SystemClock = systemClock{}
+
+// Reset the interval back to the initial retry interval and restarts the timer.
+// Reset must be called before using b.
+func (b *ExponentialBackOff) Reset() {
+	b.currentInterval = b.InitialInterval
+	b.startTime = b.Clock.Now()
+}
+
+// NextBackOff calculates the next backoff interval using the formula:
+// 	Randomized interval = RetryInterval * (1 ± RandomizationFactor)
+func (b *ExponentialBackOff) NextBackOff() time.Duration {
+	// Make sure we have not gone over the maximum elapsed time.
+	elapsed := b.GetElapsedTime()
+	next := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
+	b.incrementCurrentInterval()
+	if b.MaxElapsedTime != 0 && elapsed+next > b.MaxElapsedTime {
+		return b.Stop
+	}
+	return next
+}
+
+// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
+// is created and is reset when Reset() is called.
+//
+// The elapsed time is computed using time.Now().UnixNano(). It is
+// safe to call even while the backoff policy is used by a running
+// ticker.
+func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
+	return b.Clock.Now().Sub(b.startTime)
+}
+
+// Increments the current interval by multiplying it with the multiplier.
+func (b *ExponentialBackOff) incrementCurrentInterval() {
+	// Check for overflow, if overflow is detected set the current interval to the max interval.
+	if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
+		b.currentInterval = b.MaxInterval
+	} else {
+		b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
+	}
+}
+
+// Returns a random value from the following interval:
+// 	[currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
+func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
+	if randomizationFactor == 0 {
+		return currentInterval // make sure no randomness is used when randomizationFactor is 0.
+	}
+	var delta = randomizationFactor * float64(currentInterval)
+	var minInterval = float64(currentInterval) - delta
+	var maxInterval = float64(currentInterval) + delta
+
+	// Get a random value from the range [minInterval, maxInterval].
+	// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
+	// we want a 33% chance for selecting either 1, 2 or 3.
+	return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/retry.go b/vendor/github.com/cenkalti/backoff/v4/retry.go
new file mode 100644
index 000000000..b9c0c51cd
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/retry.go
@@ -0,0 +1,146 @@
+package backoff
+
+import (
+	"errors"
+	"time"
+)
+
+// An OperationWithData is executing by RetryWithData() or RetryNotifyWithData().
+// The operation will be retried using a backoff policy if it returns an error.
+type OperationWithData[T any] func() (T, error)
+
+// An Operation is executing by Retry() or RetryNotify().
+// The operation will be retried using a backoff policy if it returns an error.
+type Operation func() error
+
+func (o Operation) withEmptyData() OperationWithData[struct{}] {
+	return func() (struct{}, error) {
+		return struct{}{}, o()
+	}
+}
+
+// Notify is a notify-on-error function. It receives an operation error and
+// backoff delay if the operation failed (with an error).
+//
+// NOTE that if the backoff policy stated to stop retrying,
+// the notify function isn't called.
+type Notify func(error, time.Duration)
+
+// Retry the operation o until it does not return error or BackOff stops.
+// o is guaranteed to be run at least once.
+//
+// If o returns a *PermanentError, the operation is not retried, and the
+// wrapped error is returned.
+//
+// Retry sleeps the goroutine for the duration returned by BackOff after a
+// failed operation returns.
+func Retry(o Operation, b BackOff) error {
+	return RetryNotify(o, b, nil)
+}
+
+// RetryWithData is like Retry but returns data in the response too.
+func RetryWithData[T any](o OperationWithData[T], b BackOff) (T, error) {
+	return RetryNotifyWithData(o, b, nil)
+}
+
+// RetryNotify calls notify function with the error and wait duration
+// for each failed attempt before sleep.
+func RetryNotify(operation Operation, b BackOff, notify Notify) error {
+	return RetryNotifyWithTimer(operation, b, notify, nil)
+}
+
+// RetryNotifyWithData is like RetryNotify but returns data in the response too.
+func RetryNotifyWithData[T any](operation OperationWithData[T], b BackOff, notify Notify) (T, error) {
+	return doRetryNotify(operation, b, notify, nil)
+}
+
+// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer
+// for each failed attempt before sleep.
+// A default timer that uses system timer is used when nil is passed.
+func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error {
+	_, err := doRetryNotify(operation.withEmptyData(), b, notify, t)
+	return err
+}
+
+// RetryNotifyWithTimerAndData is like RetryNotifyWithTimer but returns data in the response too.
+func RetryNotifyWithTimerAndData[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
+	return doRetryNotify(operation, b, notify, t)
+}
+
+func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
+	var (
+		err  error
+		next time.Duration
+		res  T
+	)
+	if t == nil {
+		t = &defaultTimer{}
+	}
+
+	defer func() {
+		t.Stop()
+	}()
+
+	ctx := getContext(b)
+
+	b.Reset()
+	for {
+		res, err = operation()
+		if err == nil {
+			return res, nil
+		}
+
+		var permanent *PermanentError
+		if errors.As(err, &permanent) {
+			return res, permanent.Err
+		}
+
+		if next = b.NextBackOff(); next == Stop {
+			if cerr := ctx.Err(); cerr != nil {
+				return res, cerr
+			}
+
+			return res, err
+		}
+
+		if notify != nil {
+			notify(err, next)
+		}
+
+		t.Start(next)
+
+		select {
+		case <-ctx.Done():
+			return res, ctx.Err()
+		case <-t.C():
+		}
+	}
+}
+
+// PermanentError signals that the operation should not be retried.
+type PermanentError struct {
+	Err error
+}
+
+func (e *PermanentError) Error() string {
+	return e.Err.Error()
+}
+
+func (e *PermanentError) Unwrap() error {
+	return e.Err
+}
+
+func (e *PermanentError) Is(target error) bool {
+	_, ok := target.(*PermanentError)
+	return ok
+}
+
+// Permanent wraps the given err in a *PermanentError.
+func Permanent(err error) error {
+	if err == nil {
+		return nil
+	}
+	return &PermanentError{
+		Err: err,
+	}
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/ticker.go b/vendor/github.com/cenkalti/backoff/v4/ticker.go
new file mode 100644
index 000000000..df9d68bce
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/ticker.go
@@ -0,0 +1,97 @@
+package backoff
+
+import (
+	"context"
+	"sync"
+	"time"
+)
+
+// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.
+//
+// Ticks will continue to arrive when the previous operation is still running,
+// so operations that take a while to fail could run in quick succession.
+type Ticker struct {
+	C        <-chan time.Time
+	c        chan time.Time
+	b        BackOff
+	ctx      context.Context
+	timer    Timer
+	stop     chan struct{}
+	stopOnce sync.Once
+}
+
+// NewTicker returns a new Ticker containing a channel that will send
+// the time at times specified by the BackOff argument. Ticker is
+// guaranteed to tick at least once.  The channel is closed when Stop
+// method is called or BackOff stops. It is not safe to manipulate the
+// provided backoff policy (notably calling NextBackOff or Reset)
+// while the ticker is running.
+func NewTicker(b BackOff) *Ticker {
+	return NewTickerWithTimer(b, &defaultTimer{})
+}
+
+// NewTickerWithTimer returns a new Ticker with a custom timer.
+// A default timer that uses system timer is used when nil is passed.
+func NewTickerWithTimer(b BackOff, timer Timer) *Ticker {
+	if timer == nil {
+		timer = &defaultTimer{}
+	}
+	c := make(chan time.Time)
+	t := &Ticker{
+		C:     c,
+		c:     c,
+		b:     b,
+		ctx:   getContext(b),
+		timer: timer,
+		stop:  make(chan struct{}),
+	}
+	t.b.Reset()
+	go t.run()
+	return t
+}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+	t.stopOnce.Do(func() { close(t.stop) })
+}
+
+func (t *Ticker) run() {
+	c := t.c
+	defer close(c)
+
+	// Ticker is guaranteed to tick at least once.
+	afterC := t.send(time.Now())
+
+	for {
+		if afterC == nil {
+			return
+		}
+
+		select {
+		case tick := <-afterC:
+			afterC = t.send(tick)
+		case <-t.stop:
+			t.c = nil // Prevent future ticks from being sent to the channel.
+			return
+		case <-t.ctx.Done():
+			return
+		}
+	}
+}
+
+func (t *Ticker) send(tick time.Time) <-chan time.Time {
+	select {
+	case t.c <- tick:
+	case <-t.stop:
+		return nil
+	}
+
+	next := t.b.NextBackOff()
+	if next == Stop {
+		t.Stop()
+		return nil
+	}
+
+	t.timer.Start(next)
+	return t.timer.C()
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/timer.go b/vendor/github.com/cenkalti/backoff/v4/timer.go
new file mode 100644
index 000000000..8120d0213
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/timer.go
@@ -0,0 +1,35 @@
+package backoff
+
+import "time"
+
+type Timer interface {
+	Start(duration time.Duration)
+	Stop()
+	C() <-chan time.Time
+}
+
+// defaultTimer implements Timer interface using time.Timer
+type defaultTimer struct {
+	timer *time.Timer
+}
+
+// C returns the timers channel which receives the current time when the timer fires.
+func (t *defaultTimer) C() <-chan time.Time {
+	return t.timer.C
+}
+
+// Start starts the timer to fire after the given duration
+func (t *defaultTimer) Start(duration time.Duration) {
+	if t.timer == nil {
+		t.timer = time.NewTimer(duration)
+	} else {
+		t.timer.Reset(duration)
+	}
+}
+
+// Stop is called when the timer is not used anymore and resources may be freed.
+func (t *defaultTimer) Stop() {
+	if t.timer != nil {
+		t.timer.Stop()
+	}
+}
diff --git a/vendor/github.com/cenkalti/backoff/v4/tries.go b/vendor/github.com/cenkalti/backoff/v4/tries.go
new file mode 100644
index 000000000..28d58ca37
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/v4/tries.go
@@ -0,0 +1,38 @@
+package backoff
+
+import "time"
+
+/*
+WithMaxRetries creates a wrapper around another BackOff, which will
+return Stop if NextBackOff() has been called too many times since
+the last time Reset() was called
+
+Note: Implementation is not thread-safe.
+*/
+func WithMaxRetries(b BackOff, max uint64) BackOff {
+	return &backOffTries{delegate: b, maxTries: max}
+}
+
+type backOffTries struct {
+	delegate BackOff
+	maxTries uint64
+	numTries uint64
+}
+
+func (b *backOffTries) NextBackOff() time.Duration {
+	if b.maxTries == 0 {
+		return Stop
+	}
+	if b.maxTries > 0 {
+		if b.maxTries <= b.numTries {
+			return Stop
+		}
+		b.numTries++
+	}
+	return b.delegate.NextBackOff()
+}
+
+func (b *backOffTries) Reset() {
+	b.numTries = 0
+	b.delegate.Reset()
+}
diff --git a/vendor/github.com/containerd/errdefs/LICENSE b/vendor/github.com/containerd/errdefs/LICENSE
new file mode 100644
index 000000000..584149b6e
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/LICENSE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright The containerd Authors
+
+   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
+
+       https://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.
diff --git a/vendor/github.com/containerd/errdefs/README.md b/vendor/github.com/containerd/errdefs/README.md
new file mode 100644
index 000000000..bd418c63f
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/README.md
@@ -0,0 +1,13 @@
+# errdefs
+
+A Go package for defining and checking common containerd errors.
+
+## Project details
+
+**errdefs** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
diff --git a/vendor/github.com/containerd/errdefs/errors.go b/vendor/github.com/containerd/errdefs/errors.go
new file mode 100644
index 000000000..f654d1964
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/errors.go
@@ -0,0 +1,443 @@
+/*
+   Copyright The containerd Authors.
+
+   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 errdefs defines the common errors used throughout containerd
+// packages.
+//
+// Use with fmt.Errorf to add context to an error.
+//
+// To detect an error class, use the IsXXX functions to tell whether an error
+// is of a certain type.
+package errdefs
+
+import (
+	"context"
+	"errors"
+)
+
+// Definitions of common error types used throughout containerd. All containerd
+// errors returned by most packages will map into one of these errors classes.
+// Packages should return errors of these types when they want to instruct a
+// client to take a particular action.
+//
+// These errors map closely to grpc errors.
+var (
+	ErrUnknown            = errUnknown{}
+	ErrInvalidArgument    = errInvalidArgument{}
+	ErrNotFound           = errNotFound{}
+	ErrAlreadyExists      = errAlreadyExists{}
+	ErrPermissionDenied   = errPermissionDenied{}
+	ErrResourceExhausted  = errResourceExhausted{}
+	ErrFailedPrecondition = errFailedPrecondition{}
+	ErrConflict           = errConflict{}
+	ErrNotModified        = errNotModified{}
+	ErrAborted            = errAborted{}
+	ErrOutOfRange         = errOutOfRange{}
+	ErrNotImplemented     = errNotImplemented{}
+	ErrInternal           = errInternal{}
+	ErrUnavailable        = errUnavailable{}
+	ErrDataLoss           = errDataLoss{}
+	ErrUnauthenticated    = errUnauthorized{}
+)
+
+// cancelled maps to Moby's "ErrCancelled"
+type cancelled interface {
+	Cancelled()
+}
+
+// IsCanceled returns true if the error is due to `context.Canceled`.
+func IsCanceled(err error) bool {
+	return errors.Is(err, context.Canceled) || isInterface[cancelled](err)
+}
+
+type errUnknown struct{}
+
+func (errUnknown) Error() string { return "unknown" }
+
+func (errUnknown) Unknown() {}
+
+func (e errUnknown) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// unknown maps to Moby's "ErrUnknown"
+type unknown interface {
+	Unknown()
+}
+
+// IsUnknown returns true if the error is due to an unknown error,
+// unhandled condition or unexpected response.
+func IsUnknown(err error) bool {
+	return errors.Is(err, errUnknown{}) || isInterface[unknown](err)
+}
+
+type errInvalidArgument struct{}
+
+func (errInvalidArgument) Error() string { return "invalid argument" }
+
+func (errInvalidArgument) InvalidParameter() {}
+
+func (e errInvalidArgument) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// invalidParameter maps to Moby's "ErrInvalidParameter"
+type invalidParameter interface {
+	InvalidParameter()
+}
+
+// IsInvalidArgument returns true if the error is due to an invalid argument
+func IsInvalidArgument(err error) bool {
+	return errors.Is(err, ErrInvalidArgument) || isInterface[invalidParameter](err)
+}
+
+// deadlineExceed maps to Moby's "ErrDeadline"
+type deadlineExceeded interface {
+	DeadlineExceeded()
+}
+
+// IsDeadlineExceeded returns true if the error is due to
+// `context.DeadlineExceeded`.
+func IsDeadlineExceeded(err error) bool {
+	return errors.Is(err, context.DeadlineExceeded) || isInterface[deadlineExceeded](err)
+}
+
+type errNotFound struct{}
+
+func (errNotFound) Error() string { return "not found" }
+
+func (errNotFound) NotFound() {}
+
+func (e errNotFound) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// notFound maps to Moby's "ErrNotFound"
+type notFound interface {
+	NotFound()
+}
+
+// IsNotFound returns true if the error is due to a missing object
+func IsNotFound(err error) bool {
+	return errors.Is(err, ErrNotFound) || isInterface[notFound](err)
+}
+
+type errAlreadyExists struct{}
+
+func (errAlreadyExists) Error() string { return "already exists" }
+
+func (errAlreadyExists) AlreadyExists() {}
+
+func (e errAlreadyExists) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+type alreadyExists interface {
+	AlreadyExists()
+}
+
+// IsAlreadyExists returns true if the error is due to an already existing
+// metadata item
+func IsAlreadyExists(err error) bool {
+	return errors.Is(err, ErrAlreadyExists) || isInterface[alreadyExists](err)
+}
+
+type errPermissionDenied struct{}
+
+func (errPermissionDenied) Error() string { return "permission denied" }
+
+func (errPermissionDenied) Forbidden() {}
+
+func (e errPermissionDenied) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// forbidden maps to Moby's "ErrForbidden"
+type forbidden interface {
+	Forbidden()
+}
+
+// IsPermissionDenied returns true if the error is due to permission denied
+// or forbidden (403) response
+func IsPermissionDenied(err error) bool {
+	return errors.Is(err, ErrPermissionDenied) || isInterface[forbidden](err)
+}
+
+type errResourceExhausted struct{}
+
+func (errResourceExhausted) Error() string { return "resource exhausted" }
+
+func (errResourceExhausted) ResourceExhausted() {}
+
+func (e errResourceExhausted) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+type resourceExhausted interface {
+	ResourceExhausted()
+}
+
+// IsResourceExhausted returns true if the error is due to
+// a lack of resources or too many attempts.
+func IsResourceExhausted(err error) bool {
+	return errors.Is(err, errResourceExhausted{}) || isInterface[resourceExhausted](err)
+}
+
+type errFailedPrecondition struct{}
+
+func (e errFailedPrecondition) Error() string { return "failed precondition" }
+
+func (errFailedPrecondition) FailedPrecondition() {}
+
+func (e errFailedPrecondition) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+type failedPrecondition interface {
+	FailedPrecondition()
+}
+
+// IsFailedPrecondition returns true if an operation could not proceed due to
+// the lack of a particular condition
+func IsFailedPrecondition(err error) bool {
+	return errors.Is(err, errFailedPrecondition{}) || isInterface[failedPrecondition](err)
+}
+
+type errConflict struct{}
+
+func (errConflict) Error() string { return "conflict" }
+
+func (errConflict) Conflict() {}
+
+func (e errConflict) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// conflict maps to Moby's "ErrConflict"
+type conflict interface {
+	Conflict()
+}
+
+// IsConflict returns true if an operation could not proceed due to
+// a conflict.
+func IsConflict(err error) bool {
+	return errors.Is(err, errConflict{}) || isInterface[conflict](err)
+}
+
+type errNotModified struct{}
+
+func (errNotModified) Error() string { return "not modified" }
+
+func (errNotModified) NotModified() {}
+
+func (e errNotModified) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// notModified maps to Moby's "ErrNotModified"
+type notModified interface {
+	NotModified()
+}
+
+// IsNotModified returns true if an operation could not proceed due
+// to an object not modified from a previous state.
+func IsNotModified(err error) bool {
+	return errors.Is(err, errNotModified{}) || isInterface[notModified](err)
+}
+
+type errAborted struct{}
+
+func (errAborted) Error() string { return "aborted" }
+
+func (errAborted) Aborted() {}
+
+func (e errAborted) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+type aborted interface {
+	Aborted()
+}
+
+// IsAborted returns true if an operation was aborted.
+func IsAborted(err error) bool {
+	return errors.Is(err, errAborted{}) || isInterface[aborted](err)
+}
+
+type errOutOfRange struct{}
+
+func (errOutOfRange) Error() string { return "out of range" }
+
+func (errOutOfRange) OutOfRange() {}
+
+func (e errOutOfRange) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+type outOfRange interface {
+	OutOfRange()
+}
+
+// IsOutOfRange returns true if an operation could not proceed due
+// to data being out of the expected range.
+func IsOutOfRange(err error) bool {
+	return errors.Is(err, errOutOfRange{}) || isInterface[outOfRange](err)
+}
+
+type errNotImplemented struct{}
+
+func (errNotImplemented) Error() string { return "not implemented" }
+
+func (errNotImplemented) NotImplemented() {}
+
+func (e errNotImplemented) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// notImplemented maps to Moby's "ErrNotImplemented"
+type notImplemented interface {
+	NotImplemented()
+}
+
+// IsNotImplemented returns true if the error is due to not being implemented
+func IsNotImplemented(err error) bool {
+	return errors.Is(err, errNotImplemented{}) || isInterface[notImplemented](err)
+}
+
+type errInternal struct{}
+
+func (errInternal) Error() string { return "internal" }
+
+func (errInternal) System() {}
+
+func (e errInternal) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// system maps to Moby's "ErrSystem"
+type system interface {
+	System()
+}
+
+// IsInternal returns true if the error returns to an internal or system error
+func IsInternal(err error) bool {
+	return errors.Is(err, errInternal{}) || isInterface[system](err)
+}
+
+type errUnavailable struct{}
+
+func (errUnavailable) Error() string { return "unavailable" }
+
+func (errUnavailable) Unavailable() {}
+
+func (e errUnavailable) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// unavailable maps to Moby's "ErrUnavailable"
+type unavailable interface {
+	Unavailable()
+}
+
+// IsUnavailable returns true if the error is due to a resource being unavailable
+func IsUnavailable(err error) bool {
+	return errors.Is(err, errUnavailable{}) || isInterface[unavailable](err)
+}
+
+type errDataLoss struct{}
+
+func (errDataLoss) Error() string { return "data loss" }
+
+func (errDataLoss) DataLoss() {}
+
+func (e errDataLoss) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// dataLoss maps to Moby's "ErrDataLoss"
+type dataLoss interface {
+	DataLoss()
+}
+
+// IsDataLoss returns true if data during an operation was lost or corrupted
+func IsDataLoss(err error) bool {
+	return errors.Is(err, errDataLoss{}) || isInterface[dataLoss](err)
+}
+
+type errUnauthorized struct{}
+
+func (errUnauthorized) Error() string { return "unauthorized" }
+
+func (errUnauthorized) Unauthorized() {}
+
+func (e errUnauthorized) WithMessage(msg string) error {
+	return customMessage{e, msg}
+}
+
+// unauthorized maps to Moby's "ErrUnauthorized"
+type unauthorized interface {
+	Unauthorized()
+}
+
+// IsUnauthorized returns true if the error indicates that the user was
+// unauthenticated or unauthorized.
+func IsUnauthorized(err error) bool {
+	return errors.Is(err, errUnauthorized{}) || isInterface[unauthorized](err)
+}
+
+func isInterface[T any](err error) bool {
+	for {
+		switch x := err.(type) {
+		case T:
+			return true
+		case customMessage:
+			err = x.err
+		case interface{ Unwrap() error }:
+			err = x.Unwrap()
+			if err == nil {
+				return false
+			}
+		case interface{ Unwrap() []error }:
+			for _, err := range x.Unwrap() {
+				if isInterface[T](err) {
+					return true
+				}
+			}
+			return false
+		default:
+			return false
+		}
+	}
+}
+
+// customMessage is used to provide a defined error with a custom message.
+// The message is not wrapped but can be compared by the `Is(error) bool` interface.
+type customMessage struct {
+	err error
+	msg string
+}
+
+func (c customMessage) Is(err error) bool {
+	return c.err == err
+}
+
+func (c customMessage) As(target any) bool {
+	return errors.As(c.err, target)
+}
+
+func (c customMessage) Error() string {
+	return c.msg
+}
diff --git a/vendor/github.com/containerd/errdefs/pkg/LICENSE b/vendor/github.com/containerd/errdefs/pkg/LICENSE
new file mode 100644
index 000000000..584149b6e
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/pkg/LICENSE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright The containerd Authors
+
+   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
+
+       https://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.
diff --git a/vendor/github.com/containerd/errdefs/pkg/errhttp/http.go b/vendor/github.com/containerd/errdefs/pkg/errhttp/http.go
new file mode 100644
index 000000000..d7cd2b8c1
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/pkg/errhttp/http.go
@@ -0,0 +1,96 @@
+/*
+   Copyright The containerd Authors.
+
+   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 errhttp provides utility functions for translating errors to
+// and from a HTTP context.
+//
+// The functions ToHTTP and ToNative can be used to map server-side and
+// client-side errors to the correct types.
+package errhttp
+
+import (
+	"errors"
+	"net/http"
+
+	"github.com/containerd/errdefs"
+	"github.com/containerd/errdefs/pkg/internal/cause"
+)
+
+// ToHTTP returns the best status code for the given error
+func ToHTTP(err error) int {
+	switch {
+	case errdefs.IsNotFound(err):
+		return http.StatusNotFound
+	case errdefs.IsInvalidArgument(err):
+		return http.StatusBadRequest
+	case errdefs.IsConflict(err):
+		return http.StatusConflict
+	case errdefs.IsNotModified(err):
+		return http.StatusNotModified
+	case errdefs.IsFailedPrecondition(err):
+		return http.StatusPreconditionFailed
+	case errdefs.IsUnauthorized(err):
+		return http.StatusUnauthorized
+	case errdefs.IsPermissionDenied(err):
+		return http.StatusForbidden
+	case errdefs.IsResourceExhausted(err):
+		return http.StatusTooManyRequests
+	case errdefs.IsInternal(err):
+		return http.StatusInternalServerError
+	case errdefs.IsNotImplemented(err):
+		return http.StatusNotImplemented
+	case errdefs.IsUnavailable(err):
+		return http.StatusServiceUnavailable
+	case errdefs.IsUnknown(err):
+		var unexpected cause.ErrUnexpectedStatus
+		if errors.As(err, &unexpected) && unexpected.Status >= 200 && unexpected.Status < 600 {
+			return unexpected.Status
+		}
+		return http.StatusInternalServerError
+	default:
+		return http.StatusInternalServerError
+	}
+}
+
+// ToNative returns the error best matching the HTTP status code
+func ToNative(statusCode int) error {
+	switch statusCode {
+	case http.StatusNotFound:
+		return errdefs.ErrNotFound
+	case http.StatusBadRequest:
+		return errdefs.ErrInvalidArgument
+	case http.StatusConflict:
+		return errdefs.ErrConflict
+	case http.StatusPreconditionFailed:
+		return errdefs.ErrFailedPrecondition
+	case http.StatusUnauthorized:
+		return errdefs.ErrUnauthenticated
+	case http.StatusForbidden:
+		return errdefs.ErrPermissionDenied
+	case http.StatusNotModified:
+		return errdefs.ErrNotModified
+	case http.StatusTooManyRequests:
+		return errdefs.ErrResourceExhausted
+	case http.StatusInternalServerError:
+		return errdefs.ErrInternal
+	case http.StatusNotImplemented:
+		return errdefs.ErrNotImplemented
+	case http.StatusServiceUnavailable:
+		return errdefs.ErrUnavailable
+	default:
+		return cause.ErrUnexpectedStatus{Status: statusCode}
+	}
+}
diff --git a/vendor/github.com/containerd/errdefs/pkg/internal/cause/cause.go b/vendor/github.com/containerd/errdefs/pkg/internal/cause/cause.go
new file mode 100644
index 000000000..d88756bb0
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/pkg/internal/cause/cause.go
@@ -0,0 +1,33 @@
+/*
+   Copyright The containerd Authors.
+
+   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 cause is used to define root causes for errors
+// common to errors packages like grpc and http.
+package cause
+
+import "fmt"
+
+type ErrUnexpectedStatus struct {
+	Status int
+}
+
+const UnexpectedStatusPrefix = "unexpected status "
+
+func (e ErrUnexpectedStatus) Error() string {
+	return fmt.Sprintf("%s%d", UnexpectedStatusPrefix, e.Status)
+}
+
+func (ErrUnexpectedStatus) Unknown() {}
diff --git a/vendor/github.com/containerd/errdefs/resolve.go b/vendor/github.com/containerd/errdefs/resolve.go
new file mode 100644
index 000000000..c02d4a73f
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/resolve.go
@@ -0,0 +1,147 @@
+/*
+   Copyright The containerd Authors.
+
+   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 errdefs
+
+import "context"
+
+// Resolve returns the first error found in the error chain which matches an
+// error defined in this package or context error. A raw, unwrapped error is
+// returned or ErrUnknown if no matching error is found.
+//
+// This is useful for determining a response code based on the outermost wrapped
+// error rather than the original cause. For example, a not found error deep
+// in the code may be wrapped as an invalid argument. When determining status
+// code from Is* functions, the depth or ordering of the error is not
+// considered.
+//
+// The search order is depth first, a wrapped error returned from any part of
+// the chain from `Unwrap() error` will be returned before any joined errors
+// as returned by `Unwrap() []error`.
+func Resolve(err error) error {
+	if err == nil {
+		return nil
+	}
+	err = firstError(err)
+	if err == nil {
+		err = ErrUnknown
+	}
+	return err
+}
+
+func firstError(err error) error {
+	for {
+		switch err {
+		case ErrUnknown,
+			ErrInvalidArgument,
+			ErrNotFound,
+			ErrAlreadyExists,
+			ErrPermissionDenied,
+			ErrResourceExhausted,
+			ErrFailedPrecondition,
+			ErrConflict,
+			ErrNotModified,
+			ErrAborted,
+			ErrOutOfRange,
+			ErrNotImplemented,
+			ErrInternal,
+			ErrUnavailable,
+			ErrDataLoss,
+			ErrUnauthenticated,
+			context.DeadlineExceeded,
+			context.Canceled:
+			return err
+		}
+		switch e := err.(type) {
+		case customMessage:
+			err = e.err
+		case unknown:
+			return ErrUnknown
+		case invalidParameter:
+			return ErrInvalidArgument
+		case notFound:
+			return ErrNotFound
+		case alreadyExists:
+			return ErrAlreadyExists
+		case forbidden:
+			return ErrPermissionDenied
+		case resourceExhausted:
+			return ErrResourceExhausted
+		case failedPrecondition:
+			return ErrFailedPrecondition
+		case conflict:
+			return ErrConflict
+		case notModified:
+			return ErrNotModified
+		case aborted:
+			return ErrAborted
+		case errOutOfRange:
+			return ErrOutOfRange
+		case notImplemented:
+			return ErrNotImplemented
+		case system:
+			return ErrInternal
+		case unavailable:
+			return ErrUnavailable
+		case dataLoss:
+			return ErrDataLoss
+		case unauthorized:
+			return ErrUnauthenticated
+		case deadlineExceeded:
+			return context.DeadlineExceeded
+		case cancelled:
+			return context.Canceled
+		case interface{ Unwrap() error }:
+			err = e.Unwrap()
+			if err == nil {
+				return nil
+			}
+		case interface{ Unwrap() []error }:
+			for _, ue := range e.Unwrap() {
+				if fe := firstError(ue); fe != nil {
+					return fe
+				}
+			}
+			return nil
+		case interface{ Is(error) bool }:
+			for _, target := range []error{ErrUnknown,
+				ErrInvalidArgument,
+				ErrNotFound,
+				ErrAlreadyExists,
+				ErrPermissionDenied,
+				ErrResourceExhausted,
+				ErrFailedPrecondition,
+				ErrConflict,
+				ErrNotModified,
+				ErrAborted,
+				ErrOutOfRange,
+				ErrNotImplemented,
+				ErrInternal,
+				ErrUnavailable,
+				ErrDataLoss,
+				ErrUnauthenticated,
+				context.DeadlineExceeded,
+				context.Canceled} {
+				if e.Is(target) {
+					return target
+				}
+			}
+			return nil
+		default:
+			return nil
+		}
+	}
+}
diff --git a/vendor/github.com/containerd/platforms/.gitattributes b/vendor/github.com/containerd/platforms/.gitattributes
new file mode 100644
index 000000000..a0717e4b3
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/.gitattributes
@@ -0,0 +1 @@
+*.go text eol=lf
\ No newline at end of file
diff --git a/vendor/github.com/containerd/platforms/.golangci.yml b/vendor/github.com/containerd/platforms/.golangci.yml
new file mode 100644
index 000000000..a695775df
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/.golangci.yml
@@ -0,0 +1,30 @@
+linters:
+  enable:
+    - exportloopref # Checks for pointers to enclosing loop variables
+    - gofmt
+    - goimports
+    - gosec
+    - ineffassign
+    - misspell
+    - nolintlint
+    - revive
+    - staticcheck
+    - tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17
+    - unconvert
+    - unused
+    - vet
+    - dupword # Checks for duplicate words in the source code
+  disable:
+    - errcheck
+
+run:
+  timeout: 5m
+  skip-dirs:
+    - api
+    - cluster
+    - design
+    - docs
+    - docs/man
+    - releases
+    - reports
+    - test # e2e scripts
diff --git a/vendor/github.com/containerd/platforms/LICENSE b/vendor/github.com/containerd/platforms/LICENSE
new file mode 100644
index 000000000..584149b6e
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/LICENSE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright The containerd Authors
+
+   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
+
+       https://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.
diff --git a/vendor/github.com/containerd/platforms/README.md b/vendor/github.com/containerd/platforms/README.md
new file mode 100644
index 000000000..2059de771
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/README.md
@@ -0,0 +1,32 @@
+# platforms
+
+A Go package for formatting, normalizing and matching container platforms.
+
+This package is based on the Open Containers Image Spec definition of a [platform](https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/descriptor.go#L52).
+
+## Platform Specifier
+
+While the OCI platform specifications provide a tool for components to
+specify structured information, user input typically doesn't need the full
+context and much can be inferred. To solve this problem, this package introduces
+"specifiers". A specifier has the format
+`<os>|<arch>|<os>/<arch>[/<variant>]`.  The user can provide either the
+operating system or the architecture or both.
+
+An example of a common specifier is `linux/amd64`. If the host has a default
+runtime that matches this, the user can simply provide the component that
+matters. For example, if an image provides `amd64` and `arm64` support, the
+operating system, `linux` can be inferred, so they only have to provide
+`arm64` or `amd64`. Similar behavior is implemented for operating systems,
+where the architecture may be known but a runtime may support images from
+different operating systems.
+
+## Project details
+
+**platforms** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
\ No newline at end of file
diff --git a/vendor/github.com/containerd/platforms/compare.go b/vendor/github.com/containerd/platforms/compare.go
new file mode 100644
index 000000000..3913ef663
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/compare.go
@@ -0,0 +1,203 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"strconv"
+	"strings"
+
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// MatchComparer is able to match and compare platforms to
+// filter and sort platforms.
+type MatchComparer interface {
+	Matcher
+
+	Less(specs.Platform, specs.Platform) bool
+}
+
+// platformVector returns an (ordered) vector of appropriate specs.Platform
+// objects to try matching for the given platform object (see platforms.Only).
+func platformVector(platform specs.Platform) []specs.Platform {
+	vector := []specs.Platform{platform}
+
+	switch platform.Architecture {
+	case "amd64":
+		if amd64Version, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && amd64Version > 1 {
+			for amd64Version--; amd64Version >= 1; amd64Version-- {
+				vector = append(vector, specs.Platform{
+					Architecture: platform.Architecture,
+					OS:           platform.OS,
+					OSVersion:    platform.OSVersion,
+					OSFeatures:   platform.OSFeatures,
+					Variant:      "v" + strconv.Itoa(amd64Version),
+				})
+			}
+		}
+		vector = append(vector, specs.Platform{
+			Architecture: "386",
+			OS:           platform.OS,
+			OSVersion:    platform.OSVersion,
+			OSFeatures:   platform.OSFeatures,
+		})
+	case "arm":
+		if armVersion, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && armVersion > 5 {
+			for armVersion--; armVersion >= 5; armVersion-- {
+				vector = append(vector, specs.Platform{
+					Architecture: platform.Architecture,
+					OS:           platform.OS,
+					OSVersion:    platform.OSVersion,
+					OSFeatures:   platform.OSFeatures,
+					Variant:      "v" + strconv.Itoa(armVersion),
+				})
+			}
+		}
+	case "arm64":
+		variant := platform.Variant
+		if variant == "" {
+			variant = "v8"
+		}
+		vector = append(vector, platformVector(specs.Platform{
+			Architecture: "arm",
+			OS:           platform.OS,
+			OSVersion:    platform.OSVersion,
+			OSFeatures:   platform.OSFeatures,
+			Variant:      variant,
+		})...)
+	}
+
+	return vector
+}
+
+// Only returns a match comparer for a single platform
+// using default resolution logic for the platform.
+//
+// For arm/v8, will also match arm/v7, arm/v6 and arm/v5
+// For arm/v7, will also match arm/v6 and arm/v5
+// For arm/v6, will also match arm/v5
+// For amd64, will also match 386
+func Only(platform specs.Platform) MatchComparer {
+	return Ordered(platformVector(Normalize(platform))...)
+}
+
+// OnlyStrict returns a match comparer for a single platform.
+//
+// Unlike Only, OnlyStrict does not match sub platforms.
+// So, "arm/vN" will not match "arm/vM" where M < N,
+// and "amd64" will not also match "386".
+//
+// OnlyStrict matches non-canonical forms.
+// So, "arm64" matches "arm/64/v8".
+func OnlyStrict(platform specs.Platform) MatchComparer {
+	return Ordered(Normalize(platform))
+}
+
+// Ordered returns a platform MatchComparer which matches any of the platforms
+// but orders them in order they are provided.
+func Ordered(platforms ...specs.Platform) MatchComparer {
+	matchers := make([]Matcher, len(platforms))
+	for i := range platforms {
+		matchers[i] = NewMatcher(platforms[i])
+	}
+	return orderedPlatformComparer{
+		matchers: matchers,
+	}
+}
+
+// Any returns a platform MatchComparer which matches any of the platforms
+// with no preference for ordering.
+func Any(platforms ...specs.Platform) MatchComparer {
+	matchers := make([]Matcher, len(platforms))
+	for i := range platforms {
+		matchers[i] = NewMatcher(platforms[i])
+	}
+	return anyPlatformComparer{
+		matchers: matchers,
+	}
+}
+
+// All is a platform MatchComparer which matches all platforms
+// with preference for ordering.
+var All MatchComparer = allPlatformComparer{}
+
+type orderedPlatformComparer struct {
+	matchers []Matcher
+}
+
+func (c orderedPlatformComparer) Match(platform specs.Platform) bool {
+	for _, m := range c.matchers {
+		if m.Match(platform) {
+			return true
+		}
+	}
+	return false
+}
+
+func (c orderedPlatformComparer) Less(p1 specs.Platform, p2 specs.Platform) bool {
+	for _, m := range c.matchers {
+		p1m := m.Match(p1)
+		p2m := m.Match(p2)
+		if p1m && !p2m {
+			return true
+		}
+		if p1m || p2m {
+			return false
+		}
+	}
+	return false
+}
+
+type anyPlatformComparer struct {
+	matchers []Matcher
+}
+
+func (c anyPlatformComparer) Match(platform specs.Platform) bool {
+	for _, m := range c.matchers {
+		if m.Match(platform) {
+			return true
+		}
+	}
+	return false
+}
+
+func (c anyPlatformComparer) Less(p1, p2 specs.Platform) bool {
+	var p1m, p2m bool
+	for _, m := range c.matchers {
+		if !p1m && m.Match(p1) {
+			p1m = true
+		}
+		if !p2m && m.Match(p2) {
+			p2m = true
+		}
+		if p1m && p2m {
+			return false
+		}
+	}
+	// If one matches, and the other does, sort match first
+	return p1m && !p2m
+}
+
+type allPlatformComparer struct{}
+
+func (allPlatformComparer) Match(specs.Platform) bool {
+	return true
+}
+
+func (allPlatformComparer) Less(specs.Platform, specs.Platform) bool {
+	return false
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo.go b/vendor/github.com/containerd/platforms/cpuinfo.go
new file mode 100644
index 000000000..91f50e8c8
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo.go
@@ -0,0 +1,43 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"runtime"
+	"sync"
+
+	"github.com/containerd/log"
+)
+
+// Present the ARM instruction set architecture, eg: v7, v8
+// Don't use this value directly; call cpuVariant() instead.
+var cpuVariantValue string
+
+var cpuVariantOnce sync.Once
+
+func cpuVariant() string {
+	cpuVariantOnce.Do(func() {
+		if isArmArch(runtime.GOARCH) {
+			var err error
+			cpuVariantValue, err = getCPUVariant()
+			if err != nil {
+				log.L.Errorf("Error getCPUVariant for OS %s: %v", runtime.GOOS, err)
+			}
+		}
+	})
+	return cpuVariantValue
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo_linux.go b/vendor/github.com/containerd/platforms/cpuinfo_linux.go
new file mode 100644
index 000000000..98c7001f9
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo_linux.go
@@ -0,0 +1,160 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"fmt"
+	"os"
+	"runtime"
+	"strings"
+
+	"golang.org/x/sys/unix"
+)
+
+// getMachineArch retrieves the machine architecture through system call
+func getMachineArch() (string, error) {
+	var uname unix.Utsname
+	err := unix.Uname(&uname)
+	if err != nil {
+		return "", err
+	}
+
+	arch := string(uname.Machine[:bytes.IndexByte(uname.Machine[:], 0)])
+
+	return arch, nil
+}
+
+// For Linux, the kernel has already detected the ABI, ISA and Features.
+// So we don't need to access the ARM registers to detect platform information
+// by ourselves. We can just parse these information from /proc/cpuinfo
+func getCPUInfo(pattern string) (info string, err error) {
+
+	cpuinfo, err := os.Open("/proc/cpuinfo")
+	if err != nil {
+		return "", err
+	}
+	defer cpuinfo.Close()
+
+	// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
+	// the first core is enough.
+	scanner := bufio.NewScanner(cpuinfo)
+	for scanner.Scan() {
+		newline := scanner.Text()
+		list := strings.Split(newline, ":")
+
+		if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
+			return strings.TrimSpace(list[1]), nil
+		}
+	}
+
+	// Check whether the scanner encountered errors
+	err = scanner.Err()
+	if err != nil {
+		return "", err
+	}
+
+	return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errNotFound)
+}
+
+// getCPUVariantFromArch get CPU variant from arch through a system call
+func getCPUVariantFromArch(arch string) (string, error) {
+
+	var variant string
+
+	arch = strings.ToLower(arch)
+
+	if arch == "aarch64" {
+		variant = "8"
+	} else if arch[0:4] == "armv" && len(arch) >= 5 {
+		// Valid arch format is in form of armvXx
+		switch arch[3:5] {
+		case "v8":
+			variant = "8"
+		case "v7":
+			variant = "7"
+		case "v6":
+			variant = "6"
+		case "v5":
+			variant = "5"
+		case "v4":
+			variant = "4"
+		case "v3":
+			variant = "3"
+		default:
+			variant = "unknown"
+		}
+	} else {
+		return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errInvalidArgument)
+	}
+	return variant, nil
+}
+
+// getCPUVariant returns cpu variant for ARM
+// We first try reading "Cpu architecture" field from /proc/cpuinfo
+// If we can't find it, then fall back using a system call
+// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
+// was not present.
+func getCPUVariant() (string, error) {
+	variant, err := getCPUInfo("Cpu architecture")
+	if err != nil {
+		if errors.Is(err, errNotFound) {
+			// Let's try getting CPU variant from machine architecture
+			arch, err := getMachineArch()
+			if err != nil {
+				return "", fmt.Errorf("failure getting machine architecture: %v", err)
+			}
+
+			variant, err = getCPUVariantFromArch(arch)
+			if err != nil {
+				return "", fmt.Errorf("failure getting CPU variant from machine architecture: %v", err)
+			}
+		} else {
+			return "", fmt.Errorf("failure getting CPU variant: %v", err)
+		}
+	}
+
+	// handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
+	// https://www.raspberrypi.org/forums/viewtopic.php?t=12614
+	if runtime.GOARCH == "arm" && variant == "7" {
+		model, err := getCPUInfo("model name")
+		if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
+			variant = "6"
+		}
+	}
+
+	switch strings.ToLower(variant) {
+	case "8", "aarch64":
+		variant = "v8"
+	case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
+		variant = "v7"
+	case "6", "6tej":
+		variant = "v6"
+	case "5", "5t", "5te", "5tej":
+		variant = "v5"
+	case "4", "4t":
+		variant = "v4"
+	case "3":
+		variant = "v3"
+	default:
+		variant = "unknown"
+	}
+
+	return variant, nil
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo_other.go b/vendor/github.com/containerd/platforms/cpuinfo_other.go
new file mode 100644
index 000000000..97a1fe8a3
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo_other.go
@@ -0,0 +1,55 @@
+//go:build !linux
+
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"fmt"
+	"runtime"
+)
+
+func getCPUVariant() (string, error) {
+
+	var variant string
+
+	if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
+		// Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
+		// runtime.GOARCH to determine the variants
+		switch runtime.GOARCH {
+		case "arm64":
+			variant = "v8"
+		case "arm":
+			variant = "v7"
+		default:
+			variant = "unknown"
+		}
+	} else if runtime.GOOS == "freebsd" {
+		// FreeBSD supports ARMv6 and ARMv7 as well as ARMv4 and ARMv5 (though deprecated)
+		// detecting those variants is currently unimplemented
+		switch runtime.GOARCH {
+		case "arm64":
+			variant = "v8"
+		default:
+			variant = "unknown"
+		}
+	} else {
+		return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errNotImplemented)
+	}
+
+	return variant, nil
+}
diff --git a/vendor/github.com/containerd/platforms/database.go b/vendor/github.com/containerd/platforms/database.go
new file mode 100644
index 000000000..2e26fd3b4
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/database.go
@@ -0,0 +1,109 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"runtime"
+	"strings"
+)
+
+// These function are generated from https://golang.org/src/go/build/syslist.go.
+//
+// We use switch statements because they are slightly faster than map lookups
+// and use a little less memory.
+
+// isKnownOS returns true if we know about the operating system.
+//
+// The OS value should be normalized before calling this function.
+func isKnownOS(os string) bool {
+	switch os {
+	case "aix", "android", "darwin", "dragonfly", "freebsd", "hurd", "illumos", "ios", "js", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos":
+		return true
+	}
+	return false
+}
+
+// isArmArch returns true if the architecture is ARM.
+//
+// The arch value should be normalized before being passed to this function.
+func isArmArch(arch string) bool {
+	switch arch {
+	case "arm", "arm64":
+		return true
+	}
+	return false
+}
+
+// isKnownArch returns true if we know about the architecture.
+//
+// The arch value should be normalized before being passed to this function.
+func isKnownArch(arch string) bool {
+	switch arch {
+	case "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "loong64", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "riscv", "riscv64", "s390", "s390x", "sparc", "sparc64", "wasm":
+		return true
+	}
+	return false
+}
+
+func normalizeOS(os string) string {
+	if os == "" {
+		return runtime.GOOS
+	}
+	os = strings.ToLower(os)
+
+	switch os {
+	case "macos":
+		os = "darwin"
+	}
+	return os
+}
+
+// normalizeArch normalizes the architecture.
+func normalizeArch(arch, variant string) (string, string) {
+	arch, variant = strings.ToLower(arch), strings.ToLower(variant)
+	switch arch {
+	case "i386":
+		arch = "386"
+		variant = ""
+	case "x86_64", "x86-64", "amd64":
+		arch = "amd64"
+		if variant == "v1" {
+			variant = ""
+		}
+	case "aarch64", "arm64":
+		arch = "arm64"
+		switch variant {
+		case "8", "v8":
+			variant = ""
+		}
+	case "armhf":
+		arch = "arm"
+		variant = "v7"
+	case "armel":
+		arch = "arm"
+		variant = "v6"
+	case "arm":
+		switch variant {
+		case "", "7":
+			variant = "v7"
+		case "5", "6", "8":
+			variant = "v" + variant
+		}
+	}
+
+	return arch, variant
+}
diff --git a/vendor/github.com/containerd/platforms/defaults.go b/vendor/github.com/containerd/platforms/defaults.go
new file mode 100644
index 000000000..9d898d60e
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults.go
@@ -0,0 +1,29 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+// DefaultString returns the default string specifier for the platform,
+// with [PR#6](https://github.com/containerd/platforms/pull/6) the result
+// may now also include the OSVersion from the provided platform specification.
+func DefaultString() string {
+	return FormatAll(DefaultSpec())
+}
+
+// DefaultStrict returns strict form of Default.
+func DefaultStrict() MatchComparer {
+	return OnlyStrict(DefaultSpec())
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_darwin.go b/vendor/github.com/containerd/platforms/defaults_darwin.go
new file mode 100644
index 000000000..72355ca85
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_darwin.go
@@ -0,0 +1,44 @@
+//go:build darwin
+
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"runtime"
+
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+	return specs.Platform{
+		OS:           runtime.GOOS,
+		Architecture: runtime.GOARCH,
+		// The Variant field will be empty if arch != ARM.
+		Variant: cpuVariant(),
+	}
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+	return Ordered(DefaultSpec(), specs.Platform{
+		// darwin runtime also supports Linux binary via runu/LKL
+		OS:           "linux",
+		Architecture: runtime.GOARCH,
+	})
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_freebsd.go b/vendor/github.com/containerd/platforms/defaults_freebsd.go
new file mode 100644
index 000000000..d3fe89e07
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_freebsd.go
@@ -0,0 +1,43 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"runtime"
+
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+	return specs.Platform{
+		OS:           runtime.GOOS,
+		Architecture: runtime.GOARCH,
+		// The Variant field will be empty if arch != ARM.
+		Variant: cpuVariant(),
+	}
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+	return Ordered(DefaultSpec(), specs.Platform{
+		OS:           "linux",
+		Architecture: runtime.GOARCH,
+		// The Variant field will be empty if arch != ARM.
+		Variant: cpuVariant(),
+	})
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_unix.go b/vendor/github.com/containerd/platforms/defaults_unix.go
new file mode 100644
index 000000000..44acc47eb
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_unix.go
@@ -0,0 +1,40 @@
+//go:build !windows && !darwin && !freebsd
+
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"runtime"
+
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+	return specs.Platform{
+		OS:           runtime.GOOS,
+		Architecture: runtime.GOARCH,
+		// The Variant field will be empty if arch != ARM.
+		Variant: cpuVariant(),
+	}
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+	return Only(DefaultSpec())
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_windows.go b/vendor/github.com/containerd/platforms/defaults_windows.go
new file mode 100644
index 000000000..427ed72eb
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_windows.go
@@ -0,0 +1,118 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	"fmt"
+	"runtime"
+	"strconv"
+	"strings"
+
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	"golang.org/x/sys/windows"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+	major, minor, build := windows.RtlGetNtVersionNumbers()
+	return specs.Platform{
+		OS:           runtime.GOOS,
+		Architecture: runtime.GOARCH,
+		OSVersion:    fmt.Sprintf("%d.%d.%d", major, minor, build),
+		// The Variant field will be empty if arch != ARM.
+		Variant: cpuVariant(),
+	}
+}
+
+type windowsmatcher struct {
+	specs.Platform
+	osVersionPrefix string
+	defaultMatcher  Matcher
+}
+
+// Match matches platform with the same windows major, minor
+// and build version.
+func (m windowsmatcher) Match(p specs.Platform) bool {
+	match := m.defaultMatcher.Match(p)
+
+	if match && m.OS == "windows" {
+		// HPC containers do not have OS version filled
+		if m.OSVersion == "" || p.OSVersion == "" {
+			return true
+		}
+
+		hostOsVersion := getOSVersion(m.osVersionPrefix)
+		ctrOsVersion := getOSVersion(p.OSVersion)
+		return checkHostAndContainerCompat(hostOsVersion, ctrOsVersion)
+	}
+
+	return match
+}
+
+func getOSVersion(osVersionPrefix string) osVersion {
+	parts := strings.Split(osVersionPrefix, ".")
+	if len(parts) < 3 {
+		return osVersion{}
+	}
+
+	majorVersion, _ := strconv.Atoi(parts[0])
+	minorVersion, _ := strconv.Atoi(parts[1])
+	buildNumber, _ := strconv.Atoi(parts[2])
+
+	return osVersion{
+		MajorVersion: uint8(majorVersion),
+		MinorVersion: uint8(minorVersion),
+		Build:        uint16(buildNumber),
+	}
+}
+
+// Less sorts matched platforms in front of other platforms.
+// For matched platforms, it puts platforms with larger revision
+// number in front.
+func (m windowsmatcher) Less(p1, p2 specs.Platform) bool {
+	m1, m2 := m.Match(p1), m.Match(p2)
+	if m1 && m2 {
+		r1, r2 := revision(p1.OSVersion), revision(p2.OSVersion)
+		return r1 > r2
+	}
+	return m1 && !m2
+}
+
+func revision(v string) int {
+	parts := strings.Split(v, ".")
+	if len(parts) < 4 {
+		return 0
+	}
+	r, err := strconv.Atoi(parts[3])
+	if err != nil {
+		return 0
+	}
+	return r
+}
+
+func prefix(v string) string {
+	parts := strings.Split(v, ".")
+	if len(parts) < 4 {
+		return v
+	}
+	return strings.Join(parts[0:3], ".")
+}
+
+// Default returns the current platform's default platform specification.
+func Default() MatchComparer {
+	return Only(DefaultSpec())
+}
diff --git a/vendor/github.com/containerd/platforms/errors.go b/vendor/github.com/containerd/platforms/errors.go
new file mode 100644
index 000000000..5ad721e77
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/errors.go
@@ -0,0 +1,30 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import "errors"
+
+// These errors mirror the errors defined in [github.com/containerd/containerd/errdefs],
+// however, they are not exported as they are not expected to be used as sentinel
+// errors by consumers of this package.
+//
+//nolint:unused // not all errors are used on all platforms.
+var (
+	errNotFound        = errors.New("not found")
+	errInvalidArgument = errors.New("invalid argument")
+	errNotImplemented  = errors.New("not implemented")
+)
diff --git a/vendor/github.com/containerd/platforms/platform_compat_windows.go b/vendor/github.com/containerd/platforms/platform_compat_windows.go
new file mode 100644
index 000000000..89e66f0c0
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platform_compat_windows.go
@@ -0,0 +1,78 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+// osVersion is a wrapper for Windows version information
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
+type osVersion struct {
+	Version      uint32
+	MajorVersion uint8
+	MinorVersion uint8
+	Build        uint16
+}
+
+// Windows Client and Server build numbers.
+//
+// See:
+// https://learn.microsoft.com/en-us/windows/release-health/release-information
+// https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info
+// https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
+const (
+	// rs5 (version 1809, codename "Redstone 5") corresponds to Windows Server
+	// 2019 (ltsc2019), and Windows 10 (October 2018 Update).
+	rs5 = 17763
+
+	// v21H2Server corresponds to Windows Server 2022 (ltsc2022).
+	v21H2Server = 20348
+
+	// v22H2Win11 corresponds to Windows 11 (2022 Update).
+	v22H2Win11 = 22621
+)
+
+// List of stable ABI compliant ltsc releases
+// Note: List must be sorted in ascending order
+var compatLTSCReleases = []uint16{
+	v21H2Server,
+}
+
+// CheckHostAndContainerCompat checks if given host and container
+// OS versions are compatible.
+// It includes support for stable ABI compliant versions as well.
+// Every release after WS 2022 will support the previous ltsc
+// container image. Stable ABI is in preview mode for windows 11 client.
+// Refer: https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10#windows-server-host-os-compatibility
+func checkHostAndContainerCompat(host, ctr osVersion) bool {
+	// check major minor versions of host and guest
+	if host.MajorVersion != ctr.MajorVersion ||
+		host.MinorVersion != ctr.MinorVersion {
+		return false
+	}
+
+	// If host is < WS 2022, exact version match is required
+	if host.Build < v21H2Server {
+		return host.Build == ctr.Build
+	}
+
+	var supportedLtscRelease uint16
+	for i := len(compatLTSCReleases) - 1; i >= 0; i-- {
+		if host.Build >= compatLTSCReleases[i] {
+			supportedLtscRelease = compatLTSCReleases[i]
+			break
+		}
+	}
+	return ctr.Build >= supportedLtscRelease && ctr.Build <= host.Build
+}
diff --git a/vendor/github.com/containerd/platforms/platforms.go b/vendor/github.com/containerd/platforms/platforms.go
new file mode 100644
index 000000000..1bbbdb91d
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platforms.go
@@ -0,0 +1,308 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms provides a toolkit for normalizing, matching and
+// specifying container platforms.
+//
+// Centered around OCI platform specifications, we define a string-based
+// specifier syntax that can be used for user input. With a specifier, users
+// only need to specify the parts of the platform that are relevant to their
+// context, providing an operating system or architecture or both.
+//
+// How do I use this package?
+//
+// The vast majority of use cases should simply use the match function with
+// user input. The first step is to parse a specifier into a matcher:
+//
+//	m, err := Parse("linux")
+//	if err != nil { ... }
+//
+// Once you have a matcher, use it to match against the platform declared by a
+// component, typically from an image or runtime. Since extracting an images
+// platform is a little more involved, we'll use an example against the
+// platform default:
+//
+//	if ok := m.Match(Default()); !ok { /* doesn't match */ }
+//
+// This can be composed in loops for resolving runtimes or used as a filter for
+// fetch and select images.
+//
+// More details of the specifier syntax and platform spec follow.
+//
+// # Declaring Platform Support
+//
+// Components that have strict platform requirements should use the OCI
+// platform specification to declare their support. Typically, this will be
+// images and runtimes that should make these declaring which platform they
+// support specifically. This looks roughly as follows:
+//
+//	  type Platform struct {
+//		   Architecture string
+//		   OS           string
+//		   Variant      string
+//	  }
+//
+// Most images and runtimes should at least set Architecture and OS, according
+// to their GOARCH and GOOS values, respectively (follow the OCI image
+// specification when in doubt). ARM should set variant under certain
+// discussions, which are outlined below.
+//
+// # Platform Specifiers
+//
+// While the OCI platform specifications provide a tool for components to
+// specify structured information, user input typically doesn't need the full
+// context and much can be inferred. To solve this problem, we introduced
+// "specifiers". A specifier has the format
+// `<os>|<arch>|<os>/<arch>[/<variant>]`.  The user can provide either the
+// operating system or the architecture or both.
+//
+// An example of a common specifier is `linux/amd64`. If the host has a default
+// of runtime that matches this, the user can simply provide the component that
+// matters. For example, if a image provides amd64 and arm64 support, the
+// operating system, `linux` can be inferred, so they only have to provide
+// `arm64` or `amd64`. Similar behavior is implemented for operating systems,
+// where the architecture may be known but a runtime may support images from
+// different operating systems.
+//
+// # Normalization
+//
+// Because not all users are familiar with the way the Go runtime represents
+// platforms, several normalizations have been provided to make this package
+// easier to user.
+//
+// The following are performed for architectures:
+//
+//	Value    Normalized
+//	aarch64  arm64
+//	armhf    arm
+//	armel    arm/v6
+//	i386     386
+//	x86_64   amd64
+//	x86-64   amd64
+//
+// We also normalize the operating system `macos` to `darwin`.
+//
+// # ARM Support
+//
+// To qualify ARM architecture, the Variant field is used to qualify the arm
+// version. The most common arm version, v7, is represented without the variant
+// unless it is explicitly provided. This is treated as equivalent to armhf. A
+// previous architecture, armel, will be normalized to arm/v6.
+//
+// Similarly, the most common arm64 version v8, and most common amd64 version v1
+// are represented without the variant.
+//
+// While these normalizations are provided, their support on arm platforms has
+// not yet been fully implemented and tested.
+package platforms
+
+import (
+	"fmt"
+	"path"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+var (
+	specifierRe    = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
+	osAndVersionRe = regexp.MustCompile(`^([A-Za-z0-9_-]+)(?:\(([A-Za-z0-9_.-]*)\))?$`)
+)
+
+const osAndVersionFormat = "%s(%s)"
+
+// Platform is a type alias for convenience, so there is no need to import image-spec package everywhere.
+type Platform = specs.Platform
+
+// Matcher matches platforms specifications, provided by an image or runtime.
+type Matcher interface {
+	Match(platform specs.Platform) bool
+}
+
+// NewMatcher returns a simple matcher based on the provided platform
+// specification. The returned matcher only looks for equality based on os,
+// architecture and variant.
+//
+// One may implement their own matcher if this doesn't provide the required
+// functionality.
+//
+// Applications should opt to use `Match` over directly parsing specifiers.
+func NewMatcher(platform specs.Platform) Matcher {
+	return newDefaultMatcher(platform)
+}
+
+type matcher struct {
+	specs.Platform
+}
+
+func (m *matcher) Match(platform specs.Platform) bool {
+	normalized := Normalize(platform)
+	return m.OS == normalized.OS &&
+		m.Architecture == normalized.Architecture &&
+		m.Variant == normalized.Variant
+}
+
+func (m *matcher) String() string {
+	return FormatAll(m.Platform)
+}
+
+// ParseAll parses a list of platform specifiers into a list of platform.
+func ParseAll(specifiers []string) ([]specs.Platform, error) {
+	platforms := make([]specs.Platform, len(specifiers))
+	for i, s := range specifiers {
+		p, err := Parse(s)
+		if err != nil {
+			return nil, fmt.Errorf("invalid platform %s: %w", s, err)
+		}
+		platforms[i] = p
+	}
+	return platforms, nil
+}
+
+// Parse parses the platform specifier syntax into a platform declaration.
+//
+// Platform specifiers are in the format `<os>[(<OSVersion>)]|<arch>|<os>[(<OSVersion>)]/<arch>[/<variant>]`.
+// The minimum required information for a platform specifier is the operating
+// system or architecture. The OSVersion can be part of the OS like `windows(10.0.17763)`
+// When an OSVersion is specified, then specs.Platform.OSVersion is populated with that value,
+// and an empty string otherwise.
+// If there is only a single string (no slashes), the
+// value will be matched against the known set of operating systems, then fall
+// back to the known set of architectures. The missing component will be
+// inferred based on the local environment.
+func Parse(specifier string) (specs.Platform, error) {
+	if strings.Contains(specifier, "*") {
+		// TODO(stevvooe): need to work out exact wildcard handling
+		return specs.Platform{}, fmt.Errorf("%q: wildcards not yet supported: %w", specifier, errInvalidArgument)
+	}
+
+	// Limit to 4 elements to prevent unbounded split
+	parts := strings.SplitN(specifier, "/", 4)
+
+	var p specs.Platform
+	for i, part := range parts {
+		if i == 0 {
+			// First element is <os>[(<OSVersion>)]
+			osVer := osAndVersionRe.FindStringSubmatch(part)
+			if osVer == nil {
+				return specs.Platform{}, fmt.Errorf("%q is an invalid OS component of %q: OSAndVersion specifier component must match %q: %w", part, specifier, osAndVersionRe.String(), errInvalidArgument)
+			}
+
+			p.OS = normalizeOS(osVer[1])
+			p.OSVersion = osVer[2]
+		} else {
+			if !specifierRe.MatchString(part) {
+				return specs.Platform{}, fmt.Errorf("%q is an invalid component of %q: platform specifier component must match %q: %w", part, specifier, specifierRe.String(), errInvalidArgument)
+			}
+		}
+	}
+
+	switch len(parts) {
+	case 1:
+		// in this case, we will test that the value might be an OS (with or
+		// without the optional OSVersion specified) and look it up.
+		// If it is not known, we'll treat it as an architecture. Since
+		// we have very little information about the platform here, we are
+		// going to be a little more strict if we don't know about the argument
+		// value.
+		if isKnownOS(p.OS) {
+			// picks a default architecture
+			p.Architecture = runtime.GOARCH
+			if p.Architecture == "arm" && cpuVariant() != "v7" {
+				p.Variant = cpuVariant()
+			}
+
+			return p, nil
+		}
+
+		p.Architecture, p.Variant = normalizeArch(parts[0], "")
+		if p.Architecture == "arm" && p.Variant == "v7" {
+			p.Variant = ""
+		}
+		if isKnownArch(p.Architecture) {
+			p.OS = runtime.GOOS
+			return p, nil
+		}
+
+		return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errInvalidArgument)
+	case 2:
+		// In this case, we treat as a regular OS[(OSVersion)]/arch pair. We don't care
+		// about whether or not we know of the platform.
+		p.Architecture, p.Variant = normalizeArch(parts[1], "")
+		if p.Architecture == "arm" && p.Variant == "v7" {
+			p.Variant = ""
+		}
+
+		return p, nil
+	case 3:
+		// we have a fully specified variant, this is rare
+		p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
+		if p.Architecture == "arm64" && p.Variant == "" {
+			p.Variant = "v8"
+		}
+
+		return p, nil
+	}
+
+	return specs.Platform{}, fmt.Errorf("%q: cannot parse platform specifier: %w", specifier, errInvalidArgument)
+}
+
+// MustParse is like Parses but panics if the specifier cannot be parsed.
+// Simplifies initialization of global variables.
+func MustParse(specifier string) specs.Platform {
+	p, err := Parse(specifier)
+	if err != nil {
+		panic("platform: Parse(" + strconv.Quote(specifier) + "): " + err.Error())
+	}
+	return p
+}
+
+// Format returns a string specifier from the provided platform specification.
+func Format(platform specs.Platform) string {
+	if platform.OS == "" {
+		return "unknown"
+	}
+
+	return path.Join(platform.OS, platform.Architecture, platform.Variant)
+}
+
+// FormatAll returns a string specifier that also includes the OSVersion from the
+// provided platform specification.
+func FormatAll(platform specs.Platform) string {
+	if platform.OS == "" {
+		return "unknown"
+	}
+
+	if platform.OSVersion != "" {
+		OSAndVersion := fmt.Sprintf(osAndVersionFormat, platform.OS, platform.OSVersion)
+		return path.Join(OSAndVersion, platform.Architecture, platform.Variant)
+	}
+	return path.Join(platform.OS, platform.Architecture, platform.Variant)
+}
+
+// Normalize validates and translate the platform to the canonical value.
+//
+// For example, if "Aarch64" is encountered, we change it to "arm64" or if
+// "x86_64" is encountered, it becomes "amd64".
+func Normalize(platform specs.Platform) specs.Platform {
+	platform.OS = normalizeOS(platform.OS)
+	platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant)
+
+	return platform
+}
diff --git a/vendor/github.com/containerd/platforms/platforms_other.go b/vendor/github.com/containerd/platforms/platforms_other.go
new file mode 100644
index 000000000..03f4dcd99
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platforms_other.go
@@ -0,0 +1,30 @@
+//go:build !windows
+
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// NewMatcher returns the default Matcher for containerd
+func newDefaultMatcher(platform specs.Platform) Matcher {
+	return &matcher{
+		Platform: Normalize(platform),
+	}
+}
diff --git a/vendor/github.com/containerd/platforms/platforms_windows.go b/vendor/github.com/containerd/platforms/platforms_windows.go
new file mode 100644
index 000000000..950e2a2dd
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platforms_windows.go
@@ -0,0 +1,34 @@
+/*
+   Copyright The containerd Authors.
+
+   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 platforms
+
+import (
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// NewMatcher returns a Windows matcher that will match on osVersionPrefix if
+// the platform is Windows otherwise use the default matcher
+func newDefaultMatcher(platform specs.Platform) Matcher {
+	prefix := prefix(platform.OSVersion)
+	return windowsmatcher{
+		Platform:        platform,
+		osVersionPrefix: prefix,
+		defaultMatcher: &matcher{
+			Platform: Normalize(platform),
+		},
+	}
+}
diff --git a/vendor/github.com/cpuguy83/dockercfg/LICENSE b/vendor/github.com/cpuguy83/dockercfg/LICENSE
new file mode 100644
index 000000000..8ed681804
--- /dev/null
+++ b/vendor/github.com/cpuguy83/dockercfg/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Brian Goff
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/vendor/github.com/cpuguy83/dockercfg/README.md b/vendor/github.com/cpuguy83/dockercfg/README.md
new file mode 100644
index 000000000..880ab8010
--- /dev/null
+++ b/vendor/github.com/cpuguy83/dockercfg/README.md
@@ -0,0 +1,8 @@
+### github.com/cpuguy83/dockercfg
+Go library to load docker CLI configs, auths, etc. with minimal deps.
+So far the only deps are on the stdlib.
+
+### Usage
+See the [godoc](https://godoc.org/github.com/cpuguy83/dockercfg) for API details.
+
+I'm currently using this in [zapp](https://github.com/cpuguy83/zapp/blob/d25c43d4cd7ccf29fba184aafbc720a753e1a15d/main.go#L58-L83) to handle registry auth instead of always asking the user to enter it.
\ No newline at end of file
diff --git a/vendor/github.com/cpuguy83/dockercfg/auth.go b/vendor/github.com/cpuguy83/dockercfg/auth.go
new file mode 100644
index 000000000..106ab8479
--- /dev/null
+++ b/vendor/github.com/cpuguy83/dockercfg/auth.go
@@ -0,0 +1,215 @@
+package dockercfg
+
+import (
+	"bytes"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/fs"
+	"os/exec"
+	"runtime"
+	"strings"
+)
+
+// This is used by the docker CLI in cases where an oauth identity token is used.
+// In that case the username is stored literally as `<token>`
+// When fetching the credentials we check for this value to determine if.
+const tokenUsername = "<token>"
+
+// GetRegistryCredentials gets registry credentials for the passed in registry host.
+//
+// This will use [LoadDefaultConfig] to read registry auth details from the config.
+// If the config doesn't exist, it will attempt to load registry credentials using the default credential helper for the platform.
+func GetRegistryCredentials(hostname string) (string, string, error) {
+	cfg, err := LoadDefaultConfig()
+	if err != nil {
+		if !errors.Is(err, fs.ErrNotExist) {
+			return "", "", fmt.Errorf("load default config: %w", err)
+		}
+
+		return GetCredentialsFromHelper("", hostname)
+	}
+
+	return cfg.GetRegistryCredentials(hostname)
+}
+
+// ResolveRegistryHost can be used to transform a docker registry host name into what is used for the docker config/cred helpers
+//
+// This is useful for using with containerd authorizers.
+// Naturally this only transforms docker hub URLs.
+func ResolveRegistryHost(host string) string {
+	switch host {
+	case "index.docker.io", "docker.io", "https://index.docker.io/v1/", "registry-1.docker.io":
+		return "https://index.docker.io/v1/"
+	}
+	return host
+}
+
+// GetRegistryCredentials gets credentials, if any, for the provided hostname.
+//
+// Hostnames should already be resolved using [ResolveRegistryHost].
+//
+// If the returned username string is empty, the password is an identity token.
+func (c *Config) GetRegistryCredentials(hostname string) (string, string, error) {
+	h, ok := c.CredentialHelpers[hostname]
+	if ok {
+		return GetCredentialsFromHelper(h, hostname)
+	}
+
+	if c.CredentialsStore != "" {
+		username, password, err := GetCredentialsFromHelper(c.CredentialsStore, hostname)
+		if err != nil {
+			return "", "", fmt.Errorf("get credentials from store: %w", err)
+		}
+
+		if username != "" || password != "" {
+			return username, password, nil
+		}
+	}
+
+	auth, ok := c.AuthConfigs[hostname]
+	if !ok {
+		return GetCredentialsFromHelper("", hostname)
+	}
+
+	if auth.IdentityToken != "" {
+		return "", auth.IdentityToken, nil
+	}
+
+	if auth.Username != "" && auth.Password != "" {
+		return auth.Username, auth.Password, nil
+	}
+
+	return DecodeBase64Auth(auth)
+}
+
+// DecodeBase64Auth decodes the legacy file-based auth storage from the docker CLI.
+// It takes the "Auth" filed from AuthConfig and decodes that into a username and password.
+//
+// If "Auth" is empty, an empty user/pass will be returned, but not an error.
+func DecodeBase64Auth(auth AuthConfig) (string, string, error) {
+	if auth.Auth == "" {
+		return "", "", nil
+	}
+
+	decLen := base64.StdEncoding.DecodedLen(len(auth.Auth))
+	decoded := make([]byte, decLen)
+	n, err := base64.StdEncoding.Decode(decoded, []byte(auth.Auth))
+	if err != nil {
+		return "", "", fmt.Errorf("decode auth: %w", err)
+	}
+
+	decoded = decoded[:n]
+
+	const sep = ":"
+	user, pass, found := strings.Cut(string(decoded), sep)
+	if !found {
+		return "", "", fmt.Errorf("invalid auth: missing %q separator", sep)
+	}
+
+	return user, pass, nil
+}
+
+// Errors from credential helpers.
+var (
+	ErrCredentialsNotFound         = errors.New("credentials not found in native keychain")
+	ErrCredentialsMissingServerURL = errors.New("no credentials server URL")
+)
+
+//nolint:gochecknoglobals // These are used to mock exec in tests.
+var (
+	// execLookPath is a variable that can be used to mock exec.LookPath in tests.
+	execLookPath = exec.LookPath
+	// execCommand is a variable that can be used to mock exec.Command in tests.
+	execCommand = exec.Command
+)
+
+// GetCredentialsFromHelper attempts to lookup credentials from the passed in docker credential helper.
+//
+// The credential helper should just be the suffix name (no "docker-credential-").
+// If the passed in helper program is empty this will look up the default helper for the platform.
+//
+// If the credentials are not found, no error is returned, only empty credentials.
+//
+// Hostnames should already be resolved using [ResolveRegistryHost]
+//
+// If the username string is empty, the password string is an identity token.
+func GetCredentialsFromHelper(helper, hostname string) (string, string, error) {
+	if helper == "" {
+		helper, helperErr := getCredentialHelper()
+		if helperErr != nil {
+			return "", "", fmt.Errorf("get credential helper: %w", helperErr)
+		}
+
+		if helper == "" {
+			return "", "", nil
+		}
+	}
+
+	helper = "docker-credential-" + helper
+	p, err := execLookPath(helper)
+	if err != nil {
+		if !errors.Is(err, exec.ErrNotFound) {
+			return "", "", fmt.Errorf("look up %q: %w", helper, err)
+		}
+
+		return "", "", nil
+	}
+
+	var outBuf, errBuf bytes.Buffer
+	cmd := execCommand(p, "get")
+	cmd.Stdin = strings.NewReader(hostname)
+	cmd.Stdout = &outBuf
+	cmd.Stderr = &errBuf
+
+	if err = cmd.Run(); err != nil {
+		out := strings.TrimSpace(outBuf.String())
+		switch out {
+		case ErrCredentialsNotFound.Error():
+			return "", "", nil
+		case ErrCredentialsMissingServerURL.Error():
+			return "", "", ErrCredentialsMissingServerURL
+		default:
+			return "", "", fmt.Errorf("execute %q stdout: %q stderr: %q: %w",
+				helper, out, strings.TrimSpace(errBuf.String()), err,
+			)
+		}
+	}
+
+	var creds struct {
+		Username string `json:"Username"`
+		Secret   string `json:"Secret"`
+	}
+
+	if err = json.Unmarshal(outBuf.Bytes(), &creds); err != nil {
+		return "", "", fmt.Errorf("unmarshal credentials from: %q: %w", helper, err)
+	}
+
+	// When tokenUsername is used, the output is an identity token and the username is garbage.
+	if creds.Username == tokenUsername {
+		creds.Username = ""
+	}
+
+	return creds.Username, creds.Secret, nil
+}
+
+// getCredentialHelper gets the default credential helper name for the current platform.
+func getCredentialHelper() (string, error) {
+	switch runtime.GOOS {
+	case "linux":
+		if _, err := exec.LookPath("pass"); err != nil {
+			if errors.Is(err, exec.ErrNotFound) {
+				return "secretservice", nil
+			}
+			return "", fmt.Errorf(`look up "pass": %w`, err)
+		}
+		return "pass", nil
+	case "darwin":
+		return "osxkeychain", nil
+	case "windows":
+		return "wincred", nil
+	default:
+		return "", nil
+	}
+}
diff --git a/vendor/github.com/cpuguy83/dockercfg/config.go b/vendor/github.com/cpuguy83/dockercfg/config.go
new file mode 100644
index 000000000..5e5390794
--- /dev/null
+++ b/vendor/github.com/cpuguy83/dockercfg/config.go
@@ -0,0 +1,65 @@
+package dockercfg
+
+// Config represents the on disk format of the docker CLI's config file.
+type Config struct {
+	AuthConfigs          map[string]AuthConfig  `json:"auths"`
+	HTTPHeaders          map[string]string      `json:"HttpHeaders,omitempty"`
+	PsFormat             string                 `json:"psFormat,omitempty"`
+	ImagesFormat         string                 `json:"imagesFormat,omitempty"`
+	NetworksFormat       string                 `json:"networksFormat,omitempty"`
+	PluginsFormat        string                 `json:"pluginsFormat,omitempty"`
+	VolumesFormat        string                 `json:"volumesFormat,omitempty"`
+	StatsFormat          string                 `json:"statsFormat,omitempty"`
+	DetachKeys           string                 `json:"detachKeys,omitempty"`
+	CredentialsStore     string                 `json:"credsStore,omitempty"`
+	CredentialHelpers    map[string]string      `json:"credHelpers,omitempty"`
+	Filename             string                 `json:"-"` // Note: for internal use only.
+	ServiceInspectFormat string                 `json:"serviceInspectFormat,omitempty"`
+	ServicesFormat       string                 `json:"servicesFormat,omitempty"`
+	TasksFormat          string                 `json:"tasksFormat,omitempty"`
+	SecretFormat         string                 `json:"secretFormat,omitempty"`
+	ConfigFormat         string                 `json:"configFormat,omitempty"`
+	NodesFormat          string                 `json:"nodesFormat,omitempty"`
+	PruneFilters         []string               `json:"pruneFilters,omitempty"`
+	Proxies              map[string]ProxyConfig `json:"proxies,omitempty"`
+	Experimental         string                 `json:"experimental,omitempty"`
+	StackOrchestrator    string                 `json:"stackOrchestrator,omitempty"`
+	Kubernetes           *KubernetesConfig      `json:"kubernetes,omitempty"`
+	CurrentContext       string                 `json:"currentContext,omitempty"`
+	CLIPluginsExtraDirs  []string               `json:"cliPluginsExtraDirs,omitempty"`
+	Aliases              map[string]string      `json:"aliases,omitempty"`
+}
+
+// ProxyConfig contains proxy configuration settings.
+type ProxyConfig struct {
+	HTTPProxy  string `json:"httpProxy,omitempty"`
+	HTTPSProxy string `json:"httpsProxy,omitempty"`
+	NoProxy    string `json:"noProxy,omitempty"`
+	FTPProxy   string `json:"ftpProxy,omitempty"`
+}
+
+// AuthConfig contains authorization information for connecting to a Registry.
+type AuthConfig struct {
+	Username string `json:"username,omitempty"`
+	Password string `json:"password,omitempty"`
+	Auth     string `json:"auth,omitempty"`
+
+	// Email is an optional value associated with the username.
+	// This field is deprecated and will be removed in a later
+	// version of docker.
+	Email string `json:"email,omitempty"`
+
+	ServerAddress string `json:"serveraddress,omitempty"`
+
+	// IdentityToken is used to authenticate the user and get
+	// an access token for the registry.
+	IdentityToken string `json:"identitytoken,omitempty"`
+
+	// RegistryToken is a bearer token to be sent to a registry.
+	RegistryToken string `json:"registrytoken,omitempty"`
+}
+
+// KubernetesConfig contains Kubernetes orchestrator settings.
+type KubernetesConfig struct {
+	AllNamespaces string `json:"allNamespaces,omitempty"`
+}
diff --git a/vendor/github.com/cpuguy83/dockercfg/load.go b/vendor/github.com/cpuguy83/dockercfg/load.go
new file mode 100644
index 000000000..a1c4dca02
--- /dev/null
+++ b/vendor/github.com/cpuguy83/dockercfg/load.go
@@ -0,0 +1,55 @@
+package dockercfg
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"path/filepath"
+)
+
+// UserHomeConfigPath returns the path to the docker config in the current user's home dir.
+func UserHomeConfigPath() (string, error) {
+	home, err := os.UserHomeDir()
+	if err != nil {
+		return "", fmt.Errorf("user home dir: %w", err)
+	}
+
+	return filepath.Join(home, ".docker", "config.json"), nil
+}
+
+// ConfigPath returns the path to the docker cli config.
+//
+// It will either use the DOCKER_CONFIG env var if set, or the value from [UserHomeConfigPath]
+// DOCKER_CONFIG would be the dir path where `config.json` is stored, this returns the path to config.json.
+func ConfigPath() (string, error) {
+	if p := os.Getenv("DOCKER_CONFIG"); p != "" {
+		return filepath.Join(p, "config.json"), nil
+	}
+	return UserHomeConfigPath()
+}
+
+// LoadDefaultConfig loads the docker cli config from the path returned from [ConfigPath].
+func LoadDefaultConfig() (Config, error) {
+	var cfg Config
+	p, err := ConfigPath()
+	if err != nil {
+		return cfg, fmt.Errorf("config path: %w", err)
+	}
+
+	return cfg, FromFile(p, &cfg)
+}
+
+// FromFile loads config from the specified path into cfg.
+func FromFile(configPath string, cfg *Config) error {
+	f, err := os.Open(configPath)
+	if err != nil {
+		return fmt.Errorf("open config: %w", err)
+	}
+	defer f.Close()
+
+	if err = json.NewDecoder(f).Decode(&cfg); err != nil {
+		return fmt.Errorf("decode config: %w", err)
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/distribution/reference/.gitattributes b/vendor/github.com/distribution/reference/.gitattributes
new file mode 100644
index 000000000..d207b1802
--- /dev/null
+++ b/vendor/github.com/distribution/reference/.gitattributes
@@ -0,0 +1 @@
+*.go text eol=lf
diff --git a/vendor/github.com/distribution/reference/.gitignore b/vendor/github.com/distribution/reference/.gitignore
new file mode 100644
index 000000000..dc07e6b04
--- /dev/null
+++ b/vendor/github.com/distribution/reference/.gitignore
@@ -0,0 +1,2 @@
+# Cover profiles
+*.out
diff --git a/vendor/github.com/distribution/reference/.golangci.yml b/vendor/github.com/distribution/reference/.golangci.yml
new file mode 100644
index 000000000..793f0bb7e
--- /dev/null
+++ b/vendor/github.com/distribution/reference/.golangci.yml
@@ -0,0 +1,18 @@
+linters:
+  enable:
+    - bodyclose
+    - dupword # Checks for duplicate words in the source code
+    - gofmt
+    - goimports
+    - ineffassign
+    - misspell
+    - revive
+    - staticcheck
+    - unconvert
+    - unused
+    - vet
+  disable:
+    - errcheck
+
+run:
+  deadline: 2m
diff --git a/vendor/github.com/distribution/reference/CODE-OF-CONDUCT.md b/vendor/github.com/distribution/reference/CODE-OF-CONDUCT.md
new file mode 100644
index 000000000..48f6704c6
--- /dev/null
+++ b/vendor/github.com/distribution/reference/CODE-OF-CONDUCT.md
@@ -0,0 +1,5 @@
+# Code of Conduct
+
+We follow the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md).
+
+Please contact the [CNCF Code of Conduct Committee](mailto:conduct@cncf.io) in order to report violations of the Code of Conduct.
diff --git a/vendor/github.com/distribution/reference/CONTRIBUTING.md b/vendor/github.com/distribution/reference/CONTRIBUTING.md
new file mode 100644
index 000000000..ab2194665
--- /dev/null
+++ b/vendor/github.com/distribution/reference/CONTRIBUTING.md
@@ -0,0 +1,114 @@
+# Contributing to the reference library
+
+## Community help
+
+If you need help, please ask in the [#distribution](https://cloud-native.slack.com/archives/C01GVR8SY4R) channel on CNCF community slack.
+[Click here for an invite to the CNCF community slack](https://slack.cncf.io/)
+
+## Reporting security issues
+
+The maintainers take security seriously. If you discover a security
+issue, please bring it to their attention right away!
+
+Please **DO NOT** file a public issue, instead send your report privately to
+[cncf-distribution-security@lists.cncf.io](mailto:cncf-distribution-security@lists.cncf.io).
+
+## Reporting an issue properly
+
+By following these simple rules you will get better and faster feedback on your issue.
+
+ - search the bugtracker for an already reported issue
+
+### If you found an issue that describes your problem:
+
+ - please read other user comments first, and confirm this is the same issue: a given error condition might be indicative of different problems - you may also find a workaround in the comments
+ - please refrain from adding "same thing here" or "+1" comments
+ - you don't need to comment on an issue to get notified of updates: just hit the "subscribe" button
+ - comment if you have some new, technical and relevant information to add to the case
+ - __DO NOT__ comment on closed issues or merged PRs. If you think you have a related problem, open up a new issue and reference the PR or issue.
+
+### If you have not found an existing issue that describes your problem:
+
+ 1. create a new issue, with a succinct title that describes your issue:
+   - bad title: "It doesn't work with my docker"
+   - good title: "Private registry push fail: 400 error with E_INVALID_DIGEST"
+ 2. copy the output of (or similar for other container tools):
+   - `docker version`
+   - `docker info`
+   - `docker exec <registry-container> registry --version`
+ 3. copy the command line you used to launch your Registry
+ 4. restart your docker daemon in debug mode (add `-D` to the daemon launch arguments)
+ 5. reproduce your problem and get your docker daemon logs showing the error
+ 6. if relevant, copy your registry logs that show the error
+ 7. provide any relevant detail about your specific Registry configuration (e.g., storage backend used)
+ 8. indicate if you are using an enterprise proxy, Nginx, or anything else between you and your Registry
+
+## Contributing Code
+
+Contributions should be made via pull requests. Pull requests will be reviewed
+by one or more maintainers or reviewers and merged when acceptable.
+
+You should follow the basic GitHub workflow:
+
+ 1. Use your own [fork](https://help.github.com/en/articles/about-forks)
+ 2. Create your [change](https://github.com/containerd/project/blob/master/CONTRIBUTING.md#successful-changes)
+ 3. Test your code
+ 4. [Commit](https://github.com/containerd/project/blob/master/CONTRIBUTING.md#commit-messages) your work, always [sign your commits](https://github.com/containerd/project/blob/master/CONTRIBUTING.md#commit-messages)
+ 5. Push your change to your fork and create a [Pull Request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork)
+
+Refer to [containerd's contribution guide](https://github.com/containerd/project/blob/master/CONTRIBUTING.md#successful-changes)
+for tips on creating a successful contribution.
+
+## Sign your work
+
+The sign-off is a simple line at the end of the explanation for the patch. Your
+signature certifies that you wrote the patch or otherwise have the right to pass
+it on as an open-source patch. The rules are pretty simple: if you can certify
+the below (from [developercertificate.org](http://developercertificate.org/)):
+
+```
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the open source license
+    indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+    of my knowledge, is covered under an appropriate open source
+    license and I have the right under that license to submit that
+    work with modifications, whether created in whole or in part
+    by me, under the same open source license (unless I am
+    permitted to submit under a different license), as indicated
+    in the file; or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a), (b) or (c) and I have not modified
+    it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
+```
+
+Then you just add a line to every git commit message:
+
+    Signed-off-by: Joe Smith <joe.smith@email.com>
+
+Use your real name (sorry, no pseudonyms or anonymous contributions.)
+
+If you set your `user.name` and `user.email` git configs, you can sign your
+commit automatically with `git commit -s`.
diff --git a/vendor/github.com/distribution/reference/GOVERNANCE.md b/vendor/github.com/distribution/reference/GOVERNANCE.md
new file mode 100644
index 000000000..200045b05
--- /dev/null
+++ b/vendor/github.com/distribution/reference/GOVERNANCE.md
@@ -0,0 +1,144 @@
+# distribution/reference Project Governance
+
+Distribution [Code of Conduct](./CODE-OF-CONDUCT.md) can be found here.
+
+For specific guidance on practical contribution steps please
+see our [CONTRIBUTING.md](./CONTRIBUTING.md) guide.
+
+## Maintainership
+
+There are different types of maintainers, with different responsibilities, but
+all maintainers have 3 things in common:
+
+1) They share responsibility in the project's success.
+2) They have made a long-term, recurring time investment to improve the project.
+3) They spend that time doing whatever needs to be done, not necessarily what
+is the most interesting or fun.
+
+Maintainers are often under-appreciated, because their work is harder to appreciate.
+It's easy to appreciate a really cool and technically advanced feature. It's harder
+to appreciate the absence of bugs, the slow but steady improvement in stability,
+or the reliability of a release process. But those things distinguish a good
+project from a great one.
+
+## Reviewers
+
+A reviewer is a core role within the project.
+They share in reviewing issues and pull requests and their LGTM counts towards the
+required LGTM count to merge a code change into the project.
+
+Reviewers are part of the organization but do not have write access.
+Becoming a reviewer is a core aspect in the journey to becoming a maintainer.
+
+## Adding maintainers
+
+Maintainers are first and foremost contributors that have shown they are
+committed to the long term success of a project. Contributors wanting to become
+maintainers are expected to be deeply involved in contributing code, pull
+request review, and triage of issues in the project for more than three months.
+
+Just contributing does not make you a maintainer, it is about building trust
+with the current maintainers of the project and being a person that they can
+depend on and trust to make decisions in the best interest of the project.
+
+Periodically, the existing maintainers curate a list of contributors that have
+shown regular activity on the project over the prior months. From this list,
+maintainer candidates are selected and proposed in a pull request or a
+maintainers communication channel.
+
+After a candidate has been announced to the maintainers, the existing
+maintainers are given five business days to discuss the candidate, raise
+objections and cast their vote. Votes may take place on the communication
+channel or via pull request comment. Candidates must be approved by at least 66%
+of the current maintainers by adding their vote on the mailing list. The
+reviewer role has the same process but only requires 33% of current maintainers.
+Only maintainers of the repository that the candidate is proposed for are
+allowed to vote.
+
+If a candidate is approved, a maintainer will contact the candidate to invite
+the candidate to open a pull request that adds the contributor to the
+MAINTAINERS file. The voting process may take place inside a pull request if a
+maintainer has already discussed the candidacy with the candidate and a
+maintainer is willing to be a sponsor by opening the pull request. The candidate
+becomes a maintainer once the pull request is merged.
+
+## Stepping down policy
+
+Life priorities, interests, and passions can change. If you're a maintainer but
+feel you must remove yourself from the list, inform other maintainers that you
+intend to step down, and if possible, help find someone to pick up your work.
+At the very least, ensure your work can be continued where you left off.
+
+After you've informed other maintainers, create a pull request to remove
+yourself from the MAINTAINERS file.
+
+## Removal of inactive maintainers
+
+Similar to the procedure for adding new maintainers, existing maintainers can
+be removed from the list if they do not show significant activity on the
+project. Periodically, the maintainers review the list of maintainers and their
+activity over the last three months.
+
+If a maintainer has shown insufficient activity over this period, a neutral
+person will contact the maintainer to ask if they want to continue being
+a maintainer. If the maintainer decides to step down as a maintainer, they
+open a pull request to be removed from the MAINTAINERS file.
+
+If the maintainer wants to remain a maintainer, but is unable to perform the
+required duties they can be removed with a vote of at least 66% of the current
+maintainers. In this case, maintainers should first propose the change to
+maintainers via the maintainers communication channel, then open a pull request
+for voting. The voting period is five business days. The voting pull request
+should not come as a surpise to any maintainer and any discussion related to
+performance must not be discussed on the pull request.
+
+## How are decisions made?
+
+Docker distribution is an open-source project with an open design philosophy.
+This means that the repository is the source of truth for EVERY aspect of the
+project, including its philosophy, design, road map, and APIs. *If it's part of
+the project, it's in the repo. If it's in the repo, it's part of the project.*
+
+As a result, all decisions can be expressed as changes to the repository. An
+implementation change is a change to the source code. An API change is a change
+to the API specification. A philosophy change is a change to the philosophy
+manifesto, and so on.
+
+All decisions affecting distribution, big and small, follow the same 3 steps:
+
+* Step 1: Open a pull request. Anyone can do this.
+
+* Step 2: Discuss the pull request. Anyone can do this.
+
+* Step 3: Merge or refuse the pull request. Who does this depends on the nature
+of the pull request and which areas of the project it affects.
+
+## Helping contributors with the DCO
+
+The [DCO or `Sign your work`](./CONTRIBUTING.md#sign-your-work)
+requirement is not intended as a roadblock or speed bump.
+
+Some contributors are not as familiar with `git`, or have used a web
+based editor, and thus asking them to `git commit --amend -s` is not the best
+way forward.
+
+In this case, maintainers can update the commits based on clause (c) of the DCO.
+The most trivial way for a contributor to allow the maintainer to do this, is to
+add a DCO signature in a pull requests's comment, or a maintainer can simply
+note that the change is sufficiently trivial that it does not substantially
+change the existing contribution - i.e., a spelling change.
+
+When you add someone's DCO, please also add your own to keep a log.
+
+## I'm a maintainer. Should I make pull requests too?
+
+Yes. Nobody should ever push to master directly. All changes should be
+made through a pull request.
+
+## Conflict Resolution
+
+If you have a technical dispute that you feel has reached an impasse with a
+subset of the community, any contributor may open an issue, specifically
+calling for a resolution vote of the current core maintainers to resolve the
+dispute. The same voting quorums required (2/3) for adding and removing
+maintainers will apply to conflict resolution.
diff --git a/vendor/github.com/distribution/reference/LICENSE b/vendor/github.com/distribution/reference/LICENSE
new file mode 100644
index 000000000..e06d20818
--- /dev/null
+++ b/vendor/github.com/distribution/reference/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   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.
+
diff --git a/vendor/github.com/distribution/reference/MAINTAINERS b/vendor/github.com/distribution/reference/MAINTAINERS
new file mode 100644
index 000000000..9e0a60c8b
--- /dev/null
+++ b/vendor/github.com/distribution/reference/MAINTAINERS
@@ -0,0 +1,26 @@
+# Distribution project maintainers & reviewers
+#
+# See GOVERNANCE.md for maintainer versus reviewer roles
+#
+# MAINTAINERS (cncf-distribution-maintainers@lists.cncf.io)
+# GitHub ID, Name, Email address
+"chrispat","Chris Patterson","chrispat@github.com"
+"clarkbw","Bryan Clark","clarkbw@github.com"
+"corhere","Cory Snider","csnider@mirantis.com"
+"deleteriousEffect","Hayley Swimelar","hswimelar@gitlab.com"
+"heww","He Weiwei","hweiwei@vmware.com"
+"joaodrp","João Pereira","jpereira@gitlab.com"
+"justincormack","Justin Cormack","justin.cormack@docker.com"
+"squizzi","Kyle Squizzato","ksquizzato@mirantis.com"
+"milosgajdos","Milos Gajdos","milosthegajdos@gmail.com"
+"sargun","Sargun Dhillon","sargun@sargun.me"
+"wy65701436","Wang Yan","wangyan@vmware.com"
+"stevelasker","Steve Lasker","steve.lasker@microsoft.com"
+#
+# REVIEWERS
+# GitHub ID, Name, Email address
+"dmcgowan","Derek McGowan","derek@mcgstyle.net"
+"stevvooe","Stephen Day","stevvooe@gmail.com"
+"thajeztah","Sebastiaan van Stijn","github@gone.nl"
+"DavidSpek", "David van der Spek", "vanderspek.david@gmail.com"
+"Jamstah", "James Hewitt", "james.hewitt@gmail.com"
diff --git a/vendor/github.com/distribution/reference/Makefile b/vendor/github.com/distribution/reference/Makefile
new file mode 100644
index 000000000..c78576b75
--- /dev/null
+++ b/vendor/github.com/distribution/reference/Makefile
@@ -0,0 +1,25 @@
+# Project packages.
+PACKAGES=$(shell go list ./...)
+
+# Flags passed to `go test`
+BUILDFLAGS ?= 
+TESTFLAGS ?= 
+
+.PHONY: all build test coverage
+.DEFAULT: all
+
+all: build
+
+build: ## no binaries to build, so just check compilation suceeds
+	go build ${BUILDFLAGS} ./...
+
+test: ## run tests
+	go test ${TESTFLAGS} ./...
+
+coverage: ## generate coverprofiles from the unit tests
+	rm -f coverage.txt
+	go test ${TESTFLAGS} -cover -coverprofile=cover.out ./...
+
+.PHONY: help
+help:
+	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m\033[0m\n"} /^[a-zA-Z_\/%-]+:.*?##/ { printf "  \033[36m%-27s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
diff --git a/vendor/github.com/distribution/reference/README.md b/vendor/github.com/distribution/reference/README.md
new file mode 100644
index 000000000..172a02e0b
--- /dev/null
+++ b/vendor/github.com/distribution/reference/README.md
@@ -0,0 +1,30 @@
+# Distribution reference
+
+Go library to handle references to container images.
+
+<img src="/distribution-logo.svg" width="200px" />
+
+[![Build Status](https://github.com/distribution/reference/actions/workflows/test.yml/badge.svg?branch=main&event=push)](https://github.com/distribution/reference/actions?query=workflow%3ACI)
+[![GoDoc](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/distribution/reference)
+[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
+[![codecov](https://codecov.io/gh/distribution/reference/branch/main/graph/badge.svg)](https://codecov.io/gh/distribution/reference)
+[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Freference.svg?type=shield)](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Freference?ref=badge_shield)
+
+This repository contains a library for handling references to container images held in container registries. Please see [godoc](https://pkg.go.dev/github.com/distribution/reference) for details.
+
+## Contribution
+
+Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute
+issues, fixes, and patches to this project.
+
+## Communication
+
+For async communication and long running discussions please use issues and pull requests on the github repo.
+This will be the best place to discuss design and implementation.
+
+For sync communication we have a #distribution channel in the [CNCF Slack](https://slack.cncf.io/)
+that everyone is welcome to join and chat about development.
+
+## Licenses
+
+The distribution codebase is released under the [Apache 2.0 license](LICENSE).
diff --git a/vendor/github.com/distribution/reference/SECURITY.md b/vendor/github.com/distribution/reference/SECURITY.md
new file mode 100644
index 000000000..aaf983c0f
--- /dev/null
+++ b/vendor/github.com/distribution/reference/SECURITY.md
@@ -0,0 +1,7 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+The maintainers take security seriously. If you discover a security issue, please bring it to their attention right away!
+
+Please DO NOT file a public issue, instead send your report privately to cncf-distribution-security@lists.cncf.io.
diff --git a/vendor/github.com/distribution/reference/distribution-logo.svg b/vendor/github.com/distribution/reference/distribution-logo.svg
new file mode 100644
index 000000000..cc9f4073b
--- /dev/null
+++ b/vendor/github.com/distribution/reference/distribution-logo.svg
@@ -0,0 +1 @@
+<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 564.27793 654.82002"><defs><style>.cls-1{fill:#416ba9;}.cls-2{fill:#74c3d5;}</style></defs><path class="cls-1" d="M17.48582,567.55941c0-3.66375,2.2168-4.91716,4.91609-4.91716H36.66877c18.70153,0,28.24476,9.06127,28.24476,33.64387,0,22.26771-7.51889,35.57065-27.95526,35.57065H22.40191c-2.69929,0-4.91609-1.25341-4.91609-4.91609Zm20.33987,49.741c7.61539,0,10.60365-6.94043,10.60365-20.72586,0-15.13429-3.85568-19.376-10.70015-19.376H33.97v40.10182Z"/><path class="cls-1" d="M72.43613,567.55941c0-3.66375,2.21681-4.91716,4.9161-4.91716h6.36251c2.69876,0,4.91609,1.25341,4.91609,4.91716v59.38127c0,3.66268-2.21733,4.91609-4.91609,4.91609H77.35223c-2.69929,0-4.9161-1.25341-4.9161-4.91609Z"/><path class="cls-1" d="M99.718,613.05875l5.78405-1.06042c4.33764-.77092,4.53063,1.15692,5.78352,3.85674a6.70953,6.70953,0,0,0,6.5555,3.95218c3.56672,0,6.26548-1.83134,6.26548-5.59158,0-12.82046-27.6663-11.08561-27.6663-34.31724,0-10.79718,7.80839-18.1236,20.43637-18.1236,11.08614,0,16.96615,4.8196,20.05091,12.918.96445,2.31277,1.44641,4.7231-2.98826,5.59052l-5.20559,1.06042c-3.95218.77092-4.33764-1.06042-6.073-3.66269a6.39679,6.39679,0,0,0-5.49456-3.08475c-3.18125,0-5.20559,1.83134-5.20559,4.7231,0,12.24252,27.56981,10.60418,27.56981,33.73931,0,12.532-8.77231,19.66545-22.36422,19.66545-11.47159,0-17.93007-4.43467-20.82236-14.07387C95.57286,616.24,95.1874,613.92617,99.718,613.05875Z"/><path class="cls-1" d="M154.86187,576.62068h-8.09735c-3.66321,0-4.91662-2.21734-4.91662-4.91716v-4.14411c0-2.69983,1.25341-4.91716,4.91662-4.91716H179.058c3.66321,0,4.91609,2.21733,4.91609,4.91716v4.14411c0,2.69982-1.25288,4.91716-4.91609,4.91716h-8.09788v50.32c0,3.66268-2.21681,4.91609-4.9161,4.91609h-6.266c-2.69876,0-4.9161-1.25341-4.9161-4.91609Z"/><path class="cls-1" d="M189.76022,567.55941c0-3.66375,2.21681-4.91716,4.9161-4.91716h16.2912c15.13481,0,23.03969,5.68808,23.03969,20.05144,0,8.38684-3.27775,13.68787-8.29034,16.77369l9.35076,27.76173c1.34938,4.04974-.96445,4.62766-3.37425,4.62766h-8.67581c-2.89176,0-4.53063-1.92783-5.30208-4.7231L211.546,605.92532h-5.68755v21.01536c0,3.66268-2.2168,4.91609-4.91609,4.91609h-6.266c-2.69929,0-4.9161-1.25341-4.9161-4.91609Zm20.14688,25.35246c4.14517,0,7.61592-1.6394,7.61592-8.57984,0-7.61486-3.37425-8.19384-7.22993-8.19384h-4.43467v16.77368Z"/><path class="cls-1" d="M241.91422,567.55941c0-3.66375,2.2168-4.91716,4.91609-4.91716h6.36251c2.69876,0,4.9161,1.25341,4.9161,4.91716v59.38127c0,3.66268-2.21734,4.91609-4.9161,4.91609h-6.36251c-2.69929,0-4.91609-1.25341-4.91609-4.91609Z"/><path class="cls-1" d="M267.75024,567.55941c0-3.66375,2.2168-4.91716,4.91609-4.91716h14.94182c16.77316,0,24.09958,5.49508,24.09958,18.31659,0,6.94044-3.08475,11.953-8.96477,14.5553v.193c6.74744,2.31384,10.41065,7.13343,10.41065,15.80977,0,16.58069-11.3751,20.33987-25.449,20.33987H272.66633c-2.69929,0-4.91609-1.25341-4.91609-4.91609Zm20.72533,22.5572c4.33817,0,6.84447-2.12083,6.84447-7.32642,0-4.91716-2.79579-6.36251-6.84447-6.36251h-4.9161v13.68893Zm.386,27.95473c5.88,0,7.90436-2.40926,7.90436-7.80785,0-5.88-3.18126-7.80786-7.80839-7.80786h-5.39806v15.61571Z"/><path class="cls-1" d="M320.09776,567.55941c0-3.66375,2.21733-4.91716,4.91662-4.91716h6.362c2.69929,0,4.91663,1.25341,4.91663,4.91716v43.282c0,5.78457,2.3133,8.38684,6.748,8.38684,4.43413,0,7.13343-2.60227,7.13343-8.38684v-43.282c0-3.66375,2.21733-4.91716,4.91609-4.91716H361.26c2.6993,0,4.91663,1.25341,4.91663,4.91716v41.06573c0,15.80871-7.13343,24.00256-23.42516,24.00256-16.0982,0-22.6537-8.19385-22.6537-24.00256Z"/><path class="cls-1" d="M384.59236,576.62068H376.495c-3.66322,0-4.91663-2.21734-4.91663-4.91716v-4.14411c0-2.69983,1.25341-4.91716,4.91663-4.91716h32.29343c3.66321,0,4.91609,2.21733,4.91609,4.91716v4.14411c0,2.69982-1.25288,4.91716-4.91609,4.91716H400.6911v50.32c0,3.66268-2.21734,4.91609-4.91663,4.91609h-6.266c-2.69929,0-4.9161-1.25341-4.9161-4.91609Z"/><path class="cls-1" d="M419.49071,567.55941c0-3.66375,2.21681-4.91716,4.9161-4.91716h6.36251c2.69876,0,4.91609,1.25341,4.91609,4.91716v59.38127c0,3.66268-2.21733,4.91609-4.91609,4.91609h-6.36251c-2.69929,0-4.9161-1.25341-4.9161-4.91609Z"/><path class="cls-1" d="M443.20536,597.34654c0-21.30485,5.59106-35.57171,24.48505-35.57171s24.48505,14.26686,24.48505,35.57171c0,22.07472-6.84394,35.37766-24.485,35.37766S443.20536,619.42126,443.20536,597.34654Zm32.48643,0c0-16.29226-2.12083-22.26877-8.00138-22.26877-5.88,0-8.00085,5.97651-8.00085,22.26877,0,17.06212,2.4098,22.17121,8.00085,22.17121C473.378,619.51775,475.69179,614.40866,475.69179,597.34654Z"/><path class="cls-1" d="M499.69859,567.55941c0-3.66375,2.2168-4.91716,4.9161-4.91716h6.941a7.56728,7.56728,0,0,1,6.84394,4.43467l13.207,29.88363h.19247V567.55941c0-3.66375,2.21733-4.91716,4.91662-4.91716h4.62714c2.69876,0,4.91609,1.25341,4.91609,4.91716v59.38127c0,3.66268-2.21733,4.91609-4.91609,4.91609h-5.68756c-2.98878,0-4.72363-1.83134-5.977-4.43466L514.15792,593.5863h-.19247v33.35438c0,3.66268-2.21733,4.91609-4.91663,4.91609h-4.43413c-2.6993,0-4.9161-1.25341-4.9161-4.91609Z"/><g id="F1L4Xu"><path class="cls-2" d="M461.28162,365.26377c14.626-14.99573,31.51073-27.88581,43.901-45.3001,23.6055-33.17709,21.5881-53.98611-9.08528-79.89549-5.54727-4.68571-8.18237-7.96252-5.187-15.251,2.57641-6.26934,3.76528-13.21711,4.83156-19.981,5.90314-37.44659-11.00082-60.70078-48.64828-63.33267-13.137-.91842-16.45015-5.43062-19.21754-16.935-9.30387-38.67663-34.59038-53.67167-74.13662-44.585-10.18443,2.3401-17.05741,2.2529-24.8593-6.77926-30.175-34.93317-59.58084-35.22646-91.95222-.348-9.64337,10.39025-15.6225,11.83918-28.62783,5.4055-32.90341-16.27713-59.8387-3.10046-69.78437,35.47712-4.6848,18.17164-11.36854,26.3489-30.24471,30.1582-31.33028,6.32259-44.78933,33.5759-35.57532,69.531,3.76252,14.68215,4.6826,23.43655-10.28992,33.26423-22.74913,14.93216-25.22052,35.33713-11.0953,59.39875a163.06863,163.06863,0,0,0,18.46085,24.68707c6.40258,7.28037,13.94521,13.55817,19.80434,21.482C65.25053,338.04809,43.116,321.28746,27.8598,297.29993c-17.05057-26.80876-13.40609-48.15088,13.33187-65.26212,13.64688-8.73344,14.87507-15.92347,10.65871-30.93464-12.7269-45.31048,5.12054-71.29348,52.09339-78.34017,9.12234-1.36851,13.24368-4.37134,14.93358-13.09156a120.37358,120.37358,0,0,1,6.91928-23.66458C140.26672,51.59355,166.89048,40.64934,200.93587,56.76c12.995,6.14933,20.16447,5.77862,30.68022-5.2998C268.21035,12.90788,301.23887,13.957,336.089,53.95609c7.03437,8.07364,13.32723,7.58749,21.51782,5.54845,49.26567-12.26462,82.34232,9.66738,86.80352,52.02378.85563,8.12375,4.89151,12.49189,13.59822,11.06745a9.08058,9.08058,0,0,1,2.06083.01162c48.42775,3.32745,67.90447,29.37216,55.65225,76.28488-3.68675,14.11627-5.266,23.35647,9.83168,33.3918,24.025,15.96919,26.43605,40.908,10.89058,67.22194C523.519,321.384,492.3391,349.49056,461.28162,365.26377Z"/><path class="cls-2" d="M222.21166,412.15994c-43.3335,8.71069-88.628,7.98395-130.77907,28.38523,94.59324,34.57588,265.86321,39.32494,381.28659.87883-20.80256-13.03877-43.25235-15.46757-64.96771-19.52875-21.46582-4.01455-43.21049-6.53754-65.22855-9.773,2.32155-9.0906,5.71941-13.26155,14.6818-11.53506,34.9755,6.73747,70.6065,10.43856,104.30053,22.96341,8.18218,3.04152,18.89124,4.40911,19.86455,15.15614,1.09622,12.10448-6.10692,24.09739-16.79915,25.67409-30.25013,4.46064-56.38559,26.36212-84.9133,26.506-28.47048.14371-52.82989-.52977-79.492,14.17476-20.18156,11.13047-46.332,2.83194-64.16335-15.45408-6.83775-7.01216-11.13794-6.37864-19.02114-2.85829-23.91278,10.67842-47.24546,8.5124-67.31614-8.79886-7.10279-6.12627-13.27536-7.629-22.06165-6.68907a44.08867,44.08867,0,0,1-27.74743-5.86122C89.8179,459.38315,82.0507,451.437,82.898,439.18832c.77048-11.13889,11.49627-12.35089,19.55689-15.40536,33.62848-12.74306,69.18754-16.82889,104.26785-23.14551C215.75685,399.01074,219.15407,403.38339,222.21166,412.15994Z"/></g><rect class="cls-1" x="157.9184" y="278.28554" width="63.75238" height="63.75238"/><rect class="cls-1" x="241.008" y="278.28554" width="63.75238" height="63.75238"/><rect class="cls-1" x="157.9184" y="361.37514" width="63.75238" height="63.75238"/><rect class="cls-1" x="367.09657" y="153.06724" width="63.75176" height="63.75177" transform="translate(-13.91822 336.28471) rotate(-45)"/><polygon class="cls-1" points="239.799 221.785 239.799 222.389 296.3 250.79 325.004 193.987 268.201 165.284 239.799 221.785"/><rect class="cls-1" x="341.49858" y="264.8759" width="63.75384" height="63.75383" transform="translate(-59.8512 496.2174) rotate(-63.19922)"/><rect class="cls-1" x="157.9184" y="195.19594" width="63.75238" height="63.75238"/><rect class="cls-1" x="241.008" y="361.37514" width="63.75238" height="63.75238"/><rect class="cls-1" x="324.39973" y="361.37514" width="63.75238" height="63.75238"/></svg>
\ No newline at end of file
diff --git a/vendor/github.com/distribution/reference/helpers.go b/vendor/github.com/distribution/reference/helpers.go
new file mode 100644
index 000000000..d10c7ef83
--- /dev/null
+++ b/vendor/github.com/distribution/reference/helpers.go
@@ -0,0 +1,42 @@
+package reference
+
+import "path"
+
+// IsNameOnly returns true if reference only contains a repo name.
+func IsNameOnly(ref Named) bool {
+	if _, ok := ref.(NamedTagged); ok {
+		return false
+	}
+	if _, ok := ref.(Canonical); ok {
+		return false
+	}
+	return true
+}
+
+// FamiliarName returns the familiar name string
+// for the given named, familiarizing if needed.
+func FamiliarName(ref Named) string {
+	if nn, ok := ref.(normalizedNamed); ok {
+		return nn.Familiar().Name()
+	}
+	return ref.Name()
+}
+
+// FamiliarString returns the familiar string representation
+// for the given reference, familiarizing if needed.
+func FamiliarString(ref Reference) string {
+	if nn, ok := ref.(normalizedNamed); ok {
+		return nn.Familiar().String()
+	}
+	return ref.String()
+}
+
+// FamiliarMatch reports whether ref matches the specified pattern.
+// See [path.Match] for supported patterns.
+func FamiliarMatch(pattern string, ref Reference) (bool, error) {
+	matched, err := path.Match(pattern, FamiliarString(ref))
+	if namedRef, isNamed := ref.(Named); isNamed && !matched {
+		matched, _ = path.Match(pattern, FamiliarName(namedRef))
+	}
+	return matched, err
+}
diff --git a/vendor/github.com/distribution/reference/normalize.go b/vendor/github.com/distribution/reference/normalize.go
new file mode 100644
index 000000000..f4128314c
--- /dev/null
+++ b/vendor/github.com/distribution/reference/normalize.go
@@ -0,0 +1,255 @@
+package reference
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/opencontainers/go-digest"
+)
+
+const (
+	// legacyDefaultDomain is the legacy domain for Docker Hub (which was
+	// originally named "the Docker Index"). This domain is still used for
+	// authentication and image search, which were part of the "v1" Docker
+	// registry specification.
+	//
+	// This domain will continue to be supported, but there are plans to consolidate
+	// legacy domains to new "canonical" domains. Once those domains are decided
+	// on, we must update the normalization functions, but preserve compatibility
+	// with existing installs, clients, and user configuration.
+	legacyDefaultDomain = "index.docker.io"
+
+	// defaultDomain is the default domain used for images on Docker Hub.
+	// It is used to normalize "familiar" names to canonical names, for example,
+	// to convert "ubuntu" to "docker.io/library/ubuntu:latest".
+	//
+	// Note that actual domain of Docker Hub's registry is registry-1.docker.io.
+	// This domain will continue to be supported, but there are plans to consolidate
+	// legacy domains to new "canonical" domains. Once those domains are decided
+	// on, we must update the normalization functions, but preserve compatibility
+	// with existing installs, clients, and user configuration.
+	defaultDomain = "docker.io"
+
+	// officialRepoPrefix is the namespace used for official images on Docker Hub.
+	// It is used to normalize "familiar" names to canonical names, for example,
+	// to convert "ubuntu" to "docker.io/library/ubuntu:latest".
+	officialRepoPrefix = "library/"
+
+	// defaultTag is the default tag if no tag is provided.
+	defaultTag = "latest"
+)
+
+// normalizedNamed represents a name which has been
+// normalized and has a familiar form. A familiar name
+// is what is used in Docker UI. An example normalized
+// name is "docker.io/library/ubuntu" and corresponding
+// familiar name of "ubuntu".
+type normalizedNamed interface {
+	Named
+	Familiar() Named
+}
+
+// ParseNormalizedNamed parses a string into a named reference
+// transforming a familiar name from Docker UI to a fully
+// qualified reference. If the value may be an identifier
+// use ParseAnyReference.
+func ParseNormalizedNamed(s string) (Named, error) {
+	if ok := anchoredIdentifierRegexp.MatchString(s); ok {
+		return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
+	}
+	domain, remainder := splitDockerDomain(s)
+	var remote string
+	if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 {
+		remote = remainder[:tagSep]
+	} else {
+		remote = remainder
+	}
+	if strings.ToLower(remote) != remote {
+		return nil, fmt.Errorf("invalid reference format: repository name (%s) must be lowercase", remote)
+	}
+
+	ref, err := Parse(domain + "/" + remainder)
+	if err != nil {
+		return nil, err
+	}
+	named, isNamed := ref.(Named)
+	if !isNamed {
+		return nil, fmt.Errorf("reference %s has no name", ref.String())
+	}
+	return named, nil
+}
+
+// namedTaggedDigested is a reference that has both a tag and a digest.
+type namedTaggedDigested interface {
+	NamedTagged
+	Digested
+}
+
+// ParseDockerRef normalizes the image reference following the docker convention,
+// which allows for references to contain both a tag and a digest. It returns a
+// reference that is either tagged or digested. For references containing both
+// a tag and a digest, it returns a digested reference. For example, the following
+// reference:
+//
+//	docker.io/library/busybox:latest@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa
+//
+// Is returned as a digested reference (with the ":latest" tag removed):
+//
+//	docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa
+//
+// References that are already "tagged" or "digested" are returned unmodified:
+//
+//	// Already a digested reference
+//	docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa
+//
+//	// Already a named reference
+//	docker.io/library/busybox:latest
+func ParseDockerRef(ref string) (Named, error) {
+	named, err := ParseNormalizedNamed(ref)
+	if err != nil {
+		return nil, err
+	}
+	if canonical, ok := named.(namedTaggedDigested); ok {
+		// The reference is both tagged and digested; only return digested.
+		newNamed, err := WithName(canonical.Name())
+		if err != nil {
+			return nil, err
+		}
+		return WithDigest(newNamed, canonical.Digest())
+	}
+	return TagNameOnly(named), nil
+}
+
+// splitDockerDomain splits a repository name to domain and remote-name.
+// If no valid domain is found, the default domain is used. Repository name
+// needs to be already validated before.
+func splitDockerDomain(name string) (domain, remoteName string) {
+	maybeDomain, maybeRemoteName, ok := strings.Cut(name, "/")
+	if !ok {
+		// Fast-path for single element ("familiar" names), such as "ubuntu"
+		// or "ubuntu:latest". Familiar names must be handled separately, to
+		// prevent them from being handled as "hostname:port".
+		//
+		// Canonicalize them as "docker.io/library/name[:tag]"
+
+		// FIXME(thaJeztah): account for bare "localhost" or "example.com" names, which SHOULD be considered a domain.
+		return defaultDomain, officialRepoPrefix + name
+	}
+
+	switch {
+	case maybeDomain == localhost:
+		// localhost is a reserved namespace and always considered a domain.
+		domain, remoteName = maybeDomain, maybeRemoteName
+	case maybeDomain == legacyDefaultDomain:
+		// canonicalize the Docker Hub and legacy "Docker Index" domains.
+		domain, remoteName = defaultDomain, maybeRemoteName
+	case strings.ContainsAny(maybeDomain, ".:"):
+		// Likely a domain or IP-address:
+		//
+		// - contains a "." (e.g., "example.com" or "127.0.0.1")
+		// - contains a ":" (e.g., "example:5000", "::1", or "[::1]:5000")
+		domain, remoteName = maybeDomain, maybeRemoteName
+	case strings.ToLower(maybeDomain) != maybeDomain:
+		// Uppercase namespaces are not allowed, so if the first element
+		// is not lowercase, we assume it to be a domain-name.
+		domain, remoteName = maybeDomain, maybeRemoteName
+	default:
+		// None of the above: it's not a domain, so use the default, and
+		// use the name input the remote-name.
+		domain, remoteName = defaultDomain, name
+	}
+
+	if domain == defaultDomain && !strings.ContainsRune(remoteName, '/') {
+		// Canonicalize "familiar" names, but only on Docker Hub, not
+		// on other domains:
+		//
+		// "docker.io/ubuntu[:tag]" => "docker.io/library/ubuntu[:tag]"
+		remoteName = officialRepoPrefix + remoteName
+	}
+
+	return domain, remoteName
+}
+
+// familiarizeName returns a shortened version of the name familiar
+// to the Docker UI. Familiar names have the default domain
+// "docker.io" and "library/" repository prefix removed.
+// For example, "docker.io/library/redis" will have the familiar
+// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp".
+// Returns a familiarized named only reference.
+func familiarizeName(named namedRepository) repository {
+	repo := repository{
+		domain: named.Domain(),
+		path:   named.Path(),
+	}
+
+	if repo.domain == defaultDomain {
+		repo.domain = ""
+		// Handle official repositories which have the pattern "library/<official repo name>"
+		if strings.HasPrefix(repo.path, officialRepoPrefix) {
+			// TODO(thaJeztah): this check may be too strict, as it assumes the
+			//  "library/" namespace does not have nested namespaces. While this
+			//  is true (currently), technically it would be possible for Docker
+			//  Hub to use those (e.g. "library/distros/ubuntu:latest").
+			//  See https://github.com/distribution/distribution/pull/3769#issuecomment-1302031785.
+			if remainder := strings.TrimPrefix(repo.path, officialRepoPrefix); !strings.ContainsRune(remainder, '/') {
+				repo.path = remainder
+			}
+		}
+	}
+	return repo
+}
+
+func (r reference) Familiar() Named {
+	return reference{
+		namedRepository: familiarizeName(r.namedRepository),
+		tag:             r.tag,
+		digest:          r.digest,
+	}
+}
+
+func (r repository) Familiar() Named {
+	return familiarizeName(r)
+}
+
+func (t taggedReference) Familiar() Named {
+	return taggedReference{
+		namedRepository: familiarizeName(t.namedRepository),
+		tag:             t.tag,
+	}
+}
+
+func (c canonicalReference) Familiar() Named {
+	return canonicalReference{
+		namedRepository: familiarizeName(c.namedRepository),
+		digest:          c.digest,
+	}
+}
+
+// TagNameOnly adds the default tag "latest" to a reference if it only has
+// a repo name.
+func TagNameOnly(ref Named) Named {
+	if IsNameOnly(ref) {
+		namedTagged, err := WithTag(ref, defaultTag)
+		if err != nil {
+			// Default tag must be valid, to create a NamedTagged
+			// type with non-validated input the WithTag function
+			// should be used instead
+			panic(err)
+		}
+		return namedTagged
+	}
+	return ref
+}
+
+// ParseAnyReference parses a reference string as a possible identifier,
+// full digest, or familiar name.
+func ParseAnyReference(ref string) (Reference, error) {
+	if ok := anchoredIdentifierRegexp.MatchString(ref); ok {
+		return digestReference("sha256:" + ref), nil
+	}
+	if dgst, err := digest.Parse(ref); err == nil {
+		return digestReference(dgst), nil
+	}
+
+	return ParseNormalizedNamed(ref)
+}
diff --git a/vendor/github.com/distribution/reference/reference.go b/vendor/github.com/distribution/reference/reference.go
new file mode 100644
index 000000000..900398bde
--- /dev/null
+++ b/vendor/github.com/distribution/reference/reference.go
@@ -0,0 +1,432 @@
+// Package reference provides a general type to represent any way of referencing images within the registry.
+// Its main purpose is to abstract tags and digests (content-addressable hash).
+//
+// Grammar
+//
+//	reference                       := name [ ":" tag ] [ "@" digest ]
+//	name                            := [domain '/'] remote-name
+//	domain                          := host [':' port-number]
+//	host                            := domain-name | IPv4address | \[ IPv6address \]	; rfc3986 appendix-A
+//	domain-name                     := domain-component ['.' domain-component]*
+//	domain-component                := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
+//	port-number                     := /[0-9]+/
+//	path-component                  := alpha-numeric [separator alpha-numeric]*
+//	path (or "remote-name")         := path-component ['/' path-component]*
+//	alpha-numeric                   := /[a-z0-9]+/
+//	separator                       := /[_.]|__|[-]*/
+//
+//	tag                             := /[\w][\w.-]{0,127}/
+//
+//	digest                          := digest-algorithm ":" digest-hex
+//	digest-algorithm                := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]*
+//	digest-algorithm-separator      := /[+.-_]/
+//	digest-algorithm-component      := /[A-Za-z][A-Za-z0-9]*/
+//	digest-hex                      := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
+//
+//	identifier                      := /[a-f0-9]{64}/
+package reference
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/opencontainers/go-digest"
+)
+
+const (
+	// RepositoryNameTotalLengthMax is the maximum total number of characters in a repository name.
+	RepositoryNameTotalLengthMax = 255
+
+	// NameTotalLengthMax is the maximum total number of characters in a repository name.
+	//
+	// Deprecated: use [RepositoryNameTotalLengthMax] instead.
+	NameTotalLengthMax = RepositoryNameTotalLengthMax
+)
+
+var (
+	// ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference.
+	ErrReferenceInvalidFormat = errors.New("invalid reference format")
+
+	// ErrTagInvalidFormat represents an error while trying to parse a string as a tag.
+	ErrTagInvalidFormat = errors.New("invalid tag format")
+
+	// ErrDigestInvalidFormat represents an error while trying to parse a string as a tag.
+	ErrDigestInvalidFormat = errors.New("invalid digest format")
+
+	// ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters.
+	ErrNameContainsUppercase = errors.New("repository name must be lowercase")
+
+	// ErrNameEmpty is returned for empty, invalid repository names.
+	ErrNameEmpty = errors.New("repository name must have at least one component")
+
+	// ErrNameTooLong is returned when a repository name is longer than RepositoryNameTotalLengthMax.
+	ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", RepositoryNameTotalLengthMax)
+
+	// ErrNameNotCanonical is returned when a name is not canonical.
+	ErrNameNotCanonical = errors.New("repository name must be canonical")
+)
+
+// Reference is an opaque object reference identifier that may include
+// modifiers such as a hostname, name, tag, and digest.
+type Reference interface {
+	// String returns the full reference
+	String() string
+}
+
+// Field provides a wrapper type for resolving correct reference types when
+// working with encoding.
+type Field struct {
+	reference Reference
+}
+
+// AsField wraps a reference in a Field for encoding.
+func AsField(reference Reference) Field {
+	return Field{reference}
+}
+
+// Reference unwraps the reference type from the field to
+// return the Reference object. This object should be
+// of the appropriate type to further check for different
+// reference types.
+func (f Field) Reference() Reference {
+	return f.reference
+}
+
+// MarshalText serializes the field to byte text which
+// is the string of the reference.
+func (f Field) MarshalText() (p []byte, err error) {
+	return []byte(f.reference.String()), nil
+}
+
+// UnmarshalText parses text bytes by invoking the
+// reference parser to ensure the appropriately
+// typed reference object is wrapped by field.
+func (f *Field) UnmarshalText(p []byte) error {
+	r, err := Parse(string(p))
+	if err != nil {
+		return err
+	}
+
+	f.reference = r
+	return nil
+}
+
+// Named is an object with a full name
+type Named interface {
+	Reference
+	Name() string
+}
+
+// Tagged is an object which has a tag
+type Tagged interface {
+	Reference
+	Tag() string
+}
+
+// NamedTagged is an object including a name and tag.
+type NamedTagged interface {
+	Named
+	Tag() string
+}
+
+// Digested is an object which has a digest
+// in which it can be referenced by
+type Digested interface {
+	Reference
+	Digest() digest.Digest
+}
+
+// Canonical reference is an object with a fully unique
+// name including a name with domain and digest
+type Canonical interface {
+	Named
+	Digest() digest.Digest
+}
+
+// namedRepository is a reference to a repository with a name.
+// A namedRepository has both domain and path components.
+type namedRepository interface {
+	Named
+	Domain() string
+	Path() string
+}
+
+// Domain returns the domain part of the [Named] reference.
+func Domain(named Named) string {
+	if r, ok := named.(namedRepository); ok {
+		return r.Domain()
+	}
+	domain, _ := splitDomain(named.Name())
+	return domain
+}
+
+// Path returns the name without the domain part of the [Named] reference.
+func Path(named Named) (name string) {
+	if r, ok := named.(namedRepository); ok {
+		return r.Path()
+	}
+	_, path := splitDomain(named.Name())
+	return path
+}
+
+// splitDomain splits a named reference into a hostname and path string.
+// If no valid hostname is found, the hostname is empty and the full value
+// is returned as name
+func splitDomain(name string) (string, string) {
+	match := anchoredNameRegexp.FindStringSubmatch(name)
+	if len(match) != 3 {
+		return "", name
+	}
+	return match[1], match[2]
+}
+
+// Parse parses s and returns a syntactically valid Reference.
+// If an error was encountered it is returned, along with a nil Reference.
+func Parse(s string) (Reference, error) {
+	matches := ReferenceRegexp.FindStringSubmatch(s)
+	if matches == nil {
+		if s == "" {
+			return nil, ErrNameEmpty
+		}
+		if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil {
+			return nil, ErrNameContainsUppercase
+		}
+		return nil, ErrReferenceInvalidFormat
+	}
+
+	var repo repository
+
+	nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1])
+	if len(nameMatch) == 3 {
+		repo.domain = nameMatch[1]
+		repo.path = nameMatch[2]
+	} else {
+		repo.domain = ""
+		repo.path = matches[1]
+	}
+
+	if len(repo.path) > RepositoryNameTotalLengthMax {
+		return nil, ErrNameTooLong
+	}
+
+	ref := reference{
+		namedRepository: repo,
+		tag:             matches[2],
+	}
+	if matches[3] != "" {
+		var err error
+		ref.digest, err = digest.Parse(matches[3])
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	r := getBestReferenceType(ref)
+	if r == nil {
+		return nil, ErrNameEmpty
+	}
+
+	return r, nil
+}
+
+// ParseNamed parses s and returns a syntactically valid reference implementing
+// the Named interface. The reference must have a name and be in the canonical
+// form, otherwise an error is returned.
+// If an error was encountered it is returned, along with a nil Reference.
+func ParseNamed(s string) (Named, error) {
+	named, err := ParseNormalizedNamed(s)
+	if err != nil {
+		return nil, err
+	}
+	if named.String() != s {
+		return nil, ErrNameNotCanonical
+	}
+	return named, nil
+}
+
+// WithName returns a named object representing the given string. If the input
+// is invalid ErrReferenceInvalidFormat will be returned.
+func WithName(name string) (Named, error) {
+	match := anchoredNameRegexp.FindStringSubmatch(name)
+	if match == nil || len(match) != 3 {
+		return nil, ErrReferenceInvalidFormat
+	}
+
+	if len(match[2]) > RepositoryNameTotalLengthMax {
+		return nil, ErrNameTooLong
+	}
+
+	return repository{
+		domain: match[1],
+		path:   match[2],
+	}, nil
+}
+
+// WithTag combines the name from "name" and the tag from "tag" to form a
+// reference incorporating both the name and the tag.
+func WithTag(name Named, tag string) (NamedTagged, error) {
+	if !anchoredTagRegexp.MatchString(tag) {
+		return nil, ErrTagInvalidFormat
+	}
+	var repo repository
+	if r, ok := name.(namedRepository); ok {
+		repo.domain = r.Domain()
+		repo.path = r.Path()
+	} else {
+		repo.path = name.Name()
+	}
+	if canonical, ok := name.(Canonical); ok {
+		return reference{
+			namedRepository: repo,
+			tag:             tag,
+			digest:          canonical.Digest(),
+		}, nil
+	}
+	return taggedReference{
+		namedRepository: repo,
+		tag:             tag,
+	}, nil
+}
+
+// WithDigest combines the name from "name" and the digest from "digest" to form
+// a reference incorporating both the name and the digest.
+func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
+	if !anchoredDigestRegexp.MatchString(digest.String()) {
+		return nil, ErrDigestInvalidFormat
+	}
+	var repo repository
+	if r, ok := name.(namedRepository); ok {
+		repo.domain = r.Domain()
+		repo.path = r.Path()
+	} else {
+		repo.path = name.Name()
+	}
+	if tagged, ok := name.(Tagged); ok {
+		return reference{
+			namedRepository: repo,
+			tag:             tagged.Tag(),
+			digest:          digest,
+		}, nil
+	}
+	return canonicalReference{
+		namedRepository: repo,
+		digest:          digest,
+	}, nil
+}
+
+// TrimNamed removes any tag or digest from the named reference.
+func TrimNamed(ref Named) Named {
+	repo := repository{}
+	if r, ok := ref.(namedRepository); ok {
+		repo.domain, repo.path = r.Domain(), r.Path()
+	} else {
+		repo.domain, repo.path = splitDomain(ref.Name())
+	}
+	return repo
+}
+
+func getBestReferenceType(ref reference) Reference {
+	if ref.Name() == "" {
+		// Allow digest only references
+		if ref.digest != "" {
+			return digestReference(ref.digest)
+		}
+		return nil
+	}
+	if ref.tag == "" {
+		if ref.digest != "" {
+			return canonicalReference{
+				namedRepository: ref.namedRepository,
+				digest:          ref.digest,
+			}
+		}
+		return ref.namedRepository
+	}
+	if ref.digest == "" {
+		return taggedReference{
+			namedRepository: ref.namedRepository,
+			tag:             ref.tag,
+		}
+	}
+
+	return ref
+}
+
+type reference struct {
+	namedRepository
+	tag    string
+	digest digest.Digest
+}
+
+func (r reference) String() string {
+	return r.Name() + ":" + r.tag + "@" + r.digest.String()
+}
+
+func (r reference) Tag() string {
+	return r.tag
+}
+
+func (r reference) Digest() digest.Digest {
+	return r.digest
+}
+
+type repository struct {
+	domain string
+	path   string
+}
+
+func (r repository) String() string {
+	return r.Name()
+}
+
+func (r repository) Name() string {
+	if r.domain == "" {
+		return r.path
+	}
+	return r.domain + "/" + r.path
+}
+
+func (r repository) Domain() string {
+	return r.domain
+}
+
+func (r repository) Path() string {
+	return r.path
+}
+
+type digestReference digest.Digest
+
+func (d digestReference) String() string {
+	return digest.Digest(d).String()
+}
+
+func (d digestReference) Digest() digest.Digest {
+	return digest.Digest(d)
+}
+
+type taggedReference struct {
+	namedRepository
+	tag string
+}
+
+func (t taggedReference) String() string {
+	return t.Name() + ":" + t.tag
+}
+
+func (t taggedReference) Tag() string {
+	return t.tag
+}
+
+type canonicalReference struct {
+	namedRepository
+	digest digest.Digest
+}
+
+func (c canonicalReference) String() string {
+	return c.Name() + "@" + c.digest.String()
+}
+
+func (c canonicalReference) Digest() digest.Digest {
+	return c.digest
+}
diff --git a/vendor/github.com/distribution/reference/regexp.go b/vendor/github.com/distribution/reference/regexp.go
new file mode 100644
index 000000000..65bc49d79
--- /dev/null
+++ b/vendor/github.com/distribution/reference/regexp.go
@@ -0,0 +1,163 @@
+package reference
+
+import (
+	"regexp"
+	"strings"
+)
+
+// DigestRegexp matches well-formed digests, including algorithm (e.g. "sha256:<encoded>").
+var DigestRegexp = regexp.MustCompile(digestPat)
+
+// DomainRegexp matches hostname or IP-addresses, optionally including a port
+// number. It defines the structure of potential domain components that may be
+// part of image names. This is purposely a subset of what is allowed by DNS to
+// ensure backwards compatibility with Docker image names. It may be a subset of
+// DNS domain name, an IPv4 address in decimal format, or an IPv6 address between
+// square brackets (excluding zone identifiers as defined by [RFC 6874] or special
+// addresses such as IPv4-Mapped).
+//
+// [RFC 6874]: https://www.rfc-editor.org/rfc/rfc6874.
+var DomainRegexp = regexp.MustCompile(domainAndPort)
+
+// IdentifierRegexp is the format for string identifier used as a
+// content addressable identifier using sha256. These identifiers
+// are like digests without the algorithm, since sha256 is used.
+var IdentifierRegexp = regexp.MustCompile(identifier)
+
+// NameRegexp is the format for the name component of references, including
+// an optional domain and port, but without tag or digest suffix.
+var NameRegexp = regexp.MustCompile(namePat)
+
+// ReferenceRegexp is the full supported format of a reference. The regexp
+// is anchored and has capturing groups for name, tag, and digest
+// components.
+var ReferenceRegexp = regexp.MustCompile(referencePat)
+
+// TagRegexp matches valid tag names. From [docker/docker:graph/tags.go].
+//
+// [docker/docker:graph/tags.go]: https://github.com/moby/moby/blob/v1.6.0/graph/tags.go#L26-L28
+var TagRegexp = regexp.MustCompile(tag)
+
+const (
+	// alphanumeric defines the alphanumeric atom, typically a
+	// component of names. This only allows lower case characters and digits.
+	alphanumeric = `[a-z0-9]+`
+
+	// separator defines the separators allowed to be embedded in name
+	// components. This allows one period, one or two underscore and multiple
+	// dashes. Repeated dashes and underscores are intentionally treated
+	// differently. In order to support valid hostnames as name components,
+	// supporting repeated dash was added. Additionally double underscore is
+	// now allowed as a separator to loosen the restriction for previously
+	// supported names.
+	separator = `(?:[._]|__|[-]+)`
+
+	// localhost is treated as a special value for domain-name. Any other
+	// domain-name without a "." or a ":port" are considered a path component.
+	localhost = `localhost`
+
+	// domainNameComponent restricts the registry domain component of a
+	// repository name to start with a component as defined by DomainRegexp.
+	domainNameComponent = `(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`
+
+	// optionalPort matches an optional port-number including the port separator
+	// (e.g. ":80").
+	optionalPort = `(?::[0-9]+)?`
+
+	// tag matches valid tag names. From docker/docker:graph/tags.go.
+	tag = `[\w][\w.-]{0,127}`
+
+	// digestPat matches well-formed digests, including algorithm (e.g. "sha256:<encoded>").
+	//
+	// TODO(thaJeztah): this should follow the same rules as https://pkg.go.dev/github.com/opencontainers/go-digest@v1.0.0#DigestRegexp
+	// so that go-digest defines the canonical format. Note that the go-digest is
+	// more relaxed:
+	//   - it allows multiple algorithms (e.g. "sha256+b64:<encoded>") to allow
+	//     future expansion of supported algorithms.
+	//   - it allows the "<encoded>" value to use urlsafe base64 encoding as defined
+	//     in [rfc4648, section 5].
+	//
+	// [rfc4648, section 5]: https://www.rfc-editor.org/rfc/rfc4648#section-5.
+	digestPat = `[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`
+
+	// identifier is the format for a content addressable identifier using sha256.
+	// These identifiers are like digests without the algorithm, since sha256 is used.
+	identifier = `([a-f0-9]{64})`
+
+	// ipv6address are enclosed between square brackets and may be represented
+	// in many ways, see rfc5952. Only IPv6 in compressed or uncompressed format
+	// are allowed, IPv6 zone identifiers (rfc6874) or Special addresses such as
+	// IPv4-Mapped are deliberately excluded.
+	ipv6address = `\[(?:[a-fA-F0-9:]+)\]`
+)
+
+var (
+	// domainName defines the structure of potential domain components
+	// that may be part of image names. This is purposely a subset of what is
+	// allowed by DNS to ensure backwards compatibility with Docker image
+	// names. This includes IPv4 addresses on decimal format.
+	domainName = domainNameComponent + anyTimes(`\.`+domainNameComponent)
+
+	// host defines the structure of potential domains based on the URI
+	// Host subcomponent on rfc3986. It may be a subset of DNS domain name,
+	// or an IPv4 address in decimal format, or an IPv6 address between square
+	// brackets (excluding zone identifiers as defined by rfc6874 or special
+	// addresses such as IPv4-Mapped).
+	host = `(?:` + domainName + `|` + ipv6address + `)`
+
+	// allowed by the URI Host subcomponent on rfc3986 to ensure backwards
+	// compatibility with Docker image names.
+	domainAndPort = host + optionalPort
+
+	// anchoredTagRegexp matches valid tag names, anchored at the start and
+	// end of the matched string.
+	anchoredTagRegexp = regexp.MustCompile(anchored(tag))
+
+	// anchoredDigestRegexp matches valid digests, anchored at the start and
+	// end of the matched string.
+	anchoredDigestRegexp = regexp.MustCompile(anchored(digestPat))
+
+	// pathComponent restricts path-components to start with an alphanumeric
+	// character, with following parts able to be separated by a separator
+	// (one period, one or two underscore and multiple dashes).
+	pathComponent = alphanumeric + anyTimes(separator+alphanumeric)
+
+	// remoteName matches the remote-name of a repository. It consists of one
+	// or more forward slash (/) delimited path-components:
+	//
+	//	pathComponent[[/pathComponent] ...] // e.g., "library/ubuntu"
+	remoteName = pathComponent + anyTimes(`/`+pathComponent)
+	namePat    = optional(domainAndPort+`/`) + remoteName
+
+	// anchoredNameRegexp is used to parse a name value, capturing the
+	// domain and trailing components.
+	anchoredNameRegexp = regexp.MustCompile(anchored(optional(capture(domainAndPort), `/`), capture(remoteName)))
+
+	referencePat = anchored(capture(namePat), optional(`:`, capture(tag)), optional(`@`, capture(digestPat)))
+
+	// anchoredIdentifierRegexp is used to check or match an
+	// identifier value, anchored at start and end of string.
+	anchoredIdentifierRegexp = regexp.MustCompile(anchored(identifier))
+)
+
+// optional wraps the expression in a non-capturing group and makes the
+// production optional.
+func optional(res ...string) string {
+	return `(?:` + strings.Join(res, "") + `)?`
+}
+
+// anyTimes wraps the expression in a non-capturing group that can occur
+// any number of times.
+func anyTimes(res ...string) string {
+	return `(?:` + strings.Join(res, "") + `)*`
+}
+
+// capture wraps the expression in a capturing group.
+func capture(res ...string) string {
+	return `(` + strings.Join(res, "") + `)`
+}
+
+// anchored anchors the regular expression by adding start and end delimiters.
+func anchored(res ...string) string {
+	return `^` + strings.Join(res, "") + `$`
+}
diff --git a/vendor/github.com/distribution/reference/sort.go b/vendor/github.com/distribution/reference/sort.go
new file mode 100644
index 000000000..416c37b07
--- /dev/null
+++ b/vendor/github.com/distribution/reference/sort.go
@@ -0,0 +1,75 @@
+/*
+   Copyright The containerd Authors.
+
+   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 reference
+
+import (
+	"sort"
+)
+
+// Sort sorts string references preferring higher information references.
+//
+// The precedence is as follows:
+//
+//  1. [Named] + [Tagged] + [Digested] (e.g., "docker.io/library/busybox:latest@sha256:<digest>")
+//  2. [Named] + [Tagged]              (e.g., "docker.io/library/busybox:latest")
+//  3. [Named] + [Digested]            (e.g., "docker.io/library/busybo@sha256:<digest>")
+//  4. [Named]                         (e.g., "docker.io/library/busybox")
+//  5. [Digested]                      (e.g., "docker.io@sha256:<digest>")
+//  6. Parse error
+func Sort(references []string) []string {
+	var prefs []Reference
+	var bad []string
+
+	for _, ref := range references {
+		pref, err := ParseAnyReference(ref)
+		if err != nil {
+			bad = append(bad, ref)
+		} else {
+			prefs = append(prefs, pref)
+		}
+	}
+	sort.Slice(prefs, func(a, b int) bool {
+		ar := refRank(prefs[a])
+		br := refRank(prefs[b])
+		if ar == br {
+			return prefs[a].String() < prefs[b].String()
+		}
+		return ar < br
+	})
+	sort.Strings(bad)
+	var refs []string
+	for _, pref := range prefs {
+		refs = append(refs, pref.String())
+	}
+	return append(refs, bad...)
+}
+
+func refRank(ref Reference) uint8 {
+	if _, ok := ref.(Named); ok {
+		if _, ok = ref.(Tagged); ok {
+			if _, ok = ref.(Digested); ok {
+				return 1
+			}
+			return 2
+		}
+		if _, ok = ref.(Digested); ok {
+			return 3
+		}
+		return 4
+	}
+	return 5
+}
diff --git a/vendor/github.com/docker/go-connections/LICENSE b/vendor/github.com/docker/go-connections/LICENSE
new file mode 100644
index 000000000..b55b37bc3
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/LICENSE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2015 Docker, 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
+
+       https://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.
diff --git a/vendor/github.com/docker/go-connections/sockets/inmem_socket.go b/vendor/github.com/docker/go-connections/sockets/inmem_socket.go
new file mode 100644
index 000000000..06fcf747a
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/sockets/inmem_socket.go
@@ -0,0 +1,81 @@
+package sockets
+
+import (
+	"net"
+	"sync"
+)
+
+// dummyAddr is used to satisfy net.Addr for the in-mem socket
+// it is just stored as a string and returns the string for all calls
+type dummyAddr string
+
+// Network returns the addr string, satisfies net.Addr
+func (a dummyAddr) Network() string {
+	return string(a)
+}
+
+// String returns the string form
+func (a dummyAddr) String() string {
+	return string(a)
+}
+
+// InmemSocket implements [net.Listener] using in-memory only connections.
+type InmemSocket struct {
+	chConn  chan net.Conn
+	chClose chan struct{}
+	addr    dummyAddr
+	mu      sync.Mutex
+}
+
+// NewInmemSocket creates an in-memory only [net.Listener]. The addr argument
+// can be any string, but is used to satisfy the [net.Listener.Addr] part
+// of the [net.Listener] interface
+func NewInmemSocket(addr string, bufSize int) *InmemSocket {
+	return &InmemSocket{
+		chConn:  make(chan net.Conn, bufSize),
+		chClose: make(chan struct{}),
+		addr:    dummyAddr(addr),
+	}
+}
+
+// Addr returns the socket's addr string to satisfy net.Listener
+func (s *InmemSocket) Addr() net.Addr {
+	return s.addr
+}
+
+// Accept implements the Accept method in the Listener interface; it waits
+// for the next call and returns a generic Conn. It returns a [net.ErrClosed]
+// if the connection is already closed.
+func (s *InmemSocket) Accept() (net.Conn, error) {
+	select {
+	case conn := <-s.chConn:
+		return conn, nil
+	case <-s.chClose:
+		return nil, net.ErrClosed
+	}
+}
+
+// Close closes the listener. It will be unavailable for use once closed.
+func (s *InmemSocket) Close() error {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	select {
+	case <-s.chClose:
+	default:
+		close(s.chClose)
+	}
+	return nil
+}
+
+// Dial is used to establish a connection with the in-mem server.
+// It returns a [net.ErrClosed] if the connection is already closed.
+func (s *InmemSocket) Dial(network, addr string) (net.Conn, error) {
+	srvConn, clientConn := net.Pipe()
+	select {
+	case s.chConn <- srvConn:
+	case <-s.chClose:
+		return nil, net.ErrClosed
+	}
+
+	return clientConn, nil
+}
diff --git a/vendor/github.com/docker/go-connections/sockets/sockets.go b/vendor/github.com/docker/go-connections/sockets/sockets.go
new file mode 100644
index 000000000..0d7789bbd
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/sockets/sockets.go
@@ -0,0 +1,66 @@
+// Package sockets provides helper functions to create and configure Unix or TCP sockets.
+package sockets
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net"
+	"net/http"
+	"syscall"
+	"time"
+)
+
+const (
+	defaultTimeout        = 10 * time.Second
+	maxUnixSocketPathSize = len(syscall.RawSockaddrUnix{}.Path)
+)
+
+// ErrProtocolNotAvailable is returned when a given transport protocol is not provided by the operating system.
+var ErrProtocolNotAvailable = errors.New("protocol not available")
+
+// ConfigureTransport configures the specified [http.Transport] according to the specified proto
+// and addr.
+//
+// If the proto is unix (using a unix socket to communicate) or npipe the compression is disabled.
+// For other protos, compression is enabled. If you want to manually enable/disable compression,
+// make sure you do it _after_ any subsequent calls to ConfigureTransport is made against the same
+// [http.Transport].
+func ConfigureTransport(tr *http.Transport, proto, addr string) error {
+	if tr.MaxIdleConns == 0 {
+		// prevent long-lived processes from leaking connections
+		// due to idle connections not being released.
+		//
+		// TODO: see if we can also address this from the server side; see: https://github.com/moby/moby/issues/45539
+		tr.MaxIdleConns = 6
+		tr.IdleConnTimeout = 30 * time.Second
+	}
+	switch proto {
+	case "unix":
+		return configureUnixTransport(tr, addr)
+	case "npipe":
+		return configureNpipeTransport(tr, addr)
+	default:
+		tr.Proxy = http.ProxyFromEnvironment
+		tr.DisableCompression = false
+		tr.DialContext = (&net.Dialer{
+			Timeout: defaultTimeout,
+		}).DialContext
+	}
+	return nil
+}
+
+func configureUnixTransport(tr *http.Transport, addr string) error {
+	if len(addr) > maxUnixSocketPathSize {
+		return fmt.Errorf("unix socket path %q is too long", addr)
+	}
+	// No need for compression in local communications.
+	tr.DisableCompression = true
+	dialer := &net.Dialer{
+		Timeout: defaultTimeout,
+	}
+	tr.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
+		return dialer.DialContext(ctx, "unix", addr)
+	}
+	return nil
+}
diff --git a/vendor/github.com/docker/go-connections/sockets/sockets_unix.go b/vendor/github.com/docker/go-connections/sockets/sockets_unix.go
new file mode 100644
index 000000000..b37c39eab
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/sockets/sockets_unix.go
@@ -0,0 +1,7 @@
+//go:build !windows
+
+package sockets
+
+func configureNpipeTransport(any, string) error {
+	return ErrProtocolNotAvailable
+}
diff --git a/vendor/github.com/docker/go-connections/sockets/sockets_windows.go b/vendor/github.com/docker/go-connections/sockets/sockets_windows.go
new file mode 100644
index 000000000..0863fc36a
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/sockets/sockets_windows.go
@@ -0,0 +1,18 @@
+package sockets
+
+import (
+	"context"
+	"net"
+	"net/http"
+
+	"github.com/Microsoft/go-winio"
+)
+
+func configureNpipeTransport(tr *http.Transport, addr string) error {
+	// No need for compression in local communications.
+	tr.DisableCompression = true
+	tr.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
+		return winio.DialPipeContext(ctx, addr)
+	}
+	return nil
+}
diff --git a/vendor/github.com/docker/go-connections/sockets/tcp_socket.go b/vendor/github.com/docker/go-connections/sockets/tcp_socket.go
new file mode 100644
index 000000000..53cbb6c79
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/sockets/tcp_socket.go
@@ -0,0 +1,22 @@
+// Package sockets provides helper functions to create and configure Unix or TCP sockets.
+package sockets
+
+import (
+	"crypto/tls"
+	"net"
+)
+
+// NewTCPSocket creates a TCP socket listener with the specified address and
+// the specified tls configuration. If TLSConfig is set, will encapsulate the
+// TCP listener inside a TLS one.
+func NewTCPSocket(addr string, tlsConfig *tls.Config) (net.Listener, error) {
+	l, err := net.Listen("tcp", addr)
+	if err != nil {
+		return nil, err
+	}
+	if tlsConfig != nil {
+		tlsConfig.NextProtos = []string{"http/1.1"}
+		l = tls.NewListener(l, tlsConfig)
+	}
+	return l, nil
+}
diff --git a/vendor/github.com/docker/go-connections/sockets/unix_socket.go b/vendor/github.com/docker/go-connections/sockets/unix_socket.go
new file mode 100644
index 000000000..e736f71d3
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/sockets/unix_socket.go
@@ -0,0 +1,84 @@
+/*
+Package sockets is a simple unix domain socket wrapper.
+
+# Usage
+
+For example:
+
+	import(
+		"fmt"
+		"net"
+		"os"
+		"github.com/docker/go-connections/sockets"
+	)
+
+	func main() {
+		l, err := sockets.NewUnixSocketWithOpts("/path/to/sockets",
+			sockets.WithChown(0,0),sockets.WithChmod(0660))
+		if err != nil {
+			panic(err)
+		}
+		echoStr := "hello"
+
+		go func() {
+			for {
+				conn, err := l.Accept()
+				if err != nil {
+					return
+				}
+				conn.Write([]byte(echoStr))
+				conn.Close()
+			}
+		}()
+
+		conn, err := net.Dial("unix", path)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		buf := make([]byte, 5)
+		if _, err := conn.Read(buf); err != nil {
+			panic(err)
+		} else if string(buf) != echoStr {
+			panic(fmt.Errorf("msg may lost"))
+		}
+	}
+*/
+package sockets
+
+import (
+	"net"
+	"os"
+	"syscall"
+)
+
+// SockOption sets up socket file's creating option
+type SockOption func(string) error
+
+// NewUnixSocketWithOpts creates a unix socket with the specified options.
+// By default, socket permissions are 0000 (i.e.: no access for anyone); pass
+// WithChmod() and WithChown() to set the desired ownership and permissions.
+//
+// This function temporarily changes the system's "umask" to 0777 to work around
+// a race condition between creating the socket and setting its permissions. While
+// this should only be for a short duration, it may affect other processes that
+// create files/directories during that period.
+func NewUnixSocketWithOpts(path string, opts ...SockOption) (net.Listener, error) {
+	if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
+		return nil, err
+	}
+
+	l, err := listenUnix(path)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, op := range opts {
+		if err := op(path); err != nil {
+			_ = l.Close()
+			return nil, err
+		}
+	}
+
+	return l, nil
+}
diff --git a/vendor/github.com/docker/go-connections/sockets/unix_socket_unix.go b/vendor/github.com/docker/go-connections/sockets/unix_socket_unix.go
new file mode 100644
index 000000000..a41a71654
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/sockets/unix_socket_unix.go
@@ -0,0 +1,54 @@
+//go:build !windows
+
+package sockets
+
+import (
+	"net"
+	"os"
+	"syscall"
+)
+
+// WithChown modifies the socket file's uid and gid
+func WithChown(uid, gid int) SockOption {
+	return func(path string) error {
+		if err := os.Chown(path, uid, gid); err != nil {
+			return err
+		}
+		return nil
+	}
+}
+
+// WithChmod modifies socket file's access mode.
+func WithChmod(mask os.FileMode) SockOption {
+	return func(path string) error {
+		if err := os.Chmod(path, mask); err != nil {
+			return err
+		}
+		return nil
+	}
+}
+
+// NewUnixSocket creates a unix socket with the specified path and group.
+func NewUnixSocket(path string, gid int) (net.Listener, error) {
+	return NewUnixSocketWithOpts(path, WithChown(0, gid), WithChmod(0o660))
+}
+
+func listenUnix(path string) (net.Listener, error) {
+	// net.Listen does not allow for permissions to be set. As a result, when
+	// specifying custom permissions ("WithChmod()"), there is a short time
+	// between creating the socket and applying the permissions, during which
+	// the socket permissions are Less restrictive than desired.
+	//
+	// To work around this limitation of net.Listen(), we temporarily set the
+	// umask to 0777, which forces the socket to be created with 000 permissions
+	// (i.e.: no access for anyone). After that, WithChmod() must be used to set
+	// the desired permissions.
+	//
+	// We don't use "defer" here, to reset the umask to its original value as soon
+	// as possible. Ideally we'd be able to detect if WithChmod() was passed as
+	// an option, and skip changing umask if default permissions are used.
+	origUmask := syscall.Umask(0o777)
+	l, err := net.Listen("unix", path)
+	syscall.Umask(origUmask)
+	return l, err
+}
diff --git a/vendor/github.com/docker/go-connections/sockets/unix_socket_windows.go b/vendor/github.com/docker/go-connections/sockets/unix_socket_windows.go
new file mode 100644
index 000000000..01aee5f11
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/sockets/unix_socket_windows.go
@@ -0,0 +1,129 @@
+package sockets
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"strings"
+
+	"github.com/Microsoft/go-winio"
+	"golang.org/x/sys/windows"
+)
+
+// BasePermissions defines the default DACL, which allows Administrators
+// and LocalSystem full access (similar to defaults used in [moby]);
+//
+// - D:P: DACL without inheritance (protected, (P)).
+// - (A;;GA;;;BA): Allow full access (GA) for built-in Administrators (BA).
+// - (A;;GA;;;SY); Allow full access (GA) for LocalSystem (SY).
+// - Any other user is denied access.
+//
+// [moby]: https://github.com/moby/moby/blob/6b45c76a233b1b8b56465f76c21c09fd7920e82d/daemon/listeners/listeners_windows.go#L53-L59
+const BasePermissions = "D:P(A;;GA;;;BA)(A;;GA;;;SY)"
+
+// WithBasePermissions sets a default DACL, which allows Administrators
+// and LocalSystem full access (similar to defaults used in [moby]);
+//
+// - D:P: DACL without inheritance (protected, (P)).
+// - (A;;GA;;;BA): Allow full access (GA) for built-in Administrators (BA).
+// - (A;;GA;;;SY); Allow full access (GA) for LocalSystem (SY).
+// - Any other user is denied access.
+//
+// [moby]: https://github.com/moby/moby/blob/6b45c76a233b1b8b56465f76c21c09fd7920e82d/daemon/listeners/listeners_windows.go#L53-L59
+func WithBasePermissions() SockOption {
+	return withSDDL(BasePermissions)
+}
+
+// WithAdditionalUsersAndGroups modifies the socket file's DACL to grant
+// access to additional users and groups.
+//
+// It sets [BasePermissions] on the socket path and grants the given additional
+// users and groups to generic read (GR) and write (GW) access. It returns
+// an error if no groups were given, when failing to resolve any of the
+// additional users and groups, or when failing to apply the ACL.
+func WithAdditionalUsersAndGroups(additionalUsersAndGroups []string) SockOption {
+	return func(path string) error {
+		if len(additionalUsersAndGroups) == 0 {
+			return errors.New("no additional users specified")
+		}
+		sd, err := getSecurityDescriptor(additionalUsersAndGroups...)
+		if err != nil {
+			return fmt.Errorf("looking up SID: %w", err)
+		}
+		return withSDDL(sd)(path)
+	}
+}
+
+// withSDDL applies the given SDDL to the socket. It returns an error
+// when failing parse the SDDL, or if the DACL was defaulted.
+//
+// TODO(thaJeztah); this is not exported yet, as some of the checks may need review if they're not too opinionated.
+func withSDDL(sddl string) SockOption {
+	return func(path string) error {
+		sd, err := windows.SecurityDescriptorFromString(sddl)
+		if err != nil {
+			return fmt.Errorf("parsing SDDL: %w", err)
+		}
+		dacl, defaulted, err := sd.DACL()
+		if err != nil {
+			return fmt.Errorf("extracting DACL: %w", err)
+		}
+		if dacl == nil || defaulted {
+			// should never be hit with our [DefaultPermissions],
+			// as it contains "D:" and "P" (protected, don't inherit).
+			return errors.New("no DACL found in security descriptor or defaulted")
+		}
+		return windows.SetNamedSecurityInfo(
+			path,
+			windows.SE_FILE_OBJECT,
+			windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION,
+			nil, // do not change the owner
+			nil, // do not change the owner
+			dacl,
+			nil,
+		)
+	}
+}
+
+// NewUnixSocket creates a new unix socket.
+//
+// It sets [BasePermissions] on the socket path and grants the given additional
+// users and groups to generic read (GR) and write (GW) access. It returns
+// an error when failing to resolve any of the additional users and groups,
+// or when failing to apply the ACL.
+func NewUnixSocket(path string, additionalUsersAndGroups []string) (net.Listener, error) {
+	var opts []SockOption
+	if len(additionalUsersAndGroups) > 0 {
+		opts = append(opts, WithAdditionalUsersAndGroups(additionalUsersAndGroups))
+	} else {
+		opts = append(opts, WithBasePermissions())
+	}
+	return NewUnixSocketWithOpts(path, opts...)
+}
+
+// getSecurityDescriptor returns the DACL for the Unix socket.
+//
+// By default, it grants [BasePermissions], but allows for additional
+// users and groups to get generic read (GR) and write (GW) access. It
+// returns an error when failing to resolve any of the additional users
+// and groups.
+func getSecurityDescriptor(additionalUsersAndGroups ...string) (string, error) {
+	sddl := BasePermissions
+
+	// Grant generic read (GR) and write (GW) access to whatever
+	// additional users or groups were specified.
+	//
+	// TODO(thaJeztah): should we fail on, or remove duplicates?
+	for _, g := range additionalUsersAndGroups {
+		sid, err := winio.LookupSidByName(strings.TrimSpace(g))
+		if err != nil {
+			return "", fmt.Errorf("looking up SID: %w", err)
+		}
+		sddl += fmt.Sprintf("(A;;GRGW;;;%s)", sid)
+	}
+	return sddl, nil
+}
+
+func listenUnix(path string) (net.Listener, error) {
+	return net.Listen("unix", path)
+}
diff --git a/vendor/github.com/docker/go-connections/tlsconfig/certpool.go b/vendor/github.com/docker/go-connections/tlsconfig/certpool.go
new file mode 100644
index 000000000..803f1e122
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/tlsconfig/certpool.go
@@ -0,0 +1,12 @@
+package tlsconfig
+
+import "crypto/x509"
+
+// SystemCertPool returns a copy of the system cert pool.
+//
+// Deprecated: use [x509.SystemCertPool] instead.
+//
+//go:fix inline
+func SystemCertPool() (*x509.CertPool, error) {
+	return x509.SystemCertPool()
+}
diff --git a/vendor/github.com/docker/go-connections/tlsconfig/config.go b/vendor/github.com/docker/go-connections/tlsconfig/config.go
new file mode 100644
index 000000000..761b36bb8
--- /dev/null
+++ b/vendor/github.com/docker/go-connections/tlsconfig/config.go
@@ -0,0 +1,257 @@
+// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers.
+//
+// As a reminder from https://golang.org/pkg/crypto/tls/#Config:
+//
+//	A Config structure is used to configure a TLS client or server. After one has been passed to a TLS function it must not be modified.
+//	A Config may be reused; the tls package will also not modify it.
+package tlsconfig
+
+import (
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"os"
+)
+
+// Options represents the information needed to create client and server TLS configurations.
+type Options struct {
+	CAFile string
+
+	// If either CertFile or KeyFile is empty, Client() will not load them
+	// preventing the client from authenticating to the server.
+	// However, Server() requires them and will error out if they are empty.
+	CertFile string
+	KeyFile  string
+
+	// client-only option
+	InsecureSkipVerify bool
+	// server-only option
+	ClientAuth tls.ClientAuthType
+	// If ExclusiveRootPools is set, then if a CA file is provided, the root pool used for TLS
+	// creds will include exclusively the roots in that CA file.  If no CA file is provided,
+	// the system pool will be used.
+	ExclusiveRootPools bool
+	MinVersion         uint16
+
+	// systemCertPool allows mocking the system cert-pool for testing.
+	systemCertPool func() (*x509.CertPool, error)
+}
+
+// DefaultServerAcceptedCiphers should be uses by code which already has a crypto/tls
+// options struct but wants to use a commonly accepted set of TLS cipher suites, with
+// known weak algorithms removed.
+var DefaultServerAcceptedCiphers = defaultCipherSuites
+
+// defaultCipherSuites is shared by both client and server as the default set.
+var defaultCipherSuites = []uint16{
+	tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+	tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+	tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+	tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+	tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+	tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+}
+
+// ServerDefault returns a secure-enough TLS configuration for the server TLS configuration.
+func ServerDefault(ops ...func(*tls.Config)) *tls.Config {
+	return defaultConfig(ops...)
+}
+
+// ClientDefault returns a secure-enough TLS configuration for the client TLS configuration.
+func ClientDefault(ops ...func(*tls.Config)) *tls.Config {
+	return defaultConfig(ops...)
+}
+
+// defaultConfig is the default config used by both client and server TLS configuration.
+func defaultConfig(ops ...func(*tls.Config)) *tls.Config {
+	tlsConfig := &tls.Config{
+		// Avoid fallback by default to SSL protocols < TLS1.2
+		MinVersion:   tls.VersionTLS12,
+		CipherSuites: defaultCipherSuites,
+	}
+
+	for _, op := range ops {
+		op(tlsConfig)
+	}
+
+	return tlsConfig
+}
+
+// certPool returns an X.509 certificate pool from `caFile`, the certificate file.
+func certPool(opts Options) (*x509.CertPool, error) {
+	// If we should verify the server, we need to load a trusted ca
+	var (
+		pool *x509.CertPool
+		err  error
+	)
+	if opts.ExclusiveRootPools {
+		pool = x509.NewCertPool()
+	} else {
+		if opts.systemCertPool != nil {
+			pool, err = opts.systemCertPool()
+		} else {
+			pool, err = x509.SystemCertPool()
+		}
+		if err != nil {
+			return nil, fmt.Errorf("failed to read system certificates: %v", err)
+		}
+	}
+	if opts.CAFile == "" {
+		return pool, nil
+	}
+	pemData, err := os.ReadFile(opts.CAFile)
+	if err != nil {
+		return nil, fmt.Errorf("could not read CA certificate %q: %v", opts.CAFile, err)
+	}
+	if !pool.AppendCertsFromPEM(pemData) {
+		return nil, fmt.Errorf("failed to append certificates from PEM file: %q", opts.CAFile)
+	}
+	return pool, nil
+}
+
+// allTLSVersions lists all the TLS versions and is used by the code that validates
+// a uint16 value as a TLS version.
+var allTLSVersions = map[uint16]struct{}{
+	tls.VersionTLS10: {},
+	tls.VersionTLS11: {},
+	tls.VersionTLS12: {},
+	tls.VersionTLS13: {},
+}
+
+// isValidMinVersion checks that the input value is a valid tls minimum version
+func isValidMinVersion(version uint16) bool {
+	_, ok := allTLSVersions[version]
+	return ok
+}
+
+// adjustMinVersion sets the MinVersion on `config`, the input configuration.
+// It assumes the current MinVersion on the `config` is the lowest allowed.
+func adjustMinVersion(options Options, config *tls.Config) error {
+	if options.MinVersion > 0 {
+		if !isValidMinVersion(options.MinVersion) {
+			return fmt.Errorf("invalid minimum TLS version: %x", options.MinVersion)
+		}
+		if options.MinVersion < config.MinVersion {
+			return fmt.Errorf("requested minimum TLS version is too low. Should be at-least: %x", config.MinVersion)
+		}
+		config.MinVersion = options.MinVersion
+	}
+
+	return nil
+}
+
+// errEncryptedKeyDeprecated is produced when we encounter an encrypted
+// (password-protected) key. From https://go-review.googlesource.com/c/go/+/264159;
+//
+// > Legacy PEM encryption as specified in RFC 1423 is insecure by design. Since
+// > it does not authenticate the ciphertext, it is vulnerable to padding oracle
+// > attacks that can let an attacker recover the plaintext
+// >
+// > It's unfortunate that we don't implement PKCS#8 encryption so we can't
+// > recommend an alternative but PEM encryption is so broken that it's worth
+// > deprecating outright.
+//
+// Also see https://docs.docker.com/go/deprecated/
+var errEncryptedKeyDeprecated = errors.New("private key is encrypted; encrypted private keys are obsolete, and not supported")
+
+// getPrivateKey returns the private key in 'keyBytes', in PEM-encoded format.
+// It returns an error if the file could not be decoded or was protected by
+// a passphrase.
+func getPrivateKey(keyBytes []byte) ([]byte, error) {
+	// this section makes some small changes to code from notary/tuf/utils/x509.go
+	pemBlock, _ := pem.Decode(keyBytes)
+	if pemBlock == nil {
+		return nil, fmt.Errorf("no valid private key found")
+	}
+
+	if x509.IsEncryptedPEMBlock(pemBlock) { //nolint:staticcheck // Ignore SA1019 (IsEncryptedPEMBlock is deprecated)
+		return nil, errEncryptedKeyDeprecated
+	}
+
+	return keyBytes, nil
+}
+
+// getCert returns a Certificate from the CertFile and KeyFile in 'options',
+// if the key is encrypted, the Passphrase in 'options' will be used to
+// decrypt it.
+func getCert(options Options) ([]tls.Certificate, error) {
+	if options.CertFile == "" && options.KeyFile == "" {
+		return nil, nil
+	}
+
+	cert, err := os.ReadFile(options.CertFile)
+	if err != nil {
+		return nil, err
+	}
+
+	prKeyBytes, err := os.ReadFile(options.KeyFile)
+	if err != nil {
+		return nil, err
+	}
+
+	prKeyBytes, err = getPrivateKey(prKeyBytes)
+	if err != nil {
+		return nil, err
+	}
+
+	tlsCert, err := tls.X509KeyPair(cert, prKeyBytes)
+	if err != nil {
+		return nil, err
+	}
+
+	return []tls.Certificate{tlsCert}, nil
+}
+
+// Client returns a TLS configuration meant to be used by a client.
+func Client(options Options) (*tls.Config, error) {
+	tlsConfig := defaultConfig()
+	tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify
+	if !options.InsecureSkipVerify && options.CAFile != "" {
+		CAs, err := certPool(options)
+		if err != nil {
+			return nil, err
+		}
+		tlsConfig.RootCAs = CAs
+	}
+
+	tlsCerts, err := getCert(options)
+	if err != nil {
+		return nil, fmt.Errorf("could not load X509 key pair: %w", err)
+	}
+	tlsConfig.Certificates = tlsCerts
+
+	if err := adjustMinVersion(options, tlsConfig); err != nil {
+		return nil, err
+	}
+
+	return tlsConfig, nil
+}
+
+// Server returns a TLS configuration meant to be used by a server.
+func Server(options Options) (*tls.Config, error) {
+	tlsConfig := defaultConfig()
+	tlsConfig.ClientAuth = options.ClientAuth
+	tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return nil, fmt.Errorf("could not load X509 key pair (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err)
+		}
+		return nil, fmt.Errorf("error reading X509 key pair - make sure the key is not encrypted (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err)
+	}
+	tlsConfig.Certificates = []tls.Certificate{tlsCert}
+	if options.ClientAuth >= tls.VerifyClientCertIfGiven && options.CAFile != "" {
+		CAs, err := certPool(options)
+		if err != nil {
+			return nil, err
+		}
+		tlsConfig.ClientCAs = CAs
+	}
+
+	if err := adjustMinVersion(options, tlsConfig); err != nil {
+		return nil, err
+	}
+
+	return tlsConfig, nil
+}
diff --git a/vendor/github.com/docker/go-units/CONTRIBUTING.md b/vendor/github.com/docker/go-units/CONTRIBUTING.md
new file mode 100644
index 000000000..9ea86d784
--- /dev/null
+++ b/vendor/github.com/docker/go-units/CONTRIBUTING.md
@@ -0,0 +1,67 @@
+# Contributing to go-units
+
+Want to hack on go-units? Awesome! Here are instructions to get you started.
+
+go-units is a part of the [Docker](https://www.docker.com) project, and follows
+the same rules and principles. If you're already familiar with the way
+Docker does things, you'll feel right at home.
+
+Otherwise, go read Docker's
+[contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md),
+[issue triaging](https://github.com/docker/docker/blob/master/project/ISSUE-TRIAGE.md),
+[review process](https://github.com/docker/docker/blob/master/project/REVIEWING.md) and
+[branches and tags](https://github.com/docker/docker/blob/master/project/BRANCHES-AND-TAGS.md).
+
+### Sign your work
+
+The sign-off is a simple line at the end of the explanation for the patch. Your
+signature certifies that you wrote the patch or otherwise have the right to pass
+it on as an open-source patch. The rules are pretty simple: if you can certify
+the below (from [developercertificate.org](http://developercertificate.org/)):
+
+```
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the open source license
+    indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+    of my knowledge, is covered under an appropriate open source
+    license and I have the right under that license to submit that
+    work with modifications, whether created in whole or in part
+    by me, under the same open source license (unless I am
+    permitted to submit under a different license), as indicated
+    in the file; or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a), (b) or (c) and I have not modified
+    it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
+```
+
+Then you just add a line to every git commit message:
+
+    Signed-off-by: Joe Smith <joe.smith@email.com>
+
+Use your real name (sorry, no pseudonyms or anonymous contributions.)
+
+If you set your `user.name` and `user.email` git configs, you can sign your
+commit automatically with `git commit -s`.
diff --git a/vendor/github.com/docker/go-units/LICENSE b/vendor/github.com/docker/go-units/LICENSE
new file mode 100644
index 000000000..b55b37bc3
--- /dev/null
+++ b/vendor/github.com/docker/go-units/LICENSE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2015 Docker, 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
+
+       https://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.
diff --git a/vendor/github.com/docker/go-units/MAINTAINERS b/vendor/github.com/docker/go-units/MAINTAINERS
new file mode 100644
index 000000000..4aac7c741
--- /dev/null
+++ b/vendor/github.com/docker/go-units/MAINTAINERS
@@ -0,0 +1,46 @@
+# go-units maintainers file
+#
+# This file describes who runs the docker/go-units project and how.
+# This is a living document - if you see something out of date or missing, speak up!
+#
+# It is structured to be consumable by both humans and programs.
+# To extract its contents programmatically, use any TOML-compliant parser.
+#
+# This file is compiled into the MAINTAINERS file in docker/opensource.
+#
+[Org]
+	[Org."Core maintainers"]
+		people = [
+			"akihirosuda",
+			"dnephin",
+			"thajeztah",
+			"vdemeester",
+		]
+
+[people]
+
+# A reference list of all people associated with the project.
+# All other sections should refer to people by their canonical key
+# in the people section.
+
+	# ADD YOURSELF HERE IN ALPHABETICAL ORDER
+
+	[people.akihirosuda]
+	Name = "Akihiro Suda"
+	Email = "akihiro.suda.cz@hco.ntt.co.jp"
+	GitHub = "AkihiroSuda"
+
+	[people.dnephin]
+	Name = "Daniel Nephin"
+	Email = "dnephin@gmail.com"
+	GitHub = "dnephin"
+	
+	[people.thajeztah]
+	Name = "Sebastiaan van Stijn"
+	Email = "github@gone.nl"
+	GitHub = "thaJeztah"
+
+	[people.vdemeester]
+	Name = "Vincent Demeester"
+	Email = "vincent@sbr.pm"
+	GitHub = "vdemeester"
\ No newline at end of file
diff --git a/vendor/github.com/docker/go-units/README.md b/vendor/github.com/docker/go-units/README.md
new file mode 100644
index 000000000..4f70a4e13
--- /dev/null
+++ b/vendor/github.com/docker/go-units/README.md
@@ -0,0 +1,16 @@
+[![GoDoc](https://godoc.org/github.com/docker/go-units?status.svg)](https://godoc.org/github.com/docker/go-units)
+
+# Introduction
+
+go-units is a library to transform human friendly measurements into machine friendly values.
+
+## Usage
+
+See the [docs in godoc](https://godoc.org/github.com/docker/go-units) for examples and documentation.
+
+## Copyright and license
+
+Copyright © 2015 Docker, Inc.
+
+go-units is licensed under the Apache License, Version 2.0.
+See [LICENSE](LICENSE) for the full text of the license.
diff --git a/vendor/github.com/docker/go-units/circle.yml b/vendor/github.com/docker/go-units/circle.yml
new file mode 100644
index 000000000..af9d60552
--- /dev/null
+++ b/vendor/github.com/docker/go-units/circle.yml
@@ -0,0 +1,11 @@
+dependencies:
+  post:
+    # install golint
+    - go get golang.org/x/lint/golint
+
+test:
+  pre:
+    # run analysis before tests
+    - go vet ./...
+    - test -z "$(golint ./... | tee /dev/stderr)"
+    - test -z "$(gofmt -s -l . | tee /dev/stderr)"
diff --git a/vendor/github.com/docker/go-units/duration.go b/vendor/github.com/docker/go-units/duration.go
new file mode 100644
index 000000000..48dd8744d
--- /dev/null
+++ b/vendor/github.com/docker/go-units/duration.go
@@ -0,0 +1,35 @@
+// Package units provides helper function to parse and print size and time units
+// in human-readable format.
+package units
+
+import (
+	"fmt"
+	"time"
+)
+
+// HumanDuration returns a human-readable approximation of a duration
+// (eg. "About a minute", "4 hours ago", etc.).
+func HumanDuration(d time.Duration) string {
+	if seconds := int(d.Seconds()); seconds < 1 {
+		return "Less than a second"
+	} else if seconds == 1 {
+		return "1 second"
+	} else if seconds < 60 {
+		return fmt.Sprintf("%d seconds", seconds)
+	} else if minutes := int(d.Minutes()); minutes == 1 {
+		return "About a minute"
+	} else if minutes < 60 {
+		return fmt.Sprintf("%d minutes", minutes)
+	} else if hours := int(d.Hours() + 0.5); hours == 1 {
+		return "About an hour"
+	} else if hours < 48 {
+		return fmt.Sprintf("%d hours", hours)
+	} else if hours < 24*7*2 {
+		return fmt.Sprintf("%d days", hours/24)
+	} else if hours < 24*30*2 {
+		return fmt.Sprintf("%d weeks", hours/24/7)
+	} else if hours < 24*365*2 {
+		return fmt.Sprintf("%d months", hours/24/30)
+	}
+	return fmt.Sprintf("%d years", int(d.Hours())/24/365)
+}
diff --git a/vendor/github.com/docker/go-units/size.go b/vendor/github.com/docker/go-units/size.go
new file mode 100644
index 000000000..c245a8951
--- /dev/null
+++ b/vendor/github.com/docker/go-units/size.go
@@ -0,0 +1,154 @@
+package units
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// See: http://en.wikipedia.org/wiki/Binary_prefix
+const (
+	// Decimal
+
+	KB = 1000
+	MB = 1000 * KB
+	GB = 1000 * MB
+	TB = 1000 * GB
+	PB = 1000 * TB
+
+	// Binary
+
+	KiB = 1024
+	MiB = 1024 * KiB
+	GiB = 1024 * MiB
+	TiB = 1024 * GiB
+	PiB = 1024 * TiB
+)
+
+type unitMap map[byte]int64
+
+var (
+	decimalMap = unitMap{'k': KB, 'm': MB, 'g': GB, 't': TB, 'p': PB}
+	binaryMap  = unitMap{'k': KiB, 'm': MiB, 'g': GiB, 't': TiB, 'p': PiB}
+)
+
+var (
+	decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
+	binaryAbbrs  = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
+)
+
+func getSizeAndUnit(size float64, base float64, _map []string) (float64, string) {
+	i := 0
+	unitsLimit := len(_map) - 1
+	for size >= base && i < unitsLimit {
+		size = size / base
+		i++
+	}
+	return size, _map[i]
+}
+
+// CustomSize returns a human-readable approximation of a size
+// using custom format.
+func CustomSize(format string, size float64, base float64, _map []string) string {
+	size, unit := getSizeAndUnit(size, base, _map)
+	return fmt.Sprintf(format, size, unit)
+}
+
+// HumanSizeWithPrecision allows the size to be in any precision,
+// instead of 4 digit precision used in units.HumanSize.
+func HumanSizeWithPrecision(size float64, precision int) string {
+	size, unit := getSizeAndUnit(size, 1000.0, decimapAbbrs)
+	return fmt.Sprintf("%.*g%s", precision, size, unit)
+}
+
+// HumanSize returns a human-readable approximation of a size
+// capped at 4 valid numbers (eg. "2.746 MB", "796 KB").
+func HumanSize(size float64) string {
+	return HumanSizeWithPrecision(size, 4)
+}
+
+// BytesSize returns a human-readable size in bytes, kibibytes,
+// mebibytes, gibibytes, or tebibytes (eg. "44kiB", "17MiB").
+func BytesSize(size float64) string {
+	return CustomSize("%.4g%s", size, 1024.0, binaryAbbrs)
+}
+
+// FromHumanSize returns an integer from a human-readable specification of a
+// size using SI standard (eg. "44kB", "17MB").
+func FromHumanSize(size string) (int64, error) {
+	return parseSize(size, decimalMap)
+}
+
+// RAMInBytes parses a human-readable string representing an amount of RAM
+// in bytes, kibibytes, mebibytes, gibibytes, or tebibytes and
+// returns the number of bytes, or -1 if the string is unparseable.
+// Units are case-insensitive, and the 'b' suffix is optional.
+func RAMInBytes(size string) (int64, error) {
+	return parseSize(size, binaryMap)
+}
+
+// Parses the human-readable size string into the amount it represents.
+func parseSize(sizeStr string, uMap unitMap) (int64, error) {
+	// TODO: rewrite to use strings.Cut if there's a space
+	// once Go < 1.18 is deprecated.
+	sep := strings.LastIndexAny(sizeStr, "01234567890. ")
+	if sep == -1 {
+		// There should be at least a digit.
+		return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
+	}
+	var num, sfx string
+	if sizeStr[sep] != ' ' {
+		num = sizeStr[:sep+1]
+		sfx = sizeStr[sep+1:]
+	} else {
+		// Omit the space separator.
+		num = sizeStr[:sep]
+		sfx = sizeStr[sep+1:]
+	}
+
+	size, err := strconv.ParseFloat(num, 64)
+	if err != nil {
+		return -1, err
+	}
+	// Backward compatibility: reject negative sizes.
+	if size < 0 {
+		return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
+	}
+
+	if len(sfx) == 0 {
+		return int64(size), nil
+	}
+
+	// Process the suffix.
+
+	if len(sfx) > 3 { // Too long.
+		goto badSuffix
+	}
+	sfx = strings.ToLower(sfx)
+	// Trivial case: b suffix.
+	if sfx[0] == 'b' {
+		if len(sfx) > 1 { // no extra characters allowed after b.
+			goto badSuffix
+		}
+		return int64(size), nil
+	}
+	// A suffix from the map.
+	if mul, ok := uMap[sfx[0]]; ok {
+		size *= float64(mul)
+	} else {
+		goto badSuffix
+	}
+
+	// The suffix may have extra "b" or "ib" (e.g. KiB or MB).
+	switch {
+	case len(sfx) == 2 && sfx[1] != 'b':
+		goto badSuffix
+	case len(sfx) == 3 && sfx[1:] != "ib":
+		goto badSuffix
+	}
+
+	return int64(size), nil
+
+badSuffix:
+	return -1, fmt.Errorf("invalid suffix: '%s'", sfx)
+}
diff --git a/vendor/github.com/docker/go-units/ulimit.go b/vendor/github.com/docker/go-units/ulimit.go
new file mode 100644
index 000000000..fca0400cc
--- /dev/null
+++ b/vendor/github.com/docker/go-units/ulimit.go
@@ -0,0 +1,123 @@
+package units
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// Ulimit is a human friendly version of Rlimit.
+type Ulimit struct {
+	Name string
+	Hard int64
+	Soft int64
+}
+
+// Rlimit specifies the resource limits, such as max open files.
+type Rlimit struct {
+	Type int    `json:"type,omitempty"`
+	Hard uint64 `json:"hard,omitempty"`
+	Soft uint64 `json:"soft,omitempty"`
+}
+
+const (
+	// magic numbers for making the syscall
+	// some of these are defined in the syscall package, but not all.
+	// Also since Windows client doesn't get access to the syscall package, need to
+	//	define these here
+	rlimitAs         = 9
+	rlimitCore       = 4
+	rlimitCPU        = 0
+	rlimitData       = 2
+	rlimitFsize      = 1
+	rlimitLocks      = 10
+	rlimitMemlock    = 8
+	rlimitMsgqueue   = 12
+	rlimitNice       = 13
+	rlimitNofile     = 7
+	rlimitNproc      = 6
+	rlimitRss        = 5
+	rlimitRtprio     = 14
+	rlimitRttime     = 15
+	rlimitSigpending = 11
+	rlimitStack      = 3
+)
+
+var ulimitNameMapping = map[string]int{
+	//"as":         rlimitAs, // Disabled since this doesn't seem usable with the way Docker inits a container.
+	"core":       rlimitCore,
+	"cpu":        rlimitCPU,
+	"data":       rlimitData,
+	"fsize":      rlimitFsize,
+	"locks":      rlimitLocks,
+	"memlock":    rlimitMemlock,
+	"msgqueue":   rlimitMsgqueue,
+	"nice":       rlimitNice,
+	"nofile":     rlimitNofile,
+	"nproc":      rlimitNproc,
+	"rss":        rlimitRss,
+	"rtprio":     rlimitRtprio,
+	"rttime":     rlimitRttime,
+	"sigpending": rlimitSigpending,
+	"stack":      rlimitStack,
+}
+
+// ParseUlimit parses and returns a Ulimit from the specified string.
+func ParseUlimit(val string) (*Ulimit, error) {
+	parts := strings.SplitN(val, "=", 2)
+	if len(parts) != 2 {
+		return nil, fmt.Errorf("invalid ulimit argument: %s", val)
+	}
+
+	if _, exists := ulimitNameMapping[parts[0]]; !exists {
+		return nil, fmt.Errorf("invalid ulimit type: %s", parts[0])
+	}
+
+	var (
+		soft int64
+		hard = &soft // default to soft in case no hard was set
+		temp int64
+		err  error
+	)
+	switch limitVals := strings.Split(parts[1], ":"); len(limitVals) {
+	case 2:
+		temp, err = strconv.ParseInt(limitVals[1], 10, 64)
+		if err != nil {
+			return nil, err
+		}
+		hard = &temp
+		fallthrough
+	case 1:
+		soft, err = strconv.ParseInt(limitVals[0], 10, 64)
+		if err != nil {
+			return nil, err
+		}
+	default:
+		return nil, fmt.Errorf("too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1])
+	}
+
+	if *hard != -1 {
+		if soft == -1 {
+			return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: soft: -1 (unlimited), hard: %d", *hard)
+		}
+		if soft > *hard {
+			return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, *hard)
+		}
+	}
+
+	return &Ulimit{Name: parts[0], Soft: soft, Hard: *hard}, nil
+}
+
+// GetRlimit returns the RLimit corresponding to Ulimit.
+func (u *Ulimit) GetRlimit() (*Rlimit, error) {
+	t, exists := ulimitNameMapping[u.Name]
+	if !exists {
+		return nil, fmt.Errorf("invalid ulimit name %s", u.Name)
+	}
+
+	return &Rlimit{Type: t, Soft: uint64(u.Soft), Hard: uint64(u.Hard)}, nil
+}
+
+func (u *Ulimit) String() string {
+	return fmt.Sprintf("%s=%d:%d", u.Name, u.Soft, u.Hard)
+}
diff --git a/vendor/github.com/ebitengine/purego/.gitignore b/vendor/github.com/ebitengine/purego/.gitignore
new file mode 100644
index 000000000..b25c15b81
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/vendor/github.com/ebitengine/purego/LICENSE b/vendor/github.com/ebitengine/purego/LICENSE
new file mode 100644
index 000000000..8dada3eda
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   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.
diff --git a/vendor/github.com/ebitengine/purego/README.md b/vendor/github.com/ebitengine/purego/README.md
new file mode 100644
index 000000000..8fb85c2ca
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/README.md
@@ -0,0 +1,119 @@
+# purego
+[![Go Reference](https://pkg.go.dev/badge/github.com/ebitengine/purego?GOOS=darwin.svg)](https://pkg.go.dev/github.com/ebitengine/purego?GOOS=darwin)
+
+A library for calling C functions from Go without Cgo.
+
+> This is beta software so expect bugs and potentially API breaking changes
+> but each release will be tagged to avoid breaking people's code.
+> Bug reports are encouraged.
+
+## Motivation
+
+The [Ebitengine](https://github.com/hajimehoshi/ebiten) game engine was ported to use only Go on Windows. This enabled
+cross-compiling to Windows from any other operating system simply by setting `GOOS=windows`. The purego project was
+born to bring that same vision to the other platforms supported by Ebitengine.
+
+## Benefits
+
+- **Simple Cross-Compilation**: No C means you can build for other platforms easily without a C compiler.
+- **Faster Compilation**: Efficiently cache your entirely Go builds.
+- **Smaller Binaries**: Using Cgo generates a C wrapper function for each C function called. Purego doesn't!
+- **Dynamic Linking**: Load symbols at runtime and use it as a plugin system.
+- **Foreign Function Interface**: Call into other languages that are compiled into shared objects.
+- **Cgo Fallback**: Works even with CGO_ENABLED=1 so incremental porting is possible. 
+This also means unsupported GOARCHs (freebsd/riscv64, linux/mips, etc.) will still work
+except for float arguments and return values.
+
+## Supported Platforms
+
+### Tier 1
+
+Tier 1 platforms are the primary targets officially supported by PureGo. When a new version of PureGo is released, any critical bugs found on Tier 1 platforms are treated as release blockers. The release will be postponed until such issues are resolved.
+
+- **Android**: amd64<sup>1</sup>, arm64<sup>1</sup>
+- **iOS**: amd64<sup>1</sup>, arm64<sup>1</sup>
+- **Linux**: amd64, arm64
+- **macOS**: amd64, arm64
+- **Windows**: amd64, arm64
+
+### Tier 2
+
+Tier 2 platforms are supported by PureGo on a best-effort basis. Critical bugs on Tier 2 platforms do not block new PureGo releases. However, fixes contributed by external contributors are very welcome and encouraged.
+
+- **Android**: 386<sup>1</sup>, arm<sup>1</sup>
+- **FreeBSD**: amd64<sup>2</sup>, arm64<sup>2</sup>
+- **Linux**: 386, arm, loong64, ppc64le, riscv64, s390x<sup>1</sup>
+- **Windows**: 386<sup>3</sup>, arm<sup>3,4</sup>
+
+#### Support Notes
+
+1. These architectures require CGO_ENABLED=1 to compile
+2. These architectures require the special flag `-gcflags="github.com/ebitengine/purego/internal/fakecgo=-std"` to compile with CGO_ENABLED=0
+3. These architectures only support `SyscallN` and `NewCallback`
+4. These architectures are no longer supported as of Go 1.26
+
+## Example
+
+The example below only showcases purego use for macOS and Linux. The other platforms require special handling which can
+be seen in the complete example at [examples/libc](https://github.com/ebitengine/purego/tree/main/examples/libc) which supports FreeBSD and Windows.
+
+```go
+package main
+
+import (
+	"fmt"
+	"runtime"
+
+	"github.com/ebitengine/purego"
+)
+
+func getSystemLibrary() string {
+	switch runtime.GOOS {
+	case "darwin":
+		return "/usr/lib/libSystem.B.dylib"
+	case "linux":
+		return "libc.so.6"
+	default:
+		panic(fmt.Errorf("GOOS=%s is not supported", runtime.GOOS))
+	}
+}
+
+func main() {
+	libc, err := purego.Dlopen(getSystemLibrary(), purego.RTLD_NOW|purego.RTLD_GLOBAL)
+	if err != nil {
+		panic(err)
+	}
+	var puts func(string)
+	purego.RegisterLibFunc(&puts, libc, "puts")
+	puts("Calling C from Go without Cgo!")
+}
+```
+
+Then to run: `CGO_ENABLED=0 go run main.go`
+
+## Questions
+
+If you have questions about how to incorporate purego in your project or want to discuss
+how it works join the [Discord](https://discord.gg/HzGZVD6BkY)!
+
+### External Code
+
+Purego uses code that originates from the Go runtime. These files are under the BSD-3
+License that can be found [in the Go Source](https://github.com/golang/go/blob/master/LICENSE).
+This is a list of the copied files:
+
+* `abi_*.h` from package `runtime/cgo`
+* `wincallback.go` from package `runtime`
+* `zcallback_darwin_*.s` from package `runtime`
+* `internal/fakecgo/abi_*.h` from package `runtime/cgo`
+* `internal/fakecgo/asm_GOARCH.s` from package `runtime/cgo`
+* `internal/fakecgo/callbacks.go` from package `runtime/cgo`
+* `internal/fakecgo/iscgo.go` from package `runtime/cgo`
+* `internal/fakecgo/setenv.go` from package `runtime/cgo`
+* `internal/fakecgo/freebsd.go` from package `runtime/cgo`
+* `internal/fakecgo/netbsd.go` from package `runtime/cgo`
+
+The `internal/fakecgo/go_GOOS.go` files were modified from `runtime/cgo/gcc_GOOS_GOARCH.go`.
+
+The files `abi_*.h` and `internal/fakecgo/abi_*.h` are the same because Bazel does not support cross-package use of
+`#include` so we need each one once per package. (cf. [issue](https://github.com/bazelbuild/rules_go/issues/3636))
diff --git a/vendor/github.com/ebitengine/purego/abi_amd64.h b/vendor/github.com/ebitengine/purego/abi_amd64.h
new file mode 100644
index 000000000..9949435fe
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/abi_amd64.h
@@ -0,0 +1,99 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These save the frame pointer, so in general, functions that use
+// these should have zero frame size to suppress the automatic frame
+// pointer, though it's harmless to not do this.
+
+#ifdef GOOS_windows
+
+// REGS_HOST_TO_ABI0_STACK is the stack bytes used by
+// PUSH_REGS_HOST_TO_ABI0.
+#define REGS_HOST_TO_ABI0_STACK (28*8 + 8)
+
+// PUSH_REGS_HOST_TO_ABI0 prepares for transitioning from
+// the host ABI to Go ABI0 code. It saves all registers that are
+// callee-save in the host ABI and caller-save in Go ABI0 and prepares
+// for entry to Go.
+//
+// Save DI SI BP BX R12 R13 R14 R15 X6-X15 registers and the DF flag.
+// Clear the DF flag for the Go ABI.
+// MXCSR matches the Go ABI, so we don't have to set that,
+// and Go doesn't modify it, so we don't have to save it.
+#define PUSH_REGS_HOST_TO_ABI0()	\
+	PUSHFQ			\
+	CLD			\
+	ADJSP	$(REGS_HOST_TO_ABI0_STACK - 8)	\
+	MOVQ	DI, (0*0)(SP)	\
+	MOVQ	SI, (1*8)(SP)	\
+	MOVQ	BP, (2*8)(SP)	\
+	MOVQ	BX, (3*8)(SP)	\
+	MOVQ	R12, (4*8)(SP)	\
+	MOVQ	R13, (5*8)(SP)	\
+	MOVQ	R14, (6*8)(SP)	\
+	MOVQ	R15, (7*8)(SP)	\
+	MOVUPS	X6, (8*8)(SP)	\
+	MOVUPS	X7, (10*8)(SP)	\
+	MOVUPS	X8, (12*8)(SP)	\
+	MOVUPS	X9, (14*8)(SP)	\
+	MOVUPS	X10, (16*8)(SP)	\
+	MOVUPS	X11, (18*8)(SP)	\
+	MOVUPS	X12, (20*8)(SP)	\
+	MOVUPS	X13, (22*8)(SP)	\
+	MOVUPS	X14, (24*8)(SP)	\
+	MOVUPS	X15, (26*8)(SP)
+
+#define POP_REGS_HOST_TO_ABI0()	\
+	MOVQ	(0*0)(SP), DI	\
+	MOVQ	(1*8)(SP), SI	\
+	MOVQ	(2*8)(SP), BP	\
+	MOVQ	(3*8)(SP), BX	\
+	MOVQ	(4*8)(SP), R12	\
+	MOVQ	(5*8)(SP), R13	\
+	MOVQ	(6*8)(SP), R14	\
+	MOVQ	(7*8)(SP), R15	\
+	MOVUPS	(8*8)(SP), X6	\
+	MOVUPS	(10*8)(SP), X7	\
+	MOVUPS	(12*8)(SP), X8	\
+	MOVUPS	(14*8)(SP), X9	\
+	MOVUPS	(16*8)(SP), X10	\
+	MOVUPS	(18*8)(SP), X11	\
+	MOVUPS	(20*8)(SP), X12	\
+	MOVUPS	(22*8)(SP), X13	\
+	MOVUPS	(24*8)(SP), X14	\
+	MOVUPS	(26*8)(SP), X15	\
+	ADJSP	$-(REGS_HOST_TO_ABI0_STACK - 8)	\
+	POPFQ
+
+#else
+// SysV ABI
+
+#define REGS_HOST_TO_ABI0_STACK (6*8)
+
+// SysV MXCSR matches the Go ABI, so we don't have to set that,
+// and Go doesn't modify it, so we don't have to save it.
+// Both SysV and Go require DF to be cleared, so that's already clear.
+// The SysV and Go frame pointer conventions are compatible.
+#define PUSH_REGS_HOST_TO_ABI0()	\
+	ADJSP	$(REGS_HOST_TO_ABI0_STACK)	\
+	MOVQ	BP, (5*8)(SP)	\
+	LEAQ	(5*8)(SP), BP	\
+	MOVQ	BX, (0*8)(SP)	\
+	MOVQ	R12, (1*8)(SP)	\
+	MOVQ	R13, (2*8)(SP)	\
+	MOVQ	R14, (3*8)(SP)	\
+	MOVQ	R15, (4*8)(SP)
+
+#define POP_REGS_HOST_TO_ABI0()	\
+	MOVQ	(0*8)(SP), BX	\
+	MOVQ	(1*8)(SP), R12	\
+	MOVQ	(2*8)(SP), R13	\
+	MOVQ	(3*8)(SP), R14	\
+	MOVQ	(4*8)(SP), R15	\
+	MOVQ	(5*8)(SP), BP	\
+	ADJSP	$-(REGS_HOST_TO_ABI0_STACK)
+
+#endif
diff --git a/vendor/github.com/ebitengine/purego/abi_arm64.h b/vendor/github.com/ebitengine/purego/abi_arm64.h
new file mode 100644
index 000000000..5d5061ec1
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/abi_arm64.h
@@ -0,0 +1,39 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These macros save and restore the callee-saved registers
+// from the stack, but they don't adjust stack pointer, so
+// the user should prepare stack space in advance.
+// SAVE_R19_TO_R28(offset) saves R19 ~ R28 to the stack space
+// of ((offset)+0*8)(RSP) ~ ((offset)+9*8)(RSP).
+//
+// SAVE_F8_TO_F15(offset) saves F8 ~ F15 to the stack space
+// of ((offset)+0*8)(RSP) ~ ((offset)+7*8)(RSP).
+//
+// R29 is not saved because Go will save and restore it.
+
+#define SAVE_R19_TO_R28(offset) \
+	STP	(R19, R20), ((offset)+0*8)(RSP) \
+	STP	(R21, R22), ((offset)+2*8)(RSP) \
+	STP	(R23, R24), ((offset)+4*8)(RSP) \
+	STP	(R25, R26), ((offset)+6*8)(RSP) \
+	STP	(R27, g), ((offset)+8*8)(RSP)
+#define RESTORE_R19_TO_R28(offset) \
+	LDP	((offset)+0*8)(RSP), (R19, R20) \
+	LDP	((offset)+2*8)(RSP), (R21, R22) \
+	LDP	((offset)+4*8)(RSP), (R23, R24) \
+	LDP	((offset)+6*8)(RSP), (R25, R26) \
+	LDP	((offset)+8*8)(RSP), (R27, g) /* R28 */
+#define SAVE_F8_TO_F15(offset) \
+	FSTPD	(F8, F9), ((offset)+0*8)(RSP) \
+	FSTPD	(F10, F11), ((offset)+2*8)(RSP) \
+	FSTPD	(F12, F13), ((offset)+4*8)(RSP) \
+	FSTPD	(F14, F15), ((offset)+6*8)(RSP)
+#define RESTORE_F8_TO_F15(offset) \
+	FLDPD	((offset)+0*8)(RSP), (F8, F9) \
+	FLDPD	((offset)+2*8)(RSP), (F10, F11) \
+	FLDPD	((offset)+4*8)(RSP), (F12, F13) \
+	FLDPD	((offset)+6*8)(RSP), (F14, F15)
diff --git a/vendor/github.com/ebitengine/purego/abi_loong64.h b/vendor/github.com/ebitengine/purego/abi_loong64.h
new file mode 100644
index 000000000..b10d83732
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/abi_loong64.h
@@ -0,0 +1,60 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These macros save and restore the callee-saved registers
+// from the stack, but they don't adjust stack pointer, so
+// the user should prepare stack space in advance.
+// SAVE_R22_TO_R31(offset) saves R22 ~ R31 to the stack space
+// of ((offset)+0*8)(R3) ~ ((offset)+9*8)(R3).
+//
+// SAVE_F24_TO_F31(offset) saves F24 ~ F31 to the stack space
+// of ((offset)+0*8)(R3) ~ ((offset)+7*8)(R3).
+//
+// Note: g is R22
+
+#define SAVE_R22_TO_R31(offset)	\
+	MOVV	g,   ((offset)+(0*8))(R3)	\
+	MOVV	R23, ((offset)+(1*8))(R3)	\
+	MOVV	R24, ((offset)+(2*8))(R3)	\
+	MOVV	R25, ((offset)+(3*8))(R3)	\
+	MOVV	R26, ((offset)+(4*8))(R3)	\
+	MOVV	R27, ((offset)+(5*8))(R3)	\
+	MOVV	R28, ((offset)+(6*8))(R3)	\
+	MOVV	R29, ((offset)+(7*8))(R3)	\
+	MOVV	R30, ((offset)+(8*8))(R3)	\
+	MOVV	R31, ((offset)+(9*8))(R3)
+
+#define SAVE_F24_TO_F31(offset)	\
+	MOVD	F24, ((offset)+(0*8))(R3)	\
+	MOVD	F25, ((offset)+(1*8))(R3)	\
+	MOVD	F26, ((offset)+(2*8))(R3)	\
+	MOVD	F27, ((offset)+(3*8))(R3)	\
+	MOVD	F28, ((offset)+(4*8))(R3)	\
+	MOVD	F29, ((offset)+(5*8))(R3)	\
+	MOVD	F30, ((offset)+(6*8))(R3)	\
+	MOVD	F31, ((offset)+(7*8))(R3)
+
+#define RESTORE_R22_TO_R31(offset)	\
+	MOVV	((offset)+(0*8))(R3),  g	\
+	MOVV	((offset)+(1*8))(R3), R23	\
+	MOVV	((offset)+(2*8))(R3), R24	\
+	MOVV	((offset)+(3*8))(R3), R25	\
+	MOVV	((offset)+(4*8))(R3), R26	\
+	MOVV	((offset)+(5*8))(R3), R27	\
+	MOVV	((offset)+(6*8))(R3), R28	\
+	MOVV	((offset)+(7*8))(R3), R29	\
+	MOVV	((offset)+(8*8))(R3), R30	\
+	MOVV	((offset)+(9*8))(R3), R31
+
+#define RESTORE_F24_TO_F31(offset)	\
+	MOVD	((offset)+(0*8))(R3), F24	\
+	MOVD	((offset)+(1*8))(R3), F25	\
+	MOVD	((offset)+(2*8))(R3), F26	\
+	MOVD	((offset)+(3*8))(R3), F27	\
+	MOVD	((offset)+(4*8))(R3), F28	\
+	MOVD	((offset)+(5*8))(R3), F29	\
+	MOVD	((offset)+(6*8))(R3), F30	\
+	MOVD	((offset)+(7*8))(R3), F31
diff --git a/vendor/github.com/ebitengine/purego/cgo.go b/vendor/github.com/ebitengine/purego/cgo.go
new file mode 100644
index 000000000..b6def570c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/cgo.go
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build cgo && (darwin || freebsd || linux || netbsd)
+
+package purego
+
+// if CGO_ENABLED=1 import the Cgo runtime to ensure that it is set up properly.
+// This is required since some frameworks need TLS setup the C way which Go doesn't do.
+// We currently don't support ios in fakecgo mode so force Cgo or fail.
+// Even if CGO_ENABLED=1 the Cgo runtime is not imported unless `import "C"` is used,
+// which will import this package automatically. Normally this isn't an issue since it
+// usually isn't possible to call into C without using that import. However, with purego
+// it is since we don't use `import "C"`!
+import (
+	_ "runtime/cgo"
+
+	_ "github.com/ebitengine/purego/internal/cgo"
+)
diff --git a/vendor/github.com/ebitengine/purego/dlerror.go b/vendor/github.com/ebitengine/purego/dlerror.go
new file mode 100644
index 000000000..ad52b436c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlerror.go
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2023 The Ebitengine Authors
+
+//go:build darwin || freebsd || linux || netbsd
+
+package purego
+
+// Dlerror represents an error value returned from Dlopen, Dlsym, or Dlclose.
+//
+// This type is not available on Windows as there is no counterpart to it on Windows.
+type Dlerror struct {
+	s string
+}
+
+func (e Dlerror) Error() string {
+	return e.s
+}
diff --git a/vendor/github.com/ebitengine/purego/dlfcn.go b/vendor/github.com/ebitengine/purego/dlfcn.go
new file mode 100644
index 000000000..2730d82cd
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn.go
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build (darwin || freebsd || linux || netbsd) && !android && !faketime
+
+package purego
+
+import (
+	"unsafe"
+)
+
+// Unix Specification for dlfcn.h: https://pubs.opengroup.org/onlinepubs/7908799/xsh/dlfcn.h.html
+
+var (
+	fnDlopen  func(path string, mode int) uintptr
+	fnDlsym   func(handle uintptr, name string) uintptr
+	fnDlerror func() string
+	fnDlclose func(handle uintptr) bool
+)
+
+func init() {
+	RegisterFunc(&fnDlopen, dlopenABI0)
+	RegisterFunc(&fnDlsym, dlsymABI0)
+	RegisterFunc(&fnDlerror, dlerrorABI0)
+	RegisterFunc(&fnDlclose, dlcloseABI0)
+}
+
+// Dlopen examines the dynamic library or bundle file specified by path. If the file is compatible
+// with the current process and has not already been loaded into the
+// current process, it is loaded and linked. After being linked, if it contains
+// any initializer functions, they are called, before Dlopen
+// returns. It returns a handle that can be used with Dlsym and Dlclose.
+// A second call to Dlopen with the same path will return the same handle, but the internal
+// reference count for the handle will be incremented. Therefore, all
+// Dlopen calls should be balanced with a Dlclose call.
+//
+// This function is not available on Windows.
+// Use [golang.org/x/sys/windows.LoadLibrary], [golang.org/x/sys/windows.LoadLibraryEx],
+// [golang.org/x/sys/windows.NewLazyDLL], or [golang.org/x/sys/windows.NewLazySystemDLL] for Windows instead.
+func Dlopen(path string, mode int) (uintptr, error) {
+	u := fnDlopen(path, mode)
+	if u == 0 {
+		return 0, Dlerror{fnDlerror()}
+	}
+	return u, nil
+}
+
+// Dlsym takes a "handle" of a dynamic library returned by Dlopen and the symbol name.
+// It returns the address where that symbol is loaded into memory. If the symbol is not found,
+// in the specified library or any of the libraries that were automatically loaded by Dlopen
+// when that library was loaded, Dlsym returns zero.
+//
+// This function is not available on Windows.
+// Use [golang.org/x/sys/windows.GetProcAddress] for Windows instead.
+func Dlsym(handle uintptr, name string) (uintptr, error) {
+	u := fnDlsym(handle, name)
+	if u == 0 {
+		return 0, Dlerror{fnDlerror()}
+	}
+	return u, nil
+}
+
+// Dlclose decrements the reference count on the dynamic library handle.
+// If the reference count drops to zero and no other loaded libraries
+// use symbols in it, then the dynamic library is unloaded.
+//
+// This function is not available on Windows.
+// Use [golang.org/x/sys/windows.FreeLibrary] for Windows instead.
+func Dlclose(handle uintptr) error {
+	if fnDlclose(handle) {
+		return Dlerror{fnDlerror()}
+	}
+	return nil
+}
+
+func loadSymbol(handle uintptr, name string) (uintptr, error) {
+	return Dlsym(handle, name)
+}
+
+// these functions exist in dlfcn_stubs.s and are calling C functions linked to in dlfcn_GOOS.go
+// the indirection is necessary because a function is actually a pointer to the pointer to the code.
+// sadly, I do not know of anyway to remove the assembly stubs entirely because //go:linkname doesn't
+// appear to work if you link directly to the C function on darwin arm64.
+
+//go:linkname dlopen dlopen
+var dlopen uint8
+var dlopenABI0 = uintptr(unsafe.Pointer(&dlopen))
+
+//go:linkname dlsym dlsym
+var dlsym uint8
+var dlsymABI0 = uintptr(unsafe.Pointer(&dlsym))
+
+//go:linkname dlclose dlclose
+var dlclose uint8
+var dlcloseABI0 = uintptr(unsafe.Pointer(&dlclose))
+
+//go:linkname dlerror dlerror
+var dlerror uint8
+var dlerrorABI0 = uintptr(unsafe.Pointer(&dlerror))
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_android.go b/vendor/github.com/ebitengine/purego/dlfcn_android.go
new file mode 100644
index 000000000..0d5341764
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_android.go
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
+
+package purego
+
+import "github.com/ebitengine/purego/internal/cgo"
+
+// Source for constants: https://android.googlesource.com/platform/bionic/+/refs/heads/main/libc/include/dlfcn.h
+
+const (
+	is64bit      = 1 << (^uintptr(0) >> 63) / 2
+	is32bit      = 1 - is64bit
+	RTLD_DEFAULT = is32bit * 0xffffffff
+	RTLD_LAZY    = 0x00000001
+	RTLD_NOW     = is64bit * 0x00000002
+	RTLD_LOCAL   = 0x00000000
+	RTLD_GLOBAL  = is64bit*0x00100 | is32bit*0x00000002
+)
+
+func Dlopen(path string, mode int) (uintptr, error) {
+	return cgo.Dlopen(path, mode)
+}
+
+func Dlsym(handle uintptr, name string) (uintptr, error) {
+	return cgo.Dlsym(handle, name)
+}
+
+func Dlclose(handle uintptr) error {
+	return cgo.Dlclose(handle)
+}
+
+func loadSymbol(handle uintptr, name string) (uintptr, error) {
+	return Dlsym(handle, name)
+}
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_darwin.go b/vendor/github.com/ebitengine/purego/dlfcn_darwin.go
new file mode 100644
index 000000000..5dd44468d
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_darwin.go
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+package purego
+
+// Source for constants: https://opensource.apple.com/source/dyld/dyld-360.14/include/dlfcn.h.auto.html
+
+const (
+	RTLD_DEFAULT = 1<<64 - 2 // Pseudo-handle for dlsym so search for any loaded symbol
+	RTLD_LAZY    = 0x1       // Relocations are performed at an implementation-dependent time.
+	RTLD_NOW     = 0x2       // Relocations are performed when the object is loaded.
+	RTLD_LOCAL   = 0x4       // All symbols are not made available for relocation processing by other modules.
+	RTLD_GLOBAL  = 0x8       // All symbols are available for relocation processing of other modules.
+)
+
+//go:cgo_import_dynamic purego_dlopen dlopen "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_dlsym dlsym "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_dlerror dlerror "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_dlclose dlclose "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_error __error "/usr/lib/libSystem.B.dylib"
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_freebsd.go b/vendor/github.com/ebitengine/purego/dlfcn_freebsd.go
new file mode 100644
index 000000000..6b371620d
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_freebsd.go
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+package purego
+
+// Constants as defined in https://github.com/freebsd/freebsd-src/blob/main/include/dlfcn.h
+const (
+	intSize      = 32 << (^uint(0) >> 63) // 32 or 64
+	RTLD_DEFAULT = 1<<intSize - 2         // Pseudo-handle for dlsym so search for any loaded symbol
+	RTLD_LAZY    = 0x00000001             // Relocations are performed at an implementation-dependent time.
+	RTLD_NOW     = 0x00000002             // Relocations are performed when the object is loaded.
+	RTLD_LOCAL   = 0x00000000             // All symbols are not made available for relocation processing by other modules.
+	RTLD_GLOBAL  = 0x00000100             // All symbols are available for relocation processing of other modules.
+)
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_linux.go b/vendor/github.com/ebitengine/purego/dlfcn_linux.go
new file mode 100644
index 000000000..879f59592
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_linux.go
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !android
+
+package purego
+
+// Source for constants: https://codebrowser.dev/glibc/glibc/bits/dlfcn.h.html
+
+const (
+	RTLD_DEFAULT = 0x00000 // Pseudo-handle for dlsym so search for any loaded symbol
+	RTLD_LAZY    = 0x00001 // Relocations are performed at an implementation-dependent time.
+	RTLD_NOW     = 0x00002 // Relocations are performed when the object is loaded.
+	RTLD_LOCAL   = 0x00000 // All symbols are not made available for relocation processing by other modules.
+	RTLD_GLOBAL  = 0x00100 // All symbols are available for relocation processing of other modules.
+)
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_netbsd.go b/vendor/github.com/ebitengine/purego/dlfcn_netbsd.go
new file mode 100644
index 000000000..220c73676
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_netbsd.go
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+package purego
+
+// Source for constants: https://github.com/NetBSD/src/blob/trunk/include/dlfcn.h
+
+const (
+	intSize      = 32 << (^uint(0) >> 63) // 32 or 64
+	RTLD_DEFAULT = 1<<intSize - 2         // Pseudo-handle for dlsym so search for any loaded symbol
+	RTLD_LAZY    = 0x00000001             // Relocations are performed at an implementation-dependent time.
+	RTLD_NOW     = 0x00000002             // Relocations are performed when the object is loaded.
+	RTLD_LOCAL   = 0x00000000             // All symbols are not made available for relocation processing by other modules.
+	RTLD_GLOBAL  = 0x00000100             // All symbols are available for relocation processing of other modules.
+)
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_nocgo_freebsd.go b/vendor/github.com/ebitengine/purego/dlfcn_nocgo_freebsd.go
new file mode 100644
index 000000000..1bd66125b
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_nocgo_freebsd.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package purego
+
+//go:cgo_import_dynamic purego_dlopen dlopen "libc.so.7"
+//go:cgo_import_dynamic purego_dlsym dlsym "libc.so.7"
+//go:cgo_import_dynamic purego_dlerror dlerror "libc.so.7"
+//go:cgo_import_dynamic purego_dlclose dlclose "libc.so.7"
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_nocgo_linux.go b/vendor/github.com/ebitengine/purego/dlfcn_nocgo_linux.go
new file mode 100644
index 000000000..29b974441
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_nocgo_linux.go
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && !faketime
+
+package purego
+
+// if there is no Cgo we must link to each of the functions from dlfcn.h
+// then the functions are called inside dlfcn_stubs.s
+
+//go:cgo_import_dynamic purego_dlopen dlopen "libdl.so.2"
+//go:cgo_import_dynamic purego_dlsym dlsym "libdl.so.2"
+//go:cgo_import_dynamic purego_dlerror dlerror "libdl.so.2"
+//go:cgo_import_dynamic purego_dlclose dlclose "libdl.so.2"
+
+// on amd64 we don't need the following line - on 386 we do...
+// anyway - with those lines the output is better (but doesn't matter) - without it on amd64 we get multiple DT_NEEDED with "libc.so.6" etc
+
+//go:cgo_import_dynamic _ _ "libdl.so.2"
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_nocgo_netbsd.go b/vendor/github.com/ebitengine/purego/dlfcn_nocgo_netbsd.go
new file mode 100644
index 000000000..468f48419
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_nocgo_netbsd.go
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+package purego
+
+//go:cgo_import_dynamic purego_dlopen dlopen "libc.so"
+//go:cgo_import_dynamic purego_dlsym dlsym "libc.so"
+//go:cgo_import_dynamic purego_dlerror dlerror "libc.so"
+//go:cgo_import_dynamic purego_dlclose dlclose "libc.so"
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_playground.go b/vendor/github.com/ebitengine/purego/dlfcn_playground.go
new file mode 100644
index 000000000..793f900fd
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_playground.go
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
+
+//go:build faketime
+
+package purego
+
+import "errors"
+
+func Dlopen(path string, mode int) (uintptr, error) {
+	return 0, errors.New("Dlopen is not supported in the playground")
+}
+
+func Dlsym(handle uintptr, name string) (uintptr, error) {
+	return 0, errors.New("Dlsym is not supported in the playground")
+}
+
+func Dlclose(handle uintptr) error {
+	return errors.New("Dlclose is not supported in the playground")
+}
+
+func loadSymbol(handle uintptr, name string) (uintptr, error) {
+	return Dlsym(handle, name)
+}
diff --git a/vendor/github.com/ebitengine/purego/dlfcn_stubs.s b/vendor/github.com/ebitengine/purego/dlfcn_stubs.s
new file mode 100644
index 000000000..801e74674
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/dlfcn_stubs.s
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build darwin || !cgo && (freebsd || linux || netbsd) && !faketime
+
+#include "textflag.h"
+
+// func dlopen(path *byte, mode int) (ret uintptr)
+TEXT dlopen(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_dlopen(SB)
+
+// func dlsym(handle uintptr, symbol *byte) (ret uintptr)
+TEXT dlsym(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_dlsym(SB)
+
+// func dlerror() (ret *byte)
+TEXT dlerror(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_dlerror(SB)
+
+// func dlclose(handle uintptr) (ret int)
+TEXT dlclose(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_dlclose(SB)
diff --git a/vendor/github.com/ebitengine/purego/func.go b/vendor/github.com/ebitengine/purego/func.go
new file mode 100644
index 000000000..0da2c2691
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/func.go
@@ -0,0 +1,571 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build darwin || freebsd || linux || netbsd || windows
+
+package purego
+
+import (
+	"fmt"
+	"math"
+	"reflect"
+	"runtime"
+	"sync"
+	"unsafe"
+
+	"github.com/ebitengine/purego/internal/strings"
+	"github.com/ebitengine/purego/internal/xreflect"
+)
+
+const (
+	align8ByteMask = 7 // Mask for 8-byte alignment: (val + 7) &^ 7
+	align8ByteSize = 8 // 8-byte alignment boundary
+)
+
+var thePool = sync.Pool{New: func() any {
+	return new(syscall15Args)
+}}
+
+// RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name).
+// It panics if it can't find the name symbol.
+func RegisterLibFunc(fptr any, handle uintptr, name string) {
+	sym, err := loadSymbol(handle, name)
+	if err != nil {
+		panic(err)
+	}
+	RegisterFunc(fptr, sym)
+}
+
+// RegisterFunc takes a pointer to a Go function representing the calling convention of the C function.
+// fptr will be set to a function that when called will call the C function given by cfn with the
+// parameters passed in the correct registers and stack.
+//
+// A panic is produced if the type is not a function pointer or if the function returns more than 1 value.
+//
+// These conversions describe how a Go type in the fptr will be used to call
+// the C function. It is important to note that there is no way to verify that fptr
+// matches the C function. This also holds true for struct types where the padding
+// needs to be ensured to match that of C; RegisterFunc does not verify this.
+//
+// # Type Conversions (Go <=> C)
+//
+//	string <=> char*
+//	bool <=> _Bool
+//	uintptr <=> uintptr_t
+//	uint <=> uint32_t or uint64_t
+//	uint8 <=> uint8_t
+//	uint16 <=> uint16_t
+//	uint32 <=> uint32_t
+//	uint64 <=> uint64_t
+//	int <=> int32_t or int64_t
+//	int8 <=> int8_t
+//	int16 <=> int16_t
+//	int32 <=> int32_t
+//	int64 <=> int64_t
+//	float32 <=> float
+//	float64 <=> double
+//	struct <=> struct (darwin amd64/arm64, linux amd64/arm64)
+//	func <=> C function
+//	unsafe.Pointer, *T <=> void*
+//	[]T => void*
+//
+// There is a special case when the last argument of fptr is a variadic interface (or []interface}
+// it will be expanded into a call to the C function as if it had the arguments in that slice.
+// This means that using arg ...any is like a cast to the function with the arguments inside arg.
+// This is not the same as C variadic.
+//
+// # Memory
+//
+// In general it is not possible for purego to guarantee the lifetimes of objects returned or received from
+// calling functions using RegisterFunc. For arguments to a C function it is important that the C function doesn't
+// hold onto a reference to Go memory. This is the same as the [Cgo rules].
+//
+// However, there are some special cases. When passing a string as an argument if the string does not end in a null
+// terminated byte (\x00) then the string will be copied into memory maintained by purego. The memory is only valid for
+// that specific call. Therefore, if the C code keeps a reference to that string it may become invalid at some
+// undefined time. However, if the string does already contain a null-terminated byte then no copy is done.
+// It is then the responsibility of the caller to ensure the string stays alive as long as it's needed in C memory.
+// This can be done using runtime.KeepAlive or allocating the string in C memory using malloc. When a C function
+// returns a null-terminated pointer to char a Go string can be used. Purego will allocate a new string in Go memory
+// and copy the data over. This string will be garbage collected whenever Go decides it's no longer referenced.
+// This C created string will not be freed by purego. If the pointer to char is not null-terminated or must continue
+// to point to C memory (because it's a buffer for example) then use a pointer to byte and then convert that to a slice
+// using unsafe.Slice. Doing this means that it becomes the responsibility of the caller to care about the lifetime
+// of the pointer
+//
+// # Structs
+//
+// Purego can handle the most common structs that have fields of builtin types like int8, uint16, float32, etc. However,
+// it does not support aligning fields properly. It is therefore the responsibility of the caller to ensure
+// that all padding is added to the Go struct to match the C one. See `BoolStructFn` in struct_test.go for an example.
+//
+// On Darwin ARM64, purego handles proper alignment of struct arguments when passing them on the stack,
+// following the C ABI's byte-level packing rules.
+//
+// # Example
+//
+// All functions below call this C function:
+//
+//	char *foo(char *str);
+//
+//	// Let purego convert types
+//	var foo func(s string) string
+//	goString := foo("copied")
+//	// Go will garbage collect this string
+//
+//	// Manually, handle allocations
+//	var foo2 func(b string) *byte
+//	mustFree := foo2("not copied\x00")
+//	defer free(mustFree)
+//
+// [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C
+func RegisterFunc(fptr any, cfn uintptr) {
+	const is32bit = unsafe.Sizeof(uintptr(0)) == 4
+	fn := reflect.ValueOf(fptr).Elem()
+	ty := fn.Type()
+	if ty.Kind() != reflect.Func {
+		panic("purego: fptr must be a function pointer")
+	}
+	if ty.NumOut() > 1 {
+		panic("purego: function can only return zero or one values")
+	}
+	if cfn == 0 {
+		panic("purego: cfn is nil")
+	}
+	if ty.NumOut() == 1 && (ty.Out(0).Kind() == reflect.Float32 || ty.Out(0).Kind() == reflect.Float64) &&
+		runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" && runtime.GOARCH != "386" && runtime.GOARCH != "amd64" && runtime.GOARCH != "loong64" && runtime.GOARCH != "ppc64le" && runtime.GOARCH != "riscv64" && runtime.GOARCH != "s390x" {
+		panic("purego: float returns are not supported")
+	}
+	{
+		// this code checks how many registers and stack this function will use
+		// to avoid crashing with too many arguments
+		var ints int
+		var floats int
+		var stack int
+		for i := 0; i < ty.NumIn(); i++ {
+			arg := ty.In(i)
+			switch arg.Kind() {
+			case reflect.Func:
+				// This only does preliminary testing to ensure the CDecl argument
+				// is the first argument. Full testing is done when the callback is actually
+				// created in NewCallback.
+				for j := 0; j < arg.NumIn(); j++ {
+					in := arg.In(j)
+					if !in.AssignableTo(reflect.TypeOf(CDecl{})) {
+						continue
+					}
+					if j != 0 {
+						panic("purego: CDecl must be the first argument")
+					}
+				}
+			case reflect.String, reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+				reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Ptr, reflect.UnsafePointer,
+				reflect.Slice, reflect.Bool:
+				if ints < numOfIntegerRegisters() {
+					ints++
+				} else {
+					stack++
+				}
+			case reflect.Float32, reflect.Float64:
+				if floats < numOfFloatRegisters() {
+					floats++
+				} else {
+					stack++
+				}
+			case reflect.Struct:
+				ensureStructSupportedForRegisterFunc()
+				if arg.Size() == 0 {
+					continue
+				}
+				addInt := func(u uintptr) {
+					ints++
+				}
+				addFloat := func(u uintptr) {
+					floats++
+				}
+				addStack := func(u uintptr) {
+					stack++
+				}
+				_ = addStruct(reflect.New(arg).Elem(), &ints, &floats, &stack, addInt, addFloat, addStack, nil)
+			default:
+				panic("purego: unsupported kind " + arg.Kind().String())
+			}
+		}
+		if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
+			ensureStructSupportedForRegisterFunc()
+			outType := ty.Out(0)
+			checkStructFieldsSupported(outType)
+			if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize {
+				// on amd64 if struct is bigger than 16 bytes allocate the return struct
+				// and pass it in as a hidden first argument.
+				ints++
+			}
+		}
+
+		sizeOfStack := maxArgs - numOfIntegerRegisters()
+		// On Darwin ARM64, use byte-based validation since arguments pack efficiently.
+		// See https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms
+		if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+			stackBytes := estimateStackBytes(ty)
+			maxStackBytes := sizeOfStack * 8
+			if stackBytes > maxStackBytes {
+				panic("purego: too many stack arguments")
+			}
+		} else {
+			if stack > sizeOfStack {
+				panic("purego: too many stack arguments")
+			}
+		}
+	}
+
+	v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) {
+		var sysargs [maxArgs]uintptr
+		// Use maxArgs instead of numOfFloatRegisters() to keep this code path allocation-free,
+		// since numOfFloatRegisters() is a function call, not a constant.
+		// maxArgs is always greater than or equal to numOfFloatRegisters() so this is safe.
+		var floats [maxArgs]uintptr
+		var numInts int
+		var numFloats int
+		var numStack int
+		var addStack, addInt, addFloat func(x uintptr)
+		if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
+			// Windows arm64 uses the same calling convention as macOS and Linux
+			addStack = func(x uintptr) {
+				sysargs[numOfIntegerRegisters()+numStack] = x
+				numStack++
+			}
+			addInt = func(x uintptr) {
+				if numInts >= numOfIntegerRegisters() {
+					addStack(x)
+				} else {
+					sysargs[numInts] = x
+					numInts++
+				}
+			}
+			addFloat = func(x uintptr) {
+				if numFloats < numOfFloatRegisters() {
+					floats[numFloats] = x
+					numFloats++
+				} else {
+					addStack(x)
+				}
+			}
+		} else {
+			// On Windows amd64 the arguments are passed in the numbered registered.
+			// So the first int is in the first integer register and the first float
+			// is in the second floating register if there is already a first int.
+			// This is in contrast to how macOS and Linux pass arguments which
+			// tries to use as many registers as possible in the calling convention.
+			addStack = func(x uintptr) {
+				sysargs[numStack] = x
+				numStack++
+			}
+			addInt = addStack
+			addFloat = addStack
+		}
+
+		var keepAlive []any
+		defer func() {
+			runtime.KeepAlive(keepAlive)
+			runtime.KeepAlive(args)
+		}()
+
+		var arm64_r8 uintptr
+		if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
+			outType := ty.Out(0)
+			if (runtime.GOARCH == "amd64" || runtime.GOARCH == "loong64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "s390x") && outType.Size() > maxRegAllocStructSize {
+				val := reflect.New(outType)
+				keepAlive = append(keepAlive, val)
+				addInt(val.Pointer())
+			} else if runtime.GOARCH == "arm64" && outType.Size() > maxRegAllocStructSize {
+				isAllFloats, numFields := isAllSameFloat(outType)
+				if !isAllFloats || numFields > 4 {
+					val := reflect.New(outType)
+					keepAlive = append(keepAlive, val)
+					arm64_r8 = val.Pointer()
+				}
+			}
+		}
+		for i, v := range args {
+			if variadic, ok := xreflect.TypeAssert[[]any](args[i]); ok {
+				if i != len(args)-1 {
+					panic("purego: can only expand last parameter")
+				}
+				for _, x := range variadic {
+					keepAlive = addValue(reflect.ValueOf(x), keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
+				}
+				continue
+			}
+			// Check if we need to start Darwin ARM64 C-style stack packing
+			if runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" && shouldBundleStackArgs(v, numInts, numFloats) {
+				// Collect and separate remaining args into register vs stack
+				stackArgs, newKeepAlive := collectStackArgs(args, i, numInts, numFloats,
+					keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
+				keepAlive = newKeepAlive
+
+				// Bundle stack arguments with C-style packing
+				bundleStackArgs(stackArgs, addStack)
+				break
+			}
+			keepAlive = addValue(v, keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
+		}
+
+		syscall := thePool.Get().(*syscall15Args)
+		defer thePool.Put(syscall)
+
+		if runtime.GOARCH == "loong64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "s390x" {
+			syscall.Set(cfn, sysargs[:], floats[:], 0)
+			runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall))
+		} else if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
+			// Use the normal arm64 calling convention even on Windows
+			syscall.Set(cfn, sysargs[:], floats[:], arm64_r8)
+			runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall))
+		} else {
+			*syscall = syscall15Args{}
+			// This is a fallback for Windows amd64, 386, and arm. Note this may not support floats
+			syscall.a1, syscall.a2, _ = syscall_syscall15X(cfn, sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4],
+				sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
+				sysargs[12], sysargs[13], sysargs[14])
+			syscall.f1 = syscall.a2 // on amd64 a2 stores the float return. On 32bit platforms floats aren't support
+		}
+		if ty.NumOut() == 0 {
+			return nil
+		}
+		outType := ty.Out(0)
+		v := reflect.New(outType).Elem()
+		switch outType.Kind() {
+		case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+			v.SetUint(uint64(syscall.a1))
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			v.SetInt(int64(syscall.a1))
+		case reflect.Bool:
+			v.SetBool(byte(syscall.a1) != 0)
+		case reflect.UnsafePointer:
+			// We take the address and then dereference it to trick go vet from creating a possible miss-use of unsafe.Pointer
+			v.SetPointer(*(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1)))
+		case reflect.Ptr:
+			v = reflect.NewAt(outType, unsafe.Pointer(&syscall.a1)).Elem()
+		case reflect.Func:
+			// wrap this C function in a nicely typed Go function
+			v = reflect.New(outType)
+			RegisterFunc(v.Interface(), syscall.a1)
+		case reflect.String:
+			v.SetString(strings.GoString(syscall.a1))
+		case reflect.Float32:
+			// NOTE: syscall.r2 is only the floating return value on 64bit platforms.
+			// On 32bit platforms syscall.r2 is the upper part of a 64bit return.
+			// On 386, x87 FPU returns floats as float64 in ST(0), so we read as float64 and convert.
+			// On PPC64LE, C ABI converts float32 to double in FPR, so we read as float64.
+			// On S390X (big-endian), float32 is in upper 32 bits of the 64-bit FP register.
+			switch runtime.GOARCH {
+			case "386":
+				v.SetFloat(math.Float64frombits(uint64(syscall.f1) | (uint64(syscall.f2) << 32)))
+			case "ppc64le":
+				v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
+			case "s390x":
+				// S390X is big-endian: float32 in upper 32 bits of 64-bit register
+				v.SetFloat(float64(math.Float32frombits(uint32(syscall.f1 >> 32))))
+			default:
+				v.SetFloat(float64(math.Float32frombits(uint32(syscall.f1))))
+			}
+		case reflect.Float64:
+			// NOTE: syscall.r2 is only the floating return value on 64bit platforms.
+			// On 32bit platforms syscall.r2 is the upper part of a 64bit return.
+			if is32bit {
+				v.SetFloat(math.Float64frombits(uint64(syscall.f1) | (uint64(syscall.f2) << 32)))
+			} else {
+				v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
+			}
+		case reflect.Struct:
+			v = getStruct(outType, *syscall)
+		default:
+			panic("purego: unsupported return kind: " + outType.Kind().String())
+		}
+		if len(args) > 0 {
+			// reuse args slice instead of allocating one when possible
+			args[0] = v
+			return args[:1]
+		} else {
+			return []reflect.Value{v}
+		}
+	})
+	fn.Set(v)
+}
+
+func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat func(x uintptr), addStack func(x uintptr), numInts *int, numFloats *int, numStack *int) []any {
+	const is32bit = unsafe.Sizeof(uintptr(0)) == 4
+	switch v.Kind() {
+	case reflect.String:
+		ptr := strings.CString(v.String())
+		keepAlive = append(keepAlive, ptr)
+		addInt(uintptr(unsafe.Pointer(ptr)))
+	case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		addInt(uintptr(v.Uint()))
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		addInt(uintptr(v.Int()))
+	case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
+		// There is no need to keepAlive this pointer separately because it is kept alive in the args variable
+		addInt(v.Pointer())
+	case reflect.Func:
+		addInt(NewCallback(v.Interface()))
+	case reflect.Bool:
+		if v.Bool() {
+			addInt(1)
+		} else {
+			addInt(0)
+		}
+	case reflect.Float32:
+		// On S390X big-endian, float32 goes in upper 32 bits of 64-bit FP register
+		if runtime.GOARCH == "s390x" {
+			addFloat(uintptr(math.Float32bits(float32(v.Float()))) << 32)
+		} else {
+			addFloat(uintptr(math.Float32bits(float32(v.Float()))))
+		}
+	case reflect.Float64:
+		if is32bit {
+			bits := math.Float64bits(v.Float())
+			addFloat(uintptr(bits))
+			addFloat(uintptr(bits >> 32))
+		} else {
+			addFloat(uintptr(math.Float64bits(v.Float())))
+		}
+	case reflect.Struct:
+		keepAlive = addStruct(v, numInts, numFloats, numStack, addInt, addFloat, addStack, keepAlive)
+	default:
+		panic("purego: unsupported kind: " + v.Kind().String())
+	}
+	return keepAlive
+}
+
+// maxRegAllocStructSize is the biggest a struct can be while still fitting in registers.
+// if it is bigger than this than enough space must be allocated on the heap and then passed into
+// the function as the first parameter on amd64 or in R8 on arm64.
+//
+// If you change this make sure to update it in objc_runtime_darwin.go
+const maxRegAllocStructSize = 16
+
+func isAllSameFloat(ty reflect.Type) (allFloats bool, numFields int) {
+	allFloats = true
+	root := ty.Field(0).Type
+	for root.Kind() == reflect.Struct {
+		root = root.Field(0).Type
+	}
+	first := root.Kind()
+	if first != reflect.Float32 && first != reflect.Float64 {
+		allFloats = false
+	}
+	for i := 0; i < ty.NumField(); i++ {
+		f := ty.Field(i).Type
+		if f.Kind() == reflect.Struct {
+			var structNumFields int
+			allFloats, structNumFields = isAllSameFloat(f)
+			numFields += structNumFields
+			continue
+		}
+		numFields++
+		if f.Kind() != first {
+			allFloats = false
+		}
+	}
+	return allFloats, numFields
+}
+
+func checkStructFieldsSupported(ty reflect.Type) {
+	for i := 0; i < ty.NumField(); i++ {
+		f := ty.Field(i).Type
+		if f.Kind() == reflect.Array {
+			f = f.Elem()
+		} else if f.Kind() == reflect.Struct {
+			checkStructFieldsSupported(f)
+			continue
+		}
+		switch f.Kind() {
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+			reflect.Uintptr, reflect.Ptr, reflect.UnsafePointer, reflect.Float64, reflect.Float32,
+			reflect.Bool:
+		default:
+			panic(fmt.Sprintf("purego: struct field type %s is not supported", f))
+		}
+	}
+}
+
+func ensureStructSupportedForRegisterFunc() {
+	if runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" {
+		panic("purego: struct arguments are only supported on amd64 and arm64")
+	}
+	if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
+		panic("purego: struct arguments are only supported on darwin and linux")
+	}
+}
+
+func roundUpTo8(val uintptr) uintptr {
+	return (val + align8ByteMask) &^ align8ByteMask
+}
+
+func numOfFloatRegisters() int {
+	switch runtime.GOARCH {
+	case "amd64", "arm64", "loong64", "ppc64le", "riscv64":
+		return 8
+	case "s390x":
+		return 4
+	case "arm":
+		return 16
+	case "386":
+		// i386 SysV ABI passes all arguments on the stack, including floats
+		return 0
+	default:
+		// since this platform isn't supported and can therefore only access
+		// integer registers it is safest to return 8
+		return 8
+	}
+}
+
+func numOfIntegerRegisters() int {
+	switch runtime.GOARCH {
+	case "arm64", "loong64", "ppc64le", "riscv64":
+		return 8
+	case "amd64":
+		return 6
+	case "s390x":
+		// S390X uses R2-R6 for integer arguments
+		return 5
+	case "arm":
+		return 4
+	case "386":
+		// i386 SysV ABI passes all arguments on the stack
+		return 0
+	default:
+		// since this platform isn't supported and can therefore only access
+		// integer registers it is fine to return the maxArgs
+		return maxArgs
+	}
+}
+
+// estimateStackBytes estimates stack bytes needed for Darwin ARM64 validation.
+// This is a conservative estimate used only for early error detection.
+func estimateStackBytes(ty reflect.Type) int {
+	var numInts, numFloats int
+	var stackBytes int
+
+	for i := 0; i < ty.NumIn(); i++ {
+		arg := ty.In(i)
+		size := int(arg.Size())
+
+		// Check if this goes to register or stack
+		usesInt := arg.Kind() != reflect.Float32 && arg.Kind() != reflect.Float64
+		if usesInt && numInts < numOfIntegerRegisters() {
+			numInts++
+		} else if !usesInt && numFloats < numOfFloatRegisters() {
+			numFloats++
+		} else {
+			// Goes to stack - accumulate total bytes
+			stackBytes += size
+		}
+	}
+	// Round total to 8-byte boundary
+	if stackBytes > 0 && stackBytes%align8ByteSize != 0 {
+		stackBytes = int(roundUpTo8(uintptr(stackBytes)))
+	}
+	return stackBytes
+}
diff --git a/vendor/github.com/ebitengine/purego/gen.go b/vendor/github.com/ebitengine/purego/gen.go
new file mode 100644
index 000000000..9cb7c4535
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/gen.go
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+package purego
+
+//go:generate go run wincallback.go
diff --git a/vendor/github.com/ebitengine/purego/go_runtime.go b/vendor/github.com/ebitengine/purego/go_runtime.go
new file mode 100644
index 000000000..b327f7869
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/go_runtime.go
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build darwin || freebsd || linux || netbsd || windows
+
+package purego
+
+import (
+	"unsafe"
+)
+
+//go:linkname runtime_cgocall runtime.cgocall
+func runtime_cgocall(fn uintptr, arg unsafe.Pointer) int32 // from runtime/sys_libc.go
diff --git a/vendor/github.com/ebitengine/purego/internal/cgo/dlfcn_cgo_unix.go b/vendor/github.com/ebitengine/purego/internal/cgo/dlfcn_cgo_unix.go
new file mode 100644
index 000000000..6d0571abb
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/cgo/dlfcn_cgo_unix.go
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
+
+//go:build freebsd || linux || netbsd
+
+package cgo
+
+/*
+#cgo !netbsd LDFLAGS: -ldl
+
+#include <dlfcn.h>
+#include <stdlib.h>
+*/
+import "C"
+
+import (
+	"errors"
+	"unsafe"
+)
+
+func Dlopen(filename string, flag int) (uintptr, error) {
+	cfilename := C.CString(filename)
+	defer C.free(unsafe.Pointer(cfilename))
+	handle := C.dlopen(cfilename, C.int(flag))
+	if handle == nil {
+		return 0, errors.New(C.GoString(C.dlerror()))
+	}
+	return uintptr(handle), nil
+}
+
+func Dlsym(handle uintptr, symbol string) (uintptr, error) {
+	csymbol := C.CString(symbol)
+	defer C.free(unsafe.Pointer(csymbol))
+	symbolAddr := C.dlsym(*(*unsafe.Pointer)(unsafe.Pointer(&handle)), csymbol)
+	if symbolAddr == nil {
+		return 0, errors.New(C.GoString(C.dlerror()))
+	}
+	return uintptr(symbolAddr), nil
+}
+
+func Dlclose(handle uintptr) error {
+	result := C.dlclose(*(*unsafe.Pointer)(unsafe.Pointer(&handle)))
+	if result != 0 {
+		return errors.New(C.GoString(C.dlerror()))
+	}
+	return nil
+}
+
+// all that is needed is to assign each dl function because then its
+// symbol will then be made available to the linker and linked to inside dlfcn.go
+var (
+	_ = C.dlopen
+	_ = C.dlsym
+	_ = C.dlerror
+	_ = C.dlclose
+)
diff --git a/vendor/github.com/ebitengine/purego/internal/cgo/empty.go b/vendor/github.com/ebitengine/purego/internal/cgo/empty.go
new file mode 100644
index 000000000..1d7cffe2a
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/cgo/empty.go
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
+
+package cgo
+
+// Empty so that importing this package doesn't cause issue for certain platforms.
diff --git a/vendor/github.com/ebitengine/purego/internal/cgo/syscall_cgo_unix.go b/vendor/github.com/ebitengine/purego/internal/cgo/syscall_cgo_unix.go
new file mode 100644
index 000000000..1e39de3b6
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/cgo/syscall_cgo_unix.go
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build freebsd || (linux && !(386 || amd64 || arm || arm64 || loong64 || ppc64le || riscv64)) || netbsd
+
+package cgo
+
+// this file is placed inside internal/cgo and not package purego
+// because Cgo and assembly files can't be in the same package.
+
+/*
+#cgo !netbsd LDFLAGS: -ldl
+
+#include <stdint.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <assert.h>
+
+typedef struct syscall15Args {
+	uintptr_t fn;
+	uintptr_t a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15;
+	uintptr_t f1, f2, f3, f4, f5, f6, f7, f8;
+	uintptr_t err;
+} syscall15Args;
+
+void syscall15(struct syscall15Args *args) {
+	assert((args->f1|args->f2|args->f3|args->f4|args->f5|args->f6|args->f7|args->f8) == 0);
+	uintptr_t (*func_name)(uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6,
+		uintptr_t a7, uintptr_t a8, uintptr_t a9, uintptr_t a10, uintptr_t a11, uintptr_t a12,
+		uintptr_t a13, uintptr_t a14, uintptr_t a15);
+	*(void**)(&func_name) = (void*)(args->fn);
+	uintptr_t r1 =  func_name(args->a1,args->a2,args->a3,args->a4,args->a5,args->a6,args->a7,args->a8,args->a9,
+		args->a10,args->a11,args->a12,args->a13,args->a14,args->a15);
+	args->a1 = r1;
+	args->err = errno;
+}
+
+*/
+import "C"
+import "unsafe"
+
+// assign purego.syscall15XABI0 to the C version of this function.
+var Syscall15XABI0 = unsafe.Pointer(C.syscall15)
+
+//go:nosplit
+func Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
+	args := C.syscall15Args{
+		C.uintptr_t(fn), C.uintptr_t(a1), C.uintptr_t(a2), C.uintptr_t(a3),
+		C.uintptr_t(a4), C.uintptr_t(a5), C.uintptr_t(a6),
+		C.uintptr_t(a7), C.uintptr_t(a8), C.uintptr_t(a9), C.uintptr_t(a10), C.uintptr_t(a11), C.uintptr_t(a12),
+		C.uintptr_t(a13), C.uintptr_t(a14), C.uintptr_t(a15), 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	}
+	C.syscall15(&args)
+	return uintptr(args.a1), 0, uintptr(args.err)
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_amd64.h b/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_amd64.h
new file mode 100644
index 000000000..9949435fe
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_amd64.h
@@ -0,0 +1,99 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These save the frame pointer, so in general, functions that use
+// these should have zero frame size to suppress the automatic frame
+// pointer, though it's harmless to not do this.
+
+#ifdef GOOS_windows
+
+// REGS_HOST_TO_ABI0_STACK is the stack bytes used by
+// PUSH_REGS_HOST_TO_ABI0.
+#define REGS_HOST_TO_ABI0_STACK (28*8 + 8)
+
+// PUSH_REGS_HOST_TO_ABI0 prepares for transitioning from
+// the host ABI to Go ABI0 code. It saves all registers that are
+// callee-save in the host ABI and caller-save in Go ABI0 and prepares
+// for entry to Go.
+//
+// Save DI SI BP BX R12 R13 R14 R15 X6-X15 registers and the DF flag.
+// Clear the DF flag for the Go ABI.
+// MXCSR matches the Go ABI, so we don't have to set that,
+// and Go doesn't modify it, so we don't have to save it.
+#define PUSH_REGS_HOST_TO_ABI0()	\
+	PUSHFQ			\
+	CLD			\
+	ADJSP	$(REGS_HOST_TO_ABI0_STACK - 8)	\
+	MOVQ	DI, (0*0)(SP)	\
+	MOVQ	SI, (1*8)(SP)	\
+	MOVQ	BP, (2*8)(SP)	\
+	MOVQ	BX, (3*8)(SP)	\
+	MOVQ	R12, (4*8)(SP)	\
+	MOVQ	R13, (5*8)(SP)	\
+	MOVQ	R14, (6*8)(SP)	\
+	MOVQ	R15, (7*8)(SP)	\
+	MOVUPS	X6, (8*8)(SP)	\
+	MOVUPS	X7, (10*8)(SP)	\
+	MOVUPS	X8, (12*8)(SP)	\
+	MOVUPS	X9, (14*8)(SP)	\
+	MOVUPS	X10, (16*8)(SP)	\
+	MOVUPS	X11, (18*8)(SP)	\
+	MOVUPS	X12, (20*8)(SP)	\
+	MOVUPS	X13, (22*8)(SP)	\
+	MOVUPS	X14, (24*8)(SP)	\
+	MOVUPS	X15, (26*8)(SP)
+
+#define POP_REGS_HOST_TO_ABI0()	\
+	MOVQ	(0*0)(SP), DI	\
+	MOVQ	(1*8)(SP), SI	\
+	MOVQ	(2*8)(SP), BP	\
+	MOVQ	(3*8)(SP), BX	\
+	MOVQ	(4*8)(SP), R12	\
+	MOVQ	(5*8)(SP), R13	\
+	MOVQ	(6*8)(SP), R14	\
+	MOVQ	(7*8)(SP), R15	\
+	MOVUPS	(8*8)(SP), X6	\
+	MOVUPS	(10*8)(SP), X7	\
+	MOVUPS	(12*8)(SP), X8	\
+	MOVUPS	(14*8)(SP), X9	\
+	MOVUPS	(16*8)(SP), X10	\
+	MOVUPS	(18*8)(SP), X11	\
+	MOVUPS	(20*8)(SP), X12	\
+	MOVUPS	(22*8)(SP), X13	\
+	MOVUPS	(24*8)(SP), X14	\
+	MOVUPS	(26*8)(SP), X15	\
+	ADJSP	$-(REGS_HOST_TO_ABI0_STACK - 8)	\
+	POPFQ
+
+#else
+// SysV ABI
+
+#define REGS_HOST_TO_ABI0_STACK (6*8)
+
+// SysV MXCSR matches the Go ABI, so we don't have to set that,
+// and Go doesn't modify it, so we don't have to save it.
+// Both SysV and Go require DF to be cleared, so that's already clear.
+// The SysV and Go frame pointer conventions are compatible.
+#define PUSH_REGS_HOST_TO_ABI0()	\
+	ADJSP	$(REGS_HOST_TO_ABI0_STACK)	\
+	MOVQ	BP, (5*8)(SP)	\
+	LEAQ	(5*8)(SP), BP	\
+	MOVQ	BX, (0*8)(SP)	\
+	MOVQ	R12, (1*8)(SP)	\
+	MOVQ	R13, (2*8)(SP)	\
+	MOVQ	R14, (3*8)(SP)	\
+	MOVQ	R15, (4*8)(SP)
+
+#define POP_REGS_HOST_TO_ABI0()	\
+	MOVQ	(0*8)(SP), BX	\
+	MOVQ	(1*8)(SP), R12	\
+	MOVQ	(2*8)(SP), R13	\
+	MOVQ	(3*8)(SP), R14	\
+	MOVQ	(4*8)(SP), R15	\
+	MOVQ	(5*8)(SP), BP	\
+	ADJSP	$-(REGS_HOST_TO_ABI0_STACK)
+
+#endif
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_arm64.h b/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_arm64.h
new file mode 100644
index 000000000..5d5061ec1
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_arm64.h
@@ -0,0 +1,39 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These macros save and restore the callee-saved registers
+// from the stack, but they don't adjust stack pointer, so
+// the user should prepare stack space in advance.
+// SAVE_R19_TO_R28(offset) saves R19 ~ R28 to the stack space
+// of ((offset)+0*8)(RSP) ~ ((offset)+9*8)(RSP).
+//
+// SAVE_F8_TO_F15(offset) saves F8 ~ F15 to the stack space
+// of ((offset)+0*8)(RSP) ~ ((offset)+7*8)(RSP).
+//
+// R29 is not saved because Go will save and restore it.
+
+#define SAVE_R19_TO_R28(offset) \
+	STP	(R19, R20), ((offset)+0*8)(RSP) \
+	STP	(R21, R22), ((offset)+2*8)(RSP) \
+	STP	(R23, R24), ((offset)+4*8)(RSP) \
+	STP	(R25, R26), ((offset)+6*8)(RSP) \
+	STP	(R27, g), ((offset)+8*8)(RSP)
+#define RESTORE_R19_TO_R28(offset) \
+	LDP	((offset)+0*8)(RSP), (R19, R20) \
+	LDP	((offset)+2*8)(RSP), (R21, R22) \
+	LDP	((offset)+4*8)(RSP), (R23, R24) \
+	LDP	((offset)+6*8)(RSP), (R25, R26) \
+	LDP	((offset)+8*8)(RSP), (R27, g) /* R28 */
+#define SAVE_F8_TO_F15(offset) \
+	FSTPD	(F8, F9), ((offset)+0*8)(RSP) \
+	FSTPD	(F10, F11), ((offset)+2*8)(RSP) \
+	FSTPD	(F12, F13), ((offset)+4*8)(RSP) \
+	FSTPD	(F14, F15), ((offset)+6*8)(RSP)
+#define RESTORE_F8_TO_F15(offset) \
+	FLDPD	((offset)+0*8)(RSP), (F8, F9) \
+	FLDPD	((offset)+2*8)(RSP), (F10, F11) \
+	FLDPD	((offset)+4*8)(RSP), (F12, F13) \
+	FLDPD	((offset)+6*8)(RSP), (F14, F15)
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_loong64.h b/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_loong64.h
new file mode 100644
index 000000000..b10d83732
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_loong64.h
@@ -0,0 +1,60 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI0.
+//
+// These macros save and restore the callee-saved registers
+// from the stack, but they don't adjust stack pointer, so
+// the user should prepare stack space in advance.
+// SAVE_R22_TO_R31(offset) saves R22 ~ R31 to the stack space
+// of ((offset)+0*8)(R3) ~ ((offset)+9*8)(R3).
+//
+// SAVE_F24_TO_F31(offset) saves F24 ~ F31 to the stack space
+// of ((offset)+0*8)(R3) ~ ((offset)+7*8)(R3).
+//
+// Note: g is R22
+
+#define SAVE_R22_TO_R31(offset)	\
+	MOVV	g,   ((offset)+(0*8))(R3)	\
+	MOVV	R23, ((offset)+(1*8))(R3)	\
+	MOVV	R24, ((offset)+(2*8))(R3)	\
+	MOVV	R25, ((offset)+(3*8))(R3)	\
+	MOVV	R26, ((offset)+(4*8))(R3)	\
+	MOVV	R27, ((offset)+(5*8))(R3)	\
+	MOVV	R28, ((offset)+(6*8))(R3)	\
+	MOVV	R29, ((offset)+(7*8))(R3)	\
+	MOVV	R30, ((offset)+(8*8))(R3)	\
+	MOVV	R31, ((offset)+(9*8))(R3)
+
+#define SAVE_F24_TO_F31(offset)	\
+	MOVD	F24, ((offset)+(0*8))(R3)	\
+	MOVD	F25, ((offset)+(1*8))(R3)	\
+	MOVD	F26, ((offset)+(2*8))(R3)	\
+	MOVD	F27, ((offset)+(3*8))(R3)	\
+	MOVD	F28, ((offset)+(4*8))(R3)	\
+	MOVD	F29, ((offset)+(5*8))(R3)	\
+	MOVD	F30, ((offset)+(6*8))(R3)	\
+	MOVD	F31, ((offset)+(7*8))(R3)
+
+#define RESTORE_R22_TO_R31(offset)	\
+	MOVV	((offset)+(0*8))(R3),  g	\
+	MOVV	((offset)+(1*8))(R3), R23	\
+	MOVV	((offset)+(2*8))(R3), R24	\
+	MOVV	((offset)+(3*8))(R3), R25	\
+	MOVV	((offset)+(4*8))(R3), R26	\
+	MOVV	((offset)+(5*8))(R3), R27	\
+	MOVV	((offset)+(6*8))(R3), R28	\
+	MOVV	((offset)+(7*8))(R3), R29	\
+	MOVV	((offset)+(8*8))(R3), R30	\
+	MOVV	((offset)+(9*8))(R3), R31
+
+#define RESTORE_F24_TO_F31(offset)	\
+	MOVD	((offset)+(0*8))(R3), F24	\
+	MOVD	((offset)+(1*8))(R3), F25	\
+	MOVD	((offset)+(2*8))(R3), F26	\
+	MOVD	((offset)+(3*8))(R3), F27	\
+	MOVD	((offset)+(4*8))(R3), F28	\
+	MOVD	((offset)+(5*8))(R3), F29	\
+	MOVD	((offset)+(6*8))(R3), F30	\
+	MOVD	((offset)+(7*8))(R3), F31
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_ppc64x.h b/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_ppc64x.h
new file mode 100644
index 000000000..245a5266f
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/abi_ppc64x.h
@@ -0,0 +1,195 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Macros for transitioning from the host ABI to Go ABI
+//
+// On PPC64/ELFv2 targets, the following registers are callee
+// saved when called from C. They must be preserved before
+// calling into Go which does not preserve any of them.
+//
+//	R14-R31
+//	CR2-4
+//	VR20-31
+//	F14-F31
+//
+// xcoff(aix) and ELFv1 are similar, but may only require a
+// subset of these.
+//
+// These macros assume a 16 byte aligned stack pointer. This
+// is required by ELFv1, ELFv2, and AIX PPC64.
+
+#define SAVE_GPR_SIZE (18*8)
+#define SAVE_GPR(offset)               \
+	MOVD	R14, (offset+8*0)(R1)  \
+	MOVD	R15, (offset+8*1)(R1)  \
+	MOVD	R16, (offset+8*2)(R1)  \
+	MOVD	R17, (offset+8*3)(R1)  \
+	MOVD	R18, (offset+8*4)(R1)  \
+	MOVD	R19, (offset+8*5)(R1)  \
+	MOVD	R20, (offset+8*6)(R1)  \
+	MOVD	R21, (offset+8*7)(R1)  \
+	MOVD	R22, (offset+8*8)(R1)  \
+	MOVD	R23, (offset+8*9)(R1)  \
+	MOVD	R24, (offset+8*10)(R1) \
+	MOVD	R25, (offset+8*11)(R1) \
+	MOVD	R26, (offset+8*12)(R1) \
+	MOVD	R27, (offset+8*13)(R1) \
+	MOVD	R28, (offset+8*14)(R1) \
+	MOVD	R29, (offset+8*15)(R1) \
+	MOVD	g,   (offset+8*16)(R1) \
+	MOVD	R31, (offset+8*17)(R1)
+
+#define RESTORE_GPR(offset)            \
+	MOVD	(offset+8*0)(R1), R14  \
+	MOVD	(offset+8*1)(R1), R15  \
+	MOVD	(offset+8*2)(R1), R16  \
+	MOVD	(offset+8*3)(R1), R17  \
+	MOVD	(offset+8*4)(R1), R18  \
+	MOVD	(offset+8*5)(R1), R19  \
+	MOVD	(offset+8*6)(R1), R20  \
+	MOVD	(offset+8*7)(R1), R21  \
+	MOVD	(offset+8*8)(R1), R22  \
+	MOVD	(offset+8*9)(R1), R23  \
+	MOVD	(offset+8*10)(R1), R24 \
+	MOVD	(offset+8*11)(R1), R25 \
+	MOVD	(offset+8*12)(R1), R26 \
+	MOVD	(offset+8*13)(R1), R27 \
+	MOVD	(offset+8*14)(R1), R28 \
+	MOVD	(offset+8*15)(R1), R29 \
+	MOVD	(offset+8*16)(R1), g   \
+	MOVD	(offset+8*17)(R1), R31
+
+#define SAVE_FPR_SIZE (18*8)
+#define SAVE_FPR(offset)               \
+	FMOVD	F14, (offset+8*0)(R1)  \
+	FMOVD	F15, (offset+8*1)(R1)  \
+	FMOVD	F16, (offset+8*2)(R1)  \
+	FMOVD	F17, (offset+8*3)(R1)  \
+	FMOVD	F18, (offset+8*4)(R1)  \
+	FMOVD	F19, (offset+8*5)(R1)  \
+	FMOVD	F20, (offset+8*6)(R1)  \
+	FMOVD	F21, (offset+8*7)(R1)  \
+	FMOVD	F22, (offset+8*8)(R1)  \
+	FMOVD	F23, (offset+8*9)(R1)  \
+	FMOVD	F24, (offset+8*10)(R1) \
+	FMOVD	F25, (offset+8*11)(R1) \
+	FMOVD	F26, (offset+8*12)(R1) \
+	FMOVD	F27, (offset+8*13)(R1) \
+	FMOVD	F28, (offset+8*14)(R1) \
+	FMOVD	F29, (offset+8*15)(R1) \
+	FMOVD	F30, (offset+8*16)(R1) \
+	FMOVD	F31, (offset+8*17)(R1)
+
+#define RESTORE_FPR(offset)            \
+	FMOVD	(offset+8*0)(R1), F14  \
+	FMOVD	(offset+8*1)(R1), F15  \
+	FMOVD	(offset+8*2)(R1), F16  \
+	FMOVD	(offset+8*3)(R1), F17  \
+	FMOVD	(offset+8*4)(R1), F18  \
+	FMOVD	(offset+8*5)(R1), F19  \
+	FMOVD	(offset+8*6)(R1), F20  \
+	FMOVD	(offset+8*7)(R1), F21  \
+	FMOVD	(offset+8*8)(R1), F22  \
+	FMOVD	(offset+8*9)(R1), F23  \
+	FMOVD	(offset+8*10)(R1), F24 \
+	FMOVD	(offset+8*11)(R1), F25 \
+	FMOVD	(offset+8*12)(R1), F26 \
+	FMOVD	(offset+8*13)(R1), F27 \
+	FMOVD	(offset+8*14)(R1), F28 \
+	FMOVD	(offset+8*15)(R1), F29 \
+	FMOVD	(offset+8*16)(R1), F30 \
+	FMOVD	(offset+8*17)(R1), F31
+
+// Save and restore VR20-31 (aka VSR56-63). These
+// macros must point to a 16B aligned offset.
+#define SAVE_VR_SIZE (12*16)
+#define SAVE_VR(offset, rtmp)         \
+	MOVD	$(offset+16*0), rtmp  \
+	STVX	V20, (rtmp)(R1)       \
+	MOVD	$(offset+16*1), rtmp  \
+	STVX	V21, (rtmp)(R1)       \
+	MOVD	$(offset+16*2), rtmp  \
+	STVX	V22, (rtmp)(R1)       \
+	MOVD	$(offset+16*3), rtmp  \
+	STVX	V23, (rtmp)(R1)       \
+	MOVD	$(offset+16*4), rtmp  \
+	STVX	V24, (rtmp)(R1)       \
+	MOVD	$(offset+16*5), rtmp  \
+	STVX	V25, (rtmp)(R1)       \
+	MOVD	$(offset+16*6), rtmp  \
+	STVX	V26, (rtmp)(R1)       \
+	MOVD	$(offset+16*7), rtmp  \
+	STVX	V27, (rtmp)(R1)       \
+	MOVD	$(offset+16*8), rtmp  \
+	STVX	V28, (rtmp)(R1)       \
+	MOVD	$(offset+16*9), rtmp  \
+	STVX	V29, (rtmp)(R1)       \
+	MOVD	$(offset+16*10), rtmp \
+	STVX	V30, (rtmp)(R1)       \
+	MOVD	$(offset+16*11), rtmp \
+	STVX	V31, (rtmp)(R1)
+
+#define RESTORE_VR(offset, rtmp)      \
+	MOVD	$(offset+16*0), rtmp  \
+	LVX	(rtmp)(R1), V20       \
+	MOVD	$(offset+16*1), rtmp  \
+	LVX	(rtmp)(R1), V21       \
+	MOVD	$(offset+16*2), rtmp  \
+	LVX	(rtmp)(R1), V22       \
+	MOVD	$(offset+16*3), rtmp  \
+	LVX	(rtmp)(R1), V23       \
+	MOVD	$(offset+16*4), rtmp  \
+	LVX	(rtmp)(R1), V24       \
+	MOVD	$(offset+16*5), rtmp  \
+	LVX	(rtmp)(R1), V25       \
+	MOVD	$(offset+16*6), rtmp  \
+	LVX	(rtmp)(R1), V26       \
+	MOVD	$(offset+16*7), rtmp  \
+	LVX	(rtmp)(R1), V27       \
+	MOVD	$(offset+16*8), rtmp  \
+	LVX	(rtmp)(R1), V28       \
+	MOVD	$(offset+16*9), rtmp  \
+	LVX	(rtmp)(R1), V29       \
+	MOVD	$(offset+16*10), rtmp \
+	LVX	(rtmp)(R1), V30       \
+	MOVD	$(offset+16*11), rtmp \
+	LVX	(rtmp)(R1), V31
+
+// LR and CR are saved in the caller's frame. The callee must
+// make space for all other callee-save registers.
+#define SAVE_ALL_REG_SIZE (SAVE_GPR_SIZE+SAVE_FPR_SIZE+SAVE_VR_SIZE)
+
+// Stack a frame and save all callee-save registers following the
+// host OS's ABI. Fortunately, this is identical for AIX, ELFv1, and
+// ELFv2. All host ABIs require the stack pointer to maintain 16 byte
+// alignment, and save the callee-save registers in the same places.
+//
+// To restate, R1 is assumed to be aligned when this macro is used.
+// This assumes the caller's frame is compliant with the host ABI.
+// CR and LR are saved into the caller's frame per the host ABI.
+// R0 is initialized to $0 as expected by Go.
+#define STACK_AND_SAVE_HOST_TO_GO_ABI(extra)                       \
+	MOVD	LR, R0                                             \
+	MOVD	R0, 16(R1)                                         \
+	MOVW	CR, R0                                             \
+	MOVD	R0, 8(R1)                                          \
+	MOVDU	R1, -(extra)-FIXED_FRAME-SAVE_ALL_REG_SIZE(R1)     \
+	SAVE_GPR(extra+FIXED_FRAME)                                \
+	SAVE_FPR(extra+FIXED_FRAME+SAVE_GPR_SIZE)                  \
+	SAVE_VR(extra+FIXED_FRAME+SAVE_GPR_SIZE+SAVE_FPR_SIZE, R0) \
+	MOVD	$0, R0
+
+// This unstacks the frame, restoring all callee-save registers
+// as saved by STACK_AND_SAVE_HOST_TO_GO_ABI.
+//
+// R0 is not guaranteed to contain $0 after this macro.
+#define UNSTACK_AND_RESTORE_GO_TO_HOST_ABI(extra)                     \
+	RESTORE_GPR(extra+FIXED_FRAME)                                \
+	RESTORE_FPR(extra+FIXED_FRAME+SAVE_GPR_SIZE)                  \
+	RESTORE_VR(extra+FIXED_FRAME+SAVE_GPR_SIZE+SAVE_FPR_SIZE, R0) \
+	ADD 	$(extra+FIXED_FRAME+SAVE_ALL_REG_SIZE), R1            \
+	MOVD	16(R1), R0                                            \
+	MOVD	R0, LR                                                \
+	MOVD	8(R1), R0                                             \
+	MOVW	R0, CR
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_386.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_386.s
new file mode 100644
index 000000000..7475ec8a0
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_386.s
@@ -0,0 +1,29 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB), NOSPLIT, $28-16
+	MOVL BP, 24(SP)
+	MOVL BX, 20(SP)
+	MOVL SI, 16(SP)
+	MOVL DI, 12(SP)
+
+	MOVL ctxt+12(FP), AX
+	MOVL AX, 8(SP)
+	MOVL a+4(FP), AX
+	MOVL AX, 4(SP)
+	MOVL fn+0(FP), AX
+	MOVL AX, 0(SP)
+	CALL runtime·cgocallback(SB)
+
+	MOVL 12(SP), DI
+	MOVL 16(SP), SI
+	MOVL 20(SP), BX
+	MOVL 24(SP), BP
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_amd64.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_amd64.s
new file mode 100644
index 000000000..2b7eb57f8
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_amd64.s
@@ -0,0 +1,39 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "abi_amd64.h"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+// This signature is known to SWIG, so we can't change it.
+TEXT crosscall2(SB), NOSPLIT, $0-0
+	PUSH_REGS_HOST_TO_ABI0()
+
+	// Make room for arguments to cgocallback.
+	ADJSP $0x18
+
+#ifndef GOOS_windows
+	MOVQ DI, 0x0(SP) // fn
+	MOVQ SI, 0x8(SP) // arg
+
+	// Skip n in DX.
+	MOVQ CX, 0x10(SP) // ctxt
+
+#else
+	MOVQ CX, 0x0(SP) // fn
+	MOVQ DX, 0x8(SP) // arg
+
+	// Skip n in R8.
+	MOVQ R9, 0x10(SP) // ctxt
+
+#endif
+
+	CALL runtime·cgocallback(SB)
+
+	ADJSP $-0x18
+	POP_REGS_HOST_TO_ABI0()
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_arm.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_arm.s
new file mode 100644
index 000000000..68034e603
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_arm.s
@@ -0,0 +1,52 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
+	SUB $(8*9), R13 // Reserve space for the floating point registers.
+
+	// The C arguments arrive in R0, R1, R2, and R3. We want to
+	// pass R0, R1, and R3 to Go, so we push those on the stack.
+	// Also, save C callee-save registers R4-R12.
+	MOVM.WP [R0, R1, R3, R4, R5, R6, R7, R8, R9, g, R11, R12], (R13)
+
+	// Finally, save the link register R14. This also puts the
+	// arguments we pushed for cgocallback where they need to be,
+	// starting at 4(R13).
+	MOVW.W R14, -4(R13)
+
+	// Save VFP callee-saved registers D8-D15 (same as S16-S31).
+	// Note: We always save these since we target hard-float ABI.
+	MOVD F8, (13*4+8*1)(R13)
+	MOVD F9, (13*4+8*2)(R13)
+	MOVD F10, (13*4+8*3)(R13)
+	MOVD F11, (13*4+8*4)(R13)
+	MOVD F12, (13*4+8*5)(R13)
+	MOVD F13, (13*4+8*6)(R13)
+	MOVD F14, (13*4+8*7)(R13)
+	MOVD F15, (13*4+8*8)(R13)
+
+	BL runtime·load_g(SB)
+
+	// We set up the arguments to cgocallback when saving registers above.
+	BL runtime·cgocallback(SB)
+
+	MOVD (13*4+8*1)(R13), F8
+	MOVD (13*4+8*2)(R13), F9
+	MOVD (13*4+8*3)(R13), F10
+	MOVD (13*4+8*4)(R13), F11
+	MOVD (13*4+8*5)(R13), F12
+	MOVD (13*4+8*6)(R13), F13
+	MOVD (13*4+8*7)(R13), F14
+	MOVD (13*4+8*8)(R13), F15
+
+	MOVW.P   4(R13), R14
+	MOVM.IAW (R13), [R0, R1, R3, R4, R5, R6, R7, R8, R9, g, R11, R12]
+	ADD      $(8*9), R13
+	MOVW     R14, R15
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_arm64.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_arm64.s
new file mode 100644
index 000000000..50e5261d9
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_arm64.s
@@ -0,0 +1,36 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "abi_arm64.h"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
+/*
+ * We still need to save all callee save register as before, and then
+ *  push 3 args for fn (R0, R1, R3), skipping R2.
+ * Also note that at procedure entry in gc world, 8(RSP) will be the
+ *  first arg.
+ */
+	SUB  $(8*24), RSP
+	STP  (R0, R1), (8*1)(RSP)
+	MOVD R3, (8*3)(RSP)
+
+	SAVE_R19_TO_R28(8*4)
+	SAVE_F8_TO_F15(8*14)
+	STP (R29, R30), (8*22)(RSP)
+
+	// Initialize Go ABI environment
+	BL runtime·load_g(SB)
+	BL runtime·cgocallback(SB)
+
+	RESTORE_R19_TO_R28(8*4)
+	RESTORE_F8_TO_F15(8*14)
+	LDP (8*22)(RSP), (R29, R30)
+
+	ADD $(8*24), RSP
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_loong64.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_loong64.s
new file mode 100644
index 000000000..e81df86a5
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_loong64.s
@@ -0,0 +1,40 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "abi_loong64.h"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
+/*
+ * We still need to save all callee save register as before, and then
+ * push 3 args for fn (R4, R5, R7), skipping R6.
+ * Also note that at procedure entry in gc world, 8(R29) will be the
+ *  first arg.
+ */
+
+	ADDV $(-23*8), R3
+	MOVV R4, (1*8)(R3) // fn unsafe.Pointer
+	MOVV R5, (2*8)(R3) // a unsafe.Pointer
+	MOVV R7, (3*8)(R3) // ctxt uintptr
+
+	SAVE_R22_TO_R31((4*8))
+	SAVE_F24_TO_F31((14*8))
+	MOVV R1, (22*8)(R3)
+
+	// Initialize Go ABI environment
+	JAL runtime·load_g(SB)
+
+	JAL runtime·cgocallback(SB)
+
+	RESTORE_R22_TO_R31((4*8))
+	RESTORE_F24_TO_F31((14*8))
+	MOVV (22*8)(R3), R1
+
+	ADDV $(23*8), R3
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_ppc64le.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_ppc64le.s
new file mode 100644
index 000000000..6d1938cd8
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_ppc64le.s
@@ -0,0 +1,82 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "abi_ppc64x.h"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+//
+// This is a simplified version that only saves GPR and FPR registers,
+// not vector registers. This keeps the stack frame smaller to avoid
+// exceeding the nosplit stack limit.
+//
+// On PPC64LE ELFv2, callee-save registers are:
+//   R14-R31 (18 GPRs = 144 bytes)
+//   F14-F31 (18 FPRs = 144 bytes)
+//   CR2-CR4 (saved in CR field)
+//
+// Stack layout (must be 16-byte aligned):
+//   32 (FIXED_FRAME) + 24 (args) + 144 (GPR) + 144 (FPR) = 344
+//   Rounded to 352 for 16-byte alignment.
+
+#define FIXED_FRAME 32
+#define SAVE_SIZE    352
+#define GPR_OFFSET   (FIXED_FRAME+24)
+#define FPR_OFFSET   (GPR_OFFSET+SAVE_GPR_SIZE)
+
+TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
+	// Save LR and CR in caller's frame per ELFv2 ABI
+	MOVD LR, R0
+	MOVD R0, 16(R1)
+	MOVW CR, R0
+	MOVD R0, 8(R1)
+
+	// Allocate our stack frame
+	MOVDU R1, -SAVE_SIZE(R1)
+
+	// Save TOC (R2) in case needed
+	MOVD R2, 24(R1)
+
+	// Save callee-save GPRs
+	SAVE_GPR(GPR_OFFSET)
+
+	// Save callee-save FPRs
+	SAVE_FPR(FPR_OFFSET)
+
+	// Initialize R0 to 0 as expected by Go
+	MOVD $0, R0
+
+	// Load the current g.
+	BL runtime·load_g(SB)
+
+	// Set up arguments for cgocallback
+	MOVD R3, FIXED_FRAME+0(R1) // fn unsafe.Pointer
+	MOVD R4, FIXED_FRAME+8(R1) // a unsafe.Pointer
+
+	// Skip R5 = n uint32
+	MOVD R6, FIXED_FRAME+16(R1)  // ctxt uintptr
+	BL   runtime·cgocallback(SB)
+
+	// Restore callee-save FPRs
+	RESTORE_FPR(FPR_OFFSET)
+
+	// Restore callee-save GPRs
+	RESTORE_GPR(GPR_OFFSET)
+
+	// Restore TOC
+	MOVD 24(R1), R2
+
+	// Deallocate stack frame
+	ADD $SAVE_SIZE, R1
+
+	// Restore LR and CR from caller's frame
+	MOVD 16(R1), R0
+	MOVD R0, LR
+	MOVD 8(R1), R0
+	MOVW R0, CR
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_riscv64.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_riscv64.s
new file mode 100644
index 000000000..acf82c1b5
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_riscv64.s
@@ -0,0 +1,78 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
+/*
+ * Push arguments for fn (X10, X11, X13), along with all callee-save
+ * registers. Note that at procedure entry the first argument is at
+ * 8(X2).
+ */
+	ADD  $(-8*29), X2
+	MOV  X10, (8*1)(X2)  // fn unsafe.Pointer
+	MOV  X11, (8*2)(X2)  // a unsafe.Pointer
+	MOV  X13, (8*3)(X2)  // ctxt uintptr
+	MOV  X8, (8*4)(X2)
+	MOV  X9, (8*5)(X2)
+	MOV  X18, (8*6)(X2)
+	MOV  X19, (8*7)(X2)
+	MOV  X20, (8*8)(X2)
+	MOV  X21, (8*9)(X2)
+	MOV  X22, (8*10)(X2)
+	MOV  X23, (8*11)(X2)
+	MOV  X24, (8*12)(X2)
+	MOV  X25, (8*13)(X2)
+	MOV  X26, (8*14)(X2)
+	MOV  g, (8*15)(X2)
+	MOV  X1, (8*16)(X2)
+	MOVD F8, (8*17)(X2)
+	MOVD F9, (8*18)(X2)
+	MOVD F18, (8*19)(X2)
+	MOVD F19, (8*20)(X2)
+	MOVD F20, (8*21)(X2)
+	MOVD F21, (8*22)(X2)
+	MOVD F22, (8*23)(X2)
+	MOVD F23, (8*24)(X2)
+	MOVD F24, (8*25)(X2)
+	MOVD F25, (8*26)(X2)
+	MOVD F26, (8*27)(X2)
+	MOVD F27, (8*28)(X2)
+
+	// Initialize Go ABI environment
+	CALL runtime·load_g(SB)
+	CALL runtime·cgocallback(SB)
+
+	MOV  (8*4)(X2), X8
+	MOV  (8*5)(X2), X9
+	MOV  (8*6)(X2), X18
+	MOV  (8*7)(X2), X19
+	MOV  (8*8)(X2), X20
+	MOV  (8*9)(X2), X21
+	MOV  (8*10)(X2), X22
+	MOV  (8*11)(X2), X23
+	MOV  (8*12)(X2), X24
+	MOV  (8*13)(X2), X25
+	MOV  (8*14)(X2), X26
+	MOV  (8*15)(X2), g
+	MOV  (8*16)(X2), X1
+	MOVD (8*17)(X2), F8
+	MOVD (8*18)(X2), F9
+	MOVD (8*19)(X2), F18
+	MOVD (8*20)(X2), F19
+	MOVD (8*21)(X2), F20
+	MOVD (8*22)(X2), F21
+	MOVD (8*23)(X2), F22
+	MOVD (8*24)(X2), F23
+	MOVD (8*25)(X2), F24
+	MOVD (8*26)(X2), F25
+	MOVD (8*27)(X2), F26
+	MOVD (8*28)(X2), F27
+	ADD  $(8*29), X2
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_s390x.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_s390x.s
new file mode 100644
index 000000000..b64466501
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/asm_s390x.s
@@ -0,0 +1,55 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls cgocallback with three arguments.
+// fn is the PC of a func(a unsafe.Pointer) function.
+TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
+	// Start with standard C stack frame layout and linkage.
+
+	// Save R6-R15 in the register save area of the calling function.
+	STMG R6, R15, 48(R15)
+
+	// Allocate 96 bytes on the stack.
+	MOVD $-96(R15), R15
+
+	// Save F8-F15 in our stack frame.
+	FMOVD F8, 32(R15)
+	FMOVD F9, 40(R15)
+	FMOVD F10, 48(R15)
+	FMOVD F11, 56(R15)
+	FMOVD F12, 64(R15)
+	FMOVD F13, 72(R15)
+	FMOVD F14, 80(R15)
+	FMOVD F15, 88(R15)
+
+	// Initialize Go ABI environment.
+	BL runtime·load_g(SB)
+
+	MOVD R2, 8(R15)  // fn unsafe.Pointer
+	MOVD R3, 16(R15) // a unsafe.Pointer
+
+	// Skip R4 = n uint32
+	MOVD R5, 24(R15)             // ctxt uintptr
+	BL   runtime·cgocallback(SB)
+
+	FMOVD 32(R15), F8
+	FMOVD 40(R15), F9
+	FMOVD 48(R15), F10
+	FMOVD 56(R15), F11
+	FMOVD 64(R15), F12
+	FMOVD 72(R15), F13
+	FMOVD 80(R15), F14
+	FMOVD 88(R15), F15
+
+	// De-allocate stack frame.
+	MOVD $96(R15), R15
+
+	// Restore R6-R15.
+	LMG 48(R15), R6, R15
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/callbacks.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/callbacks.go
new file mode 100644
index 000000000..27d4c98c8
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/callbacks.go
@@ -0,0 +1,93 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package fakecgo
+
+import (
+	_ "unsafe"
+)
+
+// TODO: decide if we need _runtime_cgo_panic_internal
+
+//go:linkname x_cgo_init_trampoline x_cgo_init_trampoline
+//go:linkname _cgo_init _cgo_init
+var x_cgo_init_trampoline byte
+var _cgo_init = &x_cgo_init_trampoline
+
+// Creates a new system thread without updating any Go state.
+//
+// This method is invoked during shared library loading to create a new OS
+// thread to perform the runtime initialization. This method is similar to
+// _cgo_sys_thread_start except that it doesn't update any Go state.
+
+//go:linkname x_cgo_thread_start_trampoline x_cgo_thread_start_trampoline
+//go:linkname _cgo_thread_start _cgo_thread_start
+var x_cgo_thread_start_trampoline byte
+var _cgo_thread_start = &x_cgo_thread_start_trampoline
+
+// Notifies that the runtime has been initialized.
+//
+// We currently block at every CGO entry point (via _cgo_wait_runtime_init_done)
+// to ensure that the runtime has been initialized before the CGO call is
+// executed. This is necessary for shared libraries where we kickoff runtime
+// initialization in a separate thread and return without waiting for this
+// thread to complete the init.
+
+//go:linkname x_cgo_notify_runtime_init_done_trampoline x_cgo_notify_runtime_init_done_trampoline
+//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
+var x_cgo_notify_runtime_init_done_trampoline byte
+var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done_trampoline
+
+// Indicates whether a dummy thread key has been created or not.
+//
+// When calling go exported function from C, we register a destructor
+// callback, for a dummy thread key, by using pthread_key_create.
+
+//go:linkname _cgo_pthread_key_created _cgo_pthread_key_created
+var x_cgo_pthread_key_created uintptr
+var _cgo_pthread_key_created = &x_cgo_pthread_key_created
+
+// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
+// It's for the runtime package to call at init time.
+func set_crosscall2() {
+	// nothing needs to be done here for fakecgo
+	// because it's possible to just call cgocallback directly
+}
+
+//go:linkname _set_crosscall2 runtime.set_crosscall2
+var _set_crosscall2 = set_crosscall2
+
+// Store the g into the thread-specific value.
+// So that pthread_key_destructor will dropm when the thread is exiting.
+
+//go:linkname x_cgo_bindm_trampoline x_cgo_bindm_trampoline
+//go:linkname _cgo_bindm _cgo_bindm
+var x_cgo_bindm_trampoline byte
+var _cgo_bindm = &x_cgo_bindm_trampoline
+
+// TODO: decide if we need x_cgo_set_context_function
+// TODO: decide if we need _cgo_yield
+
+var (
+	// In Go 1.20 the race detector was rewritten to pure Go
+	// on darwin. This means that when CGO_ENABLED=0 is set
+	// fakecgo is built with race detector code. This is not
+	// good since this code is pretending to be C. The go:norace
+	// pragma is not enough, since it only applies to the native
+	// ABIInternal function. The ABIO wrapper (which is necessary,
+	// since all references to text symbols from assembly will use it)
+	// does not inherit the go:norace pragma, so it will still be
+	// instrumented by the race detector.
+	//
+	// To circumvent this issue, using closure calls in the
+	// assembly, which forces the compiler to use the ABIInternal
+	// native implementation (which has go:norace) instead.
+	threadentry_call        = threadentry
+	x_cgo_init_call         = x_cgo_init
+	x_cgo_setenv_call       = x_cgo_setenv
+	x_cgo_unsetenv_call     = x_cgo_unsetenv
+	x_cgo_thread_start_call = x_cgo_thread_start
+)
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/doc.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/doc.go
new file mode 100644
index 000000000..e482c120c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/doc.go
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+// Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go.
+// This allows code that calls into C to function properly when CGO_ENABLED=0.
+//
+// # Goals
+//
+// fakecgo attempts to replicate the same naming structure as in the runtime.
+// For example, functions that have the prefix "gcc_*" are named "go_*".
+// This makes it easier to port other GOOSs and GOARCHs as well as to keep
+// it in sync with runtime/cgo.
+//
+// # Support
+//
+// Currently, fakecgo only supports macOS on amd64 & arm64. It also cannot
+// be used with -buildmode=c-archive because that requires special initialization
+// that fakecgo does not implement at the moment.
+//
+// # Usage
+//
+// Using fakecgo is easy just import _ "github.com/ebitengine/purego" and then
+// set the environment variable CGO_ENABLED=0.
+// The recommended usage for fakecgo is to prefer using runtime/cgo if possible
+// but if cross-compiling or fast build times are important fakecgo is available.
+// Purego will pick which ever Cgo runtime is available and prefer the one that
+// comes with Go (runtime/cgo).
+package fakecgo
+
+//go:generate go run gen.go
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/fakecgo.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/fakecgo.go
new file mode 100644
index 000000000..384dab2a6
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/fakecgo.go
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package fakecgo
+
+import _ "unsafe"
+
+// setg_trampoline calls setg with the G provided
+func setg_trampoline(setg uintptr, G uintptr)
+
+// call5 takes fn the C function and 5 arguments and calls the function with those arguments
+func call5(fn, a1, a2, a3, a4, a5 uintptr) uintptr
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/freebsd.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/freebsd.go
new file mode 100644
index 000000000..bb73a709e
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/freebsd.go
@@ -0,0 +1,27 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build freebsd && !cgo
+
+package fakecgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ and __progname, because we don't
+// link against the standard FreeBSD crt0.o and the
+// libc dynamic library needs them.
+
+// Note: when building with cross-compiling or CGO_ENABLED=0, add
+// the following argument to `go` so that these symbols are defined by
+// making fakecgo the Cgo.
+//   -gcflags="github.com/ebitengine/purego/internal/fakecgo=-std"
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+
+//go:cgo_export_dynamic environ
+//go:cgo_export_dynamic __progname
+
+var _environ uintptr
+var _progname uintptr
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/go_darwin.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_darwin.go
new file mode 100644
index 000000000..d0868f0f7
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_darwin.go
@@ -0,0 +1,88 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !cgo
+
+package fakecgo
+
+import "unsafe"
+
+//go:nosplit
+//go:norace
+func _cgo_sys_thread_start(ts *ThreadStart) {
+	var attr pthread_attr_t
+	var ign, oset sigset_t
+	var p pthread_t
+	var size size_t
+	var err int
+
+	sigfillset(&ign)
+	pthread_sigmask(SIG_SETMASK, &ign, &oset)
+
+	size = pthread_get_stacksize_np(pthread_self())
+	pthread_attr_init(&attr)
+	pthread_attr_setstacksize(&attr, size)
+	// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+	ts.g.stackhi = uintptr(size)
+
+	err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil)
+
+	if err != 0 {
+		print("fakecgo: pthread_create failed: ")
+		println(err)
+		abort()
+	}
+}
+
+// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
+//
+//go:linkname x_threadentry_trampoline threadentry_trampoline
+var x_threadentry_trampoline byte
+var threadentry_trampolineABI0 = &x_threadentry_trampoline
+
+//go:nosplit
+//go:norace
+func threadentry(v unsafe.Pointer) unsafe.Pointer {
+	ts := *(*ThreadStart)(v)
+	free(v)
+
+	// TODO: support ios
+	//#if TARGET_OS_IPHONE
+	//	darwin_arm_init_thread_exception_port();
+	//#endif
+	setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
+
+	// faking funcs in go is a bit a... involved - but the following works :)
+	fn := uintptr(unsafe.Pointer(&ts.fn))
+	(*(*func())(unsafe.Pointer(&fn)))()
+
+	return nil
+}
+
+// here we will store a pointer to the provided setg func
+var setg_func uintptr
+
+// x_cgo_init(G *g, void (*setg)(void*)) (runtime/cgo/gcc_linux_amd64.c)
+// This get's called during startup, adjusts stacklo, and provides a pointer to setg_gcc for us
+// Additionally, if we set _cgo_init to non-null, go won't do it's own TLS setup
+// This function can't be go:systemstack since go is not in a state where the systemcheck would work.
+//
+//go:nosplit
+//go:norace
+func x_cgo_init(g *G, setg uintptr) {
+	var size size_t
+
+	setg_func = setg
+	size = pthread_get_stacksize_np(pthread_self())
+	g.stacklo = uintptr(unsafe.Add(unsafe.Pointer(&size), -size+4096))
+
+	//TODO: support ios
+	//#if TARGET_OS_IPHONE
+	//	darwin_arm_init_mach_exception_handler();
+	//	darwin_arm_init_thread_exception_port();
+	//	init_working_dir();
+	//#endif
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/go_freebsd.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_freebsd.go
new file mode 100644
index 000000000..a3ba6bc82
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_freebsd.go
@@ -0,0 +1,100 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !cgo
+
+package fakecgo
+
+import "unsafe"
+
+//go:nosplit
+func _cgo_sys_thread_start(ts *ThreadStart) {
+	var attr pthread_attr_t
+	var ign, oset sigset_t
+	var p pthread_t
+	var size size_t
+	var err int
+
+	// fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
+	sigfillset(&ign)
+	pthread_sigmask(SIG_SETMASK, &ign, &oset)
+
+	pthread_attr_init(&attr)
+	pthread_attr_getstacksize(&attr, &size)
+	// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+	ts.g.stackhi = uintptr(size)
+
+	err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil)
+
+	if err != 0 {
+		print("fakecgo: pthread_create failed: ")
+		println(err)
+		abort()
+	}
+}
+
+// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
+//
+//go:linkname x_threadentry_trampoline threadentry_trampoline
+var x_threadentry_trampoline byte
+var threadentry_trampolineABI0 = &x_threadentry_trampoline
+
+//go:nosplit
+func threadentry(v unsafe.Pointer) unsafe.Pointer {
+	ts := *(*ThreadStart)(v)
+	free(v)
+
+	setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
+
+	// faking funcs in go is a bit a... involved - but the following works :)
+	fn := uintptr(unsafe.Pointer(&ts.fn))
+	(*(*func())(unsafe.Pointer(&fn)))()
+
+	return nil
+}
+
+// here we will store a pointer to the provided setg func
+var setg_func uintptr
+
+// x_cgo_init(G *g, void (*setg)(void*)) (runtime/cgo/gcc_linux_amd64.c)
+// This get's called during startup, adjusts stacklo, and provides a pointer to setg_gcc for us
+// Additionally, if we set _cgo_init to non-null, go won't do it's own TLS setup
+// This function can't be go:systemstack since go is not in a state where the systemcheck would work.
+//
+//go:nosplit
+func x_cgo_init(g *G, setg uintptr) {
+	var size size_t
+	var attr *pthread_attr_t
+
+	/* The memory sanitizer distributed with versions of clang
+	   before 3.8 has a bug: if you call mmap before malloc, mmap
+	   may return an address that is later overwritten by the msan
+	   library.  Avoid this problem by forcing a call to malloc
+	   here, before we ever call malloc.
+
+	   This is only required for the memory sanitizer, so it's
+	   unfortunate that we always run it.  It should be possible
+	   to remove this when we no longer care about versions of
+	   clang before 3.8.  The test for this is
+	   misc/cgo/testsanitizers.
+
+	   GCC works hard to eliminate a seemingly unnecessary call to
+	   malloc, so we actually use the memory we allocate.  */
+
+	setg_func = setg
+	attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
+	if attr == nil {
+		println("fakecgo: malloc failed")
+		abort()
+	}
+	pthread_attr_init(attr)
+	pthread_attr_getstacksize(attr, &size)
+	// runtime/cgo uses __builtin_frame_address(0) instead of `uintptr(unsafe.Pointer(&size))`
+	// but this should be OK since we are taking the address of the first variable in this function.
+	g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
+	pthread_attr_destroy(attr)
+	free(unsafe.Pointer(attr))
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/go_libinit.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_libinit.go
new file mode 100644
index 000000000..0c4630669
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_libinit.go
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package fakecgo
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+var (
+	pthread_g pthread_key_t
+
+	runtime_init_cond = PTHREAD_COND_INITIALIZER
+	runtime_init_mu   = PTHREAD_MUTEX_INITIALIZER
+	runtime_init_done int
+)
+
+//go:nosplit
+//go:norace
+func x_cgo_notify_runtime_init_done() {
+	pthread_mutex_lock(&runtime_init_mu)
+	runtime_init_done = 1
+	pthread_cond_broadcast(&runtime_init_cond)
+	pthread_mutex_unlock(&runtime_init_mu)
+}
+
+// Store the g into a thread-specific value associated with the pthread key pthread_g.
+// And pthread_key_destructor will dropm when the thread is exiting.
+//
+//go:norace
+func x_cgo_bindm(g unsafe.Pointer) {
+	// We assume this will always succeed, otherwise, there might be extra M leaking,
+	// when a C thread exits after a cgo call.
+	// We only invoke this function once per thread in runtime.needAndBindM,
+	// and the next calls just reuse the bound m.
+	pthread_setspecific(pthread_g, g)
+}
+
+// _cgo_try_pthread_create retries pthread_create if it fails with
+// EAGAIN.
+//
+//go:nosplit
+//go:norace
+func _cgo_try_pthread_create(thread *pthread_t, attr *pthread_attr_t, pfn unsafe.Pointer, arg *ThreadStart) int {
+	var ts syscall.Timespec
+	// tries needs to be the same type as syscall.Timespec.Nsec
+	// but the fields are int32 on 32bit and int64 on 64bit.
+	// tries is assigned to syscall.Timespec.Nsec in order to match its type.
+	tries := ts.Nsec
+	var err int
+
+	for tries = 0; tries < 20; tries++ {
+		// inlined this call because it ran out of stack when inlining was disabled
+		err = int(call5(pthread_createABI0, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(pfn), uintptr(unsafe.Pointer(arg)), 0))
+		if err == 0 {
+			// inlined this call because it ran out of stack when inlining was disabled
+			call5(pthread_detachABI0, uintptr(*thread), 0, 0, 0, 0)
+			return 0
+		}
+		if err != int(syscall.EAGAIN) {
+			return err
+		}
+		ts.Sec = 0
+		ts.Nsec = (tries + 1) * 1000 * 1000 // Milliseconds.
+		// inlined this call because it ran out of stack when inlining was disabled
+		call5(nanosleepABI0, uintptr(unsafe.Pointer(&ts)), 0, 0, 0, 0)
+	}
+	return int(syscall.EAGAIN)
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/go_linux.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_linux.go
new file mode 100644
index 000000000..9f380c1b4
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_linux.go
@@ -0,0 +1,100 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !cgo
+
+package fakecgo
+
+import "unsafe"
+
+//go:nosplit
+func _cgo_sys_thread_start(ts *ThreadStart) {
+	var attr pthread_attr_t
+	var ign, oset sigset_t
+	var p pthread_t
+	var size size_t
+	var err int
+
+	//fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
+	sigfillset(&ign)
+	pthread_sigmask(SIG_SETMASK, &ign, &oset)
+
+	pthread_attr_init(&attr)
+	pthread_attr_getstacksize(&attr, &size)
+	// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+	ts.g.stackhi = uintptr(size)
+
+	err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil)
+
+	if err != 0 {
+		print("fakecgo: pthread_create failed: ")
+		println(err)
+		abort()
+	}
+}
+
+// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
+//
+//go:linkname x_threadentry_trampoline threadentry_trampoline
+var x_threadentry_trampoline byte
+var threadentry_trampolineABI0 = &x_threadentry_trampoline
+
+//go:nosplit
+func threadentry(v unsafe.Pointer) unsafe.Pointer {
+	ts := *(*ThreadStart)(v)
+	free(v)
+
+	setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
+
+	// faking funcs in go is a bit a... involved - but the following works :)
+	fn := uintptr(unsafe.Pointer(&ts.fn))
+	(*(*func())(unsafe.Pointer(&fn)))()
+
+	return nil
+}
+
+// here we will store a pointer to the provided setg func
+var setg_func uintptr
+
+// x_cgo_init(G *g, void (*setg)(void*)) (runtime/cgo/gcc_linux_amd64.c)
+// This get's called during startup, adjusts stacklo, and provides a pointer to setg_gcc for us
+// Additionally, if we set _cgo_init to non-null, go won't do it's own TLS setup
+// This function can't be go:systemstack since go is not in a state where the systemcheck would work.
+//
+//go:nosplit
+func x_cgo_init(g *G, setg uintptr) {
+	var size size_t
+	var attr *pthread_attr_t
+
+	/* The memory sanitizer distributed with versions of clang
+	   before 3.8 has a bug: if you call mmap before malloc, mmap
+	   may return an address that is later overwritten by the msan
+	   library.  Avoid this problem by forcing a call to malloc
+	   here, before we ever call malloc.
+
+	   This is only required for the memory sanitizer, so it's
+	   unfortunate that we always run it.  It should be possible
+	   to remove this when we no longer care about versions of
+	   clang before 3.8.  The test for this is
+	   misc/cgo/testsanitizers.
+
+	   GCC works hard to eliminate a seemingly unnecessary call to
+	   malloc, so we actually use the memory we allocate.  */
+
+	setg_func = setg
+	attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
+	if attr == nil {
+		println("fakecgo: malloc failed")
+		abort()
+	}
+	pthread_attr_init(attr)
+	pthread_attr_getstacksize(attr, &size)
+	// runtime/cgo uses __builtin_frame_address(0) instead of `uintptr(unsafe.Pointer(&size))`
+	// but this should be OK since we are taking the address of the first variable in this function.
+	g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
+	pthread_attr_destroy(attr)
+	free(unsafe.Pointer(attr))
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/go_netbsd.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_netbsd.go
new file mode 100644
index 000000000..935a334f2
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_netbsd.go
@@ -0,0 +1,106 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !cgo && (amd64 || arm64)
+
+package fakecgo
+
+import "unsafe"
+
+//go:nosplit
+func _cgo_sys_thread_start(ts *ThreadStart) {
+	var attr pthread_attr_t
+	var ign, oset sigset_t
+	var p pthread_t
+	var size size_t
+	var err int
+
+	// fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
+	sigfillset(&ign)
+	pthread_sigmask(SIG_SETMASK, &ign, &oset)
+
+	pthread_attr_init(&attr)
+	pthread_attr_getstacksize(&attr, &size)
+	// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
+	ts.g.stackhi = uintptr(size)
+
+	err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil)
+
+	if err != 0 {
+		print("fakecgo: pthread_create failed: ")
+		println(err)
+		abort()
+	}
+}
+
+// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
+//
+//go:linkname x_threadentry_trampoline threadentry_trampoline
+var x_threadentry_trampoline byte
+var threadentry_trampolineABI0 = &x_threadentry_trampoline
+
+//go:nosplit
+func threadentry(v unsafe.Pointer) unsafe.Pointer {
+	var ss stack_t
+	ts := *(*ThreadStart)(v)
+	free(v)
+
+	// On NetBSD, a new thread inherits the signal stack of the
+	// creating thread. That confuses minit, so we remove that
+	// signal stack here before calling the regular mstart. It's
+	// a bit baroque to remove a signal stack here only to add one
+	// in minit, but it's a simple change that keeps NetBSD
+	// working like other OS's. At this point all signals are
+	// blocked, so there is no race.
+	ss.ss_flags = SS_DISABLE
+	sigaltstack(&ss, nil)
+
+	setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
+
+	// faking funcs in go is a bit a... involved - but the following works :)
+	fn := uintptr(unsafe.Pointer(&ts.fn))
+	(*(*func())(unsafe.Pointer(&fn)))()
+
+	return nil
+}
+
+// here we will store a pointer to the provided setg func
+var setg_func uintptr
+
+//go:nosplit
+func x_cgo_init(g *G, setg uintptr) {
+	var size size_t
+	var attr *pthread_attr_t
+
+	/* The memory sanitizer distributed with versions of clang
+	   before 3.8 has a bug: if you call mmap before malloc, mmap
+	   may return an address that is later overwritten by the msan
+	   library.  Avoid this problem by forcing a call to malloc
+	   here, before we ever call malloc.
+
+	   This is only required for the memory sanitizer, so it's
+	   unfortunate that we always run it.  It should be possible
+	   to remove this when we no longer care about versions of
+	   clang before 3.8.  The test for this is
+	   misc/cgo/testsanitizers.
+
+	   GCC works hard to eliminate a seemingly unnecessary call to
+	   malloc, so we actually use the memory we allocate.  */
+
+	setg_func = setg
+	attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
+	if attr == nil {
+		println("fakecgo: malloc failed")
+		abort()
+	}
+	pthread_attr_init(attr)
+	pthread_attr_getstacksize(attr, &size)
+	// runtime/cgo uses __builtin_frame_address(0) instead of `uintptr(unsafe.Pointer(&size))`
+	// but this should be OK since we are taking the address of the first variable in this function.
+	g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
+	pthread_attr_destroy(attr)
+	free(unsafe.Pointer(attr))
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/go_setenv.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_setenv.go
new file mode 100644
index 000000000..dfc6629e4
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_setenv.go
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package fakecgo
+
+//go:nosplit
+//go:norace
+func x_cgo_setenv(arg *[2]*byte) {
+	setenv(arg[0], arg[1], 1)
+}
+
+//go:nosplit
+//go:norace
+func x_cgo_unsetenv(arg *[1]*byte) {
+	unsetenv(arg[0])
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/go_util.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_util.go
new file mode 100644
index 000000000..ee993baae
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/go_util.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package fakecgo
+
+import "unsafe"
+
+// _cgo_thread_start is split into three parts in cgo since only one part is system dependent (keep it here for easier handling)
+
+// _cgo_thread_start(ThreadStart *arg) (runtime/cgo/gcc_util.c)
+// This get's called instead of the go code for creating new threads
+// -> pthread_* stuff is used, so threads are setup correctly for C
+// If this is missing, TLS is only setup correctly on thread 1!
+// This function should be go:systemstack instead of go:nosplit (but that requires runtime)
+//
+//go:nosplit
+//go:norace
+func x_cgo_thread_start(arg *ThreadStart) {
+	var ts *ThreadStart
+	// Make our own copy that can persist after we return.
+	//	_cgo_tsan_acquire();
+	ts = (*ThreadStart)(malloc(unsafe.Sizeof(*ts)))
+	//	_cgo_tsan_release();
+	if ts == nil {
+		println("fakecgo: out of memory in thread_start")
+		abort()
+	}
+	// *ts = *arg would cause a writebarrier so copy using slices
+	const ptrSize = unsafe.Sizeof(uintptr(0))
+	s1 := unsafe.Slice((*uintptr)(unsafe.Pointer(ts)), unsafe.Sizeof(*ts)/ptrSize)
+	s2 := unsafe.Slice((*uintptr)(unsafe.Pointer(arg)), unsafe.Sizeof(*arg)/ptrSize)
+	for i := range s2 {
+		s1[i] = s2[i]
+	}
+	_cgo_sys_thread_start(ts) // OS-dependent half
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/iscgo.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/iscgo.go
new file mode 100644
index 000000000..12e521470
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/iscgo.go
@@ -0,0 +1,19 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+// The runtime package contains an uninitialized definition
+// for runtime·iscgo. Override it to tell the runtime we're here.
+// There are various function pointers that should be set too,
+// but those depend on dynamic linker magic to get initialized
+// correctly, and sometimes they break. This variable is a
+// backup: it depends only on old C style static linking rules.
+
+package fakecgo
+
+import _ "unsafe" // for go:linkname
+
+//go:linkname _iscgo runtime.iscgo
+var _iscgo bool = true
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo.go
new file mode 100644
index 000000000..94fd8beab
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo.go
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package fakecgo
+
+type (
+	size_t uintptr
+	// Sources:
+	// Darwin (32 bytes) - https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/_types.h#L74
+	// FreeBSD (32 bytes) - https://github.com/DoctorWkt/xv6-freebsd/blob/d2a294c2a984baed27676068b15ed9a29b06ab6f/include/signal.h#L98C9-L98C21
+	// Linux (128 bytes) - https://github.com/torvalds/linux/blob/ab75170520d4964f3acf8bb1f91d34cbc650688e/arch/x86/include/asm/signal.h#L25
+	sigset_t       [128]byte
+	pthread_attr_t [64]byte
+	pthread_t      int
+	pthread_key_t  uint64
+)
+
+// for pthread_sigmask:
+
+type sighow int32
+
+const (
+	SIG_BLOCK   sighow = 0
+	SIG_UNBLOCK sighow = 1
+	SIG_SETMASK sighow = 2
+)
+
+type G struct {
+	stacklo uintptr
+	stackhi uintptr
+}
+
+type ThreadStart struct {
+	g   *G
+	tls *uintptr
+	fn  uintptr
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_darwin.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_darwin.go
new file mode 100644
index 000000000..ecdcb2e78
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_darwin.go
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package fakecgo
+
+type (
+	pthread_mutex_t struct {
+		sig    int64
+		opaque [56]byte
+	}
+	pthread_cond_t struct {
+		sig    int64
+		opaque [40]byte
+	}
+)
+
+var (
+	PTHREAD_COND_INITIALIZER  = pthread_cond_t{sig: 0x3CB0B1BB}
+	PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{sig: 0x32AAABA7}
+)
+
+type stack_t struct {
+	/* not implemented */
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_freebsd.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_freebsd.go
new file mode 100644
index 000000000..4bfb70c3d
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_freebsd.go
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package fakecgo
+
+type (
+	pthread_cond_t  uintptr
+	pthread_mutex_t uintptr
+)
+
+var (
+	PTHREAD_COND_INITIALIZER  = pthread_cond_t(0)
+	PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
+)
+
+type stack_t struct {
+	/* not implemented */
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_linux.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_linux.go
new file mode 100644
index 000000000..b08a44a10
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_linux.go
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package fakecgo
+
+type (
+	pthread_cond_t  [48]byte
+	pthread_mutex_t [48]byte
+)
+
+var (
+	PTHREAD_COND_INITIALIZER  = pthread_cond_t{}
+	PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{}
+)
+
+type stack_t struct {
+	/* not implemented */
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_netbsd.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_netbsd.go
new file mode 100644
index 000000000..650f6953e
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/libcgo_netbsd.go
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+//go:build !cgo
+
+package fakecgo
+
+type (
+	pthread_cond_t  uintptr
+	pthread_mutex_t uintptr
+)
+
+var (
+	PTHREAD_COND_INITIALIZER  = pthread_cond_t(0)
+	PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
+)
+
+// Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/compat/linux/arch/m68k/linux_signal.h#L133
+type stack_t struct {
+	ss_sp    uintptr
+	ss_flags int32
+	ss_size  uintptr
+}
+
+// Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L261
+const SS_DISABLE = 0x004
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/netbsd.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/netbsd.go
new file mode 100644
index 000000000..2d499814f
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/netbsd.go
@@ -0,0 +1,23 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build netbsd
+
+package fakecgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ and __progname, because we don't
+// link against the standard NetBSD crt0.o and the
+// libc dynamic library needs them.
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+//go:linkname ___ps_strings __ps_strings
+
+var (
+	_environ      uintptr
+	_progname     uintptr
+	___ps_strings uintptr
+)
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/setenv.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/setenv.go
new file mode 100644
index 000000000..82308b8ca
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/setenv.go
@@ -0,0 +1,19 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package fakecgo
+
+import _ "unsafe" // for go:linkname
+
+//go:linkname x_cgo_setenv_trampoline x_cgo_setenv_trampoline
+//go:linkname _cgo_setenv runtime._cgo_setenv
+var x_cgo_setenv_trampoline byte
+var _cgo_setenv = &x_cgo_setenv_trampoline
+
+//go:linkname x_cgo_unsetenv_trampoline x_cgo_unsetenv_trampoline
+//go:linkname _cgo_unsetenv runtime._cgo_unsetenv
+var x_cgo_unsetenv_trampoline byte
+var _cgo_unsetenv = &x_cgo_unsetenv_trampoline
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_386.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_386.s
new file mode 100644
index 000000000..cd3492ea7
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_386.s
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build !cgo && (freebsd || linux)
+
+#include "textflag.h"
+#include "go_asm.h"
+
+// These trampolines map the gcc ABI to Go ABI0 and then call into the Go equivalent functions.
+// On i386, both GCC and Go use stack-based calling conventions.
+//
+// When C calls a function, the stack looks like:
+//   0(SP) = return address
+//   4(SP) = arg1
+//   8(SP) = arg2
+//   ...
+//
+// When we declare a Go function with frame size $N-0, Go's prologue
+// effectively does SUB $N, SP, so the C arguments shift up by N bytes:
+//   N+0(SP) = return address
+//   N+4(SP) = arg1
+//   N+8(SP) = arg2
+//
+// Go ABI0 on 386 expects arguments starting at 0(FP) which equals N+4(SP)
+// after the prologue (where N is the local frame size).
+
+TEXT x_cgo_init_trampoline(SB), NOSPLIT, $8-0
+	// C args at 12(SP) and 16(SP) after frame setup (8 bytes local + 4 bytes ret addr)
+	// Go function expects args at 0(SP) and 4(SP) in local frame
+	MOVL 12(SP), AX               // first C arg
+	MOVL 16(SP), BX               // second C arg
+	MOVL AX, 0(SP)                // Go arg 1
+	MOVL BX, 4(SP)                // Go arg 2
+	MOVL ·x_cgo_init_call(SB), CX
+	MOVL (CX), CX
+	CALL CX
+	RET
+
+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $4-0
+	// C args at 8(SP) after frame setup (4 bytes local + 4 bytes ret addr)
+	MOVL 8(SP), AX                        // first C arg
+	MOVL AX, 0(SP)                        // Go arg 1
+	MOVL ·x_cgo_thread_start_call(SB), CX
+	MOVL (CX), CX
+	CALL CX
+	RET
+
+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $4-0
+	MOVL 8(SP), AX                  // first C arg
+	MOVL AX, 0(SP)                  // Go arg 1
+	MOVL ·x_cgo_setenv_call(SB), CX
+	MOVL (CX), CX
+	CALL CX
+	RET
+
+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $4-0
+	MOVL 8(SP), AX                    // first C arg
+	MOVL AX, 0(SP)                    // Go arg 1
+	MOVL ·x_cgo_unsetenv_call(SB), CX
+	MOVL (CX), CX
+	CALL CX
+	RET
+
+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0-0
+	CALL ·x_cgo_notify_runtime_init_done(SB)
+	RET
+
+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
+	CALL ·x_cgo_bindm(SB)
+	RET
+
+// func setg_trampoline(setg uintptr, g uintptr)
+// This is called from Go, so args are at normal FP positions
+TEXT ·setg_trampoline(SB), NOSPLIT, $4-8
+	MOVL g+4(FP), AX
+	MOVL setg+0(FP), BX
+
+	// setg expects g in 0(SP)
+	MOVL AX, 0(SP)
+	CALL BX
+	RET
+
+TEXT threadentry_trampoline(SB), NOSPLIT, $4-0
+	MOVL 8(SP), AX                 // first C arg
+	MOVL AX, 0(SP)                 // Go arg 1
+	MOVL ·threadentry_call(SB), CX
+	MOVL (CX), CX
+	CALL CX
+	RET
+
+TEXT ·call5(SB), NOSPLIT, $20-28
+	MOVL fn+0(FP), AX
+	MOVL a1+4(FP), BX
+	MOVL a2+8(FP), CX
+	MOVL a3+12(FP), DX
+	MOVL a4+16(FP), SI
+	MOVL a5+20(FP), DI
+
+	// Place arguments on local stack frame for C calling convention
+	MOVL BX, 0(SP)     // a1
+	MOVL CX, 4(SP)     // a2
+	MOVL DX, 8(SP)     // a3
+	MOVL SI, 12(SP)    // a4
+	MOVL DI, 16(SP)    // a5
+	CALL AX
+	MOVL AX, r1+24(FP)
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_amd64.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_amd64.s
new file mode 100644
index 000000000..e4e4c75a3
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_amd64.s
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || linux || freebsd)
+
+/*
+trampoline for emulating required C functions for cgo in go (see cgo.go)
+(we convert cdecl calling convention to go and vice-versa)
+
+C Calling convention cdecl used here (we only need integer args):
+1. arg: DI
+2. arg: SI
+3. arg: DX
+4. arg: CX
+5. arg: R8
+6. arg: R9
+We don't need floats with these functions -> AX=0
+return value will be in AX
+temporary register is R11
+*/
+#include "textflag.h"
+#include "go_asm.h"
+#include "abi_amd64.h"
+
+// these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
+
+TEXT x_cgo_init_trampoline(SB), NOSPLIT, $16
+	MOVQ DI, AX
+	MOVQ SI, BX
+	MOVQ ·x_cgo_init_call(SB), R11
+	MOVQ (R11), R11
+	CALL R11
+	RET
+
+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8
+	MOVQ DI, AX
+	MOVQ ·x_cgo_thread_start_call(SB), R11
+	MOVQ (R11), R11
+	CALL R11
+	RET
+
+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8
+	MOVQ DI, AX
+	MOVQ ·x_cgo_setenv_call(SB), R11
+	MOVQ (R11), R11
+	CALL R11
+	RET
+
+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8
+	MOVQ DI, AX
+	MOVQ ·x_cgo_unsetenv_call(SB), R11
+	MOVQ (R11), R11
+	CALL R11
+	RET
+
+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0
+	JMP ·x_cgo_notify_runtime_init_done(SB)
+
+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
+	JMP ·x_cgo_bindm(SB)
+
+// func setg_trampoline(setg uintptr, g uintptr)
+TEXT ·setg_trampoline(SB), NOSPLIT, $0-16
+	MOVQ G+8(FP), DI
+	MOVQ setg+0(FP), R11
+	XORL AX, AX
+	CALL R11
+	RET
+
+TEXT threadentry_trampoline(SB), NOSPLIT, $0
+	// See crosscall2.
+	PUSH_REGS_HOST_TO_ABI0()
+
+	// X15 is designated by Go as a fixed zero register.
+	// Calling directly into ABIInternal, ensure it is zero.
+	PXOR X15, X15
+
+	MOVQ DI, AX
+	MOVQ ·threadentry_call(SB), R11
+	MOVQ (R11), R11
+	CALL R11
+
+	POP_REGS_HOST_TO_ABI0()
+	RET
+
+TEXT ·call5(SB), NOSPLIT, $0-56
+	MOVQ fn+0(FP), R11
+	MOVQ a1+8(FP), DI
+	MOVQ a2+16(FP), SI
+	MOVQ a3+24(FP), DX
+	MOVQ a4+32(FP), CX
+	MOVQ a5+40(FP), R8
+
+	XORL AX, AX // no floats
+
+	PUSHQ BP       // save BP
+	MOVQ  SP, BP   // save SP inside BP bc BP is callee-saved
+	SUBQ  $16, SP  // allocate space for alignment
+	ANDQ  $-16, SP // align on 16 bytes for SSE
+
+	CALL R11
+
+	MOVQ BP, SP // get SP back
+	POPQ BP     // restore BP
+
+	MOVQ AX, ret+48(FP)
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_arm.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_arm.s
new file mode 100644
index 000000000..00b3177ef
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_arm.s
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build !cgo && (freebsd || linux)
+
+#include "textflag.h"
+#include "go_asm.h"
+
+// These trampolines map the gcc ABI to Go ABI0 and then call into the Go equivalent functions.
+// On ARM32, Go ABI0 uses stack-based calling convention.
+// Arguments are placed on the stack starting at 4(SP) after the prologue.
+
+TEXT x_cgo_init_trampoline(SB), NOSPLIT, $8-0
+	MOVW R0, 4(R13)
+	MOVW R1, 8(R13)
+	MOVW ·x_cgo_init_call(SB), R12
+	MOVW (R12), R12
+	CALL (R12)
+	RET
+
+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8-0
+	MOVW R0, 4(R13)
+	MOVW ·x_cgo_thread_start_call(SB), R12
+	MOVW (R12), R12
+	CALL (R12)
+	RET
+
+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8-0
+	MOVW R0, 4(R13)
+	MOVW ·x_cgo_setenv_call(SB), R12
+	MOVW (R12), R12
+	CALL (R12)
+	RET
+
+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8-0
+	MOVW R0, 4(R13)
+	MOVW ·x_cgo_unsetenv_call(SB), R12
+	MOVW (R12), R12
+	CALL (R12)
+	RET
+
+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0-0
+	CALL ·x_cgo_notify_runtime_init_done(SB)
+	RET
+
+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
+	CALL ·x_cgo_bindm(SB)
+	RET
+
+// func setg_trampoline(setg uintptr, g uintptr)
+TEXT ·setg_trampoline(SB), NOSPLIT, $0-8
+	MOVW G+4(FP), R0
+	MOVW setg+0(FP), R12
+	BL   (R12)
+	RET
+
+TEXT threadentry_trampoline(SB), NOSPLIT, $8-0
+	// See crosscall2.
+	MOVW R0, 4(R13)
+	MOVW ·threadentry_call(SB), R12
+	MOVW (R12), R12
+	CALL (R12)
+	RET
+
+TEXT ·call5(SB), NOSPLIT, $8-28
+	MOVW fn+0(FP), R12
+	MOVW a1+4(FP), R0
+	MOVW a2+8(FP), R1
+	MOVW a3+12(FP), R2
+	MOVW a4+16(FP), R3
+	MOVW a5+20(FP), R4
+
+	// Store 5th arg below SP (in local frame area)
+	MOVW R4, arg5-8(SP)
+
+	// Align SP to 8 bytes for call (required by ARM AAPCS)
+	SUB  $8, R13
+	CALL (R12)
+	ADD  $8, R13
+	MOVW R0, r1+24(FP)
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_arm64.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_arm64.s
new file mode 100644
index 000000000..dceb1cac6
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_arm64.s
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux)
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "abi_arm64.h"
+
+// These trampolines map the gcc ABI to Go ABIInternal and then calls into the Go equivalent functions.
+// Note that C arguments are passed in R0-R7, which matches Go ABIInternal for the first eight arguments.
+// R9 is used as a temporary register.
+
+TEXT x_cgo_init_trampoline(SB), NOSPLIT, $0-0
+	MOVD ·x_cgo_init_call(SB), R9
+	MOVD (R9), R9
+	CALL R9
+	RET
+
+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $0-0
+	MOVD ·x_cgo_thread_start_call(SB), R9
+	MOVD (R9), R9
+	CALL R9
+	RET
+
+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $0-0
+	MOVD ·x_cgo_setenv_call(SB), R9
+	MOVD (R9), R9
+	CALL R9
+	RET
+
+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $0-0
+	MOVD ·x_cgo_unsetenv_call(SB), R9
+	MOVD (R9), R9
+	CALL R9
+	RET
+
+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0-0
+	CALL ·x_cgo_notify_runtime_init_done(SB)
+	RET
+
+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
+	CALL ·x_cgo_bindm(SB)
+	RET
+
+// func setg_trampoline(setg uintptr, g uintptr)
+TEXT ·setg_trampoline(SB), NOSPLIT, $0-16
+	MOVD G+8(FP), R0
+	MOVD setg+0(FP), R9
+	CALL R9
+	RET
+
+TEXT threadentry_trampoline(SB), NOSPLIT, $0-0
+	// See crosscall2.
+	SUB  $(8*24), RSP
+	STP  (R0, R1), (8*1)(RSP)
+	MOVD R3, (8*3)(RSP)
+
+	SAVE_R19_TO_R28(8*4)
+	SAVE_F8_TO_F15(8*14)
+	STP (R29, R30), (8*22)(RSP)
+
+	MOVD ·threadentry_call(SB), R9
+	MOVD (R9), R9
+	CALL R9
+	MOVD $0, R0                    // TODO: get the return value from threadentry
+
+	RESTORE_R19_TO_R28(8*4)
+	RESTORE_F8_TO_F15(8*14)
+	LDP (8*22)(RSP), (R29, R30)
+
+	ADD $(8*24), RSP
+	RET
+
+TEXT ·call5(SB), NOSPLIT, $0-0
+	MOVD fn+0(FP), R9
+	MOVD a1+8(FP), R0
+	MOVD a2+16(FP), R1
+	MOVD a3+24(FP), R2
+	MOVD a4+32(FP), R3
+	MOVD a5+40(FP), R4
+	CALL R9
+	MOVD R0, ret+48(FP)
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_loong64.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_loong64.s
new file mode 100644
index 000000000..7596f0da1
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_loong64.s
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+//go:build !cgo && linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "abi_loong64.h"
+
+// these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
+// R23 is used as temporary register.
+
+TEXT x_cgo_init_trampoline(SB), NOSPLIT, $16
+	MOVV R4, 8(R3)
+	MOVV R5, 16(R3)
+	MOVV ·x_cgo_init_call(SB), R23
+	MOVV (R23), R23
+	CALL (R23)
+	RET
+
+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8
+	MOVV R4, 8(R3)
+	MOVV ·x_cgo_thread_start_call(SB), R23
+	MOVV (R23), R23
+	CALL (R23)
+	RET
+
+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8
+	MOVV R4, 8(R3)
+	MOVV ·x_cgo_setenv_call(SB), R23
+	MOVV (R23), R23
+	CALL (R23)
+	RET
+
+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8
+	MOVV R4, 8(R3)
+	MOVV ·x_cgo_unsetenv_call(SB), R23
+	MOVV (R23), R23
+	CALL (R23)
+	RET
+
+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0
+	CALL ·x_cgo_notify_runtime_init_done(SB)
+	RET
+
+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
+	CALL ·x_cgo_bindm(SB)
+	RET
+
+// func setg_trampoline(setg uintptr, g uintptr)
+TEXT ·setg_trampoline(SB), NOSPLIT, $0
+	MOVV G+8(FP), R4
+	MOVV setg+0(FP), R23
+	CALL (R23)
+	RET
+
+TEXT threadentry_trampoline(SB), NOSPLIT, $0
+	// See crosscall2.
+	ADDV $(-23*8), R3
+	MOVV R4, (1*8)(R3) // fn unsafe.Pointer
+	MOVV R5, (2*8)(R3) // a unsafe.Pointer
+	MOVV R7, (3*8)(R3) // ctxt uintptr
+
+	SAVE_R22_TO_R31((4*8))
+	SAVE_F24_TO_F31((14*8))
+	MOVV R1, (22*8)(R3)
+
+	MOVV ·threadentry_call(SB), R23
+	MOVV (R23), R23
+	CALL (R23)
+
+	RESTORE_R22_TO_R31((4*8))
+	RESTORE_F24_TO_F31((14*8))
+	MOVV (22*8)(R3), R1
+
+	ADDV $(23*8), R3
+	RET
+
+TEXT ·call5(SB), NOSPLIT, $0-0
+	MOVV fn+0(FP), R23
+	MOVV a1+8(FP), R4
+	MOVV a2+16(FP), R5
+	MOVV a3+24(FP), R6
+	MOVV a4+32(FP), R7
+	MOVV a5+40(FP), R8
+	CALL (R23)
+	MOVV R4, ret+48(FP)
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_ppc64le.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_ppc64le.s
new file mode 100644
index 000000000..85f895564
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_ppc64le.s
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build !cgo && linux
+
+#include "textflag.h"
+#include "go_asm.h"
+
+// These trampolines map the C ABI to Go ABI and call into the Go equivalent functions.
+//
+// PPC64LE ELFv2 ABI stack frame layout:
+//   0(R1)  = backchain (pointer to caller's frame)
+//   8(R1)  = CR save area
+//   16(R1) = LR save area
+//   24(R1) = reserved
+//   32(R1) = parameter save area (minimum 64 bytes for 8 args)
+//
+// Two patterns are used depending on call direction:
+//
+// C→Go trampolines: The C caller already provides a 32-byte linkage area.
+//   Save LR/CR into caller's frame at 16(R1)/8(R1) BEFORE allocating,
+//   then use MOVDU to allocate and set backchain atomically.
+//
+// Go→C trampolines: Go callers don't provide ELFv2 linkage area.
+//   Allocate frame first with MOVDU, then save LR/CR into OUR frame.
+
+TEXT x_cgo_init_trampoline(SB), NOSPLIT|NOFRAME, $0-0
+	MOVD LR, 16(R1)
+	MOVW CR, R0
+	MOVD R0, 8(R1)
+
+	MOVDU R1, -32(R1)
+
+	// R3, R4 already have the arguments
+	MOVD ·x_cgo_init_call(SB), R12
+	MOVD (R12), R12
+	MOVD R12, CTR
+	CALL CTR
+
+	ADD $32, R1
+
+	MOVD 16(R1), LR
+	MOVD 8(R1), R0
+	MOVW R0, CR
+	RET
+
+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT|NOFRAME, $0-0
+	MOVD LR, 16(R1)
+	MOVW CR, R0
+	MOVD R0, 8(R1)
+
+	MOVDU R1, -32(R1)
+
+	MOVD ·x_cgo_thread_start_call(SB), R12
+	MOVD (R12), R12
+	MOVD R12, CTR
+	CALL CTR
+
+	ADD $32, R1
+
+	MOVD 16(R1), LR
+	MOVD 8(R1), R0
+	MOVW R0, CR
+	RET
+
+// void (*_cgo_setenv)(char**)
+// C arg: R3 = pointer to env
+// This is C→Go: caller is C ABI.
+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
+	MOVD LR, 16(R1)
+	MOVW CR, R0
+	MOVD R0, 8(R1)
+
+	MOVDU R1, -32(R1)
+
+	MOVD ·x_cgo_setenv_call(SB), R12
+	MOVD (R12), R12
+	MOVD R12, CTR
+	CALL CTR
+
+	ADD $32, R1
+
+	MOVD 16(R1), LR
+	MOVD 8(R1), R0
+	MOVW R0, CR
+	RET
+
+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
+	MOVD LR, 16(R1)
+	MOVW CR, R0
+	MOVD R0, 8(R1)
+
+	MOVDU R1, -32(R1)
+
+	MOVD ·x_cgo_unsetenv_call(SB), R12
+	MOVD (R12), R12
+	MOVD R12, CTR
+	CALL CTR
+
+	ADD $32, R1
+
+	MOVD 16(R1), LR
+	MOVD 8(R1), R0
+	MOVW R0, CR
+	RET
+
+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT|NOFRAME, $0-0
+	MOVD LR, 16(R1)
+	MOVW CR, R0
+	MOVD R0, 8(R1)
+
+	MOVDU R1, -32(R1)
+
+	CALL ·x_cgo_notify_runtime_init_done(SB)
+
+	ADD $32, R1
+
+	MOVD 16(R1), LR
+	MOVD 8(R1), R0
+	MOVW R0, CR
+	RET
+
+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT|NOFRAME, $0-0
+	MOVD LR, 16(R1)
+	MOVW CR, R0
+	MOVD R0, 8(R1)
+
+	MOVDU R1, -32(R1)
+
+	CALL ·x_cgo_bindm(SB)
+
+	ADD $32, R1
+
+	MOVD 16(R1), LR
+	MOVD 8(R1), R0
+	MOVW R0, CR
+	RET
+
+TEXT ·setg_trampoline(SB), NOSPLIT|NOFRAME, $0-16
+	// Save LR, CR, and R31 to non-volatile registers (C ABI preserves R14-R31)
+	MOVD LR, R20
+	MOVW CR, R21
+	MOVD R31, R22 // save R31 because load_g clobbers it
+
+	// Load arguments from Go stack
+	MOVD 32(R1), R12 // setg function pointer
+	MOVD 40(R1), R3  // g pointer → first C arg
+
+	// Allocate ELFv2 frame for the C callee (32 bytes minimum)
+	MOVDU R1, -32(R1)
+
+	// Call setg_gcc which stores g to TLS
+	MOVD R12, CTR
+	CALL CTR
+
+	// setg_gcc stored g to TLS but restored old g in R30.
+	// Call load_g to reload g from TLS into R30.
+	// Note: load_g clobbers R31
+	CALL runtime·load_g(SB)
+
+	// Deallocate frame
+	ADD $32, R1
+
+	// Clear R0 before returning to Go code.
+	// Go uses R0 as a constant 0 for things like "std r0,X(r1)" to zero stack locations.
+	// C/assembly functions may leave garbage in R0.
+	XOR R0, R0, R0
+
+	// Restore LR, CR, and R31 from non-volatile registers
+	MOVD R22, R31 // restore R31
+	MOVD R20, LR
+	MOVW R21, CR
+	RET
+
+TEXT threadentry_trampoline(SB), NOSPLIT|NOFRAME, $0-0
+	MOVD LR, 16(R1)
+	MOVW CR, R0
+	MOVD R0, 8(R1)
+
+	MOVDU R1, -32(R1)
+
+	MOVD ·threadentry_call(SB), R12
+	MOVD (R12), R12
+	MOVD R12, CTR
+	CALL CTR
+
+	ADD $32, R1
+
+	MOVD 16(R1), LR
+	MOVD 8(R1), R0
+	MOVW R0, CR
+	RET
+
+TEXT ·call5(SB), NOSPLIT|NOFRAME, $0-56
+	MOVD LR, R20
+	MOVW CR, R21
+
+	// Load arguments from Go stack into C argument registers
+	// Go placed args at 32(R1), 40(R1), etc.
+	MOVD 32(R1), R12 // fn
+	MOVD 40(R1), R3  // a1 → first C arg
+	MOVD 48(R1), R4  // a2 → second C arg
+	MOVD 56(R1), R5  // a3 → third C arg
+	MOVD 64(R1), R6  // a4 → fourth C arg
+	MOVD 72(R1), R7  // a5 → fifth C arg
+
+	MOVDU R1, -32(R1)
+
+	MOVD R12, CTR
+	CALL CTR
+
+	// Store return value
+	// After MOVDU -32, original 80(R1) is now at 80+32=112(R1)
+	MOVD R3, (80+32)(R1)
+
+	// Deallocate frame
+	ADD $32, R1
+
+	// Clear R0 before returning to Go code.
+	// Go uses R0 as a constant 0 register for things like "std r0,X(r1)"
+	// to zero stack locations. C functions may leave garbage in R0.
+	XOR R0, R0, R0
+
+	// Restore LR/CR from non-volatile registers
+	MOVD R20, LR
+	MOVW R21, CR
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_riscv64.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_riscv64.s
new file mode 100644
index 000000000..9298f8c71
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/trampolines_riscv64.s
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build !cgo && linux
+
+#include "textflag.h"
+#include "go_asm.h"
+
+// these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
+// X5 is used as temporary register.
+
+TEXT x_cgo_init_trampoline(SB), NOSPLIT, $16
+	MOV  X10, 8(SP)
+	MOV  X11, 16(SP)
+	MOV  ·x_cgo_init_call(SB), X5
+	MOV  (X5), X5
+	CALL X5
+	RET
+
+TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8
+	MOV  X10, 8(SP)
+	MOV  ·x_cgo_thread_start_call(SB), X5
+	MOV  (X5), X5
+	CALL X5
+	RET
+
+TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8
+	MOV  X10, 8(SP)
+	MOV  ·x_cgo_setenv_call(SB), X5
+	MOV  (X5), X5
+	CALL X5
+	RET
+
+TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8
+	MOV  X10, 8(SP)
+	MOV  ·x_cgo_unsetenv_call(SB), X5
+	MOV  (X5), X5
+	CALL X5
+	RET
+
+TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0
+	CALL ·x_cgo_notify_runtime_init_done(SB)
+	RET
+
+TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
+	CALL ·x_cgo_bindm(SB)
+	RET
+
+// func setg_trampoline(setg uintptr, g uintptr)
+TEXT ·setg_trampoline(SB), NOSPLIT, $0
+	MOV  gp+8(FP), X10
+	MOV  setg+0(FP), X5
+	CALL X5
+	RET
+
+TEXT threadentry_trampoline(SB), NOSPLIT, $16
+	MOV  X10, 8(SP)
+	MOV  ·threadentry_call(SB), X5
+	MOV  (X5), X5
+	CALL X5
+	RET
+
+TEXT ·call5(SB), NOSPLIT, $0-48
+	MOV  fn+0(FP), X5
+	MOV  a1+8(FP), X10
+	MOV  a2+16(FP), X11
+	MOV  a3+24(FP), X12
+	MOV  a4+32(FP), X13
+	MOV  a5+40(FP), X14
+	CALL X5
+	MOV  X10, ret+48(FP)
+	RET
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols.go
new file mode 100644
index 000000000..cc552e7d3
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols.go
@@ -0,0 +1,165 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package fakecgo
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+//go:nosplit
+//go:norace
+func malloc(size uintptr) unsafe.Pointer {
+	ret := call5(mallocABI0, uintptr(size), 0, 0, 0, 0)
+	// this indirection is to avoid go vet complaining about possible misuse of unsafe.Pointer
+	return *(*unsafe.Pointer)(unsafe.Pointer(&ret))
+}
+
+//go:nosplit
+//go:norace
+func free(ptr unsafe.Pointer) {
+	call5(freeABI0, uintptr(ptr), 0, 0, 0, 0)
+}
+
+//go:nosplit
+//go:norace
+func setenv(name *byte, value *byte, overwrite int32) int32 {
+	return int32(call5(setenvABI0, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), uintptr(overwrite), 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func unsetenv(name *byte) int32 {
+	return int32(call5(unsetenvABI0, uintptr(unsafe.Pointer(name)), 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func sigfillset(set *sigset_t) int32 {
+	return int32(call5(sigfillsetABI0, uintptr(unsafe.Pointer(set)), 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func nanosleep(ts *syscall.Timespec, rem *syscall.Timespec) int32 {
+	return int32(call5(nanosleepABI0, uintptr(unsafe.Pointer(ts)), uintptr(unsafe.Pointer(rem)), 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func abort() {
+	call5(abortABI0, 0, 0, 0, 0, 0)
+}
+
+//go:nosplit
+//go:norace
+func pthread_attr_init(attr *pthread_attr_t) int32 {
+	return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_create(thread *pthread_t, attr *pthread_attr_t, start unsafe.Pointer, arg unsafe.Pointer) int32 {
+	return int32(call5(pthread_createABI0, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(start), uintptr(arg), 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_detach(thread pthread_t) int32 {
+	return int32(call5(pthread_detachABI0, uintptr(thread), 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_sigmask(how sighow, ign *sigset_t, oset *sigset_t) int32 {
+	return int32(call5(pthread_sigmaskABI0, uintptr(how), uintptr(unsafe.Pointer(ign)), uintptr(unsafe.Pointer(oset)), 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_mutex_lock(mutex *pthread_mutex_t) int32 {
+	return int32(call5(pthread_mutex_lockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_mutex_unlock(mutex *pthread_mutex_t) int32 {
+	return int32(call5(pthread_mutex_unlockABI0, uintptr(unsafe.Pointer(mutex)), 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_cond_broadcast(cond *pthread_cond_t) int32 {
+	return int32(call5(pthread_cond_broadcastABI0, uintptr(unsafe.Pointer(cond)), 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_setspecific(key pthread_key_t, value unsafe.Pointer) int32 {
+	return int32(call5(pthread_setspecificABI0, uintptr(key), uintptr(value), 0, 0, 0))
+}
+
+//go:linkname _malloc _malloc
+var _malloc uint8
+var mallocABI0 = uintptr(unsafe.Pointer(&_malloc))
+
+//go:linkname _free _free
+var _free uint8
+var freeABI0 = uintptr(unsafe.Pointer(&_free))
+
+//go:linkname _setenv _setenv
+var _setenv uint8
+var setenvABI0 = uintptr(unsafe.Pointer(&_setenv))
+
+//go:linkname _unsetenv _unsetenv
+var _unsetenv uint8
+var unsetenvABI0 = uintptr(unsafe.Pointer(&_unsetenv))
+
+//go:linkname _sigfillset _sigfillset
+var _sigfillset uint8
+var sigfillsetABI0 = uintptr(unsafe.Pointer(&_sigfillset))
+
+//go:linkname _nanosleep _nanosleep
+var _nanosleep uint8
+var nanosleepABI0 = uintptr(unsafe.Pointer(&_nanosleep))
+
+//go:linkname _abort _abort
+var _abort uint8
+var abortABI0 = uintptr(unsafe.Pointer(&_abort))
+
+//go:linkname _pthread_attr_init _pthread_attr_init
+var _pthread_attr_init uint8
+var pthread_attr_initABI0 = uintptr(unsafe.Pointer(&_pthread_attr_init))
+
+//go:linkname _pthread_create _pthread_create
+var _pthread_create uint8
+var pthread_createABI0 = uintptr(unsafe.Pointer(&_pthread_create))
+
+//go:linkname _pthread_detach _pthread_detach
+var _pthread_detach uint8
+var pthread_detachABI0 = uintptr(unsafe.Pointer(&_pthread_detach))
+
+//go:linkname _pthread_sigmask _pthread_sigmask
+var _pthread_sigmask uint8
+var pthread_sigmaskABI0 = uintptr(unsafe.Pointer(&_pthread_sigmask))
+
+//go:linkname _pthread_mutex_lock _pthread_mutex_lock
+var _pthread_mutex_lock uint8
+var pthread_mutex_lockABI0 = uintptr(unsafe.Pointer(&_pthread_mutex_lock))
+
+//go:linkname _pthread_mutex_unlock _pthread_mutex_unlock
+var _pthread_mutex_unlock uint8
+var pthread_mutex_unlockABI0 = uintptr(unsafe.Pointer(&_pthread_mutex_unlock))
+
+//go:linkname _pthread_cond_broadcast _pthread_cond_broadcast
+var _pthread_cond_broadcast uint8
+var pthread_cond_broadcastABI0 = uintptr(unsafe.Pointer(&_pthread_cond_broadcast))
+
+//go:linkname _pthread_setspecific _pthread_setspecific
+var _pthread_setspecific uint8
+var pthread_setspecificABI0 = uintptr(unsafe.Pointer(&_pthread_setspecific))
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_darwin.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_darwin.go
new file mode 100644
index 000000000..960f8168e
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_darwin.go
@@ -0,0 +1,59 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package fakecgo
+
+import "unsafe"
+
+//go:cgo_import_dynamic purego_malloc malloc "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_free free "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_setenv setenv "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_unsetenv unsetenv "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_sigfillset sigfillset "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_nanosleep nanosleep "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_abort abort "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_create pthread_create "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_detach pthread_detach "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_self pthread_self "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_get_stacksize_np pthread_get_stacksize_np "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic purego_pthread_attr_setstacksize pthread_attr_setstacksize "/usr/lib/libSystem.B.dylib"
+
+//go:nosplit
+//go:norace
+func pthread_self() pthread_t {
+	return pthread_t(call5(pthread_selfABI0, 0, 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_get_stacksize_np(thread pthread_t) size_t {
+	return size_t(call5(pthread_get_stacksize_npABI0, uintptr(thread), 0, 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_attr_setstacksize(attr *pthread_attr_t, size size_t) int32 {
+	return int32(call5(pthread_attr_setstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(size), 0, 0, 0))
+}
+
+//go:linkname _pthread_self _pthread_self
+var _pthread_self uint8
+var pthread_selfABI0 = uintptr(unsafe.Pointer(&_pthread_self))
+
+//go:linkname _pthread_get_stacksize_np _pthread_get_stacksize_np
+var _pthread_get_stacksize_np uint8
+var pthread_get_stacksize_npABI0 = uintptr(unsafe.Pointer(&_pthread_get_stacksize_np))
+
+//go:linkname _pthread_attr_setstacksize _pthread_attr_setstacksize
+var _pthread_attr_setstacksize uint8
+var pthread_attr_setstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_setstacksize))
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_freebsd.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_freebsd.go
new file mode 100644
index 000000000..d69775596
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_freebsd.go
@@ -0,0 +1,48 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package fakecgo
+
+import "unsafe"
+
+//go:cgo_import_dynamic purego_malloc malloc "libc.so.7"
+//go:cgo_import_dynamic purego_free free "libc.so.7"
+//go:cgo_import_dynamic purego_setenv setenv "libc.so.7"
+//go:cgo_import_dynamic purego_unsetenv unsetenv "libc.so.7"
+//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.7"
+//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.7"
+//go:cgo_import_dynamic purego_abort abort "libc.so.7"
+//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "libpthread.so"
+
+//go:nosplit
+//go:norace
+func pthread_attr_getstacksize(attr *pthread_attr_t, stacksize *size_t) int32 {
+	return int32(call5(pthread_attr_getstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(stacksize)), 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_attr_destroy(attr *pthread_attr_t) int32 {
+	return int32(call5(pthread_attr_destroyABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
+}
+
+//go:linkname _pthread_attr_getstacksize _pthread_attr_getstacksize
+var _pthread_attr_getstacksize uint8
+var pthread_attr_getstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_getstacksize))
+
+//go:linkname _pthread_attr_destroy _pthread_attr_destroy
+var _pthread_attr_destroy uint8
+var pthread_attr_destroyABI0 = uintptr(unsafe.Pointer(&_pthread_attr_destroy))
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_linux.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_linux.go
new file mode 100644
index 000000000..f6bad22c3
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_linux.go
@@ -0,0 +1,48 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package fakecgo
+
+import "unsafe"
+
+//go:cgo_import_dynamic purego_malloc malloc "libc.so.6"
+//go:cgo_import_dynamic purego_free free "libc.so.6"
+//go:cgo_import_dynamic purego_setenv setenv "libc.so.6"
+//go:cgo_import_dynamic purego_unsetenv unsetenv "libc.so.6"
+//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.6"
+//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.6"
+//go:cgo_import_dynamic purego_abort abort "libc.so.6"
+//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "libpthread.so.0"
+//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "libpthread.so.0"
+
+//go:nosplit
+//go:norace
+func pthread_attr_getstacksize(attr *pthread_attr_t, stacksize *size_t) int32 {
+	return int32(call5(pthread_attr_getstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(stacksize)), 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_attr_destroy(attr *pthread_attr_t) int32 {
+	return int32(call5(pthread_attr_destroyABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
+}
+
+//go:linkname _pthread_attr_getstacksize _pthread_attr_getstacksize
+var _pthread_attr_getstacksize uint8
+var pthread_attr_getstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_getstacksize))
+
+//go:linkname _pthread_attr_destroy _pthread_attr_destroy
+var _pthread_attr_destroy uint8
+var pthread_attr_destroyABI0 = uintptr(unsafe.Pointer(&_pthread_attr_destroy))
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_netbsd.go b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_netbsd.go
new file mode 100644
index 000000000..774402cfb
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/zsymbols_netbsd.go
@@ -0,0 +1,59 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package fakecgo
+
+import "unsafe"
+
+//go:cgo_import_dynamic purego_malloc malloc "libc.so"
+//go:cgo_import_dynamic purego_free free "libc.so"
+//go:cgo_import_dynamic purego_setenv setenv "libc.so"
+//go:cgo_import_dynamic purego_unsetenv unsetenv "libc.so"
+//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so"
+//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so"
+//go:cgo_import_dynamic purego_abort abort "libc.so"
+//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so"
+//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "libpthread.so"
+//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "libpthread.so"
+
+//go:nosplit
+//go:norace
+func sigaltstack(ss *stack_t, old_ss *stack_t) int32 {
+	return int32(call5(sigaltstackABI0, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(old_ss)), 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_attr_getstacksize(attr *pthread_attr_t, stacksize *size_t) int32 {
+	return int32(call5(pthread_attr_getstacksizeABI0, uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(stacksize)), 0, 0, 0))
+}
+
+//go:nosplit
+//go:norace
+func pthread_attr_destroy(attr *pthread_attr_t) int32 {
+	return int32(call5(pthread_attr_destroyABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
+}
+
+//go:linkname _sigaltstack _sigaltstack
+var _sigaltstack uint8
+var sigaltstackABI0 = uintptr(unsafe.Pointer(&_sigaltstack))
+
+//go:linkname _pthread_attr_getstacksize _pthread_attr_getstacksize
+var _pthread_attr_getstacksize uint8
+var pthread_attr_getstacksizeABI0 = uintptr(unsafe.Pointer(&_pthread_attr_getstacksize))
+
+//go:linkname _pthread_attr_destroy _pthread_attr_destroy
+var _pthread_attr_destroy uint8
+var pthread_attr_destroyABI0 = uintptr(unsafe.Pointer(&_pthread_attr_destroy))
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_darwin.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_darwin.s
new file mode 100644
index 000000000..35ef7ac11
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_darwin.s
@@ -0,0 +1,19 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+#include "textflag.h"
+
+// these stubs are here because it is not possible to go:linkname directly the C functions
+
+TEXT _pthread_self(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_self(SB)
+
+TEXT _pthread_get_stacksize_np(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_get_stacksize_np(SB)
+
+TEXT _pthread_attr_setstacksize(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_attr_setstacksize(SB)
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_freebsd.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_freebsd.s
new file mode 100644
index 000000000..da07005c0
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_freebsd.s
@@ -0,0 +1,16 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+#include "textflag.h"
+
+// these stubs are here because it is not possible to go:linkname directly the C functions
+
+TEXT _pthread_attr_getstacksize(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_attr_getstacksize(SB)
+
+TEXT _pthread_attr_destroy(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_attr_destroy(SB)
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_linux.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_linux.s
new file mode 100644
index 000000000..da07005c0
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_linux.s
@@ -0,0 +1,16 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+#include "textflag.h"
+
+// these stubs are here because it is not possible to go:linkname directly the C functions
+
+TEXT _pthread_attr_getstacksize(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_attr_getstacksize(SB)
+
+TEXT _pthread_attr_destroy(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_attr_destroy(SB)
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_netbsd.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_netbsd.s
new file mode 100644
index 000000000..81ef76f59
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_netbsd.s
@@ -0,0 +1,19 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+#include "textflag.h"
+
+// these stubs are here because it is not possible to go:linkname directly the C functions
+
+TEXT _sigaltstack(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_sigaltstack(SB)
+
+TEXT _pthread_attr_getstacksize(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_attr_getstacksize(SB)
+
+TEXT _pthread_attr_destroy(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_attr_destroy(SB)
diff --git a/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_stubs.s b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_stubs.s
new file mode 100644
index 000000000..8e1afff73
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/fakecgo/ztrampolines_stubs.s
@@ -0,0 +1,55 @@
+// Code generated by 'go generate' with gen.go. DO NOT EDIT.
+
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+#include "textflag.h"
+
+// these stubs are here because it is not possible to go:linkname directly the C functions
+
+TEXT _malloc(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_malloc(SB)
+
+TEXT _free(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_free(SB)
+
+TEXT _setenv(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_setenv(SB)
+
+TEXT _unsetenv(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_unsetenv(SB)
+
+TEXT _sigfillset(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_sigfillset(SB)
+
+TEXT _nanosleep(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_nanosleep(SB)
+
+TEXT _abort(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_abort(SB)
+
+TEXT _pthread_attr_init(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_attr_init(SB)
+
+TEXT _pthread_create(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_create(SB)
+
+TEXT _pthread_detach(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_detach(SB)
+
+TEXT _pthread_sigmask(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_sigmask(SB)
+
+TEXT _pthread_mutex_lock(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_mutex_lock(SB)
+
+TEXT _pthread_mutex_unlock(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_mutex_unlock(SB)
+
+TEXT _pthread_cond_broadcast(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_cond_broadcast(SB)
+
+TEXT _pthread_setspecific(SB), NOSPLIT|NOFRAME, $0-0
+	JMP purego_pthread_setspecific(SB)
diff --git a/vendor/github.com/ebitengine/purego/internal/strings/strings.go b/vendor/github.com/ebitengine/purego/internal/strings/strings.go
new file mode 100644
index 000000000..5b0d25225
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/strings/strings.go
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+package strings
+
+import (
+	"unsafe"
+)
+
+// hasSuffix tests whether the string s ends with suffix.
+func hasSuffix(s, suffix string) bool {
+	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+}
+
+// CString converts a go string to *byte that can be passed to C code.
+func CString(name string) *byte {
+	if hasSuffix(name, "\x00") {
+		return &(*(*[]byte)(unsafe.Pointer(&name)))[0]
+	}
+	b := make([]byte, len(name)+1)
+	copy(b, name)
+	return &b[0]
+}
+
+// GoString copies a null-terminated char* to a Go string.
+func GoString(c uintptr) string {
+	// We take the address and then dereference it to trick go vet from creating a possible misuse of unsafe.Pointer
+	ptr := *(*unsafe.Pointer)(unsafe.Pointer(&c))
+	if ptr == nil {
+		return ""
+	}
+	var length int
+	for {
+		if *(*byte)(unsafe.Add(ptr, uintptr(length))) == '\x00' {
+			break
+		}
+		length++
+	}
+	return string(unsafe.Slice((*byte)(ptr), length))
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/xreflect/reflect_go124.go b/vendor/github.com/ebitengine/purego/internal/xreflect/reflect_go124.go
new file mode 100644
index 000000000..5eb0580e0
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/xreflect/reflect_go124.go
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+//go:build !go1.25
+
+package xreflect
+
+import "reflect"
+
+// TODO: remove this and use Go 1.25's reflect.TypeAssert when minimum go.mod version is 1.25
+
+func TypeAssert[T any](v reflect.Value) (T, bool) {
+	v2, ok := v.Interface().(T)
+	return v2, ok
+}
diff --git a/vendor/github.com/ebitengine/purego/internal/xreflect/reflect_go125.go b/vendor/github.com/ebitengine/purego/internal/xreflect/reflect_go125.go
new file mode 100644
index 000000000..62ee13d6c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/internal/xreflect/reflect_go125.go
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+//go:build go1.25
+
+package xreflect
+
+import "reflect"
+
+func TypeAssert[T any](v reflect.Value) (T, bool) {
+	return reflect.TypeAssert[T](v)
+}
diff --git a/vendor/github.com/ebitengine/purego/is_ios.go b/vendor/github.com/ebitengine/purego/is_ios.go
new file mode 100644
index 000000000..ed31da978
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/is_ios.go
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo
+
+package purego
+
+// if you are getting this error it means that you have
+// CGO_ENABLED=0 while trying to build for ios.
+// purego does not support this mode yet.
+// the fix is to set CGO_ENABLED=1 which will require
+// a C compiler.
+var _ = _PUREGO_REQUIRES_CGO_ON_IOS
diff --git a/vendor/github.com/ebitengine/purego/nocgo.go b/vendor/github.com/ebitengine/purego/nocgo.go
new file mode 100644
index 000000000..b91b9796b
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/nocgo.go
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !cgo && (darwin || freebsd || linux || netbsd)
+
+package purego
+
+// if CGO_ENABLED=0 import fakecgo to setup the Cgo runtime correctly.
+// This is required since some frameworks need TLS setup the C way which Go doesn't do.
+// We currently don't support ios in fakecgo mode so force Cgo or fail
+//
+// The way that the Cgo runtime (runtime/cgo) works is by setting some variables found
+// in runtime with non-null GCC compiled functions. The variables that are replaced are
+// var (
+//		iscgo             bool 							// in runtime/cgo.go
+//		_cgo_init         unsafe.Pointer 				// in runtime/cgo.go
+//		_cgo_thread_start unsafe.Pointer				// in runtime/cgo.go
+//		_cgo_notify_runtime_init_done unsafe.Pointer 	// in runtime/cgo.go
+//		_cgo_setenv unsafe.Pointer  					// in runtime/env_posix.go
+//		_cgo_unsetenv unsafe.Pointer					// in runtime/env_posix.go
+// )
+// importing fakecgo will set these (using //go:linkname) with functions written
+// entirely in Go (except for some assembly trampolines to change GCC ABI to Go ABI).
+// Doing so makes it possible to build applications that call into C without CGO_ENABLED=1.
+import _ "github.com/ebitengine/purego/internal/fakecgo"
diff --git a/vendor/github.com/ebitengine/purego/struct_386.go b/vendor/github.com/ebitengine/purego/struct_386.go
new file mode 100644
index 000000000..02c8ac45c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/struct_386.go
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+package purego
+
+import "reflect"
+
+func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
+	panic("purego: struct arguments are not supported")
+}
+
+func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
+	panic("purego: struct returns are not supported")
+}
+
+func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
+	panic("purego: placeRegisters not implemented on 386")
+}
+
+// shouldBundleStackArgs always returns false on 386
+// since C-style stack argument bundling is only needed on Darwin ARM64.
+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
+	return false
+}
+
+// structFitsInRegisters is not used on 386.
+func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
+	panic("purego: structFitsInRegisters should not be called on 386")
+}
+
+// collectStackArgs is not used on 386.
+func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
+	keepAlive []any, addInt, addFloat, addStack func(uintptr),
+	pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
+	panic("purego: collectStackArgs should not be called on 386")
+}
+
+// bundleStackArgs is not used on 386.
+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
+	panic("purego: bundleStackArgs should not be called on 386")
+}
diff --git a/vendor/github.com/ebitengine/purego/struct_amd64.go b/vendor/github.com/ebitengine/purego/struct_amd64.go
new file mode 100644
index 000000000..c56f957af
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/struct_amd64.go
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
+
+package purego
+
+import (
+	"math"
+	"reflect"
+	"unsafe"
+)
+
+func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
+	outSize := outType.Size()
+	switch {
+	case outSize == 0:
+		return reflect.New(outType).Elem()
+	case outSize <= 8:
+		if isAllFloats(outType) {
+			// 2 float32s or 1 float64s are return in the float register
+			return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{syscall.f1})).Elem()
+		}
+		// up to 8 bytes is returned in RAX
+		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{syscall.a1})).Elem()
+	case outSize <= 16:
+		r1, r2 := syscall.a1, syscall.a2
+		if isAllFloats(outType) {
+			r1 = syscall.f1
+			r2 = syscall.f2
+		} else {
+			// check first 8 bytes if it's floats
+			hasFirstFloat := false
+			f1 := outType.Field(0).Type
+			if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && outType.Field(1).Type.Kind() == reflect.Float32 {
+				r1 = syscall.f1
+				hasFirstFloat = true
+			}
+
+			// find index of the field that starts the second 8 bytes
+			var i int
+			for i = 0; i < outType.NumField(); i++ {
+				if outType.Field(i).Offset == 8 {
+					break
+				}
+			}
+
+			// check last 8 bytes if they are floats
+			f1 = outType.Field(i).Type
+			if f1.Kind() == reflect.Float64 || f1.Kind() == reflect.Float32 && i+1 == outType.NumField() {
+				r2 = syscall.f1
+			} else if hasFirstFloat {
+				// if the first field was a float then that means the second integer field
+				// comes from the first integer register
+				r2 = syscall.a1
+			}
+		}
+		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b uintptr }{r1, r2})).Elem()
+	default:
+		// create struct from the Go pointer created above
+		// weird pointer dereference to circumvent go vet
+		return reflect.NewAt(outType, *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))).Elem()
+	}
+}
+
+func isAllFloats(ty reflect.Type) bool {
+	for i := 0; i < ty.NumField(); i++ {
+		f := ty.Field(i)
+		switch f.Type.Kind() {
+		case reflect.Float64, reflect.Float32:
+		default:
+			return false
+		}
+	}
+	return true
+}
+
+// https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
+// https://gitlab.com/x86-psABIs/x86-64-ABI
+// Class determines where the 8 byte value goes.
+// Higher value classes win over lower value classes
+const (
+	_NO_CLASS = 0b0000
+	_SSE      = 0b0001
+	_X87      = 0b0011 // long double not used in Go
+	_INTEGER  = 0b0111
+	_MEMORY   = 0b1111
+)
+
+func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
+	if v.Type().Size() == 0 {
+		return keepAlive
+	}
+
+	// if greater than 64 bytes place on stack
+	if v.Type().Size() > 8*8 {
+		placeStack(v, addStack)
+		return keepAlive
+	}
+	var (
+		savedNumFloats = *numFloats
+		savedNumInts   = *numInts
+		savedNumStack  = *numStack
+	)
+	placeOnStack := postMerger(v.Type()) || !tryPlaceRegister(v, addFloat, addInt)
+	if placeOnStack {
+		// reset any values placed in registers
+		*numFloats = savedNumFloats
+		*numInts = savedNumInts
+		*numStack = savedNumStack
+		placeStack(v, addStack)
+	}
+	return keepAlive
+}
+
+func postMerger(t reflect.Type) (passInMemory bool) {
+	// (c) If the size of the aggregate exceeds two eightbytes and the first eight- byte isn’t SSE or any other
+	// eightbyte isn’t SSEUP, the whole argument is passed in memory.
+	if t.Kind() != reflect.Struct {
+		return false
+	}
+	if t.Size() <= 2*8 {
+		return false
+	}
+	return true // Go does not have an SSE/SSEUP type so this is always true
+}
+
+func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) {
+	ok = true
+	var val uint64
+	var shift byte // # of bits to shift
+	var flushed bool
+	class := _NO_CLASS
+	flushIfNeeded := func() {
+		if flushed {
+			return
+		}
+		flushed = true
+		if class == _SSE {
+			addFloat(uintptr(val))
+		} else {
+			addInt(uintptr(val))
+		}
+		val = 0
+		shift = 0
+		class = _NO_CLASS
+	}
+	var place func(v reflect.Value)
+	place = func(v reflect.Value) {
+		var numFields int
+		if v.Kind() == reflect.Struct {
+			numFields = v.Type().NumField()
+		} else {
+			numFields = v.Type().Len()
+		}
+
+		for i := 0; i < numFields; i++ {
+			flushed = false
+			var f reflect.Value
+			if v.Kind() == reflect.Struct {
+				f = v.Field(i)
+			} else {
+				f = v.Index(i)
+			}
+			switch f.Kind() {
+			case reflect.Struct:
+				place(f)
+			case reflect.Bool:
+				if f.Bool() {
+					val |= 1 << shift
+				}
+				shift += 8
+				class |= _INTEGER
+			case reflect.Pointer, reflect.UnsafePointer:
+				val = uint64(f.Pointer())
+				shift = 64
+				class = _INTEGER
+			case reflect.Int8:
+				val |= uint64(f.Int()&0xFF) << shift
+				shift += 8
+				class |= _INTEGER
+			case reflect.Int16:
+				val |= uint64(f.Int()&0xFFFF) << shift
+				shift += 16
+				class |= _INTEGER
+			case reflect.Int32:
+				val |= uint64(f.Int()&0xFFFF_FFFF) << shift
+				shift += 32
+				class |= _INTEGER
+			case reflect.Int64, reflect.Int:
+				val = uint64(f.Int())
+				shift = 64
+				class = _INTEGER
+			case reflect.Uint8:
+				val |= f.Uint() << shift
+				shift += 8
+				class |= _INTEGER
+			case reflect.Uint16:
+				val |= f.Uint() << shift
+				shift += 16
+				class |= _INTEGER
+			case reflect.Uint32:
+				val |= f.Uint() << shift
+				shift += 32
+				class |= _INTEGER
+			case reflect.Uint64, reflect.Uint, reflect.Uintptr:
+				val = f.Uint()
+				shift = 64
+				class = _INTEGER
+			case reflect.Float32:
+				val |= uint64(math.Float32bits(float32(f.Float()))) << shift
+				shift += 32
+				class |= _SSE
+			case reflect.Float64:
+				if v.Type().Size() > 16 {
+					ok = false
+					return
+				}
+				val = uint64(math.Float64bits(f.Float()))
+				shift = 64
+				class = _SSE
+			case reflect.Array:
+				place(f)
+			default:
+				panic("purego: unsupported kind " + f.Kind().String())
+			}
+
+			if shift == 64 {
+				flushIfNeeded()
+			} else if shift > 64 {
+				// Should never happen, but may if we forget to reset shift after flush (or forget to flush),
+				// better fall apart here, than corrupt arguments.
+				panic("purego: tryPlaceRegisters shift > 64")
+			}
+		}
+	}
+
+	place(v)
+	flushIfNeeded()
+	return ok
+}
+
+func placeStack(v reflect.Value, addStack func(uintptr)) {
+	// Copy the struct as a contiguous block of memory in eightbyte (8-byte)
+	// chunks. The x86-64 ABI requires structs passed on the stack to be
+	// laid out exactly as in memory, including padding and field packing
+	// within eightbytes. Decomposing field-by-field would place each field
+	// as a separate stack slot, breaking structs with mixed-type fields
+	// that share an eightbyte (e.g. int32 + float32).
+	if !v.CanAddr() {
+		tmp := reflect.New(v.Type()).Elem()
+		tmp.Set(v)
+		v = tmp
+	}
+	ptr := v.Addr().UnsafePointer()
+	size := v.Type().Size()
+	for off := uintptr(0); off < size; off += 8 {
+		chunk := *(*uintptr)(unsafe.Add(ptr, off))
+		addStack(chunk)
+	}
+}
+
+func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
+	panic("purego: placeRegisters not implemented on amd64")
+}
+
+// shouldBundleStackArgs always returns false on non-Darwin platforms
+// since C-style stack argument bundling is only needed on Darwin ARM64.
+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
+	return false
+}
+
+// structFitsInRegisters is not used on amd64.
+func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
+	panic("purego: structFitsInRegisters should not be called on amd64")
+}
+
+// collectStackArgs is not used on amd64.
+func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
+	keepAlive []any, addInt, addFloat, addStack func(uintptr),
+	pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
+	panic("purego: collectStackArgs should not be called on amd64")
+}
+
+// bundleStackArgs is not used on amd64.
+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
+	panic("purego: bundleStackArgs should not be called on amd64")
+}
diff --git a/vendor/github.com/ebitengine/purego/struct_arm.go b/vendor/github.com/ebitengine/purego/struct_arm.go
new file mode 100644
index 000000000..1b580585d
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/struct_arm.go
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+package purego
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
+	size := v.Type().Size()
+	if size == 0 {
+		return keepAlive
+	}
+
+	// TODO: ARM EABI: small structs are passed in registers or on stack
+	// For simplicity, pass by pointer for now
+	ptr := v.Addr().UnsafePointer()
+	keepAlive = append(keepAlive, ptr)
+	if *numInts < 4 {
+		addInt(uintptr(ptr))
+		*numInts++
+	} else {
+		addStack(uintptr(ptr))
+		*numStack++
+	}
+	return keepAlive
+}
+
+func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
+	outSize := outType.Size()
+	if outSize == 0 {
+		return reflect.New(outType).Elem()
+	}
+	if outSize <= 4 {
+		// Fits in one register
+		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{syscall.a1})).Elem()
+	}
+	if outSize <= 8 {
+		// Fits in two registers
+		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b uintptr }{syscall.a1, syscall.a2})).Elem()
+	}
+	// Larger structs returned via pointer in a1
+	return reflect.NewAt(outType, *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))).Elem()
+}
+
+func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
+	// TODO: For ARM32, just pass the struct data directly
+	// This is a simplified implementation
+	size := v.Type().Size()
+	if size == 0 {
+		return
+	}
+	ptr := unsafe.Pointer(v.UnsafeAddr())
+	if size <= 4 {
+		addInt(*(*uintptr)(ptr))
+	} else if size <= 8 {
+		addInt(*(*uintptr)(ptr))
+		addInt(*(*uintptr)(unsafe.Add(ptr, 4)))
+	}
+}
+
+// shouldBundleStackArgs always returns false on arm
+// since C-style stack argument bundling is only needed on Darwin ARM64.
+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
+	return false
+}
+
+// structFitsInRegisters is not used on arm.
+func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
+	panic("purego: structFitsInRegisters should not be called on arm")
+}
+
+// collectStackArgs is not used on arm.
+func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
+	keepAlive []any, addInt, addFloat, addStack func(uintptr),
+	pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
+	panic("purego: collectStackArgs should not be called on arm")
+}
+
+// bundleStackArgs is not used on arm.
+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
+	panic("purego: bundleStackArgs should not be called on arm")
+}
diff --git a/vendor/github.com/ebitengine/purego/struct_arm64.go b/vendor/github.com/ebitengine/purego/struct_arm64.go
new file mode 100644
index 000000000..5f347c83d
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/struct_arm64.go
@@ -0,0 +1,549 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
+
+package purego
+
+import (
+	"math"
+	"reflect"
+	"runtime"
+	"strconv"
+	stdstrings "strings"
+	"unsafe"
+
+	"github.com/ebitengine/purego/internal/strings"
+)
+
+func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
+	outSize := outType.Size()
+	switch {
+	case outSize == 0:
+		return reflect.New(outType).Elem()
+	case outSize <= 8:
+		r1 := syscall.a1
+		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
+			r1 = syscall.f1
+			if numFields == 2 {
+				r1 = syscall.f2<<32 | syscall.f1
+			}
+		}
+		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{r1})).Elem()
+	case outSize <= 16:
+		r1, r2 := syscall.a1, syscall.a2
+		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
+			switch numFields {
+			case 4:
+				r1 = syscall.f2<<32 | syscall.f1
+				r2 = syscall.f4<<32 | syscall.f3
+			case 3:
+				r1 = syscall.f2<<32 | syscall.f1
+				r2 = syscall.f3
+			case 2:
+				r1 = syscall.f1
+				r2 = syscall.f2
+			default:
+				panic("unreachable")
+			}
+		}
+		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b uintptr }{r1, r2})).Elem()
+	default:
+		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats && numFields <= 4 {
+			switch numFields {
+			case 4:
+				return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b, c, d uintptr }{syscall.f1, syscall.f2, syscall.f3, syscall.f4})).Elem()
+			case 3:
+				return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b, c uintptr }{syscall.f1, syscall.f2, syscall.f3})).Elem()
+			default:
+				panic("unreachable")
+			}
+		}
+		// create struct from the Go pointer created in arm64_r8
+		// weird pointer dereference to circumvent go vet
+		return reflect.NewAt(outType, *(*unsafe.Pointer)(unsafe.Pointer(&syscall.arm64_r8))).Elem()
+	}
+}
+
+// https://github.com/ARM-software/abi-aa/blob/main/sysvabi64/sysvabi64.rst
+const (
+	_NO_CLASS = 0b00
+	_FLOAT    = 0b01
+	_INT      = 0b11
+)
+
+func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
+	if v.Type().Size() == 0 {
+		return keepAlive
+	}
+
+	if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 {
+		// if this doesn't fit entirely in registers then
+		// each element goes onto the stack
+		if hfa && *numFloats+v.NumField() > numOfFloatRegisters() {
+			*numFloats = numOfFloatRegisters()
+		} else if hva && *numInts+v.NumField() > numOfIntegerRegisters() {
+			*numInts = numOfIntegerRegisters()
+		}
+
+		placeRegisters(v, addFloat, addInt)
+	} else {
+		keepAlive = placeStack(v, keepAlive, addInt)
+	}
+	return keepAlive // the struct was allocated so don't panic
+}
+
+func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
+	if runtime.GOOS == "darwin" {
+		placeRegistersDarwin(v, addFloat, addInt)
+		return
+	}
+	placeRegistersArm64(v, addFloat, addInt)
+}
+
+func placeRegistersArm64(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
+	var val uint64
+	var shift byte
+	var flushed bool
+	class := _NO_CLASS
+	var place func(v reflect.Value)
+	place = func(v reflect.Value) {
+		var numFields int
+		if v.Kind() == reflect.Struct {
+			numFields = v.Type().NumField()
+		} else {
+			numFields = v.Type().Len()
+		}
+		for k := 0; k < numFields; k++ {
+			flushed = false
+			var f reflect.Value
+			if v.Kind() == reflect.Struct {
+				f = v.Field(k)
+			} else {
+				f = v.Index(k)
+			}
+			align := byte(f.Type().Align()*8 - 1)
+			shift = (shift + align) &^ align
+			if shift >= 64 {
+				shift = 0
+				flushed = true
+				if class == _FLOAT {
+					addFloat(uintptr(val))
+				} else {
+					addInt(uintptr(val))
+				}
+				val = 0
+				class = _NO_CLASS
+			}
+			switch f.Type().Kind() {
+			case reflect.Struct:
+				place(f)
+			case reflect.Bool:
+				if f.Bool() {
+					val |= 1 << shift
+				}
+				shift += 8
+				class |= _INT
+			case reflect.Uint8:
+				val |= f.Uint() << shift
+				shift += 8
+				class |= _INT
+			case reflect.Uint16:
+				val |= f.Uint() << shift
+				shift += 16
+				class |= _INT
+			case reflect.Uint32:
+				val |= f.Uint() << shift
+				shift += 32
+				class |= _INT
+			case reflect.Uint64, reflect.Uint, reflect.Uintptr:
+				addInt(uintptr(f.Uint()))
+				shift = 0
+				flushed = true
+				class = _NO_CLASS
+			case reflect.Int8:
+				val |= uint64(f.Int()&0xFF) << shift
+				shift += 8
+				class |= _INT
+			case reflect.Int16:
+				val |= uint64(f.Int()&0xFFFF) << shift
+				shift += 16
+				class |= _INT
+			case reflect.Int32:
+				val |= uint64(f.Int()&0xFFFF_FFFF) << shift
+				shift += 32
+				class |= _INT
+			case reflect.Int64, reflect.Int:
+				addInt(uintptr(f.Int()))
+				shift = 0
+				flushed = true
+				class = _NO_CLASS
+			case reflect.Float32:
+				if class == _FLOAT {
+					addFloat(uintptr(val))
+					val = 0
+					shift = 0
+				}
+				val |= uint64(math.Float32bits(float32(f.Float()))) << shift
+				shift += 32
+				class |= _FLOAT
+			case reflect.Float64:
+				addFloat(uintptr(math.Float64bits(float64(f.Float()))))
+				shift = 0
+				flushed = true
+				class = _NO_CLASS
+			case reflect.Ptr, reflect.UnsafePointer:
+				addInt(f.Pointer())
+				shift = 0
+				flushed = true
+				class = _NO_CLASS
+			case reflect.Array:
+				place(f)
+			default:
+				panic("purego: unsupported kind " + f.Kind().String())
+			}
+		}
+	}
+	place(v)
+	if !flushed {
+		if class == _FLOAT {
+			addFloat(uintptr(val))
+		} else {
+			addInt(uintptr(val))
+		}
+	}
+}
+
+func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
+	// Struct is too big to be placed in registers.
+	// Copy to heap and place the pointer in register
+	ptrStruct := reflect.New(v.Type())
+	ptrStruct.Elem().Set(v)
+	ptr := ptrStruct.Elem().Addr().UnsafePointer()
+	keepAlive = append(keepAlive, ptr)
+	addInt(uintptr(ptr))
+	return keepAlive
+}
+
+// isHFA reports a Homogeneous Floating-point Aggregate (HFA) which is a Fundamental Data Type that is a
+// Floating-Point type and at most four uniquely addressable members (5.9.5.1 in [Arm64 Calling Convention]).
+// This type of struct will be placed more compactly than the individual fields.
+//
+// [Arm64 Calling Convention]: https://github.com/ARM-software/abi-aa/blob/main/sysvabi64/sysvabi64.rst
+func isHFA(t reflect.Type) bool {
+	// round up struct size to nearest 8 see section B.4
+	structSize := roundUpTo8(t.Size())
+	if structSize == 0 || t.NumField() > 4 {
+		return false
+	}
+	first := t.Field(0)
+	switch first.Type.Kind() {
+	case reflect.Float32, reflect.Float64:
+		firstKind := first.Type.Kind()
+		for i := 0; i < t.NumField(); i++ {
+			if t.Field(i).Type.Kind() != firstKind {
+				return false
+			}
+		}
+		return true
+	case reflect.Array:
+		switch first.Type.Elem().Kind() {
+		case reflect.Float32, reflect.Float64:
+			return true
+		default:
+			return false
+		}
+	case reflect.Struct:
+		for i := 0; i < first.Type.NumField(); i++ {
+			if !isHFA(first.Type) {
+				return false
+			}
+		}
+		return true
+	default:
+		return false
+	}
+}
+
+// isHVA reports a Homogeneous Aggregate with a Fundamental Data Type that is a Short-Vector type
+// and at most four uniquely addressable members (5.9.5.2 in [Arm64 Calling Convention]).
+// A short vector is a machine type that is composed of repeated instances of one fundamental integral or
+// floating-point type. It may be 8 or 16 bytes in total size (5.4 in [Arm64 Calling Convention]).
+// This type of struct will be placed more compactly than the individual fields.
+//
+// [Arm64 Calling Convention]: https://github.com/ARM-software/abi-aa/blob/main/sysvabi64/sysvabi64.rst
+func isHVA(t reflect.Type) bool {
+	// round up struct size to nearest 8 see section B.4
+	structSize := roundUpTo8(t.Size())
+	if structSize == 0 || (structSize != 8 && structSize != 16) {
+		return false
+	}
+	first := t.Field(0)
+	switch first.Type.Kind() {
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Int8, reflect.Int16, reflect.Int32:
+		firstKind := first.Type.Kind()
+		for i := 0; i < t.NumField(); i++ {
+			if t.Field(i).Type.Kind() != firstKind {
+				return false
+			}
+		}
+		return true
+	case reflect.Array:
+		switch first.Type.Elem().Kind() {
+		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Int8, reflect.Int16, reflect.Int32:
+			return true
+		default:
+			return false
+		}
+	default:
+		return false
+	}
+}
+
+// copyStruct8ByteChunks copies struct memory in 8-byte chunks to the provided callback.
+// This is used for Darwin ARM64's byte-level packing of non-HFA/HVA structs.
+func copyStruct8ByteChunks(ptr unsafe.Pointer, size uintptr, addChunk func(uintptr)) {
+	if runtime.GOOS != "darwin" {
+		panic("purego: should only be called on darwin")
+	}
+	for offset := uintptr(0); offset < size; offset += 8 {
+		var chunk uintptr
+		remaining := size - offset
+		if remaining >= 8 {
+			chunk = *(*uintptr)(unsafe.Add(ptr, offset))
+		} else {
+			// Read byte-by-byte to avoid reading beyond allocation
+			for i := uintptr(0); i < remaining; i++ {
+				b := *(*byte)(unsafe.Add(ptr, offset+i))
+				chunk |= uintptr(b) << (i * 8)
+			}
+		}
+		addChunk(chunk)
+	}
+}
+
+// placeRegisters implements Darwin ARM64 calling convention for struct arguments.
+//
+// For HFA/HVA structs, each element must go in a separate register (or stack slot for elements
+// that don't fit in registers). We use placeRegistersArm64 for this.
+//
+// For non-HFA/HVA structs, Darwin uses byte-level packing. We copy the struct memory in
+// 8-byte chunks, which works correctly for both register and stack placement.
+func placeRegistersDarwin(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
+	if runtime.GOOS != "darwin" {
+		panic("purego: placeRegistersDarwin should only be called on darwin")
+	}
+	// Check if this is an HFA/HVA
+	hfa := isHFA(v.Type())
+	hva := isHVA(v.Type())
+
+	// For HFA/HVA structs, use the standard ARM64 logic which places each element separately
+	if hfa || hva {
+		placeRegistersArm64(v, addFloat, addInt)
+		return
+	}
+
+	// For non-HFA/HVA structs, use byte-level copying
+	// If the value is not addressable, create an addressable copy
+	if !v.CanAddr() {
+		addressable := reflect.New(v.Type()).Elem()
+		addressable.Set(v)
+		v = addressable
+	}
+	ptr := unsafe.Pointer(v.Addr().Pointer())
+	size := v.Type().Size()
+	copyStruct8ByteChunks(ptr, size, addInt)
+}
+
+// shouldBundleStackArgs determines if we need to start C-style packing for
+// Darwin ARM64 stack arguments. This happens when registers are exhausted.
+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
+	if runtime.GOOS != "darwin" {
+		return false
+	}
+
+	kind := v.Kind()
+	isFloat := kind == reflect.Float32 || kind == reflect.Float64
+	isInt := !isFloat && kind != reflect.Struct
+	primitiveOnStack :=
+		(isInt && numInts >= numOfIntegerRegisters()) ||
+			(isFloat && numFloats >= numOfFloatRegisters())
+	if primitiveOnStack {
+		return true
+	}
+	if kind != reflect.Struct {
+		return false
+	}
+	hfa := isHFA(v.Type())
+	hva := isHVA(v.Type())
+	size := v.Type().Size()
+	eligible := hfa || hva || size <= 16
+	if !eligible {
+		return false
+	}
+
+	if hfa {
+		need := v.NumField()
+		return numFloats+need > numOfFloatRegisters()
+	}
+
+	if hva {
+		need := v.NumField()
+		return numInts+need > numOfIntegerRegisters()
+	}
+
+	slotsNeeded := int((size + align8ByteMask) / align8ByteSize)
+	return numInts+slotsNeeded > numOfIntegerRegisters()
+}
+
+// structFitsInRegisters determines if a struct can still fit in remaining
+// registers, used during stack argument bundling to decide if a struct
+// should go through normal register allocation or be bundled with stack args.
+func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
+	if runtime.GOOS != "darwin" {
+		panic("purego: structFitsInRegisters should only be called on darwin")
+	}
+	hfa := isHFA(val.Type())
+	hva := isHVA(val.Type())
+	size := val.Type().Size()
+
+	if hfa {
+		// HFA: check if elements fit in float registers
+		if tempNumFloats+val.NumField() <= numOfFloatRegisters() {
+			return true, tempNumInts, tempNumFloats + val.NumField()
+		}
+	} else if hva {
+		// HVA: check if elements fit in int registers
+		if tempNumInts+val.NumField() <= numOfIntegerRegisters() {
+			return true, tempNumInts + val.NumField(), tempNumFloats
+		}
+	} else if size <= 16 {
+		// Non-HFA/HVA small structs use int registers for byte-packing
+		slotsNeeded := int((size + align8ByteMask) / align8ByteSize)
+		if tempNumInts+slotsNeeded <= numOfIntegerRegisters() {
+			return true, tempNumInts + slotsNeeded, tempNumFloats
+		}
+	}
+
+	return false, tempNumInts, tempNumFloats
+}
+
+// collectStackArgs separates remaining arguments into those that fit in registers vs those that go on stack.
+// It returns the stack arguments and processes register arguments through addValue.
+func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
+	keepAlive []any, addInt, addFloat, addStack func(uintptr),
+	pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
+	if runtime.GOOS != "darwin" {
+		panic("purego: collectStackArgs should only be called on darwin")
+	}
+
+	var stackArgs []reflect.Value
+	tempNumInts := numInts
+	tempNumFloats := numFloats
+
+	for j, val := range args[startIdx:] {
+		// Determine if this argument goes to register or stack
+		var fitsInRegister bool
+		var newNumInts, newNumFloats int
+
+		if val.Kind() == reflect.Struct {
+			// Check if struct still fits in remaining registers
+			fitsInRegister, newNumInts, newNumFloats = structFitsInRegisters(val, tempNumInts, tempNumFloats)
+		} else {
+			// Primitive argument
+			isFloat := val.Kind() == reflect.Float32 || val.Kind() == reflect.Float64
+			if isFloat {
+				fitsInRegister = tempNumFloats < numOfFloatRegisters()
+				newNumFloats = tempNumFloats + 1
+				newNumInts = tempNumInts
+			} else {
+				fitsInRegister = tempNumInts < numOfIntegerRegisters()
+				newNumInts = tempNumInts + 1
+				newNumFloats = tempNumFloats
+			}
+		}
+
+		if fitsInRegister {
+			// Process through normal register allocation
+			tempNumInts = newNumInts
+			tempNumFloats = newNumFloats
+			keepAlive = addValue(val, keepAlive, addInt, addFloat, addStack, pNumInts, pNumFloats, pNumStack)
+		} else {
+			// Convert strings to C strings before bundling
+			if val.Kind() == reflect.String {
+				ptr := strings.CString(val.String())
+				keepAlive = append(keepAlive, ptr)
+				val = reflect.ValueOf(ptr)
+				args[startIdx+j] = val
+			}
+			stackArgs = append(stackArgs, val)
+		}
+	}
+
+	return stackArgs, keepAlive
+}
+
+const (
+	paddingFieldPrefix = "Pad"
+)
+
+// bundleStackArgs bundles remaining arguments for Darwin ARM64 C-style stack packing.
+// It creates a packed struct with proper alignment and copies it to the stack in 8-byte chunks.
+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
+	if runtime.GOOS != "darwin" {
+		panic("purego: bundleStackArgs should only be called on darwin")
+	}
+	if len(stackArgs) == 0 {
+		return
+	}
+
+	// Build struct fields with proper C alignment and padding
+	var fields []reflect.StructField
+	currentOffset := uintptr(0)
+	fieldIndex := 0
+
+	for j, val := range stackArgs {
+		valSize := val.Type().Size()
+		valAlign := val.Type().Align()
+
+		// ARM64 requires 8-byte alignment for 8-byte or larger structs
+		if val.Kind() == reflect.Struct && valSize >= 8 {
+			valAlign = 8
+		}
+
+		// Add padding field if needed for alignment
+		if currentOffset%uintptr(valAlign) != 0 {
+			paddingNeeded := uintptr(valAlign) - (currentOffset % uintptr(valAlign))
+			fields = append(fields, reflect.StructField{
+				Name: paddingFieldPrefix + strconv.Itoa(fieldIndex),
+				Type: reflect.ArrayOf(int(paddingNeeded), reflect.TypeOf(byte(0))),
+			})
+			currentOffset += paddingNeeded
+			fieldIndex++
+		}
+
+		fields = append(fields, reflect.StructField{
+			Name: "X" + strconv.Itoa(j),
+			Type: val.Type(),
+		})
+		currentOffset += valSize
+		fieldIndex++
+	}
+
+	// Create and populate the packed struct
+	structType := reflect.StructOf(fields)
+	structInstance := reflect.New(structType).Elem()
+
+	// Set values (skip padding fields)
+	argIndex := 0
+	for j := 0; j < structInstance.NumField(); j++ {
+		fieldName := structType.Field(j).Name
+		if stdstrings.HasPrefix(fieldName, paddingFieldPrefix) {
+			continue
+		}
+		structInstance.Field(j).Set(stackArgs[argIndex])
+		argIndex++
+	}
+
+	ptr := unsafe.Pointer(structInstance.Addr().Pointer())
+	size := structType.Size()
+	copyStruct8ByteChunks(ptr, size, addStack)
+}
diff --git a/vendor/github.com/ebitengine/purego/struct_loong64.go b/vendor/github.com/ebitengine/purego/struct_loong64.go
new file mode 100644
index 000000000..e5891401c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/struct_loong64.go
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+package purego
+
+import (
+	"math"
+	"reflect"
+	"unsafe"
+)
+
+func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
+	outSize := outType.Size()
+	switch {
+	case outSize == 0:
+		return reflect.New(outType).Elem()
+	case outSize <= 8:
+		r1 := syscall.a1
+		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
+			r1 = syscall.f1
+			if numFields == 2 {
+				r1 = syscall.f2<<32 | syscall.f1
+			}
+		}
+		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{r1})).Elem()
+	case outSize <= 16:
+		r1, r2 := syscall.a1, syscall.a2
+		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
+			switch numFields {
+			case 4:
+				r1 = syscall.f2<<32 | syscall.f1
+				r2 = syscall.f4<<32 | syscall.f3
+			case 3:
+				r1 = syscall.f2<<32 | syscall.f1
+				r2 = syscall.f3
+			case 2:
+				r1 = syscall.f1
+				r2 = syscall.f2
+			default:
+				panic("unreachable")
+			}
+		}
+		return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b uintptr }{r1, r2})).Elem()
+	default:
+		// create struct from the Go pointer created above
+		// weird pointer dereference to circumvent go vet
+		return reflect.NewAt(outType, *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))).Elem()
+	}
+}
+
+const (
+	_NO_CLASS = 0b00
+	_FLOAT    = 0b01
+	_INT      = 0b11
+)
+
+func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
+	if v.Type().Size() == 0 {
+		return keepAlive
+	}
+
+	if size := v.Type().Size(); size <= 16 {
+		placeRegisters(v, addFloat, addInt)
+	} else {
+		keepAlive = placeStack(v, keepAlive, addInt)
+	}
+	return keepAlive // the struct was allocated so don't panic
+}
+
+func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
+	var val uint64
+	var shift byte
+	var flushed bool
+	class := _NO_CLASS
+	var place func(v reflect.Value)
+	place = func(v reflect.Value) {
+		var numFields int
+		if v.Kind() == reflect.Struct {
+			numFields = v.Type().NumField()
+		} else {
+			numFields = v.Type().Len()
+		}
+		for k := 0; k < numFields; k++ {
+			flushed = false
+			var f reflect.Value
+			if v.Kind() == reflect.Struct {
+				f = v.Field(k)
+			} else {
+				f = v.Index(k)
+			}
+			align := byte(f.Type().Align()*8 - 1)
+			shift = (shift + align) &^ align
+			if shift >= 64 {
+				shift = 0
+				flushed = true
+				if class == _FLOAT {
+					addFloat(uintptr(val))
+				} else {
+					addInt(uintptr(val))
+				}
+			}
+			switch f.Type().Kind() {
+			case reflect.Struct:
+				place(f)
+			case reflect.Bool:
+				if f.Bool() {
+					val |= 1 << shift
+				}
+				shift += 8
+				class |= _INT
+			case reflect.Uint8:
+				val |= f.Uint() << shift
+				shift += 8
+				class |= _INT
+			case reflect.Uint16:
+				val |= f.Uint() << shift
+				shift += 16
+				class |= _INT
+			case reflect.Uint32:
+				val |= f.Uint() << shift
+				shift += 32
+				class |= _INT
+			case reflect.Uint64, reflect.Uint, reflect.Uintptr:
+				addInt(uintptr(f.Uint()))
+				shift = 0
+				flushed = true
+				class = _NO_CLASS
+			case reflect.Int8:
+				val |= uint64(f.Int()&0xFF) << shift
+				shift += 8
+				class |= _INT
+			case reflect.Int16:
+				val |= uint64(f.Int()&0xFFFF) << shift
+				shift += 16
+				class |= _INT
+			case reflect.Int32:
+				val |= uint64(f.Int()&0xFFFF_FFFF) << shift
+				shift += 32
+				class |= _INT
+			case reflect.Int64, reflect.Int:
+				addInt(uintptr(f.Int()))
+				shift = 0
+				flushed = true
+				class = _NO_CLASS
+			case reflect.Float32:
+				if class == _FLOAT {
+					addFloat(uintptr(val))
+					val = 0
+					shift = 0
+				}
+				val |= uint64(math.Float32bits(float32(f.Float()))) << shift
+				shift += 32
+				class |= _FLOAT
+			case reflect.Float64:
+				addFloat(uintptr(math.Float64bits(float64(f.Float()))))
+				shift = 0
+				flushed = true
+				class = _NO_CLASS
+			case reflect.Ptr, reflect.UnsafePointer:
+				addInt(f.Pointer())
+				shift = 0
+				flushed = true
+				class = _NO_CLASS
+			case reflect.Array:
+				place(f)
+			default:
+				panic("purego: unsupported kind " + f.Kind().String())
+			}
+		}
+	}
+	place(v)
+	if !flushed {
+		if class == _FLOAT {
+			addFloat(uintptr(val))
+		} else {
+			addInt(uintptr(val))
+		}
+	}
+}
+
+func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
+	// Struct is too big to be placed in registers.
+	// Copy to heap and place the pointer in register
+	ptrStruct := reflect.New(v.Type())
+	ptrStruct.Elem().Set(v)
+	ptr := ptrStruct.Elem().Addr().UnsafePointer()
+	keepAlive = append(keepAlive, ptr)
+	addInt(uintptr(ptr))
+	return keepAlive
+}
+
+// shouldBundleStackArgs always returns false on loong64
+// since C-style stack argument bundling is only needed on Darwin ARM64.
+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
+	return false
+}
+
+// structFitsInRegisters is not used on loong64.
+func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
+	panic("purego: structFitsInRegisters should not be called on loong64")
+}
+
+// collectStackArgs is not used on loong64.
+func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
+	keepAlive []any, addInt, addFloat, addStack func(uintptr),
+	pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
+	panic("purego: collectStackArgs should not be called on loong64")
+}
+
+// bundleStackArgs is not used on loong64.
+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
+	panic("purego: bundleStackArgs should not be called on loong64")
+}
diff --git a/vendor/github.com/ebitengine/purego/struct_ppc64le.go b/vendor/github.com/ebitengine/purego/struct_ppc64le.go
new file mode 100644
index 000000000..7c50dcbba
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/struct_ppc64le.go
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+package purego
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+func getStruct(outType reflect.Type, syscall syscall15Args) reflect.Value {
+	outSize := outType.Size()
+
+	switch {
+	case outSize == 0:
+		return reflect.New(outType).Elem()
+
+	case outSize <= 16:
+		// Reconstruct from registers by copying raw bytes
+		var buf [16]byte
+
+		// Integer registers
+		*(*uintptr)(unsafe.Pointer(&buf[0])) = syscall.a1
+		if outSize > 8 {
+			*(*uintptr)(unsafe.Pointer(&buf[8])) = syscall.a2
+		}
+
+		// Homogeneous float aggregates override integer regs
+		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
+			if outType.Field(0).Type.Kind() == reflect.Float32 {
+				// float32 values in FP regs
+				f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}
+				for i := 0; i < numFields; i++ {
+					*(*uint32)(unsafe.Pointer(&buf[i*4])) = uint32(f[i])
+				}
+			} else {
+				// float64: whole register value is valid
+				*(*uintptr)(unsafe.Pointer(&buf[0])) = syscall.f1
+				if outSize > 8 {
+					*(*uintptr)(unsafe.Pointer(&buf[8])) = syscall.f2
+				}
+			}
+		}
+
+		return reflect.NewAt(outType, unsafe.Pointer(&buf[0])).Elem()
+
+	default:
+		// Returned indirectly via pointer in a1
+		ptr := *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))
+		return reflect.NewAt(outType, ptr).Elem()
+	}
+}
+
+func addStruct(
+	v reflect.Value,
+	numInts, numFloats, numStack *int,
+	addInt, addFloat, addStack func(uintptr),
+	keepAlive []any,
+) []any {
+	size := v.Type().Size()
+	if size == 0 {
+		return keepAlive
+	}
+
+	if size <= 16 {
+		return placeSmallAggregatePPC64LE(v, addFloat, addInt, keepAlive)
+	}
+
+	return placeStack(v, keepAlive, addInt)
+}
+
+func placeSmallAggregatePPC64LE(
+	v reflect.Value,
+	addFloat, addInt func(uintptr),
+	keepAlive []any,
+) []any {
+	size := v.Type().Size()
+
+	var ptr unsafe.Pointer
+	if v.CanAddr() {
+		ptr = v.Addr().UnsafePointer()
+	} else {
+		tmp := reflect.New(v.Type())
+		tmp.Elem().Set(v)
+		ptr = tmp.UnsafePointer()
+		keepAlive = append(keepAlive, tmp.Interface())
+	}
+
+	var buf [16]byte
+	src := unsafe.Slice((*byte)(ptr), size)
+	copy(buf[:], src)
+
+	w0 := *(*uintptr)(unsafe.Pointer(&buf[0]))
+	w1 := uintptr(0)
+	if size > 8 {
+		w1 = *(*uintptr)(unsafe.Pointer(&buf[8]))
+	}
+
+	if isFloats, _ := isAllSameFloat(v.Type()); isFloats {
+		addFloat(w0)
+		if size > 8 {
+			addFloat(w1)
+		}
+	} else {
+		addInt(w0)
+		if size > 8 {
+			addInt(w1)
+		}
+	}
+
+	return keepAlive
+}
+
+// placeStack is a fallback for structs that are too large to fit in registers
+func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
+	if v.CanAddr() {
+		addInt(v.Addr().Pointer())
+		return keepAlive
+	}
+	ptr := reflect.New(v.Type())
+	ptr.Elem().Set(v)
+	addInt(ptr.Pointer())
+	return append(keepAlive, ptr.Interface())
+}
+
+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
+	// PPC64LE does not bundle stack args
+	return false
+}
+
+func collectStackArgs(
+	args []reflect.Value,
+	i, numInts, numFloats int,
+	keepAlive []any,
+	addInt, addFloat, addStack func(uintptr),
+	numIntsPtr, numFloatsPtr, numStackPtr *int,
+) ([]reflect.Value, []any) {
+	return nil, keepAlive
+}
+
+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
+	panic("bundleStackArgs not supported on PPC64LE")
+}
diff --git a/vendor/github.com/ebitengine/purego/struct_riscv64.go b/vendor/github.com/ebitengine/purego/struct_riscv64.go
new file mode 100644
index 000000000..eac0b8802
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/struct_riscv64.go
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+package purego
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+func getStruct(outType reflect.Type, syscall syscall15Args) reflect.Value {
+	outSize := outType.Size()
+
+	switch {
+	case outSize == 0:
+		return reflect.New(outType).Elem()
+
+	case outSize <= 16:
+		// Reconstruct from registers by copying raw bytes
+		var buf [16]byte
+
+		// Integer registers
+		*(*uintptr)(unsafe.Pointer(&buf[0])) = syscall.a1
+		if outSize > 8 {
+			*(*uintptr)(unsafe.Pointer(&buf[8])) = syscall.a2
+		}
+
+		// Homogeneous float aggregates override integer regs
+		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
+			if outType.Field(0).Type.Kind() == reflect.Float32 {
+				// float32 values are NaN-boxed in FP regs; use low 32 bits only
+				f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}
+				for i := 0; i < numFields; i++ {
+					*(*uint32)(unsafe.Pointer(&buf[i*4])) = uint32(f[i])
+				}
+			} else {
+				// float64: whole register value is valid
+				*(*uintptr)(unsafe.Pointer(&buf[0])) = syscall.f1
+				if outSize > 8 {
+					*(*uintptr)(unsafe.Pointer(&buf[8])) = syscall.f2
+				}
+			}
+		}
+
+		return reflect.NewAt(outType, unsafe.Pointer(&buf[0])).Elem()
+
+	default:
+		// Returned indirectly via pointer in a1
+		ptr := *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))
+		return reflect.NewAt(outType, ptr).Elem()
+	}
+}
+
+func addStruct(
+	v reflect.Value,
+	numInts, numFloats, numStack *int,
+	addInt, addFloat, addStack func(uintptr),
+	keepAlive []any,
+) []any {
+	size := v.Type().Size()
+	if size == 0 {
+		return keepAlive
+	}
+
+	if size <= 16 {
+		return placeSmallAggregateRISCV64(v, addFloat, addInt, keepAlive)
+	}
+
+	return placeStack(v, keepAlive, addInt)
+}
+
+func placeSmallAggregateRISCV64(
+	v reflect.Value,
+	addFloat, addInt func(uintptr),
+	keepAlive []any,
+) []any {
+	size := v.Type().Size()
+
+	var ptr unsafe.Pointer
+	if v.CanAddr() {
+		ptr = v.Addr().UnsafePointer()
+	} else {
+		tmp := reflect.New(v.Type())
+		tmp.Elem().Set(v)
+		ptr = tmp.UnsafePointer()
+		keepAlive = append(keepAlive, tmp.Interface())
+	}
+
+	var buf [16]byte
+	src := unsafe.Slice((*byte)(ptr), size)
+	copy(buf[:], src)
+
+	w0 := *(*uintptr)(unsafe.Pointer(&buf[0]))
+	w1 := uintptr(0)
+	if size > 8 {
+		w1 = *(*uintptr)(unsafe.Pointer(&buf[8]))
+	}
+
+	if isFloats, _ := isAllSameFloat(v.Type()); isFloats {
+		addFloat(w0)
+		if size > 8 {
+			addFloat(w1)
+		}
+	} else {
+		addInt(w0)
+		if size > 8 {
+			addInt(w1)
+		}
+	}
+
+	return keepAlive
+}
+
+// placeStack is a fallback for structs that are too large to fit in registers
+func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
+	if v.CanAddr() {
+		addInt(v.Addr().Pointer())
+		return keepAlive
+	}
+	ptr := reflect.New(v.Type())
+	ptr.Elem().Set(v)
+	addInt(ptr.Pointer())
+	return append(keepAlive, ptr.Interface())
+}
+
+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
+	// RISCV64 does not bundle stack args
+	return false
+}
+
+func collectStackArgs(
+	args []reflect.Value,
+	i, numInts, numFloats int,
+	keepAlive []any,
+	addInt, addFloat, addStack func(uintptr),
+	numIntsPtr, numFloatsPtr, numStackPtr *int,
+) ([]reflect.Value, []any) {
+	return nil, keepAlive
+}
+
+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
+	panic("bundleStackArgs not supported on RISCV64")
+}
diff --git a/vendor/github.com/ebitengine/purego/struct_s390x.go b/vendor/github.com/ebitengine/purego/struct_s390x.go
new file mode 100644
index 000000000..7ec5e813c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/struct_s390x.go
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+package purego
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+func getStruct(outType reflect.Type, syscall syscall15Args) reflect.Value {
+	outSize := outType.Size()
+
+	switch {
+	case outSize == 0:
+		return reflect.New(outType).Elem()
+
+	case outSize <= 16:
+		// Reconstruct from registers by copying raw bytes
+		var buf [16]byte
+
+		// Integer registers
+		*(*uintptr)(unsafe.Pointer(&buf[0])) = syscall.a1
+		if outSize > 8 {
+			*(*uintptr)(unsafe.Pointer(&buf[8])) = syscall.a2
+		}
+
+		// Homogeneous float aggregates override integer regs
+		if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
+			if outType.Field(0).Type.Kind() == reflect.Float32 {
+				// float32 values in FP regs
+				f := []uintptr{syscall.f1, syscall.f2, syscall.f3, syscall.f4}
+				for i := 0; i < numFields; i++ {
+					*(*uint32)(unsafe.Pointer(&buf[i*4])) = uint32(f[i])
+				}
+			} else {
+				// float64: whole register value is valid
+				*(*uintptr)(unsafe.Pointer(&buf[0])) = syscall.f1
+				if outSize > 8 {
+					*(*uintptr)(unsafe.Pointer(&buf[8])) = syscall.f2
+				}
+			}
+		}
+
+		return reflect.NewAt(outType, unsafe.Pointer(&buf[0])).Elem()
+
+	default:
+		// Returned indirectly via pointer in a1
+		ptr := *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))
+		return reflect.NewAt(outType, ptr).Elem()
+	}
+}
+
+func addStruct(
+	v reflect.Value,
+	numInts, numFloats, numStack *int,
+	addInt, addFloat, addStack func(uintptr),
+	keepAlive []any,
+) []any {
+	size := v.Type().Size()
+	if size == 0 {
+		return keepAlive
+	}
+
+	if size <= 16 {
+		return placeSmallAggregateS390X(v, addFloat, addInt, keepAlive)
+	}
+
+	return placeStack(v, keepAlive, addInt)
+}
+
+func placeSmallAggregateS390X(
+	v reflect.Value,
+	addFloat, addInt func(uintptr),
+	keepAlive []any,
+) []any {
+	size := v.Type().Size()
+
+	var ptr unsafe.Pointer
+	if v.CanAddr() {
+		ptr = v.Addr().UnsafePointer()
+	} else {
+		tmp := reflect.New(v.Type())
+		tmp.Elem().Set(v)
+		ptr = tmp.UnsafePointer()
+		keepAlive = append(keepAlive, tmp.Interface())
+	}
+
+	var buf [16]byte
+	src := unsafe.Slice((*byte)(ptr), size)
+	copy(buf[:], src)
+
+	w0 := *(*uintptr)(unsafe.Pointer(&buf[0]))
+	w1 := uintptr(0)
+	if size > 8 {
+		w1 = *(*uintptr)(unsafe.Pointer(&buf[8]))
+	}
+
+	if isFloats, _ := isAllSameFloat(v.Type()); isFloats {
+		addFloat(w0)
+		if size > 8 {
+			addFloat(w1)
+		}
+	} else {
+		addInt(w0)
+		if size > 8 {
+			addInt(w1)
+		}
+	}
+
+	return keepAlive
+}
+
+// placeStack is a fallback for structs that are too large to fit in registers
+func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
+	if v.CanAddr() {
+		addInt(v.Addr().Pointer())
+		return keepAlive
+	}
+	ptr := reflect.New(v.Type())
+	ptr.Elem().Set(v)
+	addInt(ptr.Pointer())
+	return append(keepAlive, ptr.Interface())
+}
+
+func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
+	// S390X does not bundle stack args
+	return false
+}
+
+func collectStackArgs(
+	args []reflect.Value,
+	i, numInts, numFloats int,
+	keepAlive []any,
+	addInt, addFloat, addStack func(uintptr),
+	numIntsPtr, numFloatsPtr, numStackPtr *int,
+) ([]reflect.Value, []any) {
+	return nil, keepAlive
+}
+
+func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
+	panic("bundleStackArgs not supported on S390X")
+}
diff --git a/vendor/github.com/ebitengine/purego/sys_386.s b/vendor/github.com/ebitengine/purego/sys_386.s
new file mode 100644
index 000000000..82931413e
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_386.s
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+#define STACK_SIZE 160
+#define PTR_ADDRESS (STACK_SIZE - 4)
+
+// syscall15X calls a function in libc on behalf of the syscall package.
+// syscall15X takes a pointer to a struct like:
+// struct {
+//	fn    uintptr
+//	a1    uintptr
+//  ...
+//	a32   uintptr
+//	f1    uintptr
+//	...
+//	f16   uintptr
+//	arm64_r8 uintptr
+// }
+// syscall15X must be called on the g0 stack with the
+// C calling convention (use libcCall).
+//
+// On i386 System V ABI, all arguments are passed on the stack.
+// Return value is in EAX (and EDX for 64-bit values).
+GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $4
+DATA ·syscall15XABI0(SB)/4, $syscall15X(SB)
+TEXT syscall15X(SB), NOSPLIT|NOFRAME, $0-0
+	// Called via C calling convention: argument pointer at 4(SP)
+	// NOT via Go calling convention
+	// On i386, the first argument is at 4(SP) after CALL pushes return address
+	MOVL 4(SP), AX // get pointer to syscall15Args
+
+	// Save callee-saved registers
+	PUSHL BP
+	PUSHL BX
+	PUSHL SI
+	PUSHL DI
+
+	MOVL AX, BX // save args pointer in BX
+
+	// Allocate stack space for C function arguments
+	// i386 SysV: all 32 args on stack = 32 * 4 = 128 bytes
+	// Plus 16 bytes for alignment and local storage
+	SUBL $STACK_SIZE, SP
+	MOVL BX, PTR_ADDRESS(SP) // save args pointer
+
+	// Load function pointer
+	MOVL syscall15Args_fn(BX), AX
+	MOVL AX, (PTR_ADDRESS-4)(SP)  // save fn pointer
+
+	// Push all integer arguments onto the stack (a1-a32)
+	// i386 SysV ABI: arguments pushed right-to-left, but we're
+	// setting up the stack from low to high addresses
+	MOVL syscall15Args_a1(BX), AX
+	MOVL AX, 0(SP)
+	MOVL syscall15Args_a2(BX), AX
+	MOVL AX, 4(SP)
+	MOVL syscall15Args_a3(BX), AX
+	MOVL AX, 8(SP)
+	MOVL syscall15Args_a4(BX), AX
+	MOVL AX, 12(SP)
+	MOVL syscall15Args_a5(BX), AX
+	MOVL AX, 16(SP)
+	MOVL syscall15Args_a6(BX), AX
+	MOVL AX, 20(SP)
+	MOVL syscall15Args_a7(BX), AX
+	MOVL AX, 24(SP)
+	MOVL syscall15Args_a8(BX), AX
+	MOVL AX, 28(SP)
+	MOVL syscall15Args_a9(BX), AX
+	MOVL AX, 32(SP)
+	MOVL syscall15Args_a10(BX), AX
+	MOVL AX, 36(SP)
+	MOVL syscall15Args_a11(BX), AX
+	MOVL AX, 40(SP)
+	MOVL syscall15Args_a12(BX), AX
+	MOVL AX, 44(SP)
+	MOVL syscall15Args_a13(BX), AX
+	MOVL AX, 48(SP)
+	MOVL syscall15Args_a14(BX), AX
+	MOVL AX, 52(SP)
+	MOVL syscall15Args_a15(BX), AX
+	MOVL AX, 56(SP)
+	MOVL syscall15Args_a16(BX), AX
+	MOVL AX, 60(SP)
+	MOVL syscall15Args_a17(BX), AX
+	MOVL AX, 64(SP)
+	MOVL syscall15Args_a18(BX), AX
+	MOVL AX, 68(SP)
+	MOVL syscall15Args_a19(BX), AX
+	MOVL AX, 72(SP)
+	MOVL syscall15Args_a20(BX), AX
+	MOVL AX, 76(SP)
+	MOVL syscall15Args_a21(BX), AX
+	MOVL AX, 80(SP)
+	MOVL syscall15Args_a22(BX), AX
+	MOVL AX, 84(SP)
+	MOVL syscall15Args_a23(BX), AX
+	MOVL AX, 88(SP)
+	MOVL syscall15Args_a24(BX), AX
+	MOVL AX, 92(SP)
+	MOVL syscall15Args_a25(BX), AX
+	MOVL AX, 96(SP)
+	MOVL syscall15Args_a26(BX), AX
+	MOVL AX, 100(SP)
+	MOVL syscall15Args_a27(BX), AX
+	MOVL AX, 104(SP)
+	MOVL syscall15Args_a28(BX), AX
+	MOVL AX, 108(SP)
+	MOVL syscall15Args_a29(BX), AX
+	MOVL AX, 112(SP)
+	MOVL syscall15Args_a30(BX), AX
+	MOVL AX, 116(SP)
+	MOVL syscall15Args_a31(BX), AX
+	MOVL AX, 120(SP)
+	MOVL syscall15Args_a32(BX), AX
+	MOVL AX, 124(SP)
+
+	// Call the C function
+	MOVL (PTR_ADDRESS-4)(SP), AX
+	CALL AX
+
+	// Get args pointer back and save results
+	MOVL PTR_ADDRESS(SP), BX
+	MOVL AX, syscall15Args_a1(BX) // return value r1
+	MOVL DX, syscall15Args_a2(BX) // return value r2 (for 64-bit returns)
+
+	// Save x87 FPU return value (ST0) to f1 field
+	// On i386 System V ABI, float/double returns are in ST(0)
+	// We save as float64 (8 bytes) to preserve precision
+	FMOVDP F0, syscall15Args_f1(BX)
+
+	// Clean up stack
+	ADDL $STACK_SIZE, SP
+
+	// Restore callee-saved registers
+	POPL DI
+	POPL SI
+	POPL BX
+	POPL BP
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_amd64.s b/vendor/github.com/ebitengine/purego/sys_amd64.s
new file mode 100644
index 000000000..15b24dd29
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_amd64.s
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build darwin || freebsd || linux || netbsd
+
+#include "textflag.h"
+#include "abi_amd64.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+#define STACK_SIZE 80
+#define PTR_ADDRESS (STACK_SIZE - 8)
+
+// syscall15X calls a function in libc on behalf of the syscall package.
+// syscall15X takes a pointer to a struct like:
+// struct {
+//	fn    uintptr
+//	a1    uintptr
+//	a2    uintptr
+//	a3    uintptr
+//	a4    uintptr
+//	a5    uintptr
+//	a6    uintptr
+//	a7    uintptr
+//	a8    uintptr
+//	a9    uintptr
+//	a10    uintptr
+//	a11    uintptr
+//	a12    uintptr
+//	a13    uintptr
+//	a14    uintptr
+//	a15    uintptr
+//	r1    uintptr
+//	r2    uintptr
+//	err   uintptr
+// }
+// syscall15X must be called on the g0 stack with the
+// C calling convention (use libcCall).
+GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $8
+DATA ·syscall15XABI0(SB)/8, $syscall15X(SB)
+TEXT syscall15X(SB), NOSPLIT|NOFRAME, $0
+	PUSHQ BP
+	MOVQ  SP, BP
+	SUBQ  $STACK_SIZE, SP
+	MOVQ  DI, PTR_ADDRESS(BP) // save the pointer
+	MOVQ  DI, R11
+
+	MOVQ syscall15Args_f1(R11), X0 // f1
+	MOVQ syscall15Args_f2(R11), X1 // f2
+	MOVQ syscall15Args_f3(R11), X2 // f3
+	MOVQ syscall15Args_f4(R11), X3 // f4
+	MOVQ syscall15Args_f5(R11), X4 // f5
+	MOVQ syscall15Args_f6(R11), X5 // f6
+	MOVQ syscall15Args_f7(R11), X6 // f7
+	MOVQ syscall15Args_f8(R11), X7 // f8
+
+	MOVQ syscall15Args_a1(R11), DI // a1
+	MOVQ syscall15Args_a2(R11), SI // a2
+	MOVQ syscall15Args_a3(R11), DX // a3
+	MOVQ syscall15Args_a4(R11), CX // a4
+	MOVQ syscall15Args_a5(R11), R8 // a5
+	MOVQ syscall15Args_a6(R11), R9 // a6
+
+	// push the remaining paramters onto the stack
+	MOVQ syscall15Args_a7(R11), R12
+	MOVQ R12, 0(SP)                  // push a7
+	MOVQ syscall15Args_a8(R11), R12
+	MOVQ R12, 8(SP)                  // push a8
+	MOVQ syscall15Args_a9(R11), R12
+	MOVQ R12, 16(SP)                 // push a9
+	MOVQ syscall15Args_a10(R11), R12
+	MOVQ R12, 24(SP)                 // push a10
+	MOVQ syscall15Args_a11(R11), R12
+	MOVQ R12, 32(SP)                 // push a11
+	MOVQ syscall15Args_a12(R11), R12
+	MOVQ R12, 40(SP)                 // push a12
+	MOVQ syscall15Args_a13(R11), R12
+	MOVQ R12, 48(SP)                 // push a13
+	MOVQ syscall15Args_a14(R11), R12
+	MOVQ R12, 56(SP)                 // push a14
+	MOVQ syscall15Args_a15(R11), R12
+	MOVQ R12, 64(SP)                 // push a15
+	XORL AX, AX                      // vararg: say "no float args"
+
+	MOVQ syscall15Args_fn(R11), R10 // fn
+	CALL R10
+
+	MOVQ PTR_ADDRESS(BP), DI      // get the pointer back
+	MOVQ AX, syscall15Args_a1(DI) // r1
+	MOVQ DX, syscall15Args_a2(DI) // r3
+	MOVQ X0, syscall15Args_f1(DI) // f1
+	MOVQ X1, syscall15Args_f2(DI) // f2
+
+#ifdef GOOS_darwin
+    CALL purego_error(SB)
+    MOVD (AX), AX
+    MOVD AX, syscall15Args_a3(DI) // save errno
+#endif
+
+	XORL AX, AX          // no error (it's ignored anyway)
+	ADDQ $STACK_SIZE, SP
+	MOVQ BP, SP
+	POPQ BP
+	RET
+
+TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
+	MOVQ 0(SP), AX  // save the return address to calculate the cb index
+	MOVQ 8(SP), R10 // get the return SP so that we can align register args with stack args
+	ADDQ $8, SP     // remove return address from stack, we are not returning to callbackasm, but to its caller.
+
+	// make space for first six int and 8 float arguments below the frame
+	ADJSP $14*8, SP
+	MOVSD X0, (1*8)(SP)
+	MOVSD X1, (2*8)(SP)
+	MOVSD X2, (3*8)(SP)
+	MOVSD X3, (4*8)(SP)
+	MOVSD X4, (5*8)(SP)
+	MOVSD X5, (6*8)(SP)
+	MOVSD X6, (7*8)(SP)
+	MOVSD X7, (8*8)(SP)
+	MOVQ  DI, (9*8)(SP)
+	MOVQ  SI, (10*8)(SP)
+	MOVQ  DX, (11*8)(SP)
+	MOVQ  CX, (12*8)(SP)
+	MOVQ  R8, (13*8)(SP)
+	MOVQ  R9, (14*8)(SP)
+	LEAQ  8(SP), R8      // R8 = address of args vector
+
+	PUSHQ R10 // push the stack pointer below registers
+
+	// Switch from the host ABI to the Go ABI.
+	PUSH_REGS_HOST_TO_ABI0()
+
+	// determine index into runtime·cbs table
+	MOVQ $callbackasm(SB), DX
+	SUBQ DX, AX
+	MOVQ $0, DX
+	MOVQ $5, CX               // divide by 5 because each call instruction in ·callbacks is 5 bytes long
+	DIVL CX
+	SUBQ $1, AX               // subtract 1 because return PC is to the next slot
+
+	// Create a struct callbackArgs on our stack to be passed as
+	// the "frame" to cgocallback and on to callbackWrap.
+	// $24 to make enough room for the arguments to runtime.cgocallback
+	SUBQ $(24+callbackArgs__size), SP
+	MOVQ AX, (24+callbackArgs_index)(SP)  // callback index
+	MOVQ R8, (24+callbackArgs_args)(SP)   // address of args vector
+	MOVQ $0, (24+callbackArgs_result)(SP) // result
+	LEAQ 24(SP), AX                       // take the address of callbackArgs
+
+	// Call cgocallback, which will call callbackWrap(frame).
+	MOVQ ·callbackWrap_call(SB), DI // Get the ABIInternal function pointer
+	MOVQ (DI), DI                   // without <ABIInternal> by using a closure.
+	MOVQ AX, SI                     // frame (address of callbackArgs)
+	MOVQ $0, CX                     // context
+
+	CALL crosscall2(SB) // runtime.cgocallback(fn, frame, ctxt uintptr)
+
+	// Get callback result.
+	MOVQ (24+callbackArgs_result)(SP), AX
+	ADDQ $(24+callbackArgs__size), SP     // remove callbackArgs struct
+
+	POP_REGS_HOST_TO_ABI0()
+
+	POPQ  R10        // get the SP back
+	ADJSP $-14*8, SP // remove arguments
+
+	MOVQ R10, 0(SP)
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_arm.s b/vendor/github.com/ebitengine/purego/sys_arm.s
new file mode 100644
index 000000000..3a8ce0d0d
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_arm.s
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+#define STACK_SIZE 128
+#define PTR_ADDRESS (STACK_SIZE - 4)
+
+// syscall15X calls a function in libc on behalf of the syscall package.
+// syscall15X takes a pointer to a struct like:
+// struct {
+//	fn    uintptr
+//	a1    uintptr
+//  ...
+//	a32   uintptr
+//	f1    uintptr
+//	...
+//	f16   uintptr
+//	arm64_r8 uintptr
+// }
+// syscall15X must be called on the g0 stack with the
+// C calling convention (use libcCall).
+GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $4
+DATA ·syscall15XABI0(SB)/4, $syscall15X(SB)
+TEXT syscall15X(SB), NOSPLIT|NOFRAME, $0-0
+	// Called via C calling convention: R0 = pointer to syscall15Args
+	// NOT via Go calling convention
+	// Save link register and callee-saved registers first
+	MOVW.W    R14, -4(R13)                         // save LR (decrement and store)
+	MOVM.DB.W [R4, R5, R6, R7, R8, R9, R11], (R13) // save callee-saved regs
+
+	MOVW R0, R8
+	SUB  $STACK_SIZE, R13
+	MOVW R8, PTR_ADDRESS(R13)
+
+	// Load function pointer first (before anything can corrupt R8)
+	MOVW syscall15Args_fn(R8), R5
+	MOVW R5, (PTR_ADDRESS-4)(R13) // save fn at offset 56
+
+	// Load floating point arguments
+	// Each float64 spans 2 uintptr slots (8 bytes) on ARM32, so we skip by 2
+	MOVD syscall15Args_f1(R8), F0  // f1+f2 -> D0
+	MOVD syscall15Args_f3(R8), F1  // f3+f4 -> D1
+	MOVD syscall15Args_f5(R8), F2  // f5+f6 -> D2
+	MOVD syscall15Args_f7(R8), F3  // f7+f8 -> D3
+	MOVD syscall15Args_f9(R8), F4  // f9+f10 -> D4
+	MOVD syscall15Args_f11(R8), F5 // f11+f12 -> D5
+	MOVD syscall15Args_f13(R8), F6 // f13+f14 -> D6
+	MOVD syscall15Args_f15(R8), F7 // f15+f16 -> D7
+
+	// Load integer arguments into registers (R0-R3 for ARM EABI)
+	MOVW syscall15Args_a1(R8), R0 // a1
+	MOVW syscall15Args_a2(R8), R1 // a2
+	MOVW syscall15Args_a3(R8), R2 // a3
+	MOVW syscall15Args_a4(R8), R3 // a4
+
+	// push a5-a32 onto stack
+	MOVW syscall15Args_a5(R8), R4
+	MOVW R4, 0(R13)
+	MOVW syscall15Args_a6(R8), R4
+	MOVW R4, 4(R13)
+	MOVW syscall15Args_a7(R8), R4
+	MOVW R4, 8(R13)
+	MOVW syscall15Args_a8(R8), R4
+	MOVW R4, 12(R13)
+	MOVW syscall15Args_a9(R8), R4
+	MOVW R4, 16(R13)
+	MOVW syscall15Args_a10(R8), R4
+	MOVW R4, 20(R13)
+	MOVW syscall15Args_a11(R8), R4
+	MOVW R4, 24(R13)
+	MOVW syscall15Args_a12(R8), R4
+	MOVW R4, 28(R13)
+	MOVW syscall15Args_a13(R8), R4
+	MOVW R4, 32(R13)
+	MOVW syscall15Args_a14(R8), R4
+	MOVW R4, 36(R13)
+	MOVW syscall15Args_a15(R8), R4
+	MOVW R4, 40(R13)
+	MOVW syscall15Args_a16(R8), R4
+	MOVW R4, 44(R13)
+	MOVW syscall15Args_a17(R8), R4
+	MOVW R4, 48(R13)
+	MOVW syscall15Args_a18(R8), R4
+	MOVW R4, 52(R13)
+	MOVW syscall15Args_a19(R8), R4
+	MOVW R4, 56(R13)
+	MOVW syscall15Args_a20(R8), R4
+	MOVW R4, 60(R13)
+	MOVW syscall15Args_a21(R8), R4
+	MOVW R4, 64(R13)
+	MOVW syscall15Args_a22(R8), R4
+	MOVW R4, 68(R13)
+	MOVW syscall15Args_a23(R8), R4
+	MOVW R4, 72(R13)
+	MOVW syscall15Args_a24(R8), R4
+	MOVW R4, 76(R13)
+	MOVW syscall15Args_a25(R8), R4
+	MOVW R4, 80(R13)
+	MOVW syscall15Args_a26(R8), R4
+	MOVW R4, 84(R13)
+	MOVW syscall15Args_a27(R8), R4
+	MOVW R4, 88(R13)
+	MOVW syscall15Args_a28(R8), R4
+	MOVW R4, 92(R13)
+	MOVW syscall15Args_a29(R8), R4
+	MOVW R4, 96(R13)
+	MOVW syscall15Args_a30(R8), R4
+	MOVW R4, 100(R13)
+	MOVW syscall15Args_a31(R8), R4
+	MOVW R4, 104(R13)
+	MOVW syscall15Args_a32(R8), R4
+	MOVW R4, 108(R13)
+
+	// Load saved function pointer and call
+	MOVW (PTR_ADDRESS-4)(R13), R4
+
+	// Use BLX for Thumb interworking - Go assembler doesn't support BLX Rn
+	// BLX R4 = 0xE12FFF34 (ARM encoding, always condition)
+	WORD $0xE12FFF34 // blx r4
+
+	// pop structure pointer
+	MOVW PTR_ADDRESS(R13), R8
+	ADD  $STACK_SIZE, R13
+
+	// save R0, R1
+	MOVW R0, syscall15Args_a1(R8)
+	MOVW R1, syscall15Args_a2(R8)
+
+	// save f0-f3 (each float64 spans 2 uintptr slots on ARM32)
+	MOVD F0, syscall15Args_f1(R8)
+	MOVD F1, syscall15Args_f3(R8)
+	MOVD F2, syscall15Args_f5(R8)
+	MOVD F3, syscall15Args_f7(R8)
+
+	// Restore callee-saved registers and return
+	MOVM.IA.W (R13), [R4, R5, R6, R7, R8, R9, R11]
+	MOVW.P    4(R13), R15                          // pop LR into PC (return)
diff --git a/vendor/github.com/ebitengine/purego/sys_arm64.s b/vendor/github.com/ebitengine/purego/sys_arm64.s
new file mode 100644
index 000000000..40a2f4c1d
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_arm64.s
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build darwin || freebsd || linux || netbsd || windows
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+#define STACK_SIZE 64
+#define PTR_ADDRESS (STACK_SIZE - 8)
+
+// syscall15X calls a function in libc on behalf of the syscall package.
+// syscall15X takes a pointer to a struct like:
+// struct {
+//	fn    uintptr
+//	a1    uintptr
+//	a2    uintptr
+//	a3    uintptr
+//	a4    uintptr
+//	a5    uintptr
+//	a6    uintptr
+//	a7    uintptr
+//	a8    uintptr
+//	a9    uintptr
+//	a10    uintptr
+//	a11    uintptr
+//	a12    uintptr
+//	a13    uintptr
+//	a14    uintptr
+//	a15    uintptr
+//	r1    uintptr
+//	r2    uintptr
+//	err   uintptr
+// }
+// syscall15X must be called on the g0 stack with the
+// C calling convention (use libcCall).
+GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $8
+DATA ·syscall15XABI0(SB)/8, $syscall15X(SB)
+TEXT syscall15X(SB), NOSPLIT, $0
+	SUB  $STACK_SIZE, RSP     // push structure pointer
+	MOVD R0, PTR_ADDRESS(RSP)
+	MOVD R0, R9
+
+	FMOVD syscall15Args_f1(R9), F0 // f1
+	FMOVD syscall15Args_f2(R9), F1 // f2
+	FMOVD syscall15Args_f3(R9), F2 // f3
+	FMOVD syscall15Args_f4(R9), F3 // f4
+	FMOVD syscall15Args_f5(R9), F4 // f5
+	FMOVD syscall15Args_f6(R9), F5 // f6
+	FMOVD syscall15Args_f7(R9), F6 // f7
+	FMOVD syscall15Args_f8(R9), F7 // f8
+
+	MOVD syscall15Args_a1(R9), R0       // a1
+	MOVD syscall15Args_a2(R9), R1       // a2
+	MOVD syscall15Args_a3(R9), R2       // a3
+	MOVD syscall15Args_a4(R9), R3       // a4
+	MOVD syscall15Args_a5(R9), R4       // a5
+	MOVD syscall15Args_a6(R9), R5       // a6
+	MOVD syscall15Args_a7(R9), R6       // a7
+	MOVD syscall15Args_a8(R9), R7       // a8
+	MOVD syscall15Args_arm64_r8(R9), R8 // r8
+
+	MOVD syscall15Args_a9(R9), R10
+	MOVD R10, 0(RSP)                // push a9 onto stack
+	MOVD syscall15Args_a10(R9), R10
+	MOVD R10, 8(RSP)                // push a10 onto stack
+	MOVD syscall15Args_a11(R9), R10
+	MOVD R10, 16(RSP)               // push a11 onto stack
+	MOVD syscall15Args_a12(R9), R10
+	MOVD R10, 24(RSP)               // push a12 onto stack
+	MOVD syscall15Args_a13(R9), R10
+	MOVD R10, 32(RSP)               // push a13 onto stack
+	MOVD syscall15Args_a14(R9), R10
+	MOVD R10, 40(RSP)               // push a14 onto stack
+	MOVD syscall15Args_a15(R9), R10
+	MOVD R10, 48(RSP)               // push a15 onto stack
+
+	MOVD syscall15Args_fn(R9), R10 // fn
+	BL   (R10)
+
+	MOVD PTR_ADDRESS(RSP), R2 // pop structure pointer
+	ADD  $STACK_SIZE, RSP
+
+	MOVD  R0, syscall15Args_a1(R2) // save r1
+	MOVD  R1, syscall15Args_a2(R2) // save r3
+	FMOVD F0, syscall15Args_f1(R2) // save f0
+	FMOVD F1, syscall15Args_f2(R2) // save f1
+	FMOVD F2, syscall15Args_f3(R2) // save f2
+	FMOVD F3, syscall15Args_f4(R2) // save f3
+
+#ifdef GOOS_darwin
+	BL purego_error(SB)
+	MOVD (R0), R0
+	MOVD R0, syscall15Args_a3(R2) // save errno
+#endif
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_loong64.s b/vendor/github.com/ebitengine/purego/sys_loong64.s
new file mode 100644
index 000000000..420b855c2
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_loong64.s
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+#define STACK_SIZE 64
+#define PTR_ADDRESS (STACK_SIZE - 8)
+
+// syscall15X calls a function in libc on behalf of the syscall package.
+// syscall15X takes a pointer to a struct like:
+// struct {
+//	fn    uintptr
+//	a1    uintptr
+//	a2    uintptr
+//	a3    uintptr
+//	a4    uintptr
+//	a5    uintptr
+//	a6    uintptr
+//	a7    uintptr
+//	a8    uintptr
+//	a9    uintptr
+//	a10    uintptr
+//	a11    uintptr
+//	a12    uintptr
+//	a13    uintptr
+//	a14    uintptr
+//	a15    uintptr
+//	r1    uintptr
+//	r2    uintptr
+//	err   uintptr
+// }
+// syscall15X must be called on the g0 stack with the
+// C calling convention (use libcCall).
+GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $8
+DATA ·syscall15XABI0(SB)/8, $syscall15X(SB)
+TEXT syscall15X(SB), NOSPLIT, $0
+	// push structure pointer
+	SUBV $STACK_SIZE, R3
+	MOVV R4, PTR_ADDRESS(R3)
+	MOVV R4, R13
+
+	MOVD syscall15Args_f1(R13), F0 // f1
+	MOVD syscall15Args_f2(R13), F1 // f2
+	MOVD syscall15Args_f3(R13), F2 // f3
+	MOVD syscall15Args_f4(R13), F3 // f4
+	MOVD syscall15Args_f5(R13), F4 // f5
+	MOVD syscall15Args_f6(R13), F5 // f6
+	MOVD syscall15Args_f7(R13), F6 // f7
+	MOVD syscall15Args_f8(R13), F7 // f8
+
+	MOVV syscall15Args_a1(R13), R4  // a1
+	MOVV syscall15Args_a2(R13), R5  // a2
+	MOVV syscall15Args_a3(R13), R6  // a3
+	MOVV syscall15Args_a4(R13), R7  // a4
+	MOVV syscall15Args_a5(R13), R8  // a5
+	MOVV syscall15Args_a6(R13), R9  // a6
+	MOVV syscall15Args_a7(R13), R10 // a7
+	MOVV syscall15Args_a8(R13), R11 // a8
+
+	// push a9-a15 onto stack
+	MOVV syscall15Args_a9(R13), R12
+	MOVV R12, 0(R3)
+	MOVV syscall15Args_a10(R13), R12
+	MOVV R12, 8(R3)
+	MOVV syscall15Args_a11(R13), R12
+	MOVV R12, 16(R3)
+	MOVV syscall15Args_a12(R13), R12
+	MOVV R12, 24(R3)
+	MOVV syscall15Args_a13(R13), R12
+	MOVV R12, 32(R3)
+	MOVV syscall15Args_a14(R13), R12
+	MOVV R12, 40(R3)
+	MOVV syscall15Args_a15(R13), R12
+	MOVV R12, 48(R3)
+
+	MOVV syscall15Args_fn(R13), R12
+	JAL  (R12)
+
+	// pop structure pointer
+	MOVV PTR_ADDRESS(R3), R13
+	ADDV $STACK_SIZE, R3
+
+	// save R4, R5
+	MOVV R4, syscall15Args_a1(R13)
+	MOVV R5, syscall15Args_a2(R13)
+
+	// save f0-f3
+	MOVD F0, syscall15Args_f1(R13)
+	MOVD F1, syscall15Args_f2(R13)
+	MOVD F2, syscall15Args_f3(R13)
+	MOVD F3, syscall15Args_f4(R13)
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_ppc64le.s b/vendor/github.com/ebitengine/purego/sys_ppc64le.s
new file mode 100644
index 000000000..391b30a95
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_ppc64le.s
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+// PPC64LE ELFv2 ABI:
+// - Integer args: R3-R10 (8 registers)
+// - Float args: F1-F8 (8 registers)
+// - Return: R3 (integer), F1 (float)
+// - Stack pointer: R1
+// - Link register: LR (special)
+// - TOC pointer: R2 (must preserve)
+
+// Stack layout for ELFv2 ABI (aligned to 16 bytes):
+// From callee's perspective when we call BL (CTR):
+//  0(R1)  - back chain (our old R1)
+//  8(R1)  - CR save word (optional)
+// 16(R1)  - LR save (optional, we save it)
+// 24(R1)  - Reserved (compilers)
+// 32(R1)  - Parameter save area start (8 * 8 = 64 bytes for R3-R10)
+// 96(R1)  - First stack arg (a9) - this is where callee looks
+// 104(R1) - Second stack arg (a10)
+// 112-152 - Stack args a11-a15 (5 * 8 = 40 bytes)
+// 160(R1) - TOC save (we put it here, outside param save area)
+// 168(R1) - saved args pointer
+// 176(R1) - padding for 16-byte alignment
+// Total: 176 bytes
+
+#define STACK_SIZE 176
+#define LR_SAVE    16
+#define TOC_SAVE   160
+#define ARGP_SAVE  168
+
+GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $8
+DATA ·syscall15XABI0(SB)/8, $syscall15X(SB)
+
+TEXT syscall15X(SB), NOSPLIT, $0
+	// Prologue: create stack frame
+	// R3 contains the args pointer on entry
+	MOVD R1, R12          // save old SP
+	SUB  $STACK_SIZE, R1  // allocate stack frame
+	MOVD R12, 0(R1)       // save back chain
+	MOVD LR, R12
+	MOVD R12, LR_SAVE(R1) // save LR
+	MOVD R2, TOC_SAVE(R1) // save TOC
+
+	// Save args pointer (in R3)
+	MOVD R3, ARGP_SAVE(R1)
+
+	// R11 := args pointer (syscall15Args*)
+	MOVD R3, R11
+
+	// Load float args into F1-F8
+	FMOVD syscall15Args_f1(R11), F1
+	FMOVD syscall15Args_f2(R11), F2
+	FMOVD syscall15Args_f3(R11), F3
+	FMOVD syscall15Args_f4(R11), F4
+	FMOVD syscall15Args_f5(R11), F5
+	FMOVD syscall15Args_f6(R11), F6
+	FMOVD syscall15Args_f7(R11), F7
+	FMOVD syscall15Args_f8(R11), F8
+
+	// Load integer args into R3-R10
+	MOVD syscall15Args_a1(R11), R3
+	MOVD syscall15Args_a2(R11), R4
+	MOVD syscall15Args_a3(R11), R5
+	MOVD syscall15Args_a4(R11), R6
+	MOVD syscall15Args_a5(R11), R7
+	MOVD syscall15Args_a6(R11), R8
+	MOVD syscall15Args_a7(R11), R9
+	MOVD syscall15Args_a8(R11), R10
+
+	// Spill a9-a15 onto the stack (stack parameters start at 96(R1))
+	// Per ELFv2: parameter save area is 32-95, stack args start at 96
+	MOVD ARGP_SAVE(R1), R11          // reload args pointer
+	MOVD syscall15Args_a9(R11), R12
+	MOVD R12, 96(R1)                 // a9 at 96(R1)
+	MOVD syscall15Args_a10(R11), R12
+	MOVD R12, 104(R1)                // a10 at 104(R1)
+	MOVD syscall15Args_a11(R11), R12
+	MOVD R12, 112(R1)                // a11 at 112(R1)
+	MOVD syscall15Args_a12(R11), R12
+	MOVD R12, 120(R1)                // a12 at 120(R1)
+	MOVD syscall15Args_a13(R11), R12
+	MOVD R12, 128(R1)                // a13 at 128(R1)
+	MOVD syscall15Args_a14(R11), R12
+	MOVD R12, 136(R1)                // a14 at 136(R1)
+	MOVD syscall15Args_a15(R11), R12
+	MOVD R12, 144(R1)                // a15 at 144(R1)
+
+	// Call function: load fn and call
+	MOVD syscall15Args_fn(R11), R12
+	MOVD R12, CTR
+	BL   (CTR)
+
+	// Restore TOC after call
+	MOVD TOC_SAVE(R1), R2
+
+	// Restore args pointer for storing results
+	MOVD ARGP_SAVE(R1), R11
+
+	// Store integer results back (R3, R4)
+	MOVD R3, syscall15Args_a1(R11)
+	MOVD R4, syscall15Args_a2(R11)
+
+	// Store float return values (F1-F4)
+	FMOVD F1, syscall15Args_f1(R11)
+	FMOVD F2, syscall15Args_f2(R11)
+	FMOVD F3, syscall15Args_f3(R11)
+	FMOVD F4, syscall15Args_f4(R11)
+
+	// Epilogue: restore and return
+	MOVD LR_SAVE(R1), R12
+	MOVD R12, LR
+	ADD  $STACK_SIZE, R1
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_riscv64.s b/vendor/github.com/ebitengine/purego/sys_riscv64.s
new file mode 100644
index 000000000..e7e887e15
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_riscv64.s
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+// Stack usage:
+//  0(SP)  - 56(SP):  stack args a9-a15 (7 * 8 bytes = 56)
+// 56(SP)  - 64(SP):  saved RA (x1)
+// 64(SP)  - 72(SP):  saved X9 (s1)
+// 72(SP)  - 80(SP):  saved X18 (s2)
+// 80(SP)  - 88(SP):  saved args pointer (original X10)
+// 88(SP)  - 96(SP):  padding
+#define STACK_SIZE 96
+#define SAVE_RA    56
+#define SAVE_X9    64
+#define SAVE_X18   72
+#define SAVE_ARGP  80
+
+GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $8
+DATA ·syscall15XABI0(SB)/8, $syscall15X(SB)
+
+TEXT syscall15X(SB), NOSPLIT, $0
+	// Allocate stack frame (keeps 16-byte alignment)
+	SUB $STACK_SIZE, SP
+
+	// Save callee-saved regs we clobber + return address
+	MOV X1, SAVE_RA(SP)
+	MOV X9, SAVE_X9(SP)
+	MOV X18, SAVE_X18(SP)
+
+	// Save original args pointer (in a0/X10)
+	MOV X10, SAVE_ARGP(SP)
+
+	// X9 := args pointer (syscall15Args*)
+	MOV X10, X9
+
+	// Load float args into fa0-fa7 (F10-F17)
+	MOVD syscall15Args_f1(X9), F10
+	MOVD syscall15Args_f2(X9), F11
+	MOVD syscall15Args_f3(X9), F12
+	MOVD syscall15Args_f4(X9), F13
+	MOVD syscall15Args_f5(X9), F14
+	MOVD syscall15Args_f6(X9), F15
+	MOVD syscall15Args_f7(X9), F16
+	MOVD syscall15Args_f8(X9), F17
+
+	// Load integer args into a0-a7 (X10-X17)
+	MOV syscall15Args_a1(X9), X10
+	MOV syscall15Args_a2(X9), X11
+	MOV syscall15Args_a3(X9), X12
+	MOV syscall15Args_a4(X9), X13
+	MOV syscall15Args_a5(X9), X14
+	MOV syscall15Args_a6(X9), X15
+	MOV syscall15Args_a7(X9), X16
+	MOV syscall15Args_a8(X9), X17
+
+	// Spill a9-a15 onto the stack (C ABI)
+	MOV syscall15Args_a9(X9), X18
+	MOV X18, 0(SP)
+	MOV syscall15Args_a10(X9), X18
+	MOV X18, 8(SP)
+	MOV syscall15Args_a11(X9), X18
+	MOV X18, 16(SP)
+	MOV syscall15Args_a12(X9), X18
+	MOV X18, 24(SP)
+	MOV syscall15Args_a13(X9), X18
+	MOV X18, 32(SP)
+	MOV syscall15Args_a14(X9), X18
+	MOV X18, 40(SP)
+	MOV syscall15Args_a15(X9), X18
+	MOV X18, 48(SP)
+
+	// Call fn
+	// IMPORTANT: preserve RA across this call (we saved it above)
+	MOV  syscall15Args_fn(X9), X18
+	CALL X18
+
+	// Restore args pointer (syscall15Args*) for storing results
+	MOV SAVE_ARGP(SP), X9
+
+	// Store results back
+	MOV X10, syscall15Args_a1(X9)
+	MOV X11, syscall15Args_a2(X9)
+
+	// Store back float return regs if used by your ABI contract
+	MOVD F10, syscall15Args_f1(X9)
+	MOVD F11, syscall15Args_f2(X9)
+	MOVD F12, syscall15Args_f3(X9)
+	MOVD F13, syscall15Args_f4(X9)
+
+	// Restore callee-saved regs and return address
+	MOV SAVE_X18(SP), X18
+	MOV SAVE_X9(SP), X9
+	MOV SAVE_RA(SP), X1
+
+	ADD $STACK_SIZE, SP
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_s390x.s b/vendor/github.com/ebitengine/purego/sys_s390x.s
new file mode 100644
index 000000000..a044e34d3
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_s390x.s
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+// S390X ELF ABI:
+// - Integer args: R2-R6 (5 registers)
+// - Float args: F0, F2, F4, F6 (4 registers, even-numbered)
+// - Return: R2 (integer), F0 (float)
+// - Stack pointer: R15
+// - Link register: R14
+// - Callee-saved: R6-R13, F8-F15 (but R6 is also used for 5th param)
+//
+// Stack frame layout (aligned to 8 bytes):
+//   0(R15)   - back chain
+//   8(R15)   - reserved
+//  16(R15)   - reserved
+//  ...       - register save area (R6-R15 at 48(R15))
+// 160(R15)  - parameter area start (args beyond registers)
+//
+// We need space for:
+// - 160 bytes standard frame (with register save area)
+// - Stack args a6-a15 (10 * 8 = 80 bytes)
+// - Saved args pointer (8 bytes)
+// - Padding for alignment
+// Total: 264 bytes (rounded to 8-byte alignment)
+
+#define STACK_SIZE 264
+#define STACK_ARGS 160
+#define ARGP_SAVE  248
+
+GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $8
+DATA ·syscall15XABI0(SB)/8, $syscall15X(SB)
+
+TEXT syscall15X(SB), NOSPLIT, $0
+	// On entry, R2 contains the args pointer
+	// Save callee-saved registers in caller's frame (per ABI)
+	STMG R6, R15, 48(R15)
+
+	// Allocate our stack frame
+	MOVD R15, R1
+	SUB  $STACK_SIZE, R15
+	MOVD R1, 0(R15)       // back chain
+
+	// Save args pointer
+	MOVD R2, ARGP_SAVE(R15)
+
+	// R9 := args pointer (syscall15Args*)
+	MOVD R2, R9
+
+	// Load float args into F0, F2, F4, F6 (s390x uses even-numbered FPRs)
+	FMOVD syscall15Args_f1(R9), F0
+	FMOVD syscall15Args_f2(R9), F2
+	FMOVD syscall15Args_f3(R9), F4
+	FMOVD syscall15Args_f4(R9), F6
+
+	// Load integer args into R2-R6 (5 registers)
+	MOVD syscall15Args_a1(R9), R2
+	MOVD syscall15Args_a2(R9), R3
+	MOVD syscall15Args_a3(R9), R4
+	MOVD syscall15Args_a4(R9), R5
+	MOVD syscall15Args_a5(R9), R6
+
+	// Spill remaining args (a6-a15) onto the stack at 160(R15)
+	MOVD ARGP_SAVE(R15), R9        // reload args pointer
+	MOVD syscall15Args_a6(R9), R1
+	MOVD R1, (STACK_ARGS+0*8)(R15)
+	MOVD syscall15Args_a7(R9), R1
+	MOVD R1, (STACK_ARGS+1*8)(R15)
+	MOVD syscall15Args_a8(R9), R1
+	MOVD R1, (STACK_ARGS+2*8)(R15)
+	MOVD syscall15Args_a9(R9), R1
+	MOVD R1, (STACK_ARGS+3*8)(R15)
+	MOVD syscall15Args_a10(R9), R1
+	MOVD R1, (STACK_ARGS+4*8)(R15)
+	MOVD syscall15Args_a11(R9), R1
+	MOVD R1, (STACK_ARGS+5*8)(R15)
+	MOVD syscall15Args_a12(R9), R1
+	MOVD R1, (STACK_ARGS+6*8)(R15)
+	MOVD syscall15Args_a13(R9), R1
+	MOVD R1, (STACK_ARGS+7*8)(R15)
+	MOVD syscall15Args_a14(R9), R1
+	MOVD R1, (STACK_ARGS+8*8)(R15)
+	MOVD syscall15Args_a15(R9), R1
+	MOVD R1, (STACK_ARGS+9*8)(R15)
+
+	// Call function
+	MOVD syscall15Args_fn(R9), R1
+	BL   (R1)
+
+	// Restore args pointer for storing results
+	MOVD ARGP_SAVE(R15), R9
+
+	// Store integer results back (R2, R3)
+	MOVD R2, syscall15Args_a1(R9)
+	MOVD R3, syscall15Args_a2(R9)
+
+	// Store float return values (F0, F2, F4, F6)
+	FMOVD F0, syscall15Args_f1(R9)
+	FMOVD F2, syscall15Args_f2(R9)
+	FMOVD F4, syscall15Args_f3(R9)
+	FMOVD F6, syscall15Args_f4(R9)
+
+	// Deallocate stack frame
+	ADD $STACK_SIZE, R15
+
+	// Restore callee-saved registers from caller's save area
+	LMG 48(R15), R6, R15
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_unix_386.s b/vendor/github.com/ebitengine/purego/sys_unix_386.s
new file mode 100644
index 000000000..31aecbf3c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_unix_386.s
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+// callbackasm1 is the second part of the callback trampoline.
+// On entry:
+//   - CX contains the callback index (set by callbackasm)
+//   - 0(SP) contains the return address to C caller
+//   - 4(SP), 8(SP), ... contain C arguments (cdecl convention)
+//
+// i386 cdecl calling convention:
+// - All arguments passed on stack
+// - Return value in EAX (and EDX for 64-bit)
+// - Caller cleans the stack
+// - Callee must preserve: EBX, ESI, EDI, EBP
+TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
+	NO_LOCAL_POINTERS
+
+	// Save the return address
+	MOVL 0(SP), AX
+
+	// Allocate stack frame (must be done carefully to preserve args access)
+	// Layout:
+	//   0-15: saved callee-saved registers (BX, SI, DI, BP)
+	//   16-19: saved callback index
+	//   20-23: saved return address
+	//   24-35: callbackArgs struct (12 bytes)
+	//   36-291: copy of C arguments (256 bytes for 64 args, matching callbackMaxFrame)
+	// Total: 292 bytes, round up to 304 for alignment
+	SUBL $304, SP
+
+	// Save callee-saved registers
+	MOVL BX, 0(SP)
+	MOVL SI, 4(SP)
+	MOVL DI, 8(SP)
+	MOVL BP, 12(SP)
+
+	// Save callback index and return address
+	MOVL CX, 16(SP)
+	MOVL AX, 20(SP)
+
+	// Copy C arguments from original stack location to our frame
+	// Original args start at 304+4(SP) = 308(SP) (past our frame + original return addr)
+	// Copy to our frame at 36(SP)
+	// Copy 64 arguments (256 bytes, matching callbackMaxFrame = 64 * ptrSize)
+	MOVL 308(SP), AX
+	MOVL AX, 36(SP)
+	MOVL 312(SP), AX
+	MOVL AX, 40(SP)
+	MOVL 316(SP), AX
+	MOVL AX, 44(SP)
+	MOVL 320(SP), AX
+	MOVL AX, 48(SP)
+	MOVL 324(SP), AX
+	MOVL AX, 52(SP)
+	MOVL 328(SP), AX
+	MOVL AX, 56(SP)
+	MOVL 332(SP), AX
+	MOVL AX, 60(SP)
+	MOVL 336(SP), AX
+	MOVL AX, 64(SP)
+	MOVL 340(SP), AX
+	MOVL AX, 68(SP)
+	MOVL 344(SP), AX
+	MOVL AX, 72(SP)
+	MOVL 348(SP), AX
+	MOVL AX, 76(SP)
+	MOVL 352(SP), AX
+	MOVL AX, 80(SP)
+	MOVL 356(SP), AX
+	MOVL AX, 84(SP)
+	MOVL 360(SP), AX
+	MOVL AX, 88(SP)
+	MOVL 364(SP), AX
+	MOVL AX, 92(SP)
+	MOVL 368(SP), AX
+	MOVL AX, 96(SP)
+	MOVL 372(SP), AX
+	MOVL AX, 100(SP)
+	MOVL 376(SP), AX
+	MOVL AX, 104(SP)
+	MOVL 380(SP), AX
+	MOVL AX, 108(SP)
+	MOVL 384(SP), AX
+	MOVL AX, 112(SP)
+	MOVL 388(SP), AX
+	MOVL AX, 116(SP)
+	MOVL 392(SP), AX
+	MOVL AX, 120(SP)
+	MOVL 396(SP), AX
+	MOVL AX, 124(SP)
+	MOVL 400(SP), AX
+	MOVL AX, 128(SP)
+	MOVL 404(SP), AX
+	MOVL AX, 132(SP)
+	MOVL 408(SP), AX
+	MOVL AX, 136(SP)
+	MOVL 412(SP), AX
+	MOVL AX, 140(SP)
+	MOVL 416(SP), AX
+	MOVL AX, 144(SP)
+	MOVL 420(SP), AX
+	MOVL AX, 148(SP)
+	MOVL 424(SP), AX
+	MOVL AX, 152(SP)
+	MOVL 428(SP), AX
+	MOVL AX, 156(SP)
+	MOVL 432(SP), AX
+	MOVL AX, 160(SP)
+	MOVL 436(SP), AX
+	MOVL AX, 164(SP)
+	MOVL 440(SP), AX
+	MOVL AX, 168(SP)
+	MOVL 444(SP), AX
+	MOVL AX, 172(SP)
+	MOVL 448(SP), AX
+	MOVL AX, 176(SP)
+	MOVL 452(SP), AX
+	MOVL AX, 180(SP)
+	MOVL 456(SP), AX
+	MOVL AX, 184(SP)
+	MOVL 460(SP), AX
+	MOVL AX, 188(SP)
+	MOVL 464(SP), AX
+	MOVL AX, 192(SP)
+	MOVL 468(SP), AX
+	MOVL AX, 196(SP)
+	MOVL 472(SP), AX
+	MOVL AX, 200(SP)
+	MOVL 476(SP), AX
+	MOVL AX, 204(SP)
+	MOVL 480(SP), AX
+	MOVL AX, 208(SP)
+	MOVL 484(SP), AX
+	MOVL AX, 212(SP)
+	MOVL 488(SP), AX
+	MOVL AX, 216(SP)
+	MOVL 492(SP), AX
+	MOVL AX, 220(SP)
+	MOVL 496(SP), AX
+	MOVL AX, 224(SP)
+	MOVL 500(SP), AX
+	MOVL AX, 228(SP)
+	MOVL 504(SP), AX
+	MOVL AX, 232(SP)
+	MOVL 508(SP), AX
+	MOVL AX, 236(SP)
+	MOVL 512(SP), AX
+	MOVL AX, 240(SP)
+	MOVL 516(SP), AX
+	MOVL AX, 244(SP)
+	MOVL 520(SP), AX
+	MOVL AX, 248(SP)
+	MOVL 524(SP), AX
+	MOVL AX, 252(SP)
+	MOVL 528(SP), AX
+	MOVL AX, 256(SP)
+	MOVL 532(SP), AX
+	MOVL AX, 260(SP)
+	MOVL 536(SP), AX
+	MOVL AX, 264(SP)
+	MOVL 540(SP), AX
+	MOVL AX, 268(SP)
+	MOVL 544(SP), AX
+	MOVL AX, 272(SP)
+	MOVL 548(SP), AX
+	MOVL AX, 276(SP)
+	MOVL 552(SP), AX
+	MOVL AX, 280(SP)
+	MOVL 556(SP), AX
+	MOVL AX, 284(SP)
+	MOVL 560(SP), AX
+	MOVL AX, 288(SP)
+
+	// Set up callbackArgs struct at 24(SP)
+	// struct callbackArgs {
+	//     index  uintptr  // offset 0
+	//     args   *byte    // offset 4
+	//     result uintptr  // offset 8
+	// }
+	MOVL 16(SP), AX // callback index
+	MOVL AX, 24(SP) // callbackArgs.index
+	LEAL 36(SP), AX // pointer to copied arguments
+	MOVL AX, 28(SP) // callbackArgs.args
+	MOVL $0, 32(SP) // callbackArgs.result = 0
+
+	// Call crosscall2(fn, frame, 0, ctxt)
+	// crosscall2 expects arguments on stack:
+	//   0(SP) = fn
+	//   4(SP) = frame (pointer to callbackArgs)
+	//   8(SP) = ignored (was n)
+	//   12(SP) = ctxt
+	SUBL $16, SP
+
+	MOVL ·callbackWrap_call(SB), AX
+	MOVL (AX), AX                   // fn = *callbackWrap_call
+	MOVL AX, 0(SP)                  // fn
+	LEAL (24+16)(SP), AX            // &callbackArgs (adjusted for SUB $16)
+	MOVL AX, 4(SP)                  // frame
+	MOVL $0, 8(SP)                  // 0
+	MOVL $0, 12(SP)                 // ctxt
+
+	CALL crosscall2(SB)
+
+	ADDL $16, SP
+
+	// Get result from callbackArgs.result
+	MOVL 32(SP), AX
+
+	// Restore callee-saved registers
+	MOVL 0(SP), BX
+	MOVL 4(SP), SI
+	MOVL 8(SP), DI
+	MOVL 12(SP), BP
+
+	// Restore return address and clean up
+	MOVL 20(SP), CX // get return address
+	ADDL $304, SP   // remove our frame
+	MOVL CX, 0(SP)  // put return address back
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_unix_arm.s b/vendor/github.com/ebitengine/purego/sys_unix_arm.s
new file mode 100644
index 000000000..a97e9437d
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_unix_arm.s
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
+	NO_LOCAL_POINTERS
+
+	// Allocate stack frame: 48 + 16 + 64 + 16 = 144 bytes
+	SUB $144, R13
+
+	// Save callee-saved registers at SP+0
+	MOVW R4, 0(R13)
+	MOVW R5, 4(R13)
+	MOVW R6, 8(R13)
+	MOVW R7, 12(R13)
+	MOVW R8, 16(R13)
+	MOVW R9, 20(R13)
+	MOVW g, 24(R13)
+	MOVW R11, 28(R13)
+	MOVW R14, 32(R13)
+
+	// Save callback index (passed in R12) at SP+36
+	MOVW R12, 36(R13)
+
+	// Save integer arguments R0-R3 at SP+128 (frame[16..19])
+	MOVW R0, 128(R13)
+	MOVW R1, 132(R13)
+	MOVW R2, 136(R13)
+	MOVW R3, 140(R13)
+
+	// Save floating point registers F0-F7 at SP+64 (frame[0..15])
+	// Note: We always save these since we target hard-float ABI.
+	MOVD F0, 64(R13)
+	MOVD F1, 72(R13)
+	MOVD F2, 80(R13)
+	MOVD F3, 88(R13)
+	MOVD F4, 96(R13)
+	MOVD F5, 104(R13)
+	MOVD F6, 112(R13)
+	MOVD F7, 120(R13)
+
+	// Set up callbackArgs at SP+48
+	MOVW 36(R13), R4
+	MOVW R4, 48(R13)
+	ADD  $64, R13, R4
+	MOVW R4, 52(R13)
+	MOVW $0, R4
+	MOVW R4, 56(R13)
+
+	// Call crosscall2(fn, frame, 0, ctxt)
+	MOVW ·callbackWrap_call(SB), R0
+	MOVW (R0), R0
+	ADD  $48, R13, R1
+	MOVW $0, R2
+	MOVW $0, R3
+
+	BL crosscall2(SB)
+
+	// Get result
+	MOVW 56(R13), R0
+
+	// Restore float registers
+	MOVD 64(R13), F0
+	MOVD 72(R13), F1
+	MOVD 80(R13), F2
+	MOVD 88(R13), F3
+	MOVD 96(R13), F4
+	MOVD 104(R13), F5
+	MOVD 112(R13), F6
+	MOVD 120(R13), F7
+
+	// Restore callee-saved registers
+	MOVW 0(R13), R4
+	MOVW 4(R13), R5
+	MOVW 8(R13), R6
+	MOVW 12(R13), R7
+	MOVW 16(R13), R8
+	MOVW 20(R13), R9
+	MOVW 24(R13), g
+	MOVW 28(R13), R11
+	MOVW 32(R13), R14
+
+	ADD $144, R13
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_unix_arm64.s b/vendor/github.com/ebitengine/purego/sys_unix_arm64.s
new file mode 100644
index 000000000..cea803ef9
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_unix_arm64.s
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2023 The Ebitengine Authors
+
+//go:build darwin || freebsd || linux || netbsd
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+#include "abi_arm64.h"
+
+TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
+	NO_LOCAL_POINTERS
+
+	// On entry, the trampoline in zcallback_darwin_arm64.s left
+	// the callback index in R12 (which is volatile in the C ABI).
+
+	// Save callback register arguments R0-R7 and F0-F7.
+	// We do this at the top of the frame so they're contiguous with stack arguments.
+	SUB   $(16*8), RSP, R14
+	FSTPD (F0, F1), (0*8)(R14)
+	FSTPD (F2, F3), (2*8)(R14)
+	FSTPD (F4, F5), (4*8)(R14)
+	FSTPD (F6, F7), (6*8)(R14)
+	STP   (R0, R1), (8*8)(R14)
+	STP   (R2, R3), (10*8)(R14)
+	STP   (R4, R5), (12*8)(R14)
+	STP   (R6, R7), (14*8)(R14)
+
+	// Adjust SP by frame size.
+	SUB $(26*8), RSP
+
+	// It is important to save R27 because the go assembler
+	// uses it for move instructions for a variable.
+	// This line:
+	// MOVD ·callbackWrap_call(SB), R0
+	// Creates the instructions:
+	// ADRP 14335(PC), R27
+	// MOVD 388(27), R0
+	// R27 is a callee saved register so we are responsible
+	// for ensuring its value doesn't change. So save it and
+	// restore it at the end of this function.
+	// R30 is the link register. crosscall2 doesn't save it
+	// so it's saved here.
+	STP (R27, R30), 0(RSP)
+
+	// Create a struct callbackArgs on our stack.
+	MOVD $(callbackArgs__size)(RSP), R13
+	MOVD R12, callbackArgs_index(R13)    // callback index
+	MOVD R14, callbackArgs_args(R13)     // address of args vector
+	MOVD ZR, callbackArgs_result(R13)    // result
+
+	// Move parameters into registers
+	// Get the ABIInternal function pointer
+	// without <ABIInternal> by using a closure.
+	MOVD ·callbackWrap_call(SB), R0
+	MOVD (R0), R0                   // fn unsafe.Pointer
+	MOVD R13, R1                    // frame (&callbackArgs{...})
+	MOVD $0, R3                     // ctxt uintptr
+
+	BL crosscall2(SB)
+
+	// Get callback result.
+	MOVD $(callbackArgs__size)(RSP), R13
+	MOVD callbackArgs_result(R13), R0
+
+	// Restore LR and R27
+	LDP 0(RSP), (R27, R30)
+	ADD $(26*8), RSP
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_unix_loong64.s b/vendor/github.com/ebitengine/purego/sys_unix_loong64.s
new file mode 100644
index 000000000..cd00f9c1a
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_unix_loong64.s
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+#include "abi_loong64.h"
+
+TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
+	NO_LOCAL_POINTERS
+
+	SUBV $(16*8), R3, R14
+	MOVD F0, 0(R14)
+	MOVD F1, 8(R14)
+	MOVD F2, 16(R14)
+	MOVD F3, 24(R14)
+	MOVD F4, 32(R14)
+	MOVD F5, 40(R14)
+	MOVD F6, 48(R14)
+	MOVD F7, 56(R14)
+	MOVV R4, 64(R14)
+	MOVV R5, 72(R14)
+	MOVV R6, 80(R14)
+	MOVV R7, 88(R14)
+	MOVV R8, 96(R14)
+	MOVV R9, 104(R14)
+	MOVV R10, 112(R14)
+	MOVV R11, 120(R14)
+
+	// Adjust SP by frame size.
+	SUBV $(22*8), R3
+
+	// It is important to save R30 because the go assembler
+	// uses it for move instructions for a variable.
+	// This line:
+	// MOVV ·callbackWrap_call(SB), R4
+	// Creates the instructions:
+	// PCALAU12I	off1(PC), R30
+	// MOVV		off2(R30), R4
+	// R30 is a callee saved register so we are responsible
+	// for ensuring its value doesn't change. So save it and
+	// restore it at the end of this function.
+	// R1 is the link register. crosscall2 doesn't save it
+	// so it's saved here.
+	MOVV R1, 0(R3)
+	MOVV R30, 8(R3)
+
+	// Create a struct callbackArgs on our stack.
+	MOVV $(callbackArgs__size)(R3), R13
+	MOVV R12, callbackArgs_index(R13)   // callback index
+	MOVV R14, callbackArgs_args(R13)    // address of args vector
+	MOVV $0, callbackArgs_result(R13)   // result
+
+	// Move parameters into registers
+	// Get the ABIInternal function pointer
+	// without <ABIInternal> by using a closure.
+	MOVV ·callbackWrap_call(SB), R4
+	MOVV (R4), R4                   // fn unsafe.Pointer
+	MOVV R13, R5                    // frame (&callbackArgs{...})
+	MOVV $0, R7                     // ctxt uintptr
+
+	JAL crosscall2(SB)
+
+	// Get callback result.
+	MOVV $(callbackArgs__size)(R3), R13
+	MOVV callbackArgs_result(R13), R4
+
+	// Restore LR and R30
+	MOVV 0(R3), R1
+	MOVV 8(R3), R30
+	ADDV $(22*8), R3
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_unix_ppc64le.s b/vendor/github.com/ebitengine/purego/sys_unix_ppc64le.s
new file mode 100644
index 000000000..37f0d8d60
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_unix_ppc64le.s
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+// PPC64LE ELFv2 ABI callbackasm1 implementation
+// On entry, R11 contains the callback index (set by callbackasm)
+//
+// ELFv2 stack frame layout requirements:
+//   0(R1)   - back chain (pointer to caller's frame)
+//   8(R1)   - CR save area (optional)
+//  16(R1)   - LR save area (for callee to save caller's LR)
+//  24(R1)   - TOC save area (if needed)
+//  32(R1)+  - parameter save area / local variables
+//
+// Our frame (total 208 bytes, 16-byte aligned):
+//  32(R1)   - saved R31 (8 bytes)
+//  40(R1)   - callbackArgs struct (32 bytes: index, args, result, stackArgs)
+//  72(R1)   - args array: floats (64) + ints (64) = 128 bytes, ends at 200
+// Total with alignment: 208 bytes
+//
+// Stack args are NOT copied - we pass a pointer to their location in caller's frame.
+// This keeps frame size small enough for NOSPLIT with CGO_ENABLED=1.
+// Budget: 208 + 544 (crosscall2) + 56 (cgocallback) = 808 bytes
+// This is 8 bytes over the 800 limit, but cgocallback's children (load_g, save_g)
+// reuse the same stack space, so in practice it works.
+
+#define FRAME_SIZE     200
+#define SAVE_R31       32
+#define CB_ARGS        40
+#define ARGS_ARRAY     72
+#define FLOAT_OFF      0
+#define INT_OFF        64
+
+TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
+	NO_LOCAL_POINTERS
+
+	// On entry, the trampoline in zcallback_ppc64le.s left
+	// the callback index in R11.
+
+	// Per ELFv2 ABI, save LR to caller's frame BEFORE allocating our frame
+	MOVD LR, R0
+	MOVD R0, 16(R1)
+
+	// Allocate our stack frame (with back chain via MOVDU)
+	MOVDU R1, -FRAME_SIZE(R1)
+
+	// Save R31 - Go assembler uses it for MOVD from SB (like arm64's R27)
+	MOVD R31, SAVE_R31(R1)
+
+	// Save R11 (callback index) immediately - it's volatile and will be clobbered!
+	// Store it in the callbackArgs struct's index field now.
+	MOVD R11, (CB_ARGS+0)(R1)
+
+	// Save callback arguments to args array.
+	// Layout: floats first (F1-F8), then ints (R3-R10), then stack args
+	FMOVD F1, (ARGS_ARRAY+FLOAT_OFF+0*8)(R1)
+	FMOVD F2, (ARGS_ARRAY+FLOAT_OFF+1*8)(R1)
+	FMOVD F3, (ARGS_ARRAY+FLOAT_OFF+2*8)(R1)
+	FMOVD F4, (ARGS_ARRAY+FLOAT_OFF+3*8)(R1)
+	FMOVD F5, (ARGS_ARRAY+FLOAT_OFF+4*8)(R1)
+	FMOVD F6, (ARGS_ARRAY+FLOAT_OFF+5*8)(R1)
+	FMOVD F7, (ARGS_ARRAY+FLOAT_OFF+6*8)(R1)
+	FMOVD F8, (ARGS_ARRAY+FLOAT_OFF+7*8)(R1)
+
+	MOVD R3, (ARGS_ARRAY+INT_OFF+0*8)(R1)
+	MOVD R4, (ARGS_ARRAY+INT_OFF+1*8)(R1)
+	MOVD R5, (ARGS_ARRAY+INT_OFF+2*8)(R1)
+	MOVD R6, (ARGS_ARRAY+INT_OFF+3*8)(R1)
+	MOVD R7, (ARGS_ARRAY+INT_OFF+4*8)(R1)
+	MOVD R8, (ARGS_ARRAY+INT_OFF+5*8)(R1)
+	MOVD R9, (ARGS_ARRAY+INT_OFF+6*8)(R1)
+	MOVD R10, (ARGS_ARRAY+INT_OFF+7*8)(R1)
+
+	// Finish setting up callbackArgs struct at CB_ARGS(R1)
+	// struct { index uintptr; args unsafe.Pointer; result uintptr; stackArgs unsafe.Pointer }
+	// Note: index was already saved earlier (R11 is volatile)
+	ADD  $ARGS_ARRAY, R1, R12
+	MOVD R12, (CB_ARGS+8)(R1) // args = address of register args
+	MOVD $0, (CB_ARGS+16)(R1) // result = 0
+
+	// stackArgs points to caller's stack arguments at old_R1+96 = R1+FRAME_SIZE+96
+	ADD  $(FRAME_SIZE+96), R1, R12
+	MOVD R12, (CB_ARGS+24)(R1)     // stackArgs = &caller_stack_args
+
+	// Call crosscall2 with arguments in registers:
+	// R3 = fn (from callbackWrap_call closure)
+	// R4 = frame (address of callbackArgs)
+	// R6 = ctxt (0)
+	MOVD ·callbackWrap_call(SB), R3
+	MOVD (R3), R3                   // dereference closure to get fn
+	ADD  $CB_ARGS, R1, R4           // frame = &callbackArgs
+	MOVD $0, R6                     // ctxt = 0
+
+	BL crosscall2(SB)
+
+	// Get callback result into R3
+	MOVD (CB_ARGS+16)(R1), R3
+
+	// Restore R31
+	MOVD SAVE_R31(R1), R31
+
+	// Deallocate frame
+	ADD $FRAME_SIZE, R1
+
+	// Restore LR from caller's frame (per ELFv2, it was saved at 16(old_R1))
+	MOVD 16(R1), R0
+	MOVD R0, LR
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_unix_riscv64.s b/vendor/github.com/ebitengine/purego/sys_unix_riscv64.s
new file mode 100644
index 000000000..8341d5b08
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_unix_riscv64.s
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+TEXT callbackasm1(SB), NOFRAME, $0
+	NO_LOCAL_POINTERS
+
+	// On entry, the trampoline in zcallback_riscv64.s left
+	// the callback index in X7.
+
+	// Save callback register arguments X10-X17 and F10-F17.
+	// Stack args (if any) are at 0(SP), 8(SP), etc.
+	// We save register args at SP-128, making them contiguous with stack args.
+	ADD $-(16*8), SP, X6
+
+	// Save float arg regs fa0-fa7 (F10-F17)
+	MOVD F10, 0(X6)
+	MOVD F11, 8(X6)
+	MOVD F12, 16(X6)
+	MOVD F13, 24(X6)
+	MOVD F14, 32(X6)
+	MOVD F15, 40(X6)
+	MOVD F16, 48(X6)
+	MOVD F17, 56(X6)
+
+	// Save integer arg regs a0-a7 (X10-X17)
+	MOV X10, 64(X6)
+	MOV X11, 72(X6)
+	MOV X12, 80(X6)
+	MOV X13, 88(X6)
+	MOV X14, 96(X6)
+	MOV X15, 104(X6)
+	MOV X16, 112(X6)
+	MOV X17, 120(X6)
+
+	// Allocate space on stack for RA, saved regs, and callbackArgs.
+	// We need: 8 (RA) + 8 (X9 callee-saved) + 24 (callbackArgs) = 40, round to 176 (22*8)
+	// to match loong64 and ensure we don't overlap with saved register args.
+	// The saved regs end at SP-8 (original), so we need new SP below SP-128.
+	ADD $-(22*8), SP
+
+	// Save link register (RA/X1) and callee-saved register X9
+	// (X9 is used by the assembler for some instructions)
+	MOV X1, 0(SP)
+	MOV X9, 8(SP)
+
+	// Create a struct callbackArgs on our stack.
+	// callbackArgs struct: index(0), args(8), result(16)
+	// Place it at 16(SP) to avoid overlap
+	ADD $16, SP, X9
+	MOV X7, 0(X9)   // callback index
+	MOV X6, 8(X9)   // address of args vector
+	MOV X0, 16(X9)  // result = 0
+
+	// Call crosscall2 with arguments in registers
+	MOV ·callbackWrap_call(SB), X10 // Get the ABIInternal function pointer
+	MOV (X10), X10                  // without <ABIInternal> by using a closure.  X10 = fn
+	MOV X9, X11                     // X11 = frame (address of callbackArgs)
+	MOV X0, X13                     // X13 = ctxt = 0
+
+	CALL crosscall2(SB)
+
+	// Get callback result.
+	ADD $16, SP, X9
+	MOV 16(X9), X10
+
+	// Restore link register and callee-saved X9
+	MOV 8(SP), X9
+	MOV 0(SP), X1
+
+	// Restore stack pointer
+	ADD $(22*8), SP
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/sys_unix_s390x.s b/vendor/github.com/ebitengine/purego/sys_unix_s390x.s
new file mode 100644
index 000000000..9eed6d29c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/sys_unix_s390x.s
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux
+
+#include "textflag.h"
+#include "go_asm.h"
+#include "funcdata.h"
+
+// S390X ELF ABI callbackasm1 implementation
+// On entry, R0 contains the callback index (set by callbackasm)
+// NOTE: We use R0 instead of R11 because R11 is callee-saved on S390X.
+//
+// S390X stack frame layout:
+//   0(R15)   - back chain
+//  48(R15)   - register save area (R6-R15)
+// 160(R15)  - parameter area
+//
+// S390X uses R2-R6 for integer arguments (5 registers) and F0,F2,F4,F6 for floats (4 registers).
+//
+// Our frame layout (total 264 bytes, 8-byte aligned):
+//  0(R15)    - back chain
+// 48(R15)   - saved R6-R15 (done by STMG)
+// 160(R15)  - callbackArgs struct (32 bytes: index, args, result, stackArgs)
+// 192(R15)  - args array start
+//
+// Args array layout:
+// - floats F0,F2,F4,F6 (32 bytes)
+// - ints R2-R6 (40 bytes)
+// Total args array: 72 bytes, ends at 264
+//
+// Stack args in caller's frame start at old_R15+160
+
+#define FRAME_SIZE     264
+#define CB_ARGS        160
+#define ARGS_ARRAY     192
+#define FLOAT_OFF      0
+#define INT_OFF        32
+
+TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
+	NO_LOCAL_POINTERS
+
+	// On entry, the trampoline in zcallback_s390x.s left
+	// the callback index in R0 (NOT R11, since R11 is callee-saved).
+	// R6 contains the 5th integer argument.
+
+	// Save R6-R15 in caller's frame (per S390X ABI) BEFORE allocating our frame
+	// STMG stores R6's current value (the 5th arg) at 48(R15)
+	STMG R6, R15, 48(R15)
+
+	// Save current stack pointer (will be back chain)
+	MOVD R15, R1
+
+	// Allocate our stack frame
+	SUB  $FRAME_SIZE, R15
+	MOVD R1, 0(R15)       // back chain
+
+	// Save R0 (callback index) immediately - it's volatile
+	MOVD R0, (CB_ARGS+0)(R15)
+
+	// Save callback arguments to args array.
+	// Layout: floats first (F0,F2,F4,F6), then ints (R2-R6)
+	FMOVD F0, (ARGS_ARRAY+FLOAT_OFF+0*8)(R15)
+	FMOVD F2, (ARGS_ARRAY+FLOAT_OFF+1*8)(R15)
+	FMOVD F4, (ARGS_ARRAY+FLOAT_OFF+2*8)(R15)
+	FMOVD F6, (ARGS_ARRAY+FLOAT_OFF+3*8)(R15)
+
+	MOVD R2, (ARGS_ARRAY+INT_OFF+0*8)(R15)
+	MOVD R3, (ARGS_ARRAY+INT_OFF+1*8)(R15)
+	MOVD R4, (ARGS_ARRAY+INT_OFF+2*8)(R15)
+	MOVD R5, (ARGS_ARRAY+INT_OFF+3*8)(R15)
+
+	// R6 (5th int arg) was saved at 48(old_R15) by STMG
+	// old_R15 = current R15 + FRAME_SIZE, so R6 is at 48+FRAME_SIZE(R15) = 312(R15)
+	MOVD (48+FRAME_SIZE)(R15), R1
+	MOVD R1, (ARGS_ARRAY+INT_OFF+4*8)(R15)
+
+	// Finish setting up callbackArgs struct at CB_ARGS(R15)
+	// struct { index uintptr; args unsafe.Pointer; result uintptr; stackArgs unsafe.Pointer }
+	// Note: index was already saved earlier
+	ADD  $ARGS_ARRAY, R15, R1
+	MOVD R1, (CB_ARGS+8)(R15)  // args = address of register args
+	MOVD $0, (CB_ARGS+16)(R15) // result = 0
+
+	// stackArgs points to caller's stack arguments at old_R15+160 = R15+FRAME_SIZE+160
+	ADD  $(FRAME_SIZE+160), R15, R1
+	MOVD R1, (CB_ARGS+24)(R15)      // stackArgs = &caller_stack_args
+
+	// Call crosscall2 with arguments in registers:
+	// R2 = fn (from callbackWrap_call closure)
+	// R3 = frame (address of callbackArgs)
+	// R5 = ctxt (0)
+	MOVD ·callbackWrap_call(SB), R2
+	MOVD (R2), R2                   // dereference closure to get fn
+	ADD  $CB_ARGS, R15, R3          // frame = &callbackArgs
+	MOVD $0, R5                     // ctxt = 0
+
+	BL crosscall2(SB)
+
+	// Get callback result into R2
+	MOVD (CB_ARGS+16)(R15), R2
+
+	// Deallocate frame
+	ADD $FRAME_SIZE, R15
+
+	// Restore R6-R15 from caller's frame
+	LMG 48(R15), R6, R15
+
+	RET
diff --git a/vendor/github.com/ebitengine/purego/syscall.go b/vendor/github.com/ebitengine/purego/syscall.go
new file mode 100644
index 000000000..7b45383d3
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/syscall.go
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build !386 && !arm && (darwin || freebsd || linux || netbsd || windows)
+
+package purego
+
+// CDecl marks a function as being called using the __cdecl calling convention as defined in
+// the [MSDocs] when passed to NewCallback. It must be the first argument to the function.
+// This is only useful on 386 Windows, but it is safe to use on other platforms.
+//
+// [MSDocs]: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170
+type CDecl struct{}
+
+const (
+	maxArgs = 15
+)
+
+type syscall15Args struct {
+	fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr
+	f1, f2, f3, f4, f5, f6, f7, f8                                       uintptr
+	arm64_r8                                                             uintptr
+}
+
+func (s *syscall15Args) Set(fn uintptr, ints []uintptr, floats []uintptr, r8 uintptr) {
+	s.fn = fn
+	s.a1 = ints[0]
+	s.a2 = ints[1]
+	s.a3 = ints[2]
+	s.a4 = ints[3]
+	s.a5 = ints[4]
+	s.a6 = ints[5]
+	s.a7 = ints[6]
+	s.a8 = ints[7]
+	s.a9 = ints[8]
+	s.a10 = ints[9]
+	s.a11 = ints[10]
+	s.a12 = ints[11]
+	s.a13 = ints[12]
+	s.a14 = ints[13]
+	s.a15 = ints[14]
+	s.f1 = floats[0]
+	s.f2 = floats[1]
+	s.f3 = floats[2]
+	s.f4 = floats[3]
+	s.f5 = floats[4]
+	s.f6 = floats[5]
+	s.f7 = floats[6]
+	s.f8 = floats[7]
+	s.arm64_r8 = r8
+}
+
+// SyscallN takes fn, a C function pointer and a list of arguments as uintptr.
+// There is an internal maximum number of arguments that SyscallN can take. It panics
+// when the maximum is exceeded. It returns the result and the libc error code if there is one.
+//
+// In order to call this function properly make sure to follow all the rules specified in [unsafe.Pointer]
+// especially point 4.
+//
+// NOTE: SyscallN does not properly call functions that have both integer and float parameters.
+// See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607
+// for an explanation of why that is.
+//
+// On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the
+// stack.
+//
+// The pragma go:nosplit is not needed at this function declaration because it uses go:uintptrescapes
+// which forces all the objects that the uintptrs point to onto the heap where a stack split won't affect
+// their memory location.
+//
+//go:uintptrescapes
+func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
+	if fn == 0 {
+		panic("purego: fn is nil")
+	}
+	if len(args) > maxArgs {
+		panic("purego: too many arguments to SyscallN")
+	}
+	// add padding so there is no out-of-bounds slicing
+	var tmp [maxArgs]uintptr
+	copy(tmp[:], args)
+	return syscall_syscall15X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14])
+}
diff --git a/vendor/github.com/ebitengine/purego/syscall_32bit.go b/vendor/github.com/ebitengine/purego/syscall_32bit.go
new file mode 100644
index 000000000..f9f376303
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/syscall_32bit.go
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build (386 || arm) && (freebsd || linux || netbsd || windows)
+
+package purego
+
+// CDecl marks a function as being called using the __cdecl calling convention as defined in
+// the [MSDocs] when passed to NewCallback. It must be the first argument to the function.
+// This is only useful on 386 Windows, but it is safe to use on other platforms.
+//
+// [MSDocs]: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170
+type CDecl struct{}
+
+const (
+	maxArgs = 32
+)
+
+type syscall15Args struct {
+	fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15                uintptr
+	a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr
+	f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16               uintptr
+	arm64_r8                                                                            uintptr
+}
+
+func (s *syscall15Args) Set(fn uintptr, ints []uintptr, floats []uintptr, r8 uintptr) {
+	s.fn = fn
+	s.a1 = ints[0]
+	s.a2 = ints[1]
+	s.a3 = ints[2]
+	s.a4 = ints[3]
+	s.a5 = ints[4]
+	s.a6 = ints[5]
+	s.a7 = ints[6]
+	s.a8 = ints[7]
+	s.a9 = ints[8]
+	s.a10 = ints[9]
+	s.a11 = ints[10]
+	s.a12 = ints[11]
+	s.a13 = ints[12]
+	s.a14 = ints[13]
+	s.a15 = ints[14]
+	s.a16 = ints[15]
+	s.a17 = ints[16]
+	s.a18 = ints[17]
+	s.a19 = ints[18]
+	s.a20 = ints[19]
+	s.a21 = ints[20]
+	s.a22 = ints[21]
+	s.a23 = ints[22]
+	s.a24 = ints[23]
+	s.a25 = ints[24]
+	s.a26 = ints[25]
+	s.a27 = ints[26]
+	s.a28 = ints[27]
+	s.a29 = ints[28]
+	s.a30 = ints[29]
+	s.a31 = ints[30]
+	s.a32 = ints[31]
+	s.f1 = floats[0]
+	s.f2 = floats[1]
+	s.f3 = floats[2]
+	s.f4 = floats[3]
+	s.f5 = floats[4]
+	s.f6 = floats[5]
+	s.f7 = floats[6]
+	s.f8 = floats[7]
+	s.f9 = floats[8]
+	s.f10 = floats[9]
+	s.f11 = floats[10]
+	s.f12 = floats[11]
+	s.f13 = floats[12]
+	s.f14 = floats[13]
+	s.f15 = floats[14]
+	s.f16 = floats[15]
+	s.arm64_r8 = r8
+}
+
+// SyscallN takes fn, a C function pointer and a list of arguments as uintptr.
+// There is an internal maximum number of arguments that SyscallN can take. It panics
+// when the maximum is exceeded. It returns the result and the libc error code if there is one.
+//
+// In order to call this function properly make sure to follow all the rules specified in [unsafe.Pointer]
+// especially point 4.
+//
+// NOTE: SyscallN does not properly call functions that have both integer and float parameters.
+// See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607
+// for an explanation of why that is.
+//
+// On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the
+// stack.
+//
+// The pragma go:nosplit is not needed at this function declaration because it uses go:uintptrescapes
+// which forces all the objects that the uintptrs point to onto the heap where a stack split won't affect
+// their memory location.
+//
+//go:uintptrescapes
+func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
+	if fn == 0 {
+		panic("purego: fn is nil")
+	}
+	if len(args) > maxArgs {
+		panic("purego: too many arguments to SyscallN")
+	}
+	// add padding so there is no out-of-bounds slicing
+	var tmp [maxArgs]uintptr
+	copy(tmp[:], args)
+	return syscall_syscall15X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14])
+}
diff --git a/vendor/github.com/ebitengine/purego/syscall_cgo_linux.go b/vendor/github.com/ebitengine/purego/syscall_cgo_linux.go
new file mode 100644
index 000000000..179167f4b
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/syscall_cgo_linux.go
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+//go:build cgo && !(386 || amd64 || arm || arm64 || loong64 || ppc64le || riscv64 || s390x)
+
+package purego
+
+import (
+	"github.com/ebitengine/purego/internal/cgo"
+)
+
+var syscall15XABI0 = uintptr(cgo.Syscall15XABI0)
+
+//go:nosplit
+func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
+	return cgo.Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
+}
+
+func NewCallback(_ any) uintptr {
+	panic("purego: NewCallback on Linux is only supported on 386/amd64/arm64/arm/loong64/ppc64le/riscv64/s390x")
+}
diff --git a/vendor/github.com/ebitengine/purego/syscall_sysv.go b/vendor/github.com/ebitengine/purego/syscall_sysv.go
new file mode 100644
index 000000000..e35b32e71
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/syscall_sysv.go
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+// TODO: remove s390x cgo dependency once golang/go#77449 is resolved
+//go:build darwin || freebsd || (linux && (386 || amd64 || arm || arm64 || loong64 || ppc64le || riscv64 || (cgo && s390x))) || netbsd
+
+package purego
+
+import (
+	"reflect"
+	"runtime"
+	"sync"
+	"unsafe"
+)
+
+var syscall15XABI0 uintptr
+
+func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
+	args := thePool.Get().(*syscall15Args)
+	defer thePool.Put(args)
+
+	*args = syscall15Args{
+		fn: fn,
+		a1: a1, a2: a2, a3: a3, a4: a4, a5: a5, a6: a6, a7: a7, a8: a8,
+		a9: a9, a10: a10, a11: a11, a12: a12, a13: a13, a14: a14, a15: a15,
+		f1: a1, f2: a2, f3: a3, f4: a4, f5: a5, f6: a6, f7: a7, f8: a8,
+	}
+
+	runtime_cgocall(syscall15XABI0, unsafe.Pointer(args))
+	return args.a1, args.a2, args.a3
+}
+
+// NewCallback converts a Go function to a function pointer conforming to the C calling convention.
+// This is useful when interoperating with C code requiring callbacks. The argument is expected to be a
+// function with zero or one uintptr-sized result. The function must not have arguments with size larger than the size
+// of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory allocated
+// for these callbacks is never released. At least 2000 callbacks can always be created. Although this function
+// provides similar functionality to windows.NewCallback it is distinct.
+func NewCallback(fn any) uintptr {
+	ty := reflect.TypeOf(fn)
+	for i := 0; i < ty.NumIn(); i++ {
+		in := ty.In(i)
+		if !in.AssignableTo(reflect.TypeOf(CDecl{})) {
+			continue
+		}
+		if i != 0 {
+			panic("purego: CDecl must be the first argument")
+		}
+	}
+	return compileCallback(fn)
+}
+
+// maxCb is the maximum number of callbacks
+// only increase this if you have added more to the callbackasm function
+const maxCB = 2000
+
+var cbs struct {
+	lock  sync.Mutex
+	numFn int                  // the number of functions currently in cbs.funcs
+	funcs [maxCB]reflect.Value // the saved callbacks
+}
+
+func compileCallback(fn any) uintptr {
+	val := reflect.ValueOf(fn)
+	if val.Kind() != reflect.Func {
+		panic("purego: the type must be a function but was not")
+	}
+	if val.IsNil() {
+		panic("purego: function must not be nil")
+	}
+	ty := val.Type()
+	for i := 0; i < ty.NumIn(); i++ {
+		in := ty.In(i)
+		switch in.Kind() {
+		case reflect.Struct:
+			if i == 0 && in.AssignableTo(reflect.TypeOf(CDecl{})) {
+				continue
+			}
+			fallthrough
+		case reflect.Interface, reflect.Func, reflect.Slice,
+			reflect.Chan, reflect.Complex64, reflect.Complex128,
+			reflect.String, reflect.Map, reflect.Invalid:
+			panic("purego: unsupported argument type: " + in.Kind().String())
+		}
+	}
+output:
+	switch {
+	case ty.NumOut() == 1:
+		switch ty.Out(0).Kind() {
+		case reflect.Pointer, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
+			reflect.Bool, reflect.UnsafePointer:
+			break output
+		}
+		panic("purego: unsupported return type: " + ty.String())
+	case ty.NumOut() > 1:
+		panic("purego: callbacks can only have one return")
+	}
+	cbs.lock.Lock()
+	defer cbs.lock.Unlock()
+	if cbs.numFn >= maxCB {
+		panic("purego: the maximum number of callbacks has been reached")
+	}
+	cbs.funcs[cbs.numFn] = val
+	cbs.numFn++
+	return callbackasmAddr(cbs.numFn - 1)
+}
+
+const ptrSize = unsafe.Sizeof((*int)(nil))
+
+const callbackMaxFrame = 64 * ptrSize
+
+// callbackasm is implemented in zcallback_GOOS_GOARCH.s
+//
+//go:linkname __callbackasm callbackasm
+var __callbackasm byte
+var callbackasmABI0 = uintptr(unsafe.Pointer(&__callbackasm))
+
+// callbackWrap_call allows the calling of the ABIInternal wrapper
+// which is required for runtime.cgocallback without the
+// <ABIInternal> tag which is only allowed in the runtime.
+// This closure is used inside sys_darwin_GOARCH.s
+var callbackWrap_call = callbackWrap
+
+// callbackWrap is called by assembly code which determines which Go function to call.
+// This function takes the arguments and passes them to the Go function and returns the result.
+func callbackWrap(a *callbackArgs) {
+	cbs.lock.Lock()
+	fn := cbs.funcs[a.index]
+	cbs.lock.Unlock()
+	fnType := fn.Type()
+	args := make([]reflect.Value, fnType.NumIn())
+	frame := (*[callbackMaxFrame]uintptr)(a.args)
+	// stackFrame points to stack-passed arguments. On most architectures this is
+	// contiguous with frame (after register args), but on ppc64le it's separate.
+	var stackFrame *[callbackMaxFrame]uintptr
+	if sf := a.stackFrame(); sf != nil {
+		// Only ppc64le uses separate stackArgs pointer due to NOSPLIT constraints
+		stackFrame = (*[callbackMaxFrame]uintptr)(sf)
+	}
+	// floatsN and intsN track the number of register slots used, not argument count.
+	// This distinction matters on ARM32 where float64 uses 2 slots (32-bit registers).
+	var floatsN int
+	var intsN int
+	// stackSlot points to the index into frame (or stackFrame) of the current stack element.
+	// When stackFrame is nil, stack begins after float and integer registers in frame.
+	// When stackFrame is not nil (ppc64le), stackSlot indexes into stackFrame starting at 0.
+	stackSlot := numOfIntegerRegisters() + numOfFloatRegisters()
+	if stackFrame != nil {
+		// ppc64le: stackArgs is a separate pointer, indices start at 0
+		stackSlot = 0
+	}
+	// stackByteOffset tracks the byte offset within the stack area for Darwin ARM64
+	// tight packing. On Darwin ARM64, C passes small types packed on the stack.
+	stackByteOffset := uintptr(0)
+	for i := range args {
+		// slots is the number of pointer-sized slots the argument takes
+		var slots int
+		inType := fnType.In(i)
+		switch inType.Kind() {
+		case reflect.Float32, reflect.Float64:
+			slots = int((fnType.In(i).Size() + ptrSize - 1) / ptrSize)
+			if floatsN+slots > numOfFloatRegisters() {
+				if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+					// Darwin ARM64: read from packed stack with proper alignment
+					args[i] = callbackArgFromStack(a.args, stackSlot, &stackByteOffset, inType)
+				} else if stackFrame != nil {
+					// ppc64le/s390x: stack args are in separate stackFrame
+					if runtime.GOARCH == "s390x" {
+						// s390x big-endian: sub-8-byte values are right-justified
+						args[i] = callbackArgFromSlotBigEndian(unsafe.Pointer(&stackFrame[stackSlot]), inType)
+					} else {
+						args[i] = reflect.NewAt(inType, unsafe.Pointer(&stackFrame[stackSlot])).Elem()
+					}
+					stackSlot += slots
+				} else {
+					args[i] = reflect.NewAt(inType, unsafe.Pointer(&frame[stackSlot])).Elem()
+					stackSlot += slots
+				}
+			} else {
+				if runtime.GOARCH == "s390x" {
+					// s390x big-endian: float32 is right-justified in 8-byte FPR slot
+					args[i] = callbackArgFromSlotBigEndian(unsafe.Pointer(&frame[floatsN]), inType)
+				} else {
+					args[i] = reflect.NewAt(inType, unsafe.Pointer(&frame[floatsN])).Elem()
+				}
+			}
+			floatsN += slots
+		case reflect.Struct:
+			// This is the CDecl field
+			args[i] = reflect.Zero(inType)
+		default:
+			slots = int((inType.Size() + ptrSize - 1) / ptrSize)
+			if intsN+slots > numOfIntegerRegisters() {
+				if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+					// Darwin ARM64: read from packed stack with proper alignment
+					args[i] = callbackArgFromStack(a.args, stackSlot, &stackByteOffset, inType)
+				} else if stackFrame != nil {
+					// ppc64le/s390x: stack args are in separate stackFrame
+					if runtime.GOARCH == "s390x" {
+						// s390x big-endian: sub-8-byte values are right-justified
+						args[i] = callbackArgFromSlotBigEndian(unsafe.Pointer(&stackFrame[stackSlot]), inType)
+					} else {
+						args[i] = reflect.NewAt(inType, unsafe.Pointer(&stackFrame[stackSlot])).Elem()
+					}
+					stackSlot += slots
+				} else {
+					args[i] = reflect.NewAt(inType, unsafe.Pointer(&frame[stackSlot])).Elem()
+					stackSlot += slots
+				}
+			} else {
+				// the integers begin after the floats in frame
+				pos := intsN + numOfFloatRegisters()
+				if runtime.GOARCH == "s390x" {
+					// s390x big-endian: sub-8-byte values are right-justified in GPR slot
+					args[i] = callbackArgFromSlotBigEndian(unsafe.Pointer(&frame[pos]), inType)
+				} else {
+					args[i] = reflect.NewAt(inType, unsafe.Pointer(&frame[pos])).Elem()
+				}
+			}
+			intsN += slots
+		}
+	}
+	ret := fn.Call(args)
+	if len(ret) > 0 {
+		switch k := ret[0].Kind(); k {
+		case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uintptr:
+			a.result = uintptr(ret[0].Uint())
+		case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
+			a.result = uintptr(ret[0].Int())
+		case reflect.Bool:
+			if ret[0].Bool() {
+				a.result = 1
+			} else {
+				a.result = 0
+			}
+		case reflect.Pointer:
+			a.result = ret[0].Pointer()
+		case reflect.UnsafePointer:
+			a.result = ret[0].Pointer()
+		default:
+			panic("purego: unsupported kind: " + k.String())
+		}
+	}
+}
+
+// callbackArgFromStack reads an argument from the tightly-packed stack area on Darwin ARM64.
+// The C ABI on Darwin ARM64 packs small types on the stack without padding to 8 bytes.
+// This function handles proper alignment and advances stackByteOffset accordingly.
+func callbackArgFromStack(argsBase unsafe.Pointer, stackSlot int, stackByteOffset *uintptr, inType reflect.Type) reflect.Value {
+	// Calculate base address of stack area (after float and int registers)
+	stackBase := unsafe.Add(argsBase, stackSlot*int(ptrSize))
+
+	// Get type's natural alignment
+	align := uintptr(inType.Align())
+	size := inType.Size()
+
+	// Align the offset
+	if *stackByteOffset%align != 0 {
+		*stackByteOffset = (*stackByteOffset + align - 1) &^ (align - 1)
+	}
+
+	// Read value at aligned offset
+	ptr := unsafe.Add(stackBase, *stackByteOffset)
+	*stackByteOffset += size
+
+	return reflect.NewAt(inType, ptr).Elem()
+}
+
+// callbackArgFromSlotBigEndian reads an argument from an 8-byte slot on big-endian architectures.
+// On s390x:
+// - Integer types are right-justified in GPRs: sub-8-byte values are at offset (8 - size)
+// - Float32 in FPRs is left-justified: stored in upper 32 bits, so at offset 0
+// - Float64 occupies the full 8-byte slot
+func callbackArgFromSlotBigEndian(slotPtr unsafe.Pointer, inType reflect.Type) reflect.Value {
+	size := inType.Size()
+	if size >= 8 {
+		// 8-byte values occupy the entire slot
+		return reflect.NewAt(inType, slotPtr).Elem()
+	}
+	// Float32 is left-justified in FPRs (upper 32 bits), so offset is 0
+	if inType.Kind() == reflect.Float32 {
+		return reflect.NewAt(inType, slotPtr).Elem()
+	}
+	// Integer types are right-justified: offset = 8 - size
+	offset := 8 - size
+	ptr := unsafe.Add(slotPtr, offset)
+	return reflect.NewAt(inType, ptr).Elem()
+}
+
+// callbackasmAddr returns address of runtime.callbackasm
+// function adjusted by i.
+// On x86 and amd64, runtime.callbackasm is a series of CALL instructions,
+// and we want callback to arrive at
+// correspondent call instruction instead of start of
+// runtime.callbackasm.
+// On ARM, runtime.callbackasm is a series of mov and branch instructions.
+// R12 is loaded with the callback index. Each entry is two instructions,
+// hence 8 bytes.
+func callbackasmAddr(i int) uintptr {
+	var entrySize int
+	switch runtime.GOARCH {
+	default:
+		panic("purego: unsupported architecture")
+	case "amd64":
+		// On amd64, each callback entry is just a CALL instruction (5 bytes)
+		entrySize = 5
+	case "386":
+		// On 386, each callback entry is MOVL $imm, CX (5 bytes) + JMP (5 bytes)
+		entrySize = 10
+	case "arm", "arm64", "loong64", "ppc64le", "riscv64":
+		// On ARM, ARM64, Loong64, PPC64LE and RISCV64, each entry is a MOV instruction
+		// followed by a branch instruction
+		entrySize = 8
+	case "s390x":
+		// On S390X, each entry is LGHI (4 bytes) + JG (6 bytes)
+		entrySize = 10
+	}
+	return callbackasmABI0 + uintptr(i*entrySize)
+}
diff --git a/vendor/github.com/ebitengine/purego/syscall_sysv_others.go b/vendor/github.com/ebitengine/purego/syscall_sysv_others.go
new file mode 100644
index 000000000..d4f6c7b7f
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/syscall_sysv_others.go
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build darwin || freebsd || (linux && (386 || amd64 || arm || arm64 || loong64 || riscv64)) || netbsd
+
+package purego
+
+import "unsafe"
+
+type callbackArgs struct {
+	index uintptr
+	// args points to the argument block.
+	//
+	// The structure of the arguments goes
+	// float registers followed by the
+	// integer registers followed by the stack.
+	//
+	// This variable is treated as a continuous
+	// block of memory containing all of the arguments
+	// for this callback.
+	args unsafe.Pointer
+	// Below are out-args from callbackWrap
+	result uintptr
+}
+
+func (c *callbackArgs) stackFrame() unsafe.Pointer {
+	return nil
+}
diff --git a/vendor/github.com/ebitengine/purego/syscall_sysv_stackargs.go b/vendor/github.com/ebitengine/purego/syscall_sysv_stackargs.go
new file mode 100644
index 000000000..87ed98111
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/syscall_sysv_stackargs.go
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
+
+//go:build linux && (ppc64le || s390x)
+
+package purego
+
+import "unsafe"
+
+type callbackArgs struct {
+	index uintptr
+	// args points to the argument block.
+	//
+	// The structure of the arguments goes
+	// float registers followed by the
+	// integer registers followed by the stack.
+	//
+	// This variable is treated as a continuous
+	// block of memory containing all of the arguments
+	// for this callback.
+	args unsafe.Pointer
+	// Below are out-args from callbackWrap
+	result uintptr
+	// stackArgs points to stack-passed arguments for architectures where
+	// they can't be made contiguous with register args (e.g., ppc64le).
+	// On other architectures, this is nil and stack args are read from
+	// the end of the args block.
+	stackArgs unsafe.Pointer
+}
+
+func (c *callbackArgs) stackFrame() unsafe.Pointer {
+	return c.stackArgs
+}
diff --git a/vendor/github.com/ebitengine/purego/syscall_windows.go b/vendor/github.com/ebitengine/purego/syscall_windows.go
new file mode 100644
index 000000000..5afd8d83c
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/syscall_windows.go
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
+
+package purego
+
+import (
+	"reflect"
+	"syscall"
+)
+
+var syscall15XABI0 uintptr
+
+func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
+	r1, r2, errno := syscall.Syscall15(fn, 15, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
+	return r1, r2, uintptr(errno)
+}
+
+// NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention.
+// This is useful when interoperating with Windows code requiring callbacks. The argument is expected to be a
+// function with one uintptr-sized result. The function must not have arguments with size larger than the
+// size of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory
+// allocated for these callbacks is never released. Between NewCallback and NewCallbackCDecl, at least 1024
+// callbacks can always be created. Although this function is similiar to the darwin version it may act
+// differently.
+func NewCallback(fn any) uintptr {
+	isCDecl := false
+	ty := reflect.TypeOf(fn)
+	for i := 0; i < ty.NumIn(); i++ {
+		in := ty.In(i)
+		if !in.AssignableTo(reflect.TypeOf(CDecl{})) {
+			continue
+		}
+		if i != 0 {
+			panic("purego: CDecl must be the first argument")
+		}
+		isCDecl = true
+	}
+	if isCDecl {
+		return syscall.NewCallbackCDecl(fn)
+	}
+	return syscall.NewCallback(fn)
+}
+
+func loadSymbol(handle uintptr, name string) (uintptr, error) {
+	return syscall.GetProcAddress(syscall.Handle(handle), name)
+}
diff --git a/vendor/github.com/ebitengine/purego/zcallback_386.s b/vendor/github.com/ebitengine/purego/zcallback_386.s
new file mode 100644
index 000000000..bd2d9c85a
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/zcallback_386.s
@@ -0,0 +1,4014 @@
+// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+
+//go:build linux
+
+// External code calls into callbackasm at an offset corresponding
+// to the callback index. Callbackasm is a table of MOVL and JMP instructions.
+// The MOVL instruction loads CX with the callback index, and the
+// JMP instruction branches to callbackasm1.
+// callbackasm1 takes the callback index from CX and
+// indexes into an array that stores information about each callback.
+// It then calls the Go implementation for that callback.
+#include "textflag.h"
+
+TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
+	MOVL $0, CX
+	JMP  callbackasm1(SB)
+	MOVL $1, CX
+	JMP  callbackasm1(SB)
+	MOVL $2, CX
+	JMP  callbackasm1(SB)
+	MOVL $3, CX
+	JMP  callbackasm1(SB)
+	MOVL $4, CX
+	JMP  callbackasm1(SB)
+	MOVL $5, CX
+	JMP  callbackasm1(SB)
+	MOVL $6, CX
+	JMP  callbackasm1(SB)
+	MOVL $7, CX
+	JMP  callbackasm1(SB)
+	MOVL $8, CX
+	JMP  callbackasm1(SB)
+	MOVL $9, CX
+	JMP  callbackasm1(SB)
+	MOVL $10, CX
+	JMP  callbackasm1(SB)
+	MOVL $11, CX
+	JMP  callbackasm1(SB)
+	MOVL $12, CX
+	JMP  callbackasm1(SB)
+	MOVL $13, CX
+	JMP  callbackasm1(SB)
+	MOVL $14, CX
+	JMP  callbackasm1(SB)
+	MOVL $15, CX
+	JMP  callbackasm1(SB)
+	MOVL $16, CX
+	JMP  callbackasm1(SB)
+	MOVL $17, CX
+	JMP  callbackasm1(SB)
+	MOVL $18, CX
+	JMP  callbackasm1(SB)
+	MOVL $19, CX
+	JMP  callbackasm1(SB)
+	MOVL $20, CX
+	JMP  callbackasm1(SB)
+	MOVL $21, CX
+	JMP  callbackasm1(SB)
+	MOVL $22, CX
+	JMP  callbackasm1(SB)
+	MOVL $23, CX
+	JMP  callbackasm1(SB)
+	MOVL $24, CX
+	JMP  callbackasm1(SB)
+	MOVL $25, CX
+	JMP  callbackasm1(SB)
+	MOVL $26, CX
+	JMP  callbackasm1(SB)
+	MOVL $27, CX
+	JMP  callbackasm1(SB)
+	MOVL $28, CX
+	JMP  callbackasm1(SB)
+	MOVL $29, CX
+	JMP  callbackasm1(SB)
+	MOVL $30, CX
+	JMP  callbackasm1(SB)
+	MOVL $31, CX
+	JMP  callbackasm1(SB)
+	MOVL $32, CX
+	JMP  callbackasm1(SB)
+	MOVL $33, CX
+	JMP  callbackasm1(SB)
+	MOVL $34, CX
+	JMP  callbackasm1(SB)
+	MOVL $35, CX
+	JMP  callbackasm1(SB)
+	MOVL $36, CX
+	JMP  callbackasm1(SB)
+	MOVL $37, CX
+	JMP  callbackasm1(SB)
+	MOVL $38, CX
+	JMP  callbackasm1(SB)
+	MOVL $39, CX
+	JMP  callbackasm1(SB)
+	MOVL $40, CX
+	JMP  callbackasm1(SB)
+	MOVL $41, CX
+	JMP  callbackasm1(SB)
+	MOVL $42, CX
+	JMP  callbackasm1(SB)
+	MOVL $43, CX
+	JMP  callbackasm1(SB)
+	MOVL $44, CX
+	JMP  callbackasm1(SB)
+	MOVL $45, CX
+	JMP  callbackasm1(SB)
+	MOVL $46, CX
+	JMP  callbackasm1(SB)
+	MOVL $47, CX
+	JMP  callbackasm1(SB)
+	MOVL $48, CX
+	JMP  callbackasm1(SB)
+	MOVL $49, CX
+	JMP  callbackasm1(SB)
+	MOVL $50, CX
+	JMP  callbackasm1(SB)
+	MOVL $51, CX
+	JMP  callbackasm1(SB)
+	MOVL $52, CX
+	JMP  callbackasm1(SB)
+	MOVL $53, CX
+	JMP  callbackasm1(SB)
+	MOVL $54, CX
+	JMP  callbackasm1(SB)
+	MOVL $55, CX
+	JMP  callbackasm1(SB)
+	MOVL $56, CX
+	JMP  callbackasm1(SB)
+	MOVL $57, CX
+	JMP  callbackasm1(SB)
+	MOVL $58, CX
+	JMP  callbackasm1(SB)
+	MOVL $59, CX
+	JMP  callbackasm1(SB)
+	MOVL $60, CX
+	JMP  callbackasm1(SB)
+	MOVL $61, CX
+	JMP  callbackasm1(SB)
+	MOVL $62, CX
+	JMP  callbackasm1(SB)
+	MOVL $63, CX
+	JMP  callbackasm1(SB)
+	MOVL $64, CX
+	JMP  callbackasm1(SB)
+	MOVL $65, CX
+	JMP  callbackasm1(SB)
+	MOVL $66, CX
+	JMP  callbackasm1(SB)
+	MOVL $67, CX
+	JMP  callbackasm1(SB)
+	MOVL $68, CX
+	JMP  callbackasm1(SB)
+	MOVL $69, CX
+	JMP  callbackasm1(SB)
+	MOVL $70, CX
+	JMP  callbackasm1(SB)
+	MOVL $71, CX
+	JMP  callbackasm1(SB)
+	MOVL $72, CX
+	JMP  callbackasm1(SB)
+	MOVL $73, CX
+	JMP  callbackasm1(SB)
+	MOVL $74, CX
+	JMP  callbackasm1(SB)
+	MOVL $75, CX
+	JMP  callbackasm1(SB)
+	MOVL $76, CX
+	JMP  callbackasm1(SB)
+	MOVL $77, CX
+	JMP  callbackasm1(SB)
+	MOVL $78, CX
+	JMP  callbackasm1(SB)
+	MOVL $79, CX
+	JMP  callbackasm1(SB)
+	MOVL $80, CX
+	JMP  callbackasm1(SB)
+	MOVL $81, CX
+	JMP  callbackasm1(SB)
+	MOVL $82, CX
+	JMP  callbackasm1(SB)
+	MOVL $83, CX
+	JMP  callbackasm1(SB)
+	MOVL $84, CX
+	JMP  callbackasm1(SB)
+	MOVL $85, CX
+	JMP  callbackasm1(SB)
+	MOVL $86, CX
+	JMP  callbackasm1(SB)
+	MOVL $87, CX
+	JMP  callbackasm1(SB)
+	MOVL $88, CX
+	JMP  callbackasm1(SB)
+	MOVL $89, CX
+	JMP  callbackasm1(SB)
+	MOVL $90, CX
+	JMP  callbackasm1(SB)
+	MOVL $91, CX
+	JMP  callbackasm1(SB)
+	MOVL $92, CX
+	JMP  callbackasm1(SB)
+	MOVL $93, CX
+	JMP  callbackasm1(SB)
+	MOVL $94, CX
+	JMP  callbackasm1(SB)
+	MOVL $95, CX
+	JMP  callbackasm1(SB)
+	MOVL $96, CX
+	JMP  callbackasm1(SB)
+	MOVL $97, CX
+	JMP  callbackasm1(SB)
+	MOVL $98, CX
+	JMP  callbackasm1(SB)
+	MOVL $99, CX
+	JMP  callbackasm1(SB)
+	MOVL $100, CX
+	JMP  callbackasm1(SB)
+	MOVL $101, CX
+	JMP  callbackasm1(SB)
+	MOVL $102, CX
+	JMP  callbackasm1(SB)
+	MOVL $103, CX
+	JMP  callbackasm1(SB)
+	MOVL $104, CX
+	JMP  callbackasm1(SB)
+	MOVL $105, CX
+	JMP  callbackasm1(SB)
+	MOVL $106, CX
+	JMP  callbackasm1(SB)
+	MOVL $107, CX
+	JMP  callbackasm1(SB)
+	MOVL $108, CX
+	JMP  callbackasm1(SB)
+	MOVL $109, CX
+	JMP  callbackasm1(SB)
+	MOVL $110, CX
+	JMP  callbackasm1(SB)
+	MOVL $111, CX
+	JMP  callbackasm1(SB)
+	MOVL $112, CX
+	JMP  callbackasm1(SB)
+	MOVL $113, CX
+	JMP  callbackasm1(SB)
+	MOVL $114, CX
+	JMP  callbackasm1(SB)
+	MOVL $115, CX
+	JMP  callbackasm1(SB)
+	MOVL $116, CX
+	JMP  callbackasm1(SB)
+	MOVL $117, CX
+	JMP  callbackasm1(SB)
+	MOVL $118, CX
+	JMP  callbackasm1(SB)
+	MOVL $119, CX
+	JMP  callbackasm1(SB)
+	MOVL $120, CX
+	JMP  callbackasm1(SB)
+	MOVL $121, CX
+	JMP  callbackasm1(SB)
+	MOVL $122, CX
+	JMP  callbackasm1(SB)
+	MOVL $123, CX
+	JMP  callbackasm1(SB)
+	MOVL $124, CX
+	JMP  callbackasm1(SB)
+	MOVL $125, CX
+	JMP  callbackasm1(SB)
+	MOVL $126, CX
+	JMP  callbackasm1(SB)
+	MOVL $127, CX
+	JMP  callbackasm1(SB)
+	MOVL $128, CX
+	JMP  callbackasm1(SB)
+	MOVL $129, CX
+	JMP  callbackasm1(SB)
+	MOVL $130, CX
+	JMP  callbackasm1(SB)
+	MOVL $131, CX
+	JMP  callbackasm1(SB)
+	MOVL $132, CX
+	JMP  callbackasm1(SB)
+	MOVL $133, CX
+	JMP  callbackasm1(SB)
+	MOVL $134, CX
+	JMP  callbackasm1(SB)
+	MOVL $135, CX
+	JMP  callbackasm1(SB)
+	MOVL $136, CX
+	JMP  callbackasm1(SB)
+	MOVL $137, CX
+	JMP  callbackasm1(SB)
+	MOVL $138, CX
+	JMP  callbackasm1(SB)
+	MOVL $139, CX
+	JMP  callbackasm1(SB)
+	MOVL $140, CX
+	JMP  callbackasm1(SB)
+	MOVL $141, CX
+	JMP  callbackasm1(SB)
+	MOVL $142, CX
+	JMP  callbackasm1(SB)
+	MOVL $143, CX
+	JMP  callbackasm1(SB)
+	MOVL $144, CX
+	JMP  callbackasm1(SB)
+	MOVL $145, CX
+	JMP  callbackasm1(SB)
+	MOVL $146, CX
+	JMP  callbackasm1(SB)
+	MOVL $147, CX
+	JMP  callbackasm1(SB)
+	MOVL $148, CX
+	JMP  callbackasm1(SB)
+	MOVL $149, CX
+	JMP  callbackasm1(SB)
+	MOVL $150, CX
+	JMP  callbackasm1(SB)
+	MOVL $151, CX
+	JMP  callbackasm1(SB)
+	MOVL $152, CX
+	JMP  callbackasm1(SB)
+	MOVL $153, CX
+	JMP  callbackasm1(SB)
+	MOVL $154, CX
+	JMP  callbackasm1(SB)
+	MOVL $155, CX
+	JMP  callbackasm1(SB)
+	MOVL $156, CX
+	JMP  callbackasm1(SB)
+	MOVL $157, CX
+	JMP  callbackasm1(SB)
+	MOVL $158, CX
+	JMP  callbackasm1(SB)
+	MOVL $159, CX
+	JMP  callbackasm1(SB)
+	MOVL $160, CX
+	JMP  callbackasm1(SB)
+	MOVL $161, CX
+	JMP  callbackasm1(SB)
+	MOVL $162, CX
+	JMP  callbackasm1(SB)
+	MOVL $163, CX
+	JMP  callbackasm1(SB)
+	MOVL $164, CX
+	JMP  callbackasm1(SB)
+	MOVL $165, CX
+	JMP  callbackasm1(SB)
+	MOVL $166, CX
+	JMP  callbackasm1(SB)
+	MOVL $167, CX
+	JMP  callbackasm1(SB)
+	MOVL $168, CX
+	JMP  callbackasm1(SB)
+	MOVL $169, CX
+	JMP  callbackasm1(SB)
+	MOVL $170, CX
+	JMP  callbackasm1(SB)
+	MOVL $171, CX
+	JMP  callbackasm1(SB)
+	MOVL $172, CX
+	JMP  callbackasm1(SB)
+	MOVL $173, CX
+	JMP  callbackasm1(SB)
+	MOVL $174, CX
+	JMP  callbackasm1(SB)
+	MOVL $175, CX
+	JMP  callbackasm1(SB)
+	MOVL $176, CX
+	JMP  callbackasm1(SB)
+	MOVL $177, CX
+	JMP  callbackasm1(SB)
+	MOVL $178, CX
+	JMP  callbackasm1(SB)
+	MOVL $179, CX
+	JMP  callbackasm1(SB)
+	MOVL $180, CX
+	JMP  callbackasm1(SB)
+	MOVL $181, CX
+	JMP  callbackasm1(SB)
+	MOVL $182, CX
+	JMP  callbackasm1(SB)
+	MOVL $183, CX
+	JMP  callbackasm1(SB)
+	MOVL $184, CX
+	JMP  callbackasm1(SB)
+	MOVL $185, CX
+	JMP  callbackasm1(SB)
+	MOVL $186, CX
+	JMP  callbackasm1(SB)
+	MOVL $187, CX
+	JMP  callbackasm1(SB)
+	MOVL $188, CX
+	JMP  callbackasm1(SB)
+	MOVL $189, CX
+	JMP  callbackasm1(SB)
+	MOVL $190, CX
+	JMP  callbackasm1(SB)
+	MOVL $191, CX
+	JMP  callbackasm1(SB)
+	MOVL $192, CX
+	JMP  callbackasm1(SB)
+	MOVL $193, CX
+	JMP  callbackasm1(SB)
+	MOVL $194, CX
+	JMP  callbackasm1(SB)
+	MOVL $195, CX
+	JMP  callbackasm1(SB)
+	MOVL $196, CX
+	JMP  callbackasm1(SB)
+	MOVL $197, CX
+	JMP  callbackasm1(SB)
+	MOVL $198, CX
+	JMP  callbackasm1(SB)
+	MOVL $199, CX
+	JMP  callbackasm1(SB)
+	MOVL $200, CX
+	JMP  callbackasm1(SB)
+	MOVL $201, CX
+	JMP  callbackasm1(SB)
+	MOVL $202, CX
+	JMP  callbackasm1(SB)
+	MOVL $203, CX
+	JMP  callbackasm1(SB)
+	MOVL $204, CX
+	JMP  callbackasm1(SB)
+	MOVL $205, CX
+	JMP  callbackasm1(SB)
+	MOVL $206, CX
+	JMP  callbackasm1(SB)
+	MOVL $207, CX
+	JMP  callbackasm1(SB)
+	MOVL $208, CX
+	JMP  callbackasm1(SB)
+	MOVL $209, CX
+	JMP  callbackasm1(SB)
+	MOVL $210, CX
+	JMP  callbackasm1(SB)
+	MOVL $211, CX
+	JMP  callbackasm1(SB)
+	MOVL $212, CX
+	JMP  callbackasm1(SB)
+	MOVL $213, CX
+	JMP  callbackasm1(SB)
+	MOVL $214, CX
+	JMP  callbackasm1(SB)
+	MOVL $215, CX
+	JMP  callbackasm1(SB)
+	MOVL $216, CX
+	JMP  callbackasm1(SB)
+	MOVL $217, CX
+	JMP  callbackasm1(SB)
+	MOVL $218, CX
+	JMP  callbackasm1(SB)
+	MOVL $219, CX
+	JMP  callbackasm1(SB)
+	MOVL $220, CX
+	JMP  callbackasm1(SB)
+	MOVL $221, CX
+	JMP  callbackasm1(SB)
+	MOVL $222, CX
+	JMP  callbackasm1(SB)
+	MOVL $223, CX
+	JMP  callbackasm1(SB)
+	MOVL $224, CX
+	JMP  callbackasm1(SB)
+	MOVL $225, CX
+	JMP  callbackasm1(SB)
+	MOVL $226, CX
+	JMP  callbackasm1(SB)
+	MOVL $227, CX
+	JMP  callbackasm1(SB)
+	MOVL $228, CX
+	JMP  callbackasm1(SB)
+	MOVL $229, CX
+	JMP  callbackasm1(SB)
+	MOVL $230, CX
+	JMP  callbackasm1(SB)
+	MOVL $231, CX
+	JMP  callbackasm1(SB)
+	MOVL $232, CX
+	JMP  callbackasm1(SB)
+	MOVL $233, CX
+	JMP  callbackasm1(SB)
+	MOVL $234, CX
+	JMP  callbackasm1(SB)
+	MOVL $235, CX
+	JMP  callbackasm1(SB)
+	MOVL $236, CX
+	JMP  callbackasm1(SB)
+	MOVL $237, CX
+	JMP  callbackasm1(SB)
+	MOVL $238, CX
+	JMP  callbackasm1(SB)
+	MOVL $239, CX
+	JMP  callbackasm1(SB)
+	MOVL $240, CX
+	JMP  callbackasm1(SB)
+	MOVL $241, CX
+	JMP  callbackasm1(SB)
+	MOVL $242, CX
+	JMP  callbackasm1(SB)
+	MOVL $243, CX
+	JMP  callbackasm1(SB)
+	MOVL $244, CX
+	JMP  callbackasm1(SB)
+	MOVL $245, CX
+	JMP  callbackasm1(SB)
+	MOVL $246, CX
+	JMP  callbackasm1(SB)
+	MOVL $247, CX
+	JMP  callbackasm1(SB)
+	MOVL $248, CX
+	JMP  callbackasm1(SB)
+	MOVL $249, CX
+	JMP  callbackasm1(SB)
+	MOVL $250, CX
+	JMP  callbackasm1(SB)
+	MOVL $251, CX
+	JMP  callbackasm1(SB)
+	MOVL $252, CX
+	JMP  callbackasm1(SB)
+	MOVL $253, CX
+	JMP  callbackasm1(SB)
+	MOVL $254, CX
+	JMP  callbackasm1(SB)
+	MOVL $255, CX
+	JMP  callbackasm1(SB)
+	MOVL $256, CX
+	JMP  callbackasm1(SB)
+	MOVL $257, CX
+	JMP  callbackasm1(SB)
+	MOVL $258, CX
+	JMP  callbackasm1(SB)
+	MOVL $259, CX
+	JMP  callbackasm1(SB)
+	MOVL $260, CX
+	JMP  callbackasm1(SB)
+	MOVL $261, CX
+	JMP  callbackasm1(SB)
+	MOVL $262, CX
+	JMP  callbackasm1(SB)
+	MOVL $263, CX
+	JMP  callbackasm1(SB)
+	MOVL $264, CX
+	JMP  callbackasm1(SB)
+	MOVL $265, CX
+	JMP  callbackasm1(SB)
+	MOVL $266, CX
+	JMP  callbackasm1(SB)
+	MOVL $267, CX
+	JMP  callbackasm1(SB)
+	MOVL $268, CX
+	JMP  callbackasm1(SB)
+	MOVL $269, CX
+	JMP  callbackasm1(SB)
+	MOVL $270, CX
+	JMP  callbackasm1(SB)
+	MOVL $271, CX
+	JMP  callbackasm1(SB)
+	MOVL $272, CX
+	JMP  callbackasm1(SB)
+	MOVL $273, CX
+	JMP  callbackasm1(SB)
+	MOVL $274, CX
+	JMP  callbackasm1(SB)
+	MOVL $275, CX
+	JMP  callbackasm1(SB)
+	MOVL $276, CX
+	JMP  callbackasm1(SB)
+	MOVL $277, CX
+	JMP  callbackasm1(SB)
+	MOVL $278, CX
+	JMP  callbackasm1(SB)
+	MOVL $279, CX
+	JMP  callbackasm1(SB)
+	MOVL $280, CX
+	JMP  callbackasm1(SB)
+	MOVL $281, CX
+	JMP  callbackasm1(SB)
+	MOVL $282, CX
+	JMP  callbackasm1(SB)
+	MOVL $283, CX
+	JMP  callbackasm1(SB)
+	MOVL $284, CX
+	JMP  callbackasm1(SB)
+	MOVL $285, CX
+	JMP  callbackasm1(SB)
+	MOVL $286, CX
+	JMP  callbackasm1(SB)
+	MOVL $287, CX
+	JMP  callbackasm1(SB)
+	MOVL $288, CX
+	JMP  callbackasm1(SB)
+	MOVL $289, CX
+	JMP  callbackasm1(SB)
+	MOVL $290, CX
+	JMP  callbackasm1(SB)
+	MOVL $291, CX
+	JMP  callbackasm1(SB)
+	MOVL $292, CX
+	JMP  callbackasm1(SB)
+	MOVL $293, CX
+	JMP  callbackasm1(SB)
+	MOVL $294, CX
+	JMP  callbackasm1(SB)
+	MOVL $295, CX
+	JMP  callbackasm1(SB)
+	MOVL $296, CX
+	JMP  callbackasm1(SB)
+	MOVL $297, CX
+	JMP  callbackasm1(SB)
+	MOVL $298, CX
+	JMP  callbackasm1(SB)
+	MOVL $299, CX
+	JMP  callbackasm1(SB)
+	MOVL $300, CX
+	JMP  callbackasm1(SB)
+	MOVL $301, CX
+	JMP  callbackasm1(SB)
+	MOVL $302, CX
+	JMP  callbackasm1(SB)
+	MOVL $303, CX
+	JMP  callbackasm1(SB)
+	MOVL $304, CX
+	JMP  callbackasm1(SB)
+	MOVL $305, CX
+	JMP  callbackasm1(SB)
+	MOVL $306, CX
+	JMP  callbackasm1(SB)
+	MOVL $307, CX
+	JMP  callbackasm1(SB)
+	MOVL $308, CX
+	JMP  callbackasm1(SB)
+	MOVL $309, CX
+	JMP  callbackasm1(SB)
+	MOVL $310, CX
+	JMP  callbackasm1(SB)
+	MOVL $311, CX
+	JMP  callbackasm1(SB)
+	MOVL $312, CX
+	JMP  callbackasm1(SB)
+	MOVL $313, CX
+	JMP  callbackasm1(SB)
+	MOVL $314, CX
+	JMP  callbackasm1(SB)
+	MOVL $315, CX
+	JMP  callbackasm1(SB)
+	MOVL $316, CX
+	JMP  callbackasm1(SB)
+	MOVL $317, CX
+	JMP  callbackasm1(SB)
+	MOVL $318, CX
+	JMP  callbackasm1(SB)
+	MOVL $319, CX
+	JMP  callbackasm1(SB)
+	MOVL $320, CX
+	JMP  callbackasm1(SB)
+	MOVL $321, CX
+	JMP  callbackasm1(SB)
+	MOVL $322, CX
+	JMP  callbackasm1(SB)
+	MOVL $323, CX
+	JMP  callbackasm1(SB)
+	MOVL $324, CX
+	JMP  callbackasm1(SB)
+	MOVL $325, CX
+	JMP  callbackasm1(SB)
+	MOVL $326, CX
+	JMP  callbackasm1(SB)
+	MOVL $327, CX
+	JMP  callbackasm1(SB)
+	MOVL $328, CX
+	JMP  callbackasm1(SB)
+	MOVL $329, CX
+	JMP  callbackasm1(SB)
+	MOVL $330, CX
+	JMP  callbackasm1(SB)
+	MOVL $331, CX
+	JMP  callbackasm1(SB)
+	MOVL $332, CX
+	JMP  callbackasm1(SB)
+	MOVL $333, CX
+	JMP  callbackasm1(SB)
+	MOVL $334, CX
+	JMP  callbackasm1(SB)
+	MOVL $335, CX
+	JMP  callbackasm1(SB)
+	MOVL $336, CX
+	JMP  callbackasm1(SB)
+	MOVL $337, CX
+	JMP  callbackasm1(SB)
+	MOVL $338, CX
+	JMP  callbackasm1(SB)
+	MOVL $339, CX
+	JMP  callbackasm1(SB)
+	MOVL $340, CX
+	JMP  callbackasm1(SB)
+	MOVL $341, CX
+	JMP  callbackasm1(SB)
+	MOVL $342, CX
+	JMP  callbackasm1(SB)
+	MOVL $343, CX
+	JMP  callbackasm1(SB)
+	MOVL $344, CX
+	JMP  callbackasm1(SB)
+	MOVL $345, CX
+	JMP  callbackasm1(SB)
+	MOVL $346, CX
+	JMP  callbackasm1(SB)
+	MOVL $347, CX
+	JMP  callbackasm1(SB)
+	MOVL $348, CX
+	JMP  callbackasm1(SB)
+	MOVL $349, CX
+	JMP  callbackasm1(SB)
+	MOVL $350, CX
+	JMP  callbackasm1(SB)
+	MOVL $351, CX
+	JMP  callbackasm1(SB)
+	MOVL $352, CX
+	JMP  callbackasm1(SB)
+	MOVL $353, CX
+	JMP  callbackasm1(SB)
+	MOVL $354, CX
+	JMP  callbackasm1(SB)
+	MOVL $355, CX
+	JMP  callbackasm1(SB)
+	MOVL $356, CX
+	JMP  callbackasm1(SB)
+	MOVL $357, CX
+	JMP  callbackasm1(SB)
+	MOVL $358, CX
+	JMP  callbackasm1(SB)
+	MOVL $359, CX
+	JMP  callbackasm1(SB)
+	MOVL $360, CX
+	JMP  callbackasm1(SB)
+	MOVL $361, CX
+	JMP  callbackasm1(SB)
+	MOVL $362, CX
+	JMP  callbackasm1(SB)
+	MOVL $363, CX
+	JMP  callbackasm1(SB)
+	MOVL $364, CX
+	JMP  callbackasm1(SB)
+	MOVL $365, CX
+	JMP  callbackasm1(SB)
+	MOVL $366, CX
+	JMP  callbackasm1(SB)
+	MOVL $367, CX
+	JMP  callbackasm1(SB)
+	MOVL $368, CX
+	JMP  callbackasm1(SB)
+	MOVL $369, CX
+	JMP  callbackasm1(SB)
+	MOVL $370, CX
+	JMP  callbackasm1(SB)
+	MOVL $371, CX
+	JMP  callbackasm1(SB)
+	MOVL $372, CX
+	JMP  callbackasm1(SB)
+	MOVL $373, CX
+	JMP  callbackasm1(SB)
+	MOVL $374, CX
+	JMP  callbackasm1(SB)
+	MOVL $375, CX
+	JMP  callbackasm1(SB)
+	MOVL $376, CX
+	JMP  callbackasm1(SB)
+	MOVL $377, CX
+	JMP  callbackasm1(SB)
+	MOVL $378, CX
+	JMP  callbackasm1(SB)
+	MOVL $379, CX
+	JMP  callbackasm1(SB)
+	MOVL $380, CX
+	JMP  callbackasm1(SB)
+	MOVL $381, CX
+	JMP  callbackasm1(SB)
+	MOVL $382, CX
+	JMP  callbackasm1(SB)
+	MOVL $383, CX
+	JMP  callbackasm1(SB)
+	MOVL $384, CX
+	JMP  callbackasm1(SB)
+	MOVL $385, CX
+	JMP  callbackasm1(SB)
+	MOVL $386, CX
+	JMP  callbackasm1(SB)
+	MOVL $387, CX
+	JMP  callbackasm1(SB)
+	MOVL $388, CX
+	JMP  callbackasm1(SB)
+	MOVL $389, CX
+	JMP  callbackasm1(SB)
+	MOVL $390, CX
+	JMP  callbackasm1(SB)
+	MOVL $391, CX
+	JMP  callbackasm1(SB)
+	MOVL $392, CX
+	JMP  callbackasm1(SB)
+	MOVL $393, CX
+	JMP  callbackasm1(SB)
+	MOVL $394, CX
+	JMP  callbackasm1(SB)
+	MOVL $395, CX
+	JMP  callbackasm1(SB)
+	MOVL $396, CX
+	JMP  callbackasm1(SB)
+	MOVL $397, CX
+	JMP  callbackasm1(SB)
+	MOVL $398, CX
+	JMP  callbackasm1(SB)
+	MOVL $399, CX
+	JMP  callbackasm1(SB)
+	MOVL $400, CX
+	JMP  callbackasm1(SB)
+	MOVL $401, CX
+	JMP  callbackasm1(SB)
+	MOVL $402, CX
+	JMP  callbackasm1(SB)
+	MOVL $403, CX
+	JMP  callbackasm1(SB)
+	MOVL $404, CX
+	JMP  callbackasm1(SB)
+	MOVL $405, CX
+	JMP  callbackasm1(SB)
+	MOVL $406, CX
+	JMP  callbackasm1(SB)
+	MOVL $407, CX
+	JMP  callbackasm1(SB)
+	MOVL $408, CX
+	JMP  callbackasm1(SB)
+	MOVL $409, CX
+	JMP  callbackasm1(SB)
+	MOVL $410, CX
+	JMP  callbackasm1(SB)
+	MOVL $411, CX
+	JMP  callbackasm1(SB)
+	MOVL $412, CX
+	JMP  callbackasm1(SB)
+	MOVL $413, CX
+	JMP  callbackasm1(SB)
+	MOVL $414, CX
+	JMP  callbackasm1(SB)
+	MOVL $415, CX
+	JMP  callbackasm1(SB)
+	MOVL $416, CX
+	JMP  callbackasm1(SB)
+	MOVL $417, CX
+	JMP  callbackasm1(SB)
+	MOVL $418, CX
+	JMP  callbackasm1(SB)
+	MOVL $419, CX
+	JMP  callbackasm1(SB)
+	MOVL $420, CX
+	JMP  callbackasm1(SB)
+	MOVL $421, CX
+	JMP  callbackasm1(SB)
+	MOVL $422, CX
+	JMP  callbackasm1(SB)
+	MOVL $423, CX
+	JMP  callbackasm1(SB)
+	MOVL $424, CX
+	JMP  callbackasm1(SB)
+	MOVL $425, CX
+	JMP  callbackasm1(SB)
+	MOVL $426, CX
+	JMP  callbackasm1(SB)
+	MOVL $427, CX
+	JMP  callbackasm1(SB)
+	MOVL $428, CX
+	JMP  callbackasm1(SB)
+	MOVL $429, CX
+	JMP  callbackasm1(SB)
+	MOVL $430, CX
+	JMP  callbackasm1(SB)
+	MOVL $431, CX
+	JMP  callbackasm1(SB)
+	MOVL $432, CX
+	JMP  callbackasm1(SB)
+	MOVL $433, CX
+	JMP  callbackasm1(SB)
+	MOVL $434, CX
+	JMP  callbackasm1(SB)
+	MOVL $435, CX
+	JMP  callbackasm1(SB)
+	MOVL $436, CX
+	JMP  callbackasm1(SB)
+	MOVL $437, CX
+	JMP  callbackasm1(SB)
+	MOVL $438, CX
+	JMP  callbackasm1(SB)
+	MOVL $439, CX
+	JMP  callbackasm1(SB)
+	MOVL $440, CX
+	JMP  callbackasm1(SB)
+	MOVL $441, CX
+	JMP  callbackasm1(SB)
+	MOVL $442, CX
+	JMP  callbackasm1(SB)
+	MOVL $443, CX
+	JMP  callbackasm1(SB)
+	MOVL $444, CX
+	JMP  callbackasm1(SB)
+	MOVL $445, CX
+	JMP  callbackasm1(SB)
+	MOVL $446, CX
+	JMP  callbackasm1(SB)
+	MOVL $447, CX
+	JMP  callbackasm1(SB)
+	MOVL $448, CX
+	JMP  callbackasm1(SB)
+	MOVL $449, CX
+	JMP  callbackasm1(SB)
+	MOVL $450, CX
+	JMP  callbackasm1(SB)
+	MOVL $451, CX
+	JMP  callbackasm1(SB)
+	MOVL $452, CX
+	JMP  callbackasm1(SB)
+	MOVL $453, CX
+	JMP  callbackasm1(SB)
+	MOVL $454, CX
+	JMP  callbackasm1(SB)
+	MOVL $455, CX
+	JMP  callbackasm1(SB)
+	MOVL $456, CX
+	JMP  callbackasm1(SB)
+	MOVL $457, CX
+	JMP  callbackasm1(SB)
+	MOVL $458, CX
+	JMP  callbackasm1(SB)
+	MOVL $459, CX
+	JMP  callbackasm1(SB)
+	MOVL $460, CX
+	JMP  callbackasm1(SB)
+	MOVL $461, CX
+	JMP  callbackasm1(SB)
+	MOVL $462, CX
+	JMP  callbackasm1(SB)
+	MOVL $463, CX
+	JMP  callbackasm1(SB)
+	MOVL $464, CX
+	JMP  callbackasm1(SB)
+	MOVL $465, CX
+	JMP  callbackasm1(SB)
+	MOVL $466, CX
+	JMP  callbackasm1(SB)
+	MOVL $467, CX
+	JMP  callbackasm1(SB)
+	MOVL $468, CX
+	JMP  callbackasm1(SB)
+	MOVL $469, CX
+	JMP  callbackasm1(SB)
+	MOVL $470, CX
+	JMP  callbackasm1(SB)
+	MOVL $471, CX
+	JMP  callbackasm1(SB)
+	MOVL $472, CX
+	JMP  callbackasm1(SB)
+	MOVL $473, CX
+	JMP  callbackasm1(SB)
+	MOVL $474, CX
+	JMP  callbackasm1(SB)
+	MOVL $475, CX
+	JMP  callbackasm1(SB)
+	MOVL $476, CX
+	JMP  callbackasm1(SB)
+	MOVL $477, CX
+	JMP  callbackasm1(SB)
+	MOVL $478, CX
+	JMP  callbackasm1(SB)
+	MOVL $479, CX
+	JMP  callbackasm1(SB)
+	MOVL $480, CX
+	JMP  callbackasm1(SB)
+	MOVL $481, CX
+	JMP  callbackasm1(SB)
+	MOVL $482, CX
+	JMP  callbackasm1(SB)
+	MOVL $483, CX
+	JMP  callbackasm1(SB)
+	MOVL $484, CX
+	JMP  callbackasm1(SB)
+	MOVL $485, CX
+	JMP  callbackasm1(SB)
+	MOVL $486, CX
+	JMP  callbackasm1(SB)
+	MOVL $487, CX
+	JMP  callbackasm1(SB)
+	MOVL $488, CX
+	JMP  callbackasm1(SB)
+	MOVL $489, CX
+	JMP  callbackasm1(SB)
+	MOVL $490, CX
+	JMP  callbackasm1(SB)
+	MOVL $491, CX
+	JMP  callbackasm1(SB)
+	MOVL $492, CX
+	JMP  callbackasm1(SB)
+	MOVL $493, CX
+	JMP  callbackasm1(SB)
+	MOVL $494, CX
+	JMP  callbackasm1(SB)
+	MOVL $495, CX
+	JMP  callbackasm1(SB)
+	MOVL $496, CX
+	JMP  callbackasm1(SB)
+	MOVL $497, CX
+	JMP  callbackasm1(SB)
+	MOVL $498, CX
+	JMP  callbackasm1(SB)
+	MOVL $499, CX
+	JMP  callbackasm1(SB)
+	MOVL $500, CX
+	JMP  callbackasm1(SB)
+	MOVL $501, CX
+	JMP  callbackasm1(SB)
+	MOVL $502, CX
+	JMP  callbackasm1(SB)
+	MOVL $503, CX
+	JMP  callbackasm1(SB)
+	MOVL $504, CX
+	JMP  callbackasm1(SB)
+	MOVL $505, CX
+	JMP  callbackasm1(SB)
+	MOVL $506, CX
+	JMP  callbackasm1(SB)
+	MOVL $507, CX
+	JMP  callbackasm1(SB)
+	MOVL $508, CX
+	JMP  callbackasm1(SB)
+	MOVL $509, CX
+	JMP  callbackasm1(SB)
+	MOVL $510, CX
+	JMP  callbackasm1(SB)
+	MOVL $511, CX
+	JMP  callbackasm1(SB)
+	MOVL $512, CX
+	JMP  callbackasm1(SB)
+	MOVL $513, CX
+	JMP  callbackasm1(SB)
+	MOVL $514, CX
+	JMP  callbackasm1(SB)
+	MOVL $515, CX
+	JMP  callbackasm1(SB)
+	MOVL $516, CX
+	JMP  callbackasm1(SB)
+	MOVL $517, CX
+	JMP  callbackasm1(SB)
+	MOVL $518, CX
+	JMP  callbackasm1(SB)
+	MOVL $519, CX
+	JMP  callbackasm1(SB)
+	MOVL $520, CX
+	JMP  callbackasm1(SB)
+	MOVL $521, CX
+	JMP  callbackasm1(SB)
+	MOVL $522, CX
+	JMP  callbackasm1(SB)
+	MOVL $523, CX
+	JMP  callbackasm1(SB)
+	MOVL $524, CX
+	JMP  callbackasm1(SB)
+	MOVL $525, CX
+	JMP  callbackasm1(SB)
+	MOVL $526, CX
+	JMP  callbackasm1(SB)
+	MOVL $527, CX
+	JMP  callbackasm1(SB)
+	MOVL $528, CX
+	JMP  callbackasm1(SB)
+	MOVL $529, CX
+	JMP  callbackasm1(SB)
+	MOVL $530, CX
+	JMP  callbackasm1(SB)
+	MOVL $531, CX
+	JMP  callbackasm1(SB)
+	MOVL $532, CX
+	JMP  callbackasm1(SB)
+	MOVL $533, CX
+	JMP  callbackasm1(SB)
+	MOVL $534, CX
+	JMP  callbackasm1(SB)
+	MOVL $535, CX
+	JMP  callbackasm1(SB)
+	MOVL $536, CX
+	JMP  callbackasm1(SB)
+	MOVL $537, CX
+	JMP  callbackasm1(SB)
+	MOVL $538, CX
+	JMP  callbackasm1(SB)
+	MOVL $539, CX
+	JMP  callbackasm1(SB)
+	MOVL $540, CX
+	JMP  callbackasm1(SB)
+	MOVL $541, CX
+	JMP  callbackasm1(SB)
+	MOVL $542, CX
+	JMP  callbackasm1(SB)
+	MOVL $543, CX
+	JMP  callbackasm1(SB)
+	MOVL $544, CX
+	JMP  callbackasm1(SB)
+	MOVL $545, CX
+	JMP  callbackasm1(SB)
+	MOVL $546, CX
+	JMP  callbackasm1(SB)
+	MOVL $547, CX
+	JMP  callbackasm1(SB)
+	MOVL $548, CX
+	JMP  callbackasm1(SB)
+	MOVL $549, CX
+	JMP  callbackasm1(SB)
+	MOVL $550, CX
+	JMP  callbackasm1(SB)
+	MOVL $551, CX
+	JMP  callbackasm1(SB)
+	MOVL $552, CX
+	JMP  callbackasm1(SB)
+	MOVL $553, CX
+	JMP  callbackasm1(SB)
+	MOVL $554, CX
+	JMP  callbackasm1(SB)
+	MOVL $555, CX
+	JMP  callbackasm1(SB)
+	MOVL $556, CX
+	JMP  callbackasm1(SB)
+	MOVL $557, CX
+	JMP  callbackasm1(SB)
+	MOVL $558, CX
+	JMP  callbackasm1(SB)
+	MOVL $559, CX
+	JMP  callbackasm1(SB)
+	MOVL $560, CX
+	JMP  callbackasm1(SB)
+	MOVL $561, CX
+	JMP  callbackasm1(SB)
+	MOVL $562, CX
+	JMP  callbackasm1(SB)
+	MOVL $563, CX
+	JMP  callbackasm1(SB)
+	MOVL $564, CX
+	JMP  callbackasm1(SB)
+	MOVL $565, CX
+	JMP  callbackasm1(SB)
+	MOVL $566, CX
+	JMP  callbackasm1(SB)
+	MOVL $567, CX
+	JMP  callbackasm1(SB)
+	MOVL $568, CX
+	JMP  callbackasm1(SB)
+	MOVL $569, CX
+	JMP  callbackasm1(SB)
+	MOVL $570, CX
+	JMP  callbackasm1(SB)
+	MOVL $571, CX
+	JMP  callbackasm1(SB)
+	MOVL $572, CX
+	JMP  callbackasm1(SB)
+	MOVL $573, CX
+	JMP  callbackasm1(SB)
+	MOVL $574, CX
+	JMP  callbackasm1(SB)
+	MOVL $575, CX
+	JMP  callbackasm1(SB)
+	MOVL $576, CX
+	JMP  callbackasm1(SB)
+	MOVL $577, CX
+	JMP  callbackasm1(SB)
+	MOVL $578, CX
+	JMP  callbackasm1(SB)
+	MOVL $579, CX
+	JMP  callbackasm1(SB)
+	MOVL $580, CX
+	JMP  callbackasm1(SB)
+	MOVL $581, CX
+	JMP  callbackasm1(SB)
+	MOVL $582, CX
+	JMP  callbackasm1(SB)
+	MOVL $583, CX
+	JMP  callbackasm1(SB)
+	MOVL $584, CX
+	JMP  callbackasm1(SB)
+	MOVL $585, CX
+	JMP  callbackasm1(SB)
+	MOVL $586, CX
+	JMP  callbackasm1(SB)
+	MOVL $587, CX
+	JMP  callbackasm1(SB)
+	MOVL $588, CX
+	JMP  callbackasm1(SB)
+	MOVL $589, CX
+	JMP  callbackasm1(SB)
+	MOVL $590, CX
+	JMP  callbackasm1(SB)
+	MOVL $591, CX
+	JMP  callbackasm1(SB)
+	MOVL $592, CX
+	JMP  callbackasm1(SB)
+	MOVL $593, CX
+	JMP  callbackasm1(SB)
+	MOVL $594, CX
+	JMP  callbackasm1(SB)
+	MOVL $595, CX
+	JMP  callbackasm1(SB)
+	MOVL $596, CX
+	JMP  callbackasm1(SB)
+	MOVL $597, CX
+	JMP  callbackasm1(SB)
+	MOVL $598, CX
+	JMP  callbackasm1(SB)
+	MOVL $599, CX
+	JMP  callbackasm1(SB)
+	MOVL $600, CX
+	JMP  callbackasm1(SB)
+	MOVL $601, CX
+	JMP  callbackasm1(SB)
+	MOVL $602, CX
+	JMP  callbackasm1(SB)
+	MOVL $603, CX
+	JMP  callbackasm1(SB)
+	MOVL $604, CX
+	JMP  callbackasm1(SB)
+	MOVL $605, CX
+	JMP  callbackasm1(SB)
+	MOVL $606, CX
+	JMP  callbackasm1(SB)
+	MOVL $607, CX
+	JMP  callbackasm1(SB)
+	MOVL $608, CX
+	JMP  callbackasm1(SB)
+	MOVL $609, CX
+	JMP  callbackasm1(SB)
+	MOVL $610, CX
+	JMP  callbackasm1(SB)
+	MOVL $611, CX
+	JMP  callbackasm1(SB)
+	MOVL $612, CX
+	JMP  callbackasm1(SB)
+	MOVL $613, CX
+	JMP  callbackasm1(SB)
+	MOVL $614, CX
+	JMP  callbackasm1(SB)
+	MOVL $615, CX
+	JMP  callbackasm1(SB)
+	MOVL $616, CX
+	JMP  callbackasm1(SB)
+	MOVL $617, CX
+	JMP  callbackasm1(SB)
+	MOVL $618, CX
+	JMP  callbackasm1(SB)
+	MOVL $619, CX
+	JMP  callbackasm1(SB)
+	MOVL $620, CX
+	JMP  callbackasm1(SB)
+	MOVL $621, CX
+	JMP  callbackasm1(SB)
+	MOVL $622, CX
+	JMP  callbackasm1(SB)
+	MOVL $623, CX
+	JMP  callbackasm1(SB)
+	MOVL $624, CX
+	JMP  callbackasm1(SB)
+	MOVL $625, CX
+	JMP  callbackasm1(SB)
+	MOVL $626, CX
+	JMP  callbackasm1(SB)
+	MOVL $627, CX
+	JMP  callbackasm1(SB)
+	MOVL $628, CX
+	JMP  callbackasm1(SB)
+	MOVL $629, CX
+	JMP  callbackasm1(SB)
+	MOVL $630, CX
+	JMP  callbackasm1(SB)
+	MOVL $631, CX
+	JMP  callbackasm1(SB)
+	MOVL $632, CX
+	JMP  callbackasm1(SB)
+	MOVL $633, CX
+	JMP  callbackasm1(SB)
+	MOVL $634, CX
+	JMP  callbackasm1(SB)
+	MOVL $635, CX
+	JMP  callbackasm1(SB)
+	MOVL $636, CX
+	JMP  callbackasm1(SB)
+	MOVL $637, CX
+	JMP  callbackasm1(SB)
+	MOVL $638, CX
+	JMP  callbackasm1(SB)
+	MOVL $639, CX
+	JMP  callbackasm1(SB)
+	MOVL $640, CX
+	JMP  callbackasm1(SB)
+	MOVL $641, CX
+	JMP  callbackasm1(SB)
+	MOVL $642, CX
+	JMP  callbackasm1(SB)
+	MOVL $643, CX
+	JMP  callbackasm1(SB)
+	MOVL $644, CX
+	JMP  callbackasm1(SB)
+	MOVL $645, CX
+	JMP  callbackasm1(SB)
+	MOVL $646, CX
+	JMP  callbackasm1(SB)
+	MOVL $647, CX
+	JMP  callbackasm1(SB)
+	MOVL $648, CX
+	JMP  callbackasm1(SB)
+	MOVL $649, CX
+	JMP  callbackasm1(SB)
+	MOVL $650, CX
+	JMP  callbackasm1(SB)
+	MOVL $651, CX
+	JMP  callbackasm1(SB)
+	MOVL $652, CX
+	JMP  callbackasm1(SB)
+	MOVL $653, CX
+	JMP  callbackasm1(SB)
+	MOVL $654, CX
+	JMP  callbackasm1(SB)
+	MOVL $655, CX
+	JMP  callbackasm1(SB)
+	MOVL $656, CX
+	JMP  callbackasm1(SB)
+	MOVL $657, CX
+	JMP  callbackasm1(SB)
+	MOVL $658, CX
+	JMP  callbackasm1(SB)
+	MOVL $659, CX
+	JMP  callbackasm1(SB)
+	MOVL $660, CX
+	JMP  callbackasm1(SB)
+	MOVL $661, CX
+	JMP  callbackasm1(SB)
+	MOVL $662, CX
+	JMP  callbackasm1(SB)
+	MOVL $663, CX
+	JMP  callbackasm1(SB)
+	MOVL $664, CX
+	JMP  callbackasm1(SB)
+	MOVL $665, CX
+	JMP  callbackasm1(SB)
+	MOVL $666, CX
+	JMP  callbackasm1(SB)
+	MOVL $667, CX
+	JMP  callbackasm1(SB)
+	MOVL $668, CX
+	JMP  callbackasm1(SB)
+	MOVL $669, CX
+	JMP  callbackasm1(SB)
+	MOVL $670, CX
+	JMP  callbackasm1(SB)
+	MOVL $671, CX
+	JMP  callbackasm1(SB)
+	MOVL $672, CX
+	JMP  callbackasm1(SB)
+	MOVL $673, CX
+	JMP  callbackasm1(SB)
+	MOVL $674, CX
+	JMP  callbackasm1(SB)
+	MOVL $675, CX
+	JMP  callbackasm1(SB)
+	MOVL $676, CX
+	JMP  callbackasm1(SB)
+	MOVL $677, CX
+	JMP  callbackasm1(SB)
+	MOVL $678, CX
+	JMP  callbackasm1(SB)
+	MOVL $679, CX
+	JMP  callbackasm1(SB)
+	MOVL $680, CX
+	JMP  callbackasm1(SB)
+	MOVL $681, CX
+	JMP  callbackasm1(SB)
+	MOVL $682, CX
+	JMP  callbackasm1(SB)
+	MOVL $683, CX
+	JMP  callbackasm1(SB)
+	MOVL $684, CX
+	JMP  callbackasm1(SB)
+	MOVL $685, CX
+	JMP  callbackasm1(SB)
+	MOVL $686, CX
+	JMP  callbackasm1(SB)
+	MOVL $687, CX
+	JMP  callbackasm1(SB)
+	MOVL $688, CX
+	JMP  callbackasm1(SB)
+	MOVL $689, CX
+	JMP  callbackasm1(SB)
+	MOVL $690, CX
+	JMP  callbackasm1(SB)
+	MOVL $691, CX
+	JMP  callbackasm1(SB)
+	MOVL $692, CX
+	JMP  callbackasm1(SB)
+	MOVL $693, CX
+	JMP  callbackasm1(SB)
+	MOVL $694, CX
+	JMP  callbackasm1(SB)
+	MOVL $695, CX
+	JMP  callbackasm1(SB)
+	MOVL $696, CX
+	JMP  callbackasm1(SB)
+	MOVL $697, CX
+	JMP  callbackasm1(SB)
+	MOVL $698, CX
+	JMP  callbackasm1(SB)
+	MOVL $699, CX
+	JMP  callbackasm1(SB)
+	MOVL $700, CX
+	JMP  callbackasm1(SB)
+	MOVL $701, CX
+	JMP  callbackasm1(SB)
+	MOVL $702, CX
+	JMP  callbackasm1(SB)
+	MOVL $703, CX
+	JMP  callbackasm1(SB)
+	MOVL $704, CX
+	JMP  callbackasm1(SB)
+	MOVL $705, CX
+	JMP  callbackasm1(SB)
+	MOVL $706, CX
+	JMP  callbackasm1(SB)
+	MOVL $707, CX
+	JMP  callbackasm1(SB)
+	MOVL $708, CX
+	JMP  callbackasm1(SB)
+	MOVL $709, CX
+	JMP  callbackasm1(SB)
+	MOVL $710, CX
+	JMP  callbackasm1(SB)
+	MOVL $711, CX
+	JMP  callbackasm1(SB)
+	MOVL $712, CX
+	JMP  callbackasm1(SB)
+	MOVL $713, CX
+	JMP  callbackasm1(SB)
+	MOVL $714, CX
+	JMP  callbackasm1(SB)
+	MOVL $715, CX
+	JMP  callbackasm1(SB)
+	MOVL $716, CX
+	JMP  callbackasm1(SB)
+	MOVL $717, CX
+	JMP  callbackasm1(SB)
+	MOVL $718, CX
+	JMP  callbackasm1(SB)
+	MOVL $719, CX
+	JMP  callbackasm1(SB)
+	MOVL $720, CX
+	JMP  callbackasm1(SB)
+	MOVL $721, CX
+	JMP  callbackasm1(SB)
+	MOVL $722, CX
+	JMP  callbackasm1(SB)
+	MOVL $723, CX
+	JMP  callbackasm1(SB)
+	MOVL $724, CX
+	JMP  callbackasm1(SB)
+	MOVL $725, CX
+	JMP  callbackasm1(SB)
+	MOVL $726, CX
+	JMP  callbackasm1(SB)
+	MOVL $727, CX
+	JMP  callbackasm1(SB)
+	MOVL $728, CX
+	JMP  callbackasm1(SB)
+	MOVL $729, CX
+	JMP  callbackasm1(SB)
+	MOVL $730, CX
+	JMP  callbackasm1(SB)
+	MOVL $731, CX
+	JMP  callbackasm1(SB)
+	MOVL $732, CX
+	JMP  callbackasm1(SB)
+	MOVL $733, CX
+	JMP  callbackasm1(SB)
+	MOVL $734, CX
+	JMP  callbackasm1(SB)
+	MOVL $735, CX
+	JMP  callbackasm1(SB)
+	MOVL $736, CX
+	JMP  callbackasm1(SB)
+	MOVL $737, CX
+	JMP  callbackasm1(SB)
+	MOVL $738, CX
+	JMP  callbackasm1(SB)
+	MOVL $739, CX
+	JMP  callbackasm1(SB)
+	MOVL $740, CX
+	JMP  callbackasm1(SB)
+	MOVL $741, CX
+	JMP  callbackasm1(SB)
+	MOVL $742, CX
+	JMP  callbackasm1(SB)
+	MOVL $743, CX
+	JMP  callbackasm1(SB)
+	MOVL $744, CX
+	JMP  callbackasm1(SB)
+	MOVL $745, CX
+	JMP  callbackasm1(SB)
+	MOVL $746, CX
+	JMP  callbackasm1(SB)
+	MOVL $747, CX
+	JMP  callbackasm1(SB)
+	MOVL $748, CX
+	JMP  callbackasm1(SB)
+	MOVL $749, CX
+	JMP  callbackasm1(SB)
+	MOVL $750, CX
+	JMP  callbackasm1(SB)
+	MOVL $751, CX
+	JMP  callbackasm1(SB)
+	MOVL $752, CX
+	JMP  callbackasm1(SB)
+	MOVL $753, CX
+	JMP  callbackasm1(SB)
+	MOVL $754, CX
+	JMP  callbackasm1(SB)
+	MOVL $755, CX
+	JMP  callbackasm1(SB)
+	MOVL $756, CX
+	JMP  callbackasm1(SB)
+	MOVL $757, CX
+	JMP  callbackasm1(SB)
+	MOVL $758, CX
+	JMP  callbackasm1(SB)
+	MOVL $759, CX
+	JMP  callbackasm1(SB)
+	MOVL $760, CX
+	JMP  callbackasm1(SB)
+	MOVL $761, CX
+	JMP  callbackasm1(SB)
+	MOVL $762, CX
+	JMP  callbackasm1(SB)
+	MOVL $763, CX
+	JMP  callbackasm1(SB)
+	MOVL $764, CX
+	JMP  callbackasm1(SB)
+	MOVL $765, CX
+	JMP  callbackasm1(SB)
+	MOVL $766, CX
+	JMP  callbackasm1(SB)
+	MOVL $767, CX
+	JMP  callbackasm1(SB)
+	MOVL $768, CX
+	JMP  callbackasm1(SB)
+	MOVL $769, CX
+	JMP  callbackasm1(SB)
+	MOVL $770, CX
+	JMP  callbackasm1(SB)
+	MOVL $771, CX
+	JMP  callbackasm1(SB)
+	MOVL $772, CX
+	JMP  callbackasm1(SB)
+	MOVL $773, CX
+	JMP  callbackasm1(SB)
+	MOVL $774, CX
+	JMP  callbackasm1(SB)
+	MOVL $775, CX
+	JMP  callbackasm1(SB)
+	MOVL $776, CX
+	JMP  callbackasm1(SB)
+	MOVL $777, CX
+	JMP  callbackasm1(SB)
+	MOVL $778, CX
+	JMP  callbackasm1(SB)
+	MOVL $779, CX
+	JMP  callbackasm1(SB)
+	MOVL $780, CX
+	JMP  callbackasm1(SB)
+	MOVL $781, CX
+	JMP  callbackasm1(SB)
+	MOVL $782, CX
+	JMP  callbackasm1(SB)
+	MOVL $783, CX
+	JMP  callbackasm1(SB)
+	MOVL $784, CX
+	JMP  callbackasm1(SB)
+	MOVL $785, CX
+	JMP  callbackasm1(SB)
+	MOVL $786, CX
+	JMP  callbackasm1(SB)
+	MOVL $787, CX
+	JMP  callbackasm1(SB)
+	MOVL $788, CX
+	JMP  callbackasm1(SB)
+	MOVL $789, CX
+	JMP  callbackasm1(SB)
+	MOVL $790, CX
+	JMP  callbackasm1(SB)
+	MOVL $791, CX
+	JMP  callbackasm1(SB)
+	MOVL $792, CX
+	JMP  callbackasm1(SB)
+	MOVL $793, CX
+	JMP  callbackasm1(SB)
+	MOVL $794, CX
+	JMP  callbackasm1(SB)
+	MOVL $795, CX
+	JMP  callbackasm1(SB)
+	MOVL $796, CX
+	JMP  callbackasm1(SB)
+	MOVL $797, CX
+	JMP  callbackasm1(SB)
+	MOVL $798, CX
+	JMP  callbackasm1(SB)
+	MOVL $799, CX
+	JMP  callbackasm1(SB)
+	MOVL $800, CX
+	JMP  callbackasm1(SB)
+	MOVL $801, CX
+	JMP  callbackasm1(SB)
+	MOVL $802, CX
+	JMP  callbackasm1(SB)
+	MOVL $803, CX
+	JMP  callbackasm1(SB)
+	MOVL $804, CX
+	JMP  callbackasm1(SB)
+	MOVL $805, CX
+	JMP  callbackasm1(SB)
+	MOVL $806, CX
+	JMP  callbackasm1(SB)
+	MOVL $807, CX
+	JMP  callbackasm1(SB)
+	MOVL $808, CX
+	JMP  callbackasm1(SB)
+	MOVL $809, CX
+	JMP  callbackasm1(SB)
+	MOVL $810, CX
+	JMP  callbackasm1(SB)
+	MOVL $811, CX
+	JMP  callbackasm1(SB)
+	MOVL $812, CX
+	JMP  callbackasm1(SB)
+	MOVL $813, CX
+	JMP  callbackasm1(SB)
+	MOVL $814, CX
+	JMP  callbackasm1(SB)
+	MOVL $815, CX
+	JMP  callbackasm1(SB)
+	MOVL $816, CX
+	JMP  callbackasm1(SB)
+	MOVL $817, CX
+	JMP  callbackasm1(SB)
+	MOVL $818, CX
+	JMP  callbackasm1(SB)
+	MOVL $819, CX
+	JMP  callbackasm1(SB)
+	MOVL $820, CX
+	JMP  callbackasm1(SB)
+	MOVL $821, CX
+	JMP  callbackasm1(SB)
+	MOVL $822, CX
+	JMP  callbackasm1(SB)
+	MOVL $823, CX
+	JMP  callbackasm1(SB)
+	MOVL $824, CX
+	JMP  callbackasm1(SB)
+	MOVL $825, CX
+	JMP  callbackasm1(SB)
+	MOVL $826, CX
+	JMP  callbackasm1(SB)
+	MOVL $827, CX
+	JMP  callbackasm1(SB)
+	MOVL $828, CX
+	JMP  callbackasm1(SB)
+	MOVL $829, CX
+	JMP  callbackasm1(SB)
+	MOVL $830, CX
+	JMP  callbackasm1(SB)
+	MOVL $831, CX
+	JMP  callbackasm1(SB)
+	MOVL $832, CX
+	JMP  callbackasm1(SB)
+	MOVL $833, CX
+	JMP  callbackasm1(SB)
+	MOVL $834, CX
+	JMP  callbackasm1(SB)
+	MOVL $835, CX
+	JMP  callbackasm1(SB)
+	MOVL $836, CX
+	JMP  callbackasm1(SB)
+	MOVL $837, CX
+	JMP  callbackasm1(SB)
+	MOVL $838, CX
+	JMP  callbackasm1(SB)
+	MOVL $839, CX
+	JMP  callbackasm1(SB)
+	MOVL $840, CX
+	JMP  callbackasm1(SB)
+	MOVL $841, CX
+	JMP  callbackasm1(SB)
+	MOVL $842, CX
+	JMP  callbackasm1(SB)
+	MOVL $843, CX
+	JMP  callbackasm1(SB)
+	MOVL $844, CX
+	JMP  callbackasm1(SB)
+	MOVL $845, CX
+	JMP  callbackasm1(SB)
+	MOVL $846, CX
+	JMP  callbackasm1(SB)
+	MOVL $847, CX
+	JMP  callbackasm1(SB)
+	MOVL $848, CX
+	JMP  callbackasm1(SB)
+	MOVL $849, CX
+	JMP  callbackasm1(SB)
+	MOVL $850, CX
+	JMP  callbackasm1(SB)
+	MOVL $851, CX
+	JMP  callbackasm1(SB)
+	MOVL $852, CX
+	JMP  callbackasm1(SB)
+	MOVL $853, CX
+	JMP  callbackasm1(SB)
+	MOVL $854, CX
+	JMP  callbackasm1(SB)
+	MOVL $855, CX
+	JMP  callbackasm1(SB)
+	MOVL $856, CX
+	JMP  callbackasm1(SB)
+	MOVL $857, CX
+	JMP  callbackasm1(SB)
+	MOVL $858, CX
+	JMP  callbackasm1(SB)
+	MOVL $859, CX
+	JMP  callbackasm1(SB)
+	MOVL $860, CX
+	JMP  callbackasm1(SB)
+	MOVL $861, CX
+	JMP  callbackasm1(SB)
+	MOVL $862, CX
+	JMP  callbackasm1(SB)
+	MOVL $863, CX
+	JMP  callbackasm1(SB)
+	MOVL $864, CX
+	JMP  callbackasm1(SB)
+	MOVL $865, CX
+	JMP  callbackasm1(SB)
+	MOVL $866, CX
+	JMP  callbackasm1(SB)
+	MOVL $867, CX
+	JMP  callbackasm1(SB)
+	MOVL $868, CX
+	JMP  callbackasm1(SB)
+	MOVL $869, CX
+	JMP  callbackasm1(SB)
+	MOVL $870, CX
+	JMP  callbackasm1(SB)
+	MOVL $871, CX
+	JMP  callbackasm1(SB)
+	MOVL $872, CX
+	JMP  callbackasm1(SB)
+	MOVL $873, CX
+	JMP  callbackasm1(SB)
+	MOVL $874, CX
+	JMP  callbackasm1(SB)
+	MOVL $875, CX
+	JMP  callbackasm1(SB)
+	MOVL $876, CX
+	JMP  callbackasm1(SB)
+	MOVL $877, CX
+	JMP  callbackasm1(SB)
+	MOVL $878, CX
+	JMP  callbackasm1(SB)
+	MOVL $879, CX
+	JMP  callbackasm1(SB)
+	MOVL $880, CX
+	JMP  callbackasm1(SB)
+	MOVL $881, CX
+	JMP  callbackasm1(SB)
+	MOVL $882, CX
+	JMP  callbackasm1(SB)
+	MOVL $883, CX
+	JMP  callbackasm1(SB)
+	MOVL $884, CX
+	JMP  callbackasm1(SB)
+	MOVL $885, CX
+	JMP  callbackasm1(SB)
+	MOVL $886, CX
+	JMP  callbackasm1(SB)
+	MOVL $887, CX
+	JMP  callbackasm1(SB)
+	MOVL $888, CX
+	JMP  callbackasm1(SB)
+	MOVL $889, CX
+	JMP  callbackasm1(SB)
+	MOVL $890, CX
+	JMP  callbackasm1(SB)
+	MOVL $891, CX
+	JMP  callbackasm1(SB)
+	MOVL $892, CX
+	JMP  callbackasm1(SB)
+	MOVL $893, CX
+	JMP  callbackasm1(SB)
+	MOVL $894, CX
+	JMP  callbackasm1(SB)
+	MOVL $895, CX
+	JMP  callbackasm1(SB)
+	MOVL $896, CX
+	JMP  callbackasm1(SB)
+	MOVL $897, CX
+	JMP  callbackasm1(SB)
+	MOVL $898, CX
+	JMP  callbackasm1(SB)
+	MOVL $899, CX
+	JMP  callbackasm1(SB)
+	MOVL $900, CX
+	JMP  callbackasm1(SB)
+	MOVL $901, CX
+	JMP  callbackasm1(SB)
+	MOVL $902, CX
+	JMP  callbackasm1(SB)
+	MOVL $903, CX
+	JMP  callbackasm1(SB)
+	MOVL $904, CX
+	JMP  callbackasm1(SB)
+	MOVL $905, CX
+	JMP  callbackasm1(SB)
+	MOVL $906, CX
+	JMP  callbackasm1(SB)
+	MOVL $907, CX
+	JMP  callbackasm1(SB)
+	MOVL $908, CX
+	JMP  callbackasm1(SB)
+	MOVL $909, CX
+	JMP  callbackasm1(SB)
+	MOVL $910, CX
+	JMP  callbackasm1(SB)
+	MOVL $911, CX
+	JMP  callbackasm1(SB)
+	MOVL $912, CX
+	JMP  callbackasm1(SB)
+	MOVL $913, CX
+	JMP  callbackasm1(SB)
+	MOVL $914, CX
+	JMP  callbackasm1(SB)
+	MOVL $915, CX
+	JMP  callbackasm1(SB)
+	MOVL $916, CX
+	JMP  callbackasm1(SB)
+	MOVL $917, CX
+	JMP  callbackasm1(SB)
+	MOVL $918, CX
+	JMP  callbackasm1(SB)
+	MOVL $919, CX
+	JMP  callbackasm1(SB)
+	MOVL $920, CX
+	JMP  callbackasm1(SB)
+	MOVL $921, CX
+	JMP  callbackasm1(SB)
+	MOVL $922, CX
+	JMP  callbackasm1(SB)
+	MOVL $923, CX
+	JMP  callbackasm1(SB)
+	MOVL $924, CX
+	JMP  callbackasm1(SB)
+	MOVL $925, CX
+	JMP  callbackasm1(SB)
+	MOVL $926, CX
+	JMP  callbackasm1(SB)
+	MOVL $927, CX
+	JMP  callbackasm1(SB)
+	MOVL $928, CX
+	JMP  callbackasm1(SB)
+	MOVL $929, CX
+	JMP  callbackasm1(SB)
+	MOVL $930, CX
+	JMP  callbackasm1(SB)
+	MOVL $931, CX
+	JMP  callbackasm1(SB)
+	MOVL $932, CX
+	JMP  callbackasm1(SB)
+	MOVL $933, CX
+	JMP  callbackasm1(SB)
+	MOVL $934, CX
+	JMP  callbackasm1(SB)
+	MOVL $935, CX
+	JMP  callbackasm1(SB)
+	MOVL $936, CX
+	JMP  callbackasm1(SB)
+	MOVL $937, CX
+	JMP  callbackasm1(SB)
+	MOVL $938, CX
+	JMP  callbackasm1(SB)
+	MOVL $939, CX
+	JMP  callbackasm1(SB)
+	MOVL $940, CX
+	JMP  callbackasm1(SB)
+	MOVL $941, CX
+	JMP  callbackasm1(SB)
+	MOVL $942, CX
+	JMP  callbackasm1(SB)
+	MOVL $943, CX
+	JMP  callbackasm1(SB)
+	MOVL $944, CX
+	JMP  callbackasm1(SB)
+	MOVL $945, CX
+	JMP  callbackasm1(SB)
+	MOVL $946, CX
+	JMP  callbackasm1(SB)
+	MOVL $947, CX
+	JMP  callbackasm1(SB)
+	MOVL $948, CX
+	JMP  callbackasm1(SB)
+	MOVL $949, CX
+	JMP  callbackasm1(SB)
+	MOVL $950, CX
+	JMP  callbackasm1(SB)
+	MOVL $951, CX
+	JMP  callbackasm1(SB)
+	MOVL $952, CX
+	JMP  callbackasm1(SB)
+	MOVL $953, CX
+	JMP  callbackasm1(SB)
+	MOVL $954, CX
+	JMP  callbackasm1(SB)
+	MOVL $955, CX
+	JMP  callbackasm1(SB)
+	MOVL $956, CX
+	JMP  callbackasm1(SB)
+	MOVL $957, CX
+	JMP  callbackasm1(SB)
+	MOVL $958, CX
+	JMP  callbackasm1(SB)
+	MOVL $959, CX
+	JMP  callbackasm1(SB)
+	MOVL $960, CX
+	JMP  callbackasm1(SB)
+	MOVL $961, CX
+	JMP  callbackasm1(SB)
+	MOVL $962, CX
+	JMP  callbackasm1(SB)
+	MOVL $963, CX
+	JMP  callbackasm1(SB)
+	MOVL $964, CX
+	JMP  callbackasm1(SB)
+	MOVL $965, CX
+	JMP  callbackasm1(SB)
+	MOVL $966, CX
+	JMP  callbackasm1(SB)
+	MOVL $967, CX
+	JMP  callbackasm1(SB)
+	MOVL $968, CX
+	JMP  callbackasm1(SB)
+	MOVL $969, CX
+	JMP  callbackasm1(SB)
+	MOVL $970, CX
+	JMP  callbackasm1(SB)
+	MOVL $971, CX
+	JMP  callbackasm1(SB)
+	MOVL $972, CX
+	JMP  callbackasm1(SB)
+	MOVL $973, CX
+	JMP  callbackasm1(SB)
+	MOVL $974, CX
+	JMP  callbackasm1(SB)
+	MOVL $975, CX
+	JMP  callbackasm1(SB)
+	MOVL $976, CX
+	JMP  callbackasm1(SB)
+	MOVL $977, CX
+	JMP  callbackasm1(SB)
+	MOVL $978, CX
+	JMP  callbackasm1(SB)
+	MOVL $979, CX
+	JMP  callbackasm1(SB)
+	MOVL $980, CX
+	JMP  callbackasm1(SB)
+	MOVL $981, CX
+	JMP  callbackasm1(SB)
+	MOVL $982, CX
+	JMP  callbackasm1(SB)
+	MOVL $983, CX
+	JMP  callbackasm1(SB)
+	MOVL $984, CX
+	JMP  callbackasm1(SB)
+	MOVL $985, CX
+	JMP  callbackasm1(SB)
+	MOVL $986, CX
+	JMP  callbackasm1(SB)
+	MOVL $987, CX
+	JMP  callbackasm1(SB)
+	MOVL $988, CX
+	JMP  callbackasm1(SB)
+	MOVL $989, CX
+	JMP  callbackasm1(SB)
+	MOVL $990, CX
+	JMP  callbackasm1(SB)
+	MOVL $991, CX
+	JMP  callbackasm1(SB)
+	MOVL $992, CX
+	JMP  callbackasm1(SB)
+	MOVL $993, CX
+	JMP  callbackasm1(SB)
+	MOVL $994, CX
+	JMP  callbackasm1(SB)
+	MOVL $995, CX
+	JMP  callbackasm1(SB)
+	MOVL $996, CX
+	JMP  callbackasm1(SB)
+	MOVL $997, CX
+	JMP  callbackasm1(SB)
+	MOVL $998, CX
+	JMP  callbackasm1(SB)
+	MOVL $999, CX
+	JMP  callbackasm1(SB)
+	MOVL $1000, CX
+	JMP  callbackasm1(SB)
+	MOVL $1001, CX
+	JMP  callbackasm1(SB)
+	MOVL $1002, CX
+	JMP  callbackasm1(SB)
+	MOVL $1003, CX
+	JMP  callbackasm1(SB)
+	MOVL $1004, CX
+	JMP  callbackasm1(SB)
+	MOVL $1005, CX
+	JMP  callbackasm1(SB)
+	MOVL $1006, CX
+	JMP  callbackasm1(SB)
+	MOVL $1007, CX
+	JMP  callbackasm1(SB)
+	MOVL $1008, CX
+	JMP  callbackasm1(SB)
+	MOVL $1009, CX
+	JMP  callbackasm1(SB)
+	MOVL $1010, CX
+	JMP  callbackasm1(SB)
+	MOVL $1011, CX
+	JMP  callbackasm1(SB)
+	MOVL $1012, CX
+	JMP  callbackasm1(SB)
+	MOVL $1013, CX
+	JMP  callbackasm1(SB)
+	MOVL $1014, CX
+	JMP  callbackasm1(SB)
+	MOVL $1015, CX
+	JMP  callbackasm1(SB)
+	MOVL $1016, CX
+	JMP  callbackasm1(SB)
+	MOVL $1017, CX
+	JMP  callbackasm1(SB)
+	MOVL $1018, CX
+	JMP  callbackasm1(SB)
+	MOVL $1019, CX
+	JMP  callbackasm1(SB)
+	MOVL $1020, CX
+	JMP  callbackasm1(SB)
+	MOVL $1021, CX
+	JMP  callbackasm1(SB)
+	MOVL $1022, CX
+	JMP  callbackasm1(SB)
+	MOVL $1023, CX
+	JMP  callbackasm1(SB)
+	MOVL $1024, CX
+	JMP  callbackasm1(SB)
+	MOVL $1025, CX
+	JMP  callbackasm1(SB)
+	MOVL $1026, CX
+	JMP  callbackasm1(SB)
+	MOVL $1027, CX
+	JMP  callbackasm1(SB)
+	MOVL $1028, CX
+	JMP  callbackasm1(SB)
+	MOVL $1029, CX
+	JMP  callbackasm1(SB)
+	MOVL $1030, CX
+	JMP  callbackasm1(SB)
+	MOVL $1031, CX
+	JMP  callbackasm1(SB)
+	MOVL $1032, CX
+	JMP  callbackasm1(SB)
+	MOVL $1033, CX
+	JMP  callbackasm1(SB)
+	MOVL $1034, CX
+	JMP  callbackasm1(SB)
+	MOVL $1035, CX
+	JMP  callbackasm1(SB)
+	MOVL $1036, CX
+	JMP  callbackasm1(SB)
+	MOVL $1037, CX
+	JMP  callbackasm1(SB)
+	MOVL $1038, CX
+	JMP  callbackasm1(SB)
+	MOVL $1039, CX
+	JMP  callbackasm1(SB)
+	MOVL $1040, CX
+	JMP  callbackasm1(SB)
+	MOVL $1041, CX
+	JMP  callbackasm1(SB)
+	MOVL $1042, CX
+	JMP  callbackasm1(SB)
+	MOVL $1043, CX
+	JMP  callbackasm1(SB)
+	MOVL $1044, CX
+	JMP  callbackasm1(SB)
+	MOVL $1045, CX
+	JMP  callbackasm1(SB)
+	MOVL $1046, CX
+	JMP  callbackasm1(SB)
+	MOVL $1047, CX
+	JMP  callbackasm1(SB)
+	MOVL $1048, CX
+	JMP  callbackasm1(SB)
+	MOVL $1049, CX
+	JMP  callbackasm1(SB)
+	MOVL $1050, CX
+	JMP  callbackasm1(SB)
+	MOVL $1051, CX
+	JMP  callbackasm1(SB)
+	MOVL $1052, CX
+	JMP  callbackasm1(SB)
+	MOVL $1053, CX
+	JMP  callbackasm1(SB)
+	MOVL $1054, CX
+	JMP  callbackasm1(SB)
+	MOVL $1055, CX
+	JMP  callbackasm1(SB)
+	MOVL $1056, CX
+	JMP  callbackasm1(SB)
+	MOVL $1057, CX
+	JMP  callbackasm1(SB)
+	MOVL $1058, CX
+	JMP  callbackasm1(SB)
+	MOVL $1059, CX
+	JMP  callbackasm1(SB)
+	MOVL $1060, CX
+	JMP  callbackasm1(SB)
+	MOVL $1061, CX
+	JMP  callbackasm1(SB)
+	MOVL $1062, CX
+	JMP  callbackasm1(SB)
+	MOVL $1063, CX
+	JMP  callbackasm1(SB)
+	MOVL $1064, CX
+	JMP  callbackasm1(SB)
+	MOVL $1065, CX
+	JMP  callbackasm1(SB)
+	MOVL $1066, CX
+	JMP  callbackasm1(SB)
+	MOVL $1067, CX
+	JMP  callbackasm1(SB)
+	MOVL $1068, CX
+	JMP  callbackasm1(SB)
+	MOVL $1069, CX
+	JMP  callbackasm1(SB)
+	MOVL $1070, CX
+	JMP  callbackasm1(SB)
+	MOVL $1071, CX
+	JMP  callbackasm1(SB)
+	MOVL $1072, CX
+	JMP  callbackasm1(SB)
+	MOVL $1073, CX
+	JMP  callbackasm1(SB)
+	MOVL $1074, CX
+	JMP  callbackasm1(SB)
+	MOVL $1075, CX
+	JMP  callbackasm1(SB)
+	MOVL $1076, CX
+	JMP  callbackasm1(SB)
+	MOVL $1077, CX
+	JMP  callbackasm1(SB)
+	MOVL $1078, CX
+	JMP  callbackasm1(SB)
+	MOVL $1079, CX
+	JMP  callbackasm1(SB)
+	MOVL $1080, CX
+	JMP  callbackasm1(SB)
+	MOVL $1081, CX
+	JMP  callbackasm1(SB)
+	MOVL $1082, CX
+	JMP  callbackasm1(SB)
+	MOVL $1083, CX
+	JMP  callbackasm1(SB)
+	MOVL $1084, CX
+	JMP  callbackasm1(SB)
+	MOVL $1085, CX
+	JMP  callbackasm1(SB)
+	MOVL $1086, CX
+	JMP  callbackasm1(SB)
+	MOVL $1087, CX
+	JMP  callbackasm1(SB)
+	MOVL $1088, CX
+	JMP  callbackasm1(SB)
+	MOVL $1089, CX
+	JMP  callbackasm1(SB)
+	MOVL $1090, CX
+	JMP  callbackasm1(SB)
+	MOVL $1091, CX
+	JMP  callbackasm1(SB)
+	MOVL $1092, CX
+	JMP  callbackasm1(SB)
+	MOVL $1093, CX
+	JMP  callbackasm1(SB)
+	MOVL $1094, CX
+	JMP  callbackasm1(SB)
+	MOVL $1095, CX
+	JMP  callbackasm1(SB)
+	MOVL $1096, CX
+	JMP  callbackasm1(SB)
+	MOVL $1097, CX
+	JMP  callbackasm1(SB)
+	MOVL $1098, CX
+	JMP  callbackasm1(SB)
+	MOVL $1099, CX
+	JMP  callbackasm1(SB)
+	MOVL $1100, CX
+	JMP  callbackasm1(SB)
+	MOVL $1101, CX
+	JMP  callbackasm1(SB)
+	MOVL $1102, CX
+	JMP  callbackasm1(SB)
+	MOVL $1103, CX
+	JMP  callbackasm1(SB)
+	MOVL $1104, CX
+	JMP  callbackasm1(SB)
+	MOVL $1105, CX
+	JMP  callbackasm1(SB)
+	MOVL $1106, CX
+	JMP  callbackasm1(SB)
+	MOVL $1107, CX
+	JMP  callbackasm1(SB)
+	MOVL $1108, CX
+	JMP  callbackasm1(SB)
+	MOVL $1109, CX
+	JMP  callbackasm1(SB)
+	MOVL $1110, CX
+	JMP  callbackasm1(SB)
+	MOVL $1111, CX
+	JMP  callbackasm1(SB)
+	MOVL $1112, CX
+	JMP  callbackasm1(SB)
+	MOVL $1113, CX
+	JMP  callbackasm1(SB)
+	MOVL $1114, CX
+	JMP  callbackasm1(SB)
+	MOVL $1115, CX
+	JMP  callbackasm1(SB)
+	MOVL $1116, CX
+	JMP  callbackasm1(SB)
+	MOVL $1117, CX
+	JMP  callbackasm1(SB)
+	MOVL $1118, CX
+	JMP  callbackasm1(SB)
+	MOVL $1119, CX
+	JMP  callbackasm1(SB)
+	MOVL $1120, CX
+	JMP  callbackasm1(SB)
+	MOVL $1121, CX
+	JMP  callbackasm1(SB)
+	MOVL $1122, CX
+	JMP  callbackasm1(SB)
+	MOVL $1123, CX
+	JMP  callbackasm1(SB)
+	MOVL $1124, CX
+	JMP  callbackasm1(SB)
+	MOVL $1125, CX
+	JMP  callbackasm1(SB)
+	MOVL $1126, CX
+	JMP  callbackasm1(SB)
+	MOVL $1127, CX
+	JMP  callbackasm1(SB)
+	MOVL $1128, CX
+	JMP  callbackasm1(SB)
+	MOVL $1129, CX
+	JMP  callbackasm1(SB)
+	MOVL $1130, CX
+	JMP  callbackasm1(SB)
+	MOVL $1131, CX
+	JMP  callbackasm1(SB)
+	MOVL $1132, CX
+	JMP  callbackasm1(SB)
+	MOVL $1133, CX
+	JMP  callbackasm1(SB)
+	MOVL $1134, CX
+	JMP  callbackasm1(SB)
+	MOVL $1135, CX
+	JMP  callbackasm1(SB)
+	MOVL $1136, CX
+	JMP  callbackasm1(SB)
+	MOVL $1137, CX
+	JMP  callbackasm1(SB)
+	MOVL $1138, CX
+	JMP  callbackasm1(SB)
+	MOVL $1139, CX
+	JMP  callbackasm1(SB)
+	MOVL $1140, CX
+	JMP  callbackasm1(SB)
+	MOVL $1141, CX
+	JMP  callbackasm1(SB)
+	MOVL $1142, CX
+	JMP  callbackasm1(SB)
+	MOVL $1143, CX
+	JMP  callbackasm1(SB)
+	MOVL $1144, CX
+	JMP  callbackasm1(SB)
+	MOVL $1145, CX
+	JMP  callbackasm1(SB)
+	MOVL $1146, CX
+	JMP  callbackasm1(SB)
+	MOVL $1147, CX
+	JMP  callbackasm1(SB)
+	MOVL $1148, CX
+	JMP  callbackasm1(SB)
+	MOVL $1149, CX
+	JMP  callbackasm1(SB)
+	MOVL $1150, CX
+	JMP  callbackasm1(SB)
+	MOVL $1151, CX
+	JMP  callbackasm1(SB)
+	MOVL $1152, CX
+	JMP  callbackasm1(SB)
+	MOVL $1153, CX
+	JMP  callbackasm1(SB)
+	MOVL $1154, CX
+	JMP  callbackasm1(SB)
+	MOVL $1155, CX
+	JMP  callbackasm1(SB)
+	MOVL $1156, CX
+	JMP  callbackasm1(SB)
+	MOVL $1157, CX
+	JMP  callbackasm1(SB)
+	MOVL $1158, CX
+	JMP  callbackasm1(SB)
+	MOVL $1159, CX
+	JMP  callbackasm1(SB)
+	MOVL $1160, CX
+	JMP  callbackasm1(SB)
+	MOVL $1161, CX
+	JMP  callbackasm1(SB)
+	MOVL $1162, CX
+	JMP  callbackasm1(SB)
+	MOVL $1163, CX
+	JMP  callbackasm1(SB)
+	MOVL $1164, CX
+	JMP  callbackasm1(SB)
+	MOVL $1165, CX
+	JMP  callbackasm1(SB)
+	MOVL $1166, CX
+	JMP  callbackasm1(SB)
+	MOVL $1167, CX
+	JMP  callbackasm1(SB)
+	MOVL $1168, CX
+	JMP  callbackasm1(SB)
+	MOVL $1169, CX
+	JMP  callbackasm1(SB)
+	MOVL $1170, CX
+	JMP  callbackasm1(SB)
+	MOVL $1171, CX
+	JMP  callbackasm1(SB)
+	MOVL $1172, CX
+	JMP  callbackasm1(SB)
+	MOVL $1173, CX
+	JMP  callbackasm1(SB)
+	MOVL $1174, CX
+	JMP  callbackasm1(SB)
+	MOVL $1175, CX
+	JMP  callbackasm1(SB)
+	MOVL $1176, CX
+	JMP  callbackasm1(SB)
+	MOVL $1177, CX
+	JMP  callbackasm1(SB)
+	MOVL $1178, CX
+	JMP  callbackasm1(SB)
+	MOVL $1179, CX
+	JMP  callbackasm1(SB)
+	MOVL $1180, CX
+	JMP  callbackasm1(SB)
+	MOVL $1181, CX
+	JMP  callbackasm1(SB)
+	MOVL $1182, CX
+	JMP  callbackasm1(SB)
+	MOVL $1183, CX
+	JMP  callbackasm1(SB)
+	MOVL $1184, CX
+	JMP  callbackasm1(SB)
+	MOVL $1185, CX
+	JMP  callbackasm1(SB)
+	MOVL $1186, CX
+	JMP  callbackasm1(SB)
+	MOVL $1187, CX
+	JMP  callbackasm1(SB)
+	MOVL $1188, CX
+	JMP  callbackasm1(SB)
+	MOVL $1189, CX
+	JMP  callbackasm1(SB)
+	MOVL $1190, CX
+	JMP  callbackasm1(SB)
+	MOVL $1191, CX
+	JMP  callbackasm1(SB)
+	MOVL $1192, CX
+	JMP  callbackasm1(SB)
+	MOVL $1193, CX
+	JMP  callbackasm1(SB)
+	MOVL $1194, CX
+	JMP  callbackasm1(SB)
+	MOVL $1195, CX
+	JMP  callbackasm1(SB)
+	MOVL $1196, CX
+	JMP  callbackasm1(SB)
+	MOVL $1197, CX
+	JMP  callbackasm1(SB)
+	MOVL $1198, CX
+	JMP  callbackasm1(SB)
+	MOVL $1199, CX
+	JMP  callbackasm1(SB)
+	MOVL $1200, CX
+	JMP  callbackasm1(SB)
+	MOVL $1201, CX
+	JMP  callbackasm1(SB)
+	MOVL $1202, CX
+	JMP  callbackasm1(SB)
+	MOVL $1203, CX
+	JMP  callbackasm1(SB)
+	MOVL $1204, CX
+	JMP  callbackasm1(SB)
+	MOVL $1205, CX
+	JMP  callbackasm1(SB)
+	MOVL $1206, CX
+	JMP  callbackasm1(SB)
+	MOVL $1207, CX
+	JMP  callbackasm1(SB)
+	MOVL $1208, CX
+	JMP  callbackasm1(SB)
+	MOVL $1209, CX
+	JMP  callbackasm1(SB)
+	MOVL $1210, CX
+	JMP  callbackasm1(SB)
+	MOVL $1211, CX
+	JMP  callbackasm1(SB)
+	MOVL $1212, CX
+	JMP  callbackasm1(SB)
+	MOVL $1213, CX
+	JMP  callbackasm1(SB)
+	MOVL $1214, CX
+	JMP  callbackasm1(SB)
+	MOVL $1215, CX
+	JMP  callbackasm1(SB)
+	MOVL $1216, CX
+	JMP  callbackasm1(SB)
+	MOVL $1217, CX
+	JMP  callbackasm1(SB)
+	MOVL $1218, CX
+	JMP  callbackasm1(SB)
+	MOVL $1219, CX
+	JMP  callbackasm1(SB)
+	MOVL $1220, CX
+	JMP  callbackasm1(SB)
+	MOVL $1221, CX
+	JMP  callbackasm1(SB)
+	MOVL $1222, CX
+	JMP  callbackasm1(SB)
+	MOVL $1223, CX
+	JMP  callbackasm1(SB)
+	MOVL $1224, CX
+	JMP  callbackasm1(SB)
+	MOVL $1225, CX
+	JMP  callbackasm1(SB)
+	MOVL $1226, CX
+	JMP  callbackasm1(SB)
+	MOVL $1227, CX
+	JMP  callbackasm1(SB)
+	MOVL $1228, CX
+	JMP  callbackasm1(SB)
+	MOVL $1229, CX
+	JMP  callbackasm1(SB)
+	MOVL $1230, CX
+	JMP  callbackasm1(SB)
+	MOVL $1231, CX
+	JMP  callbackasm1(SB)
+	MOVL $1232, CX
+	JMP  callbackasm1(SB)
+	MOVL $1233, CX
+	JMP  callbackasm1(SB)
+	MOVL $1234, CX
+	JMP  callbackasm1(SB)
+	MOVL $1235, CX
+	JMP  callbackasm1(SB)
+	MOVL $1236, CX
+	JMP  callbackasm1(SB)
+	MOVL $1237, CX
+	JMP  callbackasm1(SB)
+	MOVL $1238, CX
+	JMP  callbackasm1(SB)
+	MOVL $1239, CX
+	JMP  callbackasm1(SB)
+	MOVL $1240, CX
+	JMP  callbackasm1(SB)
+	MOVL $1241, CX
+	JMP  callbackasm1(SB)
+	MOVL $1242, CX
+	JMP  callbackasm1(SB)
+	MOVL $1243, CX
+	JMP  callbackasm1(SB)
+	MOVL $1244, CX
+	JMP  callbackasm1(SB)
+	MOVL $1245, CX
+	JMP  callbackasm1(SB)
+	MOVL $1246, CX
+	JMP  callbackasm1(SB)
+	MOVL $1247, CX
+	JMP  callbackasm1(SB)
+	MOVL $1248, CX
+	JMP  callbackasm1(SB)
+	MOVL $1249, CX
+	JMP  callbackasm1(SB)
+	MOVL $1250, CX
+	JMP  callbackasm1(SB)
+	MOVL $1251, CX
+	JMP  callbackasm1(SB)
+	MOVL $1252, CX
+	JMP  callbackasm1(SB)
+	MOVL $1253, CX
+	JMP  callbackasm1(SB)
+	MOVL $1254, CX
+	JMP  callbackasm1(SB)
+	MOVL $1255, CX
+	JMP  callbackasm1(SB)
+	MOVL $1256, CX
+	JMP  callbackasm1(SB)
+	MOVL $1257, CX
+	JMP  callbackasm1(SB)
+	MOVL $1258, CX
+	JMP  callbackasm1(SB)
+	MOVL $1259, CX
+	JMP  callbackasm1(SB)
+	MOVL $1260, CX
+	JMP  callbackasm1(SB)
+	MOVL $1261, CX
+	JMP  callbackasm1(SB)
+	MOVL $1262, CX
+	JMP  callbackasm1(SB)
+	MOVL $1263, CX
+	JMP  callbackasm1(SB)
+	MOVL $1264, CX
+	JMP  callbackasm1(SB)
+	MOVL $1265, CX
+	JMP  callbackasm1(SB)
+	MOVL $1266, CX
+	JMP  callbackasm1(SB)
+	MOVL $1267, CX
+	JMP  callbackasm1(SB)
+	MOVL $1268, CX
+	JMP  callbackasm1(SB)
+	MOVL $1269, CX
+	JMP  callbackasm1(SB)
+	MOVL $1270, CX
+	JMP  callbackasm1(SB)
+	MOVL $1271, CX
+	JMP  callbackasm1(SB)
+	MOVL $1272, CX
+	JMP  callbackasm1(SB)
+	MOVL $1273, CX
+	JMP  callbackasm1(SB)
+	MOVL $1274, CX
+	JMP  callbackasm1(SB)
+	MOVL $1275, CX
+	JMP  callbackasm1(SB)
+	MOVL $1276, CX
+	JMP  callbackasm1(SB)
+	MOVL $1277, CX
+	JMP  callbackasm1(SB)
+	MOVL $1278, CX
+	JMP  callbackasm1(SB)
+	MOVL $1279, CX
+	JMP  callbackasm1(SB)
+	MOVL $1280, CX
+	JMP  callbackasm1(SB)
+	MOVL $1281, CX
+	JMP  callbackasm1(SB)
+	MOVL $1282, CX
+	JMP  callbackasm1(SB)
+	MOVL $1283, CX
+	JMP  callbackasm1(SB)
+	MOVL $1284, CX
+	JMP  callbackasm1(SB)
+	MOVL $1285, CX
+	JMP  callbackasm1(SB)
+	MOVL $1286, CX
+	JMP  callbackasm1(SB)
+	MOVL $1287, CX
+	JMP  callbackasm1(SB)
+	MOVL $1288, CX
+	JMP  callbackasm1(SB)
+	MOVL $1289, CX
+	JMP  callbackasm1(SB)
+	MOVL $1290, CX
+	JMP  callbackasm1(SB)
+	MOVL $1291, CX
+	JMP  callbackasm1(SB)
+	MOVL $1292, CX
+	JMP  callbackasm1(SB)
+	MOVL $1293, CX
+	JMP  callbackasm1(SB)
+	MOVL $1294, CX
+	JMP  callbackasm1(SB)
+	MOVL $1295, CX
+	JMP  callbackasm1(SB)
+	MOVL $1296, CX
+	JMP  callbackasm1(SB)
+	MOVL $1297, CX
+	JMP  callbackasm1(SB)
+	MOVL $1298, CX
+	JMP  callbackasm1(SB)
+	MOVL $1299, CX
+	JMP  callbackasm1(SB)
+	MOVL $1300, CX
+	JMP  callbackasm1(SB)
+	MOVL $1301, CX
+	JMP  callbackasm1(SB)
+	MOVL $1302, CX
+	JMP  callbackasm1(SB)
+	MOVL $1303, CX
+	JMP  callbackasm1(SB)
+	MOVL $1304, CX
+	JMP  callbackasm1(SB)
+	MOVL $1305, CX
+	JMP  callbackasm1(SB)
+	MOVL $1306, CX
+	JMP  callbackasm1(SB)
+	MOVL $1307, CX
+	JMP  callbackasm1(SB)
+	MOVL $1308, CX
+	JMP  callbackasm1(SB)
+	MOVL $1309, CX
+	JMP  callbackasm1(SB)
+	MOVL $1310, CX
+	JMP  callbackasm1(SB)
+	MOVL $1311, CX
+	JMP  callbackasm1(SB)
+	MOVL $1312, CX
+	JMP  callbackasm1(SB)
+	MOVL $1313, CX
+	JMP  callbackasm1(SB)
+	MOVL $1314, CX
+	JMP  callbackasm1(SB)
+	MOVL $1315, CX
+	JMP  callbackasm1(SB)
+	MOVL $1316, CX
+	JMP  callbackasm1(SB)
+	MOVL $1317, CX
+	JMP  callbackasm1(SB)
+	MOVL $1318, CX
+	JMP  callbackasm1(SB)
+	MOVL $1319, CX
+	JMP  callbackasm1(SB)
+	MOVL $1320, CX
+	JMP  callbackasm1(SB)
+	MOVL $1321, CX
+	JMP  callbackasm1(SB)
+	MOVL $1322, CX
+	JMP  callbackasm1(SB)
+	MOVL $1323, CX
+	JMP  callbackasm1(SB)
+	MOVL $1324, CX
+	JMP  callbackasm1(SB)
+	MOVL $1325, CX
+	JMP  callbackasm1(SB)
+	MOVL $1326, CX
+	JMP  callbackasm1(SB)
+	MOVL $1327, CX
+	JMP  callbackasm1(SB)
+	MOVL $1328, CX
+	JMP  callbackasm1(SB)
+	MOVL $1329, CX
+	JMP  callbackasm1(SB)
+	MOVL $1330, CX
+	JMP  callbackasm1(SB)
+	MOVL $1331, CX
+	JMP  callbackasm1(SB)
+	MOVL $1332, CX
+	JMP  callbackasm1(SB)
+	MOVL $1333, CX
+	JMP  callbackasm1(SB)
+	MOVL $1334, CX
+	JMP  callbackasm1(SB)
+	MOVL $1335, CX
+	JMP  callbackasm1(SB)
+	MOVL $1336, CX
+	JMP  callbackasm1(SB)
+	MOVL $1337, CX
+	JMP  callbackasm1(SB)
+	MOVL $1338, CX
+	JMP  callbackasm1(SB)
+	MOVL $1339, CX
+	JMP  callbackasm1(SB)
+	MOVL $1340, CX
+	JMP  callbackasm1(SB)
+	MOVL $1341, CX
+	JMP  callbackasm1(SB)
+	MOVL $1342, CX
+	JMP  callbackasm1(SB)
+	MOVL $1343, CX
+	JMP  callbackasm1(SB)
+	MOVL $1344, CX
+	JMP  callbackasm1(SB)
+	MOVL $1345, CX
+	JMP  callbackasm1(SB)
+	MOVL $1346, CX
+	JMP  callbackasm1(SB)
+	MOVL $1347, CX
+	JMP  callbackasm1(SB)
+	MOVL $1348, CX
+	JMP  callbackasm1(SB)
+	MOVL $1349, CX
+	JMP  callbackasm1(SB)
+	MOVL $1350, CX
+	JMP  callbackasm1(SB)
+	MOVL $1351, CX
+	JMP  callbackasm1(SB)
+	MOVL $1352, CX
+	JMP  callbackasm1(SB)
+	MOVL $1353, CX
+	JMP  callbackasm1(SB)
+	MOVL $1354, CX
+	JMP  callbackasm1(SB)
+	MOVL $1355, CX
+	JMP  callbackasm1(SB)
+	MOVL $1356, CX
+	JMP  callbackasm1(SB)
+	MOVL $1357, CX
+	JMP  callbackasm1(SB)
+	MOVL $1358, CX
+	JMP  callbackasm1(SB)
+	MOVL $1359, CX
+	JMP  callbackasm1(SB)
+	MOVL $1360, CX
+	JMP  callbackasm1(SB)
+	MOVL $1361, CX
+	JMP  callbackasm1(SB)
+	MOVL $1362, CX
+	JMP  callbackasm1(SB)
+	MOVL $1363, CX
+	JMP  callbackasm1(SB)
+	MOVL $1364, CX
+	JMP  callbackasm1(SB)
+	MOVL $1365, CX
+	JMP  callbackasm1(SB)
+	MOVL $1366, CX
+	JMP  callbackasm1(SB)
+	MOVL $1367, CX
+	JMP  callbackasm1(SB)
+	MOVL $1368, CX
+	JMP  callbackasm1(SB)
+	MOVL $1369, CX
+	JMP  callbackasm1(SB)
+	MOVL $1370, CX
+	JMP  callbackasm1(SB)
+	MOVL $1371, CX
+	JMP  callbackasm1(SB)
+	MOVL $1372, CX
+	JMP  callbackasm1(SB)
+	MOVL $1373, CX
+	JMP  callbackasm1(SB)
+	MOVL $1374, CX
+	JMP  callbackasm1(SB)
+	MOVL $1375, CX
+	JMP  callbackasm1(SB)
+	MOVL $1376, CX
+	JMP  callbackasm1(SB)
+	MOVL $1377, CX
+	JMP  callbackasm1(SB)
+	MOVL $1378, CX
+	JMP  callbackasm1(SB)
+	MOVL $1379, CX
+	JMP  callbackasm1(SB)
+	MOVL $1380, CX
+	JMP  callbackasm1(SB)
+	MOVL $1381, CX
+	JMP  callbackasm1(SB)
+	MOVL $1382, CX
+	JMP  callbackasm1(SB)
+	MOVL $1383, CX
+	JMP  callbackasm1(SB)
+	MOVL $1384, CX
+	JMP  callbackasm1(SB)
+	MOVL $1385, CX
+	JMP  callbackasm1(SB)
+	MOVL $1386, CX
+	JMP  callbackasm1(SB)
+	MOVL $1387, CX
+	JMP  callbackasm1(SB)
+	MOVL $1388, CX
+	JMP  callbackasm1(SB)
+	MOVL $1389, CX
+	JMP  callbackasm1(SB)
+	MOVL $1390, CX
+	JMP  callbackasm1(SB)
+	MOVL $1391, CX
+	JMP  callbackasm1(SB)
+	MOVL $1392, CX
+	JMP  callbackasm1(SB)
+	MOVL $1393, CX
+	JMP  callbackasm1(SB)
+	MOVL $1394, CX
+	JMP  callbackasm1(SB)
+	MOVL $1395, CX
+	JMP  callbackasm1(SB)
+	MOVL $1396, CX
+	JMP  callbackasm1(SB)
+	MOVL $1397, CX
+	JMP  callbackasm1(SB)
+	MOVL $1398, CX
+	JMP  callbackasm1(SB)
+	MOVL $1399, CX
+	JMP  callbackasm1(SB)
+	MOVL $1400, CX
+	JMP  callbackasm1(SB)
+	MOVL $1401, CX
+	JMP  callbackasm1(SB)
+	MOVL $1402, CX
+	JMP  callbackasm1(SB)
+	MOVL $1403, CX
+	JMP  callbackasm1(SB)
+	MOVL $1404, CX
+	JMP  callbackasm1(SB)
+	MOVL $1405, CX
+	JMP  callbackasm1(SB)
+	MOVL $1406, CX
+	JMP  callbackasm1(SB)
+	MOVL $1407, CX
+	JMP  callbackasm1(SB)
+	MOVL $1408, CX
+	JMP  callbackasm1(SB)
+	MOVL $1409, CX
+	JMP  callbackasm1(SB)
+	MOVL $1410, CX
+	JMP  callbackasm1(SB)
+	MOVL $1411, CX
+	JMP  callbackasm1(SB)
+	MOVL $1412, CX
+	JMP  callbackasm1(SB)
+	MOVL $1413, CX
+	JMP  callbackasm1(SB)
+	MOVL $1414, CX
+	JMP  callbackasm1(SB)
+	MOVL $1415, CX
+	JMP  callbackasm1(SB)
+	MOVL $1416, CX
+	JMP  callbackasm1(SB)
+	MOVL $1417, CX
+	JMP  callbackasm1(SB)
+	MOVL $1418, CX
+	JMP  callbackasm1(SB)
+	MOVL $1419, CX
+	JMP  callbackasm1(SB)
+	MOVL $1420, CX
+	JMP  callbackasm1(SB)
+	MOVL $1421, CX
+	JMP  callbackasm1(SB)
+	MOVL $1422, CX
+	JMP  callbackasm1(SB)
+	MOVL $1423, CX
+	JMP  callbackasm1(SB)
+	MOVL $1424, CX
+	JMP  callbackasm1(SB)
+	MOVL $1425, CX
+	JMP  callbackasm1(SB)
+	MOVL $1426, CX
+	JMP  callbackasm1(SB)
+	MOVL $1427, CX
+	JMP  callbackasm1(SB)
+	MOVL $1428, CX
+	JMP  callbackasm1(SB)
+	MOVL $1429, CX
+	JMP  callbackasm1(SB)
+	MOVL $1430, CX
+	JMP  callbackasm1(SB)
+	MOVL $1431, CX
+	JMP  callbackasm1(SB)
+	MOVL $1432, CX
+	JMP  callbackasm1(SB)
+	MOVL $1433, CX
+	JMP  callbackasm1(SB)
+	MOVL $1434, CX
+	JMP  callbackasm1(SB)
+	MOVL $1435, CX
+	JMP  callbackasm1(SB)
+	MOVL $1436, CX
+	JMP  callbackasm1(SB)
+	MOVL $1437, CX
+	JMP  callbackasm1(SB)
+	MOVL $1438, CX
+	JMP  callbackasm1(SB)
+	MOVL $1439, CX
+	JMP  callbackasm1(SB)
+	MOVL $1440, CX
+	JMP  callbackasm1(SB)
+	MOVL $1441, CX
+	JMP  callbackasm1(SB)
+	MOVL $1442, CX
+	JMP  callbackasm1(SB)
+	MOVL $1443, CX
+	JMP  callbackasm1(SB)
+	MOVL $1444, CX
+	JMP  callbackasm1(SB)
+	MOVL $1445, CX
+	JMP  callbackasm1(SB)
+	MOVL $1446, CX
+	JMP  callbackasm1(SB)
+	MOVL $1447, CX
+	JMP  callbackasm1(SB)
+	MOVL $1448, CX
+	JMP  callbackasm1(SB)
+	MOVL $1449, CX
+	JMP  callbackasm1(SB)
+	MOVL $1450, CX
+	JMP  callbackasm1(SB)
+	MOVL $1451, CX
+	JMP  callbackasm1(SB)
+	MOVL $1452, CX
+	JMP  callbackasm1(SB)
+	MOVL $1453, CX
+	JMP  callbackasm1(SB)
+	MOVL $1454, CX
+	JMP  callbackasm1(SB)
+	MOVL $1455, CX
+	JMP  callbackasm1(SB)
+	MOVL $1456, CX
+	JMP  callbackasm1(SB)
+	MOVL $1457, CX
+	JMP  callbackasm1(SB)
+	MOVL $1458, CX
+	JMP  callbackasm1(SB)
+	MOVL $1459, CX
+	JMP  callbackasm1(SB)
+	MOVL $1460, CX
+	JMP  callbackasm1(SB)
+	MOVL $1461, CX
+	JMP  callbackasm1(SB)
+	MOVL $1462, CX
+	JMP  callbackasm1(SB)
+	MOVL $1463, CX
+	JMP  callbackasm1(SB)
+	MOVL $1464, CX
+	JMP  callbackasm1(SB)
+	MOVL $1465, CX
+	JMP  callbackasm1(SB)
+	MOVL $1466, CX
+	JMP  callbackasm1(SB)
+	MOVL $1467, CX
+	JMP  callbackasm1(SB)
+	MOVL $1468, CX
+	JMP  callbackasm1(SB)
+	MOVL $1469, CX
+	JMP  callbackasm1(SB)
+	MOVL $1470, CX
+	JMP  callbackasm1(SB)
+	MOVL $1471, CX
+	JMP  callbackasm1(SB)
+	MOVL $1472, CX
+	JMP  callbackasm1(SB)
+	MOVL $1473, CX
+	JMP  callbackasm1(SB)
+	MOVL $1474, CX
+	JMP  callbackasm1(SB)
+	MOVL $1475, CX
+	JMP  callbackasm1(SB)
+	MOVL $1476, CX
+	JMP  callbackasm1(SB)
+	MOVL $1477, CX
+	JMP  callbackasm1(SB)
+	MOVL $1478, CX
+	JMP  callbackasm1(SB)
+	MOVL $1479, CX
+	JMP  callbackasm1(SB)
+	MOVL $1480, CX
+	JMP  callbackasm1(SB)
+	MOVL $1481, CX
+	JMP  callbackasm1(SB)
+	MOVL $1482, CX
+	JMP  callbackasm1(SB)
+	MOVL $1483, CX
+	JMP  callbackasm1(SB)
+	MOVL $1484, CX
+	JMP  callbackasm1(SB)
+	MOVL $1485, CX
+	JMP  callbackasm1(SB)
+	MOVL $1486, CX
+	JMP  callbackasm1(SB)
+	MOVL $1487, CX
+	JMP  callbackasm1(SB)
+	MOVL $1488, CX
+	JMP  callbackasm1(SB)
+	MOVL $1489, CX
+	JMP  callbackasm1(SB)
+	MOVL $1490, CX
+	JMP  callbackasm1(SB)
+	MOVL $1491, CX
+	JMP  callbackasm1(SB)
+	MOVL $1492, CX
+	JMP  callbackasm1(SB)
+	MOVL $1493, CX
+	JMP  callbackasm1(SB)
+	MOVL $1494, CX
+	JMP  callbackasm1(SB)
+	MOVL $1495, CX
+	JMP  callbackasm1(SB)
+	MOVL $1496, CX
+	JMP  callbackasm1(SB)
+	MOVL $1497, CX
+	JMP  callbackasm1(SB)
+	MOVL $1498, CX
+	JMP  callbackasm1(SB)
+	MOVL $1499, CX
+	JMP  callbackasm1(SB)
+	MOVL $1500, CX
+	JMP  callbackasm1(SB)
+	MOVL $1501, CX
+	JMP  callbackasm1(SB)
+	MOVL $1502, CX
+	JMP  callbackasm1(SB)
+	MOVL $1503, CX
+	JMP  callbackasm1(SB)
+	MOVL $1504, CX
+	JMP  callbackasm1(SB)
+	MOVL $1505, CX
+	JMP  callbackasm1(SB)
+	MOVL $1506, CX
+	JMP  callbackasm1(SB)
+	MOVL $1507, CX
+	JMP  callbackasm1(SB)
+	MOVL $1508, CX
+	JMP  callbackasm1(SB)
+	MOVL $1509, CX
+	JMP  callbackasm1(SB)
+	MOVL $1510, CX
+	JMP  callbackasm1(SB)
+	MOVL $1511, CX
+	JMP  callbackasm1(SB)
+	MOVL $1512, CX
+	JMP  callbackasm1(SB)
+	MOVL $1513, CX
+	JMP  callbackasm1(SB)
+	MOVL $1514, CX
+	JMP  callbackasm1(SB)
+	MOVL $1515, CX
+	JMP  callbackasm1(SB)
+	MOVL $1516, CX
+	JMP  callbackasm1(SB)
+	MOVL $1517, CX
+	JMP  callbackasm1(SB)
+	MOVL $1518, CX
+	JMP  callbackasm1(SB)
+	MOVL $1519, CX
+	JMP  callbackasm1(SB)
+	MOVL $1520, CX
+	JMP  callbackasm1(SB)
+	MOVL $1521, CX
+	JMP  callbackasm1(SB)
+	MOVL $1522, CX
+	JMP  callbackasm1(SB)
+	MOVL $1523, CX
+	JMP  callbackasm1(SB)
+	MOVL $1524, CX
+	JMP  callbackasm1(SB)
+	MOVL $1525, CX
+	JMP  callbackasm1(SB)
+	MOVL $1526, CX
+	JMP  callbackasm1(SB)
+	MOVL $1527, CX
+	JMP  callbackasm1(SB)
+	MOVL $1528, CX
+	JMP  callbackasm1(SB)
+	MOVL $1529, CX
+	JMP  callbackasm1(SB)
+	MOVL $1530, CX
+	JMP  callbackasm1(SB)
+	MOVL $1531, CX
+	JMP  callbackasm1(SB)
+	MOVL $1532, CX
+	JMP  callbackasm1(SB)
+	MOVL $1533, CX
+	JMP  callbackasm1(SB)
+	MOVL $1534, CX
+	JMP  callbackasm1(SB)
+	MOVL $1535, CX
+	JMP  callbackasm1(SB)
+	MOVL $1536, CX
+	JMP  callbackasm1(SB)
+	MOVL $1537, CX
+	JMP  callbackasm1(SB)
+	MOVL $1538, CX
+	JMP  callbackasm1(SB)
+	MOVL $1539, CX
+	JMP  callbackasm1(SB)
+	MOVL $1540, CX
+	JMP  callbackasm1(SB)
+	MOVL $1541, CX
+	JMP  callbackasm1(SB)
+	MOVL $1542, CX
+	JMP  callbackasm1(SB)
+	MOVL $1543, CX
+	JMP  callbackasm1(SB)
+	MOVL $1544, CX
+	JMP  callbackasm1(SB)
+	MOVL $1545, CX
+	JMP  callbackasm1(SB)
+	MOVL $1546, CX
+	JMP  callbackasm1(SB)
+	MOVL $1547, CX
+	JMP  callbackasm1(SB)
+	MOVL $1548, CX
+	JMP  callbackasm1(SB)
+	MOVL $1549, CX
+	JMP  callbackasm1(SB)
+	MOVL $1550, CX
+	JMP  callbackasm1(SB)
+	MOVL $1551, CX
+	JMP  callbackasm1(SB)
+	MOVL $1552, CX
+	JMP  callbackasm1(SB)
+	MOVL $1553, CX
+	JMP  callbackasm1(SB)
+	MOVL $1554, CX
+	JMP  callbackasm1(SB)
+	MOVL $1555, CX
+	JMP  callbackasm1(SB)
+	MOVL $1556, CX
+	JMP  callbackasm1(SB)
+	MOVL $1557, CX
+	JMP  callbackasm1(SB)
+	MOVL $1558, CX
+	JMP  callbackasm1(SB)
+	MOVL $1559, CX
+	JMP  callbackasm1(SB)
+	MOVL $1560, CX
+	JMP  callbackasm1(SB)
+	MOVL $1561, CX
+	JMP  callbackasm1(SB)
+	MOVL $1562, CX
+	JMP  callbackasm1(SB)
+	MOVL $1563, CX
+	JMP  callbackasm1(SB)
+	MOVL $1564, CX
+	JMP  callbackasm1(SB)
+	MOVL $1565, CX
+	JMP  callbackasm1(SB)
+	MOVL $1566, CX
+	JMP  callbackasm1(SB)
+	MOVL $1567, CX
+	JMP  callbackasm1(SB)
+	MOVL $1568, CX
+	JMP  callbackasm1(SB)
+	MOVL $1569, CX
+	JMP  callbackasm1(SB)
+	MOVL $1570, CX
+	JMP  callbackasm1(SB)
+	MOVL $1571, CX
+	JMP  callbackasm1(SB)
+	MOVL $1572, CX
+	JMP  callbackasm1(SB)
+	MOVL $1573, CX
+	JMP  callbackasm1(SB)
+	MOVL $1574, CX
+	JMP  callbackasm1(SB)
+	MOVL $1575, CX
+	JMP  callbackasm1(SB)
+	MOVL $1576, CX
+	JMP  callbackasm1(SB)
+	MOVL $1577, CX
+	JMP  callbackasm1(SB)
+	MOVL $1578, CX
+	JMP  callbackasm1(SB)
+	MOVL $1579, CX
+	JMP  callbackasm1(SB)
+	MOVL $1580, CX
+	JMP  callbackasm1(SB)
+	MOVL $1581, CX
+	JMP  callbackasm1(SB)
+	MOVL $1582, CX
+	JMP  callbackasm1(SB)
+	MOVL $1583, CX
+	JMP  callbackasm1(SB)
+	MOVL $1584, CX
+	JMP  callbackasm1(SB)
+	MOVL $1585, CX
+	JMP  callbackasm1(SB)
+	MOVL $1586, CX
+	JMP  callbackasm1(SB)
+	MOVL $1587, CX
+	JMP  callbackasm1(SB)
+	MOVL $1588, CX
+	JMP  callbackasm1(SB)
+	MOVL $1589, CX
+	JMP  callbackasm1(SB)
+	MOVL $1590, CX
+	JMP  callbackasm1(SB)
+	MOVL $1591, CX
+	JMP  callbackasm1(SB)
+	MOVL $1592, CX
+	JMP  callbackasm1(SB)
+	MOVL $1593, CX
+	JMP  callbackasm1(SB)
+	MOVL $1594, CX
+	JMP  callbackasm1(SB)
+	MOVL $1595, CX
+	JMP  callbackasm1(SB)
+	MOVL $1596, CX
+	JMP  callbackasm1(SB)
+	MOVL $1597, CX
+	JMP  callbackasm1(SB)
+	MOVL $1598, CX
+	JMP  callbackasm1(SB)
+	MOVL $1599, CX
+	JMP  callbackasm1(SB)
+	MOVL $1600, CX
+	JMP  callbackasm1(SB)
+	MOVL $1601, CX
+	JMP  callbackasm1(SB)
+	MOVL $1602, CX
+	JMP  callbackasm1(SB)
+	MOVL $1603, CX
+	JMP  callbackasm1(SB)
+	MOVL $1604, CX
+	JMP  callbackasm1(SB)
+	MOVL $1605, CX
+	JMP  callbackasm1(SB)
+	MOVL $1606, CX
+	JMP  callbackasm1(SB)
+	MOVL $1607, CX
+	JMP  callbackasm1(SB)
+	MOVL $1608, CX
+	JMP  callbackasm1(SB)
+	MOVL $1609, CX
+	JMP  callbackasm1(SB)
+	MOVL $1610, CX
+	JMP  callbackasm1(SB)
+	MOVL $1611, CX
+	JMP  callbackasm1(SB)
+	MOVL $1612, CX
+	JMP  callbackasm1(SB)
+	MOVL $1613, CX
+	JMP  callbackasm1(SB)
+	MOVL $1614, CX
+	JMP  callbackasm1(SB)
+	MOVL $1615, CX
+	JMP  callbackasm1(SB)
+	MOVL $1616, CX
+	JMP  callbackasm1(SB)
+	MOVL $1617, CX
+	JMP  callbackasm1(SB)
+	MOVL $1618, CX
+	JMP  callbackasm1(SB)
+	MOVL $1619, CX
+	JMP  callbackasm1(SB)
+	MOVL $1620, CX
+	JMP  callbackasm1(SB)
+	MOVL $1621, CX
+	JMP  callbackasm1(SB)
+	MOVL $1622, CX
+	JMP  callbackasm1(SB)
+	MOVL $1623, CX
+	JMP  callbackasm1(SB)
+	MOVL $1624, CX
+	JMP  callbackasm1(SB)
+	MOVL $1625, CX
+	JMP  callbackasm1(SB)
+	MOVL $1626, CX
+	JMP  callbackasm1(SB)
+	MOVL $1627, CX
+	JMP  callbackasm1(SB)
+	MOVL $1628, CX
+	JMP  callbackasm1(SB)
+	MOVL $1629, CX
+	JMP  callbackasm1(SB)
+	MOVL $1630, CX
+	JMP  callbackasm1(SB)
+	MOVL $1631, CX
+	JMP  callbackasm1(SB)
+	MOVL $1632, CX
+	JMP  callbackasm1(SB)
+	MOVL $1633, CX
+	JMP  callbackasm1(SB)
+	MOVL $1634, CX
+	JMP  callbackasm1(SB)
+	MOVL $1635, CX
+	JMP  callbackasm1(SB)
+	MOVL $1636, CX
+	JMP  callbackasm1(SB)
+	MOVL $1637, CX
+	JMP  callbackasm1(SB)
+	MOVL $1638, CX
+	JMP  callbackasm1(SB)
+	MOVL $1639, CX
+	JMP  callbackasm1(SB)
+	MOVL $1640, CX
+	JMP  callbackasm1(SB)
+	MOVL $1641, CX
+	JMP  callbackasm1(SB)
+	MOVL $1642, CX
+	JMP  callbackasm1(SB)
+	MOVL $1643, CX
+	JMP  callbackasm1(SB)
+	MOVL $1644, CX
+	JMP  callbackasm1(SB)
+	MOVL $1645, CX
+	JMP  callbackasm1(SB)
+	MOVL $1646, CX
+	JMP  callbackasm1(SB)
+	MOVL $1647, CX
+	JMP  callbackasm1(SB)
+	MOVL $1648, CX
+	JMP  callbackasm1(SB)
+	MOVL $1649, CX
+	JMP  callbackasm1(SB)
+	MOVL $1650, CX
+	JMP  callbackasm1(SB)
+	MOVL $1651, CX
+	JMP  callbackasm1(SB)
+	MOVL $1652, CX
+	JMP  callbackasm1(SB)
+	MOVL $1653, CX
+	JMP  callbackasm1(SB)
+	MOVL $1654, CX
+	JMP  callbackasm1(SB)
+	MOVL $1655, CX
+	JMP  callbackasm1(SB)
+	MOVL $1656, CX
+	JMP  callbackasm1(SB)
+	MOVL $1657, CX
+	JMP  callbackasm1(SB)
+	MOVL $1658, CX
+	JMP  callbackasm1(SB)
+	MOVL $1659, CX
+	JMP  callbackasm1(SB)
+	MOVL $1660, CX
+	JMP  callbackasm1(SB)
+	MOVL $1661, CX
+	JMP  callbackasm1(SB)
+	MOVL $1662, CX
+	JMP  callbackasm1(SB)
+	MOVL $1663, CX
+	JMP  callbackasm1(SB)
+	MOVL $1664, CX
+	JMP  callbackasm1(SB)
+	MOVL $1665, CX
+	JMP  callbackasm1(SB)
+	MOVL $1666, CX
+	JMP  callbackasm1(SB)
+	MOVL $1667, CX
+	JMP  callbackasm1(SB)
+	MOVL $1668, CX
+	JMP  callbackasm1(SB)
+	MOVL $1669, CX
+	JMP  callbackasm1(SB)
+	MOVL $1670, CX
+	JMP  callbackasm1(SB)
+	MOVL $1671, CX
+	JMP  callbackasm1(SB)
+	MOVL $1672, CX
+	JMP  callbackasm1(SB)
+	MOVL $1673, CX
+	JMP  callbackasm1(SB)
+	MOVL $1674, CX
+	JMP  callbackasm1(SB)
+	MOVL $1675, CX
+	JMP  callbackasm1(SB)
+	MOVL $1676, CX
+	JMP  callbackasm1(SB)
+	MOVL $1677, CX
+	JMP  callbackasm1(SB)
+	MOVL $1678, CX
+	JMP  callbackasm1(SB)
+	MOVL $1679, CX
+	JMP  callbackasm1(SB)
+	MOVL $1680, CX
+	JMP  callbackasm1(SB)
+	MOVL $1681, CX
+	JMP  callbackasm1(SB)
+	MOVL $1682, CX
+	JMP  callbackasm1(SB)
+	MOVL $1683, CX
+	JMP  callbackasm1(SB)
+	MOVL $1684, CX
+	JMP  callbackasm1(SB)
+	MOVL $1685, CX
+	JMP  callbackasm1(SB)
+	MOVL $1686, CX
+	JMP  callbackasm1(SB)
+	MOVL $1687, CX
+	JMP  callbackasm1(SB)
+	MOVL $1688, CX
+	JMP  callbackasm1(SB)
+	MOVL $1689, CX
+	JMP  callbackasm1(SB)
+	MOVL $1690, CX
+	JMP  callbackasm1(SB)
+	MOVL $1691, CX
+	JMP  callbackasm1(SB)
+	MOVL $1692, CX
+	JMP  callbackasm1(SB)
+	MOVL $1693, CX
+	JMP  callbackasm1(SB)
+	MOVL $1694, CX
+	JMP  callbackasm1(SB)
+	MOVL $1695, CX
+	JMP  callbackasm1(SB)
+	MOVL $1696, CX
+	JMP  callbackasm1(SB)
+	MOVL $1697, CX
+	JMP  callbackasm1(SB)
+	MOVL $1698, CX
+	JMP  callbackasm1(SB)
+	MOVL $1699, CX
+	JMP  callbackasm1(SB)
+	MOVL $1700, CX
+	JMP  callbackasm1(SB)
+	MOVL $1701, CX
+	JMP  callbackasm1(SB)
+	MOVL $1702, CX
+	JMP  callbackasm1(SB)
+	MOVL $1703, CX
+	JMP  callbackasm1(SB)
+	MOVL $1704, CX
+	JMP  callbackasm1(SB)
+	MOVL $1705, CX
+	JMP  callbackasm1(SB)
+	MOVL $1706, CX
+	JMP  callbackasm1(SB)
+	MOVL $1707, CX
+	JMP  callbackasm1(SB)
+	MOVL $1708, CX
+	JMP  callbackasm1(SB)
+	MOVL $1709, CX
+	JMP  callbackasm1(SB)
+	MOVL $1710, CX
+	JMP  callbackasm1(SB)
+	MOVL $1711, CX
+	JMP  callbackasm1(SB)
+	MOVL $1712, CX
+	JMP  callbackasm1(SB)
+	MOVL $1713, CX
+	JMP  callbackasm1(SB)
+	MOVL $1714, CX
+	JMP  callbackasm1(SB)
+	MOVL $1715, CX
+	JMP  callbackasm1(SB)
+	MOVL $1716, CX
+	JMP  callbackasm1(SB)
+	MOVL $1717, CX
+	JMP  callbackasm1(SB)
+	MOVL $1718, CX
+	JMP  callbackasm1(SB)
+	MOVL $1719, CX
+	JMP  callbackasm1(SB)
+	MOVL $1720, CX
+	JMP  callbackasm1(SB)
+	MOVL $1721, CX
+	JMP  callbackasm1(SB)
+	MOVL $1722, CX
+	JMP  callbackasm1(SB)
+	MOVL $1723, CX
+	JMP  callbackasm1(SB)
+	MOVL $1724, CX
+	JMP  callbackasm1(SB)
+	MOVL $1725, CX
+	JMP  callbackasm1(SB)
+	MOVL $1726, CX
+	JMP  callbackasm1(SB)
+	MOVL $1727, CX
+	JMP  callbackasm1(SB)
+	MOVL $1728, CX
+	JMP  callbackasm1(SB)
+	MOVL $1729, CX
+	JMP  callbackasm1(SB)
+	MOVL $1730, CX
+	JMP  callbackasm1(SB)
+	MOVL $1731, CX
+	JMP  callbackasm1(SB)
+	MOVL $1732, CX
+	JMP  callbackasm1(SB)
+	MOVL $1733, CX
+	JMP  callbackasm1(SB)
+	MOVL $1734, CX
+	JMP  callbackasm1(SB)
+	MOVL $1735, CX
+	JMP  callbackasm1(SB)
+	MOVL $1736, CX
+	JMP  callbackasm1(SB)
+	MOVL $1737, CX
+	JMP  callbackasm1(SB)
+	MOVL $1738, CX
+	JMP  callbackasm1(SB)
+	MOVL $1739, CX
+	JMP  callbackasm1(SB)
+	MOVL $1740, CX
+	JMP  callbackasm1(SB)
+	MOVL $1741, CX
+	JMP  callbackasm1(SB)
+	MOVL $1742, CX
+	JMP  callbackasm1(SB)
+	MOVL $1743, CX
+	JMP  callbackasm1(SB)
+	MOVL $1744, CX
+	JMP  callbackasm1(SB)
+	MOVL $1745, CX
+	JMP  callbackasm1(SB)
+	MOVL $1746, CX
+	JMP  callbackasm1(SB)
+	MOVL $1747, CX
+	JMP  callbackasm1(SB)
+	MOVL $1748, CX
+	JMP  callbackasm1(SB)
+	MOVL $1749, CX
+	JMP  callbackasm1(SB)
+	MOVL $1750, CX
+	JMP  callbackasm1(SB)
+	MOVL $1751, CX
+	JMP  callbackasm1(SB)
+	MOVL $1752, CX
+	JMP  callbackasm1(SB)
+	MOVL $1753, CX
+	JMP  callbackasm1(SB)
+	MOVL $1754, CX
+	JMP  callbackasm1(SB)
+	MOVL $1755, CX
+	JMP  callbackasm1(SB)
+	MOVL $1756, CX
+	JMP  callbackasm1(SB)
+	MOVL $1757, CX
+	JMP  callbackasm1(SB)
+	MOVL $1758, CX
+	JMP  callbackasm1(SB)
+	MOVL $1759, CX
+	JMP  callbackasm1(SB)
+	MOVL $1760, CX
+	JMP  callbackasm1(SB)
+	MOVL $1761, CX
+	JMP  callbackasm1(SB)
+	MOVL $1762, CX
+	JMP  callbackasm1(SB)
+	MOVL $1763, CX
+	JMP  callbackasm1(SB)
+	MOVL $1764, CX
+	JMP  callbackasm1(SB)
+	MOVL $1765, CX
+	JMP  callbackasm1(SB)
+	MOVL $1766, CX
+	JMP  callbackasm1(SB)
+	MOVL $1767, CX
+	JMP  callbackasm1(SB)
+	MOVL $1768, CX
+	JMP  callbackasm1(SB)
+	MOVL $1769, CX
+	JMP  callbackasm1(SB)
+	MOVL $1770, CX
+	JMP  callbackasm1(SB)
+	MOVL $1771, CX
+	JMP  callbackasm1(SB)
+	MOVL $1772, CX
+	JMP  callbackasm1(SB)
+	MOVL $1773, CX
+	JMP  callbackasm1(SB)
+	MOVL $1774, CX
+	JMP  callbackasm1(SB)
+	MOVL $1775, CX
+	JMP  callbackasm1(SB)
+	MOVL $1776, CX
+	JMP  callbackasm1(SB)
+	MOVL $1777, CX
+	JMP  callbackasm1(SB)
+	MOVL $1778, CX
+	JMP  callbackasm1(SB)
+	MOVL $1779, CX
+	JMP  callbackasm1(SB)
+	MOVL $1780, CX
+	JMP  callbackasm1(SB)
+	MOVL $1781, CX
+	JMP  callbackasm1(SB)
+	MOVL $1782, CX
+	JMP  callbackasm1(SB)
+	MOVL $1783, CX
+	JMP  callbackasm1(SB)
+	MOVL $1784, CX
+	JMP  callbackasm1(SB)
+	MOVL $1785, CX
+	JMP  callbackasm1(SB)
+	MOVL $1786, CX
+	JMP  callbackasm1(SB)
+	MOVL $1787, CX
+	JMP  callbackasm1(SB)
+	MOVL $1788, CX
+	JMP  callbackasm1(SB)
+	MOVL $1789, CX
+	JMP  callbackasm1(SB)
+	MOVL $1790, CX
+	JMP  callbackasm1(SB)
+	MOVL $1791, CX
+	JMP  callbackasm1(SB)
+	MOVL $1792, CX
+	JMP  callbackasm1(SB)
+	MOVL $1793, CX
+	JMP  callbackasm1(SB)
+	MOVL $1794, CX
+	JMP  callbackasm1(SB)
+	MOVL $1795, CX
+	JMP  callbackasm1(SB)
+	MOVL $1796, CX
+	JMP  callbackasm1(SB)
+	MOVL $1797, CX
+	JMP  callbackasm1(SB)
+	MOVL $1798, CX
+	JMP  callbackasm1(SB)
+	MOVL $1799, CX
+	JMP  callbackasm1(SB)
+	MOVL $1800, CX
+	JMP  callbackasm1(SB)
+	MOVL $1801, CX
+	JMP  callbackasm1(SB)
+	MOVL $1802, CX
+	JMP  callbackasm1(SB)
+	MOVL $1803, CX
+	JMP  callbackasm1(SB)
+	MOVL $1804, CX
+	JMP  callbackasm1(SB)
+	MOVL $1805, CX
+	JMP  callbackasm1(SB)
+	MOVL $1806, CX
+	JMP  callbackasm1(SB)
+	MOVL $1807, CX
+	JMP  callbackasm1(SB)
+	MOVL $1808, CX
+	JMP  callbackasm1(SB)
+	MOVL $1809, CX
+	JMP  callbackasm1(SB)
+	MOVL $1810, CX
+	JMP  callbackasm1(SB)
+	MOVL $1811, CX
+	JMP  callbackasm1(SB)
+	MOVL $1812, CX
+	JMP  callbackasm1(SB)
+	MOVL $1813, CX
+	JMP  callbackasm1(SB)
+	MOVL $1814, CX
+	JMP  callbackasm1(SB)
+	MOVL $1815, CX
+	JMP  callbackasm1(SB)
+	MOVL $1816, CX
+	JMP  callbackasm1(SB)
+	MOVL $1817, CX
+	JMP  callbackasm1(SB)
+	MOVL $1818, CX
+	JMP  callbackasm1(SB)
+	MOVL $1819, CX
+	JMP  callbackasm1(SB)
+	MOVL $1820, CX
+	JMP  callbackasm1(SB)
+	MOVL $1821, CX
+	JMP  callbackasm1(SB)
+	MOVL $1822, CX
+	JMP  callbackasm1(SB)
+	MOVL $1823, CX
+	JMP  callbackasm1(SB)
+	MOVL $1824, CX
+	JMP  callbackasm1(SB)
+	MOVL $1825, CX
+	JMP  callbackasm1(SB)
+	MOVL $1826, CX
+	JMP  callbackasm1(SB)
+	MOVL $1827, CX
+	JMP  callbackasm1(SB)
+	MOVL $1828, CX
+	JMP  callbackasm1(SB)
+	MOVL $1829, CX
+	JMP  callbackasm1(SB)
+	MOVL $1830, CX
+	JMP  callbackasm1(SB)
+	MOVL $1831, CX
+	JMP  callbackasm1(SB)
+	MOVL $1832, CX
+	JMP  callbackasm1(SB)
+	MOVL $1833, CX
+	JMP  callbackasm1(SB)
+	MOVL $1834, CX
+	JMP  callbackasm1(SB)
+	MOVL $1835, CX
+	JMP  callbackasm1(SB)
+	MOVL $1836, CX
+	JMP  callbackasm1(SB)
+	MOVL $1837, CX
+	JMP  callbackasm1(SB)
+	MOVL $1838, CX
+	JMP  callbackasm1(SB)
+	MOVL $1839, CX
+	JMP  callbackasm1(SB)
+	MOVL $1840, CX
+	JMP  callbackasm1(SB)
+	MOVL $1841, CX
+	JMP  callbackasm1(SB)
+	MOVL $1842, CX
+	JMP  callbackasm1(SB)
+	MOVL $1843, CX
+	JMP  callbackasm1(SB)
+	MOVL $1844, CX
+	JMP  callbackasm1(SB)
+	MOVL $1845, CX
+	JMP  callbackasm1(SB)
+	MOVL $1846, CX
+	JMP  callbackasm1(SB)
+	MOVL $1847, CX
+	JMP  callbackasm1(SB)
+	MOVL $1848, CX
+	JMP  callbackasm1(SB)
+	MOVL $1849, CX
+	JMP  callbackasm1(SB)
+	MOVL $1850, CX
+	JMP  callbackasm1(SB)
+	MOVL $1851, CX
+	JMP  callbackasm1(SB)
+	MOVL $1852, CX
+	JMP  callbackasm1(SB)
+	MOVL $1853, CX
+	JMP  callbackasm1(SB)
+	MOVL $1854, CX
+	JMP  callbackasm1(SB)
+	MOVL $1855, CX
+	JMP  callbackasm1(SB)
+	MOVL $1856, CX
+	JMP  callbackasm1(SB)
+	MOVL $1857, CX
+	JMP  callbackasm1(SB)
+	MOVL $1858, CX
+	JMP  callbackasm1(SB)
+	MOVL $1859, CX
+	JMP  callbackasm1(SB)
+	MOVL $1860, CX
+	JMP  callbackasm1(SB)
+	MOVL $1861, CX
+	JMP  callbackasm1(SB)
+	MOVL $1862, CX
+	JMP  callbackasm1(SB)
+	MOVL $1863, CX
+	JMP  callbackasm1(SB)
+	MOVL $1864, CX
+	JMP  callbackasm1(SB)
+	MOVL $1865, CX
+	JMP  callbackasm1(SB)
+	MOVL $1866, CX
+	JMP  callbackasm1(SB)
+	MOVL $1867, CX
+	JMP  callbackasm1(SB)
+	MOVL $1868, CX
+	JMP  callbackasm1(SB)
+	MOVL $1869, CX
+	JMP  callbackasm1(SB)
+	MOVL $1870, CX
+	JMP  callbackasm1(SB)
+	MOVL $1871, CX
+	JMP  callbackasm1(SB)
+	MOVL $1872, CX
+	JMP  callbackasm1(SB)
+	MOVL $1873, CX
+	JMP  callbackasm1(SB)
+	MOVL $1874, CX
+	JMP  callbackasm1(SB)
+	MOVL $1875, CX
+	JMP  callbackasm1(SB)
+	MOVL $1876, CX
+	JMP  callbackasm1(SB)
+	MOVL $1877, CX
+	JMP  callbackasm1(SB)
+	MOVL $1878, CX
+	JMP  callbackasm1(SB)
+	MOVL $1879, CX
+	JMP  callbackasm1(SB)
+	MOVL $1880, CX
+	JMP  callbackasm1(SB)
+	MOVL $1881, CX
+	JMP  callbackasm1(SB)
+	MOVL $1882, CX
+	JMP  callbackasm1(SB)
+	MOVL $1883, CX
+	JMP  callbackasm1(SB)
+	MOVL $1884, CX
+	JMP  callbackasm1(SB)
+	MOVL $1885, CX
+	JMP  callbackasm1(SB)
+	MOVL $1886, CX
+	JMP  callbackasm1(SB)
+	MOVL $1887, CX
+	JMP  callbackasm1(SB)
+	MOVL $1888, CX
+	JMP  callbackasm1(SB)
+	MOVL $1889, CX
+	JMP  callbackasm1(SB)
+	MOVL $1890, CX
+	JMP  callbackasm1(SB)
+	MOVL $1891, CX
+	JMP  callbackasm1(SB)
+	MOVL $1892, CX
+	JMP  callbackasm1(SB)
+	MOVL $1893, CX
+	JMP  callbackasm1(SB)
+	MOVL $1894, CX
+	JMP  callbackasm1(SB)
+	MOVL $1895, CX
+	JMP  callbackasm1(SB)
+	MOVL $1896, CX
+	JMP  callbackasm1(SB)
+	MOVL $1897, CX
+	JMP  callbackasm1(SB)
+	MOVL $1898, CX
+	JMP  callbackasm1(SB)
+	MOVL $1899, CX
+	JMP  callbackasm1(SB)
+	MOVL $1900, CX
+	JMP  callbackasm1(SB)
+	MOVL $1901, CX
+	JMP  callbackasm1(SB)
+	MOVL $1902, CX
+	JMP  callbackasm1(SB)
+	MOVL $1903, CX
+	JMP  callbackasm1(SB)
+	MOVL $1904, CX
+	JMP  callbackasm1(SB)
+	MOVL $1905, CX
+	JMP  callbackasm1(SB)
+	MOVL $1906, CX
+	JMP  callbackasm1(SB)
+	MOVL $1907, CX
+	JMP  callbackasm1(SB)
+	MOVL $1908, CX
+	JMP  callbackasm1(SB)
+	MOVL $1909, CX
+	JMP  callbackasm1(SB)
+	MOVL $1910, CX
+	JMP  callbackasm1(SB)
+	MOVL $1911, CX
+	JMP  callbackasm1(SB)
+	MOVL $1912, CX
+	JMP  callbackasm1(SB)
+	MOVL $1913, CX
+	JMP  callbackasm1(SB)
+	MOVL $1914, CX
+	JMP  callbackasm1(SB)
+	MOVL $1915, CX
+	JMP  callbackasm1(SB)
+	MOVL $1916, CX
+	JMP  callbackasm1(SB)
+	MOVL $1917, CX
+	JMP  callbackasm1(SB)
+	MOVL $1918, CX
+	JMP  callbackasm1(SB)
+	MOVL $1919, CX
+	JMP  callbackasm1(SB)
+	MOVL $1920, CX
+	JMP  callbackasm1(SB)
+	MOVL $1921, CX
+	JMP  callbackasm1(SB)
+	MOVL $1922, CX
+	JMP  callbackasm1(SB)
+	MOVL $1923, CX
+	JMP  callbackasm1(SB)
+	MOVL $1924, CX
+	JMP  callbackasm1(SB)
+	MOVL $1925, CX
+	JMP  callbackasm1(SB)
+	MOVL $1926, CX
+	JMP  callbackasm1(SB)
+	MOVL $1927, CX
+	JMP  callbackasm1(SB)
+	MOVL $1928, CX
+	JMP  callbackasm1(SB)
+	MOVL $1929, CX
+	JMP  callbackasm1(SB)
+	MOVL $1930, CX
+	JMP  callbackasm1(SB)
+	MOVL $1931, CX
+	JMP  callbackasm1(SB)
+	MOVL $1932, CX
+	JMP  callbackasm1(SB)
+	MOVL $1933, CX
+	JMP  callbackasm1(SB)
+	MOVL $1934, CX
+	JMP  callbackasm1(SB)
+	MOVL $1935, CX
+	JMP  callbackasm1(SB)
+	MOVL $1936, CX
+	JMP  callbackasm1(SB)
+	MOVL $1937, CX
+	JMP  callbackasm1(SB)
+	MOVL $1938, CX
+	JMP  callbackasm1(SB)
+	MOVL $1939, CX
+	JMP  callbackasm1(SB)
+	MOVL $1940, CX
+	JMP  callbackasm1(SB)
+	MOVL $1941, CX
+	JMP  callbackasm1(SB)
+	MOVL $1942, CX
+	JMP  callbackasm1(SB)
+	MOVL $1943, CX
+	JMP  callbackasm1(SB)
+	MOVL $1944, CX
+	JMP  callbackasm1(SB)
+	MOVL $1945, CX
+	JMP  callbackasm1(SB)
+	MOVL $1946, CX
+	JMP  callbackasm1(SB)
+	MOVL $1947, CX
+	JMP  callbackasm1(SB)
+	MOVL $1948, CX
+	JMP  callbackasm1(SB)
+	MOVL $1949, CX
+	JMP  callbackasm1(SB)
+	MOVL $1950, CX
+	JMP  callbackasm1(SB)
+	MOVL $1951, CX
+	JMP  callbackasm1(SB)
+	MOVL $1952, CX
+	JMP  callbackasm1(SB)
+	MOVL $1953, CX
+	JMP  callbackasm1(SB)
+	MOVL $1954, CX
+	JMP  callbackasm1(SB)
+	MOVL $1955, CX
+	JMP  callbackasm1(SB)
+	MOVL $1956, CX
+	JMP  callbackasm1(SB)
+	MOVL $1957, CX
+	JMP  callbackasm1(SB)
+	MOVL $1958, CX
+	JMP  callbackasm1(SB)
+	MOVL $1959, CX
+	JMP  callbackasm1(SB)
+	MOVL $1960, CX
+	JMP  callbackasm1(SB)
+	MOVL $1961, CX
+	JMP  callbackasm1(SB)
+	MOVL $1962, CX
+	JMP  callbackasm1(SB)
+	MOVL $1963, CX
+	JMP  callbackasm1(SB)
+	MOVL $1964, CX
+	JMP  callbackasm1(SB)
+	MOVL $1965, CX
+	JMP  callbackasm1(SB)
+	MOVL $1966, CX
+	JMP  callbackasm1(SB)
+	MOVL $1967, CX
+	JMP  callbackasm1(SB)
+	MOVL $1968, CX
+	JMP  callbackasm1(SB)
+	MOVL $1969, CX
+	JMP  callbackasm1(SB)
+	MOVL $1970, CX
+	JMP  callbackasm1(SB)
+	MOVL $1971, CX
+	JMP  callbackasm1(SB)
+	MOVL $1972, CX
+	JMP  callbackasm1(SB)
+	MOVL $1973, CX
+	JMP  callbackasm1(SB)
+	MOVL $1974, CX
+	JMP  callbackasm1(SB)
+	MOVL $1975, CX
+	JMP  callbackasm1(SB)
+	MOVL $1976, CX
+	JMP  callbackasm1(SB)
+	MOVL $1977, CX
+	JMP  callbackasm1(SB)
+	MOVL $1978, CX
+	JMP  callbackasm1(SB)
+	MOVL $1979, CX
+	JMP  callbackasm1(SB)
+	MOVL $1980, CX
+	JMP  callbackasm1(SB)
+	MOVL $1981, CX
+	JMP  callbackasm1(SB)
+	MOVL $1982, CX
+	JMP  callbackasm1(SB)
+	MOVL $1983, CX
+	JMP  callbackasm1(SB)
+	MOVL $1984, CX
+	JMP  callbackasm1(SB)
+	MOVL $1985, CX
+	JMP  callbackasm1(SB)
+	MOVL $1986, CX
+	JMP  callbackasm1(SB)
+	MOVL $1987, CX
+	JMP  callbackasm1(SB)
+	MOVL $1988, CX
+	JMP  callbackasm1(SB)
+	MOVL $1989, CX
+	JMP  callbackasm1(SB)
+	MOVL $1990, CX
+	JMP  callbackasm1(SB)
+	MOVL $1991, CX
+	JMP  callbackasm1(SB)
+	MOVL $1992, CX
+	JMP  callbackasm1(SB)
+	MOVL $1993, CX
+	JMP  callbackasm1(SB)
+	MOVL $1994, CX
+	JMP  callbackasm1(SB)
+	MOVL $1995, CX
+	JMP  callbackasm1(SB)
+	MOVL $1996, CX
+	JMP  callbackasm1(SB)
+	MOVL $1997, CX
+	JMP  callbackasm1(SB)
+	MOVL $1998, CX
+	JMP  callbackasm1(SB)
+	MOVL $1999, CX
+	JMP  callbackasm1(SB)
diff --git a/vendor/github.com/ebitengine/purego/zcallback_amd64.s b/vendor/github.com/ebitengine/purego/zcallback_amd64.s
new file mode 100644
index 000000000..b2da02255
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/zcallback_amd64.s
@@ -0,0 +1,2014 @@
+// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+
+//go:build darwin || freebsd || linux || netbsd
+
+// runtime·callbackasm is called by external code to
+// execute Go implemented callback function. It is not
+// called from the start, instead runtime·compilecallback
+// always returns address into runtime·callbackasm offset
+// appropriately so different callbacks start with different
+// CALL instruction in runtime·callbackasm. This determines
+// which Go callback function is executed later on.
+#include "textflag.h"
+
+TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
+	CALL callbackasm1(SB)
diff --git a/vendor/github.com/ebitengine/purego/zcallback_arm.s b/vendor/github.com/ebitengine/purego/zcallback_arm.s
new file mode 100644
index 000000000..d969d81d0
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/zcallback_arm.s
@@ -0,0 +1,4014 @@
+// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+
+//go:build linux
+
+// External code calls into callbackasm at an offset corresponding
+// to the callback index. Callbackasm is a table of MOVW and B instructions.
+// The MOVW instruction loads R12 with the callback index, and the
+// B instruction branches to callbackasm1.
+// callbackasm1 takes the callback index from R12 and
+// indexes into an array that stores information about each callback.
+// It then calls the Go implementation for that callback.
+#include "textflag.h"
+
+TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
+	MOVW $0, R12
+	B    callbackasm1(SB)
+	MOVW $1, R12
+	B    callbackasm1(SB)
+	MOVW $2, R12
+	B    callbackasm1(SB)
+	MOVW $3, R12
+	B    callbackasm1(SB)
+	MOVW $4, R12
+	B    callbackasm1(SB)
+	MOVW $5, R12
+	B    callbackasm1(SB)
+	MOVW $6, R12
+	B    callbackasm1(SB)
+	MOVW $7, R12
+	B    callbackasm1(SB)
+	MOVW $8, R12
+	B    callbackasm1(SB)
+	MOVW $9, R12
+	B    callbackasm1(SB)
+	MOVW $10, R12
+	B    callbackasm1(SB)
+	MOVW $11, R12
+	B    callbackasm1(SB)
+	MOVW $12, R12
+	B    callbackasm1(SB)
+	MOVW $13, R12
+	B    callbackasm1(SB)
+	MOVW $14, R12
+	B    callbackasm1(SB)
+	MOVW $15, R12
+	B    callbackasm1(SB)
+	MOVW $16, R12
+	B    callbackasm1(SB)
+	MOVW $17, R12
+	B    callbackasm1(SB)
+	MOVW $18, R12
+	B    callbackasm1(SB)
+	MOVW $19, R12
+	B    callbackasm1(SB)
+	MOVW $20, R12
+	B    callbackasm1(SB)
+	MOVW $21, R12
+	B    callbackasm1(SB)
+	MOVW $22, R12
+	B    callbackasm1(SB)
+	MOVW $23, R12
+	B    callbackasm1(SB)
+	MOVW $24, R12
+	B    callbackasm1(SB)
+	MOVW $25, R12
+	B    callbackasm1(SB)
+	MOVW $26, R12
+	B    callbackasm1(SB)
+	MOVW $27, R12
+	B    callbackasm1(SB)
+	MOVW $28, R12
+	B    callbackasm1(SB)
+	MOVW $29, R12
+	B    callbackasm1(SB)
+	MOVW $30, R12
+	B    callbackasm1(SB)
+	MOVW $31, R12
+	B    callbackasm1(SB)
+	MOVW $32, R12
+	B    callbackasm1(SB)
+	MOVW $33, R12
+	B    callbackasm1(SB)
+	MOVW $34, R12
+	B    callbackasm1(SB)
+	MOVW $35, R12
+	B    callbackasm1(SB)
+	MOVW $36, R12
+	B    callbackasm1(SB)
+	MOVW $37, R12
+	B    callbackasm1(SB)
+	MOVW $38, R12
+	B    callbackasm1(SB)
+	MOVW $39, R12
+	B    callbackasm1(SB)
+	MOVW $40, R12
+	B    callbackasm1(SB)
+	MOVW $41, R12
+	B    callbackasm1(SB)
+	MOVW $42, R12
+	B    callbackasm1(SB)
+	MOVW $43, R12
+	B    callbackasm1(SB)
+	MOVW $44, R12
+	B    callbackasm1(SB)
+	MOVW $45, R12
+	B    callbackasm1(SB)
+	MOVW $46, R12
+	B    callbackasm1(SB)
+	MOVW $47, R12
+	B    callbackasm1(SB)
+	MOVW $48, R12
+	B    callbackasm1(SB)
+	MOVW $49, R12
+	B    callbackasm1(SB)
+	MOVW $50, R12
+	B    callbackasm1(SB)
+	MOVW $51, R12
+	B    callbackasm1(SB)
+	MOVW $52, R12
+	B    callbackasm1(SB)
+	MOVW $53, R12
+	B    callbackasm1(SB)
+	MOVW $54, R12
+	B    callbackasm1(SB)
+	MOVW $55, R12
+	B    callbackasm1(SB)
+	MOVW $56, R12
+	B    callbackasm1(SB)
+	MOVW $57, R12
+	B    callbackasm1(SB)
+	MOVW $58, R12
+	B    callbackasm1(SB)
+	MOVW $59, R12
+	B    callbackasm1(SB)
+	MOVW $60, R12
+	B    callbackasm1(SB)
+	MOVW $61, R12
+	B    callbackasm1(SB)
+	MOVW $62, R12
+	B    callbackasm1(SB)
+	MOVW $63, R12
+	B    callbackasm1(SB)
+	MOVW $64, R12
+	B    callbackasm1(SB)
+	MOVW $65, R12
+	B    callbackasm1(SB)
+	MOVW $66, R12
+	B    callbackasm1(SB)
+	MOVW $67, R12
+	B    callbackasm1(SB)
+	MOVW $68, R12
+	B    callbackasm1(SB)
+	MOVW $69, R12
+	B    callbackasm1(SB)
+	MOVW $70, R12
+	B    callbackasm1(SB)
+	MOVW $71, R12
+	B    callbackasm1(SB)
+	MOVW $72, R12
+	B    callbackasm1(SB)
+	MOVW $73, R12
+	B    callbackasm1(SB)
+	MOVW $74, R12
+	B    callbackasm1(SB)
+	MOVW $75, R12
+	B    callbackasm1(SB)
+	MOVW $76, R12
+	B    callbackasm1(SB)
+	MOVW $77, R12
+	B    callbackasm1(SB)
+	MOVW $78, R12
+	B    callbackasm1(SB)
+	MOVW $79, R12
+	B    callbackasm1(SB)
+	MOVW $80, R12
+	B    callbackasm1(SB)
+	MOVW $81, R12
+	B    callbackasm1(SB)
+	MOVW $82, R12
+	B    callbackasm1(SB)
+	MOVW $83, R12
+	B    callbackasm1(SB)
+	MOVW $84, R12
+	B    callbackasm1(SB)
+	MOVW $85, R12
+	B    callbackasm1(SB)
+	MOVW $86, R12
+	B    callbackasm1(SB)
+	MOVW $87, R12
+	B    callbackasm1(SB)
+	MOVW $88, R12
+	B    callbackasm1(SB)
+	MOVW $89, R12
+	B    callbackasm1(SB)
+	MOVW $90, R12
+	B    callbackasm1(SB)
+	MOVW $91, R12
+	B    callbackasm1(SB)
+	MOVW $92, R12
+	B    callbackasm1(SB)
+	MOVW $93, R12
+	B    callbackasm1(SB)
+	MOVW $94, R12
+	B    callbackasm1(SB)
+	MOVW $95, R12
+	B    callbackasm1(SB)
+	MOVW $96, R12
+	B    callbackasm1(SB)
+	MOVW $97, R12
+	B    callbackasm1(SB)
+	MOVW $98, R12
+	B    callbackasm1(SB)
+	MOVW $99, R12
+	B    callbackasm1(SB)
+	MOVW $100, R12
+	B    callbackasm1(SB)
+	MOVW $101, R12
+	B    callbackasm1(SB)
+	MOVW $102, R12
+	B    callbackasm1(SB)
+	MOVW $103, R12
+	B    callbackasm1(SB)
+	MOVW $104, R12
+	B    callbackasm1(SB)
+	MOVW $105, R12
+	B    callbackasm1(SB)
+	MOVW $106, R12
+	B    callbackasm1(SB)
+	MOVW $107, R12
+	B    callbackasm1(SB)
+	MOVW $108, R12
+	B    callbackasm1(SB)
+	MOVW $109, R12
+	B    callbackasm1(SB)
+	MOVW $110, R12
+	B    callbackasm1(SB)
+	MOVW $111, R12
+	B    callbackasm1(SB)
+	MOVW $112, R12
+	B    callbackasm1(SB)
+	MOVW $113, R12
+	B    callbackasm1(SB)
+	MOVW $114, R12
+	B    callbackasm1(SB)
+	MOVW $115, R12
+	B    callbackasm1(SB)
+	MOVW $116, R12
+	B    callbackasm1(SB)
+	MOVW $117, R12
+	B    callbackasm1(SB)
+	MOVW $118, R12
+	B    callbackasm1(SB)
+	MOVW $119, R12
+	B    callbackasm1(SB)
+	MOVW $120, R12
+	B    callbackasm1(SB)
+	MOVW $121, R12
+	B    callbackasm1(SB)
+	MOVW $122, R12
+	B    callbackasm1(SB)
+	MOVW $123, R12
+	B    callbackasm1(SB)
+	MOVW $124, R12
+	B    callbackasm1(SB)
+	MOVW $125, R12
+	B    callbackasm1(SB)
+	MOVW $126, R12
+	B    callbackasm1(SB)
+	MOVW $127, R12
+	B    callbackasm1(SB)
+	MOVW $128, R12
+	B    callbackasm1(SB)
+	MOVW $129, R12
+	B    callbackasm1(SB)
+	MOVW $130, R12
+	B    callbackasm1(SB)
+	MOVW $131, R12
+	B    callbackasm1(SB)
+	MOVW $132, R12
+	B    callbackasm1(SB)
+	MOVW $133, R12
+	B    callbackasm1(SB)
+	MOVW $134, R12
+	B    callbackasm1(SB)
+	MOVW $135, R12
+	B    callbackasm1(SB)
+	MOVW $136, R12
+	B    callbackasm1(SB)
+	MOVW $137, R12
+	B    callbackasm1(SB)
+	MOVW $138, R12
+	B    callbackasm1(SB)
+	MOVW $139, R12
+	B    callbackasm1(SB)
+	MOVW $140, R12
+	B    callbackasm1(SB)
+	MOVW $141, R12
+	B    callbackasm1(SB)
+	MOVW $142, R12
+	B    callbackasm1(SB)
+	MOVW $143, R12
+	B    callbackasm1(SB)
+	MOVW $144, R12
+	B    callbackasm1(SB)
+	MOVW $145, R12
+	B    callbackasm1(SB)
+	MOVW $146, R12
+	B    callbackasm1(SB)
+	MOVW $147, R12
+	B    callbackasm1(SB)
+	MOVW $148, R12
+	B    callbackasm1(SB)
+	MOVW $149, R12
+	B    callbackasm1(SB)
+	MOVW $150, R12
+	B    callbackasm1(SB)
+	MOVW $151, R12
+	B    callbackasm1(SB)
+	MOVW $152, R12
+	B    callbackasm1(SB)
+	MOVW $153, R12
+	B    callbackasm1(SB)
+	MOVW $154, R12
+	B    callbackasm1(SB)
+	MOVW $155, R12
+	B    callbackasm1(SB)
+	MOVW $156, R12
+	B    callbackasm1(SB)
+	MOVW $157, R12
+	B    callbackasm1(SB)
+	MOVW $158, R12
+	B    callbackasm1(SB)
+	MOVW $159, R12
+	B    callbackasm1(SB)
+	MOVW $160, R12
+	B    callbackasm1(SB)
+	MOVW $161, R12
+	B    callbackasm1(SB)
+	MOVW $162, R12
+	B    callbackasm1(SB)
+	MOVW $163, R12
+	B    callbackasm1(SB)
+	MOVW $164, R12
+	B    callbackasm1(SB)
+	MOVW $165, R12
+	B    callbackasm1(SB)
+	MOVW $166, R12
+	B    callbackasm1(SB)
+	MOVW $167, R12
+	B    callbackasm1(SB)
+	MOVW $168, R12
+	B    callbackasm1(SB)
+	MOVW $169, R12
+	B    callbackasm1(SB)
+	MOVW $170, R12
+	B    callbackasm1(SB)
+	MOVW $171, R12
+	B    callbackasm1(SB)
+	MOVW $172, R12
+	B    callbackasm1(SB)
+	MOVW $173, R12
+	B    callbackasm1(SB)
+	MOVW $174, R12
+	B    callbackasm1(SB)
+	MOVW $175, R12
+	B    callbackasm1(SB)
+	MOVW $176, R12
+	B    callbackasm1(SB)
+	MOVW $177, R12
+	B    callbackasm1(SB)
+	MOVW $178, R12
+	B    callbackasm1(SB)
+	MOVW $179, R12
+	B    callbackasm1(SB)
+	MOVW $180, R12
+	B    callbackasm1(SB)
+	MOVW $181, R12
+	B    callbackasm1(SB)
+	MOVW $182, R12
+	B    callbackasm1(SB)
+	MOVW $183, R12
+	B    callbackasm1(SB)
+	MOVW $184, R12
+	B    callbackasm1(SB)
+	MOVW $185, R12
+	B    callbackasm1(SB)
+	MOVW $186, R12
+	B    callbackasm1(SB)
+	MOVW $187, R12
+	B    callbackasm1(SB)
+	MOVW $188, R12
+	B    callbackasm1(SB)
+	MOVW $189, R12
+	B    callbackasm1(SB)
+	MOVW $190, R12
+	B    callbackasm1(SB)
+	MOVW $191, R12
+	B    callbackasm1(SB)
+	MOVW $192, R12
+	B    callbackasm1(SB)
+	MOVW $193, R12
+	B    callbackasm1(SB)
+	MOVW $194, R12
+	B    callbackasm1(SB)
+	MOVW $195, R12
+	B    callbackasm1(SB)
+	MOVW $196, R12
+	B    callbackasm1(SB)
+	MOVW $197, R12
+	B    callbackasm1(SB)
+	MOVW $198, R12
+	B    callbackasm1(SB)
+	MOVW $199, R12
+	B    callbackasm1(SB)
+	MOVW $200, R12
+	B    callbackasm1(SB)
+	MOVW $201, R12
+	B    callbackasm1(SB)
+	MOVW $202, R12
+	B    callbackasm1(SB)
+	MOVW $203, R12
+	B    callbackasm1(SB)
+	MOVW $204, R12
+	B    callbackasm1(SB)
+	MOVW $205, R12
+	B    callbackasm1(SB)
+	MOVW $206, R12
+	B    callbackasm1(SB)
+	MOVW $207, R12
+	B    callbackasm1(SB)
+	MOVW $208, R12
+	B    callbackasm1(SB)
+	MOVW $209, R12
+	B    callbackasm1(SB)
+	MOVW $210, R12
+	B    callbackasm1(SB)
+	MOVW $211, R12
+	B    callbackasm1(SB)
+	MOVW $212, R12
+	B    callbackasm1(SB)
+	MOVW $213, R12
+	B    callbackasm1(SB)
+	MOVW $214, R12
+	B    callbackasm1(SB)
+	MOVW $215, R12
+	B    callbackasm1(SB)
+	MOVW $216, R12
+	B    callbackasm1(SB)
+	MOVW $217, R12
+	B    callbackasm1(SB)
+	MOVW $218, R12
+	B    callbackasm1(SB)
+	MOVW $219, R12
+	B    callbackasm1(SB)
+	MOVW $220, R12
+	B    callbackasm1(SB)
+	MOVW $221, R12
+	B    callbackasm1(SB)
+	MOVW $222, R12
+	B    callbackasm1(SB)
+	MOVW $223, R12
+	B    callbackasm1(SB)
+	MOVW $224, R12
+	B    callbackasm1(SB)
+	MOVW $225, R12
+	B    callbackasm1(SB)
+	MOVW $226, R12
+	B    callbackasm1(SB)
+	MOVW $227, R12
+	B    callbackasm1(SB)
+	MOVW $228, R12
+	B    callbackasm1(SB)
+	MOVW $229, R12
+	B    callbackasm1(SB)
+	MOVW $230, R12
+	B    callbackasm1(SB)
+	MOVW $231, R12
+	B    callbackasm1(SB)
+	MOVW $232, R12
+	B    callbackasm1(SB)
+	MOVW $233, R12
+	B    callbackasm1(SB)
+	MOVW $234, R12
+	B    callbackasm1(SB)
+	MOVW $235, R12
+	B    callbackasm1(SB)
+	MOVW $236, R12
+	B    callbackasm1(SB)
+	MOVW $237, R12
+	B    callbackasm1(SB)
+	MOVW $238, R12
+	B    callbackasm1(SB)
+	MOVW $239, R12
+	B    callbackasm1(SB)
+	MOVW $240, R12
+	B    callbackasm1(SB)
+	MOVW $241, R12
+	B    callbackasm1(SB)
+	MOVW $242, R12
+	B    callbackasm1(SB)
+	MOVW $243, R12
+	B    callbackasm1(SB)
+	MOVW $244, R12
+	B    callbackasm1(SB)
+	MOVW $245, R12
+	B    callbackasm1(SB)
+	MOVW $246, R12
+	B    callbackasm1(SB)
+	MOVW $247, R12
+	B    callbackasm1(SB)
+	MOVW $248, R12
+	B    callbackasm1(SB)
+	MOVW $249, R12
+	B    callbackasm1(SB)
+	MOVW $250, R12
+	B    callbackasm1(SB)
+	MOVW $251, R12
+	B    callbackasm1(SB)
+	MOVW $252, R12
+	B    callbackasm1(SB)
+	MOVW $253, R12
+	B    callbackasm1(SB)
+	MOVW $254, R12
+	B    callbackasm1(SB)
+	MOVW $255, R12
+	B    callbackasm1(SB)
+	MOVW $256, R12
+	B    callbackasm1(SB)
+	MOVW $257, R12
+	B    callbackasm1(SB)
+	MOVW $258, R12
+	B    callbackasm1(SB)
+	MOVW $259, R12
+	B    callbackasm1(SB)
+	MOVW $260, R12
+	B    callbackasm1(SB)
+	MOVW $261, R12
+	B    callbackasm1(SB)
+	MOVW $262, R12
+	B    callbackasm1(SB)
+	MOVW $263, R12
+	B    callbackasm1(SB)
+	MOVW $264, R12
+	B    callbackasm1(SB)
+	MOVW $265, R12
+	B    callbackasm1(SB)
+	MOVW $266, R12
+	B    callbackasm1(SB)
+	MOVW $267, R12
+	B    callbackasm1(SB)
+	MOVW $268, R12
+	B    callbackasm1(SB)
+	MOVW $269, R12
+	B    callbackasm1(SB)
+	MOVW $270, R12
+	B    callbackasm1(SB)
+	MOVW $271, R12
+	B    callbackasm1(SB)
+	MOVW $272, R12
+	B    callbackasm1(SB)
+	MOVW $273, R12
+	B    callbackasm1(SB)
+	MOVW $274, R12
+	B    callbackasm1(SB)
+	MOVW $275, R12
+	B    callbackasm1(SB)
+	MOVW $276, R12
+	B    callbackasm1(SB)
+	MOVW $277, R12
+	B    callbackasm1(SB)
+	MOVW $278, R12
+	B    callbackasm1(SB)
+	MOVW $279, R12
+	B    callbackasm1(SB)
+	MOVW $280, R12
+	B    callbackasm1(SB)
+	MOVW $281, R12
+	B    callbackasm1(SB)
+	MOVW $282, R12
+	B    callbackasm1(SB)
+	MOVW $283, R12
+	B    callbackasm1(SB)
+	MOVW $284, R12
+	B    callbackasm1(SB)
+	MOVW $285, R12
+	B    callbackasm1(SB)
+	MOVW $286, R12
+	B    callbackasm1(SB)
+	MOVW $287, R12
+	B    callbackasm1(SB)
+	MOVW $288, R12
+	B    callbackasm1(SB)
+	MOVW $289, R12
+	B    callbackasm1(SB)
+	MOVW $290, R12
+	B    callbackasm1(SB)
+	MOVW $291, R12
+	B    callbackasm1(SB)
+	MOVW $292, R12
+	B    callbackasm1(SB)
+	MOVW $293, R12
+	B    callbackasm1(SB)
+	MOVW $294, R12
+	B    callbackasm1(SB)
+	MOVW $295, R12
+	B    callbackasm1(SB)
+	MOVW $296, R12
+	B    callbackasm1(SB)
+	MOVW $297, R12
+	B    callbackasm1(SB)
+	MOVW $298, R12
+	B    callbackasm1(SB)
+	MOVW $299, R12
+	B    callbackasm1(SB)
+	MOVW $300, R12
+	B    callbackasm1(SB)
+	MOVW $301, R12
+	B    callbackasm1(SB)
+	MOVW $302, R12
+	B    callbackasm1(SB)
+	MOVW $303, R12
+	B    callbackasm1(SB)
+	MOVW $304, R12
+	B    callbackasm1(SB)
+	MOVW $305, R12
+	B    callbackasm1(SB)
+	MOVW $306, R12
+	B    callbackasm1(SB)
+	MOVW $307, R12
+	B    callbackasm1(SB)
+	MOVW $308, R12
+	B    callbackasm1(SB)
+	MOVW $309, R12
+	B    callbackasm1(SB)
+	MOVW $310, R12
+	B    callbackasm1(SB)
+	MOVW $311, R12
+	B    callbackasm1(SB)
+	MOVW $312, R12
+	B    callbackasm1(SB)
+	MOVW $313, R12
+	B    callbackasm1(SB)
+	MOVW $314, R12
+	B    callbackasm1(SB)
+	MOVW $315, R12
+	B    callbackasm1(SB)
+	MOVW $316, R12
+	B    callbackasm1(SB)
+	MOVW $317, R12
+	B    callbackasm1(SB)
+	MOVW $318, R12
+	B    callbackasm1(SB)
+	MOVW $319, R12
+	B    callbackasm1(SB)
+	MOVW $320, R12
+	B    callbackasm1(SB)
+	MOVW $321, R12
+	B    callbackasm1(SB)
+	MOVW $322, R12
+	B    callbackasm1(SB)
+	MOVW $323, R12
+	B    callbackasm1(SB)
+	MOVW $324, R12
+	B    callbackasm1(SB)
+	MOVW $325, R12
+	B    callbackasm1(SB)
+	MOVW $326, R12
+	B    callbackasm1(SB)
+	MOVW $327, R12
+	B    callbackasm1(SB)
+	MOVW $328, R12
+	B    callbackasm1(SB)
+	MOVW $329, R12
+	B    callbackasm1(SB)
+	MOVW $330, R12
+	B    callbackasm1(SB)
+	MOVW $331, R12
+	B    callbackasm1(SB)
+	MOVW $332, R12
+	B    callbackasm1(SB)
+	MOVW $333, R12
+	B    callbackasm1(SB)
+	MOVW $334, R12
+	B    callbackasm1(SB)
+	MOVW $335, R12
+	B    callbackasm1(SB)
+	MOVW $336, R12
+	B    callbackasm1(SB)
+	MOVW $337, R12
+	B    callbackasm1(SB)
+	MOVW $338, R12
+	B    callbackasm1(SB)
+	MOVW $339, R12
+	B    callbackasm1(SB)
+	MOVW $340, R12
+	B    callbackasm1(SB)
+	MOVW $341, R12
+	B    callbackasm1(SB)
+	MOVW $342, R12
+	B    callbackasm1(SB)
+	MOVW $343, R12
+	B    callbackasm1(SB)
+	MOVW $344, R12
+	B    callbackasm1(SB)
+	MOVW $345, R12
+	B    callbackasm1(SB)
+	MOVW $346, R12
+	B    callbackasm1(SB)
+	MOVW $347, R12
+	B    callbackasm1(SB)
+	MOVW $348, R12
+	B    callbackasm1(SB)
+	MOVW $349, R12
+	B    callbackasm1(SB)
+	MOVW $350, R12
+	B    callbackasm1(SB)
+	MOVW $351, R12
+	B    callbackasm1(SB)
+	MOVW $352, R12
+	B    callbackasm1(SB)
+	MOVW $353, R12
+	B    callbackasm1(SB)
+	MOVW $354, R12
+	B    callbackasm1(SB)
+	MOVW $355, R12
+	B    callbackasm1(SB)
+	MOVW $356, R12
+	B    callbackasm1(SB)
+	MOVW $357, R12
+	B    callbackasm1(SB)
+	MOVW $358, R12
+	B    callbackasm1(SB)
+	MOVW $359, R12
+	B    callbackasm1(SB)
+	MOVW $360, R12
+	B    callbackasm1(SB)
+	MOVW $361, R12
+	B    callbackasm1(SB)
+	MOVW $362, R12
+	B    callbackasm1(SB)
+	MOVW $363, R12
+	B    callbackasm1(SB)
+	MOVW $364, R12
+	B    callbackasm1(SB)
+	MOVW $365, R12
+	B    callbackasm1(SB)
+	MOVW $366, R12
+	B    callbackasm1(SB)
+	MOVW $367, R12
+	B    callbackasm1(SB)
+	MOVW $368, R12
+	B    callbackasm1(SB)
+	MOVW $369, R12
+	B    callbackasm1(SB)
+	MOVW $370, R12
+	B    callbackasm1(SB)
+	MOVW $371, R12
+	B    callbackasm1(SB)
+	MOVW $372, R12
+	B    callbackasm1(SB)
+	MOVW $373, R12
+	B    callbackasm1(SB)
+	MOVW $374, R12
+	B    callbackasm1(SB)
+	MOVW $375, R12
+	B    callbackasm1(SB)
+	MOVW $376, R12
+	B    callbackasm1(SB)
+	MOVW $377, R12
+	B    callbackasm1(SB)
+	MOVW $378, R12
+	B    callbackasm1(SB)
+	MOVW $379, R12
+	B    callbackasm1(SB)
+	MOVW $380, R12
+	B    callbackasm1(SB)
+	MOVW $381, R12
+	B    callbackasm1(SB)
+	MOVW $382, R12
+	B    callbackasm1(SB)
+	MOVW $383, R12
+	B    callbackasm1(SB)
+	MOVW $384, R12
+	B    callbackasm1(SB)
+	MOVW $385, R12
+	B    callbackasm1(SB)
+	MOVW $386, R12
+	B    callbackasm1(SB)
+	MOVW $387, R12
+	B    callbackasm1(SB)
+	MOVW $388, R12
+	B    callbackasm1(SB)
+	MOVW $389, R12
+	B    callbackasm1(SB)
+	MOVW $390, R12
+	B    callbackasm1(SB)
+	MOVW $391, R12
+	B    callbackasm1(SB)
+	MOVW $392, R12
+	B    callbackasm1(SB)
+	MOVW $393, R12
+	B    callbackasm1(SB)
+	MOVW $394, R12
+	B    callbackasm1(SB)
+	MOVW $395, R12
+	B    callbackasm1(SB)
+	MOVW $396, R12
+	B    callbackasm1(SB)
+	MOVW $397, R12
+	B    callbackasm1(SB)
+	MOVW $398, R12
+	B    callbackasm1(SB)
+	MOVW $399, R12
+	B    callbackasm1(SB)
+	MOVW $400, R12
+	B    callbackasm1(SB)
+	MOVW $401, R12
+	B    callbackasm1(SB)
+	MOVW $402, R12
+	B    callbackasm1(SB)
+	MOVW $403, R12
+	B    callbackasm1(SB)
+	MOVW $404, R12
+	B    callbackasm1(SB)
+	MOVW $405, R12
+	B    callbackasm1(SB)
+	MOVW $406, R12
+	B    callbackasm1(SB)
+	MOVW $407, R12
+	B    callbackasm1(SB)
+	MOVW $408, R12
+	B    callbackasm1(SB)
+	MOVW $409, R12
+	B    callbackasm1(SB)
+	MOVW $410, R12
+	B    callbackasm1(SB)
+	MOVW $411, R12
+	B    callbackasm1(SB)
+	MOVW $412, R12
+	B    callbackasm1(SB)
+	MOVW $413, R12
+	B    callbackasm1(SB)
+	MOVW $414, R12
+	B    callbackasm1(SB)
+	MOVW $415, R12
+	B    callbackasm1(SB)
+	MOVW $416, R12
+	B    callbackasm1(SB)
+	MOVW $417, R12
+	B    callbackasm1(SB)
+	MOVW $418, R12
+	B    callbackasm1(SB)
+	MOVW $419, R12
+	B    callbackasm1(SB)
+	MOVW $420, R12
+	B    callbackasm1(SB)
+	MOVW $421, R12
+	B    callbackasm1(SB)
+	MOVW $422, R12
+	B    callbackasm1(SB)
+	MOVW $423, R12
+	B    callbackasm1(SB)
+	MOVW $424, R12
+	B    callbackasm1(SB)
+	MOVW $425, R12
+	B    callbackasm1(SB)
+	MOVW $426, R12
+	B    callbackasm1(SB)
+	MOVW $427, R12
+	B    callbackasm1(SB)
+	MOVW $428, R12
+	B    callbackasm1(SB)
+	MOVW $429, R12
+	B    callbackasm1(SB)
+	MOVW $430, R12
+	B    callbackasm1(SB)
+	MOVW $431, R12
+	B    callbackasm1(SB)
+	MOVW $432, R12
+	B    callbackasm1(SB)
+	MOVW $433, R12
+	B    callbackasm1(SB)
+	MOVW $434, R12
+	B    callbackasm1(SB)
+	MOVW $435, R12
+	B    callbackasm1(SB)
+	MOVW $436, R12
+	B    callbackasm1(SB)
+	MOVW $437, R12
+	B    callbackasm1(SB)
+	MOVW $438, R12
+	B    callbackasm1(SB)
+	MOVW $439, R12
+	B    callbackasm1(SB)
+	MOVW $440, R12
+	B    callbackasm1(SB)
+	MOVW $441, R12
+	B    callbackasm1(SB)
+	MOVW $442, R12
+	B    callbackasm1(SB)
+	MOVW $443, R12
+	B    callbackasm1(SB)
+	MOVW $444, R12
+	B    callbackasm1(SB)
+	MOVW $445, R12
+	B    callbackasm1(SB)
+	MOVW $446, R12
+	B    callbackasm1(SB)
+	MOVW $447, R12
+	B    callbackasm1(SB)
+	MOVW $448, R12
+	B    callbackasm1(SB)
+	MOVW $449, R12
+	B    callbackasm1(SB)
+	MOVW $450, R12
+	B    callbackasm1(SB)
+	MOVW $451, R12
+	B    callbackasm1(SB)
+	MOVW $452, R12
+	B    callbackasm1(SB)
+	MOVW $453, R12
+	B    callbackasm1(SB)
+	MOVW $454, R12
+	B    callbackasm1(SB)
+	MOVW $455, R12
+	B    callbackasm1(SB)
+	MOVW $456, R12
+	B    callbackasm1(SB)
+	MOVW $457, R12
+	B    callbackasm1(SB)
+	MOVW $458, R12
+	B    callbackasm1(SB)
+	MOVW $459, R12
+	B    callbackasm1(SB)
+	MOVW $460, R12
+	B    callbackasm1(SB)
+	MOVW $461, R12
+	B    callbackasm1(SB)
+	MOVW $462, R12
+	B    callbackasm1(SB)
+	MOVW $463, R12
+	B    callbackasm1(SB)
+	MOVW $464, R12
+	B    callbackasm1(SB)
+	MOVW $465, R12
+	B    callbackasm1(SB)
+	MOVW $466, R12
+	B    callbackasm1(SB)
+	MOVW $467, R12
+	B    callbackasm1(SB)
+	MOVW $468, R12
+	B    callbackasm1(SB)
+	MOVW $469, R12
+	B    callbackasm1(SB)
+	MOVW $470, R12
+	B    callbackasm1(SB)
+	MOVW $471, R12
+	B    callbackasm1(SB)
+	MOVW $472, R12
+	B    callbackasm1(SB)
+	MOVW $473, R12
+	B    callbackasm1(SB)
+	MOVW $474, R12
+	B    callbackasm1(SB)
+	MOVW $475, R12
+	B    callbackasm1(SB)
+	MOVW $476, R12
+	B    callbackasm1(SB)
+	MOVW $477, R12
+	B    callbackasm1(SB)
+	MOVW $478, R12
+	B    callbackasm1(SB)
+	MOVW $479, R12
+	B    callbackasm1(SB)
+	MOVW $480, R12
+	B    callbackasm1(SB)
+	MOVW $481, R12
+	B    callbackasm1(SB)
+	MOVW $482, R12
+	B    callbackasm1(SB)
+	MOVW $483, R12
+	B    callbackasm1(SB)
+	MOVW $484, R12
+	B    callbackasm1(SB)
+	MOVW $485, R12
+	B    callbackasm1(SB)
+	MOVW $486, R12
+	B    callbackasm1(SB)
+	MOVW $487, R12
+	B    callbackasm1(SB)
+	MOVW $488, R12
+	B    callbackasm1(SB)
+	MOVW $489, R12
+	B    callbackasm1(SB)
+	MOVW $490, R12
+	B    callbackasm1(SB)
+	MOVW $491, R12
+	B    callbackasm1(SB)
+	MOVW $492, R12
+	B    callbackasm1(SB)
+	MOVW $493, R12
+	B    callbackasm1(SB)
+	MOVW $494, R12
+	B    callbackasm1(SB)
+	MOVW $495, R12
+	B    callbackasm1(SB)
+	MOVW $496, R12
+	B    callbackasm1(SB)
+	MOVW $497, R12
+	B    callbackasm1(SB)
+	MOVW $498, R12
+	B    callbackasm1(SB)
+	MOVW $499, R12
+	B    callbackasm1(SB)
+	MOVW $500, R12
+	B    callbackasm1(SB)
+	MOVW $501, R12
+	B    callbackasm1(SB)
+	MOVW $502, R12
+	B    callbackasm1(SB)
+	MOVW $503, R12
+	B    callbackasm1(SB)
+	MOVW $504, R12
+	B    callbackasm1(SB)
+	MOVW $505, R12
+	B    callbackasm1(SB)
+	MOVW $506, R12
+	B    callbackasm1(SB)
+	MOVW $507, R12
+	B    callbackasm1(SB)
+	MOVW $508, R12
+	B    callbackasm1(SB)
+	MOVW $509, R12
+	B    callbackasm1(SB)
+	MOVW $510, R12
+	B    callbackasm1(SB)
+	MOVW $511, R12
+	B    callbackasm1(SB)
+	MOVW $512, R12
+	B    callbackasm1(SB)
+	MOVW $513, R12
+	B    callbackasm1(SB)
+	MOVW $514, R12
+	B    callbackasm1(SB)
+	MOVW $515, R12
+	B    callbackasm1(SB)
+	MOVW $516, R12
+	B    callbackasm1(SB)
+	MOVW $517, R12
+	B    callbackasm1(SB)
+	MOVW $518, R12
+	B    callbackasm1(SB)
+	MOVW $519, R12
+	B    callbackasm1(SB)
+	MOVW $520, R12
+	B    callbackasm1(SB)
+	MOVW $521, R12
+	B    callbackasm1(SB)
+	MOVW $522, R12
+	B    callbackasm1(SB)
+	MOVW $523, R12
+	B    callbackasm1(SB)
+	MOVW $524, R12
+	B    callbackasm1(SB)
+	MOVW $525, R12
+	B    callbackasm1(SB)
+	MOVW $526, R12
+	B    callbackasm1(SB)
+	MOVW $527, R12
+	B    callbackasm1(SB)
+	MOVW $528, R12
+	B    callbackasm1(SB)
+	MOVW $529, R12
+	B    callbackasm1(SB)
+	MOVW $530, R12
+	B    callbackasm1(SB)
+	MOVW $531, R12
+	B    callbackasm1(SB)
+	MOVW $532, R12
+	B    callbackasm1(SB)
+	MOVW $533, R12
+	B    callbackasm1(SB)
+	MOVW $534, R12
+	B    callbackasm1(SB)
+	MOVW $535, R12
+	B    callbackasm1(SB)
+	MOVW $536, R12
+	B    callbackasm1(SB)
+	MOVW $537, R12
+	B    callbackasm1(SB)
+	MOVW $538, R12
+	B    callbackasm1(SB)
+	MOVW $539, R12
+	B    callbackasm1(SB)
+	MOVW $540, R12
+	B    callbackasm1(SB)
+	MOVW $541, R12
+	B    callbackasm1(SB)
+	MOVW $542, R12
+	B    callbackasm1(SB)
+	MOVW $543, R12
+	B    callbackasm1(SB)
+	MOVW $544, R12
+	B    callbackasm1(SB)
+	MOVW $545, R12
+	B    callbackasm1(SB)
+	MOVW $546, R12
+	B    callbackasm1(SB)
+	MOVW $547, R12
+	B    callbackasm1(SB)
+	MOVW $548, R12
+	B    callbackasm1(SB)
+	MOVW $549, R12
+	B    callbackasm1(SB)
+	MOVW $550, R12
+	B    callbackasm1(SB)
+	MOVW $551, R12
+	B    callbackasm1(SB)
+	MOVW $552, R12
+	B    callbackasm1(SB)
+	MOVW $553, R12
+	B    callbackasm1(SB)
+	MOVW $554, R12
+	B    callbackasm1(SB)
+	MOVW $555, R12
+	B    callbackasm1(SB)
+	MOVW $556, R12
+	B    callbackasm1(SB)
+	MOVW $557, R12
+	B    callbackasm1(SB)
+	MOVW $558, R12
+	B    callbackasm1(SB)
+	MOVW $559, R12
+	B    callbackasm1(SB)
+	MOVW $560, R12
+	B    callbackasm1(SB)
+	MOVW $561, R12
+	B    callbackasm1(SB)
+	MOVW $562, R12
+	B    callbackasm1(SB)
+	MOVW $563, R12
+	B    callbackasm1(SB)
+	MOVW $564, R12
+	B    callbackasm1(SB)
+	MOVW $565, R12
+	B    callbackasm1(SB)
+	MOVW $566, R12
+	B    callbackasm1(SB)
+	MOVW $567, R12
+	B    callbackasm1(SB)
+	MOVW $568, R12
+	B    callbackasm1(SB)
+	MOVW $569, R12
+	B    callbackasm1(SB)
+	MOVW $570, R12
+	B    callbackasm1(SB)
+	MOVW $571, R12
+	B    callbackasm1(SB)
+	MOVW $572, R12
+	B    callbackasm1(SB)
+	MOVW $573, R12
+	B    callbackasm1(SB)
+	MOVW $574, R12
+	B    callbackasm1(SB)
+	MOVW $575, R12
+	B    callbackasm1(SB)
+	MOVW $576, R12
+	B    callbackasm1(SB)
+	MOVW $577, R12
+	B    callbackasm1(SB)
+	MOVW $578, R12
+	B    callbackasm1(SB)
+	MOVW $579, R12
+	B    callbackasm1(SB)
+	MOVW $580, R12
+	B    callbackasm1(SB)
+	MOVW $581, R12
+	B    callbackasm1(SB)
+	MOVW $582, R12
+	B    callbackasm1(SB)
+	MOVW $583, R12
+	B    callbackasm1(SB)
+	MOVW $584, R12
+	B    callbackasm1(SB)
+	MOVW $585, R12
+	B    callbackasm1(SB)
+	MOVW $586, R12
+	B    callbackasm1(SB)
+	MOVW $587, R12
+	B    callbackasm1(SB)
+	MOVW $588, R12
+	B    callbackasm1(SB)
+	MOVW $589, R12
+	B    callbackasm1(SB)
+	MOVW $590, R12
+	B    callbackasm1(SB)
+	MOVW $591, R12
+	B    callbackasm1(SB)
+	MOVW $592, R12
+	B    callbackasm1(SB)
+	MOVW $593, R12
+	B    callbackasm1(SB)
+	MOVW $594, R12
+	B    callbackasm1(SB)
+	MOVW $595, R12
+	B    callbackasm1(SB)
+	MOVW $596, R12
+	B    callbackasm1(SB)
+	MOVW $597, R12
+	B    callbackasm1(SB)
+	MOVW $598, R12
+	B    callbackasm1(SB)
+	MOVW $599, R12
+	B    callbackasm1(SB)
+	MOVW $600, R12
+	B    callbackasm1(SB)
+	MOVW $601, R12
+	B    callbackasm1(SB)
+	MOVW $602, R12
+	B    callbackasm1(SB)
+	MOVW $603, R12
+	B    callbackasm1(SB)
+	MOVW $604, R12
+	B    callbackasm1(SB)
+	MOVW $605, R12
+	B    callbackasm1(SB)
+	MOVW $606, R12
+	B    callbackasm1(SB)
+	MOVW $607, R12
+	B    callbackasm1(SB)
+	MOVW $608, R12
+	B    callbackasm1(SB)
+	MOVW $609, R12
+	B    callbackasm1(SB)
+	MOVW $610, R12
+	B    callbackasm1(SB)
+	MOVW $611, R12
+	B    callbackasm1(SB)
+	MOVW $612, R12
+	B    callbackasm1(SB)
+	MOVW $613, R12
+	B    callbackasm1(SB)
+	MOVW $614, R12
+	B    callbackasm1(SB)
+	MOVW $615, R12
+	B    callbackasm1(SB)
+	MOVW $616, R12
+	B    callbackasm1(SB)
+	MOVW $617, R12
+	B    callbackasm1(SB)
+	MOVW $618, R12
+	B    callbackasm1(SB)
+	MOVW $619, R12
+	B    callbackasm1(SB)
+	MOVW $620, R12
+	B    callbackasm1(SB)
+	MOVW $621, R12
+	B    callbackasm1(SB)
+	MOVW $622, R12
+	B    callbackasm1(SB)
+	MOVW $623, R12
+	B    callbackasm1(SB)
+	MOVW $624, R12
+	B    callbackasm1(SB)
+	MOVW $625, R12
+	B    callbackasm1(SB)
+	MOVW $626, R12
+	B    callbackasm1(SB)
+	MOVW $627, R12
+	B    callbackasm1(SB)
+	MOVW $628, R12
+	B    callbackasm1(SB)
+	MOVW $629, R12
+	B    callbackasm1(SB)
+	MOVW $630, R12
+	B    callbackasm1(SB)
+	MOVW $631, R12
+	B    callbackasm1(SB)
+	MOVW $632, R12
+	B    callbackasm1(SB)
+	MOVW $633, R12
+	B    callbackasm1(SB)
+	MOVW $634, R12
+	B    callbackasm1(SB)
+	MOVW $635, R12
+	B    callbackasm1(SB)
+	MOVW $636, R12
+	B    callbackasm1(SB)
+	MOVW $637, R12
+	B    callbackasm1(SB)
+	MOVW $638, R12
+	B    callbackasm1(SB)
+	MOVW $639, R12
+	B    callbackasm1(SB)
+	MOVW $640, R12
+	B    callbackasm1(SB)
+	MOVW $641, R12
+	B    callbackasm1(SB)
+	MOVW $642, R12
+	B    callbackasm1(SB)
+	MOVW $643, R12
+	B    callbackasm1(SB)
+	MOVW $644, R12
+	B    callbackasm1(SB)
+	MOVW $645, R12
+	B    callbackasm1(SB)
+	MOVW $646, R12
+	B    callbackasm1(SB)
+	MOVW $647, R12
+	B    callbackasm1(SB)
+	MOVW $648, R12
+	B    callbackasm1(SB)
+	MOVW $649, R12
+	B    callbackasm1(SB)
+	MOVW $650, R12
+	B    callbackasm1(SB)
+	MOVW $651, R12
+	B    callbackasm1(SB)
+	MOVW $652, R12
+	B    callbackasm1(SB)
+	MOVW $653, R12
+	B    callbackasm1(SB)
+	MOVW $654, R12
+	B    callbackasm1(SB)
+	MOVW $655, R12
+	B    callbackasm1(SB)
+	MOVW $656, R12
+	B    callbackasm1(SB)
+	MOVW $657, R12
+	B    callbackasm1(SB)
+	MOVW $658, R12
+	B    callbackasm1(SB)
+	MOVW $659, R12
+	B    callbackasm1(SB)
+	MOVW $660, R12
+	B    callbackasm1(SB)
+	MOVW $661, R12
+	B    callbackasm1(SB)
+	MOVW $662, R12
+	B    callbackasm1(SB)
+	MOVW $663, R12
+	B    callbackasm1(SB)
+	MOVW $664, R12
+	B    callbackasm1(SB)
+	MOVW $665, R12
+	B    callbackasm1(SB)
+	MOVW $666, R12
+	B    callbackasm1(SB)
+	MOVW $667, R12
+	B    callbackasm1(SB)
+	MOVW $668, R12
+	B    callbackasm1(SB)
+	MOVW $669, R12
+	B    callbackasm1(SB)
+	MOVW $670, R12
+	B    callbackasm1(SB)
+	MOVW $671, R12
+	B    callbackasm1(SB)
+	MOVW $672, R12
+	B    callbackasm1(SB)
+	MOVW $673, R12
+	B    callbackasm1(SB)
+	MOVW $674, R12
+	B    callbackasm1(SB)
+	MOVW $675, R12
+	B    callbackasm1(SB)
+	MOVW $676, R12
+	B    callbackasm1(SB)
+	MOVW $677, R12
+	B    callbackasm1(SB)
+	MOVW $678, R12
+	B    callbackasm1(SB)
+	MOVW $679, R12
+	B    callbackasm1(SB)
+	MOVW $680, R12
+	B    callbackasm1(SB)
+	MOVW $681, R12
+	B    callbackasm1(SB)
+	MOVW $682, R12
+	B    callbackasm1(SB)
+	MOVW $683, R12
+	B    callbackasm1(SB)
+	MOVW $684, R12
+	B    callbackasm1(SB)
+	MOVW $685, R12
+	B    callbackasm1(SB)
+	MOVW $686, R12
+	B    callbackasm1(SB)
+	MOVW $687, R12
+	B    callbackasm1(SB)
+	MOVW $688, R12
+	B    callbackasm1(SB)
+	MOVW $689, R12
+	B    callbackasm1(SB)
+	MOVW $690, R12
+	B    callbackasm1(SB)
+	MOVW $691, R12
+	B    callbackasm1(SB)
+	MOVW $692, R12
+	B    callbackasm1(SB)
+	MOVW $693, R12
+	B    callbackasm1(SB)
+	MOVW $694, R12
+	B    callbackasm1(SB)
+	MOVW $695, R12
+	B    callbackasm1(SB)
+	MOVW $696, R12
+	B    callbackasm1(SB)
+	MOVW $697, R12
+	B    callbackasm1(SB)
+	MOVW $698, R12
+	B    callbackasm1(SB)
+	MOVW $699, R12
+	B    callbackasm1(SB)
+	MOVW $700, R12
+	B    callbackasm1(SB)
+	MOVW $701, R12
+	B    callbackasm1(SB)
+	MOVW $702, R12
+	B    callbackasm1(SB)
+	MOVW $703, R12
+	B    callbackasm1(SB)
+	MOVW $704, R12
+	B    callbackasm1(SB)
+	MOVW $705, R12
+	B    callbackasm1(SB)
+	MOVW $706, R12
+	B    callbackasm1(SB)
+	MOVW $707, R12
+	B    callbackasm1(SB)
+	MOVW $708, R12
+	B    callbackasm1(SB)
+	MOVW $709, R12
+	B    callbackasm1(SB)
+	MOVW $710, R12
+	B    callbackasm1(SB)
+	MOVW $711, R12
+	B    callbackasm1(SB)
+	MOVW $712, R12
+	B    callbackasm1(SB)
+	MOVW $713, R12
+	B    callbackasm1(SB)
+	MOVW $714, R12
+	B    callbackasm1(SB)
+	MOVW $715, R12
+	B    callbackasm1(SB)
+	MOVW $716, R12
+	B    callbackasm1(SB)
+	MOVW $717, R12
+	B    callbackasm1(SB)
+	MOVW $718, R12
+	B    callbackasm1(SB)
+	MOVW $719, R12
+	B    callbackasm1(SB)
+	MOVW $720, R12
+	B    callbackasm1(SB)
+	MOVW $721, R12
+	B    callbackasm1(SB)
+	MOVW $722, R12
+	B    callbackasm1(SB)
+	MOVW $723, R12
+	B    callbackasm1(SB)
+	MOVW $724, R12
+	B    callbackasm1(SB)
+	MOVW $725, R12
+	B    callbackasm1(SB)
+	MOVW $726, R12
+	B    callbackasm1(SB)
+	MOVW $727, R12
+	B    callbackasm1(SB)
+	MOVW $728, R12
+	B    callbackasm1(SB)
+	MOVW $729, R12
+	B    callbackasm1(SB)
+	MOVW $730, R12
+	B    callbackasm1(SB)
+	MOVW $731, R12
+	B    callbackasm1(SB)
+	MOVW $732, R12
+	B    callbackasm1(SB)
+	MOVW $733, R12
+	B    callbackasm1(SB)
+	MOVW $734, R12
+	B    callbackasm1(SB)
+	MOVW $735, R12
+	B    callbackasm1(SB)
+	MOVW $736, R12
+	B    callbackasm1(SB)
+	MOVW $737, R12
+	B    callbackasm1(SB)
+	MOVW $738, R12
+	B    callbackasm1(SB)
+	MOVW $739, R12
+	B    callbackasm1(SB)
+	MOVW $740, R12
+	B    callbackasm1(SB)
+	MOVW $741, R12
+	B    callbackasm1(SB)
+	MOVW $742, R12
+	B    callbackasm1(SB)
+	MOVW $743, R12
+	B    callbackasm1(SB)
+	MOVW $744, R12
+	B    callbackasm1(SB)
+	MOVW $745, R12
+	B    callbackasm1(SB)
+	MOVW $746, R12
+	B    callbackasm1(SB)
+	MOVW $747, R12
+	B    callbackasm1(SB)
+	MOVW $748, R12
+	B    callbackasm1(SB)
+	MOVW $749, R12
+	B    callbackasm1(SB)
+	MOVW $750, R12
+	B    callbackasm1(SB)
+	MOVW $751, R12
+	B    callbackasm1(SB)
+	MOVW $752, R12
+	B    callbackasm1(SB)
+	MOVW $753, R12
+	B    callbackasm1(SB)
+	MOVW $754, R12
+	B    callbackasm1(SB)
+	MOVW $755, R12
+	B    callbackasm1(SB)
+	MOVW $756, R12
+	B    callbackasm1(SB)
+	MOVW $757, R12
+	B    callbackasm1(SB)
+	MOVW $758, R12
+	B    callbackasm1(SB)
+	MOVW $759, R12
+	B    callbackasm1(SB)
+	MOVW $760, R12
+	B    callbackasm1(SB)
+	MOVW $761, R12
+	B    callbackasm1(SB)
+	MOVW $762, R12
+	B    callbackasm1(SB)
+	MOVW $763, R12
+	B    callbackasm1(SB)
+	MOVW $764, R12
+	B    callbackasm1(SB)
+	MOVW $765, R12
+	B    callbackasm1(SB)
+	MOVW $766, R12
+	B    callbackasm1(SB)
+	MOVW $767, R12
+	B    callbackasm1(SB)
+	MOVW $768, R12
+	B    callbackasm1(SB)
+	MOVW $769, R12
+	B    callbackasm1(SB)
+	MOVW $770, R12
+	B    callbackasm1(SB)
+	MOVW $771, R12
+	B    callbackasm1(SB)
+	MOVW $772, R12
+	B    callbackasm1(SB)
+	MOVW $773, R12
+	B    callbackasm1(SB)
+	MOVW $774, R12
+	B    callbackasm1(SB)
+	MOVW $775, R12
+	B    callbackasm1(SB)
+	MOVW $776, R12
+	B    callbackasm1(SB)
+	MOVW $777, R12
+	B    callbackasm1(SB)
+	MOVW $778, R12
+	B    callbackasm1(SB)
+	MOVW $779, R12
+	B    callbackasm1(SB)
+	MOVW $780, R12
+	B    callbackasm1(SB)
+	MOVW $781, R12
+	B    callbackasm1(SB)
+	MOVW $782, R12
+	B    callbackasm1(SB)
+	MOVW $783, R12
+	B    callbackasm1(SB)
+	MOVW $784, R12
+	B    callbackasm1(SB)
+	MOVW $785, R12
+	B    callbackasm1(SB)
+	MOVW $786, R12
+	B    callbackasm1(SB)
+	MOVW $787, R12
+	B    callbackasm1(SB)
+	MOVW $788, R12
+	B    callbackasm1(SB)
+	MOVW $789, R12
+	B    callbackasm1(SB)
+	MOVW $790, R12
+	B    callbackasm1(SB)
+	MOVW $791, R12
+	B    callbackasm1(SB)
+	MOVW $792, R12
+	B    callbackasm1(SB)
+	MOVW $793, R12
+	B    callbackasm1(SB)
+	MOVW $794, R12
+	B    callbackasm1(SB)
+	MOVW $795, R12
+	B    callbackasm1(SB)
+	MOVW $796, R12
+	B    callbackasm1(SB)
+	MOVW $797, R12
+	B    callbackasm1(SB)
+	MOVW $798, R12
+	B    callbackasm1(SB)
+	MOVW $799, R12
+	B    callbackasm1(SB)
+	MOVW $800, R12
+	B    callbackasm1(SB)
+	MOVW $801, R12
+	B    callbackasm1(SB)
+	MOVW $802, R12
+	B    callbackasm1(SB)
+	MOVW $803, R12
+	B    callbackasm1(SB)
+	MOVW $804, R12
+	B    callbackasm1(SB)
+	MOVW $805, R12
+	B    callbackasm1(SB)
+	MOVW $806, R12
+	B    callbackasm1(SB)
+	MOVW $807, R12
+	B    callbackasm1(SB)
+	MOVW $808, R12
+	B    callbackasm1(SB)
+	MOVW $809, R12
+	B    callbackasm1(SB)
+	MOVW $810, R12
+	B    callbackasm1(SB)
+	MOVW $811, R12
+	B    callbackasm1(SB)
+	MOVW $812, R12
+	B    callbackasm1(SB)
+	MOVW $813, R12
+	B    callbackasm1(SB)
+	MOVW $814, R12
+	B    callbackasm1(SB)
+	MOVW $815, R12
+	B    callbackasm1(SB)
+	MOVW $816, R12
+	B    callbackasm1(SB)
+	MOVW $817, R12
+	B    callbackasm1(SB)
+	MOVW $818, R12
+	B    callbackasm1(SB)
+	MOVW $819, R12
+	B    callbackasm1(SB)
+	MOVW $820, R12
+	B    callbackasm1(SB)
+	MOVW $821, R12
+	B    callbackasm1(SB)
+	MOVW $822, R12
+	B    callbackasm1(SB)
+	MOVW $823, R12
+	B    callbackasm1(SB)
+	MOVW $824, R12
+	B    callbackasm1(SB)
+	MOVW $825, R12
+	B    callbackasm1(SB)
+	MOVW $826, R12
+	B    callbackasm1(SB)
+	MOVW $827, R12
+	B    callbackasm1(SB)
+	MOVW $828, R12
+	B    callbackasm1(SB)
+	MOVW $829, R12
+	B    callbackasm1(SB)
+	MOVW $830, R12
+	B    callbackasm1(SB)
+	MOVW $831, R12
+	B    callbackasm1(SB)
+	MOVW $832, R12
+	B    callbackasm1(SB)
+	MOVW $833, R12
+	B    callbackasm1(SB)
+	MOVW $834, R12
+	B    callbackasm1(SB)
+	MOVW $835, R12
+	B    callbackasm1(SB)
+	MOVW $836, R12
+	B    callbackasm1(SB)
+	MOVW $837, R12
+	B    callbackasm1(SB)
+	MOVW $838, R12
+	B    callbackasm1(SB)
+	MOVW $839, R12
+	B    callbackasm1(SB)
+	MOVW $840, R12
+	B    callbackasm1(SB)
+	MOVW $841, R12
+	B    callbackasm1(SB)
+	MOVW $842, R12
+	B    callbackasm1(SB)
+	MOVW $843, R12
+	B    callbackasm1(SB)
+	MOVW $844, R12
+	B    callbackasm1(SB)
+	MOVW $845, R12
+	B    callbackasm1(SB)
+	MOVW $846, R12
+	B    callbackasm1(SB)
+	MOVW $847, R12
+	B    callbackasm1(SB)
+	MOVW $848, R12
+	B    callbackasm1(SB)
+	MOVW $849, R12
+	B    callbackasm1(SB)
+	MOVW $850, R12
+	B    callbackasm1(SB)
+	MOVW $851, R12
+	B    callbackasm1(SB)
+	MOVW $852, R12
+	B    callbackasm1(SB)
+	MOVW $853, R12
+	B    callbackasm1(SB)
+	MOVW $854, R12
+	B    callbackasm1(SB)
+	MOVW $855, R12
+	B    callbackasm1(SB)
+	MOVW $856, R12
+	B    callbackasm1(SB)
+	MOVW $857, R12
+	B    callbackasm1(SB)
+	MOVW $858, R12
+	B    callbackasm1(SB)
+	MOVW $859, R12
+	B    callbackasm1(SB)
+	MOVW $860, R12
+	B    callbackasm1(SB)
+	MOVW $861, R12
+	B    callbackasm1(SB)
+	MOVW $862, R12
+	B    callbackasm1(SB)
+	MOVW $863, R12
+	B    callbackasm1(SB)
+	MOVW $864, R12
+	B    callbackasm1(SB)
+	MOVW $865, R12
+	B    callbackasm1(SB)
+	MOVW $866, R12
+	B    callbackasm1(SB)
+	MOVW $867, R12
+	B    callbackasm1(SB)
+	MOVW $868, R12
+	B    callbackasm1(SB)
+	MOVW $869, R12
+	B    callbackasm1(SB)
+	MOVW $870, R12
+	B    callbackasm1(SB)
+	MOVW $871, R12
+	B    callbackasm1(SB)
+	MOVW $872, R12
+	B    callbackasm1(SB)
+	MOVW $873, R12
+	B    callbackasm1(SB)
+	MOVW $874, R12
+	B    callbackasm1(SB)
+	MOVW $875, R12
+	B    callbackasm1(SB)
+	MOVW $876, R12
+	B    callbackasm1(SB)
+	MOVW $877, R12
+	B    callbackasm1(SB)
+	MOVW $878, R12
+	B    callbackasm1(SB)
+	MOVW $879, R12
+	B    callbackasm1(SB)
+	MOVW $880, R12
+	B    callbackasm1(SB)
+	MOVW $881, R12
+	B    callbackasm1(SB)
+	MOVW $882, R12
+	B    callbackasm1(SB)
+	MOVW $883, R12
+	B    callbackasm1(SB)
+	MOVW $884, R12
+	B    callbackasm1(SB)
+	MOVW $885, R12
+	B    callbackasm1(SB)
+	MOVW $886, R12
+	B    callbackasm1(SB)
+	MOVW $887, R12
+	B    callbackasm1(SB)
+	MOVW $888, R12
+	B    callbackasm1(SB)
+	MOVW $889, R12
+	B    callbackasm1(SB)
+	MOVW $890, R12
+	B    callbackasm1(SB)
+	MOVW $891, R12
+	B    callbackasm1(SB)
+	MOVW $892, R12
+	B    callbackasm1(SB)
+	MOVW $893, R12
+	B    callbackasm1(SB)
+	MOVW $894, R12
+	B    callbackasm1(SB)
+	MOVW $895, R12
+	B    callbackasm1(SB)
+	MOVW $896, R12
+	B    callbackasm1(SB)
+	MOVW $897, R12
+	B    callbackasm1(SB)
+	MOVW $898, R12
+	B    callbackasm1(SB)
+	MOVW $899, R12
+	B    callbackasm1(SB)
+	MOVW $900, R12
+	B    callbackasm1(SB)
+	MOVW $901, R12
+	B    callbackasm1(SB)
+	MOVW $902, R12
+	B    callbackasm1(SB)
+	MOVW $903, R12
+	B    callbackasm1(SB)
+	MOVW $904, R12
+	B    callbackasm1(SB)
+	MOVW $905, R12
+	B    callbackasm1(SB)
+	MOVW $906, R12
+	B    callbackasm1(SB)
+	MOVW $907, R12
+	B    callbackasm1(SB)
+	MOVW $908, R12
+	B    callbackasm1(SB)
+	MOVW $909, R12
+	B    callbackasm1(SB)
+	MOVW $910, R12
+	B    callbackasm1(SB)
+	MOVW $911, R12
+	B    callbackasm1(SB)
+	MOVW $912, R12
+	B    callbackasm1(SB)
+	MOVW $913, R12
+	B    callbackasm1(SB)
+	MOVW $914, R12
+	B    callbackasm1(SB)
+	MOVW $915, R12
+	B    callbackasm1(SB)
+	MOVW $916, R12
+	B    callbackasm1(SB)
+	MOVW $917, R12
+	B    callbackasm1(SB)
+	MOVW $918, R12
+	B    callbackasm1(SB)
+	MOVW $919, R12
+	B    callbackasm1(SB)
+	MOVW $920, R12
+	B    callbackasm1(SB)
+	MOVW $921, R12
+	B    callbackasm1(SB)
+	MOVW $922, R12
+	B    callbackasm1(SB)
+	MOVW $923, R12
+	B    callbackasm1(SB)
+	MOVW $924, R12
+	B    callbackasm1(SB)
+	MOVW $925, R12
+	B    callbackasm1(SB)
+	MOVW $926, R12
+	B    callbackasm1(SB)
+	MOVW $927, R12
+	B    callbackasm1(SB)
+	MOVW $928, R12
+	B    callbackasm1(SB)
+	MOVW $929, R12
+	B    callbackasm1(SB)
+	MOVW $930, R12
+	B    callbackasm1(SB)
+	MOVW $931, R12
+	B    callbackasm1(SB)
+	MOVW $932, R12
+	B    callbackasm1(SB)
+	MOVW $933, R12
+	B    callbackasm1(SB)
+	MOVW $934, R12
+	B    callbackasm1(SB)
+	MOVW $935, R12
+	B    callbackasm1(SB)
+	MOVW $936, R12
+	B    callbackasm1(SB)
+	MOVW $937, R12
+	B    callbackasm1(SB)
+	MOVW $938, R12
+	B    callbackasm1(SB)
+	MOVW $939, R12
+	B    callbackasm1(SB)
+	MOVW $940, R12
+	B    callbackasm1(SB)
+	MOVW $941, R12
+	B    callbackasm1(SB)
+	MOVW $942, R12
+	B    callbackasm1(SB)
+	MOVW $943, R12
+	B    callbackasm1(SB)
+	MOVW $944, R12
+	B    callbackasm1(SB)
+	MOVW $945, R12
+	B    callbackasm1(SB)
+	MOVW $946, R12
+	B    callbackasm1(SB)
+	MOVW $947, R12
+	B    callbackasm1(SB)
+	MOVW $948, R12
+	B    callbackasm1(SB)
+	MOVW $949, R12
+	B    callbackasm1(SB)
+	MOVW $950, R12
+	B    callbackasm1(SB)
+	MOVW $951, R12
+	B    callbackasm1(SB)
+	MOVW $952, R12
+	B    callbackasm1(SB)
+	MOVW $953, R12
+	B    callbackasm1(SB)
+	MOVW $954, R12
+	B    callbackasm1(SB)
+	MOVW $955, R12
+	B    callbackasm1(SB)
+	MOVW $956, R12
+	B    callbackasm1(SB)
+	MOVW $957, R12
+	B    callbackasm1(SB)
+	MOVW $958, R12
+	B    callbackasm1(SB)
+	MOVW $959, R12
+	B    callbackasm1(SB)
+	MOVW $960, R12
+	B    callbackasm1(SB)
+	MOVW $961, R12
+	B    callbackasm1(SB)
+	MOVW $962, R12
+	B    callbackasm1(SB)
+	MOVW $963, R12
+	B    callbackasm1(SB)
+	MOVW $964, R12
+	B    callbackasm1(SB)
+	MOVW $965, R12
+	B    callbackasm1(SB)
+	MOVW $966, R12
+	B    callbackasm1(SB)
+	MOVW $967, R12
+	B    callbackasm1(SB)
+	MOVW $968, R12
+	B    callbackasm1(SB)
+	MOVW $969, R12
+	B    callbackasm1(SB)
+	MOVW $970, R12
+	B    callbackasm1(SB)
+	MOVW $971, R12
+	B    callbackasm1(SB)
+	MOVW $972, R12
+	B    callbackasm1(SB)
+	MOVW $973, R12
+	B    callbackasm1(SB)
+	MOVW $974, R12
+	B    callbackasm1(SB)
+	MOVW $975, R12
+	B    callbackasm1(SB)
+	MOVW $976, R12
+	B    callbackasm1(SB)
+	MOVW $977, R12
+	B    callbackasm1(SB)
+	MOVW $978, R12
+	B    callbackasm1(SB)
+	MOVW $979, R12
+	B    callbackasm1(SB)
+	MOVW $980, R12
+	B    callbackasm1(SB)
+	MOVW $981, R12
+	B    callbackasm1(SB)
+	MOVW $982, R12
+	B    callbackasm1(SB)
+	MOVW $983, R12
+	B    callbackasm1(SB)
+	MOVW $984, R12
+	B    callbackasm1(SB)
+	MOVW $985, R12
+	B    callbackasm1(SB)
+	MOVW $986, R12
+	B    callbackasm1(SB)
+	MOVW $987, R12
+	B    callbackasm1(SB)
+	MOVW $988, R12
+	B    callbackasm1(SB)
+	MOVW $989, R12
+	B    callbackasm1(SB)
+	MOVW $990, R12
+	B    callbackasm1(SB)
+	MOVW $991, R12
+	B    callbackasm1(SB)
+	MOVW $992, R12
+	B    callbackasm1(SB)
+	MOVW $993, R12
+	B    callbackasm1(SB)
+	MOVW $994, R12
+	B    callbackasm1(SB)
+	MOVW $995, R12
+	B    callbackasm1(SB)
+	MOVW $996, R12
+	B    callbackasm1(SB)
+	MOVW $997, R12
+	B    callbackasm1(SB)
+	MOVW $998, R12
+	B    callbackasm1(SB)
+	MOVW $999, R12
+	B    callbackasm1(SB)
+	MOVW $1000, R12
+	B    callbackasm1(SB)
+	MOVW $1001, R12
+	B    callbackasm1(SB)
+	MOVW $1002, R12
+	B    callbackasm1(SB)
+	MOVW $1003, R12
+	B    callbackasm1(SB)
+	MOVW $1004, R12
+	B    callbackasm1(SB)
+	MOVW $1005, R12
+	B    callbackasm1(SB)
+	MOVW $1006, R12
+	B    callbackasm1(SB)
+	MOVW $1007, R12
+	B    callbackasm1(SB)
+	MOVW $1008, R12
+	B    callbackasm1(SB)
+	MOVW $1009, R12
+	B    callbackasm1(SB)
+	MOVW $1010, R12
+	B    callbackasm1(SB)
+	MOVW $1011, R12
+	B    callbackasm1(SB)
+	MOVW $1012, R12
+	B    callbackasm1(SB)
+	MOVW $1013, R12
+	B    callbackasm1(SB)
+	MOVW $1014, R12
+	B    callbackasm1(SB)
+	MOVW $1015, R12
+	B    callbackasm1(SB)
+	MOVW $1016, R12
+	B    callbackasm1(SB)
+	MOVW $1017, R12
+	B    callbackasm1(SB)
+	MOVW $1018, R12
+	B    callbackasm1(SB)
+	MOVW $1019, R12
+	B    callbackasm1(SB)
+	MOVW $1020, R12
+	B    callbackasm1(SB)
+	MOVW $1021, R12
+	B    callbackasm1(SB)
+	MOVW $1022, R12
+	B    callbackasm1(SB)
+	MOVW $1023, R12
+	B    callbackasm1(SB)
+	MOVW $1024, R12
+	B    callbackasm1(SB)
+	MOVW $1025, R12
+	B    callbackasm1(SB)
+	MOVW $1026, R12
+	B    callbackasm1(SB)
+	MOVW $1027, R12
+	B    callbackasm1(SB)
+	MOVW $1028, R12
+	B    callbackasm1(SB)
+	MOVW $1029, R12
+	B    callbackasm1(SB)
+	MOVW $1030, R12
+	B    callbackasm1(SB)
+	MOVW $1031, R12
+	B    callbackasm1(SB)
+	MOVW $1032, R12
+	B    callbackasm1(SB)
+	MOVW $1033, R12
+	B    callbackasm1(SB)
+	MOVW $1034, R12
+	B    callbackasm1(SB)
+	MOVW $1035, R12
+	B    callbackasm1(SB)
+	MOVW $1036, R12
+	B    callbackasm1(SB)
+	MOVW $1037, R12
+	B    callbackasm1(SB)
+	MOVW $1038, R12
+	B    callbackasm1(SB)
+	MOVW $1039, R12
+	B    callbackasm1(SB)
+	MOVW $1040, R12
+	B    callbackasm1(SB)
+	MOVW $1041, R12
+	B    callbackasm1(SB)
+	MOVW $1042, R12
+	B    callbackasm1(SB)
+	MOVW $1043, R12
+	B    callbackasm1(SB)
+	MOVW $1044, R12
+	B    callbackasm1(SB)
+	MOVW $1045, R12
+	B    callbackasm1(SB)
+	MOVW $1046, R12
+	B    callbackasm1(SB)
+	MOVW $1047, R12
+	B    callbackasm1(SB)
+	MOVW $1048, R12
+	B    callbackasm1(SB)
+	MOVW $1049, R12
+	B    callbackasm1(SB)
+	MOVW $1050, R12
+	B    callbackasm1(SB)
+	MOVW $1051, R12
+	B    callbackasm1(SB)
+	MOVW $1052, R12
+	B    callbackasm1(SB)
+	MOVW $1053, R12
+	B    callbackasm1(SB)
+	MOVW $1054, R12
+	B    callbackasm1(SB)
+	MOVW $1055, R12
+	B    callbackasm1(SB)
+	MOVW $1056, R12
+	B    callbackasm1(SB)
+	MOVW $1057, R12
+	B    callbackasm1(SB)
+	MOVW $1058, R12
+	B    callbackasm1(SB)
+	MOVW $1059, R12
+	B    callbackasm1(SB)
+	MOVW $1060, R12
+	B    callbackasm1(SB)
+	MOVW $1061, R12
+	B    callbackasm1(SB)
+	MOVW $1062, R12
+	B    callbackasm1(SB)
+	MOVW $1063, R12
+	B    callbackasm1(SB)
+	MOVW $1064, R12
+	B    callbackasm1(SB)
+	MOVW $1065, R12
+	B    callbackasm1(SB)
+	MOVW $1066, R12
+	B    callbackasm1(SB)
+	MOVW $1067, R12
+	B    callbackasm1(SB)
+	MOVW $1068, R12
+	B    callbackasm1(SB)
+	MOVW $1069, R12
+	B    callbackasm1(SB)
+	MOVW $1070, R12
+	B    callbackasm1(SB)
+	MOVW $1071, R12
+	B    callbackasm1(SB)
+	MOVW $1072, R12
+	B    callbackasm1(SB)
+	MOVW $1073, R12
+	B    callbackasm1(SB)
+	MOVW $1074, R12
+	B    callbackasm1(SB)
+	MOVW $1075, R12
+	B    callbackasm1(SB)
+	MOVW $1076, R12
+	B    callbackasm1(SB)
+	MOVW $1077, R12
+	B    callbackasm1(SB)
+	MOVW $1078, R12
+	B    callbackasm1(SB)
+	MOVW $1079, R12
+	B    callbackasm1(SB)
+	MOVW $1080, R12
+	B    callbackasm1(SB)
+	MOVW $1081, R12
+	B    callbackasm1(SB)
+	MOVW $1082, R12
+	B    callbackasm1(SB)
+	MOVW $1083, R12
+	B    callbackasm1(SB)
+	MOVW $1084, R12
+	B    callbackasm1(SB)
+	MOVW $1085, R12
+	B    callbackasm1(SB)
+	MOVW $1086, R12
+	B    callbackasm1(SB)
+	MOVW $1087, R12
+	B    callbackasm1(SB)
+	MOVW $1088, R12
+	B    callbackasm1(SB)
+	MOVW $1089, R12
+	B    callbackasm1(SB)
+	MOVW $1090, R12
+	B    callbackasm1(SB)
+	MOVW $1091, R12
+	B    callbackasm1(SB)
+	MOVW $1092, R12
+	B    callbackasm1(SB)
+	MOVW $1093, R12
+	B    callbackasm1(SB)
+	MOVW $1094, R12
+	B    callbackasm1(SB)
+	MOVW $1095, R12
+	B    callbackasm1(SB)
+	MOVW $1096, R12
+	B    callbackasm1(SB)
+	MOVW $1097, R12
+	B    callbackasm1(SB)
+	MOVW $1098, R12
+	B    callbackasm1(SB)
+	MOVW $1099, R12
+	B    callbackasm1(SB)
+	MOVW $1100, R12
+	B    callbackasm1(SB)
+	MOVW $1101, R12
+	B    callbackasm1(SB)
+	MOVW $1102, R12
+	B    callbackasm1(SB)
+	MOVW $1103, R12
+	B    callbackasm1(SB)
+	MOVW $1104, R12
+	B    callbackasm1(SB)
+	MOVW $1105, R12
+	B    callbackasm1(SB)
+	MOVW $1106, R12
+	B    callbackasm1(SB)
+	MOVW $1107, R12
+	B    callbackasm1(SB)
+	MOVW $1108, R12
+	B    callbackasm1(SB)
+	MOVW $1109, R12
+	B    callbackasm1(SB)
+	MOVW $1110, R12
+	B    callbackasm1(SB)
+	MOVW $1111, R12
+	B    callbackasm1(SB)
+	MOVW $1112, R12
+	B    callbackasm1(SB)
+	MOVW $1113, R12
+	B    callbackasm1(SB)
+	MOVW $1114, R12
+	B    callbackasm1(SB)
+	MOVW $1115, R12
+	B    callbackasm1(SB)
+	MOVW $1116, R12
+	B    callbackasm1(SB)
+	MOVW $1117, R12
+	B    callbackasm1(SB)
+	MOVW $1118, R12
+	B    callbackasm1(SB)
+	MOVW $1119, R12
+	B    callbackasm1(SB)
+	MOVW $1120, R12
+	B    callbackasm1(SB)
+	MOVW $1121, R12
+	B    callbackasm1(SB)
+	MOVW $1122, R12
+	B    callbackasm1(SB)
+	MOVW $1123, R12
+	B    callbackasm1(SB)
+	MOVW $1124, R12
+	B    callbackasm1(SB)
+	MOVW $1125, R12
+	B    callbackasm1(SB)
+	MOVW $1126, R12
+	B    callbackasm1(SB)
+	MOVW $1127, R12
+	B    callbackasm1(SB)
+	MOVW $1128, R12
+	B    callbackasm1(SB)
+	MOVW $1129, R12
+	B    callbackasm1(SB)
+	MOVW $1130, R12
+	B    callbackasm1(SB)
+	MOVW $1131, R12
+	B    callbackasm1(SB)
+	MOVW $1132, R12
+	B    callbackasm1(SB)
+	MOVW $1133, R12
+	B    callbackasm1(SB)
+	MOVW $1134, R12
+	B    callbackasm1(SB)
+	MOVW $1135, R12
+	B    callbackasm1(SB)
+	MOVW $1136, R12
+	B    callbackasm1(SB)
+	MOVW $1137, R12
+	B    callbackasm1(SB)
+	MOVW $1138, R12
+	B    callbackasm1(SB)
+	MOVW $1139, R12
+	B    callbackasm1(SB)
+	MOVW $1140, R12
+	B    callbackasm1(SB)
+	MOVW $1141, R12
+	B    callbackasm1(SB)
+	MOVW $1142, R12
+	B    callbackasm1(SB)
+	MOVW $1143, R12
+	B    callbackasm1(SB)
+	MOVW $1144, R12
+	B    callbackasm1(SB)
+	MOVW $1145, R12
+	B    callbackasm1(SB)
+	MOVW $1146, R12
+	B    callbackasm1(SB)
+	MOVW $1147, R12
+	B    callbackasm1(SB)
+	MOVW $1148, R12
+	B    callbackasm1(SB)
+	MOVW $1149, R12
+	B    callbackasm1(SB)
+	MOVW $1150, R12
+	B    callbackasm1(SB)
+	MOVW $1151, R12
+	B    callbackasm1(SB)
+	MOVW $1152, R12
+	B    callbackasm1(SB)
+	MOVW $1153, R12
+	B    callbackasm1(SB)
+	MOVW $1154, R12
+	B    callbackasm1(SB)
+	MOVW $1155, R12
+	B    callbackasm1(SB)
+	MOVW $1156, R12
+	B    callbackasm1(SB)
+	MOVW $1157, R12
+	B    callbackasm1(SB)
+	MOVW $1158, R12
+	B    callbackasm1(SB)
+	MOVW $1159, R12
+	B    callbackasm1(SB)
+	MOVW $1160, R12
+	B    callbackasm1(SB)
+	MOVW $1161, R12
+	B    callbackasm1(SB)
+	MOVW $1162, R12
+	B    callbackasm1(SB)
+	MOVW $1163, R12
+	B    callbackasm1(SB)
+	MOVW $1164, R12
+	B    callbackasm1(SB)
+	MOVW $1165, R12
+	B    callbackasm1(SB)
+	MOVW $1166, R12
+	B    callbackasm1(SB)
+	MOVW $1167, R12
+	B    callbackasm1(SB)
+	MOVW $1168, R12
+	B    callbackasm1(SB)
+	MOVW $1169, R12
+	B    callbackasm1(SB)
+	MOVW $1170, R12
+	B    callbackasm1(SB)
+	MOVW $1171, R12
+	B    callbackasm1(SB)
+	MOVW $1172, R12
+	B    callbackasm1(SB)
+	MOVW $1173, R12
+	B    callbackasm1(SB)
+	MOVW $1174, R12
+	B    callbackasm1(SB)
+	MOVW $1175, R12
+	B    callbackasm1(SB)
+	MOVW $1176, R12
+	B    callbackasm1(SB)
+	MOVW $1177, R12
+	B    callbackasm1(SB)
+	MOVW $1178, R12
+	B    callbackasm1(SB)
+	MOVW $1179, R12
+	B    callbackasm1(SB)
+	MOVW $1180, R12
+	B    callbackasm1(SB)
+	MOVW $1181, R12
+	B    callbackasm1(SB)
+	MOVW $1182, R12
+	B    callbackasm1(SB)
+	MOVW $1183, R12
+	B    callbackasm1(SB)
+	MOVW $1184, R12
+	B    callbackasm1(SB)
+	MOVW $1185, R12
+	B    callbackasm1(SB)
+	MOVW $1186, R12
+	B    callbackasm1(SB)
+	MOVW $1187, R12
+	B    callbackasm1(SB)
+	MOVW $1188, R12
+	B    callbackasm1(SB)
+	MOVW $1189, R12
+	B    callbackasm1(SB)
+	MOVW $1190, R12
+	B    callbackasm1(SB)
+	MOVW $1191, R12
+	B    callbackasm1(SB)
+	MOVW $1192, R12
+	B    callbackasm1(SB)
+	MOVW $1193, R12
+	B    callbackasm1(SB)
+	MOVW $1194, R12
+	B    callbackasm1(SB)
+	MOVW $1195, R12
+	B    callbackasm1(SB)
+	MOVW $1196, R12
+	B    callbackasm1(SB)
+	MOVW $1197, R12
+	B    callbackasm1(SB)
+	MOVW $1198, R12
+	B    callbackasm1(SB)
+	MOVW $1199, R12
+	B    callbackasm1(SB)
+	MOVW $1200, R12
+	B    callbackasm1(SB)
+	MOVW $1201, R12
+	B    callbackasm1(SB)
+	MOVW $1202, R12
+	B    callbackasm1(SB)
+	MOVW $1203, R12
+	B    callbackasm1(SB)
+	MOVW $1204, R12
+	B    callbackasm1(SB)
+	MOVW $1205, R12
+	B    callbackasm1(SB)
+	MOVW $1206, R12
+	B    callbackasm1(SB)
+	MOVW $1207, R12
+	B    callbackasm1(SB)
+	MOVW $1208, R12
+	B    callbackasm1(SB)
+	MOVW $1209, R12
+	B    callbackasm1(SB)
+	MOVW $1210, R12
+	B    callbackasm1(SB)
+	MOVW $1211, R12
+	B    callbackasm1(SB)
+	MOVW $1212, R12
+	B    callbackasm1(SB)
+	MOVW $1213, R12
+	B    callbackasm1(SB)
+	MOVW $1214, R12
+	B    callbackasm1(SB)
+	MOVW $1215, R12
+	B    callbackasm1(SB)
+	MOVW $1216, R12
+	B    callbackasm1(SB)
+	MOVW $1217, R12
+	B    callbackasm1(SB)
+	MOVW $1218, R12
+	B    callbackasm1(SB)
+	MOVW $1219, R12
+	B    callbackasm1(SB)
+	MOVW $1220, R12
+	B    callbackasm1(SB)
+	MOVW $1221, R12
+	B    callbackasm1(SB)
+	MOVW $1222, R12
+	B    callbackasm1(SB)
+	MOVW $1223, R12
+	B    callbackasm1(SB)
+	MOVW $1224, R12
+	B    callbackasm1(SB)
+	MOVW $1225, R12
+	B    callbackasm1(SB)
+	MOVW $1226, R12
+	B    callbackasm1(SB)
+	MOVW $1227, R12
+	B    callbackasm1(SB)
+	MOVW $1228, R12
+	B    callbackasm1(SB)
+	MOVW $1229, R12
+	B    callbackasm1(SB)
+	MOVW $1230, R12
+	B    callbackasm1(SB)
+	MOVW $1231, R12
+	B    callbackasm1(SB)
+	MOVW $1232, R12
+	B    callbackasm1(SB)
+	MOVW $1233, R12
+	B    callbackasm1(SB)
+	MOVW $1234, R12
+	B    callbackasm1(SB)
+	MOVW $1235, R12
+	B    callbackasm1(SB)
+	MOVW $1236, R12
+	B    callbackasm1(SB)
+	MOVW $1237, R12
+	B    callbackasm1(SB)
+	MOVW $1238, R12
+	B    callbackasm1(SB)
+	MOVW $1239, R12
+	B    callbackasm1(SB)
+	MOVW $1240, R12
+	B    callbackasm1(SB)
+	MOVW $1241, R12
+	B    callbackasm1(SB)
+	MOVW $1242, R12
+	B    callbackasm1(SB)
+	MOVW $1243, R12
+	B    callbackasm1(SB)
+	MOVW $1244, R12
+	B    callbackasm1(SB)
+	MOVW $1245, R12
+	B    callbackasm1(SB)
+	MOVW $1246, R12
+	B    callbackasm1(SB)
+	MOVW $1247, R12
+	B    callbackasm1(SB)
+	MOVW $1248, R12
+	B    callbackasm1(SB)
+	MOVW $1249, R12
+	B    callbackasm1(SB)
+	MOVW $1250, R12
+	B    callbackasm1(SB)
+	MOVW $1251, R12
+	B    callbackasm1(SB)
+	MOVW $1252, R12
+	B    callbackasm1(SB)
+	MOVW $1253, R12
+	B    callbackasm1(SB)
+	MOVW $1254, R12
+	B    callbackasm1(SB)
+	MOVW $1255, R12
+	B    callbackasm1(SB)
+	MOVW $1256, R12
+	B    callbackasm1(SB)
+	MOVW $1257, R12
+	B    callbackasm1(SB)
+	MOVW $1258, R12
+	B    callbackasm1(SB)
+	MOVW $1259, R12
+	B    callbackasm1(SB)
+	MOVW $1260, R12
+	B    callbackasm1(SB)
+	MOVW $1261, R12
+	B    callbackasm1(SB)
+	MOVW $1262, R12
+	B    callbackasm1(SB)
+	MOVW $1263, R12
+	B    callbackasm1(SB)
+	MOVW $1264, R12
+	B    callbackasm1(SB)
+	MOVW $1265, R12
+	B    callbackasm1(SB)
+	MOVW $1266, R12
+	B    callbackasm1(SB)
+	MOVW $1267, R12
+	B    callbackasm1(SB)
+	MOVW $1268, R12
+	B    callbackasm1(SB)
+	MOVW $1269, R12
+	B    callbackasm1(SB)
+	MOVW $1270, R12
+	B    callbackasm1(SB)
+	MOVW $1271, R12
+	B    callbackasm1(SB)
+	MOVW $1272, R12
+	B    callbackasm1(SB)
+	MOVW $1273, R12
+	B    callbackasm1(SB)
+	MOVW $1274, R12
+	B    callbackasm1(SB)
+	MOVW $1275, R12
+	B    callbackasm1(SB)
+	MOVW $1276, R12
+	B    callbackasm1(SB)
+	MOVW $1277, R12
+	B    callbackasm1(SB)
+	MOVW $1278, R12
+	B    callbackasm1(SB)
+	MOVW $1279, R12
+	B    callbackasm1(SB)
+	MOVW $1280, R12
+	B    callbackasm1(SB)
+	MOVW $1281, R12
+	B    callbackasm1(SB)
+	MOVW $1282, R12
+	B    callbackasm1(SB)
+	MOVW $1283, R12
+	B    callbackasm1(SB)
+	MOVW $1284, R12
+	B    callbackasm1(SB)
+	MOVW $1285, R12
+	B    callbackasm1(SB)
+	MOVW $1286, R12
+	B    callbackasm1(SB)
+	MOVW $1287, R12
+	B    callbackasm1(SB)
+	MOVW $1288, R12
+	B    callbackasm1(SB)
+	MOVW $1289, R12
+	B    callbackasm1(SB)
+	MOVW $1290, R12
+	B    callbackasm1(SB)
+	MOVW $1291, R12
+	B    callbackasm1(SB)
+	MOVW $1292, R12
+	B    callbackasm1(SB)
+	MOVW $1293, R12
+	B    callbackasm1(SB)
+	MOVW $1294, R12
+	B    callbackasm1(SB)
+	MOVW $1295, R12
+	B    callbackasm1(SB)
+	MOVW $1296, R12
+	B    callbackasm1(SB)
+	MOVW $1297, R12
+	B    callbackasm1(SB)
+	MOVW $1298, R12
+	B    callbackasm1(SB)
+	MOVW $1299, R12
+	B    callbackasm1(SB)
+	MOVW $1300, R12
+	B    callbackasm1(SB)
+	MOVW $1301, R12
+	B    callbackasm1(SB)
+	MOVW $1302, R12
+	B    callbackasm1(SB)
+	MOVW $1303, R12
+	B    callbackasm1(SB)
+	MOVW $1304, R12
+	B    callbackasm1(SB)
+	MOVW $1305, R12
+	B    callbackasm1(SB)
+	MOVW $1306, R12
+	B    callbackasm1(SB)
+	MOVW $1307, R12
+	B    callbackasm1(SB)
+	MOVW $1308, R12
+	B    callbackasm1(SB)
+	MOVW $1309, R12
+	B    callbackasm1(SB)
+	MOVW $1310, R12
+	B    callbackasm1(SB)
+	MOVW $1311, R12
+	B    callbackasm1(SB)
+	MOVW $1312, R12
+	B    callbackasm1(SB)
+	MOVW $1313, R12
+	B    callbackasm1(SB)
+	MOVW $1314, R12
+	B    callbackasm1(SB)
+	MOVW $1315, R12
+	B    callbackasm1(SB)
+	MOVW $1316, R12
+	B    callbackasm1(SB)
+	MOVW $1317, R12
+	B    callbackasm1(SB)
+	MOVW $1318, R12
+	B    callbackasm1(SB)
+	MOVW $1319, R12
+	B    callbackasm1(SB)
+	MOVW $1320, R12
+	B    callbackasm1(SB)
+	MOVW $1321, R12
+	B    callbackasm1(SB)
+	MOVW $1322, R12
+	B    callbackasm1(SB)
+	MOVW $1323, R12
+	B    callbackasm1(SB)
+	MOVW $1324, R12
+	B    callbackasm1(SB)
+	MOVW $1325, R12
+	B    callbackasm1(SB)
+	MOVW $1326, R12
+	B    callbackasm1(SB)
+	MOVW $1327, R12
+	B    callbackasm1(SB)
+	MOVW $1328, R12
+	B    callbackasm1(SB)
+	MOVW $1329, R12
+	B    callbackasm1(SB)
+	MOVW $1330, R12
+	B    callbackasm1(SB)
+	MOVW $1331, R12
+	B    callbackasm1(SB)
+	MOVW $1332, R12
+	B    callbackasm1(SB)
+	MOVW $1333, R12
+	B    callbackasm1(SB)
+	MOVW $1334, R12
+	B    callbackasm1(SB)
+	MOVW $1335, R12
+	B    callbackasm1(SB)
+	MOVW $1336, R12
+	B    callbackasm1(SB)
+	MOVW $1337, R12
+	B    callbackasm1(SB)
+	MOVW $1338, R12
+	B    callbackasm1(SB)
+	MOVW $1339, R12
+	B    callbackasm1(SB)
+	MOVW $1340, R12
+	B    callbackasm1(SB)
+	MOVW $1341, R12
+	B    callbackasm1(SB)
+	MOVW $1342, R12
+	B    callbackasm1(SB)
+	MOVW $1343, R12
+	B    callbackasm1(SB)
+	MOVW $1344, R12
+	B    callbackasm1(SB)
+	MOVW $1345, R12
+	B    callbackasm1(SB)
+	MOVW $1346, R12
+	B    callbackasm1(SB)
+	MOVW $1347, R12
+	B    callbackasm1(SB)
+	MOVW $1348, R12
+	B    callbackasm1(SB)
+	MOVW $1349, R12
+	B    callbackasm1(SB)
+	MOVW $1350, R12
+	B    callbackasm1(SB)
+	MOVW $1351, R12
+	B    callbackasm1(SB)
+	MOVW $1352, R12
+	B    callbackasm1(SB)
+	MOVW $1353, R12
+	B    callbackasm1(SB)
+	MOVW $1354, R12
+	B    callbackasm1(SB)
+	MOVW $1355, R12
+	B    callbackasm1(SB)
+	MOVW $1356, R12
+	B    callbackasm1(SB)
+	MOVW $1357, R12
+	B    callbackasm1(SB)
+	MOVW $1358, R12
+	B    callbackasm1(SB)
+	MOVW $1359, R12
+	B    callbackasm1(SB)
+	MOVW $1360, R12
+	B    callbackasm1(SB)
+	MOVW $1361, R12
+	B    callbackasm1(SB)
+	MOVW $1362, R12
+	B    callbackasm1(SB)
+	MOVW $1363, R12
+	B    callbackasm1(SB)
+	MOVW $1364, R12
+	B    callbackasm1(SB)
+	MOVW $1365, R12
+	B    callbackasm1(SB)
+	MOVW $1366, R12
+	B    callbackasm1(SB)
+	MOVW $1367, R12
+	B    callbackasm1(SB)
+	MOVW $1368, R12
+	B    callbackasm1(SB)
+	MOVW $1369, R12
+	B    callbackasm1(SB)
+	MOVW $1370, R12
+	B    callbackasm1(SB)
+	MOVW $1371, R12
+	B    callbackasm1(SB)
+	MOVW $1372, R12
+	B    callbackasm1(SB)
+	MOVW $1373, R12
+	B    callbackasm1(SB)
+	MOVW $1374, R12
+	B    callbackasm1(SB)
+	MOVW $1375, R12
+	B    callbackasm1(SB)
+	MOVW $1376, R12
+	B    callbackasm1(SB)
+	MOVW $1377, R12
+	B    callbackasm1(SB)
+	MOVW $1378, R12
+	B    callbackasm1(SB)
+	MOVW $1379, R12
+	B    callbackasm1(SB)
+	MOVW $1380, R12
+	B    callbackasm1(SB)
+	MOVW $1381, R12
+	B    callbackasm1(SB)
+	MOVW $1382, R12
+	B    callbackasm1(SB)
+	MOVW $1383, R12
+	B    callbackasm1(SB)
+	MOVW $1384, R12
+	B    callbackasm1(SB)
+	MOVW $1385, R12
+	B    callbackasm1(SB)
+	MOVW $1386, R12
+	B    callbackasm1(SB)
+	MOVW $1387, R12
+	B    callbackasm1(SB)
+	MOVW $1388, R12
+	B    callbackasm1(SB)
+	MOVW $1389, R12
+	B    callbackasm1(SB)
+	MOVW $1390, R12
+	B    callbackasm1(SB)
+	MOVW $1391, R12
+	B    callbackasm1(SB)
+	MOVW $1392, R12
+	B    callbackasm1(SB)
+	MOVW $1393, R12
+	B    callbackasm1(SB)
+	MOVW $1394, R12
+	B    callbackasm1(SB)
+	MOVW $1395, R12
+	B    callbackasm1(SB)
+	MOVW $1396, R12
+	B    callbackasm1(SB)
+	MOVW $1397, R12
+	B    callbackasm1(SB)
+	MOVW $1398, R12
+	B    callbackasm1(SB)
+	MOVW $1399, R12
+	B    callbackasm1(SB)
+	MOVW $1400, R12
+	B    callbackasm1(SB)
+	MOVW $1401, R12
+	B    callbackasm1(SB)
+	MOVW $1402, R12
+	B    callbackasm1(SB)
+	MOVW $1403, R12
+	B    callbackasm1(SB)
+	MOVW $1404, R12
+	B    callbackasm1(SB)
+	MOVW $1405, R12
+	B    callbackasm1(SB)
+	MOVW $1406, R12
+	B    callbackasm1(SB)
+	MOVW $1407, R12
+	B    callbackasm1(SB)
+	MOVW $1408, R12
+	B    callbackasm1(SB)
+	MOVW $1409, R12
+	B    callbackasm1(SB)
+	MOVW $1410, R12
+	B    callbackasm1(SB)
+	MOVW $1411, R12
+	B    callbackasm1(SB)
+	MOVW $1412, R12
+	B    callbackasm1(SB)
+	MOVW $1413, R12
+	B    callbackasm1(SB)
+	MOVW $1414, R12
+	B    callbackasm1(SB)
+	MOVW $1415, R12
+	B    callbackasm1(SB)
+	MOVW $1416, R12
+	B    callbackasm1(SB)
+	MOVW $1417, R12
+	B    callbackasm1(SB)
+	MOVW $1418, R12
+	B    callbackasm1(SB)
+	MOVW $1419, R12
+	B    callbackasm1(SB)
+	MOVW $1420, R12
+	B    callbackasm1(SB)
+	MOVW $1421, R12
+	B    callbackasm1(SB)
+	MOVW $1422, R12
+	B    callbackasm1(SB)
+	MOVW $1423, R12
+	B    callbackasm1(SB)
+	MOVW $1424, R12
+	B    callbackasm1(SB)
+	MOVW $1425, R12
+	B    callbackasm1(SB)
+	MOVW $1426, R12
+	B    callbackasm1(SB)
+	MOVW $1427, R12
+	B    callbackasm1(SB)
+	MOVW $1428, R12
+	B    callbackasm1(SB)
+	MOVW $1429, R12
+	B    callbackasm1(SB)
+	MOVW $1430, R12
+	B    callbackasm1(SB)
+	MOVW $1431, R12
+	B    callbackasm1(SB)
+	MOVW $1432, R12
+	B    callbackasm1(SB)
+	MOVW $1433, R12
+	B    callbackasm1(SB)
+	MOVW $1434, R12
+	B    callbackasm1(SB)
+	MOVW $1435, R12
+	B    callbackasm1(SB)
+	MOVW $1436, R12
+	B    callbackasm1(SB)
+	MOVW $1437, R12
+	B    callbackasm1(SB)
+	MOVW $1438, R12
+	B    callbackasm1(SB)
+	MOVW $1439, R12
+	B    callbackasm1(SB)
+	MOVW $1440, R12
+	B    callbackasm1(SB)
+	MOVW $1441, R12
+	B    callbackasm1(SB)
+	MOVW $1442, R12
+	B    callbackasm1(SB)
+	MOVW $1443, R12
+	B    callbackasm1(SB)
+	MOVW $1444, R12
+	B    callbackasm1(SB)
+	MOVW $1445, R12
+	B    callbackasm1(SB)
+	MOVW $1446, R12
+	B    callbackasm1(SB)
+	MOVW $1447, R12
+	B    callbackasm1(SB)
+	MOVW $1448, R12
+	B    callbackasm1(SB)
+	MOVW $1449, R12
+	B    callbackasm1(SB)
+	MOVW $1450, R12
+	B    callbackasm1(SB)
+	MOVW $1451, R12
+	B    callbackasm1(SB)
+	MOVW $1452, R12
+	B    callbackasm1(SB)
+	MOVW $1453, R12
+	B    callbackasm1(SB)
+	MOVW $1454, R12
+	B    callbackasm1(SB)
+	MOVW $1455, R12
+	B    callbackasm1(SB)
+	MOVW $1456, R12
+	B    callbackasm1(SB)
+	MOVW $1457, R12
+	B    callbackasm1(SB)
+	MOVW $1458, R12
+	B    callbackasm1(SB)
+	MOVW $1459, R12
+	B    callbackasm1(SB)
+	MOVW $1460, R12
+	B    callbackasm1(SB)
+	MOVW $1461, R12
+	B    callbackasm1(SB)
+	MOVW $1462, R12
+	B    callbackasm1(SB)
+	MOVW $1463, R12
+	B    callbackasm1(SB)
+	MOVW $1464, R12
+	B    callbackasm1(SB)
+	MOVW $1465, R12
+	B    callbackasm1(SB)
+	MOVW $1466, R12
+	B    callbackasm1(SB)
+	MOVW $1467, R12
+	B    callbackasm1(SB)
+	MOVW $1468, R12
+	B    callbackasm1(SB)
+	MOVW $1469, R12
+	B    callbackasm1(SB)
+	MOVW $1470, R12
+	B    callbackasm1(SB)
+	MOVW $1471, R12
+	B    callbackasm1(SB)
+	MOVW $1472, R12
+	B    callbackasm1(SB)
+	MOVW $1473, R12
+	B    callbackasm1(SB)
+	MOVW $1474, R12
+	B    callbackasm1(SB)
+	MOVW $1475, R12
+	B    callbackasm1(SB)
+	MOVW $1476, R12
+	B    callbackasm1(SB)
+	MOVW $1477, R12
+	B    callbackasm1(SB)
+	MOVW $1478, R12
+	B    callbackasm1(SB)
+	MOVW $1479, R12
+	B    callbackasm1(SB)
+	MOVW $1480, R12
+	B    callbackasm1(SB)
+	MOVW $1481, R12
+	B    callbackasm1(SB)
+	MOVW $1482, R12
+	B    callbackasm1(SB)
+	MOVW $1483, R12
+	B    callbackasm1(SB)
+	MOVW $1484, R12
+	B    callbackasm1(SB)
+	MOVW $1485, R12
+	B    callbackasm1(SB)
+	MOVW $1486, R12
+	B    callbackasm1(SB)
+	MOVW $1487, R12
+	B    callbackasm1(SB)
+	MOVW $1488, R12
+	B    callbackasm1(SB)
+	MOVW $1489, R12
+	B    callbackasm1(SB)
+	MOVW $1490, R12
+	B    callbackasm1(SB)
+	MOVW $1491, R12
+	B    callbackasm1(SB)
+	MOVW $1492, R12
+	B    callbackasm1(SB)
+	MOVW $1493, R12
+	B    callbackasm1(SB)
+	MOVW $1494, R12
+	B    callbackasm1(SB)
+	MOVW $1495, R12
+	B    callbackasm1(SB)
+	MOVW $1496, R12
+	B    callbackasm1(SB)
+	MOVW $1497, R12
+	B    callbackasm1(SB)
+	MOVW $1498, R12
+	B    callbackasm1(SB)
+	MOVW $1499, R12
+	B    callbackasm1(SB)
+	MOVW $1500, R12
+	B    callbackasm1(SB)
+	MOVW $1501, R12
+	B    callbackasm1(SB)
+	MOVW $1502, R12
+	B    callbackasm1(SB)
+	MOVW $1503, R12
+	B    callbackasm1(SB)
+	MOVW $1504, R12
+	B    callbackasm1(SB)
+	MOVW $1505, R12
+	B    callbackasm1(SB)
+	MOVW $1506, R12
+	B    callbackasm1(SB)
+	MOVW $1507, R12
+	B    callbackasm1(SB)
+	MOVW $1508, R12
+	B    callbackasm1(SB)
+	MOVW $1509, R12
+	B    callbackasm1(SB)
+	MOVW $1510, R12
+	B    callbackasm1(SB)
+	MOVW $1511, R12
+	B    callbackasm1(SB)
+	MOVW $1512, R12
+	B    callbackasm1(SB)
+	MOVW $1513, R12
+	B    callbackasm1(SB)
+	MOVW $1514, R12
+	B    callbackasm1(SB)
+	MOVW $1515, R12
+	B    callbackasm1(SB)
+	MOVW $1516, R12
+	B    callbackasm1(SB)
+	MOVW $1517, R12
+	B    callbackasm1(SB)
+	MOVW $1518, R12
+	B    callbackasm1(SB)
+	MOVW $1519, R12
+	B    callbackasm1(SB)
+	MOVW $1520, R12
+	B    callbackasm1(SB)
+	MOVW $1521, R12
+	B    callbackasm1(SB)
+	MOVW $1522, R12
+	B    callbackasm1(SB)
+	MOVW $1523, R12
+	B    callbackasm1(SB)
+	MOVW $1524, R12
+	B    callbackasm1(SB)
+	MOVW $1525, R12
+	B    callbackasm1(SB)
+	MOVW $1526, R12
+	B    callbackasm1(SB)
+	MOVW $1527, R12
+	B    callbackasm1(SB)
+	MOVW $1528, R12
+	B    callbackasm1(SB)
+	MOVW $1529, R12
+	B    callbackasm1(SB)
+	MOVW $1530, R12
+	B    callbackasm1(SB)
+	MOVW $1531, R12
+	B    callbackasm1(SB)
+	MOVW $1532, R12
+	B    callbackasm1(SB)
+	MOVW $1533, R12
+	B    callbackasm1(SB)
+	MOVW $1534, R12
+	B    callbackasm1(SB)
+	MOVW $1535, R12
+	B    callbackasm1(SB)
+	MOVW $1536, R12
+	B    callbackasm1(SB)
+	MOVW $1537, R12
+	B    callbackasm1(SB)
+	MOVW $1538, R12
+	B    callbackasm1(SB)
+	MOVW $1539, R12
+	B    callbackasm1(SB)
+	MOVW $1540, R12
+	B    callbackasm1(SB)
+	MOVW $1541, R12
+	B    callbackasm1(SB)
+	MOVW $1542, R12
+	B    callbackasm1(SB)
+	MOVW $1543, R12
+	B    callbackasm1(SB)
+	MOVW $1544, R12
+	B    callbackasm1(SB)
+	MOVW $1545, R12
+	B    callbackasm1(SB)
+	MOVW $1546, R12
+	B    callbackasm1(SB)
+	MOVW $1547, R12
+	B    callbackasm1(SB)
+	MOVW $1548, R12
+	B    callbackasm1(SB)
+	MOVW $1549, R12
+	B    callbackasm1(SB)
+	MOVW $1550, R12
+	B    callbackasm1(SB)
+	MOVW $1551, R12
+	B    callbackasm1(SB)
+	MOVW $1552, R12
+	B    callbackasm1(SB)
+	MOVW $1553, R12
+	B    callbackasm1(SB)
+	MOVW $1554, R12
+	B    callbackasm1(SB)
+	MOVW $1555, R12
+	B    callbackasm1(SB)
+	MOVW $1556, R12
+	B    callbackasm1(SB)
+	MOVW $1557, R12
+	B    callbackasm1(SB)
+	MOVW $1558, R12
+	B    callbackasm1(SB)
+	MOVW $1559, R12
+	B    callbackasm1(SB)
+	MOVW $1560, R12
+	B    callbackasm1(SB)
+	MOVW $1561, R12
+	B    callbackasm1(SB)
+	MOVW $1562, R12
+	B    callbackasm1(SB)
+	MOVW $1563, R12
+	B    callbackasm1(SB)
+	MOVW $1564, R12
+	B    callbackasm1(SB)
+	MOVW $1565, R12
+	B    callbackasm1(SB)
+	MOVW $1566, R12
+	B    callbackasm1(SB)
+	MOVW $1567, R12
+	B    callbackasm1(SB)
+	MOVW $1568, R12
+	B    callbackasm1(SB)
+	MOVW $1569, R12
+	B    callbackasm1(SB)
+	MOVW $1570, R12
+	B    callbackasm1(SB)
+	MOVW $1571, R12
+	B    callbackasm1(SB)
+	MOVW $1572, R12
+	B    callbackasm1(SB)
+	MOVW $1573, R12
+	B    callbackasm1(SB)
+	MOVW $1574, R12
+	B    callbackasm1(SB)
+	MOVW $1575, R12
+	B    callbackasm1(SB)
+	MOVW $1576, R12
+	B    callbackasm1(SB)
+	MOVW $1577, R12
+	B    callbackasm1(SB)
+	MOVW $1578, R12
+	B    callbackasm1(SB)
+	MOVW $1579, R12
+	B    callbackasm1(SB)
+	MOVW $1580, R12
+	B    callbackasm1(SB)
+	MOVW $1581, R12
+	B    callbackasm1(SB)
+	MOVW $1582, R12
+	B    callbackasm1(SB)
+	MOVW $1583, R12
+	B    callbackasm1(SB)
+	MOVW $1584, R12
+	B    callbackasm1(SB)
+	MOVW $1585, R12
+	B    callbackasm1(SB)
+	MOVW $1586, R12
+	B    callbackasm1(SB)
+	MOVW $1587, R12
+	B    callbackasm1(SB)
+	MOVW $1588, R12
+	B    callbackasm1(SB)
+	MOVW $1589, R12
+	B    callbackasm1(SB)
+	MOVW $1590, R12
+	B    callbackasm1(SB)
+	MOVW $1591, R12
+	B    callbackasm1(SB)
+	MOVW $1592, R12
+	B    callbackasm1(SB)
+	MOVW $1593, R12
+	B    callbackasm1(SB)
+	MOVW $1594, R12
+	B    callbackasm1(SB)
+	MOVW $1595, R12
+	B    callbackasm1(SB)
+	MOVW $1596, R12
+	B    callbackasm1(SB)
+	MOVW $1597, R12
+	B    callbackasm1(SB)
+	MOVW $1598, R12
+	B    callbackasm1(SB)
+	MOVW $1599, R12
+	B    callbackasm1(SB)
+	MOVW $1600, R12
+	B    callbackasm1(SB)
+	MOVW $1601, R12
+	B    callbackasm1(SB)
+	MOVW $1602, R12
+	B    callbackasm1(SB)
+	MOVW $1603, R12
+	B    callbackasm1(SB)
+	MOVW $1604, R12
+	B    callbackasm1(SB)
+	MOVW $1605, R12
+	B    callbackasm1(SB)
+	MOVW $1606, R12
+	B    callbackasm1(SB)
+	MOVW $1607, R12
+	B    callbackasm1(SB)
+	MOVW $1608, R12
+	B    callbackasm1(SB)
+	MOVW $1609, R12
+	B    callbackasm1(SB)
+	MOVW $1610, R12
+	B    callbackasm1(SB)
+	MOVW $1611, R12
+	B    callbackasm1(SB)
+	MOVW $1612, R12
+	B    callbackasm1(SB)
+	MOVW $1613, R12
+	B    callbackasm1(SB)
+	MOVW $1614, R12
+	B    callbackasm1(SB)
+	MOVW $1615, R12
+	B    callbackasm1(SB)
+	MOVW $1616, R12
+	B    callbackasm1(SB)
+	MOVW $1617, R12
+	B    callbackasm1(SB)
+	MOVW $1618, R12
+	B    callbackasm1(SB)
+	MOVW $1619, R12
+	B    callbackasm1(SB)
+	MOVW $1620, R12
+	B    callbackasm1(SB)
+	MOVW $1621, R12
+	B    callbackasm1(SB)
+	MOVW $1622, R12
+	B    callbackasm1(SB)
+	MOVW $1623, R12
+	B    callbackasm1(SB)
+	MOVW $1624, R12
+	B    callbackasm1(SB)
+	MOVW $1625, R12
+	B    callbackasm1(SB)
+	MOVW $1626, R12
+	B    callbackasm1(SB)
+	MOVW $1627, R12
+	B    callbackasm1(SB)
+	MOVW $1628, R12
+	B    callbackasm1(SB)
+	MOVW $1629, R12
+	B    callbackasm1(SB)
+	MOVW $1630, R12
+	B    callbackasm1(SB)
+	MOVW $1631, R12
+	B    callbackasm1(SB)
+	MOVW $1632, R12
+	B    callbackasm1(SB)
+	MOVW $1633, R12
+	B    callbackasm1(SB)
+	MOVW $1634, R12
+	B    callbackasm1(SB)
+	MOVW $1635, R12
+	B    callbackasm1(SB)
+	MOVW $1636, R12
+	B    callbackasm1(SB)
+	MOVW $1637, R12
+	B    callbackasm1(SB)
+	MOVW $1638, R12
+	B    callbackasm1(SB)
+	MOVW $1639, R12
+	B    callbackasm1(SB)
+	MOVW $1640, R12
+	B    callbackasm1(SB)
+	MOVW $1641, R12
+	B    callbackasm1(SB)
+	MOVW $1642, R12
+	B    callbackasm1(SB)
+	MOVW $1643, R12
+	B    callbackasm1(SB)
+	MOVW $1644, R12
+	B    callbackasm1(SB)
+	MOVW $1645, R12
+	B    callbackasm1(SB)
+	MOVW $1646, R12
+	B    callbackasm1(SB)
+	MOVW $1647, R12
+	B    callbackasm1(SB)
+	MOVW $1648, R12
+	B    callbackasm1(SB)
+	MOVW $1649, R12
+	B    callbackasm1(SB)
+	MOVW $1650, R12
+	B    callbackasm1(SB)
+	MOVW $1651, R12
+	B    callbackasm1(SB)
+	MOVW $1652, R12
+	B    callbackasm1(SB)
+	MOVW $1653, R12
+	B    callbackasm1(SB)
+	MOVW $1654, R12
+	B    callbackasm1(SB)
+	MOVW $1655, R12
+	B    callbackasm1(SB)
+	MOVW $1656, R12
+	B    callbackasm1(SB)
+	MOVW $1657, R12
+	B    callbackasm1(SB)
+	MOVW $1658, R12
+	B    callbackasm1(SB)
+	MOVW $1659, R12
+	B    callbackasm1(SB)
+	MOVW $1660, R12
+	B    callbackasm1(SB)
+	MOVW $1661, R12
+	B    callbackasm1(SB)
+	MOVW $1662, R12
+	B    callbackasm1(SB)
+	MOVW $1663, R12
+	B    callbackasm1(SB)
+	MOVW $1664, R12
+	B    callbackasm1(SB)
+	MOVW $1665, R12
+	B    callbackasm1(SB)
+	MOVW $1666, R12
+	B    callbackasm1(SB)
+	MOVW $1667, R12
+	B    callbackasm1(SB)
+	MOVW $1668, R12
+	B    callbackasm1(SB)
+	MOVW $1669, R12
+	B    callbackasm1(SB)
+	MOVW $1670, R12
+	B    callbackasm1(SB)
+	MOVW $1671, R12
+	B    callbackasm1(SB)
+	MOVW $1672, R12
+	B    callbackasm1(SB)
+	MOVW $1673, R12
+	B    callbackasm1(SB)
+	MOVW $1674, R12
+	B    callbackasm1(SB)
+	MOVW $1675, R12
+	B    callbackasm1(SB)
+	MOVW $1676, R12
+	B    callbackasm1(SB)
+	MOVW $1677, R12
+	B    callbackasm1(SB)
+	MOVW $1678, R12
+	B    callbackasm1(SB)
+	MOVW $1679, R12
+	B    callbackasm1(SB)
+	MOVW $1680, R12
+	B    callbackasm1(SB)
+	MOVW $1681, R12
+	B    callbackasm1(SB)
+	MOVW $1682, R12
+	B    callbackasm1(SB)
+	MOVW $1683, R12
+	B    callbackasm1(SB)
+	MOVW $1684, R12
+	B    callbackasm1(SB)
+	MOVW $1685, R12
+	B    callbackasm1(SB)
+	MOVW $1686, R12
+	B    callbackasm1(SB)
+	MOVW $1687, R12
+	B    callbackasm1(SB)
+	MOVW $1688, R12
+	B    callbackasm1(SB)
+	MOVW $1689, R12
+	B    callbackasm1(SB)
+	MOVW $1690, R12
+	B    callbackasm1(SB)
+	MOVW $1691, R12
+	B    callbackasm1(SB)
+	MOVW $1692, R12
+	B    callbackasm1(SB)
+	MOVW $1693, R12
+	B    callbackasm1(SB)
+	MOVW $1694, R12
+	B    callbackasm1(SB)
+	MOVW $1695, R12
+	B    callbackasm1(SB)
+	MOVW $1696, R12
+	B    callbackasm1(SB)
+	MOVW $1697, R12
+	B    callbackasm1(SB)
+	MOVW $1698, R12
+	B    callbackasm1(SB)
+	MOVW $1699, R12
+	B    callbackasm1(SB)
+	MOVW $1700, R12
+	B    callbackasm1(SB)
+	MOVW $1701, R12
+	B    callbackasm1(SB)
+	MOVW $1702, R12
+	B    callbackasm1(SB)
+	MOVW $1703, R12
+	B    callbackasm1(SB)
+	MOVW $1704, R12
+	B    callbackasm1(SB)
+	MOVW $1705, R12
+	B    callbackasm1(SB)
+	MOVW $1706, R12
+	B    callbackasm1(SB)
+	MOVW $1707, R12
+	B    callbackasm1(SB)
+	MOVW $1708, R12
+	B    callbackasm1(SB)
+	MOVW $1709, R12
+	B    callbackasm1(SB)
+	MOVW $1710, R12
+	B    callbackasm1(SB)
+	MOVW $1711, R12
+	B    callbackasm1(SB)
+	MOVW $1712, R12
+	B    callbackasm1(SB)
+	MOVW $1713, R12
+	B    callbackasm1(SB)
+	MOVW $1714, R12
+	B    callbackasm1(SB)
+	MOVW $1715, R12
+	B    callbackasm1(SB)
+	MOVW $1716, R12
+	B    callbackasm1(SB)
+	MOVW $1717, R12
+	B    callbackasm1(SB)
+	MOVW $1718, R12
+	B    callbackasm1(SB)
+	MOVW $1719, R12
+	B    callbackasm1(SB)
+	MOVW $1720, R12
+	B    callbackasm1(SB)
+	MOVW $1721, R12
+	B    callbackasm1(SB)
+	MOVW $1722, R12
+	B    callbackasm1(SB)
+	MOVW $1723, R12
+	B    callbackasm1(SB)
+	MOVW $1724, R12
+	B    callbackasm1(SB)
+	MOVW $1725, R12
+	B    callbackasm1(SB)
+	MOVW $1726, R12
+	B    callbackasm1(SB)
+	MOVW $1727, R12
+	B    callbackasm1(SB)
+	MOVW $1728, R12
+	B    callbackasm1(SB)
+	MOVW $1729, R12
+	B    callbackasm1(SB)
+	MOVW $1730, R12
+	B    callbackasm1(SB)
+	MOVW $1731, R12
+	B    callbackasm1(SB)
+	MOVW $1732, R12
+	B    callbackasm1(SB)
+	MOVW $1733, R12
+	B    callbackasm1(SB)
+	MOVW $1734, R12
+	B    callbackasm1(SB)
+	MOVW $1735, R12
+	B    callbackasm1(SB)
+	MOVW $1736, R12
+	B    callbackasm1(SB)
+	MOVW $1737, R12
+	B    callbackasm1(SB)
+	MOVW $1738, R12
+	B    callbackasm1(SB)
+	MOVW $1739, R12
+	B    callbackasm1(SB)
+	MOVW $1740, R12
+	B    callbackasm1(SB)
+	MOVW $1741, R12
+	B    callbackasm1(SB)
+	MOVW $1742, R12
+	B    callbackasm1(SB)
+	MOVW $1743, R12
+	B    callbackasm1(SB)
+	MOVW $1744, R12
+	B    callbackasm1(SB)
+	MOVW $1745, R12
+	B    callbackasm1(SB)
+	MOVW $1746, R12
+	B    callbackasm1(SB)
+	MOVW $1747, R12
+	B    callbackasm1(SB)
+	MOVW $1748, R12
+	B    callbackasm1(SB)
+	MOVW $1749, R12
+	B    callbackasm1(SB)
+	MOVW $1750, R12
+	B    callbackasm1(SB)
+	MOVW $1751, R12
+	B    callbackasm1(SB)
+	MOVW $1752, R12
+	B    callbackasm1(SB)
+	MOVW $1753, R12
+	B    callbackasm1(SB)
+	MOVW $1754, R12
+	B    callbackasm1(SB)
+	MOVW $1755, R12
+	B    callbackasm1(SB)
+	MOVW $1756, R12
+	B    callbackasm1(SB)
+	MOVW $1757, R12
+	B    callbackasm1(SB)
+	MOVW $1758, R12
+	B    callbackasm1(SB)
+	MOVW $1759, R12
+	B    callbackasm1(SB)
+	MOVW $1760, R12
+	B    callbackasm1(SB)
+	MOVW $1761, R12
+	B    callbackasm1(SB)
+	MOVW $1762, R12
+	B    callbackasm1(SB)
+	MOVW $1763, R12
+	B    callbackasm1(SB)
+	MOVW $1764, R12
+	B    callbackasm1(SB)
+	MOVW $1765, R12
+	B    callbackasm1(SB)
+	MOVW $1766, R12
+	B    callbackasm1(SB)
+	MOVW $1767, R12
+	B    callbackasm1(SB)
+	MOVW $1768, R12
+	B    callbackasm1(SB)
+	MOVW $1769, R12
+	B    callbackasm1(SB)
+	MOVW $1770, R12
+	B    callbackasm1(SB)
+	MOVW $1771, R12
+	B    callbackasm1(SB)
+	MOVW $1772, R12
+	B    callbackasm1(SB)
+	MOVW $1773, R12
+	B    callbackasm1(SB)
+	MOVW $1774, R12
+	B    callbackasm1(SB)
+	MOVW $1775, R12
+	B    callbackasm1(SB)
+	MOVW $1776, R12
+	B    callbackasm1(SB)
+	MOVW $1777, R12
+	B    callbackasm1(SB)
+	MOVW $1778, R12
+	B    callbackasm1(SB)
+	MOVW $1779, R12
+	B    callbackasm1(SB)
+	MOVW $1780, R12
+	B    callbackasm1(SB)
+	MOVW $1781, R12
+	B    callbackasm1(SB)
+	MOVW $1782, R12
+	B    callbackasm1(SB)
+	MOVW $1783, R12
+	B    callbackasm1(SB)
+	MOVW $1784, R12
+	B    callbackasm1(SB)
+	MOVW $1785, R12
+	B    callbackasm1(SB)
+	MOVW $1786, R12
+	B    callbackasm1(SB)
+	MOVW $1787, R12
+	B    callbackasm1(SB)
+	MOVW $1788, R12
+	B    callbackasm1(SB)
+	MOVW $1789, R12
+	B    callbackasm1(SB)
+	MOVW $1790, R12
+	B    callbackasm1(SB)
+	MOVW $1791, R12
+	B    callbackasm1(SB)
+	MOVW $1792, R12
+	B    callbackasm1(SB)
+	MOVW $1793, R12
+	B    callbackasm1(SB)
+	MOVW $1794, R12
+	B    callbackasm1(SB)
+	MOVW $1795, R12
+	B    callbackasm1(SB)
+	MOVW $1796, R12
+	B    callbackasm1(SB)
+	MOVW $1797, R12
+	B    callbackasm1(SB)
+	MOVW $1798, R12
+	B    callbackasm1(SB)
+	MOVW $1799, R12
+	B    callbackasm1(SB)
+	MOVW $1800, R12
+	B    callbackasm1(SB)
+	MOVW $1801, R12
+	B    callbackasm1(SB)
+	MOVW $1802, R12
+	B    callbackasm1(SB)
+	MOVW $1803, R12
+	B    callbackasm1(SB)
+	MOVW $1804, R12
+	B    callbackasm1(SB)
+	MOVW $1805, R12
+	B    callbackasm1(SB)
+	MOVW $1806, R12
+	B    callbackasm1(SB)
+	MOVW $1807, R12
+	B    callbackasm1(SB)
+	MOVW $1808, R12
+	B    callbackasm1(SB)
+	MOVW $1809, R12
+	B    callbackasm1(SB)
+	MOVW $1810, R12
+	B    callbackasm1(SB)
+	MOVW $1811, R12
+	B    callbackasm1(SB)
+	MOVW $1812, R12
+	B    callbackasm1(SB)
+	MOVW $1813, R12
+	B    callbackasm1(SB)
+	MOVW $1814, R12
+	B    callbackasm1(SB)
+	MOVW $1815, R12
+	B    callbackasm1(SB)
+	MOVW $1816, R12
+	B    callbackasm1(SB)
+	MOVW $1817, R12
+	B    callbackasm1(SB)
+	MOVW $1818, R12
+	B    callbackasm1(SB)
+	MOVW $1819, R12
+	B    callbackasm1(SB)
+	MOVW $1820, R12
+	B    callbackasm1(SB)
+	MOVW $1821, R12
+	B    callbackasm1(SB)
+	MOVW $1822, R12
+	B    callbackasm1(SB)
+	MOVW $1823, R12
+	B    callbackasm1(SB)
+	MOVW $1824, R12
+	B    callbackasm1(SB)
+	MOVW $1825, R12
+	B    callbackasm1(SB)
+	MOVW $1826, R12
+	B    callbackasm1(SB)
+	MOVW $1827, R12
+	B    callbackasm1(SB)
+	MOVW $1828, R12
+	B    callbackasm1(SB)
+	MOVW $1829, R12
+	B    callbackasm1(SB)
+	MOVW $1830, R12
+	B    callbackasm1(SB)
+	MOVW $1831, R12
+	B    callbackasm1(SB)
+	MOVW $1832, R12
+	B    callbackasm1(SB)
+	MOVW $1833, R12
+	B    callbackasm1(SB)
+	MOVW $1834, R12
+	B    callbackasm1(SB)
+	MOVW $1835, R12
+	B    callbackasm1(SB)
+	MOVW $1836, R12
+	B    callbackasm1(SB)
+	MOVW $1837, R12
+	B    callbackasm1(SB)
+	MOVW $1838, R12
+	B    callbackasm1(SB)
+	MOVW $1839, R12
+	B    callbackasm1(SB)
+	MOVW $1840, R12
+	B    callbackasm1(SB)
+	MOVW $1841, R12
+	B    callbackasm1(SB)
+	MOVW $1842, R12
+	B    callbackasm1(SB)
+	MOVW $1843, R12
+	B    callbackasm1(SB)
+	MOVW $1844, R12
+	B    callbackasm1(SB)
+	MOVW $1845, R12
+	B    callbackasm1(SB)
+	MOVW $1846, R12
+	B    callbackasm1(SB)
+	MOVW $1847, R12
+	B    callbackasm1(SB)
+	MOVW $1848, R12
+	B    callbackasm1(SB)
+	MOVW $1849, R12
+	B    callbackasm1(SB)
+	MOVW $1850, R12
+	B    callbackasm1(SB)
+	MOVW $1851, R12
+	B    callbackasm1(SB)
+	MOVW $1852, R12
+	B    callbackasm1(SB)
+	MOVW $1853, R12
+	B    callbackasm1(SB)
+	MOVW $1854, R12
+	B    callbackasm1(SB)
+	MOVW $1855, R12
+	B    callbackasm1(SB)
+	MOVW $1856, R12
+	B    callbackasm1(SB)
+	MOVW $1857, R12
+	B    callbackasm1(SB)
+	MOVW $1858, R12
+	B    callbackasm1(SB)
+	MOVW $1859, R12
+	B    callbackasm1(SB)
+	MOVW $1860, R12
+	B    callbackasm1(SB)
+	MOVW $1861, R12
+	B    callbackasm1(SB)
+	MOVW $1862, R12
+	B    callbackasm1(SB)
+	MOVW $1863, R12
+	B    callbackasm1(SB)
+	MOVW $1864, R12
+	B    callbackasm1(SB)
+	MOVW $1865, R12
+	B    callbackasm1(SB)
+	MOVW $1866, R12
+	B    callbackasm1(SB)
+	MOVW $1867, R12
+	B    callbackasm1(SB)
+	MOVW $1868, R12
+	B    callbackasm1(SB)
+	MOVW $1869, R12
+	B    callbackasm1(SB)
+	MOVW $1870, R12
+	B    callbackasm1(SB)
+	MOVW $1871, R12
+	B    callbackasm1(SB)
+	MOVW $1872, R12
+	B    callbackasm1(SB)
+	MOVW $1873, R12
+	B    callbackasm1(SB)
+	MOVW $1874, R12
+	B    callbackasm1(SB)
+	MOVW $1875, R12
+	B    callbackasm1(SB)
+	MOVW $1876, R12
+	B    callbackasm1(SB)
+	MOVW $1877, R12
+	B    callbackasm1(SB)
+	MOVW $1878, R12
+	B    callbackasm1(SB)
+	MOVW $1879, R12
+	B    callbackasm1(SB)
+	MOVW $1880, R12
+	B    callbackasm1(SB)
+	MOVW $1881, R12
+	B    callbackasm1(SB)
+	MOVW $1882, R12
+	B    callbackasm1(SB)
+	MOVW $1883, R12
+	B    callbackasm1(SB)
+	MOVW $1884, R12
+	B    callbackasm1(SB)
+	MOVW $1885, R12
+	B    callbackasm1(SB)
+	MOVW $1886, R12
+	B    callbackasm1(SB)
+	MOVW $1887, R12
+	B    callbackasm1(SB)
+	MOVW $1888, R12
+	B    callbackasm1(SB)
+	MOVW $1889, R12
+	B    callbackasm1(SB)
+	MOVW $1890, R12
+	B    callbackasm1(SB)
+	MOVW $1891, R12
+	B    callbackasm1(SB)
+	MOVW $1892, R12
+	B    callbackasm1(SB)
+	MOVW $1893, R12
+	B    callbackasm1(SB)
+	MOVW $1894, R12
+	B    callbackasm1(SB)
+	MOVW $1895, R12
+	B    callbackasm1(SB)
+	MOVW $1896, R12
+	B    callbackasm1(SB)
+	MOVW $1897, R12
+	B    callbackasm1(SB)
+	MOVW $1898, R12
+	B    callbackasm1(SB)
+	MOVW $1899, R12
+	B    callbackasm1(SB)
+	MOVW $1900, R12
+	B    callbackasm1(SB)
+	MOVW $1901, R12
+	B    callbackasm1(SB)
+	MOVW $1902, R12
+	B    callbackasm1(SB)
+	MOVW $1903, R12
+	B    callbackasm1(SB)
+	MOVW $1904, R12
+	B    callbackasm1(SB)
+	MOVW $1905, R12
+	B    callbackasm1(SB)
+	MOVW $1906, R12
+	B    callbackasm1(SB)
+	MOVW $1907, R12
+	B    callbackasm1(SB)
+	MOVW $1908, R12
+	B    callbackasm1(SB)
+	MOVW $1909, R12
+	B    callbackasm1(SB)
+	MOVW $1910, R12
+	B    callbackasm1(SB)
+	MOVW $1911, R12
+	B    callbackasm1(SB)
+	MOVW $1912, R12
+	B    callbackasm1(SB)
+	MOVW $1913, R12
+	B    callbackasm1(SB)
+	MOVW $1914, R12
+	B    callbackasm1(SB)
+	MOVW $1915, R12
+	B    callbackasm1(SB)
+	MOVW $1916, R12
+	B    callbackasm1(SB)
+	MOVW $1917, R12
+	B    callbackasm1(SB)
+	MOVW $1918, R12
+	B    callbackasm1(SB)
+	MOVW $1919, R12
+	B    callbackasm1(SB)
+	MOVW $1920, R12
+	B    callbackasm1(SB)
+	MOVW $1921, R12
+	B    callbackasm1(SB)
+	MOVW $1922, R12
+	B    callbackasm1(SB)
+	MOVW $1923, R12
+	B    callbackasm1(SB)
+	MOVW $1924, R12
+	B    callbackasm1(SB)
+	MOVW $1925, R12
+	B    callbackasm1(SB)
+	MOVW $1926, R12
+	B    callbackasm1(SB)
+	MOVW $1927, R12
+	B    callbackasm1(SB)
+	MOVW $1928, R12
+	B    callbackasm1(SB)
+	MOVW $1929, R12
+	B    callbackasm1(SB)
+	MOVW $1930, R12
+	B    callbackasm1(SB)
+	MOVW $1931, R12
+	B    callbackasm1(SB)
+	MOVW $1932, R12
+	B    callbackasm1(SB)
+	MOVW $1933, R12
+	B    callbackasm1(SB)
+	MOVW $1934, R12
+	B    callbackasm1(SB)
+	MOVW $1935, R12
+	B    callbackasm1(SB)
+	MOVW $1936, R12
+	B    callbackasm1(SB)
+	MOVW $1937, R12
+	B    callbackasm1(SB)
+	MOVW $1938, R12
+	B    callbackasm1(SB)
+	MOVW $1939, R12
+	B    callbackasm1(SB)
+	MOVW $1940, R12
+	B    callbackasm1(SB)
+	MOVW $1941, R12
+	B    callbackasm1(SB)
+	MOVW $1942, R12
+	B    callbackasm1(SB)
+	MOVW $1943, R12
+	B    callbackasm1(SB)
+	MOVW $1944, R12
+	B    callbackasm1(SB)
+	MOVW $1945, R12
+	B    callbackasm1(SB)
+	MOVW $1946, R12
+	B    callbackasm1(SB)
+	MOVW $1947, R12
+	B    callbackasm1(SB)
+	MOVW $1948, R12
+	B    callbackasm1(SB)
+	MOVW $1949, R12
+	B    callbackasm1(SB)
+	MOVW $1950, R12
+	B    callbackasm1(SB)
+	MOVW $1951, R12
+	B    callbackasm1(SB)
+	MOVW $1952, R12
+	B    callbackasm1(SB)
+	MOVW $1953, R12
+	B    callbackasm1(SB)
+	MOVW $1954, R12
+	B    callbackasm1(SB)
+	MOVW $1955, R12
+	B    callbackasm1(SB)
+	MOVW $1956, R12
+	B    callbackasm1(SB)
+	MOVW $1957, R12
+	B    callbackasm1(SB)
+	MOVW $1958, R12
+	B    callbackasm1(SB)
+	MOVW $1959, R12
+	B    callbackasm1(SB)
+	MOVW $1960, R12
+	B    callbackasm1(SB)
+	MOVW $1961, R12
+	B    callbackasm1(SB)
+	MOVW $1962, R12
+	B    callbackasm1(SB)
+	MOVW $1963, R12
+	B    callbackasm1(SB)
+	MOVW $1964, R12
+	B    callbackasm1(SB)
+	MOVW $1965, R12
+	B    callbackasm1(SB)
+	MOVW $1966, R12
+	B    callbackasm1(SB)
+	MOVW $1967, R12
+	B    callbackasm1(SB)
+	MOVW $1968, R12
+	B    callbackasm1(SB)
+	MOVW $1969, R12
+	B    callbackasm1(SB)
+	MOVW $1970, R12
+	B    callbackasm1(SB)
+	MOVW $1971, R12
+	B    callbackasm1(SB)
+	MOVW $1972, R12
+	B    callbackasm1(SB)
+	MOVW $1973, R12
+	B    callbackasm1(SB)
+	MOVW $1974, R12
+	B    callbackasm1(SB)
+	MOVW $1975, R12
+	B    callbackasm1(SB)
+	MOVW $1976, R12
+	B    callbackasm1(SB)
+	MOVW $1977, R12
+	B    callbackasm1(SB)
+	MOVW $1978, R12
+	B    callbackasm1(SB)
+	MOVW $1979, R12
+	B    callbackasm1(SB)
+	MOVW $1980, R12
+	B    callbackasm1(SB)
+	MOVW $1981, R12
+	B    callbackasm1(SB)
+	MOVW $1982, R12
+	B    callbackasm1(SB)
+	MOVW $1983, R12
+	B    callbackasm1(SB)
+	MOVW $1984, R12
+	B    callbackasm1(SB)
+	MOVW $1985, R12
+	B    callbackasm1(SB)
+	MOVW $1986, R12
+	B    callbackasm1(SB)
+	MOVW $1987, R12
+	B    callbackasm1(SB)
+	MOVW $1988, R12
+	B    callbackasm1(SB)
+	MOVW $1989, R12
+	B    callbackasm1(SB)
+	MOVW $1990, R12
+	B    callbackasm1(SB)
+	MOVW $1991, R12
+	B    callbackasm1(SB)
+	MOVW $1992, R12
+	B    callbackasm1(SB)
+	MOVW $1993, R12
+	B    callbackasm1(SB)
+	MOVW $1994, R12
+	B    callbackasm1(SB)
+	MOVW $1995, R12
+	B    callbackasm1(SB)
+	MOVW $1996, R12
+	B    callbackasm1(SB)
+	MOVW $1997, R12
+	B    callbackasm1(SB)
+	MOVW $1998, R12
+	B    callbackasm1(SB)
+	MOVW $1999, R12
+	B    callbackasm1(SB)
diff --git a/vendor/github.com/ebitengine/purego/zcallback_arm64.s b/vendor/github.com/ebitengine/purego/zcallback_arm64.s
new file mode 100644
index 000000000..3fea4af8b
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/zcallback_arm64.s
@@ -0,0 +1,4014 @@
+// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+
+//go:build darwin || freebsd || linux || netbsd
+
+// External code calls into callbackasm at an offset corresponding
+// to the callback index. Callbackasm is a table of MOV and B instructions.
+// The MOV instruction loads R12 with the callback index, and the
+// B instruction branches to callbackasm1.
+// callbackasm1 takes the callback index from R12 and
+// indexes into an array that stores information about each callback.
+// It then calls the Go implementation for that callback.
+#include "textflag.h"
+
+TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
+	MOVD $0, R12
+	B    callbackasm1(SB)
+	MOVD $1, R12
+	B    callbackasm1(SB)
+	MOVD $2, R12
+	B    callbackasm1(SB)
+	MOVD $3, R12
+	B    callbackasm1(SB)
+	MOVD $4, R12
+	B    callbackasm1(SB)
+	MOVD $5, R12
+	B    callbackasm1(SB)
+	MOVD $6, R12
+	B    callbackasm1(SB)
+	MOVD $7, R12
+	B    callbackasm1(SB)
+	MOVD $8, R12
+	B    callbackasm1(SB)
+	MOVD $9, R12
+	B    callbackasm1(SB)
+	MOVD $10, R12
+	B    callbackasm1(SB)
+	MOVD $11, R12
+	B    callbackasm1(SB)
+	MOVD $12, R12
+	B    callbackasm1(SB)
+	MOVD $13, R12
+	B    callbackasm1(SB)
+	MOVD $14, R12
+	B    callbackasm1(SB)
+	MOVD $15, R12
+	B    callbackasm1(SB)
+	MOVD $16, R12
+	B    callbackasm1(SB)
+	MOVD $17, R12
+	B    callbackasm1(SB)
+	MOVD $18, R12
+	B    callbackasm1(SB)
+	MOVD $19, R12
+	B    callbackasm1(SB)
+	MOVD $20, R12
+	B    callbackasm1(SB)
+	MOVD $21, R12
+	B    callbackasm1(SB)
+	MOVD $22, R12
+	B    callbackasm1(SB)
+	MOVD $23, R12
+	B    callbackasm1(SB)
+	MOVD $24, R12
+	B    callbackasm1(SB)
+	MOVD $25, R12
+	B    callbackasm1(SB)
+	MOVD $26, R12
+	B    callbackasm1(SB)
+	MOVD $27, R12
+	B    callbackasm1(SB)
+	MOVD $28, R12
+	B    callbackasm1(SB)
+	MOVD $29, R12
+	B    callbackasm1(SB)
+	MOVD $30, R12
+	B    callbackasm1(SB)
+	MOVD $31, R12
+	B    callbackasm1(SB)
+	MOVD $32, R12
+	B    callbackasm1(SB)
+	MOVD $33, R12
+	B    callbackasm1(SB)
+	MOVD $34, R12
+	B    callbackasm1(SB)
+	MOVD $35, R12
+	B    callbackasm1(SB)
+	MOVD $36, R12
+	B    callbackasm1(SB)
+	MOVD $37, R12
+	B    callbackasm1(SB)
+	MOVD $38, R12
+	B    callbackasm1(SB)
+	MOVD $39, R12
+	B    callbackasm1(SB)
+	MOVD $40, R12
+	B    callbackasm1(SB)
+	MOVD $41, R12
+	B    callbackasm1(SB)
+	MOVD $42, R12
+	B    callbackasm1(SB)
+	MOVD $43, R12
+	B    callbackasm1(SB)
+	MOVD $44, R12
+	B    callbackasm1(SB)
+	MOVD $45, R12
+	B    callbackasm1(SB)
+	MOVD $46, R12
+	B    callbackasm1(SB)
+	MOVD $47, R12
+	B    callbackasm1(SB)
+	MOVD $48, R12
+	B    callbackasm1(SB)
+	MOVD $49, R12
+	B    callbackasm1(SB)
+	MOVD $50, R12
+	B    callbackasm1(SB)
+	MOVD $51, R12
+	B    callbackasm1(SB)
+	MOVD $52, R12
+	B    callbackasm1(SB)
+	MOVD $53, R12
+	B    callbackasm1(SB)
+	MOVD $54, R12
+	B    callbackasm1(SB)
+	MOVD $55, R12
+	B    callbackasm1(SB)
+	MOVD $56, R12
+	B    callbackasm1(SB)
+	MOVD $57, R12
+	B    callbackasm1(SB)
+	MOVD $58, R12
+	B    callbackasm1(SB)
+	MOVD $59, R12
+	B    callbackasm1(SB)
+	MOVD $60, R12
+	B    callbackasm1(SB)
+	MOVD $61, R12
+	B    callbackasm1(SB)
+	MOVD $62, R12
+	B    callbackasm1(SB)
+	MOVD $63, R12
+	B    callbackasm1(SB)
+	MOVD $64, R12
+	B    callbackasm1(SB)
+	MOVD $65, R12
+	B    callbackasm1(SB)
+	MOVD $66, R12
+	B    callbackasm1(SB)
+	MOVD $67, R12
+	B    callbackasm1(SB)
+	MOVD $68, R12
+	B    callbackasm1(SB)
+	MOVD $69, R12
+	B    callbackasm1(SB)
+	MOVD $70, R12
+	B    callbackasm1(SB)
+	MOVD $71, R12
+	B    callbackasm1(SB)
+	MOVD $72, R12
+	B    callbackasm1(SB)
+	MOVD $73, R12
+	B    callbackasm1(SB)
+	MOVD $74, R12
+	B    callbackasm1(SB)
+	MOVD $75, R12
+	B    callbackasm1(SB)
+	MOVD $76, R12
+	B    callbackasm1(SB)
+	MOVD $77, R12
+	B    callbackasm1(SB)
+	MOVD $78, R12
+	B    callbackasm1(SB)
+	MOVD $79, R12
+	B    callbackasm1(SB)
+	MOVD $80, R12
+	B    callbackasm1(SB)
+	MOVD $81, R12
+	B    callbackasm1(SB)
+	MOVD $82, R12
+	B    callbackasm1(SB)
+	MOVD $83, R12
+	B    callbackasm1(SB)
+	MOVD $84, R12
+	B    callbackasm1(SB)
+	MOVD $85, R12
+	B    callbackasm1(SB)
+	MOVD $86, R12
+	B    callbackasm1(SB)
+	MOVD $87, R12
+	B    callbackasm1(SB)
+	MOVD $88, R12
+	B    callbackasm1(SB)
+	MOVD $89, R12
+	B    callbackasm1(SB)
+	MOVD $90, R12
+	B    callbackasm1(SB)
+	MOVD $91, R12
+	B    callbackasm1(SB)
+	MOVD $92, R12
+	B    callbackasm1(SB)
+	MOVD $93, R12
+	B    callbackasm1(SB)
+	MOVD $94, R12
+	B    callbackasm1(SB)
+	MOVD $95, R12
+	B    callbackasm1(SB)
+	MOVD $96, R12
+	B    callbackasm1(SB)
+	MOVD $97, R12
+	B    callbackasm1(SB)
+	MOVD $98, R12
+	B    callbackasm1(SB)
+	MOVD $99, R12
+	B    callbackasm1(SB)
+	MOVD $100, R12
+	B    callbackasm1(SB)
+	MOVD $101, R12
+	B    callbackasm1(SB)
+	MOVD $102, R12
+	B    callbackasm1(SB)
+	MOVD $103, R12
+	B    callbackasm1(SB)
+	MOVD $104, R12
+	B    callbackasm1(SB)
+	MOVD $105, R12
+	B    callbackasm1(SB)
+	MOVD $106, R12
+	B    callbackasm1(SB)
+	MOVD $107, R12
+	B    callbackasm1(SB)
+	MOVD $108, R12
+	B    callbackasm1(SB)
+	MOVD $109, R12
+	B    callbackasm1(SB)
+	MOVD $110, R12
+	B    callbackasm1(SB)
+	MOVD $111, R12
+	B    callbackasm1(SB)
+	MOVD $112, R12
+	B    callbackasm1(SB)
+	MOVD $113, R12
+	B    callbackasm1(SB)
+	MOVD $114, R12
+	B    callbackasm1(SB)
+	MOVD $115, R12
+	B    callbackasm1(SB)
+	MOVD $116, R12
+	B    callbackasm1(SB)
+	MOVD $117, R12
+	B    callbackasm1(SB)
+	MOVD $118, R12
+	B    callbackasm1(SB)
+	MOVD $119, R12
+	B    callbackasm1(SB)
+	MOVD $120, R12
+	B    callbackasm1(SB)
+	MOVD $121, R12
+	B    callbackasm1(SB)
+	MOVD $122, R12
+	B    callbackasm1(SB)
+	MOVD $123, R12
+	B    callbackasm1(SB)
+	MOVD $124, R12
+	B    callbackasm1(SB)
+	MOVD $125, R12
+	B    callbackasm1(SB)
+	MOVD $126, R12
+	B    callbackasm1(SB)
+	MOVD $127, R12
+	B    callbackasm1(SB)
+	MOVD $128, R12
+	B    callbackasm1(SB)
+	MOVD $129, R12
+	B    callbackasm1(SB)
+	MOVD $130, R12
+	B    callbackasm1(SB)
+	MOVD $131, R12
+	B    callbackasm1(SB)
+	MOVD $132, R12
+	B    callbackasm1(SB)
+	MOVD $133, R12
+	B    callbackasm1(SB)
+	MOVD $134, R12
+	B    callbackasm1(SB)
+	MOVD $135, R12
+	B    callbackasm1(SB)
+	MOVD $136, R12
+	B    callbackasm1(SB)
+	MOVD $137, R12
+	B    callbackasm1(SB)
+	MOVD $138, R12
+	B    callbackasm1(SB)
+	MOVD $139, R12
+	B    callbackasm1(SB)
+	MOVD $140, R12
+	B    callbackasm1(SB)
+	MOVD $141, R12
+	B    callbackasm1(SB)
+	MOVD $142, R12
+	B    callbackasm1(SB)
+	MOVD $143, R12
+	B    callbackasm1(SB)
+	MOVD $144, R12
+	B    callbackasm1(SB)
+	MOVD $145, R12
+	B    callbackasm1(SB)
+	MOVD $146, R12
+	B    callbackasm1(SB)
+	MOVD $147, R12
+	B    callbackasm1(SB)
+	MOVD $148, R12
+	B    callbackasm1(SB)
+	MOVD $149, R12
+	B    callbackasm1(SB)
+	MOVD $150, R12
+	B    callbackasm1(SB)
+	MOVD $151, R12
+	B    callbackasm1(SB)
+	MOVD $152, R12
+	B    callbackasm1(SB)
+	MOVD $153, R12
+	B    callbackasm1(SB)
+	MOVD $154, R12
+	B    callbackasm1(SB)
+	MOVD $155, R12
+	B    callbackasm1(SB)
+	MOVD $156, R12
+	B    callbackasm1(SB)
+	MOVD $157, R12
+	B    callbackasm1(SB)
+	MOVD $158, R12
+	B    callbackasm1(SB)
+	MOVD $159, R12
+	B    callbackasm1(SB)
+	MOVD $160, R12
+	B    callbackasm1(SB)
+	MOVD $161, R12
+	B    callbackasm1(SB)
+	MOVD $162, R12
+	B    callbackasm1(SB)
+	MOVD $163, R12
+	B    callbackasm1(SB)
+	MOVD $164, R12
+	B    callbackasm1(SB)
+	MOVD $165, R12
+	B    callbackasm1(SB)
+	MOVD $166, R12
+	B    callbackasm1(SB)
+	MOVD $167, R12
+	B    callbackasm1(SB)
+	MOVD $168, R12
+	B    callbackasm1(SB)
+	MOVD $169, R12
+	B    callbackasm1(SB)
+	MOVD $170, R12
+	B    callbackasm1(SB)
+	MOVD $171, R12
+	B    callbackasm1(SB)
+	MOVD $172, R12
+	B    callbackasm1(SB)
+	MOVD $173, R12
+	B    callbackasm1(SB)
+	MOVD $174, R12
+	B    callbackasm1(SB)
+	MOVD $175, R12
+	B    callbackasm1(SB)
+	MOVD $176, R12
+	B    callbackasm1(SB)
+	MOVD $177, R12
+	B    callbackasm1(SB)
+	MOVD $178, R12
+	B    callbackasm1(SB)
+	MOVD $179, R12
+	B    callbackasm1(SB)
+	MOVD $180, R12
+	B    callbackasm1(SB)
+	MOVD $181, R12
+	B    callbackasm1(SB)
+	MOVD $182, R12
+	B    callbackasm1(SB)
+	MOVD $183, R12
+	B    callbackasm1(SB)
+	MOVD $184, R12
+	B    callbackasm1(SB)
+	MOVD $185, R12
+	B    callbackasm1(SB)
+	MOVD $186, R12
+	B    callbackasm1(SB)
+	MOVD $187, R12
+	B    callbackasm1(SB)
+	MOVD $188, R12
+	B    callbackasm1(SB)
+	MOVD $189, R12
+	B    callbackasm1(SB)
+	MOVD $190, R12
+	B    callbackasm1(SB)
+	MOVD $191, R12
+	B    callbackasm1(SB)
+	MOVD $192, R12
+	B    callbackasm1(SB)
+	MOVD $193, R12
+	B    callbackasm1(SB)
+	MOVD $194, R12
+	B    callbackasm1(SB)
+	MOVD $195, R12
+	B    callbackasm1(SB)
+	MOVD $196, R12
+	B    callbackasm1(SB)
+	MOVD $197, R12
+	B    callbackasm1(SB)
+	MOVD $198, R12
+	B    callbackasm1(SB)
+	MOVD $199, R12
+	B    callbackasm1(SB)
+	MOVD $200, R12
+	B    callbackasm1(SB)
+	MOVD $201, R12
+	B    callbackasm1(SB)
+	MOVD $202, R12
+	B    callbackasm1(SB)
+	MOVD $203, R12
+	B    callbackasm1(SB)
+	MOVD $204, R12
+	B    callbackasm1(SB)
+	MOVD $205, R12
+	B    callbackasm1(SB)
+	MOVD $206, R12
+	B    callbackasm1(SB)
+	MOVD $207, R12
+	B    callbackasm1(SB)
+	MOVD $208, R12
+	B    callbackasm1(SB)
+	MOVD $209, R12
+	B    callbackasm1(SB)
+	MOVD $210, R12
+	B    callbackasm1(SB)
+	MOVD $211, R12
+	B    callbackasm1(SB)
+	MOVD $212, R12
+	B    callbackasm1(SB)
+	MOVD $213, R12
+	B    callbackasm1(SB)
+	MOVD $214, R12
+	B    callbackasm1(SB)
+	MOVD $215, R12
+	B    callbackasm1(SB)
+	MOVD $216, R12
+	B    callbackasm1(SB)
+	MOVD $217, R12
+	B    callbackasm1(SB)
+	MOVD $218, R12
+	B    callbackasm1(SB)
+	MOVD $219, R12
+	B    callbackasm1(SB)
+	MOVD $220, R12
+	B    callbackasm1(SB)
+	MOVD $221, R12
+	B    callbackasm1(SB)
+	MOVD $222, R12
+	B    callbackasm1(SB)
+	MOVD $223, R12
+	B    callbackasm1(SB)
+	MOVD $224, R12
+	B    callbackasm1(SB)
+	MOVD $225, R12
+	B    callbackasm1(SB)
+	MOVD $226, R12
+	B    callbackasm1(SB)
+	MOVD $227, R12
+	B    callbackasm1(SB)
+	MOVD $228, R12
+	B    callbackasm1(SB)
+	MOVD $229, R12
+	B    callbackasm1(SB)
+	MOVD $230, R12
+	B    callbackasm1(SB)
+	MOVD $231, R12
+	B    callbackasm1(SB)
+	MOVD $232, R12
+	B    callbackasm1(SB)
+	MOVD $233, R12
+	B    callbackasm1(SB)
+	MOVD $234, R12
+	B    callbackasm1(SB)
+	MOVD $235, R12
+	B    callbackasm1(SB)
+	MOVD $236, R12
+	B    callbackasm1(SB)
+	MOVD $237, R12
+	B    callbackasm1(SB)
+	MOVD $238, R12
+	B    callbackasm1(SB)
+	MOVD $239, R12
+	B    callbackasm1(SB)
+	MOVD $240, R12
+	B    callbackasm1(SB)
+	MOVD $241, R12
+	B    callbackasm1(SB)
+	MOVD $242, R12
+	B    callbackasm1(SB)
+	MOVD $243, R12
+	B    callbackasm1(SB)
+	MOVD $244, R12
+	B    callbackasm1(SB)
+	MOVD $245, R12
+	B    callbackasm1(SB)
+	MOVD $246, R12
+	B    callbackasm1(SB)
+	MOVD $247, R12
+	B    callbackasm1(SB)
+	MOVD $248, R12
+	B    callbackasm1(SB)
+	MOVD $249, R12
+	B    callbackasm1(SB)
+	MOVD $250, R12
+	B    callbackasm1(SB)
+	MOVD $251, R12
+	B    callbackasm1(SB)
+	MOVD $252, R12
+	B    callbackasm1(SB)
+	MOVD $253, R12
+	B    callbackasm1(SB)
+	MOVD $254, R12
+	B    callbackasm1(SB)
+	MOVD $255, R12
+	B    callbackasm1(SB)
+	MOVD $256, R12
+	B    callbackasm1(SB)
+	MOVD $257, R12
+	B    callbackasm1(SB)
+	MOVD $258, R12
+	B    callbackasm1(SB)
+	MOVD $259, R12
+	B    callbackasm1(SB)
+	MOVD $260, R12
+	B    callbackasm1(SB)
+	MOVD $261, R12
+	B    callbackasm1(SB)
+	MOVD $262, R12
+	B    callbackasm1(SB)
+	MOVD $263, R12
+	B    callbackasm1(SB)
+	MOVD $264, R12
+	B    callbackasm1(SB)
+	MOVD $265, R12
+	B    callbackasm1(SB)
+	MOVD $266, R12
+	B    callbackasm1(SB)
+	MOVD $267, R12
+	B    callbackasm1(SB)
+	MOVD $268, R12
+	B    callbackasm1(SB)
+	MOVD $269, R12
+	B    callbackasm1(SB)
+	MOVD $270, R12
+	B    callbackasm1(SB)
+	MOVD $271, R12
+	B    callbackasm1(SB)
+	MOVD $272, R12
+	B    callbackasm1(SB)
+	MOVD $273, R12
+	B    callbackasm1(SB)
+	MOVD $274, R12
+	B    callbackasm1(SB)
+	MOVD $275, R12
+	B    callbackasm1(SB)
+	MOVD $276, R12
+	B    callbackasm1(SB)
+	MOVD $277, R12
+	B    callbackasm1(SB)
+	MOVD $278, R12
+	B    callbackasm1(SB)
+	MOVD $279, R12
+	B    callbackasm1(SB)
+	MOVD $280, R12
+	B    callbackasm1(SB)
+	MOVD $281, R12
+	B    callbackasm1(SB)
+	MOVD $282, R12
+	B    callbackasm1(SB)
+	MOVD $283, R12
+	B    callbackasm1(SB)
+	MOVD $284, R12
+	B    callbackasm1(SB)
+	MOVD $285, R12
+	B    callbackasm1(SB)
+	MOVD $286, R12
+	B    callbackasm1(SB)
+	MOVD $287, R12
+	B    callbackasm1(SB)
+	MOVD $288, R12
+	B    callbackasm1(SB)
+	MOVD $289, R12
+	B    callbackasm1(SB)
+	MOVD $290, R12
+	B    callbackasm1(SB)
+	MOVD $291, R12
+	B    callbackasm1(SB)
+	MOVD $292, R12
+	B    callbackasm1(SB)
+	MOVD $293, R12
+	B    callbackasm1(SB)
+	MOVD $294, R12
+	B    callbackasm1(SB)
+	MOVD $295, R12
+	B    callbackasm1(SB)
+	MOVD $296, R12
+	B    callbackasm1(SB)
+	MOVD $297, R12
+	B    callbackasm1(SB)
+	MOVD $298, R12
+	B    callbackasm1(SB)
+	MOVD $299, R12
+	B    callbackasm1(SB)
+	MOVD $300, R12
+	B    callbackasm1(SB)
+	MOVD $301, R12
+	B    callbackasm1(SB)
+	MOVD $302, R12
+	B    callbackasm1(SB)
+	MOVD $303, R12
+	B    callbackasm1(SB)
+	MOVD $304, R12
+	B    callbackasm1(SB)
+	MOVD $305, R12
+	B    callbackasm1(SB)
+	MOVD $306, R12
+	B    callbackasm1(SB)
+	MOVD $307, R12
+	B    callbackasm1(SB)
+	MOVD $308, R12
+	B    callbackasm1(SB)
+	MOVD $309, R12
+	B    callbackasm1(SB)
+	MOVD $310, R12
+	B    callbackasm1(SB)
+	MOVD $311, R12
+	B    callbackasm1(SB)
+	MOVD $312, R12
+	B    callbackasm1(SB)
+	MOVD $313, R12
+	B    callbackasm1(SB)
+	MOVD $314, R12
+	B    callbackasm1(SB)
+	MOVD $315, R12
+	B    callbackasm1(SB)
+	MOVD $316, R12
+	B    callbackasm1(SB)
+	MOVD $317, R12
+	B    callbackasm1(SB)
+	MOVD $318, R12
+	B    callbackasm1(SB)
+	MOVD $319, R12
+	B    callbackasm1(SB)
+	MOVD $320, R12
+	B    callbackasm1(SB)
+	MOVD $321, R12
+	B    callbackasm1(SB)
+	MOVD $322, R12
+	B    callbackasm1(SB)
+	MOVD $323, R12
+	B    callbackasm1(SB)
+	MOVD $324, R12
+	B    callbackasm1(SB)
+	MOVD $325, R12
+	B    callbackasm1(SB)
+	MOVD $326, R12
+	B    callbackasm1(SB)
+	MOVD $327, R12
+	B    callbackasm1(SB)
+	MOVD $328, R12
+	B    callbackasm1(SB)
+	MOVD $329, R12
+	B    callbackasm1(SB)
+	MOVD $330, R12
+	B    callbackasm1(SB)
+	MOVD $331, R12
+	B    callbackasm1(SB)
+	MOVD $332, R12
+	B    callbackasm1(SB)
+	MOVD $333, R12
+	B    callbackasm1(SB)
+	MOVD $334, R12
+	B    callbackasm1(SB)
+	MOVD $335, R12
+	B    callbackasm1(SB)
+	MOVD $336, R12
+	B    callbackasm1(SB)
+	MOVD $337, R12
+	B    callbackasm1(SB)
+	MOVD $338, R12
+	B    callbackasm1(SB)
+	MOVD $339, R12
+	B    callbackasm1(SB)
+	MOVD $340, R12
+	B    callbackasm1(SB)
+	MOVD $341, R12
+	B    callbackasm1(SB)
+	MOVD $342, R12
+	B    callbackasm1(SB)
+	MOVD $343, R12
+	B    callbackasm1(SB)
+	MOVD $344, R12
+	B    callbackasm1(SB)
+	MOVD $345, R12
+	B    callbackasm1(SB)
+	MOVD $346, R12
+	B    callbackasm1(SB)
+	MOVD $347, R12
+	B    callbackasm1(SB)
+	MOVD $348, R12
+	B    callbackasm1(SB)
+	MOVD $349, R12
+	B    callbackasm1(SB)
+	MOVD $350, R12
+	B    callbackasm1(SB)
+	MOVD $351, R12
+	B    callbackasm1(SB)
+	MOVD $352, R12
+	B    callbackasm1(SB)
+	MOVD $353, R12
+	B    callbackasm1(SB)
+	MOVD $354, R12
+	B    callbackasm1(SB)
+	MOVD $355, R12
+	B    callbackasm1(SB)
+	MOVD $356, R12
+	B    callbackasm1(SB)
+	MOVD $357, R12
+	B    callbackasm1(SB)
+	MOVD $358, R12
+	B    callbackasm1(SB)
+	MOVD $359, R12
+	B    callbackasm1(SB)
+	MOVD $360, R12
+	B    callbackasm1(SB)
+	MOVD $361, R12
+	B    callbackasm1(SB)
+	MOVD $362, R12
+	B    callbackasm1(SB)
+	MOVD $363, R12
+	B    callbackasm1(SB)
+	MOVD $364, R12
+	B    callbackasm1(SB)
+	MOVD $365, R12
+	B    callbackasm1(SB)
+	MOVD $366, R12
+	B    callbackasm1(SB)
+	MOVD $367, R12
+	B    callbackasm1(SB)
+	MOVD $368, R12
+	B    callbackasm1(SB)
+	MOVD $369, R12
+	B    callbackasm1(SB)
+	MOVD $370, R12
+	B    callbackasm1(SB)
+	MOVD $371, R12
+	B    callbackasm1(SB)
+	MOVD $372, R12
+	B    callbackasm1(SB)
+	MOVD $373, R12
+	B    callbackasm1(SB)
+	MOVD $374, R12
+	B    callbackasm1(SB)
+	MOVD $375, R12
+	B    callbackasm1(SB)
+	MOVD $376, R12
+	B    callbackasm1(SB)
+	MOVD $377, R12
+	B    callbackasm1(SB)
+	MOVD $378, R12
+	B    callbackasm1(SB)
+	MOVD $379, R12
+	B    callbackasm1(SB)
+	MOVD $380, R12
+	B    callbackasm1(SB)
+	MOVD $381, R12
+	B    callbackasm1(SB)
+	MOVD $382, R12
+	B    callbackasm1(SB)
+	MOVD $383, R12
+	B    callbackasm1(SB)
+	MOVD $384, R12
+	B    callbackasm1(SB)
+	MOVD $385, R12
+	B    callbackasm1(SB)
+	MOVD $386, R12
+	B    callbackasm1(SB)
+	MOVD $387, R12
+	B    callbackasm1(SB)
+	MOVD $388, R12
+	B    callbackasm1(SB)
+	MOVD $389, R12
+	B    callbackasm1(SB)
+	MOVD $390, R12
+	B    callbackasm1(SB)
+	MOVD $391, R12
+	B    callbackasm1(SB)
+	MOVD $392, R12
+	B    callbackasm1(SB)
+	MOVD $393, R12
+	B    callbackasm1(SB)
+	MOVD $394, R12
+	B    callbackasm1(SB)
+	MOVD $395, R12
+	B    callbackasm1(SB)
+	MOVD $396, R12
+	B    callbackasm1(SB)
+	MOVD $397, R12
+	B    callbackasm1(SB)
+	MOVD $398, R12
+	B    callbackasm1(SB)
+	MOVD $399, R12
+	B    callbackasm1(SB)
+	MOVD $400, R12
+	B    callbackasm1(SB)
+	MOVD $401, R12
+	B    callbackasm1(SB)
+	MOVD $402, R12
+	B    callbackasm1(SB)
+	MOVD $403, R12
+	B    callbackasm1(SB)
+	MOVD $404, R12
+	B    callbackasm1(SB)
+	MOVD $405, R12
+	B    callbackasm1(SB)
+	MOVD $406, R12
+	B    callbackasm1(SB)
+	MOVD $407, R12
+	B    callbackasm1(SB)
+	MOVD $408, R12
+	B    callbackasm1(SB)
+	MOVD $409, R12
+	B    callbackasm1(SB)
+	MOVD $410, R12
+	B    callbackasm1(SB)
+	MOVD $411, R12
+	B    callbackasm1(SB)
+	MOVD $412, R12
+	B    callbackasm1(SB)
+	MOVD $413, R12
+	B    callbackasm1(SB)
+	MOVD $414, R12
+	B    callbackasm1(SB)
+	MOVD $415, R12
+	B    callbackasm1(SB)
+	MOVD $416, R12
+	B    callbackasm1(SB)
+	MOVD $417, R12
+	B    callbackasm1(SB)
+	MOVD $418, R12
+	B    callbackasm1(SB)
+	MOVD $419, R12
+	B    callbackasm1(SB)
+	MOVD $420, R12
+	B    callbackasm1(SB)
+	MOVD $421, R12
+	B    callbackasm1(SB)
+	MOVD $422, R12
+	B    callbackasm1(SB)
+	MOVD $423, R12
+	B    callbackasm1(SB)
+	MOVD $424, R12
+	B    callbackasm1(SB)
+	MOVD $425, R12
+	B    callbackasm1(SB)
+	MOVD $426, R12
+	B    callbackasm1(SB)
+	MOVD $427, R12
+	B    callbackasm1(SB)
+	MOVD $428, R12
+	B    callbackasm1(SB)
+	MOVD $429, R12
+	B    callbackasm1(SB)
+	MOVD $430, R12
+	B    callbackasm1(SB)
+	MOVD $431, R12
+	B    callbackasm1(SB)
+	MOVD $432, R12
+	B    callbackasm1(SB)
+	MOVD $433, R12
+	B    callbackasm1(SB)
+	MOVD $434, R12
+	B    callbackasm1(SB)
+	MOVD $435, R12
+	B    callbackasm1(SB)
+	MOVD $436, R12
+	B    callbackasm1(SB)
+	MOVD $437, R12
+	B    callbackasm1(SB)
+	MOVD $438, R12
+	B    callbackasm1(SB)
+	MOVD $439, R12
+	B    callbackasm1(SB)
+	MOVD $440, R12
+	B    callbackasm1(SB)
+	MOVD $441, R12
+	B    callbackasm1(SB)
+	MOVD $442, R12
+	B    callbackasm1(SB)
+	MOVD $443, R12
+	B    callbackasm1(SB)
+	MOVD $444, R12
+	B    callbackasm1(SB)
+	MOVD $445, R12
+	B    callbackasm1(SB)
+	MOVD $446, R12
+	B    callbackasm1(SB)
+	MOVD $447, R12
+	B    callbackasm1(SB)
+	MOVD $448, R12
+	B    callbackasm1(SB)
+	MOVD $449, R12
+	B    callbackasm1(SB)
+	MOVD $450, R12
+	B    callbackasm1(SB)
+	MOVD $451, R12
+	B    callbackasm1(SB)
+	MOVD $452, R12
+	B    callbackasm1(SB)
+	MOVD $453, R12
+	B    callbackasm1(SB)
+	MOVD $454, R12
+	B    callbackasm1(SB)
+	MOVD $455, R12
+	B    callbackasm1(SB)
+	MOVD $456, R12
+	B    callbackasm1(SB)
+	MOVD $457, R12
+	B    callbackasm1(SB)
+	MOVD $458, R12
+	B    callbackasm1(SB)
+	MOVD $459, R12
+	B    callbackasm1(SB)
+	MOVD $460, R12
+	B    callbackasm1(SB)
+	MOVD $461, R12
+	B    callbackasm1(SB)
+	MOVD $462, R12
+	B    callbackasm1(SB)
+	MOVD $463, R12
+	B    callbackasm1(SB)
+	MOVD $464, R12
+	B    callbackasm1(SB)
+	MOVD $465, R12
+	B    callbackasm1(SB)
+	MOVD $466, R12
+	B    callbackasm1(SB)
+	MOVD $467, R12
+	B    callbackasm1(SB)
+	MOVD $468, R12
+	B    callbackasm1(SB)
+	MOVD $469, R12
+	B    callbackasm1(SB)
+	MOVD $470, R12
+	B    callbackasm1(SB)
+	MOVD $471, R12
+	B    callbackasm1(SB)
+	MOVD $472, R12
+	B    callbackasm1(SB)
+	MOVD $473, R12
+	B    callbackasm1(SB)
+	MOVD $474, R12
+	B    callbackasm1(SB)
+	MOVD $475, R12
+	B    callbackasm1(SB)
+	MOVD $476, R12
+	B    callbackasm1(SB)
+	MOVD $477, R12
+	B    callbackasm1(SB)
+	MOVD $478, R12
+	B    callbackasm1(SB)
+	MOVD $479, R12
+	B    callbackasm1(SB)
+	MOVD $480, R12
+	B    callbackasm1(SB)
+	MOVD $481, R12
+	B    callbackasm1(SB)
+	MOVD $482, R12
+	B    callbackasm1(SB)
+	MOVD $483, R12
+	B    callbackasm1(SB)
+	MOVD $484, R12
+	B    callbackasm1(SB)
+	MOVD $485, R12
+	B    callbackasm1(SB)
+	MOVD $486, R12
+	B    callbackasm1(SB)
+	MOVD $487, R12
+	B    callbackasm1(SB)
+	MOVD $488, R12
+	B    callbackasm1(SB)
+	MOVD $489, R12
+	B    callbackasm1(SB)
+	MOVD $490, R12
+	B    callbackasm1(SB)
+	MOVD $491, R12
+	B    callbackasm1(SB)
+	MOVD $492, R12
+	B    callbackasm1(SB)
+	MOVD $493, R12
+	B    callbackasm1(SB)
+	MOVD $494, R12
+	B    callbackasm1(SB)
+	MOVD $495, R12
+	B    callbackasm1(SB)
+	MOVD $496, R12
+	B    callbackasm1(SB)
+	MOVD $497, R12
+	B    callbackasm1(SB)
+	MOVD $498, R12
+	B    callbackasm1(SB)
+	MOVD $499, R12
+	B    callbackasm1(SB)
+	MOVD $500, R12
+	B    callbackasm1(SB)
+	MOVD $501, R12
+	B    callbackasm1(SB)
+	MOVD $502, R12
+	B    callbackasm1(SB)
+	MOVD $503, R12
+	B    callbackasm1(SB)
+	MOVD $504, R12
+	B    callbackasm1(SB)
+	MOVD $505, R12
+	B    callbackasm1(SB)
+	MOVD $506, R12
+	B    callbackasm1(SB)
+	MOVD $507, R12
+	B    callbackasm1(SB)
+	MOVD $508, R12
+	B    callbackasm1(SB)
+	MOVD $509, R12
+	B    callbackasm1(SB)
+	MOVD $510, R12
+	B    callbackasm1(SB)
+	MOVD $511, R12
+	B    callbackasm1(SB)
+	MOVD $512, R12
+	B    callbackasm1(SB)
+	MOVD $513, R12
+	B    callbackasm1(SB)
+	MOVD $514, R12
+	B    callbackasm1(SB)
+	MOVD $515, R12
+	B    callbackasm1(SB)
+	MOVD $516, R12
+	B    callbackasm1(SB)
+	MOVD $517, R12
+	B    callbackasm1(SB)
+	MOVD $518, R12
+	B    callbackasm1(SB)
+	MOVD $519, R12
+	B    callbackasm1(SB)
+	MOVD $520, R12
+	B    callbackasm1(SB)
+	MOVD $521, R12
+	B    callbackasm1(SB)
+	MOVD $522, R12
+	B    callbackasm1(SB)
+	MOVD $523, R12
+	B    callbackasm1(SB)
+	MOVD $524, R12
+	B    callbackasm1(SB)
+	MOVD $525, R12
+	B    callbackasm1(SB)
+	MOVD $526, R12
+	B    callbackasm1(SB)
+	MOVD $527, R12
+	B    callbackasm1(SB)
+	MOVD $528, R12
+	B    callbackasm1(SB)
+	MOVD $529, R12
+	B    callbackasm1(SB)
+	MOVD $530, R12
+	B    callbackasm1(SB)
+	MOVD $531, R12
+	B    callbackasm1(SB)
+	MOVD $532, R12
+	B    callbackasm1(SB)
+	MOVD $533, R12
+	B    callbackasm1(SB)
+	MOVD $534, R12
+	B    callbackasm1(SB)
+	MOVD $535, R12
+	B    callbackasm1(SB)
+	MOVD $536, R12
+	B    callbackasm1(SB)
+	MOVD $537, R12
+	B    callbackasm1(SB)
+	MOVD $538, R12
+	B    callbackasm1(SB)
+	MOVD $539, R12
+	B    callbackasm1(SB)
+	MOVD $540, R12
+	B    callbackasm1(SB)
+	MOVD $541, R12
+	B    callbackasm1(SB)
+	MOVD $542, R12
+	B    callbackasm1(SB)
+	MOVD $543, R12
+	B    callbackasm1(SB)
+	MOVD $544, R12
+	B    callbackasm1(SB)
+	MOVD $545, R12
+	B    callbackasm1(SB)
+	MOVD $546, R12
+	B    callbackasm1(SB)
+	MOVD $547, R12
+	B    callbackasm1(SB)
+	MOVD $548, R12
+	B    callbackasm1(SB)
+	MOVD $549, R12
+	B    callbackasm1(SB)
+	MOVD $550, R12
+	B    callbackasm1(SB)
+	MOVD $551, R12
+	B    callbackasm1(SB)
+	MOVD $552, R12
+	B    callbackasm1(SB)
+	MOVD $553, R12
+	B    callbackasm1(SB)
+	MOVD $554, R12
+	B    callbackasm1(SB)
+	MOVD $555, R12
+	B    callbackasm1(SB)
+	MOVD $556, R12
+	B    callbackasm1(SB)
+	MOVD $557, R12
+	B    callbackasm1(SB)
+	MOVD $558, R12
+	B    callbackasm1(SB)
+	MOVD $559, R12
+	B    callbackasm1(SB)
+	MOVD $560, R12
+	B    callbackasm1(SB)
+	MOVD $561, R12
+	B    callbackasm1(SB)
+	MOVD $562, R12
+	B    callbackasm1(SB)
+	MOVD $563, R12
+	B    callbackasm1(SB)
+	MOVD $564, R12
+	B    callbackasm1(SB)
+	MOVD $565, R12
+	B    callbackasm1(SB)
+	MOVD $566, R12
+	B    callbackasm1(SB)
+	MOVD $567, R12
+	B    callbackasm1(SB)
+	MOVD $568, R12
+	B    callbackasm1(SB)
+	MOVD $569, R12
+	B    callbackasm1(SB)
+	MOVD $570, R12
+	B    callbackasm1(SB)
+	MOVD $571, R12
+	B    callbackasm1(SB)
+	MOVD $572, R12
+	B    callbackasm1(SB)
+	MOVD $573, R12
+	B    callbackasm1(SB)
+	MOVD $574, R12
+	B    callbackasm1(SB)
+	MOVD $575, R12
+	B    callbackasm1(SB)
+	MOVD $576, R12
+	B    callbackasm1(SB)
+	MOVD $577, R12
+	B    callbackasm1(SB)
+	MOVD $578, R12
+	B    callbackasm1(SB)
+	MOVD $579, R12
+	B    callbackasm1(SB)
+	MOVD $580, R12
+	B    callbackasm1(SB)
+	MOVD $581, R12
+	B    callbackasm1(SB)
+	MOVD $582, R12
+	B    callbackasm1(SB)
+	MOVD $583, R12
+	B    callbackasm1(SB)
+	MOVD $584, R12
+	B    callbackasm1(SB)
+	MOVD $585, R12
+	B    callbackasm1(SB)
+	MOVD $586, R12
+	B    callbackasm1(SB)
+	MOVD $587, R12
+	B    callbackasm1(SB)
+	MOVD $588, R12
+	B    callbackasm1(SB)
+	MOVD $589, R12
+	B    callbackasm1(SB)
+	MOVD $590, R12
+	B    callbackasm1(SB)
+	MOVD $591, R12
+	B    callbackasm1(SB)
+	MOVD $592, R12
+	B    callbackasm1(SB)
+	MOVD $593, R12
+	B    callbackasm1(SB)
+	MOVD $594, R12
+	B    callbackasm1(SB)
+	MOVD $595, R12
+	B    callbackasm1(SB)
+	MOVD $596, R12
+	B    callbackasm1(SB)
+	MOVD $597, R12
+	B    callbackasm1(SB)
+	MOVD $598, R12
+	B    callbackasm1(SB)
+	MOVD $599, R12
+	B    callbackasm1(SB)
+	MOVD $600, R12
+	B    callbackasm1(SB)
+	MOVD $601, R12
+	B    callbackasm1(SB)
+	MOVD $602, R12
+	B    callbackasm1(SB)
+	MOVD $603, R12
+	B    callbackasm1(SB)
+	MOVD $604, R12
+	B    callbackasm1(SB)
+	MOVD $605, R12
+	B    callbackasm1(SB)
+	MOVD $606, R12
+	B    callbackasm1(SB)
+	MOVD $607, R12
+	B    callbackasm1(SB)
+	MOVD $608, R12
+	B    callbackasm1(SB)
+	MOVD $609, R12
+	B    callbackasm1(SB)
+	MOVD $610, R12
+	B    callbackasm1(SB)
+	MOVD $611, R12
+	B    callbackasm1(SB)
+	MOVD $612, R12
+	B    callbackasm1(SB)
+	MOVD $613, R12
+	B    callbackasm1(SB)
+	MOVD $614, R12
+	B    callbackasm1(SB)
+	MOVD $615, R12
+	B    callbackasm1(SB)
+	MOVD $616, R12
+	B    callbackasm1(SB)
+	MOVD $617, R12
+	B    callbackasm1(SB)
+	MOVD $618, R12
+	B    callbackasm1(SB)
+	MOVD $619, R12
+	B    callbackasm1(SB)
+	MOVD $620, R12
+	B    callbackasm1(SB)
+	MOVD $621, R12
+	B    callbackasm1(SB)
+	MOVD $622, R12
+	B    callbackasm1(SB)
+	MOVD $623, R12
+	B    callbackasm1(SB)
+	MOVD $624, R12
+	B    callbackasm1(SB)
+	MOVD $625, R12
+	B    callbackasm1(SB)
+	MOVD $626, R12
+	B    callbackasm1(SB)
+	MOVD $627, R12
+	B    callbackasm1(SB)
+	MOVD $628, R12
+	B    callbackasm1(SB)
+	MOVD $629, R12
+	B    callbackasm1(SB)
+	MOVD $630, R12
+	B    callbackasm1(SB)
+	MOVD $631, R12
+	B    callbackasm1(SB)
+	MOVD $632, R12
+	B    callbackasm1(SB)
+	MOVD $633, R12
+	B    callbackasm1(SB)
+	MOVD $634, R12
+	B    callbackasm1(SB)
+	MOVD $635, R12
+	B    callbackasm1(SB)
+	MOVD $636, R12
+	B    callbackasm1(SB)
+	MOVD $637, R12
+	B    callbackasm1(SB)
+	MOVD $638, R12
+	B    callbackasm1(SB)
+	MOVD $639, R12
+	B    callbackasm1(SB)
+	MOVD $640, R12
+	B    callbackasm1(SB)
+	MOVD $641, R12
+	B    callbackasm1(SB)
+	MOVD $642, R12
+	B    callbackasm1(SB)
+	MOVD $643, R12
+	B    callbackasm1(SB)
+	MOVD $644, R12
+	B    callbackasm1(SB)
+	MOVD $645, R12
+	B    callbackasm1(SB)
+	MOVD $646, R12
+	B    callbackasm1(SB)
+	MOVD $647, R12
+	B    callbackasm1(SB)
+	MOVD $648, R12
+	B    callbackasm1(SB)
+	MOVD $649, R12
+	B    callbackasm1(SB)
+	MOVD $650, R12
+	B    callbackasm1(SB)
+	MOVD $651, R12
+	B    callbackasm1(SB)
+	MOVD $652, R12
+	B    callbackasm1(SB)
+	MOVD $653, R12
+	B    callbackasm1(SB)
+	MOVD $654, R12
+	B    callbackasm1(SB)
+	MOVD $655, R12
+	B    callbackasm1(SB)
+	MOVD $656, R12
+	B    callbackasm1(SB)
+	MOVD $657, R12
+	B    callbackasm1(SB)
+	MOVD $658, R12
+	B    callbackasm1(SB)
+	MOVD $659, R12
+	B    callbackasm1(SB)
+	MOVD $660, R12
+	B    callbackasm1(SB)
+	MOVD $661, R12
+	B    callbackasm1(SB)
+	MOVD $662, R12
+	B    callbackasm1(SB)
+	MOVD $663, R12
+	B    callbackasm1(SB)
+	MOVD $664, R12
+	B    callbackasm1(SB)
+	MOVD $665, R12
+	B    callbackasm1(SB)
+	MOVD $666, R12
+	B    callbackasm1(SB)
+	MOVD $667, R12
+	B    callbackasm1(SB)
+	MOVD $668, R12
+	B    callbackasm1(SB)
+	MOVD $669, R12
+	B    callbackasm1(SB)
+	MOVD $670, R12
+	B    callbackasm1(SB)
+	MOVD $671, R12
+	B    callbackasm1(SB)
+	MOVD $672, R12
+	B    callbackasm1(SB)
+	MOVD $673, R12
+	B    callbackasm1(SB)
+	MOVD $674, R12
+	B    callbackasm1(SB)
+	MOVD $675, R12
+	B    callbackasm1(SB)
+	MOVD $676, R12
+	B    callbackasm1(SB)
+	MOVD $677, R12
+	B    callbackasm1(SB)
+	MOVD $678, R12
+	B    callbackasm1(SB)
+	MOVD $679, R12
+	B    callbackasm1(SB)
+	MOVD $680, R12
+	B    callbackasm1(SB)
+	MOVD $681, R12
+	B    callbackasm1(SB)
+	MOVD $682, R12
+	B    callbackasm1(SB)
+	MOVD $683, R12
+	B    callbackasm1(SB)
+	MOVD $684, R12
+	B    callbackasm1(SB)
+	MOVD $685, R12
+	B    callbackasm1(SB)
+	MOVD $686, R12
+	B    callbackasm1(SB)
+	MOVD $687, R12
+	B    callbackasm1(SB)
+	MOVD $688, R12
+	B    callbackasm1(SB)
+	MOVD $689, R12
+	B    callbackasm1(SB)
+	MOVD $690, R12
+	B    callbackasm1(SB)
+	MOVD $691, R12
+	B    callbackasm1(SB)
+	MOVD $692, R12
+	B    callbackasm1(SB)
+	MOVD $693, R12
+	B    callbackasm1(SB)
+	MOVD $694, R12
+	B    callbackasm1(SB)
+	MOVD $695, R12
+	B    callbackasm1(SB)
+	MOVD $696, R12
+	B    callbackasm1(SB)
+	MOVD $697, R12
+	B    callbackasm1(SB)
+	MOVD $698, R12
+	B    callbackasm1(SB)
+	MOVD $699, R12
+	B    callbackasm1(SB)
+	MOVD $700, R12
+	B    callbackasm1(SB)
+	MOVD $701, R12
+	B    callbackasm1(SB)
+	MOVD $702, R12
+	B    callbackasm1(SB)
+	MOVD $703, R12
+	B    callbackasm1(SB)
+	MOVD $704, R12
+	B    callbackasm1(SB)
+	MOVD $705, R12
+	B    callbackasm1(SB)
+	MOVD $706, R12
+	B    callbackasm1(SB)
+	MOVD $707, R12
+	B    callbackasm1(SB)
+	MOVD $708, R12
+	B    callbackasm1(SB)
+	MOVD $709, R12
+	B    callbackasm1(SB)
+	MOVD $710, R12
+	B    callbackasm1(SB)
+	MOVD $711, R12
+	B    callbackasm1(SB)
+	MOVD $712, R12
+	B    callbackasm1(SB)
+	MOVD $713, R12
+	B    callbackasm1(SB)
+	MOVD $714, R12
+	B    callbackasm1(SB)
+	MOVD $715, R12
+	B    callbackasm1(SB)
+	MOVD $716, R12
+	B    callbackasm1(SB)
+	MOVD $717, R12
+	B    callbackasm1(SB)
+	MOVD $718, R12
+	B    callbackasm1(SB)
+	MOVD $719, R12
+	B    callbackasm1(SB)
+	MOVD $720, R12
+	B    callbackasm1(SB)
+	MOVD $721, R12
+	B    callbackasm1(SB)
+	MOVD $722, R12
+	B    callbackasm1(SB)
+	MOVD $723, R12
+	B    callbackasm1(SB)
+	MOVD $724, R12
+	B    callbackasm1(SB)
+	MOVD $725, R12
+	B    callbackasm1(SB)
+	MOVD $726, R12
+	B    callbackasm1(SB)
+	MOVD $727, R12
+	B    callbackasm1(SB)
+	MOVD $728, R12
+	B    callbackasm1(SB)
+	MOVD $729, R12
+	B    callbackasm1(SB)
+	MOVD $730, R12
+	B    callbackasm1(SB)
+	MOVD $731, R12
+	B    callbackasm1(SB)
+	MOVD $732, R12
+	B    callbackasm1(SB)
+	MOVD $733, R12
+	B    callbackasm1(SB)
+	MOVD $734, R12
+	B    callbackasm1(SB)
+	MOVD $735, R12
+	B    callbackasm1(SB)
+	MOVD $736, R12
+	B    callbackasm1(SB)
+	MOVD $737, R12
+	B    callbackasm1(SB)
+	MOVD $738, R12
+	B    callbackasm1(SB)
+	MOVD $739, R12
+	B    callbackasm1(SB)
+	MOVD $740, R12
+	B    callbackasm1(SB)
+	MOVD $741, R12
+	B    callbackasm1(SB)
+	MOVD $742, R12
+	B    callbackasm1(SB)
+	MOVD $743, R12
+	B    callbackasm1(SB)
+	MOVD $744, R12
+	B    callbackasm1(SB)
+	MOVD $745, R12
+	B    callbackasm1(SB)
+	MOVD $746, R12
+	B    callbackasm1(SB)
+	MOVD $747, R12
+	B    callbackasm1(SB)
+	MOVD $748, R12
+	B    callbackasm1(SB)
+	MOVD $749, R12
+	B    callbackasm1(SB)
+	MOVD $750, R12
+	B    callbackasm1(SB)
+	MOVD $751, R12
+	B    callbackasm1(SB)
+	MOVD $752, R12
+	B    callbackasm1(SB)
+	MOVD $753, R12
+	B    callbackasm1(SB)
+	MOVD $754, R12
+	B    callbackasm1(SB)
+	MOVD $755, R12
+	B    callbackasm1(SB)
+	MOVD $756, R12
+	B    callbackasm1(SB)
+	MOVD $757, R12
+	B    callbackasm1(SB)
+	MOVD $758, R12
+	B    callbackasm1(SB)
+	MOVD $759, R12
+	B    callbackasm1(SB)
+	MOVD $760, R12
+	B    callbackasm1(SB)
+	MOVD $761, R12
+	B    callbackasm1(SB)
+	MOVD $762, R12
+	B    callbackasm1(SB)
+	MOVD $763, R12
+	B    callbackasm1(SB)
+	MOVD $764, R12
+	B    callbackasm1(SB)
+	MOVD $765, R12
+	B    callbackasm1(SB)
+	MOVD $766, R12
+	B    callbackasm1(SB)
+	MOVD $767, R12
+	B    callbackasm1(SB)
+	MOVD $768, R12
+	B    callbackasm1(SB)
+	MOVD $769, R12
+	B    callbackasm1(SB)
+	MOVD $770, R12
+	B    callbackasm1(SB)
+	MOVD $771, R12
+	B    callbackasm1(SB)
+	MOVD $772, R12
+	B    callbackasm1(SB)
+	MOVD $773, R12
+	B    callbackasm1(SB)
+	MOVD $774, R12
+	B    callbackasm1(SB)
+	MOVD $775, R12
+	B    callbackasm1(SB)
+	MOVD $776, R12
+	B    callbackasm1(SB)
+	MOVD $777, R12
+	B    callbackasm1(SB)
+	MOVD $778, R12
+	B    callbackasm1(SB)
+	MOVD $779, R12
+	B    callbackasm1(SB)
+	MOVD $780, R12
+	B    callbackasm1(SB)
+	MOVD $781, R12
+	B    callbackasm1(SB)
+	MOVD $782, R12
+	B    callbackasm1(SB)
+	MOVD $783, R12
+	B    callbackasm1(SB)
+	MOVD $784, R12
+	B    callbackasm1(SB)
+	MOVD $785, R12
+	B    callbackasm1(SB)
+	MOVD $786, R12
+	B    callbackasm1(SB)
+	MOVD $787, R12
+	B    callbackasm1(SB)
+	MOVD $788, R12
+	B    callbackasm1(SB)
+	MOVD $789, R12
+	B    callbackasm1(SB)
+	MOVD $790, R12
+	B    callbackasm1(SB)
+	MOVD $791, R12
+	B    callbackasm1(SB)
+	MOVD $792, R12
+	B    callbackasm1(SB)
+	MOVD $793, R12
+	B    callbackasm1(SB)
+	MOVD $794, R12
+	B    callbackasm1(SB)
+	MOVD $795, R12
+	B    callbackasm1(SB)
+	MOVD $796, R12
+	B    callbackasm1(SB)
+	MOVD $797, R12
+	B    callbackasm1(SB)
+	MOVD $798, R12
+	B    callbackasm1(SB)
+	MOVD $799, R12
+	B    callbackasm1(SB)
+	MOVD $800, R12
+	B    callbackasm1(SB)
+	MOVD $801, R12
+	B    callbackasm1(SB)
+	MOVD $802, R12
+	B    callbackasm1(SB)
+	MOVD $803, R12
+	B    callbackasm1(SB)
+	MOVD $804, R12
+	B    callbackasm1(SB)
+	MOVD $805, R12
+	B    callbackasm1(SB)
+	MOVD $806, R12
+	B    callbackasm1(SB)
+	MOVD $807, R12
+	B    callbackasm1(SB)
+	MOVD $808, R12
+	B    callbackasm1(SB)
+	MOVD $809, R12
+	B    callbackasm1(SB)
+	MOVD $810, R12
+	B    callbackasm1(SB)
+	MOVD $811, R12
+	B    callbackasm1(SB)
+	MOVD $812, R12
+	B    callbackasm1(SB)
+	MOVD $813, R12
+	B    callbackasm1(SB)
+	MOVD $814, R12
+	B    callbackasm1(SB)
+	MOVD $815, R12
+	B    callbackasm1(SB)
+	MOVD $816, R12
+	B    callbackasm1(SB)
+	MOVD $817, R12
+	B    callbackasm1(SB)
+	MOVD $818, R12
+	B    callbackasm1(SB)
+	MOVD $819, R12
+	B    callbackasm1(SB)
+	MOVD $820, R12
+	B    callbackasm1(SB)
+	MOVD $821, R12
+	B    callbackasm1(SB)
+	MOVD $822, R12
+	B    callbackasm1(SB)
+	MOVD $823, R12
+	B    callbackasm1(SB)
+	MOVD $824, R12
+	B    callbackasm1(SB)
+	MOVD $825, R12
+	B    callbackasm1(SB)
+	MOVD $826, R12
+	B    callbackasm1(SB)
+	MOVD $827, R12
+	B    callbackasm1(SB)
+	MOVD $828, R12
+	B    callbackasm1(SB)
+	MOVD $829, R12
+	B    callbackasm1(SB)
+	MOVD $830, R12
+	B    callbackasm1(SB)
+	MOVD $831, R12
+	B    callbackasm1(SB)
+	MOVD $832, R12
+	B    callbackasm1(SB)
+	MOVD $833, R12
+	B    callbackasm1(SB)
+	MOVD $834, R12
+	B    callbackasm1(SB)
+	MOVD $835, R12
+	B    callbackasm1(SB)
+	MOVD $836, R12
+	B    callbackasm1(SB)
+	MOVD $837, R12
+	B    callbackasm1(SB)
+	MOVD $838, R12
+	B    callbackasm1(SB)
+	MOVD $839, R12
+	B    callbackasm1(SB)
+	MOVD $840, R12
+	B    callbackasm1(SB)
+	MOVD $841, R12
+	B    callbackasm1(SB)
+	MOVD $842, R12
+	B    callbackasm1(SB)
+	MOVD $843, R12
+	B    callbackasm1(SB)
+	MOVD $844, R12
+	B    callbackasm1(SB)
+	MOVD $845, R12
+	B    callbackasm1(SB)
+	MOVD $846, R12
+	B    callbackasm1(SB)
+	MOVD $847, R12
+	B    callbackasm1(SB)
+	MOVD $848, R12
+	B    callbackasm1(SB)
+	MOVD $849, R12
+	B    callbackasm1(SB)
+	MOVD $850, R12
+	B    callbackasm1(SB)
+	MOVD $851, R12
+	B    callbackasm1(SB)
+	MOVD $852, R12
+	B    callbackasm1(SB)
+	MOVD $853, R12
+	B    callbackasm1(SB)
+	MOVD $854, R12
+	B    callbackasm1(SB)
+	MOVD $855, R12
+	B    callbackasm1(SB)
+	MOVD $856, R12
+	B    callbackasm1(SB)
+	MOVD $857, R12
+	B    callbackasm1(SB)
+	MOVD $858, R12
+	B    callbackasm1(SB)
+	MOVD $859, R12
+	B    callbackasm1(SB)
+	MOVD $860, R12
+	B    callbackasm1(SB)
+	MOVD $861, R12
+	B    callbackasm1(SB)
+	MOVD $862, R12
+	B    callbackasm1(SB)
+	MOVD $863, R12
+	B    callbackasm1(SB)
+	MOVD $864, R12
+	B    callbackasm1(SB)
+	MOVD $865, R12
+	B    callbackasm1(SB)
+	MOVD $866, R12
+	B    callbackasm1(SB)
+	MOVD $867, R12
+	B    callbackasm1(SB)
+	MOVD $868, R12
+	B    callbackasm1(SB)
+	MOVD $869, R12
+	B    callbackasm1(SB)
+	MOVD $870, R12
+	B    callbackasm1(SB)
+	MOVD $871, R12
+	B    callbackasm1(SB)
+	MOVD $872, R12
+	B    callbackasm1(SB)
+	MOVD $873, R12
+	B    callbackasm1(SB)
+	MOVD $874, R12
+	B    callbackasm1(SB)
+	MOVD $875, R12
+	B    callbackasm1(SB)
+	MOVD $876, R12
+	B    callbackasm1(SB)
+	MOVD $877, R12
+	B    callbackasm1(SB)
+	MOVD $878, R12
+	B    callbackasm1(SB)
+	MOVD $879, R12
+	B    callbackasm1(SB)
+	MOVD $880, R12
+	B    callbackasm1(SB)
+	MOVD $881, R12
+	B    callbackasm1(SB)
+	MOVD $882, R12
+	B    callbackasm1(SB)
+	MOVD $883, R12
+	B    callbackasm1(SB)
+	MOVD $884, R12
+	B    callbackasm1(SB)
+	MOVD $885, R12
+	B    callbackasm1(SB)
+	MOVD $886, R12
+	B    callbackasm1(SB)
+	MOVD $887, R12
+	B    callbackasm1(SB)
+	MOVD $888, R12
+	B    callbackasm1(SB)
+	MOVD $889, R12
+	B    callbackasm1(SB)
+	MOVD $890, R12
+	B    callbackasm1(SB)
+	MOVD $891, R12
+	B    callbackasm1(SB)
+	MOVD $892, R12
+	B    callbackasm1(SB)
+	MOVD $893, R12
+	B    callbackasm1(SB)
+	MOVD $894, R12
+	B    callbackasm1(SB)
+	MOVD $895, R12
+	B    callbackasm1(SB)
+	MOVD $896, R12
+	B    callbackasm1(SB)
+	MOVD $897, R12
+	B    callbackasm1(SB)
+	MOVD $898, R12
+	B    callbackasm1(SB)
+	MOVD $899, R12
+	B    callbackasm1(SB)
+	MOVD $900, R12
+	B    callbackasm1(SB)
+	MOVD $901, R12
+	B    callbackasm1(SB)
+	MOVD $902, R12
+	B    callbackasm1(SB)
+	MOVD $903, R12
+	B    callbackasm1(SB)
+	MOVD $904, R12
+	B    callbackasm1(SB)
+	MOVD $905, R12
+	B    callbackasm1(SB)
+	MOVD $906, R12
+	B    callbackasm1(SB)
+	MOVD $907, R12
+	B    callbackasm1(SB)
+	MOVD $908, R12
+	B    callbackasm1(SB)
+	MOVD $909, R12
+	B    callbackasm1(SB)
+	MOVD $910, R12
+	B    callbackasm1(SB)
+	MOVD $911, R12
+	B    callbackasm1(SB)
+	MOVD $912, R12
+	B    callbackasm1(SB)
+	MOVD $913, R12
+	B    callbackasm1(SB)
+	MOVD $914, R12
+	B    callbackasm1(SB)
+	MOVD $915, R12
+	B    callbackasm1(SB)
+	MOVD $916, R12
+	B    callbackasm1(SB)
+	MOVD $917, R12
+	B    callbackasm1(SB)
+	MOVD $918, R12
+	B    callbackasm1(SB)
+	MOVD $919, R12
+	B    callbackasm1(SB)
+	MOVD $920, R12
+	B    callbackasm1(SB)
+	MOVD $921, R12
+	B    callbackasm1(SB)
+	MOVD $922, R12
+	B    callbackasm1(SB)
+	MOVD $923, R12
+	B    callbackasm1(SB)
+	MOVD $924, R12
+	B    callbackasm1(SB)
+	MOVD $925, R12
+	B    callbackasm1(SB)
+	MOVD $926, R12
+	B    callbackasm1(SB)
+	MOVD $927, R12
+	B    callbackasm1(SB)
+	MOVD $928, R12
+	B    callbackasm1(SB)
+	MOVD $929, R12
+	B    callbackasm1(SB)
+	MOVD $930, R12
+	B    callbackasm1(SB)
+	MOVD $931, R12
+	B    callbackasm1(SB)
+	MOVD $932, R12
+	B    callbackasm1(SB)
+	MOVD $933, R12
+	B    callbackasm1(SB)
+	MOVD $934, R12
+	B    callbackasm1(SB)
+	MOVD $935, R12
+	B    callbackasm1(SB)
+	MOVD $936, R12
+	B    callbackasm1(SB)
+	MOVD $937, R12
+	B    callbackasm1(SB)
+	MOVD $938, R12
+	B    callbackasm1(SB)
+	MOVD $939, R12
+	B    callbackasm1(SB)
+	MOVD $940, R12
+	B    callbackasm1(SB)
+	MOVD $941, R12
+	B    callbackasm1(SB)
+	MOVD $942, R12
+	B    callbackasm1(SB)
+	MOVD $943, R12
+	B    callbackasm1(SB)
+	MOVD $944, R12
+	B    callbackasm1(SB)
+	MOVD $945, R12
+	B    callbackasm1(SB)
+	MOVD $946, R12
+	B    callbackasm1(SB)
+	MOVD $947, R12
+	B    callbackasm1(SB)
+	MOVD $948, R12
+	B    callbackasm1(SB)
+	MOVD $949, R12
+	B    callbackasm1(SB)
+	MOVD $950, R12
+	B    callbackasm1(SB)
+	MOVD $951, R12
+	B    callbackasm1(SB)
+	MOVD $952, R12
+	B    callbackasm1(SB)
+	MOVD $953, R12
+	B    callbackasm1(SB)
+	MOVD $954, R12
+	B    callbackasm1(SB)
+	MOVD $955, R12
+	B    callbackasm1(SB)
+	MOVD $956, R12
+	B    callbackasm1(SB)
+	MOVD $957, R12
+	B    callbackasm1(SB)
+	MOVD $958, R12
+	B    callbackasm1(SB)
+	MOVD $959, R12
+	B    callbackasm1(SB)
+	MOVD $960, R12
+	B    callbackasm1(SB)
+	MOVD $961, R12
+	B    callbackasm1(SB)
+	MOVD $962, R12
+	B    callbackasm1(SB)
+	MOVD $963, R12
+	B    callbackasm1(SB)
+	MOVD $964, R12
+	B    callbackasm1(SB)
+	MOVD $965, R12
+	B    callbackasm1(SB)
+	MOVD $966, R12
+	B    callbackasm1(SB)
+	MOVD $967, R12
+	B    callbackasm1(SB)
+	MOVD $968, R12
+	B    callbackasm1(SB)
+	MOVD $969, R12
+	B    callbackasm1(SB)
+	MOVD $970, R12
+	B    callbackasm1(SB)
+	MOVD $971, R12
+	B    callbackasm1(SB)
+	MOVD $972, R12
+	B    callbackasm1(SB)
+	MOVD $973, R12
+	B    callbackasm1(SB)
+	MOVD $974, R12
+	B    callbackasm1(SB)
+	MOVD $975, R12
+	B    callbackasm1(SB)
+	MOVD $976, R12
+	B    callbackasm1(SB)
+	MOVD $977, R12
+	B    callbackasm1(SB)
+	MOVD $978, R12
+	B    callbackasm1(SB)
+	MOVD $979, R12
+	B    callbackasm1(SB)
+	MOVD $980, R12
+	B    callbackasm1(SB)
+	MOVD $981, R12
+	B    callbackasm1(SB)
+	MOVD $982, R12
+	B    callbackasm1(SB)
+	MOVD $983, R12
+	B    callbackasm1(SB)
+	MOVD $984, R12
+	B    callbackasm1(SB)
+	MOVD $985, R12
+	B    callbackasm1(SB)
+	MOVD $986, R12
+	B    callbackasm1(SB)
+	MOVD $987, R12
+	B    callbackasm1(SB)
+	MOVD $988, R12
+	B    callbackasm1(SB)
+	MOVD $989, R12
+	B    callbackasm1(SB)
+	MOVD $990, R12
+	B    callbackasm1(SB)
+	MOVD $991, R12
+	B    callbackasm1(SB)
+	MOVD $992, R12
+	B    callbackasm1(SB)
+	MOVD $993, R12
+	B    callbackasm1(SB)
+	MOVD $994, R12
+	B    callbackasm1(SB)
+	MOVD $995, R12
+	B    callbackasm1(SB)
+	MOVD $996, R12
+	B    callbackasm1(SB)
+	MOVD $997, R12
+	B    callbackasm1(SB)
+	MOVD $998, R12
+	B    callbackasm1(SB)
+	MOVD $999, R12
+	B    callbackasm1(SB)
+	MOVD $1000, R12
+	B    callbackasm1(SB)
+	MOVD $1001, R12
+	B    callbackasm1(SB)
+	MOVD $1002, R12
+	B    callbackasm1(SB)
+	MOVD $1003, R12
+	B    callbackasm1(SB)
+	MOVD $1004, R12
+	B    callbackasm1(SB)
+	MOVD $1005, R12
+	B    callbackasm1(SB)
+	MOVD $1006, R12
+	B    callbackasm1(SB)
+	MOVD $1007, R12
+	B    callbackasm1(SB)
+	MOVD $1008, R12
+	B    callbackasm1(SB)
+	MOVD $1009, R12
+	B    callbackasm1(SB)
+	MOVD $1010, R12
+	B    callbackasm1(SB)
+	MOVD $1011, R12
+	B    callbackasm1(SB)
+	MOVD $1012, R12
+	B    callbackasm1(SB)
+	MOVD $1013, R12
+	B    callbackasm1(SB)
+	MOVD $1014, R12
+	B    callbackasm1(SB)
+	MOVD $1015, R12
+	B    callbackasm1(SB)
+	MOVD $1016, R12
+	B    callbackasm1(SB)
+	MOVD $1017, R12
+	B    callbackasm1(SB)
+	MOVD $1018, R12
+	B    callbackasm1(SB)
+	MOVD $1019, R12
+	B    callbackasm1(SB)
+	MOVD $1020, R12
+	B    callbackasm1(SB)
+	MOVD $1021, R12
+	B    callbackasm1(SB)
+	MOVD $1022, R12
+	B    callbackasm1(SB)
+	MOVD $1023, R12
+	B    callbackasm1(SB)
+	MOVD $1024, R12
+	B    callbackasm1(SB)
+	MOVD $1025, R12
+	B    callbackasm1(SB)
+	MOVD $1026, R12
+	B    callbackasm1(SB)
+	MOVD $1027, R12
+	B    callbackasm1(SB)
+	MOVD $1028, R12
+	B    callbackasm1(SB)
+	MOVD $1029, R12
+	B    callbackasm1(SB)
+	MOVD $1030, R12
+	B    callbackasm1(SB)
+	MOVD $1031, R12
+	B    callbackasm1(SB)
+	MOVD $1032, R12
+	B    callbackasm1(SB)
+	MOVD $1033, R12
+	B    callbackasm1(SB)
+	MOVD $1034, R12
+	B    callbackasm1(SB)
+	MOVD $1035, R12
+	B    callbackasm1(SB)
+	MOVD $1036, R12
+	B    callbackasm1(SB)
+	MOVD $1037, R12
+	B    callbackasm1(SB)
+	MOVD $1038, R12
+	B    callbackasm1(SB)
+	MOVD $1039, R12
+	B    callbackasm1(SB)
+	MOVD $1040, R12
+	B    callbackasm1(SB)
+	MOVD $1041, R12
+	B    callbackasm1(SB)
+	MOVD $1042, R12
+	B    callbackasm1(SB)
+	MOVD $1043, R12
+	B    callbackasm1(SB)
+	MOVD $1044, R12
+	B    callbackasm1(SB)
+	MOVD $1045, R12
+	B    callbackasm1(SB)
+	MOVD $1046, R12
+	B    callbackasm1(SB)
+	MOVD $1047, R12
+	B    callbackasm1(SB)
+	MOVD $1048, R12
+	B    callbackasm1(SB)
+	MOVD $1049, R12
+	B    callbackasm1(SB)
+	MOVD $1050, R12
+	B    callbackasm1(SB)
+	MOVD $1051, R12
+	B    callbackasm1(SB)
+	MOVD $1052, R12
+	B    callbackasm1(SB)
+	MOVD $1053, R12
+	B    callbackasm1(SB)
+	MOVD $1054, R12
+	B    callbackasm1(SB)
+	MOVD $1055, R12
+	B    callbackasm1(SB)
+	MOVD $1056, R12
+	B    callbackasm1(SB)
+	MOVD $1057, R12
+	B    callbackasm1(SB)
+	MOVD $1058, R12
+	B    callbackasm1(SB)
+	MOVD $1059, R12
+	B    callbackasm1(SB)
+	MOVD $1060, R12
+	B    callbackasm1(SB)
+	MOVD $1061, R12
+	B    callbackasm1(SB)
+	MOVD $1062, R12
+	B    callbackasm1(SB)
+	MOVD $1063, R12
+	B    callbackasm1(SB)
+	MOVD $1064, R12
+	B    callbackasm1(SB)
+	MOVD $1065, R12
+	B    callbackasm1(SB)
+	MOVD $1066, R12
+	B    callbackasm1(SB)
+	MOVD $1067, R12
+	B    callbackasm1(SB)
+	MOVD $1068, R12
+	B    callbackasm1(SB)
+	MOVD $1069, R12
+	B    callbackasm1(SB)
+	MOVD $1070, R12
+	B    callbackasm1(SB)
+	MOVD $1071, R12
+	B    callbackasm1(SB)
+	MOVD $1072, R12
+	B    callbackasm1(SB)
+	MOVD $1073, R12
+	B    callbackasm1(SB)
+	MOVD $1074, R12
+	B    callbackasm1(SB)
+	MOVD $1075, R12
+	B    callbackasm1(SB)
+	MOVD $1076, R12
+	B    callbackasm1(SB)
+	MOVD $1077, R12
+	B    callbackasm1(SB)
+	MOVD $1078, R12
+	B    callbackasm1(SB)
+	MOVD $1079, R12
+	B    callbackasm1(SB)
+	MOVD $1080, R12
+	B    callbackasm1(SB)
+	MOVD $1081, R12
+	B    callbackasm1(SB)
+	MOVD $1082, R12
+	B    callbackasm1(SB)
+	MOVD $1083, R12
+	B    callbackasm1(SB)
+	MOVD $1084, R12
+	B    callbackasm1(SB)
+	MOVD $1085, R12
+	B    callbackasm1(SB)
+	MOVD $1086, R12
+	B    callbackasm1(SB)
+	MOVD $1087, R12
+	B    callbackasm1(SB)
+	MOVD $1088, R12
+	B    callbackasm1(SB)
+	MOVD $1089, R12
+	B    callbackasm1(SB)
+	MOVD $1090, R12
+	B    callbackasm1(SB)
+	MOVD $1091, R12
+	B    callbackasm1(SB)
+	MOVD $1092, R12
+	B    callbackasm1(SB)
+	MOVD $1093, R12
+	B    callbackasm1(SB)
+	MOVD $1094, R12
+	B    callbackasm1(SB)
+	MOVD $1095, R12
+	B    callbackasm1(SB)
+	MOVD $1096, R12
+	B    callbackasm1(SB)
+	MOVD $1097, R12
+	B    callbackasm1(SB)
+	MOVD $1098, R12
+	B    callbackasm1(SB)
+	MOVD $1099, R12
+	B    callbackasm1(SB)
+	MOVD $1100, R12
+	B    callbackasm1(SB)
+	MOVD $1101, R12
+	B    callbackasm1(SB)
+	MOVD $1102, R12
+	B    callbackasm1(SB)
+	MOVD $1103, R12
+	B    callbackasm1(SB)
+	MOVD $1104, R12
+	B    callbackasm1(SB)
+	MOVD $1105, R12
+	B    callbackasm1(SB)
+	MOVD $1106, R12
+	B    callbackasm1(SB)
+	MOVD $1107, R12
+	B    callbackasm1(SB)
+	MOVD $1108, R12
+	B    callbackasm1(SB)
+	MOVD $1109, R12
+	B    callbackasm1(SB)
+	MOVD $1110, R12
+	B    callbackasm1(SB)
+	MOVD $1111, R12
+	B    callbackasm1(SB)
+	MOVD $1112, R12
+	B    callbackasm1(SB)
+	MOVD $1113, R12
+	B    callbackasm1(SB)
+	MOVD $1114, R12
+	B    callbackasm1(SB)
+	MOVD $1115, R12
+	B    callbackasm1(SB)
+	MOVD $1116, R12
+	B    callbackasm1(SB)
+	MOVD $1117, R12
+	B    callbackasm1(SB)
+	MOVD $1118, R12
+	B    callbackasm1(SB)
+	MOVD $1119, R12
+	B    callbackasm1(SB)
+	MOVD $1120, R12
+	B    callbackasm1(SB)
+	MOVD $1121, R12
+	B    callbackasm1(SB)
+	MOVD $1122, R12
+	B    callbackasm1(SB)
+	MOVD $1123, R12
+	B    callbackasm1(SB)
+	MOVD $1124, R12
+	B    callbackasm1(SB)
+	MOVD $1125, R12
+	B    callbackasm1(SB)
+	MOVD $1126, R12
+	B    callbackasm1(SB)
+	MOVD $1127, R12
+	B    callbackasm1(SB)
+	MOVD $1128, R12
+	B    callbackasm1(SB)
+	MOVD $1129, R12
+	B    callbackasm1(SB)
+	MOVD $1130, R12
+	B    callbackasm1(SB)
+	MOVD $1131, R12
+	B    callbackasm1(SB)
+	MOVD $1132, R12
+	B    callbackasm1(SB)
+	MOVD $1133, R12
+	B    callbackasm1(SB)
+	MOVD $1134, R12
+	B    callbackasm1(SB)
+	MOVD $1135, R12
+	B    callbackasm1(SB)
+	MOVD $1136, R12
+	B    callbackasm1(SB)
+	MOVD $1137, R12
+	B    callbackasm1(SB)
+	MOVD $1138, R12
+	B    callbackasm1(SB)
+	MOVD $1139, R12
+	B    callbackasm1(SB)
+	MOVD $1140, R12
+	B    callbackasm1(SB)
+	MOVD $1141, R12
+	B    callbackasm1(SB)
+	MOVD $1142, R12
+	B    callbackasm1(SB)
+	MOVD $1143, R12
+	B    callbackasm1(SB)
+	MOVD $1144, R12
+	B    callbackasm1(SB)
+	MOVD $1145, R12
+	B    callbackasm1(SB)
+	MOVD $1146, R12
+	B    callbackasm1(SB)
+	MOVD $1147, R12
+	B    callbackasm1(SB)
+	MOVD $1148, R12
+	B    callbackasm1(SB)
+	MOVD $1149, R12
+	B    callbackasm1(SB)
+	MOVD $1150, R12
+	B    callbackasm1(SB)
+	MOVD $1151, R12
+	B    callbackasm1(SB)
+	MOVD $1152, R12
+	B    callbackasm1(SB)
+	MOVD $1153, R12
+	B    callbackasm1(SB)
+	MOVD $1154, R12
+	B    callbackasm1(SB)
+	MOVD $1155, R12
+	B    callbackasm1(SB)
+	MOVD $1156, R12
+	B    callbackasm1(SB)
+	MOVD $1157, R12
+	B    callbackasm1(SB)
+	MOVD $1158, R12
+	B    callbackasm1(SB)
+	MOVD $1159, R12
+	B    callbackasm1(SB)
+	MOVD $1160, R12
+	B    callbackasm1(SB)
+	MOVD $1161, R12
+	B    callbackasm1(SB)
+	MOVD $1162, R12
+	B    callbackasm1(SB)
+	MOVD $1163, R12
+	B    callbackasm1(SB)
+	MOVD $1164, R12
+	B    callbackasm1(SB)
+	MOVD $1165, R12
+	B    callbackasm1(SB)
+	MOVD $1166, R12
+	B    callbackasm1(SB)
+	MOVD $1167, R12
+	B    callbackasm1(SB)
+	MOVD $1168, R12
+	B    callbackasm1(SB)
+	MOVD $1169, R12
+	B    callbackasm1(SB)
+	MOVD $1170, R12
+	B    callbackasm1(SB)
+	MOVD $1171, R12
+	B    callbackasm1(SB)
+	MOVD $1172, R12
+	B    callbackasm1(SB)
+	MOVD $1173, R12
+	B    callbackasm1(SB)
+	MOVD $1174, R12
+	B    callbackasm1(SB)
+	MOVD $1175, R12
+	B    callbackasm1(SB)
+	MOVD $1176, R12
+	B    callbackasm1(SB)
+	MOVD $1177, R12
+	B    callbackasm1(SB)
+	MOVD $1178, R12
+	B    callbackasm1(SB)
+	MOVD $1179, R12
+	B    callbackasm1(SB)
+	MOVD $1180, R12
+	B    callbackasm1(SB)
+	MOVD $1181, R12
+	B    callbackasm1(SB)
+	MOVD $1182, R12
+	B    callbackasm1(SB)
+	MOVD $1183, R12
+	B    callbackasm1(SB)
+	MOVD $1184, R12
+	B    callbackasm1(SB)
+	MOVD $1185, R12
+	B    callbackasm1(SB)
+	MOVD $1186, R12
+	B    callbackasm1(SB)
+	MOVD $1187, R12
+	B    callbackasm1(SB)
+	MOVD $1188, R12
+	B    callbackasm1(SB)
+	MOVD $1189, R12
+	B    callbackasm1(SB)
+	MOVD $1190, R12
+	B    callbackasm1(SB)
+	MOVD $1191, R12
+	B    callbackasm1(SB)
+	MOVD $1192, R12
+	B    callbackasm1(SB)
+	MOVD $1193, R12
+	B    callbackasm1(SB)
+	MOVD $1194, R12
+	B    callbackasm1(SB)
+	MOVD $1195, R12
+	B    callbackasm1(SB)
+	MOVD $1196, R12
+	B    callbackasm1(SB)
+	MOVD $1197, R12
+	B    callbackasm1(SB)
+	MOVD $1198, R12
+	B    callbackasm1(SB)
+	MOVD $1199, R12
+	B    callbackasm1(SB)
+	MOVD $1200, R12
+	B    callbackasm1(SB)
+	MOVD $1201, R12
+	B    callbackasm1(SB)
+	MOVD $1202, R12
+	B    callbackasm1(SB)
+	MOVD $1203, R12
+	B    callbackasm1(SB)
+	MOVD $1204, R12
+	B    callbackasm1(SB)
+	MOVD $1205, R12
+	B    callbackasm1(SB)
+	MOVD $1206, R12
+	B    callbackasm1(SB)
+	MOVD $1207, R12
+	B    callbackasm1(SB)
+	MOVD $1208, R12
+	B    callbackasm1(SB)
+	MOVD $1209, R12
+	B    callbackasm1(SB)
+	MOVD $1210, R12
+	B    callbackasm1(SB)
+	MOVD $1211, R12
+	B    callbackasm1(SB)
+	MOVD $1212, R12
+	B    callbackasm1(SB)
+	MOVD $1213, R12
+	B    callbackasm1(SB)
+	MOVD $1214, R12
+	B    callbackasm1(SB)
+	MOVD $1215, R12
+	B    callbackasm1(SB)
+	MOVD $1216, R12
+	B    callbackasm1(SB)
+	MOVD $1217, R12
+	B    callbackasm1(SB)
+	MOVD $1218, R12
+	B    callbackasm1(SB)
+	MOVD $1219, R12
+	B    callbackasm1(SB)
+	MOVD $1220, R12
+	B    callbackasm1(SB)
+	MOVD $1221, R12
+	B    callbackasm1(SB)
+	MOVD $1222, R12
+	B    callbackasm1(SB)
+	MOVD $1223, R12
+	B    callbackasm1(SB)
+	MOVD $1224, R12
+	B    callbackasm1(SB)
+	MOVD $1225, R12
+	B    callbackasm1(SB)
+	MOVD $1226, R12
+	B    callbackasm1(SB)
+	MOVD $1227, R12
+	B    callbackasm1(SB)
+	MOVD $1228, R12
+	B    callbackasm1(SB)
+	MOVD $1229, R12
+	B    callbackasm1(SB)
+	MOVD $1230, R12
+	B    callbackasm1(SB)
+	MOVD $1231, R12
+	B    callbackasm1(SB)
+	MOVD $1232, R12
+	B    callbackasm1(SB)
+	MOVD $1233, R12
+	B    callbackasm1(SB)
+	MOVD $1234, R12
+	B    callbackasm1(SB)
+	MOVD $1235, R12
+	B    callbackasm1(SB)
+	MOVD $1236, R12
+	B    callbackasm1(SB)
+	MOVD $1237, R12
+	B    callbackasm1(SB)
+	MOVD $1238, R12
+	B    callbackasm1(SB)
+	MOVD $1239, R12
+	B    callbackasm1(SB)
+	MOVD $1240, R12
+	B    callbackasm1(SB)
+	MOVD $1241, R12
+	B    callbackasm1(SB)
+	MOVD $1242, R12
+	B    callbackasm1(SB)
+	MOVD $1243, R12
+	B    callbackasm1(SB)
+	MOVD $1244, R12
+	B    callbackasm1(SB)
+	MOVD $1245, R12
+	B    callbackasm1(SB)
+	MOVD $1246, R12
+	B    callbackasm1(SB)
+	MOVD $1247, R12
+	B    callbackasm1(SB)
+	MOVD $1248, R12
+	B    callbackasm1(SB)
+	MOVD $1249, R12
+	B    callbackasm1(SB)
+	MOVD $1250, R12
+	B    callbackasm1(SB)
+	MOVD $1251, R12
+	B    callbackasm1(SB)
+	MOVD $1252, R12
+	B    callbackasm1(SB)
+	MOVD $1253, R12
+	B    callbackasm1(SB)
+	MOVD $1254, R12
+	B    callbackasm1(SB)
+	MOVD $1255, R12
+	B    callbackasm1(SB)
+	MOVD $1256, R12
+	B    callbackasm1(SB)
+	MOVD $1257, R12
+	B    callbackasm1(SB)
+	MOVD $1258, R12
+	B    callbackasm1(SB)
+	MOVD $1259, R12
+	B    callbackasm1(SB)
+	MOVD $1260, R12
+	B    callbackasm1(SB)
+	MOVD $1261, R12
+	B    callbackasm1(SB)
+	MOVD $1262, R12
+	B    callbackasm1(SB)
+	MOVD $1263, R12
+	B    callbackasm1(SB)
+	MOVD $1264, R12
+	B    callbackasm1(SB)
+	MOVD $1265, R12
+	B    callbackasm1(SB)
+	MOVD $1266, R12
+	B    callbackasm1(SB)
+	MOVD $1267, R12
+	B    callbackasm1(SB)
+	MOVD $1268, R12
+	B    callbackasm1(SB)
+	MOVD $1269, R12
+	B    callbackasm1(SB)
+	MOVD $1270, R12
+	B    callbackasm1(SB)
+	MOVD $1271, R12
+	B    callbackasm1(SB)
+	MOVD $1272, R12
+	B    callbackasm1(SB)
+	MOVD $1273, R12
+	B    callbackasm1(SB)
+	MOVD $1274, R12
+	B    callbackasm1(SB)
+	MOVD $1275, R12
+	B    callbackasm1(SB)
+	MOVD $1276, R12
+	B    callbackasm1(SB)
+	MOVD $1277, R12
+	B    callbackasm1(SB)
+	MOVD $1278, R12
+	B    callbackasm1(SB)
+	MOVD $1279, R12
+	B    callbackasm1(SB)
+	MOVD $1280, R12
+	B    callbackasm1(SB)
+	MOVD $1281, R12
+	B    callbackasm1(SB)
+	MOVD $1282, R12
+	B    callbackasm1(SB)
+	MOVD $1283, R12
+	B    callbackasm1(SB)
+	MOVD $1284, R12
+	B    callbackasm1(SB)
+	MOVD $1285, R12
+	B    callbackasm1(SB)
+	MOVD $1286, R12
+	B    callbackasm1(SB)
+	MOVD $1287, R12
+	B    callbackasm1(SB)
+	MOVD $1288, R12
+	B    callbackasm1(SB)
+	MOVD $1289, R12
+	B    callbackasm1(SB)
+	MOVD $1290, R12
+	B    callbackasm1(SB)
+	MOVD $1291, R12
+	B    callbackasm1(SB)
+	MOVD $1292, R12
+	B    callbackasm1(SB)
+	MOVD $1293, R12
+	B    callbackasm1(SB)
+	MOVD $1294, R12
+	B    callbackasm1(SB)
+	MOVD $1295, R12
+	B    callbackasm1(SB)
+	MOVD $1296, R12
+	B    callbackasm1(SB)
+	MOVD $1297, R12
+	B    callbackasm1(SB)
+	MOVD $1298, R12
+	B    callbackasm1(SB)
+	MOVD $1299, R12
+	B    callbackasm1(SB)
+	MOVD $1300, R12
+	B    callbackasm1(SB)
+	MOVD $1301, R12
+	B    callbackasm1(SB)
+	MOVD $1302, R12
+	B    callbackasm1(SB)
+	MOVD $1303, R12
+	B    callbackasm1(SB)
+	MOVD $1304, R12
+	B    callbackasm1(SB)
+	MOVD $1305, R12
+	B    callbackasm1(SB)
+	MOVD $1306, R12
+	B    callbackasm1(SB)
+	MOVD $1307, R12
+	B    callbackasm1(SB)
+	MOVD $1308, R12
+	B    callbackasm1(SB)
+	MOVD $1309, R12
+	B    callbackasm1(SB)
+	MOVD $1310, R12
+	B    callbackasm1(SB)
+	MOVD $1311, R12
+	B    callbackasm1(SB)
+	MOVD $1312, R12
+	B    callbackasm1(SB)
+	MOVD $1313, R12
+	B    callbackasm1(SB)
+	MOVD $1314, R12
+	B    callbackasm1(SB)
+	MOVD $1315, R12
+	B    callbackasm1(SB)
+	MOVD $1316, R12
+	B    callbackasm1(SB)
+	MOVD $1317, R12
+	B    callbackasm1(SB)
+	MOVD $1318, R12
+	B    callbackasm1(SB)
+	MOVD $1319, R12
+	B    callbackasm1(SB)
+	MOVD $1320, R12
+	B    callbackasm1(SB)
+	MOVD $1321, R12
+	B    callbackasm1(SB)
+	MOVD $1322, R12
+	B    callbackasm1(SB)
+	MOVD $1323, R12
+	B    callbackasm1(SB)
+	MOVD $1324, R12
+	B    callbackasm1(SB)
+	MOVD $1325, R12
+	B    callbackasm1(SB)
+	MOVD $1326, R12
+	B    callbackasm1(SB)
+	MOVD $1327, R12
+	B    callbackasm1(SB)
+	MOVD $1328, R12
+	B    callbackasm1(SB)
+	MOVD $1329, R12
+	B    callbackasm1(SB)
+	MOVD $1330, R12
+	B    callbackasm1(SB)
+	MOVD $1331, R12
+	B    callbackasm1(SB)
+	MOVD $1332, R12
+	B    callbackasm1(SB)
+	MOVD $1333, R12
+	B    callbackasm1(SB)
+	MOVD $1334, R12
+	B    callbackasm1(SB)
+	MOVD $1335, R12
+	B    callbackasm1(SB)
+	MOVD $1336, R12
+	B    callbackasm1(SB)
+	MOVD $1337, R12
+	B    callbackasm1(SB)
+	MOVD $1338, R12
+	B    callbackasm1(SB)
+	MOVD $1339, R12
+	B    callbackasm1(SB)
+	MOVD $1340, R12
+	B    callbackasm1(SB)
+	MOVD $1341, R12
+	B    callbackasm1(SB)
+	MOVD $1342, R12
+	B    callbackasm1(SB)
+	MOVD $1343, R12
+	B    callbackasm1(SB)
+	MOVD $1344, R12
+	B    callbackasm1(SB)
+	MOVD $1345, R12
+	B    callbackasm1(SB)
+	MOVD $1346, R12
+	B    callbackasm1(SB)
+	MOVD $1347, R12
+	B    callbackasm1(SB)
+	MOVD $1348, R12
+	B    callbackasm1(SB)
+	MOVD $1349, R12
+	B    callbackasm1(SB)
+	MOVD $1350, R12
+	B    callbackasm1(SB)
+	MOVD $1351, R12
+	B    callbackasm1(SB)
+	MOVD $1352, R12
+	B    callbackasm1(SB)
+	MOVD $1353, R12
+	B    callbackasm1(SB)
+	MOVD $1354, R12
+	B    callbackasm1(SB)
+	MOVD $1355, R12
+	B    callbackasm1(SB)
+	MOVD $1356, R12
+	B    callbackasm1(SB)
+	MOVD $1357, R12
+	B    callbackasm1(SB)
+	MOVD $1358, R12
+	B    callbackasm1(SB)
+	MOVD $1359, R12
+	B    callbackasm1(SB)
+	MOVD $1360, R12
+	B    callbackasm1(SB)
+	MOVD $1361, R12
+	B    callbackasm1(SB)
+	MOVD $1362, R12
+	B    callbackasm1(SB)
+	MOVD $1363, R12
+	B    callbackasm1(SB)
+	MOVD $1364, R12
+	B    callbackasm1(SB)
+	MOVD $1365, R12
+	B    callbackasm1(SB)
+	MOVD $1366, R12
+	B    callbackasm1(SB)
+	MOVD $1367, R12
+	B    callbackasm1(SB)
+	MOVD $1368, R12
+	B    callbackasm1(SB)
+	MOVD $1369, R12
+	B    callbackasm1(SB)
+	MOVD $1370, R12
+	B    callbackasm1(SB)
+	MOVD $1371, R12
+	B    callbackasm1(SB)
+	MOVD $1372, R12
+	B    callbackasm1(SB)
+	MOVD $1373, R12
+	B    callbackasm1(SB)
+	MOVD $1374, R12
+	B    callbackasm1(SB)
+	MOVD $1375, R12
+	B    callbackasm1(SB)
+	MOVD $1376, R12
+	B    callbackasm1(SB)
+	MOVD $1377, R12
+	B    callbackasm1(SB)
+	MOVD $1378, R12
+	B    callbackasm1(SB)
+	MOVD $1379, R12
+	B    callbackasm1(SB)
+	MOVD $1380, R12
+	B    callbackasm1(SB)
+	MOVD $1381, R12
+	B    callbackasm1(SB)
+	MOVD $1382, R12
+	B    callbackasm1(SB)
+	MOVD $1383, R12
+	B    callbackasm1(SB)
+	MOVD $1384, R12
+	B    callbackasm1(SB)
+	MOVD $1385, R12
+	B    callbackasm1(SB)
+	MOVD $1386, R12
+	B    callbackasm1(SB)
+	MOVD $1387, R12
+	B    callbackasm1(SB)
+	MOVD $1388, R12
+	B    callbackasm1(SB)
+	MOVD $1389, R12
+	B    callbackasm1(SB)
+	MOVD $1390, R12
+	B    callbackasm1(SB)
+	MOVD $1391, R12
+	B    callbackasm1(SB)
+	MOVD $1392, R12
+	B    callbackasm1(SB)
+	MOVD $1393, R12
+	B    callbackasm1(SB)
+	MOVD $1394, R12
+	B    callbackasm1(SB)
+	MOVD $1395, R12
+	B    callbackasm1(SB)
+	MOVD $1396, R12
+	B    callbackasm1(SB)
+	MOVD $1397, R12
+	B    callbackasm1(SB)
+	MOVD $1398, R12
+	B    callbackasm1(SB)
+	MOVD $1399, R12
+	B    callbackasm1(SB)
+	MOVD $1400, R12
+	B    callbackasm1(SB)
+	MOVD $1401, R12
+	B    callbackasm1(SB)
+	MOVD $1402, R12
+	B    callbackasm1(SB)
+	MOVD $1403, R12
+	B    callbackasm1(SB)
+	MOVD $1404, R12
+	B    callbackasm1(SB)
+	MOVD $1405, R12
+	B    callbackasm1(SB)
+	MOVD $1406, R12
+	B    callbackasm1(SB)
+	MOVD $1407, R12
+	B    callbackasm1(SB)
+	MOVD $1408, R12
+	B    callbackasm1(SB)
+	MOVD $1409, R12
+	B    callbackasm1(SB)
+	MOVD $1410, R12
+	B    callbackasm1(SB)
+	MOVD $1411, R12
+	B    callbackasm1(SB)
+	MOVD $1412, R12
+	B    callbackasm1(SB)
+	MOVD $1413, R12
+	B    callbackasm1(SB)
+	MOVD $1414, R12
+	B    callbackasm1(SB)
+	MOVD $1415, R12
+	B    callbackasm1(SB)
+	MOVD $1416, R12
+	B    callbackasm1(SB)
+	MOVD $1417, R12
+	B    callbackasm1(SB)
+	MOVD $1418, R12
+	B    callbackasm1(SB)
+	MOVD $1419, R12
+	B    callbackasm1(SB)
+	MOVD $1420, R12
+	B    callbackasm1(SB)
+	MOVD $1421, R12
+	B    callbackasm1(SB)
+	MOVD $1422, R12
+	B    callbackasm1(SB)
+	MOVD $1423, R12
+	B    callbackasm1(SB)
+	MOVD $1424, R12
+	B    callbackasm1(SB)
+	MOVD $1425, R12
+	B    callbackasm1(SB)
+	MOVD $1426, R12
+	B    callbackasm1(SB)
+	MOVD $1427, R12
+	B    callbackasm1(SB)
+	MOVD $1428, R12
+	B    callbackasm1(SB)
+	MOVD $1429, R12
+	B    callbackasm1(SB)
+	MOVD $1430, R12
+	B    callbackasm1(SB)
+	MOVD $1431, R12
+	B    callbackasm1(SB)
+	MOVD $1432, R12
+	B    callbackasm1(SB)
+	MOVD $1433, R12
+	B    callbackasm1(SB)
+	MOVD $1434, R12
+	B    callbackasm1(SB)
+	MOVD $1435, R12
+	B    callbackasm1(SB)
+	MOVD $1436, R12
+	B    callbackasm1(SB)
+	MOVD $1437, R12
+	B    callbackasm1(SB)
+	MOVD $1438, R12
+	B    callbackasm1(SB)
+	MOVD $1439, R12
+	B    callbackasm1(SB)
+	MOVD $1440, R12
+	B    callbackasm1(SB)
+	MOVD $1441, R12
+	B    callbackasm1(SB)
+	MOVD $1442, R12
+	B    callbackasm1(SB)
+	MOVD $1443, R12
+	B    callbackasm1(SB)
+	MOVD $1444, R12
+	B    callbackasm1(SB)
+	MOVD $1445, R12
+	B    callbackasm1(SB)
+	MOVD $1446, R12
+	B    callbackasm1(SB)
+	MOVD $1447, R12
+	B    callbackasm1(SB)
+	MOVD $1448, R12
+	B    callbackasm1(SB)
+	MOVD $1449, R12
+	B    callbackasm1(SB)
+	MOVD $1450, R12
+	B    callbackasm1(SB)
+	MOVD $1451, R12
+	B    callbackasm1(SB)
+	MOVD $1452, R12
+	B    callbackasm1(SB)
+	MOVD $1453, R12
+	B    callbackasm1(SB)
+	MOVD $1454, R12
+	B    callbackasm1(SB)
+	MOVD $1455, R12
+	B    callbackasm1(SB)
+	MOVD $1456, R12
+	B    callbackasm1(SB)
+	MOVD $1457, R12
+	B    callbackasm1(SB)
+	MOVD $1458, R12
+	B    callbackasm1(SB)
+	MOVD $1459, R12
+	B    callbackasm1(SB)
+	MOVD $1460, R12
+	B    callbackasm1(SB)
+	MOVD $1461, R12
+	B    callbackasm1(SB)
+	MOVD $1462, R12
+	B    callbackasm1(SB)
+	MOVD $1463, R12
+	B    callbackasm1(SB)
+	MOVD $1464, R12
+	B    callbackasm1(SB)
+	MOVD $1465, R12
+	B    callbackasm1(SB)
+	MOVD $1466, R12
+	B    callbackasm1(SB)
+	MOVD $1467, R12
+	B    callbackasm1(SB)
+	MOVD $1468, R12
+	B    callbackasm1(SB)
+	MOVD $1469, R12
+	B    callbackasm1(SB)
+	MOVD $1470, R12
+	B    callbackasm1(SB)
+	MOVD $1471, R12
+	B    callbackasm1(SB)
+	MOVD $1472, R12
+	B    callbackasm1(SB)
+	MOVD $1473, R12
+	B    callbackasm1(SB)
+	MOVD $1474, R12
+	B    callbackasm1(SB)
+	MOVD $1475, R12
+	B    callbackasm1(SB)
+	MOVD $1476, R12
+	B    callbackasm1(SB)
+	MOVD $1477, R12
+	B    callbackasm1(SB)
+	MOVD $1478, R12
+	B    callbackasm1(SB)
+	MOVD $1479, R12
+	B    callbackasm1(SB)
+	MOVD $1480, R12
+	B    callbackasm1(SB)
+	MOVD $1481, R12
+	B    callbackasm1(SB)
+	MOVD $1482, R12
+	B    callbackasm1(SB)
+	MOVD $1483, R12
+	B    callbackasm1(SB)
+	MOVD $1484, R12
+	B    callbackasm1(SB)
+	MOVD $1485, R12
+	B    callbackasm1(SB)
+	MOVD $1486, R12
+	B    callbackasm1(SB)
+	MOVD $1487, R12
+	B    callbackasm1(SB)
+	MOVD $1488, R12
+	B    callbackasm1(SB)
+	MOVD $1489, R12
+	B    callbackasm1(SB)
+	MOVD $1490, R12
+	B    callbackasm1(SB)
+	MOVD $1491, R12
+	B    callbackasm1(SB)
+	MOVD $1492, R12
+	B    callbackasm1(SB)
+	MOVD $1493, R12
+	B    callbackasm1(SB)
+	MOVD $1494, R12
+	B    callbackasm1(SB)
+	MOVD $1495, R12
+	B    callbackasm1(SB)
+	MOVD $1496, R12
+	B    callbackasm1(SB)
+	MOVD $1497, R12
+	B    callbackasm1(SB)
+	MOVD $1498, R12
+	B    callbackasm1(SB)
+	MOVD $1499, R12
+	B    callbackasm1(SB)
+	MOVD $1500, R12
+	B    callbackasm1(SB)
+	MOVD $1501, R12
+	B    callbackasm1(SB)
+	MOVD $1502, R12
+	B    callbackasm1(SB)
+	MOVD $1503, R12
+	B    callbackasm1(SB)
+	MOVD $1504, R12
+	B    callbackasm1(SB)
+	MOVD $1505, R12
+	B    callbackasm1(SB)
+	MOVD $1506, R12
+	B    callbackasm1(SB)
+	MOVD $1507, R12
+	B    callbackasm1(SB)
+	MOVD $1508, R12
+	B    callbackasm1(SB)
+	MOVD $1509, R12
+	B    callbackasm1(SB)
+	MOVD $1510, R12
+	B    callbackasm1(SB)
+	MOVD $1511, R12
+	B    callbackasm1(SB)
+	MOVD $1512, R12
+	B    callbackasm1(SB)
+	MOVD $1513, R12
+	B    callbackasm1(SB)
+	MOVD $1514, R12
+	B    callbackasm1(SB)
+	MOVD $1515, R12
+	B    callbackasm1(SB)
+	MOVD $1516, R12
+	B    callbackasm1(SB)
+	MOVD $1517, R12
+	B    callbackasm1(SB)
+	MOVD $1518, R12
+	B    callbackasm1(SB)
+	MOVD $1519, R12
+	B    callbackasm1(SB)
+	MOVD $1520, R12
+	B    callbackasm1(SB)
+	MOVD $1521, R12
+	B    callbackasm1(SB)
+	MOVD $1522, R12
+	B    callbackasm1(SB)
+	MOVD $1523, R12
+	B    callbackasm1(SB)
+	MOVD $1524, R12
+	B    callbackasm1(SB)
+	MOVD $1525, R12
+	B    callbackasm1(SB)
+	MOVD $1526, R12
+	B    callbackasm1(SB)
+	MOVD $1527, R12
+	B    callbackasm1(SB)
+	MOVD $1528, R12
+	B    callbackasm1(SB)
+	MOVD $1529, R12
+	B    callbackasm1(SB)
+	MOVD $1530, R12
+	B    callbackasm1(SB)
+	MOVD $1531, R12
+	B    callbackasm1(SB)
+	MOVD $1532, R12
+	B    callbackasm1(SB)
+	MOVD $1533, R12
+	B    callbackasm1(SB)
+	MOVD $1534, R12
+	B    callbackasm1(SB)
+	MOVD $1535, R12
+	B    callbackasm1(SB)
+	MOVD $1536, R12
+	B    callbackasm1(SB)
+	MOVD $1537, R12
+	B    callbackasm1(SB)
+	MOVD $1538, R12
+	B    callbackasm1(SB)
+	MOVD $1539, R12
+	B    callbackasm1(SB)
+	MOVD $1540, R12
+	B    callbackasm1(SB)
+	MOVD $1541, R12
+	B    callbackasm1(SB)
+	MOVD $1542, R12
+	B    callbackasm1(SB)
+	MOVD $1543, R12
+	B    callbackasm1(SB)
+	MOVD $1544, R12
+	B    callbackasm1(SB)
+	MOVD $1545, R12
+	B    callbackasm1(SB)
+	MOVD $1546, R12
+	B    callbackasm1(SB)
+	MOVD $1547, R12
+	B    callbackasm1(SB)
+	MOVD $1548, R12
+	B    callbackasm1(SB)
+	MOVD $1549, R12
+	B    callbackasm1(SB)
+	MOVD $1550, R12
+	B    callbackasm1(SB)
+	MOVD $1551, R12
+	B    callbackasm1(SB)
+	MOVD $1552, R12
+	B    callbackasm1(SB)
+	MOVD $1553, R12
+	B    callbackasm1(SB)
+	MOVD $1554, R12
+	B    callbackasm1(SB)
+	MOVD $1555, R12
+	B    callbackasm1(SB)
+	MOVD $1556, R12
+	B    callbackasm1(SB)
+	MOVD $1557, R12
+	B    callbackasm1(SB)
+	MOVD $1558, R12
+	B    callbackasm1(SB)
+	MOVD $1559, R12
+	B    callbackasm1(SB)
+	MOVD $1560, R12
+	B    callbackasm1(SB)
+	MOVD $1561, R12
+	B    callbackasm1(SB)
+	MOVD $1562, R12
+	B    callbackasm1(SB)
+	MOVD $1563, R12
+	B    callbackasm1(SB)
+	MOVD $1564, R12
+	B    callbackasm1(SB)
+	MOVD $1565, R12
+	B    callbackasm1(SB)
+	MOVD $1566, R12
+	B    callbackasm1(SB)
+	MOVD $1567, R12
+	B    callbackasm1(SB)
+	MOVD $1568, R12
+	B    callbackasm1(SB)
+	MOVD $1569, R12
+	B    callbackasm1(SB)
+	MOVD $1570, R12
+	B    callbackasm1(SB)
+	MOVD $1571, R12
+	B    callbackasm1(SB)
+	MOVD $1572, R12
+	B    callbackasm1(SB)
+	MOVD $1573, R12
+	B    callbackasm1(SB)
+	MOVD $1574, R12
+	B    callbackasm1(SB)
+	MOVD $1575, R12
+	B    callbackasm1(SB)
+	MOVD $1576, R12
+	B    callbackasm1(SB)
+	MOVD $1577, R12
+	B    callbackasm1(SB)
+	MOVD $1578, R12
+	B    callbackasm1(SB)
+	MOVD $1579, R12
+	B    callbackasm1(SB)
+	MOVD $1580, R12
+	B    callbackasm1(SB)
+	MOVD $1581, R12
+	B    callbackasm1(SB)
+	MOVD $1582, R12
+	B    callbackasm1(SB)
+	MOVD $1583, R12
+	B    callbackasm1(SB)
+	MOVD $1584, R12
+	B    callbackasm1(SB)
+	MOVD $1585, R12
+	B    callbackasm1(SB)
+	MOVD $1586, R12
+	B    callbackasm1(SB)
+	MOVD $1587, R12
+	B    callbackasm1(SB)
+	MOVD $1588, R12
+	B    callbackasm1(SB)
+	MOVD $1589, R12
+	B    callbackasm1(SB)
+	MOVD $1590, R12
+	B    callbackasm1(SB)
+	MOVD $1591, R12
+	B    callbackasm1(SB)
+	MOVD $1592, R12
+	B    callbackasm1(SB)
+	MOVD $1593, R12
+	B    callbackasm1(SB)
+	MOVD $1594, R12
+	B    callbackasm1(SB)
+	MOVD $1595, R12
+	B    callbackasm1(SB)
+	MOVD $1596, R12
+	B    callbackasm1(SB)
+	MOVD $1597, R12
+	B    callbackasm1(SB)
+	MOVD $1598, R12
+	B    callbackasm1(SB)
+	MOVD $1599, R12
+	B    callbackasm1(SB)
+	MOVD $1600, R12
+	B    callbackasm1(SB)
+	MOVD $1601, R12
+	B    callbackasm1(SB)
+	MOVD $1602, R12
+	B    callbackasm1(SB)
+	MOVD $1603, R12
+	B    callbackasm1(SB)
+	MOVD $1604, R12
+	B    callbackasm1(SB)
+	MOVD $1605, R12
+	B    callbackasm1(SB)
+	MOVD $1606, R12
+	B    callbackasm1(SB)
+	MOVD $1607, R12
+	B    callbackasm1(SB)
+	MOVD $1608, R12
+	B    callbackasm1(SB)
+	MOVD $1609, R12
+	B    callbackasm1(SB)
+	MOVD $1610, R12
+	B    callbackasm1(SB)
+	MOVD $1611, R12
+	B    callbackasm1(SB)
+	MOVD $1612, R12
+	B    callbackasm1(SB)
+	MOVD $1613, R12
+	B    callbackasm1(SB)
+	MOVD $1614, R12
+	B    callbackasm1(SB)
+	MOVD $1615, R12
+	B    callbackasm1(SB)
+	MOVD $1616, R12
+	B    callbackasm1(SB)
+	MOVD $1617, R12
+	B    callbackasm1(SB)
+	MOVD $1618, R12
+	B    callbackasm1(SB)
+	MOVD $1619, R12
+	B    callbackasm1(SB)
+	MOVD $1620, R12
+	B    callbackasm1(SB)
+	MOVD $1621, R12
+	B    callbackasm1(SB)
+	MOVD $1622, R12
+	B    callbackasm1(SB)
+	MOVD $1623, R12
+	B    callbackasm1(SB)
+	MOVD $1624, R12
+	B    callbackasm1(SB)
+	MOVD $1625, R12
+	B    callbackasm1(SB)
+	MOVD $1626, R12
+	B    callbackasm1(SB)
+	MOVD $1627, R12
+	B    callbackasm1(SB)
+	MOVD $1628, R12
+	B    callbackasm1(SB)
+	MOVD $1629, R12
+	B    callbackasm1(SB)
+	MOVD $1630, R12
+	B    callbackasm1(SB)
+	MOVD $1631, R12
+	B    callbackasm1(SB)
+	MOVD $1632, R12
+	B    callbackasm1(SB)
+	MOVD $1633, R12
+	B    callbackasm1(SB)
+	MOVD $1634, R12
+	B    callbackasm1(SB)
+	MOVD $1635, R12
+	B    callbackasm1(SB)
+	MOVD $1636, R12
+	B    callbackasm1(SB)
+	MOVD $1637, R12
+	B    callbackasm1(SB)
+	MOVD $1638, R12
+	B    callbackasm1(SB)
+	MOVD $1639, R12
+	B    callbackasm1(SB)
+	MOVD $1640, R12
+	B    callbackasm1(SB)
+	MOVD $1641, R12
+	B    callbackasm1(SB)
+	MOVD $1642, R12
+	B    callbackasm1(SB)
+	MOVD $1643, R12
+	B    callbackasm1(SB)
+	MOVD $1644, R12
+	B    callbackasm1(SB)
+	MOVD $1645, R12
+	B    callbackasm1(SB)
+	MOVD $1646, R12
+	B    callbackasm1(SB)
+	MOVD $1647, R12
+	B    callbackasm1(SB)
+	MOVD $1648, R12
+	B    callbackasm1(SB)
+	MOVD $1649, R12
+	B    callbackasm1(SB)
+	MOVD $1650, R12
+	B    callbackasm1(SB)
+	MOVD $1651, R12
+	B    callbackasm1(SB)
+	MOVD $1652, R12
+	B    callbackasm1(SB)
+	MOVD $1653, R12
+	B    callbackasm1(SB)
+	MOVD $1654, R12
+	B    callbackasm1(SB)
+	MOVD $1655, R12
+	B    callbackasm1(SB)
+	MOVD $1656, R12
+	B    callbackasm1(SB)
+	MOVD $1657, R12
+	B    callbackasm1(SB)
+	MOVD $1658, R12
+	B    callbackasm1(SB)
+	MOVD $1659, R12
+	B    callbackasm1(SB)
+	MOVD $1660, R12
+	B    callbackasm1(SB)
+	MOVD $1661, R12
+	B    callbackasm1(SB)
+	MOVD $1662, R12
+	B    callbackasm1(SB)
+	MOVD $1663, R12
+	B    callbackasm1(SB)
+	MOVD $1664, R12
+	B    callbackasm1(SB)
+	MOVD $1665, R12
+	B    callbackasm1(SB)
+	MOVD $1666, R12
+	B    callbackasm1(SB)
+	MOVD $1667, R12
+	B    callbackasm1(SB)
+	MOVD $1668, R12
+	B    callbackasm1(SB)
+	MOVD $1669, R12
+	B    callbackasm1(SB)
+	MOVD $1670, R12
+	B    callbackasm1(SB)
+	MOVD $1671, R12
+	B    callbackasm1(SB)
+	MOVD $1672, R12
+	B    callbackasm1(SB)
+	MOVD $1673, R12
+	B    callbackasm1(SB)
+	MOVD $1674, R12
+	B    callbackasm1(SB)
+	MOVD $1675, R12
+	B    callbackasm1(SB)
+	MOVD $1676, R12
+	B    callbackasm1(SB)
+	MOVD $1677, R12
+	B    callbackasm1(SB)
+	MOVD $1678, R12
+	B    callbackasm1(SB)
+	MOVD $1679, R12
+	B    callbackasm1(SB)
+	MOVD $1680, R12
+	B    callbackasm1(SB)
+	MOVD $1681, R12
+	B    callbackasm1(SB)
+	MOVD $1682, R12
+	B    callbackasm1(SB)
+	MOVD $1683, R12
+	B    callbackasm1(SB)
+	MOVD $1684, R12
+	B    callbackasm1(SB)
+	MOVD $1685, R12
+	B    callbackasm1(SB)
+	MOVD $1686, R12
+	B    callbackasm1(SB)
+	MOVD $1687, R12
+	B    callbackasm1(SB)
+	MOVD $1688, R12
+	B    callbackasm1(SB)
+	MOVD $1689, R12
+	B    callbackasm1(SB)
+	MOVD $1690, R12
+	B    callbackasm1(SB)
+	MOVD $1691, R12
+	B    callbackasm1(SB)
+	MOVD $1692, R12
+	B    callbackasm1(SB)
+	MOVD $1693, R12
+	B    callbackasm1(SB)
+	MOVD $1694, R12
+	B    callbackasm1(SB)
+	MOVD $1695, R12
+	B    callbackasm1(SB)
+	MOVD $1696, R12
+	B    callbackasm1(SB)
+	MOVD $1697, R12
+	B    callbackasm1(SB)
+	MOVD $1698, R12
+	B    callbackasm1(SB)
+	MOVD $1699, R12
+	B    callbackasm1(SB)
+	MOVD $1700, R12
+	B    callbackasm1(SB)
+	MOVD $1701, R12
+	B    callbackasm1(SB)
+	MOVD $1702, R12
+	B    callbackasm1(SB)
+	MOVD $1703, R12
+	B    callbackasm1(SB)
+	MOVD $1704, R12
+	B    callbackasm1(SB)
+	MOVD $1705, R12
+	B    callbackasm1(SB)
+	MOVD $1706, R12
+	B    callbackasm1(SB)
+	MOVD $1707, R12
+	B    callbackasm1(SB)
+	MOVD $1708, R12
+	B    callbackasm1(SB)
+	MOVD $1709, R12
+	B    callbackasm1(SB)
+	MOVD $1710, R12
+	B    callbackasm1(SB)
+	MOVD $1711, R12
+	B    callbackasm1(SB)
+	MOVD $1712, R12
+	B    callbackasm1(SB)
+	MOVD $1713, R12
+	B    callbackasm1(SB)
+	MOVD $1714, R12
+	B    callbackasm1(SB)
+	MOVD $1715, R12
+	B    callbackasm1(SB)
+	MOVD $1716, R12
+	B    callbackasm1(SB)
+	MOVD $1717, R12
+	B    callbackasm1(SB)
+	MOVD $1718, R12
+	B    callbackasm1(SB)
+	MOVD $1719, R12
+	B    callbackasm1(SB)
+	MOVD $1720, R12
+	B    callbackasm1(SB)
+	MOVD $1721, R12
+	B    callbackasm1(SB)
+	MOVD $1722, R12
+	B    callbackasm1(SB)
+	MOVD $1723, R12
+	B    callbackasm1(SB)
+	MOVD $1724, R12
+	B    callbackasm1(SB)
+	MOVD $1725, R12
+	B    callbackasm1(SB)
+	MOVD $1726, R12
+	B    callbackasm1(SB)
+	MOVD $1727, R12
+	B    callbackasm1(SB)
+	MOVD $1728, R12
+	B    callbackasm1(SB)
+	MOVD $1729, R12
+	B    callbackasm1(SB)
+	MOVD $1730, R12
+	B    callbackasm1(SB)
+	MOVD $1731, R12
+	B    callbackasm1(SB)
+	MOVD $1732, R12
+	B    callbackasm1(SB)
+	MOVD $1733, R12
+	B    callbackasm1(SB)
+	MOVD $1734, R12
+	B    callbackasm1(SB)
+	MOVD $1735, R12
+	B    callbackasm1(SB)
+	MOVD $1736, R12
+	B    callbackasm1(SB)
+	MOVD $1737, R12
+	B    callbackasm1(SB)
+	MOVD $1738, R12
+	B    callbackasm1(SB)
+	MOVD $1739, R12
+	B    callbackasm1(SB)
+	MOVD $1740, R12
+	B    callbackasm1(SB)
+	MOVD $1741, R12
+	B    callbackasm1(SB)
+	MOVD $1742, R12
+	B    callbackasm1(SB)
+	MOVD $1743, R12
+	B    callbackasm1(SB)
+	MOVD $1744, R12
+	B    callbackasm1(SB)
+	MOVD $1745, R12
+	B    callbackasm1(SB)
+	MOVD $1746, R12
+	B    callbackasm1(SB)
+	MOVD $1747, R12
+	B    callbackasm1(SB)
+	MOVD $1748, R12
+	B    callbackasm1(SB)
+	MOVD $1749, R12
+	B    callbackasm1(SB)
+	MOVD $1750, R12
+	B    callbackasm1(SB)
+	MOVD $1751, R12
+	B    callbackasm1(SB)
+	MOVD $1752, R12
+	B    callbackasm1(SB)
+	MOVD $1753, R12
+	B    callbackasm1(SB)
+	MOVD $1754, R12
+	B    callbackasm1(SB)
+	MOVD $1755, R12
+	B    callbackasm1(SB)
+	MOVD $1756, R12
+	B    callbackasm1(SB)
+	MOVD $1757, R12
+	B    callbackasm1(SB)
+	MOVD $1758, R12
+	B    callbackasm1(SB)
+	MOVD $1759, R12
+	B    callbackasm1(SB)
+	MOVD $1760, R12
+	B    callbackasm1(SB)
+	MOVD $1761, R12
+	B    callbackasm1(SB)
+	MOVD $1762, R12
+	B    callbackasm1(SB)
+	MOVD $1763, R12
+	B    callbackasm1(SB)
+	MOVD $1764, R12
+	B    callbackasm1(SB)
+	MOVD $1765, R12
+	B    callbackasm1(SB)
+	MOVD $1766, R12
+	B    callbackasm1(SB)
+	MOVD $1767, R12
+	B    callbackasm1(SB)
+	MOVD $1768, R12
+	B    callbackasm1(SB)
+	MOVD $1769, R12
+	B    callbackasm1(SB)
+	MOVD $1770, R12
+	B    callbackasm1(SB)
+	MOVD $1771, R12
+	B    callbackasm1(SB)
+	MOVD $1772, R12
+	B    callbackasm1(SB)
+	MOVD $1773, R12
+	B    callbackasm1(SB)
+	MOVD $1774, R12
+	B    callbackasm1(SB)
+	MOVD $1775, R12
+	B    callbackasm1(SB)
+	MOVD $1776, R12
+	B    callbackasm1(SB)
+	MOVD $1777, R12
+	B    callbackasm1(SB)
+	MOVD $1778, R12
+	B    callbackasm1(SB)
+	MOVD $1779, R12
+	B    callbackasm1(SB)
+	MOVD $1780, R12
+	B    callbackasm1(SB)
+	MOVD $1781, R12
+	B    callbackasm1(SB)
+	MOVD $1782, R12
+	B    callbackasm1(SB)
+	MOVD $1783, R12
+	B    callbackasm1(SB)
+	MOVD $1784, R12
+	B    callbackasm1(SB)
+	MOVD $1785, R12
+	B    callbackasm1(SB)
+	MOVD $1786, R12
+	B    callbackasm1(SB)
+	MOVD $1787, R12
+	B    callbackasm1(SB)
+	MOVD $1788, R12
+	B    callbackasm1(SB)
+	MOVD $1789, R12
+	B    callbackasm1(SB)
+	MOVD $1790, R12
+	B    callbackasm1(SB)
+	MOVD $1791, R12
+	B    callbackasm1(SB)
+	MOVD $1792, R12
+	B    callbackasm1(SB)
+	MOVD $1793, R12
+	B    callbackasm1(SB)
+	MOVD $1794, R12
+	B    callbackasm1(SB)
+	MOVD $1795, R12
+	B    callbackasm1(SB)
+	MOVD $1796, R12
+	B    callbackasm1(SB)
+	MOVD $1797, R12
+	B    callbackasm1(SB)
+	MOVD $1798, R12
+	B    callbackasm1(SB)
+	MOVD $1799, R12
+	B    callbackasm1(SB)
+	MOVD $1800, R12
+	B    callbackasm1(SB)
+	MOVD $1801, R12
+	B    callbackasm1(SB)
+	MOVD $1802, R12
+	B    callbackasm1(SB)
+	MOVD $1803, R12
+	B    callbackasm1(SB)
+	MOVD $1804, R12
+	B    callbackasm1(SB)
+	MOVD $1805, R12
+	B    callbackasm1(SB)
+	MOVD $1806, R12
+	B    callbackasm1(SB)
+	MOVD $1807, R12
+	B    callbackasm1(SB)
+	MOVD $1808, R12
+	B    callbackasm1(SB)
+	MOVD $1809, R12
+	B    callbackasm1(SB)
+	MOVD $1810, R12
+	B    callbackasm1(SB)
+	MOVD $1811, R12
+	B    callbackasm1(SB)
+	MOVD $1812, R12
+	B    callbackasm1(SB)
+	MOVD $1813, R12
+	B    callbackasm1(SB)
+	MOVD $1814, R12
+	B    callbackasm1(SB)
+	MOVD $1815, R12
+	B    callbackasm1(SB)
+	MOVD $1816, R12
+	B    callbackasm1(SB)
+	MOVD $1817, R12
+	B    callbackasm1(SB)
+	MOVD $1818, R12
+	B    callbackasm1(SB)
+	MOVD $1819, R12
+	B    callbackasm1(SB)
+	MOVD $1820, R12
+	B    callbackasm1(SB)
+	MOVD $1821, R12
+	B    callbackasm1(SB)
+	MOVD $1822, R12
+	B    callbackasm1(SB)
+	MOVD $1823, R12
+	B    callbackasm1(SB)
+	MOVD $1824, R12
+	B    callbackasm1(SB)
+	MOVD $1825, R12
+	B    callbackasm1(SB)
+	MOVD $1826, R12
+	B    callbackasm1(SB)
+	MOVD $1827, R12
+	B    callbackasm1(SB)
+	MOVD $1828, R12
+	B    callbackasm1(SB)
+	MOVD $1829, R12
+	B    callbackasm1(SB)
+	MOVD $1830, R12
+	B    callbackasm1(SB)
+	MOVD $1831, R12
+	B    callbackasm1(SB)
+	MOVD $1832, R12
+	B    callbackasm1(SB)
+	MOVD $1833, R12
+	B    callbackasm1(SB)
+	MOVD $1834, R12
+	B    callbackasm1(SB)
+	MOVD $1835, R12
+	B    callbackasm1(SB)
+	MOVD $1836, R12
+	B    callbackasm1(SB)
+	MOVD $1837, R12
+	B    callbackasm1(SB)
+	MOVD $1838, R12
+	B    callbackasm1(SB)
+	MOVD $1839, R12
+	B    callbackasm1(SB)
+	MOVD $1840, R12
+	B    callbackasm1(SB)
+	MOVD $1841, R12
+	B    callbackasm1(SB)
+	MOVD $1842, R12
+	B    callbackasm1(SB)
+	MOVD $1843, R12
+	B    callbackasm1(SB)
+	MOVD $1844, R12
+	B    callbackasm1(SB)
+	MOVD $1845, R12
+	B    callbackasm1(SB)
+	MOVD $1846, R12
+	B    callbackasm1(SB)
+	MOVD $1847, R12
+	B    callbackasm1(SB)
+	MOVD $1848, R12
+	B    callbackasm1(SB)
+	MOVD $1849, R12
+	B    callbackasm1(SB)
+	MOVD $1850, R12
+	B    callbackasm1(SB)
+	MOVD $1851, R12
+	B    callbackasm1(SB)
+	MOVD $1852, R12
+	B    callbackasm1(SB)
+	MOVD $1853, R12
+	B    callbackasm1(SB)
+	MOVD $1854, R12
+	B    callbackasm1(SB)
+	MOVD $1855, R12
+	B    callbackasm1(SB)
+	MOVD $1856, R12
+	B    callbackasm1(SB)
+	MOVD $1857, R12
+	B    callbackasm1(SB)
+	MOVD $1858, R12
+	B    callbackasm1(SB)
+	MOVD $1859, R12
+	B    callbackasm1(SB)
+	MOVD $1860, R12
+	B    callbackasm1(SB)
+	MOVD $1861, R12
+	B    callbackasm1(SB)
+	MOVD $1862, R12
+	B    callbackasm1(SB)
+	MOVD $1863, R12
+	B    callbackasm1(SB)
+	MOVD $1864, R12
+	B    callbackasm1(SB)
+	MOVD $1865, R12
+	B    callbackasm1(SB)
+	MOVD $1866, R12
+	B    callbackasm1(SB)
+	MOVD $1867, R12
+	B    callbackasm1(SB)
+	MOVD $1868, R12
+	B    callbackasm1(SB)
+	MOVD $1869, R12
+	B    callbackasm1(SB)
+	MOVD $1870, R12
+	B    callbackasm1(SB)
+	MOVD $1871, R12
+	B    callbackasm1(SB)
+	MOVD $1872, R12
+	B    callbackasm1(SB)
+	MOVD $1873, R12
+	B    callbackasm1(SB)
+	MOVD $1874, R12
+	B    callbackasm1(SB)
+	MOVD $1875, R12
+	B    callbackasm1(SB)
+	MOVD $1876, R12
+	B    callbackasm1(SB)
+	MOVD $1877, R12
+	B    callbackasm1(SB)
+	MOVD $1878, R12
+	B    callbackasm1(SB)
+	MOVD $1879, R12
+	B    callbackasm1(SB)
+	MOVD $1880, R12
+	B    callbackasm1(SB)
+	MOVD $1881, R12
+	B    callbackasm1(SB)
+	MOVD $1882, R12
+	B    callbackasm1(SB)
+	MOVD $1883, R12
+	B    callbackasm1(SB)
+	MOVD $1884, R12
+	B    callbackasm1(SB)
+	MOVD $1885, R12
+	B    callbackasm1(SB)
+	MOVD $1886, R12
+	B    callbackasm1(SB)
+	MOVD $1887, R12
+	B    callbackasm1(SB)
+	MOVD $1888, R12
+	B    callbackasm1(SB)
+	MOVD $1889, R12
+	B    callbackasm1(SB)
+	MOVD $1890, R12
+	B    callbackasm1(SB)
+	MOVD $1891, R12
+	B    callbackasm1(SB)
+	MOVD $1892, R12
+	B    callbackasm1(SB)
+	MOVD $1893, R12
+	B    callbackasm1(SB)
+	MOVD $1894, R12
+	B    callbackasm1(SB)
+	MOVD $1895, R12
+	B    callbackasm1(SB)
+	MOVD $1896, R12
+	B    callbackasm1(SB)
+	MOVD $1897, R12
+	B    callbackasm1(SB)
+	MOVD $1898, R12
+	B    callbackasm1(SB)
+	MOVD $1899, R12
+	B    callbackasm1(SB)
+	MOVD $1900, R12
+	B    callbackasm1(SB)
+	MOVD $1901, R12
+	B    callbackasm1(SB)
+	MOVD $1902, R12
+	B    callbackasm1(SB)
+	MOVD $1903, R12
+	B    callbackasm1(SB)
+	MOVD $1904, R12
+	B    callbackasm1(SB)
+	MOVD $1905, R12
+	B    callbackasm1(SB)
+	MOVD $1906, R12
+	B    callbackasm1(SB)
+	MOVD $1907, R12
+	B    callbackasm1(SB)
+	MOVD $1908, R12
+	B    callbackasm1(SB)
+	MOVD $1909, R12
+	B    callbackasm1(SB)
+	MOVD $1910, R12
+	B    callbackasm1(SB)
+	MOVD $1911, R12
+	B    callbackasm1(SB)
+	MOVD $1912, R12
+	B    callbackasm1(SB)
+	MOVD $1913, R12
+	B    callbackasm1(SB)
+	MOVD $1914, R12
+	B    callbackasm1(SB)
+	MOVD $1915, R12
+	B    callbackasm1(SB)
+	MOVD $1916, R12
+	B    callbackasm1(SB)
+	MOVD $1917, R12
+	B    callbackasm1(SB)
+	MOVD $1918, R12
+	B    callbackasm1(SB)
+	MOVD $1919, R12
+	B    callbackasm1(SB)
+	MOVD $1920, R12
+	B    callbackasm1(SB)
+	MOVD $1921, R12
+	B    callbackasm1(SB)
+	MOVD $1922, R12
+	B    callbackasm1(SB)
+	MOVD $1923, R12
+	B    callbackasm1(SB)
+	MOVD $1924, R12
+	B    callbackasm1(SB)
+	MOVD $1925, R12
+	B    callbackasm1(SB)
+	MOVD $1926, R12
+	B    callbackasm1(SB)
+	MOVD $1927, R12
+	B    callbackasm1(SB)
+	MOVD $1928, R12
+	B    callbackasm1(SB)
+	MOVD $1929, R12
+	B    callbackasm1(SB)
+	MOVD $1930, R12
+	B    callbackasm1(SB)
+	MOVD $1931, R12
+	B    callbackasm1(SB)
+	MOVD $1932, R12
+	B    callbackasm1(SB)
+	MOVD $1933, R12
+	B    callbackasm1(SB)
+	MOVD $1934, R12
+	B    callbackasm1(SB)
+	MOVD $1935, R12
+	B    callbackasm1(SB)
+	MOVD $1936, R12
+	B    callbackasm1(SB)
+	MOVD $1937, R12
+	B    callbackasm1(SB)
+	MOVD $1938, R12
+	B    callbackasm1(SB)
+	MOVD $1939, R12
+	B    callbackasm1(SB)
+	MOVD $1940, R12
+	B    callbackasm1(SB)
+	MOVD $1941, R12
+	B    callbackasm1(SB)
+	MOVD $1942, R12
+	B    callbackasm1(SB)
+	MOVD $1943, R12
+	B    callbackasm1(SB)
+	MOVD $1944, R12
+	B    callbackasm1(SB)
+	MOVD $1945, R12
+	B    callbackasm1(SB)
+	MOVD $1946, R12
+	B    callbackasm1(SB)
+	MOVD $1947, R12
+	B    callbackasm1(SB)
+	MOVD $1948, R12
+	B    callbackasm1(SB)
+	MOVD $1949, R12
+	B    callbackasm1(SB)
+	MOVD $1950, R12
+	B    callbackasm1(SB)
+	MOVD $1951, R12
+	B    callbackasm1(SB)
+	MOVD $1952, R12
+	B    callbackasm1(SB)
+	MOVD $1953, R12
+	B    callbackasm1(SB)
+	MOVD $1954, R12
+	B    callbackasm1(SB)
+	MOVD $1955, R12
+	B    callbackasm1(SB)
+	MOVD $1956, R12
+	B    callbackasm1(SB)
+	MOVD $1957, R12
+	B    callbackasm1(SB)
+	MOVD $1958, R12
+	B    callbackasm1(SB)
+	MOVD $1959, R12
+	B    callbackasm1(SB)
+	MOVD $1960, R12
+	B    callbackasm1(SB)
+	MOVD $1961, R12
+	B    callbackasm1(SB)
+	MOVD $1962, R12
+	B    callbackasm1(SB)
+	MOVD $1963, R12
+	B    callbackasm1(SB)
+	MOVD $1964, R12
+	B    callbackasm1(SB)
+	MOVD $1965, R12
+	B    callbackasm1(SB)
+	MOVD $1966, R12
+	B    callbackasm1(SB)
+	MOVD $1967, R12
+	B    callbackasm1(SB)
+	MOVD $1968, R12
+	B    callbackasm1(SB)
+	MOVD $1969, R12
+	B    callbackasm1(SB)
+	MOVD $1970, R12
+	B    callbackasm1(SB)
+	MOVD $1971, R12
+	B    callbackasm1(SB)
+	MOVD $1972, R12
+	B    callbackasm1(SB)
+	MOVD $1973, R12
+	B    callbackasm1(SB)
+	MOVD $1974, R12
+	B    callbackasm1(SB)
+	MOVD $1975, R12
+	B    callbackasm1(SB)
+	MOVD $1976, R12
+	B    callbackasm1(SB)
+	MOVD $1977, R12
+	B    callbackasm1(SB)
+	MOVD $1978, R12
+	B    callbackasm1(SB)
+	MOVD $1979, R12
+	B    callbackasm1(SB)
+	MOVD $1980, R12
+	B    callbackasm1(SB)
+	MOVD $1981, R12
+	B    callbackasm1(SB)
+	MOVD $1982, R12
+	B    callbackasm1(SB)
+	MOVD $1983, R12
+	B    callbackasm1(SB)
+	MOVD $1984, R12
+	B    callbackasm1(SB)
+	MOVD $1985, R12
+	B    callbackasm1(SB)
+	MOVD $1986, R12
+	B    callbackasm1(SB)
+	MOVD $1987, R12
+	B    callbackasm1(SB)
+	MOVD $1988, R12
+	B    callbackasm1(SB)
+	MOVD $1989, R12
+	B    callbackasm1(SB)
+	MOVD $1990, R12
+	B    callbackasm1(SB)
+	MOVD $1991, R12
+	B    callbackasm1(SB)
+	MOVD $1992, R12
+	B    callbackasm1(SB)
+	MOVD $1993, R12
+	B    callbackasm1(SB)
+	MOVD $1994, R12
+	B    callbackasm1(SB)
+	MOVD $1995, R12
+	B    callbackasm1(SB)
+	MOVD $1996, R12
+	B    callbackasm1(SB)
+	MOVD $1997, R12
+	B    callbackasm1(SB)
+	MOVD $1998, R12
+	B    callbackasm1(SB)
+	MOVD $1999, R12
+	B    callbackasm1(SB)
diff --git a/vendor/github.com/ebitengine/purego/zcallback_loong64.s b/vendor/github.com/ebitengine/purego/zcallback_loong64.s
new file mode 100644
index 000000000..c5dcd48e5
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/zcallback_loong64.s
@@ -0,0 +1,4014 @@
+// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+
+//go:build darwin || freebsd || linux || netbsd
+
+// External code calls into callbackasm at an offset corresponding
+// to the callback index. Callbackasm is a table of MOVV and JMP instructions.
+// The MOVV instruction loads R12 with the callback index, and the
+// JMP instruction branches to callbackasm1.
+// callbackasm1 takes the callback index from R12 and
+// indexes into an array that stores information about each callback.
+// It then calls the Go implementation for that callback.
+#include "textflag.h"
+
+TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
+	MOVV $0, R12
+	JMP  callbackasm1(SB)
+	MOVV $1, R12
+	JMP  callbackasm1(SB)
+	MOVV $2, R12
+	JMP  callbackasm1(SB)
+	MOVV $3, R12
+	JMP  callbackasm1(SB)
+	MOVV $4, R12
+	JMP  callbackasm1(SB)
+	MOVV $5, R12
+	JMP  callbackasm1(SB)
+	MOVV $6, R12
+	JMP  callbackasm1(SB)
+	MOVV $7, R12
+	JMP  callbackasm1(SB)
+	MOVV $8, R12
+	JMP  callbackasm1(SB)
+	MOVV $9, R12
+	JMP  callbackasm1(SB)
+	MOVV $10, R12
+	JMP  callbackasm1(SB)
+	MOVV $11, R12
+	JMP  callbackasm1(SB)
+	MOVV $12, R12
+	JMP  callbackasm1(SB)
+	MOVV $13, R12
+	JMP  callbackasm1(SB)
+	MOVV $14, R12
+	JMP  callbackasm1(SB)
+	MOVV $15, R12
+	JMP  callbackasm1(SB)
+	MOVV $16, R12
+	JMP  callbackasm1(SB)
+	MOVV $17, R12
+	JMP  callbackasm1(SB)
+	MOVV $18, R12
+	JMP  callbackasm1(SB)
+	MOVV $19, R12
+	JMP  callbackasm1(SB)
+	MOVV $20, R12
+	JMP  callbackasm1(SB)
+	MOVV $21, R12
+	JMP  callbackasm1(SB)
+	MOVV $22, R12
+	JMP  callbackasm1(SB)
+	MOVV $23, R12
+	JMP  callbackasm1(SB)
+	MOVV $24, R12
+	JMP  callbackasm1(SB)
+	MOVV $25, R12
+	JMP  callbackasm1(SB)
+	MOVV $26, R12
+	JMP  callbackasm1(SB)
+	MOVV $27, R12
+	JMP  callbackasm1(SB)
+	MOVV $28, R12
+	JMP  callbackasm1(SB)
+	MOVV $29, R12
+	JMP  callbackasm1(SB)
+	MOVV $30, R12
+	JMP  callbackasm1(SB)
+	MOVV $31, R12
+	JMP  callbackasm1(SB)
+	MOVV $32, R12
+	JMP  callbackasm1(SB)
+	MOVV $33, R12
+	JMP  callbackasm1(SB)
+	MOVV $34, R12
+	JMP  callbackasm1(SB)
+	MOVV $35, R12
+	JMP  callbackasm1(SB)
+	MOVV $36, R12
+	JMP  callbackasm1(SB)
+	MOVV $37, R12
+	JMP  callbackasm1(SB)
+	MOVV $38, R12
+	JMP  callbackasm1(SB)
+	MOVV $39, R12
+	JMP  callbackasm1(SB)
+	MOVV $40, R12
+	JMP  callbackasm1(SB)
+	MOVV $41, R12
+	JMP  callbackasm1(SB)
+	MOVV $42, R12
+	JMP  callbackasm1(SB)
+	MOVV $43, R12
+	JMP  callbackasm1(SB)
+	MOVV $44, R12
+	JMP  callbackasm1(SB)
+	MOVV $45, R12
+	JMP  callbackasm1(SB)
+	MOVV $46, R12
+	JMP  callbackasm1(SB)
+	MOVV $47, R12
+	JMP  callbackasm1(SB)
+	MOVV $48, R12
+	JMP  callbackasm1(SB)
+	MOVV $49, R12
+	JMP  callbackasm1(SB)
+	MOVV $50, R12
+	JMP  callbackasm1(SB)
+	MOVV $51, R12
+	JMP  callbackasm1(SB)
+	MOVV $52, R12
+	JMP  callbackasm1(SB)
+	MOVV $53, R12
+	JMP  callbackasm1(SB)
+	MOVV $54, R12
+	JMP  callbackasm1(SB)
+	MOVV $55, R12
+	JMP  callbackasm1(SB)
+	MOVV $56, R12
+	JMP  callbackasm1(SB)
+	MOVV $57, R12
+	JMP  callbackasm1(SB)
+	MOVV $58, R12
+	JMP  callbackasm1(SB)
+	MOVV $59, R12
+	JMP  callbackasm1(SB)
+	MOVV $60, R12
+	JMP  callbackasm1(SB)
+	MOVV $61, R12
+	JMP  callbackasm1(SB)
+	MOVV $62, R12
+	JMP  callbackasm1(SB)
+	MOVV $63, R12
+	JMP  callbackasm1(SB)
+	MOVV $64, R12
+	JMP  callbackasm1(SB)
+	MOVV $65, R12
+	JMP  callbackasm1(SB)
+	MOVV $66, R12
+	JMP  callbackasm1(SB)
+	MOVV $67, R12
+	JMP  callbackasm1(SB)
+	MOVV $68, R12
+	JMP  callbackasm1(SB)
+	MOVV $69, R12
+	JMP  callbackasm1(SB)
+	MOVV $70, R12
+	JMP  callbackasm1(SB)
+	MOVV $71, R12
+	JMP  callbackasm1(SB)
+	MOVV $72, R12
+	JMP  callbackasm1(SB)
+	MOVV $73, R12
+	JMP  callbackasm1(SB)
+	MOVV $74, R12
+	JMP  callbackasm1(SB)
+	MOVV $75, R12
+	JMP  callbackasm1(SB)
+	MOVV $76, R12
+	JMP  callbackasm1(SB)
+	MOVV $77, R12
+	JMP  callbackasm1(SB)
+	MOVV $78, R12
+	JMP  callbackasm1(SB)
+	MOVV $79, R12
+	JMP  callbackasm1(SB)
+	MOVV $80, R12
+	JMP  callbackasm1(SB)
+	MOVV $81, R12
+	JMP  callbackasm1(SB)
+	MOVV $82, R12
+	JMP  callbackasm1(SB)
+	MOVV $83, R12
+	JMP  callbackasm1(SB)
+	MOVV $84, R12
+	JMP  callbackasm1(SB)
+	MOVV $85, R12
+	JMP  callbackasm1(SB)
+	MOVV $86, R12
+	JMP  callbackasm1(SB)
+	MOVV $87, R12
+	JMP  callbackasm1(SB)
+	MOVV $88, R12
+	JMP  callbackasm1(SB)
+	MOVV $89, R12
+	JMP  callbackasm1(SB)
+	MOVV $90, R12
+	JMP  callbackasm1(SB)
+	MOVV $91, R12
+	JMP  callbackasm1(SB)
+	MOVV $92, R12
+	JMP  callbackasm1(SB)
+	MOVV $93, R12
+	JMP  callbackasm1(SB)
+	MOVV $94, R12
+	JMP  callbackasm1(SB)
+	MOVV $95, R12
+	JMP  callbackasm1(SB)
+	MOVV $96, R12
+	JMP  callbackasm1(SB)
+	MOVV $97, R12
+	JMP  callbackasm1(SB)
+	MOVV $98, R12
+	JMP  callbackasm1(SB)
+	MOVV $99, R12
+	JMP  callbackasm1(SB)
+	MOVV $100, R12
+	JMP  callbackasm1(SB)
+	MOVV $101, R12
+	JMP  callbackasm1(SB)
+	MOVV $102, R12
+	JMP  callbackasm1(SB)
+	MOVV $103, R12
+	JMP  callbackasm1(SB)
+	MOVV $104, R12
+	JMP  callbackasm1(SB)
+	MOVV $105, R12
+	JMP  callbackasm1(SB)
+	MOVV $106, R12
+	JMP  callbackasm1(SB)
+	MOVV $107, R12
+	JMP  callbackasm1(SB)
+	MOVV $108, R12
+	JMP  callbackasm1(SB)
+	MOVV $109, R12
+	JMP  callbackasm1(SB)
+	MOVV $110, R12
+	JMP  callbackasm1(SB)
+	MOVV $111, R12
+	JMP  callbackasm1(SB)
+	MOVV $112, R12
+	JMP  callbackasm1(SB)
+	MOVV $113, R12
+	JMP  callbackasm1(SB)
+	MOVV $114, R12
+	JMP  callbackasm1(SB)
+	MOVV $115, R12
+	JMP  callbackasm1(SB)
+	MOVV $116, R12
+	JMP  callbackasm1(SB)
+	MOVV $117, R12
+	JMP  callbackasm1(SB)
+	MOVV $118, R12
+	JMP  callbackasm1(SB)
+	MOVV $119, R12
+	JMP  callbackasm1(SB)
+	MOVV $120, R12
+	JMP  callbackasm1(SB)
+	MOVV $121, R12
+	JMP  callbackasm1(SB)
+	MOVV $122, R12
+	JMP  callbackasm1(SB)
+	MOVV $123, R12
+	JMP  callbackasm1(SB)
+	MOVV $124, R12
+	JMP  callbackasm1(SB)
+	MOVV $125, R12
+	JMP  callbackasm1(SB)
+	MOVV $126, R12
+	JMP  callbackasm1(SB)
+	MOVV $127, R12
+	JMP  callbackasm1(SB)
+	MOVV $128, R12
+	JMP  callbackasm1(SB)
+	MOVV $129, R12
+	JMP  callbackasm1(SB)
+	MOVV $130, R12
+	JMP  callbackasm1(SB)
+	MOVV $131, R12
+	JMP  callbackasm1(SB)
+	MOVV $132, R12
+	JMP  callbackasm1(SB)
+	MOVV $133, R12
+	JMP  callbackasm1(SB)
+	MOVV $134, R12
+	JMP  callbackasm1(SB)
+	MOVV $135, R12
+	JMP  callbackasm1(SB)
+	MOVV $136, R12
+	JMP  callbackasm1(SB)
+	MOVV $137, R12
+	JMP  callbackasm1(SB)
+	MOVV $138, R12
+	JMP  callbackasm1(SB)
+	MOVV $139, R12
+	JMP  callbackasm1(SB)
+	MOVV $140, R12
+	JMP  callbackasm1(SB)
+	MOVV $141, R12
+	JMP  callbackasm1(SB)
+	MOVV $142, R12
+	JMP  callbackasm1(SB)
+	MOVV $143, R12
+	JMP  callbackasm1(SB)
+	MOVV $144, R12
+	JMP  callbackasm1(SB)
+	MOVV $145, R12
+	JMP  callbackasm1(SB)
+	MOVV $146, R12
+	JMP  callbackasm1(SB)
+	MOVV $147, R12
+	JMP  callbackasm1(SB)
+	MOVV $148, R12
+	JMP  callbackasm1(SB)
+	MOVV $149, R12
+	JMP  callbackasm1(SB)
+	MOVV $150, R12
+	JMP  callbackasm1(SB)
+	MOVV $151, R12
+	JMP  callbackasm1(SB)
+	MOVV $152, R12
+	JMP  callbackasm1(SB)
+	MOVV $153, R12
+	JMP  callbackasm1(SB)
+	MOVV $154, R12
+	JMP  callbackasm1(SB)
+	MOVV $155, R12
+	JMP  callbackasm1(SB)
+	MOVV $156, R12
+	JMP  callbackasm1(SB)
+	MOVV $157, R12
+	JMP  callbackasm1(SB)
+	MOVV $158, R12
+	JMP  callbackasm1(SB)
+	MOVV $159, R12
+	JMP  callbackasm1(SB)
+	MOVV $160, R12
+	JMP  callbackasm1(SB)
+	MOVV $161, R12
+	JMP  callbackasm1(SB)
+	MOVV $162, R12
+	JMP  callbackasm1(SB)
+	MOVV $163, R12
+	JMP  callbackasm1(SB)
+	MOVV $164, R12
+	JMP  callbackasm1(SB)
+	MOVV $165, R12
+	JMP  callbackasm1(SB)
+	MOVV $166, R12
+	JMP  callbackasm1(SB)
+	MOVV $167, R12
+	JMP  callbackasm1(SB)
+	MOVV $168, R12
+	JMP  callbackasm1(SB)
+	MOVV $169, R12
+	JMP  callbackasm1(SB)
+	MOVV $170, R12
+	JMP  callbackasm1(SB)
+	MOVV $171, R12
+	JMP  callbackasm1(SB)
+	MOVV $172, R12
+	JMP  callbackasm1(SB)
+	MOVV $173, R12
+	JMP  callbackasm1(SB)
+	MOVV $174, R12
+	JMP  callbackasm1(SB)
+	MOVV $175, R12
+	JMP  callbackasm1(SB)
+	MOVV $176, R12
+	JMP  callbackasm1(SB)
+	MOVV $177, R12
+	JMP  callbackasm1(SB)
+	MOVV $178, R12
+	JMP  callbackasm1(SB)
+	MOVV $179, R12
+	JMP  callbackasm1(SB)
+	MOVV $180, R12
+	JMP  callbackasm1(SB)
+	MOVV $181, R12
+	JMP  callbackasm1(SB)
+	MOVV $182, R12
+	JMP  callbackasm1(SB)
+	MOVV $183, R12
+	JMP  callbackasm1(SB)
+	MOVV $184, R12
+	JMP  callbackasm1(SB)
+	MOVV $185, R12
+	JMP  callbackasm1(SB)
+	MOVV $186, R12
+	JMP  callbackasm1(SB)
+	MOVV $187, R12
+	JMP  callbackasm1(SB)
+	MOVV $188, R12
+	JMP  callbackasm1(SB)
+	MOVV $189, R12
+	JMP  callbackasm1(SB)
+	MOVV $190, R12
+	JMP  callbackasm1(SB)
+	MOVV $191, R12
+	JMP  callbackasm1(SB)
+	MOVV $192, R12
+	JMP  callbackasm1(SB)
+	MOVV $193, R12
+	JMP  callbackasm1(SB)
+	MOVV $194, R12
+	JMP  callbackasm1(SB)
+	MOVV $195, R12
+	JMP  callbackasm1(SB)
+	MOVV $196, R12
+	JMP  callbackasm1(SB)
+	MOVV $197, R12
+	JMP  callbackasm1(SB)
+	MOVV $198, R12
+	JMP  callbackasm1(SB)
+	MOVV $199, R12
+	JMP  callbackasm1(SB)
+	MOVV $200, R12
+	JMP  callbackasm1(SB)
+	MOVV $201, R12
+	JMP  callbackasm1(SB)
+	MOVV $202, R12
+	JMP  callbackasm1(SB)
+	MOVV $203, R12
+	JMP  callbackasm1(SB)
+	MOVV $204, R12
+	JMP  callbackasm1(SB)
+	MOVV $205, R12
+	JMP  callbackasm1(SB)
+	MOVV $206, R12
+	JMP  callbackasm1(SB)
+	MOVV $207, R12
+	JMP  callbackasm1(SB)
+	MOVV $208, R12
+	JMP  callbackasm1(SB)
+	MOVV $209, R12
+	JMP  callbackasm1(SB)
+	MOVV $210, R12
+	JMP  callbackasm1(SB)
+	MOVV $211, R12
+	JMP  callbackasm1(SB)
+	MOVV $212, R12
+	JMP  callbackasm1(SB)
+	MOVV $213, R12
+	JMP  callbackasm1(SB)
+	MOVV $214, R12
+	JMP  callbackasm1(SB)
+	MOVV $215, R12
+	JMP  callbackasm1(SB)
+	MOVV $216, R12
+	JMP  callbackasm1(SB)
+	MOVV $217, R12
+	JMP  callbackasm1(SB)
+	MOVV $218, R12
+	JMP  callbackasm1(SB)
+	MOVV $219, R12
+	JMP  callbackasm1(SB)
+	MOVV $220, R12
+	JMP  callbackasm1(SB)
+	MOVV $221, R12
+	JMP  callbackasm1(SB)
+	MOVV $222, R12
+	JMP  callbackasm1(SB)
+	MOVV $223, R12
+	JMP  callbackasm1(SB)
+	MOVV $224, R12
+	JMP  callbackasm1(SB)
+	MOVV $225, R12
+	JMP  callbackasm1(SB)
+	MOVV $226, R12
+	JMP  callbackasm1(SB)
+	MOVV $227, R12
+	JMP  callbackasm1(SB)
+	MOVV $228, R12
+	JMP  callbackasm1(SB)
+	MOVV $229, R12
+	JMP  callbackasm1(SB)
+	MOVV $230, R12
+	JMP  callbackasm1(SB)
+	MOVV $231, R12
+	JMP  callbackasm1(SB)
+	MOVV $232, R12
+	JMP  callbackasm1(SB)
+	MOVV $233, R12
+	JMP  callbackasm1(SB)
+	MOVV $234, R12
+	JMP  callbackasm1(SB)
+	MOVV $235, R12
+	JMP  callbackasm1(SB)
+	MOVV $236, R12
+	JMP  callbackasm1(SB)
+	MOVV $237, R12
+	JMP  callbackasm1(SB)
+	MOVV $238, R12
+	JMP  callbackasm1(SB)
+	MOVV $239, R12
+	JMP  callbackasm1(SB)
+	MOVV $240, R12
+	JMP  callbackasm1(SB)
+	MOVV $241, R12
+	JMP  callbackasm1(SB)
+	MOVV $242, R12
+	JMP  callbackasm1(SB)
+	MOVV $243, R12
+	JMP  callbackasm1(SB)
+	MOVV $244, R12
+	JMP  callbackasm1(SB)
+	MOVV $245, R12
+	JMP  callbackasm1(SB)
+	MOVV $246, R12
+	JMP  callbackasm1(SB)
+	MOVV $247, R12
+	JMP  callbackasm1(SB)
+	MOVV $248, R12
+	JMP  callbackasm1(SB)
+	MOVV $249, R12
+	JMP  callbackasm1(SB)
+	MOVV $250, R12
+	JMP  callbackasm1(SB)
+	MOVV $251, R12
+	JMP  callbackasm1(SB)
+	MOVV $252, R12
+	JMP  callbackasm1(SB)
+	MOVV $253, R12
+	JMP  callbackasm1(SB)
+	MOVV $254, R12
+	JMP  callbackasm1(SB)
+	MOVV $255, R12
+	JMP  callbackasm1(SB)
+	MOVV $256, R12
+	JMP  callbackasm1(SB)
+	MOVV $257, R12
+	JMP  callbackasm1(SB)
+	MOVV $258, R12
+	JMP  callbackasm1(SB)
+	MOVV $259, R12
+	JMP  callbackasm1(SB)
+	MOVV $260, R12
+	JMP  callbackasm1(SB)
+	MOVV $261, R12
+	JMP  callbackasm1(SB)
+	MOVV $262, R12
+	JMP  callbackasm1(SB)
+	MOVV $263, R12
+	JMP  callbackasm1(SB)
+	MOVV $264, R12
+	JMP  callbackasm1(SB)
+	MOVV $265, R12
+	JMP  callbackasm1(SB)
+	MOVV $266, R12
+	JMP  callbackasm1(SB)
+	MOVV $267, R12
+	JMP  callbackasm1(SB)
+	MOVV $268, R12
+	JMP  callbackasm1(SB)
+	MOVV $269, R12
+	JMP  callbackasm1(SB)
+	MOVV $270, R12
+	JMP  callbackasm1(SB)
+	MOVV $271, R12
+	JMP  callbackasm1(SB)
+	MOVV $272, R12
+	JMP  callbackasm1(SB)
+	MOVV $273, R12
+	JMP  callbackasm1(SB)
+	MOVV $274, R12
+	JMP  callbackasm1(SB)
+	MOVV $275, R12
+	JMP  callbackasm1(SB)
+	MOVV $276, R12
+	JMP  callbackasm1(SB)
+	MOVV $277, R12
+	JMP  callbackasm1(SB)
+	MOVV $278, R12
+	JMP  callbackasm1(SB)
+	MOVV $279, R12
+	JMP  callbackasm1(SB)
+	MOVV $280, R12
+	JMP  callbackasm1(SB)
+	MOVV $281, R12
+	JMP  callbackasm1(SB)
+	MOVV $282, R12
+	JMP  callbackasm1(SB)
+	MOVV $283, R12
+	JMP  callbackasm1(SB)
+	MOVV $284, R12
+	JMP  callbackasm1(SB)
+	MOVV $285, R12
+	JMP  callbackasm1(SB)
+	MOVV $286, R12
+	JMP  callbackasm1(SB)
+	MOVV $287, R12
+	JMP  callbackasm1(SB)
+	MOVV $288, R12
+	JMP  callbackasm1(SB)
+	MOVV $289, R12
+	JMP  callbackasm1(SB)
+	MOVV $290, R12
+	JMP  callbackasm1(SB)
+	MOVV $291, R12
+	JMP  callbackasm1(SB)
+	MOVV $292, R12
+	JMP  callbackasm1(SB)
+	MOVV $293, R12
+	JMP  callbackasm1(SB)
+	MOVV $294, R12
+	JMP  callbackasm1(SB)
+	MOVV $295, R12
+	JMP  callbackasm1(SB)
+	MOVV $296, R12
+	JMP  callbackasm1(SB)
+	MOVV $297, R12
+	JMP  callbackasm1(SB)
+	MOVV $298, R12
+	JMP  callbackasm1(SB)
+	MOVV $299, R12
+	JMP  callbackasm1(SB)
+	MOVV $300, R12
+	JMP  callbackasm1(SB)
+	MOVV $301, R12
+	JMP  callbackasm1(SB)
+	MOVV $302, R12
+	JMP  callbackasm1(SB)
+	MOVV $303, R12
+	JMP  callbackasm1(SB)
+	MOVV $304, R12
+	JMP  callbackasm1(SB)
+	MOVV $305, R12
+	JMP  callbackasm1(SB)
+	MOVV $306, R12
+	JMP  callbackasm1(SB)
+	MOVV $307, R12
+	JMP  callbackasm1(SB)
+	MOVV $308, R12
+	JMP  callbackasm1(SB)
+	MOVV $309, R12
+	JMP  callbackasm1(SB)
+	MOVV $310, R12
+	JMP  callbackasm1(SB)
+	MOVV $311, R12
+	JMP  callbackasm1(SB)
+	MOVV $312, R12
+	JMP  callbackasm1(SB)
+	MOVV $313, R12
+	JMP  callbackasm1(SB)
+	MOVV $314, R12
+	JMP  callbackasm1(SB)
+	MOVV $315, R12
+	JMP  callbackasm1(SB)
+	MOVV $316, R12
+	JMP  callbackasm1(SB)
+	MOVV $317, R12
+	JMP  callbackasm1(SB)
+	MOVV $318, R12
+	JMP  callbackasm1(SB)
+	MOVV $319, R12
+	JMP  callbackasm1(SB)
+	MOVV $320, R12
+	JMP  callbackasm1(SB)
+	MOVV $321, R12
+	JMP  callbackasm1(SB)
+	MOVV $322, R12
+	JMP  callbackasm1(SB)
+	MOVV $323, R12
+	JMP  callbackasm1(SB)
+	MOVV $324, R12
+	JMP  callbackasm1(SB)
+	MOVV $325, R12
+	JMP  callbackasm1(SB)
+	MOVV $326, R12
+	JMP  callbackasm1(SB)
+	MOVV $327, R12
+	JMP  callbackasm1(SB)
+	MOVV $328, R12
+	JMP  callbackasm1(SB)
+	MOVV $329, R12
+	JMP  callbackasm1(SB)
+	MOVV $330, R12
+	JMP  callbackasm1(SB)
+	MOVV $331, R12
+	JMP  callbackasm1(SB)
+	MOVV $332, R12
+	JMP  callbackasm1(SB)
+	MOVV $333, R12
+	JMP  callbackasm1(SB)
+	MOVV $334, R12
+	JMP  callbackasm1(SB)
+	MOVV $335, R12
+	JMP  callbackasm1(SB)
+	MOVV $336, R12
+	JMP  callbackasm1(SB)
+	MOVV $337, R12
+	JMP  callbackasm1(SB)
+	MOVV $338, R12
+	JMP  callbackasm1(SB)
+	MOVV $339, R12
+	JMP  callbackasm1(SB)
+	MOVV $340, R12
+	JMP  callbackasm1(SB)
+	MOVV $341, R12
+	JMP  callbackasm1(SB)
+	MOVV $342, R12
+	JMP  callbackasm1(SB)
+	MOVV $343, R12
+	JMP  callbackasm1(SB)
+	MOVV $344, R12
+	JMP  callbackasm1(SB)
+	MOVV $345, R12
+	JMP  callbackasm1(SB)
+	MOVV $346, R12
+	JMP  callbackasm1(SB)
+	MOVV $347, R12
+	JMP  callbackasm1(SB)
+	MOVV $348, R12
+	JMP  callbackasm1(SB)
+	MOVV $349, R12
+	JMP  callbackasm1(SB)
+	MOVV $350, R12
+	JMP  callbackasm1(SB)
+	MOVV $351, R12
+	JMP  callbackasm1(SB)
+	MOVV $352, R12
+	JMP  callbackasm1(SB)
+	MOVV $353, R12
+	JMP  callbackasm1(SB)
+	MOVV $354, R12
+	JMP  callbackasm1(SB)
+	MOVV $355, R12
+	JMP  callbackasm1(SB)
+	MOVV $356, R12
+	JMP  callbackasm1(SB)
+	MOVV $357, R12
+	JMP  callbackasm1(SB)
+	MOVV $358, R12
+	JMP  callbackasm1(SB)
+	MOVV $359, R12
+	JMP  callbackasm1(SB)
+	MOVV $360, R12
+	JMP  callbackasm1(SB)
+	MOVV $361, R12
+	JMP  callbackasm1(SB)
+	MOVV $362, R12
+	JMP  callbackasm1(SB)
+	MOVV $363, R12
+	JMP  callbackasm1(SB)
+	MOVV $364, R12
+	JMP  callbackasm1(SB)
+	MOVV $365, R12
+	JMP  callbackasm1(SB)
+	MOVV $366, R12
+	JMP  callbackasm1(SB)
+	MOVV $367, R12
+	JMP  callbackasm1(SB)
+	MOVV $368, R12
+	JMP  callbackasm1(SB)
+	MOVV $369, R12
+	JMP  callbackasm1(SB)
+	MOVV $370, R12
+	JMP  callbackasm1(SB)
+	MOVV $371, R12
+	JMP  callbackasm1(SB)
+	MOVV $372, R12
+	JMP  callbackasm1(SB)
+	MOVV $373, R12
+	JMP  callbackasm1(SB)
+	MOVV $374, R12
+	JMP  callbackasm1(SB)
+	MOVV $375, R12
+	JMP  callbackasm1(SB)
+	MOVV $376, R12
+	JMP  callbackasm1(SB)
+	MOVV $377, R12
+	JMP  callbackasm1(SB)
+	MOVV $378, R12
+	JMP  callbackasm1(SB)
+	MOVV $379, R12
+	JMP  callbackasm1(SB)
+	MOVV $380, R12
+	JMP  callbackasm1(SB)
+	MOVV $381, R12
+	JMP  callbackasm1(SB)
+	MOVV $382, R12
+	JMP  callbackasm1(SB)
+	MOVV $383, R12
+	JMP  callbackasm1(SB)
+	MOVV $384, R12
+	JMP  callbackasm1(SB)
+	MOVV $385, R12
+	JMP  callbackasm1(SB)
+	MOVV $386, R12
+	JMP  callbackasm1(SB)
+	MOVV $387, R12
+	JMP  callbackasm1(SB)
+	MOVV $388, R12
+	JMP  callbackasm1(SB)
+	MOVV $389, R12
+	JMP  callbackasm1(SB)
+	MOVV $390, R12
+	JMP  callbackasm1(SB)
+	MOVV $391, R12
+	JMP  callbackasm1(SB)
+	MOVV $392, R12
+	JMP  callbackasm1(SB)
+	MOVV $393, R12
+	JMP  callbackasm1(SB)
+	MOVV $394, R12
+	JMP  callbackasm1(SB)
+	MOVV $395, R12
+	JMP  callbackasm1(SB)
+	MOVV $396, R12
+	JMP  callbackasm1(SB)
+	MOVV $397, R12
+	JMP  callbackasm1(SB)
+	MOVV $398, R12
+	JMP  callbackasm1(SB)
+	MOVV $399, R12
+	JMP  callbackasm1(SB)
+	MOVV $400, R12
+	JMP  callbackasm1(SB)
+	MOVV $401, R12
+	JMP  callbackasm1(SB)
+	MOVV $402, R12
+	JMP  callbackasm1(SB)
+	MOVV $403, R12
+	JMP  callbackasm1(SB)
+	MOVV $404, R12
+	JMP  callbackasm1(SB)
+	MOVV $405, R12
+	JMP  callbackasm1(SB)
+	MOVV $406, R12
+	JMP  callbackasm1(SB)
+	MOVV $407, R12
+	JMP  callbackasm1(SB)
+	MOVV $408, R12
+	JMP  callbackasm1(SB)
+	MOVV $409, R12
+	JMP  callbackasm1(SB)
+	MOVV $410, R12
+	JMP  callbackasm1(SB)
+	MOVV $411, R12
+	JMP  callbackasm1(SB)
+	MOVV $412, R12
+	JMP  callbackasm1(SB)
+	MOVV $413, R12
+	JMP  callbackasm1(SB)
+	MOVV $414, R12
+	JMP  callbackasm1(SB)
+	MOVV $415, R12
+	JMP  callbackasm1(SB)
+	MOVV $416, R12
+	JMP  callbackasm1(SB)
+	MOVV $417, R12
+	JMP  callbackasm1(SB)
+	MOVV $418, R12
+	JMP  callbackasm1(SB)
+	MOVV $419, R12
+	JMP  callbackasm1(SB)
+	MOVV $420, R12
+	JMP  callbackasm1(SB)
+	MOVV $421, R12
+	JMP  callbackasm1(SB)
+	MOVV $422, R12
+	JMP  callbackasm1(SB)
+	MOVV $423, R12
+	JMP  callbackasm1(SB)
+	MOVV $424, R12
+	JMP  callbackasm1(SB)
+	MOVV $425, R12
+	JMP  callbackasm1(SB)
+	MOVV $426, R12
+	JMP  callbackasm1(SB)
+	MOVV $427, R12
+	JMP  callbackasm1(SB)
+	MOVV $428, R12
+	JMP  callbackasm1(SB)
+	MOVV $429, R12
+	JMP  callbackasm1(SB)
+	MOVV $430, R12
+	JMP  callbackasm1(SB)
+	MOVV $431, R12
+	JMP  callbackasm1(SB)
+	MOVV $432, R12
+	JMP  callbackasm1(SB)
+	MOVV $433, R12
+	JMP  callbackasm1(SB)
+	MOVV $434, R12
+	JMP  callbackasm1(SB)
+	MOVV $435, R12
+	JMP  callbackasm1(SB)
+	MOVV $436, R12
+	JMP  callbackasm1(SB)
+	MOVV $437, R12
+	JMP  callbackasm1(SB)
+	MOVV $438, R12
+	JMP  callbackasm1(SB)
+	MOVV $439, R12
+	JMP  callbackasm1(SB)
+	MOVV $440, R12
+	JMP  callbackasm1(SB)
+	MOVV $441, R12
+	JMP  callbackasm1(SB)
+	MOVV $442, R12
+	JMP  callbackasm1(SB)
+	MOVV $443, R12
+	JMP  callbackasm1(SB)
+	MOVV $444, R12
+	JMP  callbackasm1(SB)
+	MOVV $445, R12
+	JMP  callbackasm1(SB)
+	MOVV $446, R12
+	JMP  callbackasm1(SB)
+	MOVV $447, R12
+	JMP  callbackasm1(SB)
+	MOVV $448, R12
+	JMP  callbackasm1(SB)
+	MOVV $449, R12
+	JMP  callbackasm1(SB)
+	MOVV $450, R12
+	JMP  callbackasm1(SB)
+	MOVV $451, R12
+	JMP  callbackasm1(SB)
+	MOVV $452, R12
+	JMP  callbackasm1(SB)
+	MOVV $453, R12
+	JMP  callbackasm1(SB)
+	MOVV $454, R12
+	JMP  callbackasm1(SB)
+	MOVV $455, R12
+	JMP  callbackasm1(SB)
+	MOVV $456, R12
+	JMP  callbackasm1(SB)
+	MOVV $457, R12
+	JMP  callbackasm1(SB)
+	MOVV $458, R12
+	JMP  callbackasm1(SB)
+	MOVV $459, R12
+	JMP  callbackasm1(SB)
+	MOVV $460, R12
+	JMP  callbackasm1(SB)
+	MOVV $461, R12
+	JMP  callbackasm1(SB)
+	MOVV $462, R12
+	JMP  callbackasm1(SB)
+	MOVV $463, R12
+	JMP  callbackasm1(SB)
+	MOVV $464, R12
+	JMP  callbackasm1(SB)
+	MOVV $465, R12
+	JMP  callbackasm1(SB)
+	MOVV $466, R12
+	JMP  callbackasm1(SB)
+	MOVV $467, R12
+	JMP  callbackasm1(SB)
+	MOVV $468, R12
+	JMP  callbackasm1(SB)
+	MOVV $469, R12
+	JMP  callbackasm1(SB)
+	MOVV $470, R12
+	JMP  callbackasm1(SB)
+	MOVV $471, R12
+	JMP  callbackasm1(SB)
+	MOVV $472, R12
+	JMP  callbackasm1(SB)
+	MOVV $473, R12
+	JMP  callbackasm1(SB)
+	MOVV $474, R12
+	JMP  callbackasm1(SB)
+	MOVV $475, R12
+	JMP  callbackasm1(SB)
+	MOVV $476, R12
+	JMP  callbackasm1(SB)
+	MOVV $477, R12
+	JMP  callbackasm1(SB)
+	MOVV $478, R12
+	JMP  callbackasm1(SB)
+	MOVV $479, R12
+	JMP  callbackasm1(SB)
+	MOVV $480, R12
+	JMP  callbackasm1(SB)
+	MOVV $481, R12
+	JMP  callbackasm1(SB)
+	MOVV $482, R12
+	JMP  callbackasm1(SB)
+	MOVV $483, R12
+	JMP  callbackasm1(SB)
+	MOVV $484, R12
+	JMP  callbackasm1(SB)
+	MOVV $485, R12
+	JMP  callbackasm1(SB)
+	MOVV $486, R12
+	JMP  callbackasm1(SB)
+	MOVV $487, R12
+	JMP  callbackasm1(SB)
+	MOVV $488, R12
+	JMP  callbackasm1(SB)
+	MOVV $489, R12
+	JMP  callbackasm1(SB)
+	MOVV $490, R12
+	JMP  callbackasm1(SB)
+	MOVV $491, R12
+	JMP  callbackasm1(SB)
+	MOVV $492, R12
+	JMP  callbackasm1(SB)
+	MOVV $493, R12
+	JMP  callbackasm1(SB)
+	MOVV $494, R12
+	JMP  callbackasm1(SB)
+	MOVV $495, R12
+	JMP  callbackasm1(SB)
+	MOVV $496, R12
+	JMP  callbackasm1(SB)
+	MOVV $497, R12
+	JMP  callbackasm1(SB)
+	MOVV $498, R12
+	JMP  callbackasm1(SB)
+	MOVV $499, R12
+	JMP  callbackasm1(SB)
+	MOVV $500, R12
+	JMP  callbackasm1(SB)
+	MOVV $501, R12
+	JMP  callbackasm1(SB)
+	MOVV $502, R12
+	JMP  callbackasm1(SB)
+	MOVV $503, R12
+	JMP  callbackasm1(SB)
+	MOVV $504, R12
+	JMP  callbackasm1(SB)
+	MOVV $505, R12
+	JMP  callbackasm1(SB)
+	MOVV $506, R12
+	JMP  callbackasm1(SB)
+	MOVV $507, R12
+	JMP  callbackasm1(SB)
+	MOVV $508, R12
+	JMP  callbackasm1(SB)
+	MOVV $509, R12
+	JMP  callbackasm1(SB)
+	MOVV $510, R12
+	JMP  callbackasm1(SB)
+	MOVV $511, R12
+	JMP  callbackasm1(SB)
+	MOVV $512, R12
+	JMP  callbackasm1(SB)
+	MOVV $513, R12
+	JMP  callbackasm1(SB)
+	MOVV $514, R12
+	JMP  callbackasm1(SB)
+	MOVV $515, R12
+	JMP  callbackasm1(SB)
+	MOVV $516, R12
+	JMP  callbackasm1(SB)
+	MOVV $517, R12
+	JMP  callbackasm1(SB)
+	MOVV $518, R12
+	JMP  callbackasm1(SB)
+	MOVV $519, R12
+	JMP  callbackasm1(SB)
+	MOVV $520, R12
+	JMP  callbackasm1(SB)
+	MOVV $521, R12
+	JMP  callbackasm1(SB)
+	MOVV $522, R12
+	JMP  callbackasm1(SB)
+	MOVV $523, R12
+	JMP  callbackasm1(SB)
+	MOVV $524, R12
+	JMP  callbackasm1(SB)
+	MOVV $525, R12
+	JMP  callbackasm1(SB)
+	MOVV $526, R12
+	JMP  callbackasm1(SB)
+	MOVV $527, R12
+	JMP  callbackasm1(SB)
+	MOVV $528, R12
+	JMP  callbackasm1(SB)
+	MOVV $529, R12
+	JMP  callbackasm1(SB)
+	MOVV $530, R12
+	JMP  callbackasm1(SB)
+	MOVV $531, R12
+	JMP  callbackasm1(SB)
+	MOVV $532, R12
+	JMP  callbackasm1(SB)
+	MOVV $533, R12
+	JMP  callbackasm1(SB)
+	MOVV $534, R12
+	JMP  callbackasm1(SB)
+	MOVV $535, R12
+	JMP  callbackasm1(SB)
+	MOVV $536, R12
+	JMP  callbackasm1(SB)
+	MOVV $537, R12
+	JMP  callbackasm1(SB)
+	MOVV $538, R12
+	JMP  callbackasm1(SB)
+	MOVV $539, R12
+	JMP  callbackasm1(SB)
+	MOVV $540, R12
+	JMP  callbackasm1(SB)
+	MOVV $541, R12
+	JMP  callbackasm1(SB)
+	MOVV $542, R12
+	JMP  callbackasm1(SB)
+	MOVV $543, R12
+	JMP  callbackasm1(SB)
+	MOVV $544, R12
+	JMP  callbackasm1(SB)
+	MOVV $545, R12
+	JMP  callbackasm1(SB)
+	MOVV $546, R12
+	JMP  callbackasm1(SB)
+	MOVV $547, R12
+	JMP  callbackasm1(SB)
+	MOVV $548, R12
+	JMP  callbackasm1(SB)
+	MOVV $549, R12
+	JMP  callbackasm1(SB)
+	MOVV $550, R12
+	JMP  callbackasm1(SB)
+	MOVV $551, R12
+	JMP  callbackasm1(SB)
+	MOVV $552, R12
+	JMP  callbackasm1(SB)
+	MOVV $553, R12
+	JMP  callbackasm1(SB)
+	MOVV $554, R12
+	JMP  callbackasm1(SB)
+	MOVV $555, R12
+	JMP  callbackasm1(SB)
+	MOVV $556, R12
+	JMP  callbackasm1(SB)
+	MOVV $557, R12
+	JMP  callbackasm1(SB)
+	MOVV $558, R12
+	JMP  callbackasm1(SB)
+	MOVV $559, R12
+	JMP  callbackasm1(SB)
+	MOVV $560, R12
+	JMP  callbackasm1(SB)
+	MOVV $561, R12
+	JMP  callbackasm1(SB)
+	MOVV $562, R12
+	JMP  callbackasm1(SB)
+	MOVV $563, R12
+	JMP  callbackasm1(SB)
+	MOVV $564, R12
+	JMP  callbackasm1(SB)
+	MOVV $565, R12
+	JMP  callbackasm1(SB)
+	MOVV $566, R12
+	JMP  callbackasm1(SB)
+	MOVV $567, R12
+	JMP  callbackasm1(SB)
+	MOVV $568, R12
+	JMP  callbackasm1(SB)
+	MOVV $569, R12
+	JMP  callbackasm1(SB)
+	MOVV $570, R12
+	JMP  callbackasm1(SB)
+	MOVV $571, R12
+	JMP  callbackasm1(SB)
+	MOVV $572, R12
+	JMP  callbackasm1(SB)
+	MOVV $573, R12
+	JMP  callbackasm1(SB)
+	MOVV $574, R12
+	JMP  callbackasm1(SB)
+	MOVV $575, R12
+	JMP  callbackasm1(SB)
+	MOVV $576, R12
+	JMP  callbackasm1(SB)
+	MOVV $577, R12
+	JMP  callbackasm1(SB)
+	MOVV $578, R12
+	JMP  callbackasm1(SB)
+	MOVV $579, R12
+	JMP  callbackasm1(SB)
+	MOVV $580, R12
+	JMP  callbackasm1(SB)
+	MOVV $581, R12
+	JMP  callbackasm1(SB)
+	MOVV $582, R12
+	JMP  callbackasm1(SB)
+	MOVV $583, R12
+	JMP  callbackasm1(SB)
+	MOVV $584, R12
+	JMP  callbackasm1(SB)
+	MOVV $585, R12
+	JMP  callbackasm1(SB)
+	MOVV $586, R12
+	JMP  callbackasm1(SB)
+	MOVV $587, R12
+	JMP  callbackasm1(SB)
+	MOVV $588, R12
+	JMP  callbackasm1(SB)
+	MOVV $589, R12
+	JMP  callbackasm1(SB)
+	MOVV $590, R12
+	JMP  callbackasm1(SB)
+	MOVV $591, R12
+	JMP  callbackasm1(SB)
+	MOVV $592, R12
+	JMP  callbackasm1(SB)
+	MOVV $593, R12
+	JMP  callbackasm1(SB)
+	MOVV $594, R12
+	JMP  callbackasm1(SB)
+	MOVV $595, R12
+	JMP  callbackasm1(SB)
+	MOVV $596, R12
+	JMP  callbackasm1(SB)
+	MOVV $597, R12
+	JMP  callbackasm1(SB)
+	MOVV $598, R12
+	JMP  callbackasm1(SB)
+	MOVV $599, R12
+	JMP  callbackasm1(SB)
+	MOVV $600, R12
+	JMP  callbackasm1(SB)
+	MOVV $601, R12
+	JMP  callbackasm1(SB)
+	MOVV $602, R12
+	JMP  callbackasm1(SB)
+	MOVV $603, R12
+	JMP  callbackasm1(SB)
+	MOVV $604, R12
+	JMP  callbackasm1(SB)
+	MOVV $605, R12
+	JMP  callbackasm1(SB)
+	MOVV $606, R12
+	JMP  callbackasm1(SB)
+	MOVV $607, R12
+	JMP  callbackasm1(SB)
+	MOVV $608, R12
+	JMP  callbackasm1(SB)
+	MOVV $609, R12
+	JMP  callbackasm1(SB)
+	MOVV $610, R12
+	JMP  callbackasm1(SB)
+	MOVV $611, R12
+	JMP  callbackasm1(SB)
+	MOVV $612, R12
+	JMP  callbackasm1(SB)
+	MOVV $613, R12
+	JMP  callbackasm1(SB)
+	MOVV $614, R12
+	JMP  callbackasm1(SB)
+	MOVV $615, R12
+	JMP  callbackasm1(SB)
+	MOVV $616, R12
+	JMP  callbackasm1(SB)
+	MOVV $617, R12
+	JMP  callbackasm1(SB)
+	MOVV $618, R12
+	JMP  callbackasm1(SB)
+	MOVV $619, R12
+	JMP  callbackasm1(SB)
+	MOVV $620, R12
+	JMP  callbackasm1(SB)
+	MOVV $621, R12
+	JMP  callbackasm1(SB)
+	MOVV $622, R12
+	JMP  callbackasm1(SB)
+	MOVV $623, R12
+	JMP  callbackasm1(SB)
+	MOVV $624, R12
+	JMP  callbackasm1(SB)
+	MOVV $625, R12
+	JMP  callbackasm1(SB)
+	MOVV $626, R12
+	JMP  callbackasm1(SB)
+	MOVV $627, R12
+	JMP  callbackasm1(SB)
+	MOVV $628, R12
+	JMP  callbackasm1(SB)
+	MOVV $629, R12
+	JMP  callbackasm1(SB)
+	MOVV $630, R12
+	JMP  callbackasm1(SB)
+	MOVV $631, R12
+	JMP  callbackasm1(SB)
+	MOVV $632, R12
+	JMP  callbackasm1(SB)
+	MOVV $633, R12
+	JMP  callbackasm1(SB)
+	MOVV $634, R12
+	JMP  callbackasm1(SB)
+	MOVV $635, R12
+	JMP  callbackasm1(SB)
+	MOVV $636, R12
+	JMP  callbackasm1(SB)
+	MOVV $637, R12
+	JMP  callbackasm1(SB)
+	MOVV $638, R12
+	JMP  callbackasm1(SB)
+	MOVV $639, R12
+	JMP  callbackasm1(SB)
+	MOVV $640, R12
+	JMP  callbackasm1(SB)
+	MOVV $641, R12
+	JMP  callbackasm1(SB)
+	MOVV $642, R12
+	JMP  callbackasm1(SB)
+	MOVV $643, R12
+	JMP  callbackasm1(SB)
+	MOVV $644, R12
+	JMP  callbackasm1(SB)
+	MOVV $645, R12
+	JMP  callbackasm1(SB)
+	MOVV $646, R12
+	JMP  callbackasm1(SB)
+	MOVV $647, R12
+	JMP  callbackasm1(SB)
+	MOVV $648, R12
+	JMP  callbackasm1(SB)
+	MOVV $649, R12
+	JMP  callbackasm1(SB)
+	MOVV $650, R12
+	JMP  callbackasm1(SB)
+	MOVV $651, R12
+	JMP  callbackasm1(SB)
+	MOVV $652, R12
+	JMP  callbackasm1(SB)
+	MOVV $653, R12
+	JMP  callbackasm1(SB)
+	MOVV $654, R12
+	JMP  callbackasm1(SB)
+	MOVV $655, R12
+	JMP  callbackasm1(SB)
+	MOVV $656, R12
+	JMP  callbackasm1(SB)
+	MOVV $657, R12
+	JMP  callbackasm1(SB)
+	MOVV $658, R12
+	JMP  callbackasm1(SB)
+	MOVV $659, R12
+	JMP  callbackasm1(SB)
+	MOVV $660, R12
+	JMP  callbackasm1(SB)
+	MOVV $661, R12
+	JMP  callbackasm1(SB)
+	MOVV $662, R12
+	JMP  callbackasm1(SB)
+	MOVV $663, R12
+	JMP  callbackasm1(SB)
+	MOVV $664, R12
+	JMP  callbackasm1(SB)
+	MOVV $665, R12
+	JMP  callbackasm1(SB)
+	MOVV $666, R12
+	JMP  callbackasm1(SB)
+	MOVV $667, R12
+	JMP  callbackasm1(SB)
+	MOVV $668, R12
+	JMP  callbackasm1(SB)
+	MOVV $669, R12
+	JMP  callbackasm1(SB)
+	MOVV $670, R12
+	JMP  callbackasm1(SB)
+	MOVV $671, R12
+	JMP  callbackasm1(SB)
+	MOVV $672, R12
+	JMP  callbackasm1(SB)
+	MOVV $673, R12
+	JMP  callbackasm1(SB)
+	MOVV $674, R12
+	JMP  callbackasm1(SB)
+	MOVV $675, R12
+	JMP  callbackasm1(SB)
+	MOVV $676, R12
+	JMP  callbackasm1(SB)
+	MOVV $677, R12
+	JMP  callbackasm1(SB)
+	MOVV $678, R12
+	JMP  callbackasm1(SB)
+	MOVV $679, R12
+	JMP  callbackasm1(SB)
+	MOVV $680, R12
+	JMP  callbackasm1(SB)
+	MOVV $681, R12
+	JMP  callbackasm1(SB)
+	MOVV $682, R12
+	JMP  callbackasm1(SB)
+	MOVV $683, R12
+	JMP  callbackasm1(SB)
+	MOVV $684, R12
+	JMP  callbackasm1(SB)
+	MOVV $685, R12
+	JMP  callbackasm1(SB)
+	MOVV $686, R12
+	JMP  callbackasm1(SB)
+	MOVV $687, R12
+	JMP  callbackasm1(SB)
+	MOVV $688, R12
+	JMP  callbackasm1(SB)
+	MOVV $689, R12
+	JMP  callbackasm1(SB)
+	MOVV $690, R12
+	JMP  callbackasm1(SB)
+	MOVV $691, R12
+	JMP  callbackasm1(SB)
+	MOVV $692, R12
+	JMP  callbackasm1(SB)
+	MOVV $693, R12
+	JMP  callbackasm1(SB)
+	MOVV $694, R12
+	JMP  callbackasm1(SB)
+	MOVV $695, R12
+	JMP  callbackasm1(SB)
+	MOVV $696, R12
+	JMP  callbackasm1(SB)
+	MOVV $697, R12
+	JMP  callbackasm1(SB)
+	MOVV $698, R12
+	JMP  callbackasm1(SB)
+	MOVV $699, R12
+	JMP  callbackasm1(SB)
+	MOVV $700, R12
+	JMP  callbackasm1(SB)
+	MOVV $701, R12
+	JMP  callbackasm1(SB)
+	MOVV $702, R12
+	JMP  callbackasm1(SB)
+	MOVV $703, R12
+	JMP  callbackasm1(SB)
+	MOVV $704, R12
+	JMP  callbackasm1(SB)
+	MOVV $705, R12
+	JMP  callbackasm1(SB)
+	MOVV $706, R12
+	JMP  callbackasm1(SB)
+	MOVV $707, R12
+	JMP  callbackasm1(SB)
+	MOVV $708, R12
+	JMP  callbackasm1(SB)
+	MOVV $709, R12
+	JMP  callbackasm1(SB)
+	MOVV $710, R12
+	JMP  callbackasm1(SB)
+	MOVV $711, R12
+	JMP  callbackasm1(SB)
+	MOVV $712, R12
+	JMP  callbackasm1(SB)
+	MOVV $713, R12
+	JMP  callbackasm1(SB)
+	MOVV $714, R12
+	JMP  callbackasm1(SB)
+	MOVV $715, R12
+	JMP  callbackasm1(SB)
+	MOVV $716, R12
+	JMP  callbackasm1(SB)
+	MOVV $717, R12
+	JMP  callbackasm1(SB)
+	MOVV $718, R12
+	JMP  callbackasm1(SB)
+	MOVV $719, R12
+	JMP  callbackasm1(SB)
+	MOVV $720, R12
+	JMP  callbackasm1(SB)
+	MOVV $721, R12
+	JMP  callbackasm1(SB)
+	MOVV $722, R12
+	JMP  callbackasm1(SB)
+	MOVV $723, R12
+	JMP  callbackasm1(SB)
+	MOVV $724, R12
+	JMP  callbackasm1(SB)
+	MOVV $725, R12
+	JMP  callbackasm1(SB)
+	MOVV $726, R12
+	JMP  callbackasm1(SB)
+	MOVV $727, R12
+	JMP  callbackasm1(SB)
+	MOVV $728, R12
+	JMP  callbackasm1(SB)
+	MOVV $729, R12
+	JMP  callbackasm1(SB)
+	MOVV $730, R12
+	JMP  callbackasm1(SB)
+	MOVV $731, R12
+	JMP  callbackasm1(SB)
+	MOVV $732, R12
+	JMP  callbackasm1(SB)
+	MOVV $733, R12
+	JMP  callbackasm1(SB)
+	MOVV $734, R12
+	JMP  callbackasm1(SB)
+	MOVV $735, R12
+	JMP  callbackasm1(SB)
+	MOVV $736, R12
+	JMP  callbackasm1(SB)
+	MOVV $737, R12
+	JMP  callbackasm1(SB)
+	MOVV $738, R12
+	JMP  callbackasm1(SB)
+	MOVV $739, R12
+	JMP  callbackasm1(SB)
+	MOVV $740, R12
+	JMP  callbackasm1(SB)
+	MOVV $741, R12
+	JMP  callbackasm1(SB)
+	MOVV $742, R12
+	JMP  callbackasm1(SB)
+	MOVV $743, R12
+	JMP  callbackasm1(SB)
+	MOVV $744, R12
+	JMP  callbackasm1(SB)
+	MOVV $745, R12
+	JMP  callbackasm1(SB)
+	MOVV $746, R12
+	JMP  callbackasm1(SB)
+	MOVV $747, R12
+	JMP  callbackasm1(SB)
+	MOVV $748, R12
+	JMP  callbackasm1(SB)
+	MOVV $749, R12
+	JMP  callbackasm1(SB)
+	MOVV $750, R12
+	JMP  callbackasm1(SB)
+	MOVV $751, R12
+	JMP  callbackasm1(SB)
+	MOVV $752, R12
+	JMP  callbackasm1(SB)
+	MOVV $753, R12
+	JMP  callbackasm1(SB)
+	MOVV $754, R12
+	JMP  callbackasm1(SB)
+	MOVV $755, R12
+	JMP  callbackasm1(SB)
+	MOVV $756, R12
+	JMP  callbackasm1(SB)
+	MOVV $757, R12
+	JMP  callbackasm1(SB)
+	MOVV $758, R12
+	JMP  callbackasm1(SB)
+	MOVV $759, R12
+	JMP  callbackasm1(SB)
+	MOVV $760, R12
+	JMP  callbackasm1(SB)
+	MOVV $761, R12
+	JMP  callbackasm1(SB)
+	MOVV $762, R12
+	JMP  callbackasm1(SB)
+	MOVV $763, R12
+	JMP  callbackasm1(SB)
+	MOVV $764, R12
+	JMP  callbackasm1(SB)
+	MOVV $765, R12
+	JMP  callbackasm1(SB)
+	MOVV $766, R12
+	JMP  callbackasm1(SB)
+	MOVV $767, R12
+	JMP  callbackasm1(SB)
+	MOVV $768, R12
+	JMP  callbackasm1(SB)
+	MOVV $769, R12
+	JMP  callbackasm1(SB)
+	MOVV $770, R12
+	JMP  callbackasm1(SB)
+	MOVV $771, R12
+	JMP  callbackasm1(SB)
+	MOVV $772, R12
+	JMP  callbackasm1(SB)
+	MOVV $773, R12
+	JMP  callbackasm1(SB)
+	MOVV $774, R12
+	JMP  callbackasm1(SB)
+	MOVV $775, R12
+	JMP  callbackasm1(SB)
+	MOVV $776, R12
+	JMP  callbackasm1(SB)
+	MOVV $777, R12
+	JMP  callbackasm1(SB)
+	MOVV $778, R12
+	JMP  callbackasm1(SB)
+	MOVV $779, R12
+	JMP  callbackasm1(SB)
+	MOVV $780, R12
+	JMP  callbackasm1(SB)
+	MOVV $781, R12
+	JMP  callbackasm1(SB)
+	MOVV $782, R12
+	JMP  callbackasm1(SB)
+	MOVV $783, R12
+	JMP  callbackasm1(SB)
+	MOVV $784, R12
+	JMP  callbackasm1(SB)
+	MOVV $785, R12
+	JMP  callbackasm1(SB)
+	MOVV $786, R12
+	JMP  callbackasm1(SB)
+	MOVV $787, R12
+	JMP  callbackasm1(SB)
+	MOVV $788, R12
+	JMP  callbackasm1(SB)
+	MOVV $789, R12
+	JMP  callbackasm1(SB)
+	MOVV $790, R12
+	JMP  callbackasm1(SB)
+	MOVV $791, R12
+	JMP  callbackasm1(SB)
+	MOVV $792, R12
+	JMP  callbackasm1(SB)
+	MOVV $793, R12
+	JMP  callbackasm1(SB)
+	MOVV $794, R12
+	JMP  callbackasm1(SB)
+	MOVV $795, R12
+	JMP  callbackasm1(SB)
+	MOVV $796, R12
+	JMP  callbackasm1(SB)
+	MOVV $797, R12
+	JMP  callbackasm1(SB)
+	MOVV $798, R12
+	JMP  callbackasm1(SB)
+	MOVV $799, R12
+	JMP  callbackasm1(SB)
+	MOVV $800, R12
+	JMP  callbackasm1(SB)
+	MOVV $801, R12
+	JMP  callbackasm1(SB)
+	MOVV $802, R12
+	JMP  callbackasm1(SB)
+	MOVV $803, R12
+	JMP  callbackasm1(SB)
+	MOVV $804, R12
+	JMP  callbackasm1(SB)
+	MOVV $805, R12
+	JMP  callbackasm1(SB)
+	MOVV $806, R12
+	JMP  callbackasm1(SB)
+	MOVV $807, R12
+	JMP  callbackasm1(SB)
+	MOVV $808, R12
+	JMP  callbackasm1(SB)
+	MOVV $809, R12
+	JMP  callbackasm1(SB)
+	MOVV $810, R12
+	JMP  callbackasm1(SB)
+	MOVV $811, R12
+	JMP  callbackasm1(SB)
+	MOVV $812, R12
+	JMP  callbackasm1(SB)
+	MOVV $813, R12
+	JMP  callbackasm1(SB)
+	MOVV $814, R12
+	JMP  callbackasm1(SB)
+	MOVV $815, R12
+	JMP  callbackasm1(SB)
+	MOVV $816, R12
+	JMP  callbackasm1(SB)
+	MOVV $817, R12
+	JMP  callbackasm1(SB)
+	MOVV $818, R12
+	JMP  callbackasm1(SB)
+	MOVV $819, R12
+	JMP  callbackasm1(SB)
+	MOVV $820, R12
+	JMP  callbackasm1(SB)
+	MOVV $821, R12
+	JMP  callbackasm1(SB)
+	MOVV $822, R12
+	JMP  callbackasm1(SB)
+	MOVV $823, R12
+	JMP  callbackasm1(SB)
+	MOVV $824, R12
+	JMP  callbackasm1(SB)
+	MOVV $825, R12
+	JMP  callbackasm1(SB)
+	MOVV $826, R12
+	JMP  callbackasm1(SB)
+	MOVV $827, R12
+	JMP  callbackasm1(SB)
+	MOVV $828, R12
+	JMP  callbackasm1(SB)
+	MOVV $829, R12
+	JMP  callbackasm1(SB)
+	MOVV $830, R12
+	JMP  callbackasm1(SB)
+	MOVV $831, R12
+	JMP  callbackasm1(SB)
+	MOVV $832, R12
+	JMP  callbackasm1(SB)
+	MOVV $833, R12
+	JMP  callbackasm1(SB)
+	MOVV $834, R12
+	JMP  callbackasm1(SB)
+	MOVV $835, R12
+	JMP  callbackasm1(SB)
+	MOVV $836, R12
+	JMP  callbackasm1(SB)
+	MOVV $837, R12
+	JMP  callbackasm1(SB)
+	MOVV $838, R12
+	JMP  callbackasm1(SB)
+	MOVV $839, R12
+	JMP  callbackasm1(SB)
+	MOVV $840, R12
+	JMP  callbackasm1(SB)
+	MOVV $841, R12
+	JMP  callbackasm1(SB)
+	MOVV $842, R12
+	JMP  callbackasm1(SB)
+	MOVV $843, R12
+	JMP  callbackasm1(SB)
+	MOVV $844, R12
+	JMP  callbackasm1(SB)
+	MOVV $845, R12
+	JMP  callbackasm1(SB)
+	MOVV $846, R12
+	JMP  callbackasm1(SB)
+	MOVV $847, R12
+	JMP  callbackasm1(SB)
+	MOVV $848, R12
+	JMP  callbackasm1(SB)
+	MOVV $849, R12
+	JMP  callbackasm1(SB)
+	MOVV $850, R12
+	JMP  callbackasm1(SB)
+	MOVV $851, R12
+	JMP  callbackasm1(SB)
+	MOVV $852, R12
+	JMP  callbackasm1(SB)
+	MOVV $853, R12
+	JMP  callbackasm1(SB)
+	MOVV $854, R12
+	JMP  callbackasm1(SB)
+	MOVV $855, R12
+	JMP  callbackasm1(SB)
+	MOVV $856, R12
+	JMP  callbackasm1(SB)
+	MOVV $857, R12
+	JMP  callbackasm1(SB)
+	MOVV $858, R12
+	JMP  callbackasm1(SB)
+	MOVV $859, R12
+	JMP  callbackasm1(SB)
+	MOVV $860, R12
+	JMP  callbackasm1(SB)
+	MOVV $861, R12
+	JMP  callbackasm1(SB)
+	MOVV $862, R12
+	JMP  callbackasm1(SB)
+	MOVV $863, R12
+	JMP  callbackasm1(SB)
+	MOVV $864, R12
+	JMP  callbackasm1(SB)
+	MOVV $865, R12
+	JMP  callbackasm1(SB)
+	MOVV $866, R12
+	JMP  callbackasm1(SB)
+	MOVV $867, R12
+	JMP  callbackasm1(SB)
+	MOVV $868, R12
+	JMP  callbackasm1(SB)
+	MOVV $869, R12
+	JMP  callbackasm1(SB)
+	MOVV $870, R12
+	JMP  callbackasm1(SB)
+	MOVV $871, R12
+	JMP  callbackasm1(SB)
+	MOVV $872, R12
+	JMP  callbackasm1(SB)
+	MOVV $873, R12
+	JMP  callbackasm1(SB)
+	MOVV $874, R12
+	JMP  callbackasm1(SB)
+	MOVV $875, R12
+	JMP  callbackasm1(SB)
+	MOVV $876, R12
+	JMP  callbackasm1(SB)
+	MOVV $877, R12
+	JMP  callbackasm1(SB)
+	MOVV $878, R12
+	JMP  callbackasm1(SB)
+	MOVV $879, R12
+	JMP  callbackasm1(SB)
+	MOVV $880, R12
+	JMP  callbackasm1(SB)
+	MOVV $881, R12
+	JMP  callbackasm1(SB)
+	MOVV $882, R12
+	JMP  callbackasm1(SB)
+	MOVV $883, R12
+	JMP  callbackasm1(SB)
+	MOVV $884, R12
+	JMP  callbackasm1(SB)
+	MOVV $885, R12
+	JMP  callbackasm1(SB)
+	MOVV $886, R12
+	JMP  callbackasm1(SB)
+	MOVV $887, R12
+	JMP  callbackasm1(SB)
+	MOVV $888, R12
+	JMP  callbackasm1(SB)
+	MOVV $889, R12
+	JMP  callbackasm1(SB)
+	MOVV $890, R12
+	JMP  callbackasm1(SB)
+	MOVV $891, R12
+	JMP  callbackasm1(SB)
+	MOVV $892, R12
+	JMP  callbackasm1(SB)
+	MOVV $893, R12
+	JMP  callbackasm1(SB)
+	MOVV $894, R12
+	JMP  callbackasm1(SB)
+	MOVV $895, R12
+	JMP  callbackasm1(SB)
+	MOVV $896, R12
+	JMP  callbackasm1(SB)
+	MOVV $897, R12
+	JMP  callbackasm1(SB)
+	MOVV $898, R12
+	JMP  callbackasm1(SB)
+	MOVV $899, R12
+	JMP  callbackasm1(SB)
+	MOVV $900, R12
+	JMP  callbackasm1(SB)
+	MOVV $901, R12
+	JMP  callbackasm1(SB)
+	MOVV $902, R12
+	JMP  callbackasm1(SB)
+	MOVV $903, R12
+	JMP  callbackasm1(SB)
+	MOVV $904, R12
+	JMP  callbackasm1(SB)
+	MOVV $905, R12
+	JMP  callbackasm1(SB)
+	MOVV $906, R12
+	JMP  callbackasm1(SB)
+	MOVV $907, R12
+	JMP  callbackasm1(SB)
+	MOVV $908, R12
+	JMP  callbackasm1(SB)
+	MOVV $909, R12
+	JMP  callbackasm1(SB)
+	MOVV $910, R12
+	JMP  callbackasm1(SB)
+	MOVV $911, R12
+	JMP  callbackasm1(SB)
+	MOVV $912, R12
+	JMP  callbackasm1(SB)
+	MOVV $913, R12
+	JMP  callbackasm1(SB)
+	MOVV $914, R12
+	JMP  callbackasm1(SB)
+	MOVV $915, R12
+	JMP  callbackasm1(SB)
+	MOVV $916, R12
+	JMP  callbackasm1(SB)
+	MOVV $917, R12
+	JMP  callbackasm1(SB)
+	MOVV $918, R12
+	JMP  callbackasm1(SB)
+	MOVV $919, R12
+	JMP  callbackasm1(SB)
+	MOVV $920, R12
+	JMP  callbackasm1(SB)
+	MOVV $921, R12
+	JMP  callbackasm1(SB)
+	MOVV $922, R12
+	JMP  callbackasm1(SB)
+	MOVV $923, R12
+	JMP  callbackasm1(SB)
+	MOVV $924, R12
+	JMP  callbackasm1(SB)
+	MOVV $925, R12
+	JMP  callbackasm1(SB)
+	MOVV $926, R12
+	JMP  callbackasm1(SB)
+	MOVV $927, R12
+	JMP  callbackasm1(SB)
+	MOVV $928, R12
+	JMP  callbackasm1(SB)
+	MOVV $929, R12
+	JMP  callbackasm1(SB)
+	MOVV $930, R12
+	JMP  callbackasm1(SB)
+	MOVV $931, R12
+	JMP  callbackasm1(SB)
+	MOVV $932, R12
+	JMP  callbackasm1(SB)
+	MOVV $933, R12
+	JMP  callbackasm1(SB)
+	MOVV $934, R12
+	JMP  callbackasm1(SB)
+	MOVV $935, R12
+	JMP  callbackasm1(SB)
+	MOVV $936, R12
+	JMP  callbackasm1(SB)
+	MOVV $937, R12
+	JMP  callbackasm1(SB)
+	MOVV $938, R12
+	JMP  callbackasm1(SB)
+	MOVV $939, R12
+	JMP  callbackasm1(SB)
+	MOVV $940, R12
+	JMP  callbackasm1(SB)
+	MOVV $941, R12
+	JMP  callbackasm1(SB)
+	MOVV $942, R12
+	JMP  callbackasm1(SB)
+	MOVV $943, R12
+	JMP  callbackasm1(SB)
+	MOVV $944, R12
+	JMP  callbackasm1(SB)
+	MOVV $945, R12
+	JMP  callbackasm1(SB)
+	MOVV $946, R12
+	JMP  callbackasm1(SB)
+	MOVV $947, R12
+	JMP  callbackasm1(SB)
+	MOVV $948, R12
+	JMP  callbackasm1(SB)
+	MOVV $949, R12
+	JMP  callbackasm1(SB)
+	MOVV $950, R12
+	JMP  callbackasm1(SB)
+	MOVV $951, R12
+	JMP  callbackasm1(SB)
+	MOVV $952, R12
+	JMP  callbackasm1(SB)
+	MOVV $953, R12
+	JMP  callbackasm1(SB)
+	MOVV $954, R12
+	JMP  callbackasm1(SB)
+	MOVV $955, R12
+	JMP  callbackasm1(SB)
+	MOVV $956, R12
+	JMP  callbackasm1(SB)
+	MOVV $957, R12
+	JMP  callbackasm1(SB)
+	MOVV $958, R12
+	JMP  callbackasm1(SB)
+	MOVV $959, R12
+	JMP  callbackasm1(SB)
+	MOVV $960, R12
+	JMP  callbackasm1(SB)
+	MOVV $961, R12
+	JMP  callbackasm1(SB)
+	MOVV $962, R12
+	JMP  callbackasm1(SB)
+	MOVV $963, R12
+	JMP  callbackasm1(SB)
+	MOVV $964, R12
+	JMP  callbackasm1(SB)
+	MOVV $965, R12
+	JMP  callbackasm1(SB)
+	MOVV $966, R12
+	JMP  callbackasm1(SB)
+	MOVV $967, R12
+	JMP  callbackasm1(SB)
+	MOVV $968, R12
+	JMP  callbackasm1(SB)
+	MOVV $969, R12
+	JMP  callbackasm1(SB)
+	MOVV $970, R12
+	JMP  callbackasm1(SB)
+	MOVV $971, R12
+	JMP  callbackasm1(SB)
+	MOVV $972, R12
+	JMP  callbackasm1(SB)
+	MOVV $973, R12
+	JMP  callbackasm1(SB)
+	MOVV $974, R12
+	JMP  callbackasm1(SB)
+	MOVV $975, R12
+	JMP  callbackasm1(SB)
+	MOVV $976, R12
+	JMP  callbackasm1(SB)
+	MOVV $977, R12
+	JMP  callbackasm1(SB)
+	MOVV $978, R12
+	JMP  callbackasm1(SB)
+	MOVV $979, R12
+	JMP  callbackasm1(SB)
+	MOVV $980, R12
+	JMP  callbackasm1(SB)
+	MOVV $981, R12
+	JMP  callbackasm1(SB)
+	MOVV $982, R12
+	JMP  callbackasm1(SB)
+	MOVV $983, R12
+	JMP  callbackasm1(SB)
+	MOVV $984, R12
+	JMP  callbackasm1(SB)
+	MOVV $985, R12
+	JMP  callbackasm1(SB)
+	MOVV $986, R12
+	JMP  callbackasm1(SB)
+	MOVV $987, R12
+	JMP  callbackasm1(SB)
+	MOVV $988, R12
+	JMP  callbackasm1(SB)
+	MOVV $989, R12
+	JMP  callbackasm1(SB)
+	MOVV $990, R12
+	JMP  callbackasm1(SB)
+	MOVV $991, R12
+	JMP  callbackasm1(SB)
+	MOVV $992, R12
+	JMP  callbackasm1(SB)
+	MOVV $993, R12
+	JMP  callbackasm1(SB)
+	MOVV $994, R12
+	JMP  callbackasm1(SB)
+	MOVV $995, R12
+	JMP  callbackasm1(SB)
+	MOVV $996, R12
+	JMP  callbackasm1(SB)
+	MOVV $997, R12
+	JMP  callbackasm1(SB)
+	MOVV $998, R12
+	JMP  callbackasm1(SB)
+	MOVV $999, R12
+	JMP  callbackasm1(SB)
+	MOVV $1000, R12
+	JMP  callbackasm1(SB)
+	MOVV $1001, R12
+	JMP  callbackasm1(SB)
+	MOVV $1002, R12
+	JMP  callbackasm1(SB)
+	MOVV $1003, R12
+	JMP  callbackasm1(SB)
+	MOVV $1004, R12
+	JMP  callbackasm1(SB)
+	MOVV $1005, R12
+	JMP  callbackasm1(SB)
+	MOVV $1006, R12
+	JMP  callbackasm1(SB)
+	MOVV $1007, R12
+	JMP  callbackasm1(SB)
+	MOVV $1008, R12
+	JMP  callbackasm1(SB)
+	MOVV $1009, R12
+	JMP  callbackasm1(SB)
+	MOVV $1010, R12
+	JMP  callbackasm1(SB)
+	MOVV $1011, R12
+	JMP  callbackasm1(SB)
+	MOVV $1012, R12
+	JMP  callbackasm1(SB)
+	MOVV $1013, R12
+	JMP  callbackasm1(SB)
+	MOVV $1014, R12
+	JMP  callbackasm1(SB)
+	MOVV $1015, R12
+	JMP  callbackasm1(SB)
+	MOVV $1016, R12
+	JMP  callbackasm1(SB)
+	MOVV $1017, R12
+	JMP  callbackasm1(SB)
+	MOVV $1018, R12
+	JMP  callbackasm1(SB)
+	MOVV $1019, R12
+	JMP  callbackasm1(SB)
+	MOVV $1020, R12
+	JMP  callbackasm1(SB)
+	MOVV $1021, R12
+	JMP  callbackasm1(SB)
+	MOVV $1022, R12
+	JMP  callbackasm1(SB)
+	MOVV $1023, R12
+	JMP  callbackasm1(SB)
+	MOVV $1024, R12
+	JMP  callbackasm1(SB)
+	MOVV $1025, R12
+	JMP  callbackasm1(SB)
+	MOVV $1026, R12
+	JMP  callbackasm1(SB)
+	MOVV $1027, R12
+	JMP  callbackasm1(SB)
+	MOVV $1028, R12
+	JMP  callbackasm1(SB)
+	MOVV $1029, R12
+	JMP  callbackasm1(SB)
+	MOVV $1030, R12
+	JMP  callbackasm1(SB)
+	MOVV $1031, R12
+	JMP  callbackasm1(SB)
+	MOVV $1032, R12
+	JMP  callbackasm1(SB)
+	MOVV $1033, R12
+	JMP  callbackasm1(SB)
+	MOVV $1034, R12
+	JMP  callbackasm1(SB)
+	MOVV $1035, R12
+	JMP  callbackasm1(SB)
+	MOVV $1036, R12
+	JMP  callbackasm1(SB)
+	MOVV $1037, R12
+	JMP  callbackasm1(SB)
+	MOVV $1038, R12
+	JMP  callbackasm1(SB)
+	MOVV $1039, R12
+	JMP  callbackasm1(SB)
+	MOVV $1040, R12
+	JMP  callbackasm1(SB)
+	MOVV $1041, R12
+	JMP  callbackasm1(SB)
+	MOVV $1042, R12
+	JMP  callbackasm1(SB)
+	MOVV $1043, R12
+	JMP  callbackasm1(SB)
+	MOVV $1044, R12
+	JMP  callbackasm1(SB)
+	MOVV $1045, R12
+	JMP  callbackasm1(SB)
+	MOVV $1046, R12
+	JMP  callbackasm1(SB)
+	MOVV $1047, R12
+	JMP  callbackasm1(SB)
+	MOVV $1048, R12
+	JMP  callbackasm1(SB)
+	MOVV $1049, R12
+	JMP  callbackasm1(SB)
+	MOVV $1050, R12
+	JMP  callbackasm1(SB)
+	MOVV $1051, R12
+	JMP  callbackasm1(SB)
+	MOVV $1052, R12
+	JMP  callbackasm1(SB)
+	MOVV $1053, R12
+	JMP  callbackasm1(SB)
+	MOVV $1054, R12
+	JMP  callbackasm1(SB)
+	MOVV $1055, R12
+	JMP  callbackasm1(SB)
+	MOVV $1056, R12
+	JMP  callbackasm1(SB)
+	MOVV $1057, R12
+	JMP  callbackasm1(SB)
+	MOVV $1058, R12
+	JMP  callbackasm1(SB)
+	MOVV $1059, R12
+	JMP  callbackasm1(SB)
+	MOVV $1060, R12
+	JMP  callbackasm1(SB)
+	MOVV $1061, R12
+	JMP  callbackasm1(SB)
+	MOVV $1062, R12
+	JMP  callbackasm1(SB)
+	MOVV $1063, R12
+	JMP  callbackasm1(SB)
+	MOVV $1064, R12
+	JMP  callbackasm1(SB)
+	MOVV $1065, R12
+	JMP  callbackasm1(SB)
+	MOVV $1066, R12
+	JMP  callbackasm1(SB)
+	MOVV $1067, R12
+	JMP  callbackasm1(SB)
+	MOVV $1068, R12
+	JMP  callbackasm1(SB)
+	MOVV $1069, R12
+	JMP  callbackasm1(SB)
+	MOVV $1070, R12
+	JMP  callbackasm1(SB)
+	MOVV $1071, R12
+	JMP  callbackasm1(SB)
+	MOVV $1072, R12
+	JMP  callbackasm1(SB)
+	MOVV $1073, R12
+	JMP  callbackasm1(SB)
+	MOVV $1074, R12
+	JMP  callbackasm1(SB)
+	MOVV $1075, R12
+	JMP  callbackasm1(SB)
+	MOVV $1076, R12
+	JMP  callbackasm1(SB)
+	MOVV $1077, R12
+	JMP  callbackasm1(SB)
+	MOVV $1078, R12
+	JMP  callbackasm1(SB)
+	MOVV $1079, R12
+	JMP  callbackasm1(SB)
+	MOVV $1080, R12
+	JMP  callbackasm1(SB)
+	MOVV $1081, R12
+	JMP  callbackasm1(SB)
+	MOVV $1082, R12
+	JMP  callbackasm1(SB)
+	MOVV $1083, R12
+	JMP  callbackasm1(SB)
+	MOVV $1084, R12
+	JMP  callbackasm1(SB)
+	MOVV $1085, R12
+	JMP  callbackasm1(SB)
+	MOVV $1086, R12
+	JMP  callbackasm1(SB)
+	MOVV $1087, R12
+	JMP  callbackasm1(SB)
+	MOVV $1088, R12
+	JMP  callbackasm1(SB)
+	MOVV $1089, R12
+	JMP  callbackasm1(SB)
+	MOVV $1090, R12
+	JMP  callbackasm1(SB)
+	MOVV $1091, R12
+	JMP  callbackasm1(SB)
+	MOVV $1092, R12
+	JMP  callbackasm1(SB)
+	MOVV $1093, R12
+	JMP  callbackasm1(SB)
+	MOVV $1094, R12
+	JMP  callbackasm1(SB)
+	MOVV $1095, R12
+	JMP  callbackasm1(SB)
+	MOVV $1096, R12
+	JMP  callbackasm1(SB)
+	MOVV $1097, R12
+	JMP  callbackasm1(SB)
+	MOVV $1098, R12
+	JMP  callbackasm1(SB)
+	MOVV $1099, R12
+	JMP  callbackasm1(SB)
+	MOVV $1100, R12
+	JMP  callbackasm1(SB)
+	MOVV $1101, R12
+	JMP  callbackasm1(SB)
+	MOVV $1102, R12
+	JMP  callbackasm1(SB)
+	MOVV $1103, R12
+	JMP  callbackasm1(SB)
+	MOVV $1104, R12
+	JMP  callbackasm1(SB)
+	MOVV $1105, R12
+	JMP  callbackasm1(SB)
+	MOVV $1106, R12
+	JMP  callbackasm1(SB)
+	MOVV $1107, R12
+	JMP  callbackasm1(SB)
+	MOVV $1108, R12
+	JMP  callbackasm1(SB)
+	MOVV $1109, R12
+	JMP  callbackasm1(SB)
+	MOVV $1110, R12
+	JMP  callbackasm1(SB)
+	MOVV $1111, R12
+	JMP  callbackasm1(SB)
+	MOVV $1112, R12
+	JMP  callbackasm1(SB)
+	MOVV $1113, R12
+	JMP  callbackasm1(SB)
+	MOVV $1114, R12
+	JMP  callbackasm1(SB)
+	MOVV $1115, R12
+	JMP  callbackasm1(SB)
+	MOVV $1116, R12
+	JMP  callbackasm1(SB)
+	MOVV $1117, R12
+	JMP  callbackasm1(SB)
+	MOVV $1118, R12
+	JMP  callbackasm1(SB)
+	MOVV $1119, R12
+	JMP  callbackasm1(SB)
+	MOVV $1120, R12
+	JMP  callbackasm1(SB)
+	MOVV $1121, R12
+	JMP  callbackasm1(SB)
+	MOVV $1122, R12
+	JMP  callbackasm1(SB)
+	MOVV $1123, R12
+	JMP  callbackasm1(SB)
+	MOVV $1124, R12
+	JMP  callbackasm1(SB)
+	MOVV $1125, R12
+	JMP  callbackasm1(SB)
+	MOVV $1126, R12
+	JMP  callbackasm1(SB)
+	MOVV $1127, R12
+	JMP  callbackasm1(SB)
+	MOVV $1128, R12
+	JMP  callbackasm1(SB)
+	MOVV $1129, R12
+	JMP  callbackasm1(SB)
+	MOVV $1130, R12
+	JMP  callbackasm1(SB)
+	MOVV $1131, R12
+	JMP  callbackasm1(SB)
+	MOVV $1132, R12
+	JMP  callbackasm1(SB)
+	MOVV $1133, R12
+	JMP  callbackasm1(SB)
+	MOVV $1134, R12
+	JMP  callbackasm1(SB)
+	MOVV $1135, R12
+	JMP  callbackasm1(SB)
+	MOVV $1136, R12
+	JMP  callbackasm1(SB)
+	MOVV $1137, R12
+	JMP  callbackasm1(SB)
+	MOVV $1138, R12
+	JMP  callbackasm1(SB)
+	MOVV $1139, R12
+	JMP  callbackasm1(SB)
+	MOVV $1140, R12
+	JMP  callbackasm1(SB)
+	MOVV $1141, R12
+	JMP  callbackasm1(SB)
+	MOVV $1142, R12
+	JMP  callbackasm1(SB)
+	MOVV $1143, R12
+	JMP  callbackasm1(SB)
+	MOVV $1144, R12
+	JMP  callbackasm1(SB)
+	MOVV $1145, R12
+	JMP  callbackasm1(SB)
+	MOVV $1146, R12
+	JMP  callbackasm1(SB)
+	MOVV $1147, R12
+	JMP  callbackasm1(SB)
+	MOVV $1148, R12
+	JMP  callbackasm1(SB)
+	MOVV $1149, R12
+	JMP  callbackasm1(SB)
+	MOVV $1150, R12
+	JMP  callbackasm1(SB)
+	MOVV $1151, R12
+	JMP  callbackasm1(SB)
+	MOVV $1152, R12
+	JMP  callbackasm1(SB)
+	MOVV $1153, R12
+	JMP  callbackasm1(SB)
+	MOVV $1154, R12
+	JMP  callbackasm1(SB)
+	MOVV $1155, R12
+	JMP  callbackasm1(SB)
+	MOVV $1156, R12
+	JMP  callbackasm1(SB)
+	MOVV $1157, R12
+	JMP  callbackasm1(SB)
+	MOVV $1158, R12
+	JMP  callbackasm1(SB)
+	MOVV $1159, R12
+	JMP  callbackasm1(SB)
+	MOVV $1160, R12
+	JMP  callbackasm1(SB)
+	MOVV $1161, R12
+	JMP  callbackasm1(SB)
+	MOVV $1162, R12
+	JMP  callbackasm1(SB)
+	MOVV $1163, R12
+	JMP  callbackasm1(SB)
+	MOVV $1164, R12
+	JMP  callbackasm1(SB)
+	MOVV $1165, R12
+	JMP  callbackasm1(SB)
+	MOVV $1166, R12
+	JMP  callbackasm1(SB)
+	MOVV $1167, R12
+	JMP  callbackasm1(SB)
+	MOVV $1168, R12
+	JMP  callbackasm1(SB)
+	MOVV $1169, R12
+	JMP  callbackasm1(SB)
+	MOVV $1170, R12
+	JMP  callbackasm1(SB)
+	MOVV $1171, R12
+	JMP  callbackasm1(SB)
+	MOVV $1172, R12
+	JMP  callbackasm1(SB)
+	MOVV $1173, R12
+	JMP  callbackasm1(SB)
+	MOVV $1174, R12
+	JMP  callbackasm1(SB)
+	MOVV $1175, R12
+	JMP  callbackasm1(SB)
+	MOVV $1176, R12
+	JMP  callbackasm1(SB)
+	MOVV $1177, R12
+	JMP  callbackasm1(SB)
+	MOVV $1178, R12
+	JMP  callbackasm1(SB)
+	MOVV $1179, R12
+	JMP  callbackasm1(SB)
+	MOVV $1180, R12
+	JMP  callbackasm1(SB)
+	MOVV $1181, R12
+	JMP  callbackasm1(SB)
+	MOVV $1182, R12
+	JMP  callbackasm1(SB)
+	MOVV $1183, R12
+	JMP  callbackasm1(SB)
+	MOVV $1184, R12
+	JMP  callbackasm1(SB)
+	MOVV $1185, R12
+	JMP  callbackasm1(SB)
+	MOVV $1186, R12
+	JMP  callbackasm1(SB)
+	MOVV $1187, R12
+	JMP  callbackasm1(SB)
+	MOVV $1188, R12
+	JMP  callbackasm1(SB)
+	MOVV $1189, R12
+	JMP  callbackasm1(SB)
+	MOVV $1190, R12
+	JMP  callbackasm1(SB)
+	MOVV $1191, R12
+	JMP  callbackasm1(SB)
+	MOVV $1192, R12
+	JMP  callbackasm1(SB)
+	MOVV $1193, R12
+	JMP  callbackasm1(SB)
+	MOVV $1194, R12
+	JMP  callbackasm1(SB)
+	MOVV $1195, R12
+	JMP  callbackasm1(SB)
+	MOVV $1196, R12
+	JMP  callbackasm1(SB)
+	MOVV $1197, R12
+	JMP  callbackasm1(SB)
+	MOVV $1198, R12
+	JMP  callbackasm1(SB)
+	MOVV $1199, R12
+	JMP  callbackasm1(SB)
+	MOVV $1200, R12
+	JMP  callbackasm1(SB)
+	MOVV $1201, R12
+	JMP  callbackasm1(SB)
+	MOVV $1202, R12
+	JMP  callbackasm1(SB)
+	MOVV $1203, R12
+	JMP  callbackasm1(SB)
+	MOVV $1204, R12
+	JMP  callbackasm1(SB)
+	MOVV $1205, R12
+	JMP  callbackasm1(SB)
+	MOVV $1206, R12
+	JMP  callbackasm1(SB)
+	MOVV $1207, R12
+	JMP  callbackasm1(SB)
+	MOVV $1208, R12
+	JMP  callbackasm1(SB)
+	MOVV $1209, R12
+	JMP  callbackasm1(SB)
+	MOVV $1210, R12
+	JMP  callbackasm1(SB)
+	MOVV $1211, R12
+	JMP  callbackasm1(SB)
+	MOVV $1212, R12
+	JMP  callbackasm1(SB)
+	MOVV $1213, R12
+	JMP  callbackasm1(SB)
+	MOVV $1214, R12
+	JMP  callbackasm1(SB)
+	MOVV $1215, R12
+	JMP  callbackasm1(SB)
+	MOVV $1216, R12
+	JMP  callbackasm1(SB)
+	MOVV $1217, R12
+	JMP  callbackasm1(SB)
+	MOVV $1218, R12
+	JMP  callbackasm1(SB)
+	MOVV $1219, R12
+	JMP  callbackasm1(SB)
+	MOVV $1220, R12
+	JMP  callbackasm1(SB)
+	MOVV $1221, R12
+	JMP  callbackasm1(SB)
+	MOVV $1222, R12
+	JMP  callbackasm1(SB)
+	MOVV $1223, R12
+	JMP  callbackasm1(SB)
+	MOVV $1224, R12
+	JMP  callbackasm1(SB)
+	MOVV $1225, R12
+	JMP  callbackasm1(SB)
+	MOVV $1226, R12
+	JMP  callbackasm1(SB)
+	MOVV $1227, R12
+	JMP  callbackasm1(SB)
+	MOVV $1228, R12
+	JMP  callbackasm1(SB)
+	MOVV $1229, R12
+	JMP  callbackasm1(SB)
+	MOVV $1230, R12
+	JMP  callbackasm1(SB)
+	MOVV $1231, R12
+	JMP  callbackasm1(SB)
+	MOVV $1232, R12
+	JMP  callbackasm1(SB)
+	MOVV $1233, R12
+	JMP  callbackasm1(SB)
+	MOVV $1234, R12
+	JMP  callbackasm1(SB)
+	MOVV $1235, R12
+	JMP  callbackasm1(SB)
+	MOVV $1236, R12
+	JMP  callbackasm1(SB)
+	MOVV $1237, R12
+	JMP  callbackasm1(SB)
+	MOVV $1238, R12
+	JMP  callbackasm1(SB)
+	MOVV $1239, R12
+	JMP  callbackasm1(SB)
+	MOVV $1240, R12
+	JMP  callbackasm1(SB)
+	MOVV $1241, R12
+	JMP  callbackasm1(SB)
+	MOVV $1242, R12
+	JMP  callbackasm1(SB)
+	MOVV $1243, R12
+	JMP  callbackasm1(SB)
+	MOVV $1244, R12
+	JMP  callbackasm1(SB)
+	MOVV $1245, R12
+	JMP  callbackasm1(SB)
+	MOVV $1246, R12
+	JMP  callbackasm1(SB)
+	MOVV $1247, R12
+	JMP  callbackasm1(SB)
+	MOVV $1248, R12
+	JMP  callbackasm1(SB)
+	MOVV $1249, R12
+	JMP  callbackasm1(SB)
+	MOVV $1250, R12
+	JMP  callbackasm1(SB)
+	MOVV $1251, R12
+	JMP  callbackasm1(SB)
+	MOVV $1252, R12
+	JMP  callbackasm1(SB)
+	MOVV $1253, R12
+	JMP  callbackasm1(SB)
+	MOVV $1254, R12
+	JMP  callbackasm1(SB)
+	MOVV $1255, R12
+	JMP  callbackasm1(SB)
+	MOVV $1256, R12
+	JMP  callbackasm1(SB)
+	MOVV $1257, R12
+	JMP  callbackasm1(SB)
+	MOVV $1258, R12
+	JMP  callbackasm1(SB)
+	MOVV $1259, R12
+	JMP  callbackasm1(SB)
+	MOVV $1260, R12
+	JMP  callbackasm1(SB)
+	MOVV $1261, R12
+	JMP  callbackasm1(SB)
+	MOVV $1262, R12
+	JMP  callbackasm1(SB)
+	MOVV $1263, R12
+	JMP  callbackasm1(SB)
+	MOVV $1264, R12
+	JMP  callbackasm1(SB)
+	MOVV $1265, R12
+	JMP  callbackasm1(SB)
+	MOVV $1266, R12
+	JMP  callbackasm1(SB)
+	MOVV $1267, R12
+	JMP  callbackasm1(SB)
+	MOVV $1268, R12
+	JMP  callbackasm1(SB)
+	MOVV $1269, R12
+	JMP  callbackasm1(SB)
+	MOVV $1270, R12
+	JMP  callbackasm1(SB)
+	MOVV $1271, R12
+	JMP  callbackasm1(SB)
+	MOVV $1272, R12
+	JMP  callbackasm1(SB)
+	MOVV $1273, R12
+	JMP  callbackasm1(SB)
+	MOVV $1274, R12
+	JMP  callbackasm1(SB)
+	MOVV $1275, R12
+	JMP  callbackasm1(SB)
+	MOVV $1276, R12
+	JMP  callbackasm1(SB)
+	MOVV $1277, R12
+	JMP  callbackasm1(SB)
+	MOVV $1278, R12
+	JMP  callbackasm1(SB)
+	MOVV $1279, R12
+	JMP  callbackasm1(SB)
+	MOVV $1280, R12
+	JMP  callbackasm1(SB)
+	MOVV $1281, R12
+	JMP  callbackasm1(SB)
+	MOVV $1282, R12
+	JMP  callbackasm1(SB)
+	MOVV $1283, R12
+	JMP  callbackasm1(SB)
+	MOVV $1284, R12
+	JMP  callbackasm1(SB)
+	MOVV $1285, R12
+	JMP  callbackasm1(SB)
+	MOVV $1286, R12
+	JMP  callbackasm1(SB)
+	MOVV $1287, R12
+	JMP  callbackasm1(SB)
+	MOVV $1288, R12
+	JMP  callbackasm1(SB)
+	MOVV $1289, R12
+	JMP  callbackasm1(SB)
+	MOVV $1290, R12
+	JMP  callbackasm1(SB)
+	MOVV $1291, R12
+	JMP  callbackasm1(SB)
+	MOVV $1292, R12
+	JMP  callbackasm1(SB)
+	MOVV $1293, R12
+	JMP  callbackasm1(SB)
+	MOVV $1294, R12
+	JMP  callbackasm1(SB)
+	MOVV $1295, R12
+	JMP  callbackasm1(SB)
+	MOVV $1296, R12
+	JMP  callbackasm1(SB)
+	MOVV $1297, R12
+	JMP  callbackasm1(SB)
+	MOVV $1298, R12
+	JMP  callbackasm1(SB)
+	MOVV $1299, R12
+	JMP  callbackasm1(SB)
+	MOVV $1300, R12
+	JMP  callbackasm1(SB)
+	MOVV $1301, R12
+	JMP  callbackasm1(SB)
+	MOVV $1302, R12
+	JMP  callbackasm1(SB)
+	MOVV $1303, R12
+	JMP  callbackasm1(SB)
+	MOVV $1304, R12
+	JMP  callbackasm1(SB)
+	MOVV $1305, R12
+	JMP  callbackasm1(SB)
+	MOVV $1306, R12
+	JMP  callbackasm1(SB)
+	MOVV $1307, R12
+	JMP  callbackasm1(SB)
+	MOVV $1308, R12
+	JMP  callbackasm1(SB)
+	MOVV $1309, R12
+	JMP  callbackasm1(SB)
+	MOVV $1310, R12
+	JMP  callbackasm1(SB)
+	MOVV $1311, R12
+	JMP  callbackasm1(SB)
+	MOVV $1312, R12
+	JMP  callbackasm1(SB)
+	MOVV $1313, R12
+	JMP  callbackasm1(SB)
+	MOVV $1314, R12
+	JMP  callbackasm1(SB)
+	MOVV $1315, R12
+	JMP  callbackasm1(SB)
+	MOVV $1316, R12
+	JMP  callbackasm1(SB)
+	MOVV $1317, R12
+	JMP  callbackasm1(SB)
+	MOVV $1318, R12
+	JMP  callbackasm1(SB)
+	MOVV $1319, R12
+	JMP  callbackasm1(SB)
+	MOVV $1320, R12
+	JMP  callbackasm1(SB)
+	MOVV $1321, R12
+	JMP  callbackasm1(SB)
+	MOVV $1322, R12
+	JMP  callbackasm1(SB)
+	MOVV $1323, R12
+	JMP  callbackasm1(SB)
+	MOVV $1324, R12
+	JMP  callbackasm1(SB)
+	MOVV $1325, R12
+	JMP  callbackasm1(SB)
+	MOVV $1326, R12
+	JMP  callbackasm1(SB)
+	MOVV $1327, R12
+	JMP  callbackasm1(SB)
+	MOVV $1328, R12
+	JMP  callbackasm1(SB)
+	MOVV $1329, R12
+	JMP  callbackasm1(SB)
+	MOVV $1330, R12
+	JMP  callbackasm1(SB)
+	MOVV $1331, R12
+	JMP  callbackasm1(SB)
+	MOVV $1332, R12
+	JMP  callbackasm1(SB)
+	MOVV $1333, R12
+	JMP  callbackasm1(SB)
+	MOVV $1334, R12
+	JMP  callbackasm1(SB)
+	MOVV $1335, R12
+	JMP  callbackasm1(SB)
+	MOVV $1336, R12
+	JMP  callbackasm1(SB)
+	MOVV $1337, R12
+	JMP  callbackasm1(SB)
+	MOVV $1338, R12
+	JMP  callbackasm1(SB)
+	MOVV $1339, R12
+	JMP  callbackasm1(SB)
+	MOVV $1340, R12
+	JMP  callbackasm1(SB)
+	MOVV $1341, R12
+	JMP  callbackasm1(SB)
+	MOVV $1342, R12
+	JMP  callbackasm1(SB)
+	MOVV $1343, R12
+	JMP  callbackasm1(SB)
+	MOVV $1344, R12
+	JMP  callbackasm1(SB)
+	MOVV $1345, R12
+	JMP  callbackasm1(SB)
+	MOVV $1346, R12
+	JMP  callbackasm1(SB)
+	MOVV $1347, R12
+	JMP  callbackasm1(SB)
+	MOVV $1348, R12
+	JMP  callbackasm1(SB)
+	MOVV $1349, R12
+	JMP  callbackasm1(SB)
+	MOVV $1350, R12
+	JMP  callbackasm1(SB)
+	MOVV $1351, R12
+	JMP  callbackasm1(SB)
+	MOVV $1352, R12
+	JMP  callbackasm1(SB)
+	MOVV $1353, R12
+	JMP  callbackasm1(SB)
+	MOVV $1354, R12
+	JMP  callbackasm1(SB)
+	MOVV $1355, R12
+	JMP  callbackasm1(SB)
+	MOVV $1356, R12
+	JMP  callbackasm1(SB)
+	MOVV $1357, R12
+	JMP  callbackasm1(SB)
+	MOVV $1358, R12
+	JMP  callbackasm1(SB)
+	MOVV $1359, R12
+	JMP  callbackasm1(SB)
+	MOVV $1360, R12
+	JMP  callbackasm1(SB)
+	MOVV $1361, R12
+	JMP  callbackasm1(SB)
+	MOVV $1362, R12
+	JMP  callbackasm1(SB)
+	MOVV $1363, R12
+	JMP  callbackasm1(SB)
+	MOVV $1364, R12
+	JMP  callbackasm1(SB)
+	MOVV $1365, R12
+	JMP  callbackasm1(SB)
+	MOVV $1366, R12
+	JMP  callbackasm1(SB)
+	MOVV $1367, R12
+	JMP  callbackasm1(SB)
+	MOVV $1368, R12
+	JMP  callbackasm1(SB)
+	MOVV $1369, R12
+	JMP  callbackasm1(SB)
+	MOVV $1370, R12
+	JMP  callbackasm1(SB)
+	MOVV $1371, R12
+	JMP  callbackasm1(SB)
+	MOVV $1372, R12
+	JMP  callbackasm1(SB)
+	MOVV $1373, R12
+	JMP  callbackasm1(SB)
+	MOVV $1374, R12
+	JMP  callbackasm1(SB)
+	MOVV $1375, R12
+	JMP  callbackasm1(SB)
+	MOVV $1376, R12
+	JMP  callbackasm1(SB)
+	MOVV $1377, R12
+	JMP  callbackasm1(SB)
+	MOVV $1378, R12
+	JMP  callbackasm1(SB)
+	MOVV $1379, R12
+	JMP  callbackasm1(SB)
+	MOVV $1380, R12
+	JMP  callbackasm1(SB)
+	MOVV $1381, R12
+	JMP  callbackasm1(SB)
+	MOVV $1382, R12
+	JMP  callbackasm1(SB)
+	MOVV $1383, R12
+	JMP  callbackasm1(SB)
+	MOVV $1384, R12
+	JMP  callbackasm1(SB)
+	MOVV $1385, R12
+	JMP  callbackasm1(SB)
+	MOVV $1386, R12
+	JMP  callbackasm1(SB)
+	MOVV $1387, R12
+	JMP  callbackasm1(SB)
+	MOVV $1388, R12
+	JMP  callbackasm1(SB)
+	MOVV $1389, R12
+	JMP  callbackasm1(SB)
+	MOVV $1390, R12
+	JMP  callbackasm1(SB)
+	MOVV $1391, R12
+	JMP  callbackasm1(SB)
+	MOVV $1392, R12
+	JMP  callbackasm1(SB)
+	MOVV $1393, R12
+	JMP  callbackasm1(SB)
+	MOVV $1394, R12
+	JMP  callbackasm1(SB)
+	MOVV $1395, R12
+	JMP  callbackasm1(SB)
+	MOVV $1396, R12
+	JMP  callbackasm1(SB)
+	MOVV $1397, R12
+	JMP  callbackasm1(SB)
+	MOVV $1398, R12
+	JMP  callbackasm1(SB)
+	MOVV $1399, R12
+	JMP  callbackasm1(SB)
+	MOVV $1400, R12
+	JMP  callbackasm1(SB)
+	MOVV $1401, R12
+	JMP  callbackasm1(SB)
+	MOVV $1402, R12
+	JMP  callbackasm1(SB)
+	MOVV $1403, R12
+	JMP  callbackasm1(SB)
+	MOVV $1404, R12
+	JMP  callbackasm1(SB)
+	MOVV $1405, R12
+	JMP  callbackasm1(SB)
+	MOVV $1406, R12
+	JMP  callbackasm1(SB)
+	MOVV $1407, R12
+	JMP  callbackasm1(SB)
+	MOVV $1408, R12
+	JMP  callbackasm1(SB)
+	MOVV $1409, R12
+	JMP  callbackasm1(SB)
+	MOVV $1410, R12
+	JMP  callbackasm1(SB)
+	MOVV $1411, R12
+	JMP  callbackasm1(SB)
+	MOVV $1412, R12
+	JMP  callbackasm1(SB)
+	MOVV $1413, R12
+	JMP  callbackasm1(SB)
+	MOVV $1414, R12
+	JMP  callbackasm1(SB)
+	MOVV $1415, R12
+	JMP  callbackasm1(SB)
+	MOVV $1416, R12
+	JMP  callbackasm1(SB)
+	MOVV $1417, R12
+	JMP  callbackasm1(SB)
+	MOVV $1418, R12
+	JMP  callbackasm1(SB)
+	MOVV $1419, R12
+	JMP  callbackasm1(SB)
+	MOVV $1420, R12
+	JMP  callbackasm1(SB)
+	MOVV $1421, R12
+	JMP  callbackasm1(SB)
+	MOVV $1422, R12
+	JMP  callbackasm1(SB)
+	MOVV $1423, R12
+	JMP  callbackasm1(SB)
+	MOVV $1424, R12
+	JMP  callbackasm1(SB)
+	MOVV $1425, R12
+	JMP  callbackasm1(SB)
+	MOVV $1426, R12
+	JMP  callbackasm1(SB)
+	MOVV $1427, R12
+	JMP  callbackasm1(SB)
+	MOVV $1428, R12
+	JMP  callbackasm1(SB)
+	MOVV $1429, R12
+	JMP  callbackasm1(SB)
+	MOVV $1430, R12
+	JMP  callbackasm1(SB)
+	MOVV $1431, R12
+	JMP  callbackasm1(SB)
+	MOVV $1432, R12
+	JMP  callbackasm1(SB)
+	MOVV $1433, R12
+	JMP  callbackasm1(SB)
+	MOVV $1434, R12
+	JMP  callbackasm1(SB)
+	MOVV $1435, R12
+	JMP  callbackasm1(SB)
+	MOVV $1436, R12
+	JMP  callbackasm1(SB)
+	MOVV $1437, R12
+	JMP  callbackasm1(SB)
+	MOVV $1438, R12
+	JMP  callbackasm1(SB)
+	MOVV $1439, R12
+	JMP  callbackasm1(SB)
+	MOVV $1440, R12
+	JMP  callbackasm1(SB)
+	MOVV $1441, R12
+	JMP  callbackasm1(SB)
+	MOVV $1442, R12
+	JMP  callbackasm1(SB)
+	MOVV $1443, R12
+	JMP  callbackasm1(SB)
+	MOVV $1444, R12
+	JMP  callbackasm1(SB)
+	MOVV $1445, R12
+	JMP  callbackasm1(SB)
+	MOVV $1446, R12
+	JMP  callbackasm1(SB)
+	MOVV $1447, R12
+	JMP  callbackasm1(SB)
+	MOVV $1448, R12
+	JMP  callbackasm1(SB)
+	MOVV $1449, R12
+	JMP  callbackasm1(SB)
+	MOVV $1450, R12
+	JMP  callbackasm1(SB)
+	MOVV $1451, R12
+	JMP  callbackasm1(SB)
+	MOVV $1452, R12
+	JMP  callbackasm1(SB)
+	MOVV $1453, R12
+	JMP  callbackasm1(SB)
+	MOVV $1454, R12
+	JMP  callbackasm1(SB)
+	MOVV $1455, R12
+	JMP  callbackasm1(SB)
+	MOVV $1456, R12
+	JMP  callbackasm1(SB)
+	MOVV $1457, R12
+	JMP  callbackasm1(SB)
+	MOVV $1458, R12
+	JMP  callbackasm1(SB)
+	MOVV $1459, R12
+	JMP  callbackasm1(SB)
+	MOVV $1460, R12
+	JMP  callbackasm1(SB)
+	MOVV $1461, R12
+	JMP  callbackasm1(SB)
+	MOVV $1462, R12
+	JMP  callbackasm1(SB)
+	MOVV $1463, R12
+	JMP  callbackasm1(SB)
+	MOVV $1464, R12
+	JMP  callbackasm1(SB)
+	MOVV $1465, R12
+	JMP  callbackasm1(SB)
+	MOVV $1466, R12
+	JMP  callbackasm1(SB)
+	MOVV $1467, R12
+	JMP  callbackasm1(SB)
+	MOVV $1468, R12
+	JMP  callbackasm1(SB)
+	MOVV $1469, R12
+	JMP  callbackasm1(SB)
+	MOVV $1470, R12
+	JMP  callbackasm1(SB)
+	MOVV $1471, R12
+	JMP  callbackasm1(SB)
+	MOVV $1472, R12
+	JMP  callbackasm1(SB)
+	MOVV $1473, R12
+	JMP  callbackasm1(SB)
+	MOVV $1474, R12
+	JMP  callbackasm1(SB)
+	MOVV $1475, R12
+	JMP  callbackasm1(SB)
+	MOVV $1476, R12
+	JMP  callbackasm1(SB)
+	MOVV $1477, R12
+	JMP  callbackasm1(SB)
+	MOVV $1478, R12
+	JMP  callbackasm1(SB)
+	MOVV $1479, R12
+	JMP  callbackasm1(SB)
+	MOVV $1480, R12
+	JMP  callbackasm1(SB)
+	MOVV $1481, R12
+	JMP  callbackasm1(SB)
+	MOVV $1482, R12
+	JMP  callbackasm1(SB)
+	MOVV $1483, R12
+	JMP  callbackasm1(SB)
+	MOVV $1484, R12
+	JMP  callbackasm1(SB)
+	MOVV $1485, R12
+	JMP  callbackasm1(SB)
+	MOVV $1486, R12
+	JMP  callbackasm1(SB)
+	MOVV $1487, R12
+	JMP  callbackasm1(SB)
+	MOVV $1488, R12
+	JMP  callbackasm1(SB)
+	MOVV $1489, R12
+	JMP  callbackasm1(SB)
+	MOVV $1490, R12
+	JMP  callbackasm1(SB)
+	MOVV $1491, R12
+	JMP  callbackasm1(SB)
+	MOVV $1492, R12
+	JMP  callbackasm1(SB)
+	MOVV $1493, R12
+	JMP  callbackasm1(SB)
+	MOVV $1494, R12
+	JMP  callbackasm1(SB)
+	MOVV $1495, R12
+	JMP  callbackasm1(SB)
+	MOVV $1496, R12
+	JMP  callbackasm1(SB)
+	MOVV $1497, R12
+	JMP  callbackasm1(SB)
+	MOVV $1498, R12
+	JMP  callbackasm1(SB)
+	MOVV $1499, R12
+	JMP  callbackasm1(SB)
+	MOVV $1500, R12
+	JMP  callbackasm1(SB)
+	MOVV $1501, R12
+	JMP  callbackasm1(SB)
+	MOVV $1502, R12
+	JMP  callbackasm1(SB)
+	MOVV $1503, R12
+	JMP  callbackasm1(SB)
+	MOVV $1504, R12
+	JMP  callbackasm1(SB)
+	MOVV $1505, R12
+	JMP  callbackasm1(SB)
+	MOVV $1506, R12
+	JMP  callbackasm1(SB)
+	MOVV $1507, R12
+	JMP  callbackasm1(SB)
+	MOVV $1508, R12
+	JMP  callbackasm1(SB)
+	MOVV $1509, R12
+	JMP  callbackasm1(SB)
+	MOVV $1510, R12
+	JMP  callbackasm1(SB)
+	MOVV $1511, R12
+	JMP  callbackasm1(SB)
+	MOVV $1512, R12
+	JMP  callbackasm1(SB)
+	MOVV $1513, R12
+	JMP  callbackasm1(SB)
+	MOVV $1514, R12
+	JMP  callbackasm1(SB)
+	MOVV $1515, R12
+	JMP  callbackasm1(SB)
+	MOVV $1516, R12
+	JMP  callbackasm1(SB)
+	MOVV $1517, R12
+	JMP  callbackasm1(SB)
+	MOVV $1518, R12
+	JMP  callbackasm1(SB)
+	MOVV $1519, R12
+	JMP  callbackasm1(SB)
+	MOVV $1520, R12
+	JMP  callbackasm1(SB)
+	MOVV $1521, R12
+	JMP  callbackasm1(SB)
+	MOVV $1522, R12
+	JMP  callbackasm1(SB)
+	MOVV $1523, R12
+	JMP  callbackasm1(SB)
+	MOVV $1524, R12
+	JMP  callbackasm1(SB)
+	MOVV $1525, R12
+	JMP  callbackasm1(SB)
+	MOVV $1526, R12
+	JMP  callbackasm1(SB)
+	MOVV $1527, R12
+	JMP  callbackasm1(SB)
+	MOVV $1528, R12
+	JMP  callbackasm1(SB)
+	MOVV $1529, R12
+	JMP  callbackasm1(SB)
+	MOVV $1530, R12
+	JMP  callbackasm1(SB)
+	MOVV $1531, R12
+	JMP  callbackasm1(SB)
+	MOVV $1532, R12
+	JMP  callbackasm1(SB)
+	MOVV $1533, R12
+	JMP  callbackasm1(SB)
+	MOVV $1534, R12
+	JMP  callbackasm1(SB)
+	MOVV $1535, R12
+	JMP  callbackasm1(SB)
+	MOVV $1536, R12
+	JMP  callbackasm1(SB)
+	MOVV $1537, R12
+	JMP  callbackasm1(SB)
+	MOVV $1538, R12
+	JMP  callbackasm1(SB)
+	MOVV $1539, R12
+	JMP  callbackasm1(SB)
+	MOVV $1540, R12
+	JMP  callbackasm1(SB)
+	MOVV $1541, R12
+	JMP  callbackasm1(SB)
+	MOVV $1542, R12
+	JMP  callbackasm1(SB)
+	MOVV $1543, R12
+	JMP  callbackasm1(SB)
+	MOVV $1544, R12
+	JMP  callbackasm1(SB)
+	MOVV $1545, R12
+	JMP  callbackasm1(SB)
+	MOVV $1546, R12
+	JMP  callbackasm1(SB)
+	MOVV $1547, R12
+	JMP  callbackasm1(SB)
+	MOVV $1548, R12
+	JMP  callbackasm1(SB)
+	MOVV $1549, R12
+	JMP  callbackasm1(SB)
+	MOVV $1550, R12
+	JMP  callbackasm1(SB)
+	MOVV $1551, R12
+	JMP  callbackasm1(SB)
+	MOVV $1552, R12
+	JMP  callbackasm1(SB)
+	MOVV $1553, R12
+	JMP  callbackasm1(SB)
+	MOVV $1554, R12
+	JMP  callbackasm1(SB)
+	MOVV $1555, R12
+	JMP  callbackasm1(SB)
+	MOVV $1556, R12
+	JMP  callbackasm1(SB)
+	MOVV $1557, R12
+	JMP  callbackasm1(SB)
+	MOVV $1558, R12
+	JMP  callbackasm1(SB)
+	MOVV $1559, R12
+	JMP  callbackasm1(SB)
+	MOVV $1560, R12
+	JMP  callbackasm1(SB)
+	MOVV $1561, R12
+	JMP  callbackasm1(SB)
+	MOVV $1562, R12
+	JMP  callbackasm1(SB)
+	MOVV $1563, R12
+	JMP  callbackasm1(SB)
+	MOVV $1564, R12
+	JMP  callbackasm1(SB)
+	MOVV $1565, R12
+	JMP  callbackasm1(SB)
+	MOVV $1566, R12
+	JMP  callbackasm1(SB)
+	MOVV $1567, R12
+	JMP  callbackasm1(SB)
+	MOVV $1568, R12
+	JMP  callbackasm1(SB)
+	MOVV $1569, R12
+	JMP  callbackasm1(SB)
+	MOVV $1570, R12
+	JMP  callbackasm1(SB)
+	MOVV $1571, R12
+	JMP  callbackasm1(SB)
+	MOVV $1572, R12
+	JMP  callbackasm1(SB)
+	MOVV $1573, R12
+	JMP  callbackasm1(SB)
+	MOVV $1574, R12
+	JMP  callbackasm1(SB)
+	MOVV $1575, R12
+	JMP  callbackasm1(SB)
+	MOVV $1576, R12
+	JMP  callbackasm1(SB)
+	MOVV $1577, R12
+	JMP  callbackasm1(SB)
+	MOVV $1578, R12
+	JMP  callbackasm1(SB)
+	MOVV $1579, R12
+	JMP  callbackasm1(SB)
+	MOVV $1580, R12
+	JMP  callbackasm1(SB)
+	MOVV $1581, R12
+	JMP  callbackasm1(SB)
+	MOVV $1582, R12
+	JMP  callbackasm1(SB)
+	MOVV $1583, R12
+	JMP  callbackasm1(SB)
+	MOVV $1584, R12
+	JMP  callbackasm1(SB)
+	MOVV $1585, R12
+	JMP  callbackasm1(SB)
+	MOVV $1586, R12
+	JMP  callbackasm1(SB)
+	MOVV $1587, R12
+	JMP  callbackasm1(SB)
+	MOVV $1588, R12
+	JMP  callbackasm1(SB)
+	MOVV $1589, R12
+	JMP  callbackasm1(SB)
+	MOVV $1590, R12
+	JMP  callbackasm1(SB)
+	MOVV $1591, R12
+	JMP  callbackasm1(SB)
+	MOVV $1592, R12
+	JMP  callbackasm1(SB)
+	MOVV $1593, R12
+	JMP  callbackasm1(SB)
+	MOVV $1594, R12
+	JMP  callbackasm1(SB)
+	MOVV $1595, R12
+	JMP  callbackasm1(SB)
+	MOVV $1596, R12
+	JMP  callbackasm1(SB)
+	MOVV $1597, R12
+	JMP  callbackasm1(SB)
+	MOVV $1598, R12
+	JMP  callbackasm1(SB)
+	MOVV $1599, R12
+	JMP  callbackasm1(SB)
+	MOVV $1600, R12
+	JMP  callbackasm1(SB)
+	MOVV $1601, R12
+	JMP  callbackasm1(SB)
+	MOVV $1602, R12
+	JMP  callbackasm1(SB)
+	MOVV $1603, R12
+	JMP  callbackasm1(SB)
+	MOVV $1604, R12
+	JMP  callbackasm1(SB)
+	MOVV $1605, R12
+	JMP  callbackasm1(SB)
+	MOVV $1606, R12
+	JMP  callbackasm1(SB)
+	MOVV $1607, R12
+	JMP  callbackasm1(SB)
+	MOVV $1608, R12
+	JMP  callbackasm1(SB)
+	MOVV $1609, R12
+	JMP  callbackasm1(SB)
+	MOVV $1610, R12
+	JMP  callbackasm1(SB)
+	MOVV $1611, R12
+	JMP  callbackasm1(SB)
+	MOVV $1612, R12
+	JMP  callbackasm1(SB)
+	MOVV $1613, R12
+	JMP  callbackasm1(SB)
+	MOVV $1614, R12
+	JMP  callbackasm1(SB)
+	MOVV $1615, R12
+	JMP  callbackasm1(SB)
+	MOVV $1616, R12
+	JMP  callbackasm1(SB)
+	MOVV $1617, R12
+	JMP  callbackasm1(SB)
+	MOVV $1618, R12
+	JMP  callbackasm1(SB)
+	MOVV $1619, R12
+	JMP  callbackasm1(SB)
+	MOVV $1620, R12
+	JMP  callbackasm1(SB)
+	MOVV $1621, R12
+	JMP  callbackasm1(SB)
+	MOVV $1622, R12
+	JMP  callbackasm1(SB)
+	MOVV $1623, R12
+	JMP  callbackasm1(SB)
+	MOVV $1624, R12
+	JMP  callbackasm1(SB)
+	MOVV $1625, R12
+	JMP  callbackasm1(SB)
+	MOVV $1626, R12
+	JMP  callbackasm1(SB)
+	MOVV $1627, R12
+	JMP  callbackasm1(SB)
+	MOVV $1628, R12
+	JMP  callbackasm1(SB)
+	MOVV $1629, R12
+	JMP  callbackasm1(SB)
+	MOVV $1630, R12
+	JMP  callbackasm1(SB)
+	MOVV $1631, R12
+	JMP  callbackasm1(SB)
+	MOVV $1632, R12
+	JMP  callbackasm1(SB)
+	MOVV $1633, R12
+	JMP  callbackasm1(SB)
+	MOVV $1634, R12
+	JMP  callbackasm1(SB)
+	MOVV $1635, R12
+	JMP  callbackasm1(SB)
+	MOVV $1636, R12
+	JMP  callbackasm1(SB)
+	MOVV $1637, R12
+	JMP  callbackasm1(SB)
+	MOVV $1638, R12
+	JMP  callbackasm1(SB)
+	MOVV $1639, R12
+	JMP  callbackasm1(SB)
+	MOVV $1640, R12
+	JMP  callbackasm1(SB)
+	MOVV $1641, R12
+	JMP  callbackasm1(SB)
+	MOVV $1642, R12
+	JMP  callbackasm1(SB)
+	MOVV $1643, R12
+	JMP  callbackasm1(SB)
+	MOVV $1644, R12
+	JMP  callbackasm1(SB)
+	MOVV $1645, R12
+	JMP  callbackasm1(SB)
+	MOVV $1646, R12
+	JMP  callbackasm1(SB)
+	MOVV $1647, R12
+	JMP  callbackasm1(SB)
+	MOVV $1648, R12
+	JMP  callbackasm1(SB)
+	MOVV $1649, R12
+	JMP  callbackasm1(SB)
+	MOVV $1650, R12
+	JMP  callbackasm1(SB)
+	MOVV $1651, R12
+	JMP  callbackasm1(SB)
+	MOVV $1652, R12
+	JMP  callbackasm1(SB)
+	MOVV $1653, R12
+	JMP  callbackasm1(SB)
+	MOVV $1654, R12
+	JMP  callbackasm1(SB)
+	MOVV $1655, R12
+	JMP  callbackasm1(SB)
+	MOVV $1656, R12
+	JMP  callbackasm1(SB)
+	MOVV $1657, R12
+	JMP  callbackasm1(SB)
+	MOVV $1658, R12
+	JMP  callbackasm1(SB)
+	MOVV $1659, R12
+	JMP  callbackasm1(SB)
+	MOVV $1660, R12
+	JMP  callbackasm1(SB)
+	MOVV $1661, R12
+	JMP  callbackasm1(SB)
+	MOVV $1662, R12
+	JMP  callbackasm1(SB)
+	MOVV $1663, R12
+	JMP  callbackasm1(SB)
+	MOVV $1664, R12
+	JMP  callbackasm1(SB)
+	MOVV $1665, R12
+	JMP  callbackasm1(SB)
+	MOVV $1666, R12
+	JMP  callbackasm1(SB)
+	MOVV $1667, R12
+	JMP  callbackasm1(SB)
+	MOVV $1668, R12
+	JMP  callbackasm1(SB)
+	MOVV $1669, R12
+	JMP  callbackasm1(SB)
+	MOVV $1670, R12
+	JMP  callbackasm1(SB)
+	MOVV $1671, R12
+	JMP  callbackasm1(SB)
+	MOVV $1672, R12
+	JMP  callbackasm1(SB)
+	MOVV $1673, R12
+	JMP  callbackasm1(SB)
+	MOVV $1674, R12
+	JMP  callbackasm1(SB)
+	MOVV $1675, R12
+	JMP  callbackasm1(SB)
+	MOVV $1676, R12
+	JMP  callbackasm1(SB)
+	MOVV $1677, R12
+	JMP  callbackasm1(SB)
+	MOVV $1678, R12
+	JMP  callbackasm1(SB)
+	MOVV $1679, R12
+	JMP  callbackasm1(SB)
+	MOVV $1680, R12
+	JMP  callbackasm1(SB)
+	MOVV $1681, R12
+	JMP  callbackasm1(SB)
+	MOVV $1682, R12
+	JMP  callbackasm1(SB)
+	MOVV $1683, R12
+	JMP  callbackasm1(SB)
+	MOVV $1684, R12
+	JMP  callbackasm1(SB)
+	MOVV $1685, R12
+	JMP  callbackasm1(SB)
+	MOVV $1686, R12
+	JMP  callbackasm1(SB)
+	MOVV $1687, R12
+	JMP  callbackasm1(SB)
+	MOVV $1688, R12
+	JMP  callbackasm1(SB)
+	MOVV $1689, R12
+	JMP  callbackasm1(SB)
+	MOVV $1690, R12
+	JMP  callbackasm1(SB)
+	MOVV $1691, R12
+	JMP  callbackasm1(SB)
+	MOVV $1692, R12
+	JMP  callbackasm1(SB)
+	MOVV $1693, R12
+	JMP  callbackasm1(SB)
+	MOVV $1694, R12
+	JMP  callbackasm1(SB)
+	MOVV $1695, R12
+	JMP  callbackasm1(SB)
+	MOVV $1696, R12
+	JMP  callbackasm1(SB)
+	MOVV $1697, R12
+	JMP  callbackasm1(SB)
+	MOVV $1698, R12
+	JMP  callbackasm1(SB)
+	MOVV $1699, R12
+	JMP  callbackasm1(SB)
+	MOVV $1700, R12
+	JMP  callbackasm1(SB)
+	MOVV $1701, R12
+	JMP  callbackasm1(SB)
+	MOVV $1702, R12
+	JMP  callbackasm1(SB)
+	MOVV $1703, R12
+	JMP  callbackasm1(SB)
+	MOVV $1704, R12
+	JMP  callbackasm1(SB)
+	MOVV $1705, R12
+	JMP  callbackasm1(SB)
+	MOVV $1706, R12
+	JMP  callbackasm1(SB)
+	MOVV $1707, R12
+	JMP  callbackasm1(SB)
+	MOVV $1708, R12
+	JMP  callbackasm1(SB)
+	MOVV $1709, R12
+	JMP  callbackasm1(SB)
+	MOVV $1710, R12
+	JMP  callbackasm1(SB)
+	MOVV $1711, R12
+	JMP  callbackasm1(SB)
+	MOVV $1712, R12
+	JMP  callbackasm1(SB)
+	MOVV $1713, R12
+	JMP  callbackasm1(SB)
+	MOVV $1714, R12
+	JMP  callbackasm1(SB)
+	MOVV $1715, R12
+	JMP  callbackasm1(SB)
+	MOVV $1716, R12
+	JMP  callbackasm1(SB)
+	MOVV $1717, R12
+	JMP  callbackasm1(SB)
+	MOVV $1718, R12
+	JMP  callbackasm1(SB)
+	MOVV $1719, R12
+	JMP  callbackasm1(SB)
+	MOVV $1720, R12
+	JMP  callbackasm1(SB)
+	MOVV $1721, R12
+	JMP  callbackasm1(SB)
+	MOVV $1722, R12
+	JMP  callbackasm1(SB)
+	MOVV $1723, R12
+	JMP  callbackasm1(SB)
+	MOVV $1724, R12
+	JMP  callbackasm1(SB)
+	MOVV $1725, R12
+	JMP  callbackasm1(SB)
+	MOVV $1726, R12
+	JMP  callbackasm1(SB)
+	MOVV $1727, R12
+	JMP  callbackasm1(SB)
+	MOVV $1728, R12
+	JMP  callbackasm1(SB)
+	MOVV $1729, R12
+	JMP  callbackasm1(SB)
+	MOVV $1730, R12
+	JMP  callbackasm1(SB)
+	MOVV $1731, R12
+	JMP  callbackasm1(SB)
+	MOVV $1732, R12
+	JMP  callbackasm1(SB)
+	MOVV $1733, R12
+	JMP  callbackasm1(SB)
+	MOVV $1734, R12
+	JMP  callbackasm1(SB)
+	MOVV $1735, R12
+	JMP  callbackasm1(SB)
+	MOVV $1736, R12
+	JMP  callbackasm1(SB)
+	MOVV $1737, R12
+	JMP  callbackasm1(SB)
+	MOVV $1738, R12
+	JMP  callbackasm1(SB)
+	MOVV $1739, R12
+	JMP  callbackasm1(SB)
+	MOVV $1740, R12
+	JMP  callbackasm1(SB)
+	MOVV $1741, R12
+	JMP  callbackasm1(SB)
+	MOVV $1742, R12
+	JMP  callbackasm1(SB)
+	MOVV $1743, R12
+	JMP  callbackasm1(SB)
+	MOVV $1744, R12
+	JMP  callbackasm1(SB)
+	MOVV $1745, R12
+	JMP  callbackasm1(SB)
+	MOVV $1746, R12
+	JMP  callbackasm1(SB)
+	MOVV $1747, R12
+	JMP  callbackasm1(SB)
+	MOVV $1748, R12
+	JMP  callbackasm1(SB)
+	MOVV $1749, R12
+	JMP  callbackasm1(SB)
+	MOVV $1750, R12
+	JMP  callbackasm1(SB)
+	MOVV $1751, R12
+	JMP  callbackasm1(SB)
+	MOVV $1752, R12
+	JMP  callbackasm1(SB)
+	MOVV $1753, R12
+	JMP  callbackasm1(SB)
+	MOVV $1754, R12
+	JMP  callbackasm1(SB)
+	MOVV $1755, R12
+	JMP  callbackasm1(SB)
+	MOVV $1756, R12
+	JMP  callbackasm1(SB)
+	MOVV $1757, R12
+	JMP  callbackasm1(SB)
+	MOVV $1758, R12
+	JMP  callbackasm1(SB)
+	MOVV $1759, R12
+	JMP  callbackasm1(SB)
+	MOVV $1760, R12
+	JMP  callbackasm1(SB)
+	MOVV $1761, R12
+	JMP  callbackasm1(SB)
+	MOVV $1762, R12
+	JMP  callbackasm1(SB)
+	MOVV $1763, R12
+	JMP  callbackasm1(SB)
+	MOVV $1764, R12
+	JMP  callbackasm1(SB)
+	MOVV $1765, R12
+	JMP  callbackasm1(SB)
+	MOVV $1766, R12
+	JMP  callbackasm1(SB)
+	MOVV $1767, R12
+	JMP  callbackasm1(SB)
+	MOVV $1768, R12
+	JMP  callbackasm1(SB)
+	MOVV $1769, R12
+	JMP  callbackasm1(SB)
+	MOVV $1770, R12
+	JMP  callbackasm1(SB)
+	MOVV $1771, R12
+	JMP  callbackasm1(SB)
+	MOVV $1772, R12
+	JMP  callbackasm1(SB)
+	MOVV $1773, R12
+	JMP  callbackasm1(SB)
+	MOVV $1774, R12
+	JMP  callbackasm1(SB)
+	MOVV $1775, R12
+	JMP  callbackasm1(SB)
+	MOVV $1776, R12
+	JMP  callbackasm1(SB)
+	MOVV $1777, R12
+	JMP  callbackasm1(SB)
+	MOVV $1778, R12
+	JMP  callbackasm1(SB)
+	MOVV $1779, R12
+	JMP  callbackasm1(SB)
+	MOVV $1780, R12
+	JMP  callbackasm1(SB)
+	MOVV $1781, R12
+	JMP  callbackasm1(SB)
+	MOVV $1782, R12
+	JMP  callbackasm1(SB)
+	MOVV $1783, R12
+	JMP  callbackasm1(SB)
+	MOVV $1784, R12
+	JMP  callbackasm1(SB)
+	MOVV $1785, R12
+	JMP  callbackasm1(SB)
+	MOVV $1786, R12
+	JMP  callbackasm1(SB)
+	MOVV $1787, R12
+	JMP  callbackasm1(SB)
+	MOVV $1788, R12
+	JMP  callbackasm1(SB)
+	MOVV $1789, R12
+	JMP  callbackasm1(SB)
+	MOVV $1790, R12
+	JMP  callbackasm1(SB)
+	MOVV $1791, R12
+	JMP  callbackasm1(SB)
+	MOVV $1792, R12
+	JMP  callbackasm1(SB)
+	MOVV $1793, R12
+	JMP  callbackasm1(SB)
+	MOVV $1794, R12
+	JMP  callbackasm1(SB)
+	MOVV $1795, R12
+	JMP  callbackasm1(SB)
+	MOVV $1796, R12
+	JMP  callbackasm1(SB)
+	MOVV $1797, R12
+	JMP  callbackasm1(SB)
+	MOVV $1798, R12
+	JMP  callbackasm1(SB)
+	MOVV $1799, R12
+	JMP  callbackasm1(SB)
+	MOVV $1800, R12
+	JMP  callbackasm1(SB)
+	MOVV $1801, R12
+	JMP  callbackasm1(SB)
+	MOVV $1802, R12
+	JMP  callbackasm1(SB)
+	MOVV $1803, R12
+	JMP  callbackasm1(SB)
+	MOVV $1804, R12
+	JMP  callbackasm1(SB)
+	MOVV $1805, R12
+	JMP  callbackasm1(SB)
+	MOVV $1806, R12
+	JMP  callbackasm1(SB)
+	MOVV $1807, R12
+	JMP  callbackasm1(SB)
+	MOVV $1808, R12
+	JMP  callbackasm1(SB)
+	MOVV $1809, R12
+	JMP  callbackasm1(SB)
+	MOVV $1810, R12
+	JMP  callbackasm1(SB)
+	MOVV $1811, R12
+	JMP  callbackasm1(SB)
+	MOVV $1812, R12
+	JMP  callbackasm1(SB)
+	MOVV $1813, R12
+	JMP  callbackasm1(SB)
+	MOVV $1814, R12
+	JMP  callbackasm1(SB)
+	MOVV $1815, R12
+	JMP  callbackasm1(SB)
+	MOVV $1816, R12
+	JMP  callbackasm1(SB)
+	MOVV $1817, R12
+	JMP  callbackasm1(SB)
+	MOVV $1818, R12
+	JMP  callbackasm1(SB)
+	MOVV $1819, R12
+	JMP  callbackasm1(SB)
+	MOVV $1820, R12
+	JMP  callbackasm1(SB)
+	MOVV $1821, R12
+	JMP  callbackasm1(SB)
+	MOVV $1822, R12
+	JMP  callbackasm1(SB)
+	MOVV $1823, R12
+	JMP  callbackasm1(SB)
+	MOVV $1824, R12
+	JMP  callbackasm1(SB)
+	MOVV $1825, R12
+	JMP  callbackasm1(SB)
+	MOVV $1826, R12
+	JMP  callbackasm1(SB)
+	MOVV $1827, R12
+	JMP  callbackasm1(SB)
+	MOVV $1828, R12
+	JMP  callbackasm1(SB)
+	MOVV $1829, R12
+	JMP  callbackasm1(SB)
+	MOVV $1830, R12
+	JMP  callbackasm1(SB)
+	MOVV $1831, R12
+	JMP  callbackasm1(SB)
+	MOVV $1832, R12
+	JMP  callbackasm1(SB)
+	MOVV $1833, R12
+	JMP  callbackasm1(SB)
+	MOVV $1834, R12
+	JMP  callbackasm1(SB)
+	MOVV $1835, R12
+	JMP  callbackasm1(SB)
+	MOVV $1836, R12
+	JMP  callbackasm1(SB)
+	MOVV $1837, R12
+	JMP  callbackasm1(SB)
+	MOVV $1838, R12
+	JMP  callbackasm1(SB)
+	MOVV $1839, R12
+	JMP  callbackasm1(SB)
+	MOVV $1840, R12
+	JMP  callbackasm1(SB)
+	MOVV $1841, R12
+	JMP  callbackasm1(SB)
+	MOVV $1842, R12
+	JMP  callbackasm1(SB)
+	MOVV $1843, R12
+	JMP  callbackasm1(SB)
+	MOVV $1844, R12
+	JMP  callbackasm1(SB)
+	MOVV $1845, R12
+	JMP  callbackasm1(SB)
+	MOVV $1846, R12
+	JMP  callbackasm1(SB)
+	MOVV $1847, R12
+	JMP  callbackasm1(SB)
+	MOVV $1848, R12
+	JMP  callbackasm1(SB)
+	MOVV $1849, R12
+	JMP  callbackasm1(SB)
+	MOVV $1850, R12
+	JMP  callbackasm1(SB)
+	MOVV $1851, R12
+	JMP  callbackasm1(SB)
+	MOVV $1852, R12
+	JMP  callbackasm1(SB)
+	MOVV $1853, R12
+	JMP  callbackasm1(SB)
+	MOVV $1854, R12
+	JMP  callbackasm1(SB)
+	MOVV $1855, R12
+	JMP  callbackasm1(SB)
+	MOVV $1856, R12
+	JMP  callbackasm1(SB)
+	MOVV $1857, R12
+	JMP  callbackasm1(SB)
+	MOVV $1858, R12
+	JMP  callbackasm1(SB)
+	MOVV $1859, R12
+	JMP  callbackasm1(SB)
+	MOVV $1860, R12
+	JMP  callbackasm1(SB)
+	MOVV $1861, R12
+	JMP  callbackasm1(SB)
+	MOVV $1862, R12
+	JMP  callbackasm1(SB)
+	MOVV $1863, R12
+	JMP  callbackasm1(SB)
+	MOVV $1864, R12
+	JMP  callbackasm1(SB)
+	MOVV $1865, R12
+	JMP  callbackasm1(SB)
+	MOVV $1866, R12
+	JMP  callbackasm1(SB)
+	MOVV $1867, R12
+	JMP  callbackasm1(SB)
+	MOVV $1868, R12
+	JMP  callbackasm1(SB)
+	MOVV $1869, R12
+	JMP  callbackasm1(SB)
+	MOVV $1870, R12
+	JMP  callbackasm1(SB)
+	MOVV $1871, R12
+	JMP  callbackasm1(SB)
+	MOVV $1872, R12
+	JMP  callbackasm1(SB)
+	MOVV $1873, R12
+	JMP  callbackasm1(SB)
+	MOVV $1874, R12
+	JMP  callbackasm1(SB)
+	MOVV $1875, R12
+	JMP  callbackasm1(SB)
+	MOVV $1876, R12
+	JMP  callbackasm1(SB)
+	MOVV $1877, R12
+	JMP  callbackasm1(SB)
+	MOVV $1878, R12
+	JMP  callbackasm1(SB)
+	MOVV $1879, R12
+	JMP  callbackasm1(SB)
+	MOVV $1880, R12
+	JMP  callbackasm1(SB)
+	MOVV $1881, R12
+	JMP  callbackasm1(SB)
+	MOVV $1882, R12
+	JMP  callbackasm1(SB)
+	MOVV $1883, R12
+	JMP  callbackasm1(SB)
+	MOVV $1884, R12
+	JMP  callbackasm1(SB)
+	MOVV $1885, R12
+	JMP  callbackasm1(SB)
+	MOVV $1886, R12
+	JMP  callbackasm1(SB)
+	MOVV $1887, R12
+	JMP  callbackasm1(SB)
+	MOVV $1888, R12
+	JMP  callbackasm1(SB)
+	MOVV $1889, R12
+	JMP  callbackasm1(SB)
+	MOVV $1890, R12
+	JMP  callbackasm1(SB)
+	MOVV $1891, R12
+	JMP  callbackasm1(SB)
+	MOVV $1892, R12
+	JMP  callbackasm1(SB)
+	MOVV $1893, R12
+	JMP  callbackasm1(SB)
+	MOVV $1894, R12
+	JMP  callbackasm1(SB)
+	MOVV $1895, R12
+	JMP  callbackasm1(SB)
+	MOVV $1896, R12
+	JMP  callbackasm1(SB)
+	MOVV $1897, R12
+	JMP  callbackasm1(SB)
+	MOVV $1898, R12
+	JMP  callbackasm1(SB)
+	MOVV $1899, R12
+	JMP  callbackasm1(SB)
+	MOVV $1900, R12
+	JMP  callbackasm1(SB)
+	MOVV $1901, R12
+	JMP  callbackasm1(SB)
+	MOVV $1902, R12
+	JMP  callbackasm1(SB)
+	MOVV $1903, R12
+	JMP  callbackasm1(SB)
+	MOVV $1904, R12
+	JMP  callbackasm1(SB)
+	MOVV $1905, R12
+	JMP  callbackasm1(SB)
+	MOVV $1906, R12
+	JMP  callbackasm1(SB)
+	MOVV $1907, R12
+	JMP  callbackasm1(SB)
+	MOVV $1908, R12
+	JMP  callbackasm1(SB)
+	MOVV $1909, R12
+	JMP  callbackasm1(SB)
+	MOVV $1910, R12
+	JMP  callbackasm1(SB)
+	MOVV $1911, R12
+	JMP  callbackasm1(SB)
+	MOVV $1912, R12
+	JMP  callbackasm1(SB)
+	MOVV $1913, R12
+	JMP  callbackasm1(SB)
+	MOVV $1914, R12
+	JMP  callbackasm1(SB)
+	MOVV $1915, R12
+	JMP  callbackasm1(SB)
+	MOVV $1916, R12
+	JMP  callbackasm1(SB)
+	MOVV $1917, R12
+	JMP  callbackasm1(SB)
+	MOVV $1918, R12
+	JMP  callbackasm1(SB)
+	MOVV $1919, R12
+	JMP  callbackasm1(SB)
+	MOVV $1920, R12
+	JMP  callbackasm1(SB)
+	MOVV $1921, R12
+	JMP  callbackasm1(SB)
+	MOVV $1922, R12
+	JMP  callbackasm1(SB)
+	MOVV $1923, R12
+	JMP  callbackasm1(SB)
+	MOVV $1924, R12
+	JMP  callbackasm1(SB)
+	MOVV $1925, R12
+	JMP  callbackasm1(SB)
+	MOVV $1926, R12
+	JMP  callbackasm1(SB)
+	MOVV $1927, R12
+	JMP  callbackasm1(SB)
+	MOVV $1928, R12
+	JMP  callbackasm1(SB)
+	MOVV $1929, R12
+	JMP  callbackasm1(SB)
+	MOVV $1930, R12
+	JMP  callbackasm1(SB)
+	MOVV $1931, R12
+	JMP  callbackasm1(SB)
+	MOVV $1932, R12
+	JMP  callbackasm1(SB)
+	MOVV $1933, R12
+	JMP  callbackasm1(SB)
+	MOVV $1934, R12
+	JMP  callbackasm1(SB)
+	MOVV $1935, R12
+	JMP  callbackasm1(SB)
+	MOVV $1936, R12
+	JMP  callbackasm1(SB)
+	MOVV $1937, R12
+	JMP  callbackasm1(SB)
+	MOVV $1938, R12
+	JMP  callbackasm1(SB)
+	MOVV $1939, R12
+	JMP  callbackasm1(SB)
+	MOVV $1940, R12
+	JMP  callbackasm1(SB)
+	MOVV $1941, R12
+	JMP  callbackasm1(SB)
+	MOVV $1942, R12
+	JMP  callbackasm1(SB)
+	MOVV $1943, R12
+	JMP  callbackasm1(SB)
+	MOVV $1944, R12
+	JMP  callbackasm1(SB)
+	MOVV $1945, R12
+	JMP  callbackasm1(SB)
+	MOVV $1946, R12
+	JMP  callbackasm1(SB)
+	MOVV $1947, R12
+	JMP  callbackasm1(SB)
+	MOVV $1948, R12
+	JMP  callbackasm1(SB)
+	MOVV $1949, R12
+	JMP  callbackasm1(SB)
+	MOVV $1950, R12
+	JMP  callbackasm1(SB)
+	MOVV $1951, R12
+	JMP  callbackasm1(SB)
+	MOVV $1952, R12
+	JMP  callbackasm1(SB)
+	MOVV $1953, R12
+	JMP  callbackasm1(SB)
+	MOVV $1954, R12
+	JMP  callbackasm1(SB)
+	MOVV $1955, R12
+	JMP  callbackasm1(SB)
+	MOVV $1956, R12
+	JMP  callbackasm1(SB)
+	MOVV $1957, R12
+	JMP  callbackasm1(SB)
+	MOVV $1958, R12
+	JMP  callbackasm1(SB)
+	MOVV $1959, R12
+	JMP  callbackasm1(SB)
+	MOVV $1960, R12
+	JMP  callbackasm1(SB)
+	MOVV $1961, R12
+	JMP  callbackasm1(SB)
+	MOVV $1962, R12
+	JMP  callbackasm1(SB)
+	MOVV $1963, R12
+	JMP  callbackasm1(SB)
+	MOVV $1964, R12
+	JMP  callbackasm1(SB)
+	MOVV $1965, R12
+	JMP  callbackasm1(SB)
+	MOVV $1966, R12
+	JMP  callbackasm1(SB)
+	MOVV $1967, R12
+	JMP  callbackasm1(SB)
+	MOVV $1968, R12
+	JMP  callbackasm1(SB)
+	MOVV $1969, R12
+	JMP  callbackasm1(SB)
+	MOVV $1970, R12
+	JMP  callbackasm1(SB)
+	MOVV $1971, R12
+	JMP  callbackasm1(SB)
+	MOVV $1972, R12
+	JMP  callbackasm1(SB)
+	MOVV $1973, R12
+	JMP  callbackasm1(SB)
+	MOVV $1974, R12
+	JMP  callbackasm1(SB)
+	MOVV $1975, R12
+	JMP  callbackasm1(SB)
+	MOVV $1976, R12
+	JMP  callbackasm1(SB)
+	MOVV $1977, R12
+	JMP  callbackasm1(SB)
+	MOVV $1978, R12
+	JMP  callbackasm1(SB)
+	MOVV $1979, R12
+	JMP  callbackasm1(SB)
+	MOVV $1980, R12
+	JMP  callbackasm1(SB)
+	MOVV $1981, R12
+	JMP  callbackasm1(SB)
+	MOVV $1982, R12
+	JMP  callbackasm1(SB)
+	MOVV $1983, R12
+	JMP  callbackasm1(SB)
+	MOVV $1984, R12
+	JMP  callbackasm1(SB)
+	MOVV $1985, R12
+	JMP  callbackasm1(SB)
+	MOVV $1986, R12
+	JMP  callbackasm1(SB)
+	MOVV $1987, R12
+	JMP  callbackasm1(SB)
+	MOVV $1988, R12
+	JMP  callbackasm1(SB)
+	MOVV $1989, R12
+	JMP  callbackasm1(SB)
+	MOVV $1990, R12
+	JMP  callbackasm1(SB)
+	MOVV $1991, R12
+	JMP  callbackasm1(SB)
+	MOVV $1992, R12
+	JMP  callbackasm1(SB)
+	MOVV $1993, R12
+	JMP  callbackasm1(SB)
+	MOVV $1994, R12
+	JMP  callbackasm1(SB)
+	MOVV $1995, R12
+	JMP  callbackasm1(SB)
+	MOVV $1996, R12
+	JMP  callbackasm1(SB)
+	MOVV $1997, R12
+	JMP  callbackasm1(SB)
+	MOVV $1998, R12
+	JMP  callbackasm1(SB)
+	MOVV $1999, R12
+	JMP  callbackasm1(SB)
diff --git a/vendor/github.com/ebitengine/purego/zcallback_ppc64le.s b/vendor/github.com/ebitengine/purego/zcallback_ppc64le.s
new file mode 100644
index 000000000..702243b1e
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/zcallback_ppc64le.s
@@ -0,0 +1,4014 @@
+// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+
+//go:build linux
+
+// External code calls into callbackasm at an offset corresponding
+// to the callback index. Callbackasm is a table of MOVD and BR instructions.
+// The MOVD instruction loads R11 with the callback index, and the
+// BR instruction branches to callbackasm1.
+// callbackasm1 takes the callback index from R11 and
+// indexes into an array that stores information about each callback.
+// It then calls the Go implementation for that callback.
+#include "textflag.h"
+
+TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
+	MOVD $0, R11
+	BR   callbackasm1(SB)
+	MOVD $1, R11
+	BR   callbackasm1(SB)
+	MOVD $2, R11
+	BR   callbackasm1(SB)
+	MOVD $3, R11
+	BR   callbackasm1(SB)
+	MOVD $4, R11
+	BR   callbackasm1(SB)
+	MOVD $5, R11
+	BR   callbackasm1(SB)
+	MOVD $6, R11
+	BR   callbackasm1(SB)
+	MOVD $7, R11
+	BR   callbackasm1(SB)
+	MOVD $8, R11
+	BR   callbackasm1(SB)
+	MOVD $9, R11
+	BR   callbackasm1(SB)
+	MOVD $10, R11
+	BR   callbackasm1(SB)
+	MOVD $11, R11
+	BR   callbackasm1(SB)
+	MOVD $12, R11
+	BR   callbackasm1(SB)
+	MOVD $13, R11
+	BR   callbackasm1(SB)
+	MOVD $14, R11
+	BR   callbackasm1(SB)
+	MOVD $15, R11
+	BR   callbackasm1(SB)
+	MOVD $16, R11
+	BR   callbackasm1(SB)
+	MOVD $17, R11
+	BR   callbackasm1(SB)
+	MOVD $18, R11
+	BR   callbackasm1(SB)
+	MOVD $19, R11
+	BR   callbackasm1(SB)
+	MOVD $20, R11
+	BR   callbackasm1(SB)
+	MOVD $21, R11
+	BR   callbackasm1(SB)
+	MOVD $22, R11
+	BR   callbackasm1(SB)
+	MOVD $23, R11
+	BR   callbackasm1(SB)
+	MOVD $24, R11
+	BR   callbackasm1(SB)
+	MOVD $25, R11
+	BR   callbackasm1(SB)
+	MOVD $26, R11
+	BR   callbackasm1(SB)
+	MOVD $27, R11
+	BR   callbackasm1(SB)
+	MOVD $28, R11
+	BR   callbackasm1(SB)
+	MOVD $29, R11
+	BR   callbackasm1(SB)
+	MOVD $30, R11
+	BR   callbackasm1(SB)
+	MOVD $31, R11
+	BR   callbackasm1(SB)
+	MOVD $32, R11
+	BR   callbackasm1(SB)
+	MOVD $33, R11
+	BR   callbackasm1(SB)
+	MOVD $34, R11
+	BR   callbackasm1(SB)
+	MOVD $35, R11
+	BR   callbackasm1(SB)
+	MOVD $36, R11
+	BR   callbackasm1(SB)
+	MOVD $37, R11
+	BR   callbackasm1(SB)
+	MOVD $38, R11
+	BR   callbackasm1(SB)
+	MOVD $39, R11
+	BR   callbackasm1(SB)
+	MOVD $40, R11
+	BR   callbackasm1(SB)
+	MOVD $41, R11
+	BR   callbackasm1(SB)
+	MOVD $42, R11
+	BR   callbackasm1(SB)
+	MOVD $43, R11
+	BR   callbackasm1(SB)
+	MOVD $44, R11
+	BR   callbackasm1(SB)
+	MOVD $45, R11
+	BR   callbackasm1(SB)
+	MOVD $46, R11
+	BR   callbackasm1(SB)
+	MOVD $47, R11
+	BR   callbackasm1(SB)
+	MOVD $48, R11
+	BR   callbackasm1(SB)
+	MOVD $49, R11
+	BR   callbackasm1(SB)
+	MOVD $50, R11
+	BR   callbackasm1(SB)
+	MOVD $51, R11
+	BR   callbackasm1(SB)
+	MOVD $52, R11
+	BR   callbackasm1(SB)
+	MOVD $53, R11
+	BR   callbackasm1(SB)
+	MOVD $54, R11
+	BR   callbackasm1(SB)
+	MOVD $55, R11
+	BR   callbackasm1(SB)
+	MOVD $56, R11
+	BR   callbackasm1(SB)
+	MOVD $57, R11
+	BR   callbackasm1(SB)
+	MOVD $58, R11
+	BR   callbackasm1(SB)
+	MOVD $59, R11
+	BR   callbackasm1(SB)
+	MOVD $60, R11
+	BR   callbackasm1(SB)
+	MOVD $61, R11
+	BR   callbackasm1(SB)
+	MOVD $62, R11
+	BR   callbackasm1(SB)
+	MOVD $63, R11
+	BR   callbackasm1(SB)
+	MOVD $64, R11
+	BR   callbackasm1(SB)
+	MOVD $65, R11
+	BR   callbackasm1(SB)
+	MOVD $66, R11
+	BR   callbackasm1(SB)
+	MOVD $67, R11
+	BR   callbackasm1(SB)
+	MOVD $68, R11
+	BR   callbackasm1(SB)
+	MOVD $69, R11
+	BR   callbackasm1(SB)
+	MOVD $70, R11
+	BR   callbackasm1(SB)
+	MOVD $71, R11
+	BR   callbackasm1(SB)
+	MOVD $72, R11
+	BR   callbackasm1(SB)
+	MOVD $73, R11
+	BR   callbackasm1(SB)
+	MOVD $74, R11
+	BR   callbackasm1(SB)
+	MOVD $75, R11
+	BR   callbackasm1(SB)
+	MOVD $76, R11
+	BR   callbackasm1(SB)
+	MOVD $77, R11
+	BR   callbackasm1(SB)
+	MOVD $78, R11
+	BR   callbackasm1(SB)
+	MOVD $79, R11
+	BR   callbackasm1(SB)
+	MOVD $80, R11
+	BR   callbackasm1(SB)
+	MOVD $81, R11
+	BR   callbackasm1(SB)
+	MOVD $82, R11
+	BR   callbackasm1(SB)
+	MOVD $83, R11
+	BR   callbackasm1(SB)
+	MOVD $84, R11
+	BR   callbackasm1(SB)
+	MOVD $85, R11
+	BR   callbackasm1(SB)
+	MOVD $86, R11
+	BR   callbackasm1(SB)
+	MOVD $87, R11
+	BR   callbackasm1(SB)
+	MOVD $88, R11
+	BR   callbackasm1(SB)
+	MOVD $89, R11
+	BR   callbackasm1(SB)
+	MOVD $90, R11
+	BR   callbackasm1(SB)
+	MOVD $91, R11
+	BR   callbackasm1(SB)
+	MOVD $92, R11
+	BR   callbackasm1(SB)
+	MOVD $93, R11
+	BR   callbackasm1(SB)
+	MOVD $94, R11
+	BR   callbackasm1(SB)
+	MOVD $95, R11
+	BR   callbackasm1(SB)
+	MOVD $96, R11
+	BR   callbackasm1(SB)
+	MOVD $97, R11
+	BR   callbackasm1(SB)
+	MOVD $98, R11
+	BR   callbackasm1(SB)
+	MOVD $99, R11
+	BR   callbackasm1(SB)
+	MOVD $100, R11
+	BR   callbackasm1(SB)
+	MOVD $101, R11
+	BR   callbackasm1(SB)
+	MOVD $102, R11
+	BR   callbackasm1(SB)
+	MOVD $103, R11
+	BR   callbackasm1(SB)
+	MOVD $104, R11
+	BR   callbackasm1(SB)
+	MOVD $105, R11
+	BR   callbackasm1(SB)
+	MOVD $106, R11
+	BR   callbackasm1(SB)
+	MOVD $107, R11
+	BR   callbackasm1(SB)
+	MOVD $108, R11
+	BR   callbackasm1(SB)
+	MOVD $109, R11
+	BR   callbackasm1(SB)
+	MOVD $110, R11
+	BR   callbackasm1(SB)
+	MOVD $111, R11
+	BR   callbackasm1(SB)
+	MOVD $112, R11
+	BR   callbackasm1(SB)
+	MOVD $113, R11
+	BR   callbackasm1(SB)
+	MOVD $114, R11
+	BR   callbackasm1(SB)
+	MOVD $115, R11
+	BR   callbackasm1(SB)
+	MOVD $116, R11
+	BR   callbackasm1(SB)
+	MOVD $117, R11
+	BR   callbackasm1(SB)
+	MOVD $118, R11
+	BR   callbackasm1(SB)
+	MOVD $119, R11
+	BR   callbackasm1(SB)
+	MOVD $120, R11
+	BR   callbackasm1(SB)
+	MOVD $121, R11
+	BR   callbackasm1(SB)
+	MOVD $122, R11
+	BR   callbackasm1(SB)
+	MOVD $123, R11
+	BR   callbackasm1(SB)
+	MOVD $124, R11
+	BR   callbackasm1(SB)
+	MOVD $125, R11
+	BR   callbackasm1(SB)
+	MOVD $126, R11
+	BR   callbackasm1(SB)
+	MOVD $127, R11
+	BR   callbackasm1(SB)
+	MOVD $128, R11
+	BR   callbackasm1(SB)
+	MOVD $129, R11
+	BR   callbackasm1(SB)
+	MOVD $130, R11
+	BR   callbackasm1(SB)
+	MOVD $131, R11
+	BR   callbackasm1(SB)
+	MOVD $132, R11
+	BR   callbackasm1(SB)
+	MOVD $133, R11
+	BR   callbackasm1(SB)
+	MOVD $134, R11
+	BR   callbackasm1(SB)
+	MOVD $135, R11
+	BR   callbackasm1(SB)
+	MOVD $136, R11
+	BR   callbackasm1(SB)
+	MOVD $137, R11
+	BR   callbackasm1(SB)
+	MOVD $138, R11
+	BR   callbackasm1(SB)
+	MOVD $139, R11
+	BR   callbackasm1(SB)
+	MOVD $140, R11
+	BR   callbackasm1(SB)
+	MOVD $141, R11
+	BR   callbackasm1(SB)
+	MOVD $142, R11
+	BR   callbackasm1(SB)
+	MOVD $143, R11
+	BR   callbackasm1(SB)
+	MOVD $144, R11
+	BR   callbackasm1(SB)
+	MOVD $145, R11
+	BR   callbackasm1(SB)
+	MOVD $146, R11
+	BR   callbackasm1(SB)
+	MOVD $147, R11
+	BR   callbackasm1(SB)
+	MOVD $148, R11
+	BR   callbackasm1(SB)
+	MOVD $149, R11
+	BR   callbackasm1(SB)
+	MOVD $150, R11
+	BR   callbackasm1(SB)
+	MOVD $151, R11
+	BR   callbackasm1(SB)
+	MOVD $152, R11
+	BR   callbackasm1(SB)
+	MOVD $153, R11
+	BR   callbackasm1(SB)
+	MOVD $154, R11
+	BR   callbackasm1(SB)
+	MOVD $155, R11
+	BR   callbackasm1(SB)
+	MOVD $156, R11
+	BR   callbackasm1(SB)
+	MOVD $157, R11
+	BR   callbackasm1(SB)
+	MOVD $158, R11
+	BR   callbackasm1(SB)
+	MOVD $159, R11
+	BR   callbackasm1(SB)
+	MOVD $160, R11
+	BR   callbackasm1(SB)
+	MOVD $161, R11
+	BR   callbackasm1(SB)
+	MOVD $162, R11
+	BR   callbackasm1(SB)
+	MOVD $163, R11
+	BR   callbackasm1(SB)
+	MOVD $164, R11
+	BR   callbackasm1(SB)
+	MOVD $165, R11
+	BR   callbackasm1(SB)
+	MOVD $166, R11
+	BR   callbackasm1(SB)
+	MOVD $167, R11
+	BR   callbackasm1(SB)
+	MOVD $168, R11
+	BR   callbackasm1(SB)
+	MOVD $169, R11
+	BR   callbackasm1(SB)
+	MOVD $170, R11
+	BR   callbackasm1(SB)
+	MOVD $171, R11
+	BR   callbackasm1(SB)
+	MOVD $172, R11
+	BR   callbackasm1(SB)
+	MOVD $173, R11
+	BR   callbackasm1(SB)
+	MOVD $174, R11
+	BR   callbackasm1(SB)
+	MOVD $175, R11
+	BR   callbackasm1(SB)
+	MOVD $176, R11
+	BR   callbackasm1(SB)
+	MOVD $177, R11
+	BR   callbackasm1(SB)
+	MOVD $178, R11
+	BR   callbackasm1(SB)
+	MOVD $179, R11
+	BR   callbackasm1(SB)
+	MOVD $180, R11
+	BR   callbackasm1(SB)
+	MOVD $181, R11
+	BR   callbackasm1(SB)
+	MOVD $182, R11
+	BR   callbackasm1(SB)
+	MOVD $183, R11
+	BR   callbackasm1(SB)
+	MOVD $184, R11
+	BR   callbackasm1(SB)
+	MOVD $185, R11
+	BR   callbackasm1(SB)
+	MOVD $186, R11
+	BR   callbackasm1(SB)
+	MOVD $187, R11
+	BR   callbackasm1(SB)
+	MOVD $188, R11
+	BR   callbackasm1(SB)
+	MOVD $189, R11
+	BR   callbackasm1(SB)
+	MOVD $190, R11
+	BR   callbackasm1(SB)
+	MOVD $191, R11
+	BR   callbackasm1(SB)
+	MOVD $192, R11
+	BR   callbackasm1(SB)
+	MOVD $193, R11
+	BR   callbackasm1(SB)
+	MOVD $194, R11
+	BR   callbackasm1(SB)
+	MOVD $195, R11
+	BR   callbackasm1(SB)
+	MOVD $196, R11
+	BR   callbackasm1(SB)
+	MOVD $197, R11
+	BR   callbackasm1(SB)
+	MOVD $198, R11
+	BR   callbackasm1(SB)
+	MOVD $199, R11
+	BR   callbackasm1(SB)
+	MOVD $200, R11
+	BR   callbackasm1(SB)
+	MOVD $201, R11
+	BR   callbackasm1(SB)
+	MOVD $202, R11
+	BR   callbackasm1(SB)
+	MOVD $203, R11
+	BR   callbackasm1(SB)
+	MOVD $204, R11
+	BR   callbackasm1(SB)
+	MOVD $205, R11
+	BR   callbackasm1(SB)
+	MOVD $206, R11
+	BR   callbackasm1(SB)
+	MOVD $207, R11
+	BR   callbackasm1(SB)
+	MOVD $208, R11
+	BR   callbackasm1(SB)
+	MOVD $209, R11
+	BR   callbackasm1(SB)
+	MOVD $210, R11
+	BR   callbackasm1(SB)
+	MOVD $211, R11
+	BR   callbackasm1(SB)
+	MOVD $212, R11
+	BR   callbackasm1(SB)
+	MOVD $213, R11
+	BR   callbackasm1(SB)
+	MOVD $214, R11
+	BR   callbackasm1(SB)
+	MOVD $215, R11
+	BR   callbackasm1(SB)
+	MOVD $216, R11
+	BR   callbackasm1(SB)
+	MOVD $217, R11
+	BR   callbackasm1(SB)
+	MOVD $218, R11
+	BR   callbackasm1(SB)
+	MOVD $219, R11
+	BR   callbackasm1(SB)
+	MOVD $220, R11
+	BR   callbackasm1(SB)
+	MOVD $221, R11
+	BR   callbackasm1(SB)
+	MOVD $222, R11
+	BR   callbackasm1(SB)
+	MOVD $223, R11
+	BR   callbackasm1(SB)
+	MOVD $224, R11
+	BR   callbackasm1(SB)
+	MOVD $225, R11
+	BR   callbackasm1(SB)
+	MOVD $226, R11
+	BR   callbackasm1(SB)
+	MOVD $227, R11
+	BR   callbackasm1(SB)
+	MOVD $228, R11
+	BR   callbackasm1(SB)
+	MOVD $229, R11
+	BR   callbackasm1(SB)
+	MOVD $230, R11
+	BR   callbackasm1(SB)
+	MOVD $231, R11
+	BR   callbackasm1(SB)
+	MOVD $232, R11
+	BR   callbackasm1(SB)
+	MOVD $233, R11
+	BR   callbackasm1(SB)
+	MOVD $234, R11
+	BR   callbackasm1(SB)
+	MOVD $235, R11
+	BR   callbackasm1(SB)
+	MOVD $236, R11
+	BR   callbackasm1(SB)
+	MOVD $237, R11
+	BR   callbackasm1(SB)
+	MOVD $238, R11
+	BR   callbackasm1(SB)
+	MOVD $239, R11
+	BR   callbackasm1(SB)
+	MOVD $240, R11
+	BR   callbackasm1(SB)
+	MOVD $241, R11
+	BR   callbackasm1(SB)
+	MOVD $242, R11
+	BR   callbackasm1(SB)
+	MOVD $243, R11
+	BR   callbackasm1(SB)
+	MOVD $244, R11
+	BR   callbackasm1(SB)
+	MOVD $245, R11
+	BR   callbackasm1(SB)
+	MOVD $246, R11
+	BR   callbackasm1(SB)
+	MOVD $247, R11
+	BR   callbackasm1(SB)
+	MOVD $248, R11
+	BR   callbackasm1(SB)
+	MOVD $249, R11
+	BR   callbackasm1(SB)
+	MOVD $250, R11
+	BR   callbackasm1(SB)
+	MOVD $251, R11
+	BR   callbackasm1(SB)
+	MOVD $252, R11
+	BR   callbackasm1(SB)
+	MOVD $253, R11
+	BR   callbackasm1(SB)
+	MOVD $254, R11
+	BR   callbackasm1(SB)
+	MOVD $255, R11
+	BR   callbackasm1(SB)
+	MOVD $256, R11
+	BR   callbackasm1(SB)
+	MOVD $257, R11
+	BR   callbackasm1(SB)
+	MOVD $258, R11
+	BR   callbackasm1(SB)
+	MOVD $259, R11
+	BR   callbackasm1(SB)
+	MOVD $260, R11
+	BR   callbackasm1(SB)
+	MOVD $261, R11
+	BR   callbackasm1(SB)
+	MOVD $262, R11
+	BR   callbackasm1(SB)
+	MOVD $263, R11
+	BR   callbackasm1(SB)
+	MOVD $264, R11
+	BR   callbackasm1(SB)
+	MOVD $265, R11
+	BR   callbackasm1(SB)
+	MOVD $266, R11
+	BR   callbackasm1(SB)
+	MOVD $267, R11
+	BR   callbackasm1(SB)
+	MOVD $268, R11
+	BR   callbackasm1(SB)
+	MOVD $269, R11
+	BR   callbackasm1(SB)
+	MOVD $270, R11
+	BR   callbackasm1(SB)
+	MOVD $271, R11
+	BR   callbackasm1(SB)
+	MOVD $272, R11
+	BR   callbackasm1(SB)
+	MOVD $273, R11
+	BR   callbackasm1(SB)
+	MOVD $274, R11
+	BR   callbackasm1(SB)
+	MOVD $275, R11
+	BR   callbackasm1(SB)
+	MOVD $276, R11
+	BR   callbackasm1(SB)
+	MOVD $277, R11
+	BR   callbackasm1(SB)
+	MOVD $278, R11
+	BR   callbackasm1(SB)
+	MOVD $279, R11
+	BR   callbackasm1(SB)
+	MOVD $280, R11
+	BR   callbackasm1(SB)
+	MOVD $281, R11
+	BR   callbackasm1(SB)
+	MOVD $282, R11
+	BR   callbackasm1(SB)
+	MOVD $283, R11
+	BR   callbackasm1(SB)
+	MOVD $284, R11
+	BR   callbackasm1(SB)
+	MOVD $285, R11
+	BR   callbackasm1(SB)
+	MOVD $286, R11
+	BR   callbackasm1(SB)
+	MOVD $287, R11
+	BR   callbackasm1(SB)
+	MOVD $288, R11
+	BR   callbackasm1(SB)
+	MOVD $289, R11
+	BR   callbackasm1(SB)
+	MOVD $290, R11
+	BR   callbackasm1(SB)
+	MOVD $291, R11
+	BR   callbackasm1(SB)
+	MOVD $292, R11
+	BR   callbackasm1(SB)
+	MOVD $293, R11
+	BR   callbackasm1(SB)
+	MOVD $294, R11
+	BR   callbackasm1(SB)
+	MOVD $295, R11
+	BR   callbackasm1(SB)
+	MOVD $296, R11
+	BR   callbackasm1(SB)
+	MOVD $297, R11
+	BR   callbackasm1(SB)
+	MOVD $298, R11
+	BR   callbackasm1(SB)
+	MOVD $299, R11
+	BR   callbackasm1(SB)
+	MOVD $300, R11
+	BR   callbackasm1(SB)
+	MOVD $301, R11
+	BR   callbackasm1(SB)
+	MOVD $302, R11
+	BR   callbackasm1(SB)
+	MOVD $303, R11
+	BR   callbackasm1(SB)
+	MOVD $304, R11
+	BR   callbackasm1(SB)
+	MOVD $305, R11
+	BR   callbackasm1(SB)
+	MOVD $306, R11
+	BR   callbackasm1(SB)
+	MOVD $307, R11
+	BR   callbackasm1(SB)
+	MOVD $308, R11
+	BR   callbackasm1(SB)
+	MOVD $309, R11
+	BR   callbackasm1(SB)
+	MOVD $310, R11
+	BR   callbackasm1(SB)
+	MOVD $311, R11
+	BR   callbackasm1(SB)
+	MOVD $312, R11
+	BR   callbackasm1(SB)
+	MOVD $313, R11
+	BR   callbackasm1(SB)
+	MOVD $314, R11
+	BR   callbackasm1(SB)
+	MOVD $315, R11
+	BR   callbackasm1(SB)
+	MOVD $316, R11
+	BR   callbackasm1(SB)
+	MOVD $317, R11
+	BR   callbackasm1(SB)
+	MOVD $318, R11
+	BR   callbackasm1(SB)
+	MOVD $319, R11
+	BR   callbackasm1(SB)
+	MOVD $320, R11
+	BR   callbackasm1(SB)
+	MOVD $321, R11
+	BR   callbackasm1(SB)
+	MOVD $322, R11
+	BR   callbackasm1(SB)
+	MOVD $323, R11
+	BR   callbackasm1(SB)
+	MOVD $324, R11
+	BR   callbackasm1(SB)
+	MOVD $325, R11
+	BR   callbackasm1(SB)
+	MOVD $326, R11
+	BR   callbackasm1(SB)
+	MOVD $327, R11
+	BR   callbackasm1(SB)
+	MOVD $328, R11
+	BR   callbackasm1(SB)
+	MOVD $329, R11
+	BR   callbackasm1(SB)
+	MOVD $330, R11
+	BR   callbackasm1(SB)
+	MOVD $331, R11
+	BR   callbackasm1(SB)
+	MOVD $332, R11
+	BR   callbackasm1(SB)
+	MOVD $333, R11
+	BR   callbackasm1(SB)
+	MOVD $334, R11
+	BR   callbackasm1(SB)
+	MOVD $335, R11
+	BR   callbackasm1(SB)
+	MOVD $336, R11
+	BR   callbackasm1(SB)
+	MOVD $337, R11
+	BR   callbackasm1(SB)
+	MOVD $338, R11
+	BR   callbackasm1(SB)
+	MOVD $339, R11
+	BR   callbackasm1(SB)
+	MOVD $340, R11
+	BR   callbackasm1(SB)
+	MOVD $341, R11
+	BR   callbackasm1(SB)
+	MOVD $342, R11
+	BR   callbackasm1(SB)
+	MOVD $343, R11
+	BR   callbackasm1(SB)
+	MOVD $344, R11
+	BR   callbackasm1(SB)
+	MOVD $345, R11
+	BR   callbackasm1(SB)
+	MOVD $346, R11
+	BR   callbackasm1(SB)
+	MOVD $347, R11
+	BR   callbackasm1(SB)
+	MOVD $348, R11
+	BR   callbackasm1(SB)
+	MOVD $349, R11
+	BR   callbackasm1(SB)
+	MOVD $350, R11
+	BR   callbackasm1(SB)
+	MOVD $351, R11
+	BR   callbackasm1(SB)
+	MOVD $352, R11
+	BR   callbackasm1(SB)
+	MOVD $353, R11
+	BR   callbackasm1(SB)
+	MOVD $354, R11
+	BR   callbackasm1(SB)
+	MOVD $355, R11
+	BR   callbackasm1(SB)
+	MOVD $356, R11
+	BR   callbackasm1(SB)
+	MOVD $357, R11
+	BR   callbackasm1(SB)
+	MOVD $358, R11
+	BR   callbackasm1(SB)
+	MOVD $359, R11
+	BR   callbackasm1(SB)
+	MOVD $360, R11
+	BR   callbackasm1(SB)
+	MOVD $361, R11
+	BR   callbackasm1(SB)
+	MOVD $362, R11
+	BR   callbackasm1(SB)
+	MOVD $363, R11
+	BR   callbackasm1(SB)
+	MOVD $364, R11
+	BR   callbackasm1(SB)
+	MOVD $365, R11
+	BR   callbackasm1(SB)
+	MOVD $366, R11
+	BR   callbackasm1(SB)
+	MOVD $367, R11
+	BR   callbackasm1(SB)
+	MOVD $368, R11
+	BR   callbackasm1(SB)
+	MOVD $369, R11
+	BR   callbackasm1(SB)
+	MOVD $370, R11
+	BR   callbackasm1(SB)
+	MOVD $371, R11
+	BR   callbackasm1(SB)
+	MOVD $372, R11
+	BR   callbackasm1(SB)
+	MOVD $373, R11
+	BR   callbackasm1(SB)
+	MOVD $374, R11
+	BR   callbackasm1(SB)
+	MOVD $375, R11
+	BR   callbackasm1(SB)
+	MOVD $376, R11
+	BR   callbackasm1(SB)
+	MOVD $377, R11
+	BR   callbackasm1(SB)
+	MOVD $378, R11
+	BR   callbackasm1(SB)
+	MOVD $379, R11
+	BR   callbackasm1(SB)
+	MOVD $380, R11
+	BR   callbackasm1(SB)
+	MOVD $381, R11
+	BR   callbackasm1(SB)
+	MOVD $382, R11
+	BR   callbackasm1(SB)
+	MOVD $383, R11
+	BR   callbackasm1(SB)
+	MOVD $384, R11
+	BR   callbackasm1(SB)
+	MOVD $385, R11
+	BR   callbackasm1(SB)
+	MOVD $386, R11
+	BR   callbackasm1(SB)
+	MOVD $387, R11
+	BR   callbackasm1(SB)
+	MOVD $388, R11
+	BR   callbackasm1(SB)
+	MOVD $389, R11
+	BR   callbackasm1(SB)
+	MOVD $390, R11
+	BR   callbackasm1(SB)
+	MOVD $391, R11
+	BR   callbackasm1(SB)
+	MOVD $392, R11
+	BR   callbackasm1(SB)
+	MOVD $393, R11
+	BR   callbackasm1(SB)
+	MOVD $394, R11
+	BR   callbackasm1(SB)
+	MOVD $395, R11
+	BR   callbackasm1(SB)
+	MOVD $396, R11
+	BR   callbackasm1(SB)
+	MOVD $397, R11
+	BR   callbackasm1(SB)
+	MOVD $398, R11
+	BR   callbackasm1(SB)
+	MOVD $399, R11
+	BR   callbackasm1(SB)
+	MOVD $400, R11
+	BR   callbackasm1(SB)
+	MOVD $401, R11
+	BR   callbackasm1(SB)
+	MOVD $402, R11
+	BR   callbackasm1(SB)
+	MOVD $403, R11
+	BR   callbackasm1(SB)
+	MOVD $404, R11
+	BR   callbackasm1(SB)
+	MOVD $405, R11
+	BR   callbackasm1(SB)
+	MOVD $406, R11
+	BR   callbackasm1(SB)
+	MOVD $407, R11
+	BR   callbackasm1(SB)
+	MOVD $408, R11
+	BR   callbackasm1(SB)
+	MOVD $409, R11
+	BR   callbackasm1(SB)
+	MOVD $410, R11
+	BR   callbackasm1(SB)
+	MOVD $411, R11
+	BR   callbackasm1(SB)
+	MOVD $412, R11
+	BR   callbackasm1(SB)
+	MOVD $413, R11
+	BR   callbackasm1(SB)
+	MOVD $414, R11
+	BR   callbackasm1(SB)
+	MOVD $415, R11
+	BR   callbackasm1(SB)
+	MOVD $416, R11
+	BR   callbackasm1(SB)
+	MOVD $417, R11
+	BR   callbackasm1(SB)
+	MOVD $418, R11
+	BR   callbackasm1(SB)
+	MOVD $419, R11
+	BR   callbackasm1(SB)
+	MOVD $420, R11
+	BR   callbackasm1(SB)
+	MOVD $421, R11
+	BR   callbackasm1(SB)
+	MOVD $422, R11
+	BR   callbackasm1(SB)
+	MOVD $423, R11
+	BR   callbackasm1(SB)
+	MOVD $424, R11
+	BR   callbackasm1(SB)
+	MOVD $425, R11
+	BR   callbackasm1(SB)
+	MOVD $426, R11
+	BR   callbackasm1(SB)
+	MOVD $427, R11
+	BR   callbackasm1(SB)
+	MOVD $428, R11
+	BR   callbackasm1(SB)
+	MOVD $429, R11
+	BR   callbackasm1(SB)
+	MOVD $430, R11
+	BR   callbackasm1(SB)
+	MOVD $431, R11
+	BR   callbackasm1(SB)
+	MOVD $432, R11
+	BR   callbackasm1(SB)
+	MOVD $433, R11
+	BR   callbackasm1(SB)
+	MOVD $434, R11
+	BR   callbackasm1(SB)
+	MOVD $435, R11
+	BR   callbackasm1(SB)
+	MOVD $436, R11
+	BR   callbackasm1(SB)
+	MOVD $437, R11
+	BR   callbackasm1(SB)
+	MOVD $438, R11
+	BR   callbackasm1(SB)
+	MOVD $439, R11
+	BR   callbackasm1(SB)
+	MOVD $440, R11
+	BR   callbackasm1(SB)
+	MOVD $441, R11
+	BR   callbackasm1(SB)
+	MOVD $442, R11
+	BR   callbackasm1(SB)
+	MOVD $443, R11
+	BR   callbackasm1(SB)
+	MOVD $444, R11
+	BR   callbackasm1(SB)
+	MOVD $445, R11
+	BR   callbackasm1(SB)
+	MOVD $446, R11
+	BR   callbackasm1(SB)
+	MOVD $447, R11
+	BR   callbackasm1(SB)
+	MOVD $448, R11
+	BR   callbackasm1(SB)
+	MOVD $449, R11
+	BR   callbackasm1(SB)
+	MOVD $450, R11
+	BR   callbackasm1(SB)
+	MOVD $451, R11
+	BR   callbackasm1(SB)
+	MOVD $452, R11
+	BR   callbackasm1(SB)
+	MOVD $453, R11
+	BR   callbackasm1(SB)
+	MOVD $454, R11
+	BR   callbackasm1(SB)
+	MOVD $455, R11
+	BR   callbackasm1(SB)
+	MOVD $456, R11
+	BR   callbackasm1(SB)
+	MOVD $457, R11
+	BR   callbackasm1(SB)
+	MOVD $458, R11
+	BR   callbackasm1(SB)
+	MOVD $459, R11
+	BR   callbackasm1(SB)
+	MOVD $460, R11
+	BR   callbackasm1(SB)
+	MOVD $461, R11
+	BR   callbackasm1(SB)
+	MOVD $462, R11
+	BR   callbackasm1(SB)
+	MOVD $463, R11
+	BR   callbackasm1(SB)
+	MOVD $464, R11
+	BR   callbackasm1(SB)
+	MOVD $465, R11
+	BR   callbackasm1(SB)
+	MOVD $466, R11
+	BR   callbackasm1(SB)
+	MOVD $467, R11
+	BR   callbackasm1(SB)
+	MOVD $468, R11
+	BR   callbackasm1(SB)
+	MOVD $469, R11
+	BR   callbackasm1(SB)
+	MOVD $470, R11
+	BR   callbackasm1(SB)
+	MOVD $471, R11
+	BR   callbackasm1(SB)
+	MOVD $472, R11
+	BR   callbackasm1(SB)
+	MOVD $473, R11
+	BR   callbackasm1(SB)
+	MOVD $474, R11
+	BR   callbackasm1(SB)
+	MOVD $475, R11
+	BR   callbackasm1(SB)
+	MOVD $476, R11
+	BR   callbackasm1(SB)
+	MOVD $477, R11
+	BR   callbackasm1(SB)
+	MOVD $478, R11
+	BR   callbackasm1(SB)
+	MOVD $479, R11
+	BR   callbackasm1(SB)
+	MOVD $480, R11
+	BR   callbackasm1(SB)
+	MOVD $481, R11
+	BR   callbackasm1(SB)
+	MOVD $482, R11
+	BR   callbackasm1(SB)
+	MOVD $483, R11
+	BR   callbackasm1(SB)
+	MOVD $484, R11
+	BR   callbackasm1(SB)
+	MOVD $485, R11
+	BR   callbackasm1(SB)
+	MOVD $486, R11
+	BR   callbackasm1(SB)
+	MOVD $487, R11
+	BR   callbackasm1(SB)
+	MOVD $488, R11
+	BR   callbackasm1(SB)
+	MOVD $489, R11
+	BR   callbackasm1(SB)
+	MOVD $490, R11
+	BR   callbackasm1(SB)
+	MOVD $491, R11
+	BR   callbackasm1(SB)
+	MOVD $492, R11
+	BR   callbackasm1(SB)
+	MOVD $493, R11
+	BR   callbackasm1(SB)
+	MOVD $494, R11
+	BR   callbackasm1(SB)
+	MOVD $495, R11
+	BR   callbackasm1(SB)
+	MOVD $496, R11
+	BR   callbackasm1(SB)
+	MOVD $497, R11
+	BR   callbackasm1(SB)
+	MOVD $498, R11
+	BR   callbackasm1(SB)
+	MOVD $499, R11
+	BR   callbackasm1(SB)
+	MOVD $500, R11
+	BR   callbackasm1(SB)
+	MOVD $501, R11
+	BR   callbackasm1(SB)
+	MOVD $502, R11
+	BR   callbackasm1(SB)
+	MOVD $503, R11
+	BR   callbackasm1(SB)
+	MOVD $504, R11
+	BR   callbackasm1(SB)
+	MOVD $505, R11
+	BR   callbackasm1(SB)
+	MOVD $506, R11
+	BR   callbackasm1(SB)
+	MOVD $507, R11
+	BR   callbackasm1(SB)
+	MOVD $508, R11
+	BR   callbackasm1(SB)
+	MOVD $509, R11
+	BR   callbackasm1(SB)
+	MOVD $510, R11
+	BR   callbackasm1(SB)
+	MOVD $511, R11
+	BR   callbackasm1(SB)
+	MOVD $512, R11
+	BR   callbackasm1(SB)
+	MOVD $513, R11
+	BR   callbackasm1(SB)
+	MOVD $514, R11
+	BR   callbackasm1(SB)
+	MOVD $515, R11
+	BR   callbackasm1(SB)
+	MOVD $516, R11
+	BR   callbackasm1(SB)
+	MOVD $517, R11
+	BR   callbackasm1(SB)
+	MOVD $518, R11
+	BR   callbackasm1(SB)
+	MOVD $519, R11
+	BR   callbackasm1(SB)
+	MOVD $520, R11
+	BR   callbackasm1(SB)
+	MOVD $521, R11
+	BR   callbackasm1(SB)
+	MOVD $522, R11
+	BR   callbackasm1(SB)
+	MOVD $523, R11
+	BR   callbackasm1(SB)
+	MOVD $524, R11
+	BR   callbackasm1(SB)
+	MOVD $525, R11
+	BR   callbackasm1(SB)
+	MOVD $526, R11
+	BR   callbackasm1(SB)
+	MOVD $527, R11
+	BR   callbackasm1(SB)
+	MOVD $528, R11
+	BR   callbackasm1(SB)
+	MOVD $529, R11
+	BR   callbackasm1(SB)
+	MOVD $530, R11
+	BR   callbackasm1(SB)
+	MOVD $531, R11
+	BR   callbackasm1(SB)
+	MOVD $532, R11
+	BR   callbackasm1(SB)
+	MOVD $533, R11
+	BR   callbackasm1(SB)
+	MOVD $534, R11
+	BR   callbackasm1(SB)
+	MOVD $535, R11
+	BR   callbackasm1(SB)
+	MOVD $536, R11
+	BR   callbackasm1(SB)
+	MOVD $537, R11
+	BR   callbackasm1(SB)
+	MOVD $538, R11
+	BR   callbackasm1(SB)
+	MOVD $539, R11
+	BR   callbackasm1(SB)
+	MOVD $540, R11
+	BR   callbackasm1(SB)
+	MOVD $541, R11
+	BR   callbackasm1(SB)
+	MOVD $542, R11
+	BR   callbackasm1(SB)
+	MOVD $543, R11
+	BR   callbackasm1(SB)
+	MOVD $544, R11
+	BR   callbackasm1(SB)
+	MOVD $545, R11
+	BR   callbackasm1(SB)
+	MOVD $546, R11
+	BR   callbackasm1(SB)
+	MOVD $547, R11
+	BR   callbackasm1(SB)
+	MOVD $548, R11
+	BR   callbackasm1(SB)
+	MOVD $549, R11
+	BR   callbackasm1(SB)
+	MOVD $550, R11
+	BR   callbackasm1(SB)
+	MOVD $551, R11
+	BR   callbackasm1(SB)
+	MOVD $552, R11
+	BR   callbackasm1(SB)
+	MOVD $553, R11
+	BR   callbackasm1(SB)
+	MOVD $554, R11
+	BR   callbackasm1(SB)
+	MOVD $555, R11
+	BR   callbackasm1(SB)
+	MOVD $556, R11
+	BR   callbackasm1(SB)
+	MOVD $557, R11
+	BR   callbackasm1(SB)
+	MOVD $558, R11
+	BR   callbackasm1(SB)
+	MOVD $559, R11
+	BR   callbackasm1(SB)
+	MOVD $560, R11
+	BR   callbackasm1(SB)
+	MOVD $561, R11
+	BR   callbackasm1(SB)
+	MOVD $562, R11
+	BR   callbackasm1(SB)
+	MOVD $563, R11
+	BR   callbackasm1(SB)
+	MOVD $564, R11
+	BR   callbackasm1(SB)
+	MOVD $565, R11
+	BR   callbackasm1(SB)
+	MOVD $566, R11
+	BR   callbackasm1(SB)
+	MOVD $567, R11
+	BR   callbackasm1(SB)
+	MOVD $568, R11
+	BR   callbackasm1(SB)
+	MOVD $569, R11
+	BR   callbackasm1(SB)
+	MOVD $570, R11
+	BR   callbackasm1(SB)
+	MOVD $571, R11
+	BR   callbackasm1(SB)
+	MOVD $572, R11
+	BR   callbackasm1(SB)
+	MOVD $573, R11
+	BR   callbackasm1(SB)
+	MOVD $574, R11
+	BR   callbackasm1(SB)
+	MOVD $575, R11
+	BR   callbackasm1(SB)
+	MOVD $576, R11
+	BR   callbackasm1(SB)
+	MOVD $577, R11
+	BR   callbackasm1(SB)
+	MOVD $578, R11
+	BR   callbackasm1(SB)
+	MOVD $579, R11
+	BR   callbackasm1(SB)
+	MOVD $580, R11
+	BR   callbackasm1(SB)
+	MOVD $581, R11
+	BR   callbackasm1(SB)
+	MOVD $582, R11
+	BR   callbackasm1(SB)
+	MOVD $583, R11
+	BR   callbackasm1(SB)
+	MOVD $584, R11
+	BR   callbackasm1(SB)
+	MOVD $585, R11
+	BR   callbackasm1(SB)
+	MOVD $586, R11
+	BR   callbackasm1(SB)
+	MOVD $587, R11
+	BR   callbackasm1(SB)
+	MOVD $588, R11
+	BR   callbackasm1(SB)
+	MOVD $589, R11
+	BR   callbackasm1(SB)
+	MOVD $590, R11
+	BR   callbackasm1(SB)
+	MOVD $591, R11
+	BR   callbackasm1(SB)
+	MOVD $592, R11
+	BR   callbackasm1(SB)
+	MOVD $593, R11
+	BR   callbackasm1(SB)
+	MOVD $594, R11
+	BR   callbackasm1(SB)
+	MOVD $595, R11
+	BR   callbackasm1(SB)
+	MOVD $596, R11
+	BR   callbackasm1(SB)
+	MOVD $597, R11
+	BR   callbackasm1(SB)
+	MOVD $598, R11
+	BR   callbackasm1(SB)
+	MOVD $599, R11
+	BR   callbackasm1(SB)
+	MOVD $600, R11
+	BR   callbackasm1(SB)
+	MOVD $601, R11
+	BR   callbackasm1(SB)
+	MOVD $602, R11
+	BR   callbackasm1(SB)
+	MOVD $603, R11
+	BR   callbackasm1(SB)
+	MOVD $604, R11
+	BR   callbackasm1(SB)
+	MOVD $605, R11
+	BR   callbackasm1(SB)
+	MOVD $606, R11
+	BR   callbackasm1(SB)
+	MOVD $607, R11
+	BR   callbackasm1(SB)
+	MOVD $608, R11
+	BR   callbackasm1(SB)
+	MOVD $609, R11
+	BR   callbackasm1(SB)
+	MOVD $610, R11
+	BR   callbackasm1(SB)
+	MOVD $611, R11
+	BR   callbackasm1(SB)
+	MOVD $612, R11
+	BR   callbackasm1(SB)
+	MOVD $613, R11
+	BR   callbackasm1(SB)
+	MOVD $614, R11
+	BR   callbackasm1(SB)
+	MOVD $615, R11
+	BR   callbackasm1(SB)
+	MOVD $616, R11
+	BR   callbackasm1(SB)
+	MOVD $617, R11
+	BR   callbackasm1(SB)
+	MOVD $618, R11
+	BR   callbackasm1(SB)
+	MOVD $619, R11
+	BR   callbackasm1(SB)
+	MOVD $620, R11
+	BR   callbackasm1(SB)
+	MOVD $621, R11
+	BR   callbackasm1(SB)
+	MOVD $622, R11
+	BR   callbackasm1(SB)
+	MOVD $623, R11
+	BR   callbackasm1(SB)
+	MOVD $624, R11
+	BR   callbackasm1(SB)
+	MOVD $625, R11
+	BR   callbackasm1(SB)
+	MOVD $626, R11
+	BR   callbackasm1(SB)
+	MOVD $627, R11
+	BR   callbackasm1(SB)
+	MOVD $628, R11
+	BR   callbackasm1(SB)
+	MOVD $629, R11
+	BR   callbackasm1(SB)
+	MOVD $630, R11
+	BR   callbackasm1(SB)
+	MOVD $631, R11
+	BR   callbackasm1(SB)
+	MOVD $632, R11
+	BR   callbackasm1(SB)
+	MOVD $633, R11
+	BR   callbackasm1(SB)
+	MOVD $634, R11
+	BR   callbackasm1(SB)
+	MOVD $635, R11
+	BR   callbackasm1(SB)
+	MOVD $636, R11
+	BR   callbackasm1(SB)
+	MOVD $637, R11
+	BR   callbackasm1(SB)
+	MOVD $638, R11
+	BR   callbackasm1(SB)
+	MOVD $639, R11
+	BR   callbackasm1(SB)
+	MOVD $640, R11
+	BR   callbackasm1(SB)
+	MOVD $641, R11
+	BR   callbackasm1(SB)
+	MOVD $642, R11
+	BR   callbackasm1(SB)
+	MOVD $643, R11
+	BR   callbackasm1(SB)
+	MOVD $644, R11
+	BR   callbackasm1(SB)
+	MOVD $645, R11
+	BR   callbackasm1(SB)
+	MOVD $646, R11
+	BR   callbackasm1(SB)
+	MOVD $647, R11
+	BR   callbackasm1(SB)
+	MOVD $648, R11
+	BR   callbackasm1(SB)
+	MOVD $649, R11
+	BR   callbackasm1(SB)
+	MOVD $650, R11
+	BR   callbackasm1(SB)
+	MOVD $651, R11
+	BR   callbackasm1(SB)
+	MOVD $652, R11
+	BR   callbackasm1(SB)
+	MOVD $653, R11
+	BR   callbackasm1(SB)
+	MOVD $654, R11
+	BR   callbackasm1(SB)
+	MOVD $655, R11
+	BR   callbackasm1(SB)
+	MOVD $656, R11
+	BR   callbackasm1(SB)
+	MOVD $657, R11
+	BR   callbackasm1(SB)
+	MOVD $658, R11
+	BR   callbackasm1(SB)
+	MOVD $659, R11
+	BR   callbackasm1(SB)
+	MOVD $660, R11
+	BR   callbackasm1(SB)
+	MOVD $661, R11
+	BR   callbackasm1(SB)
+	MOVD $662, R11
+	BR   callbackasm1(SB)
+	MOVD $663, R11
+	BR   callbackasm1(SB)
+	MOVD $664, R11
+	BR   callbackasm1(SB)
+	MOVD $665, R11
+	BR   callbackasm1(SB)
+	MOVD $666, R11
+	BR   callbackasm1(SB)
+	MOVD $667, R11
+	BR   callbackasm1(SB)
+	MOVD $668, R11
+	BR   callbackasm1(SB)
+	MOVD $669, R11
+	BR   callbackasm1(SB)
+	MOVD $670, R11
+	BR   callbackasm1(SB)
+	MOVD $671, R11
+	BR   callbackasm1(SB)
+	MOVD $672, R11
+	BR   callbackasm1(SB)
+	MOVD $673, R11
+	BR   callbackasm1(SB)
+	MOVD $674, R11
+	BR   callbackasm1(SB)
+	MOVD $675, R11
+	BR   callbackasm1(SB)
+	MOVD $676, R11
+	BR   callbackasm1(SB)
+	MOVD $677, R11
+	BR   callbackasm1(SB)
+	MOVD $678, R11
+	BR   callbackasm1(SB)
+	MOVD $679, R11
+	BR   callbackasm1(SB)
+	MOVD $680, R11
+	BR   callbackasm1(SB)
+	MOVD $681, R11
+	BR   callbackasm1(SB)
+	MOVD $682, R11
+	BR   callbackasm1(SB)
+	MOVD $683, R11
+	BR   callbackasm1(SB)
+	MOVD $684, R11
+	BR   callbackasm1(SB)
+	MOVD $685, R11
+	BR   callbackasm1(SB)
+	MOVD $686, R11
+	BR   callbackasm1(SB)
+	MOVD $687, R11
+	BR   callbackasm1(SB)
+	MOVD $688, R11
+	BR   callbackasm1(SB)
+	MOVD $689, R11
+	BR   callbackasm1(SB)
+	MOVD $690, R11
+	BR   callbackasm1(SB)
+	MOVD $691, R11
+	BR   callbackasm1(SB)
+	MOVD $692, R11
+	BR   callbackasm1(SB)
+	MOVD $693, R11
+	BR   callbackasm1(SB)
+	MOVD $694, R11
+	BR   callbackasm1(SB)
+	MOVD $695, R11
+	BR   callbackasm1(SB)
+	MOVD $696, R11
+	BR   callbackasm1(SB)
+	MOVD $697, R11
+	BR   callbackasm1(SB)
+	MOVD $698, R11
+	BR   callbackasm1(SB)
+	MOVD $699, R11
+	BR   callbackasm1(SB)
+	MOVD $700, R11
+	BR   callbackasm1(SB)
+	MOVD $701, R11
+	BR   callbackasm1(SB)
+	MOVD $702, R11
+	BR   callbackasm1(SB)
+	MOVD $703, R11
+	BR   callbackasm1(SB)
+	MOVD $704, R11
+	BR   callbackasm1(SB)
+	MOVD $705, R11
+	BR   callbackasm1(SB)
+	MOVD $706, R11
+	BR   callbackasm1(SB)
+	MOVD $707, R11
+	BR   callbackasm1(SB)
+	MOVD $708, R11
+	BR   callbackasm1(SB)
+	MOVD $709, R11
+	BR   callbackasm1(SB)
+	MOVD $710, R11
+	BR   callbackasm1(SB)
+	MOVD $711, R11
+	BR   callbackasm1(SB)
+	MOVD $712, R11
+	BR   callbackasm1(SB)
+	MOVD $713, R11
+	BR   callbackasm1(SB)
+	MOVD $714, R11
+	BR   callbackasm1(SB)
+	MOVD $715, R11
+	BR   callbackasm1(SB)
+	MOVD $716, R11
+	BR   callbackasm1(SB)
+	MOVD $717, R11
+	BR   callbackasm1(SB)
+	MOVD $718, R11
+	BR   callbackasm1(SB)
+	MOVD $719, R11
+	BR   callbackasm1(SB)
+	MOVD $720, R11
+	BR   callbackasm1(SB)
+	MOVD $721, R11
+	BR   callbackasm1(SB)
+	MOVD $722, R11
+	BR   callbackasm1(SB)
+	MOVD $723, R11
+	BR   callbackasm1(SB)
+	MOVD $724, R11
+	BR   callbackasm1(SB)
+	MOVD $725, R11
+	BR   callbackasm1(SB)
+	MOVD $726, R11
+	BR   callbackasm1(SB)
+	MOVD $727, R11
+	BR   callbackasm1(SB)
+	MOVD $728, R11
+	BR   callbackasm1(SB)
+	MOVD $729, R11
+	BR   callbackasm1(SB)
+	MOVD $730, R11
+	BR   callbackasm1(SB)
+	MOVD $731, R11
+	BR   callbackasm1(SB)
+	MOVD $732, R11
+	BR   callbackasm1(SB)
+	MOVD $733, R11
+	BR   callbackasm1(SB)
+	MOVD $734, R11
+	BR   callbackasm1(SB)
+	MOVD $735, R11
+	BR   callbackasm1(SB)
+	MOVD $736, R11
+	BR   callbackasm1(SB)
+	MOVD $737, R11
+	BR   callbackasm1(SB)
+	MOVD $738, R11
+	BR   callbackasm1(SB)
+	MOVD $739, R11
+	BR   callbackasm1(SB)
+	MOVD $740, R11
+	BR   callbackasm1(SB)
+	MOVD $741, R11
+	BR   callbackasm1(SB)
+	MOVD $742, R11
+	BR   callbackasm1(SB)
+	MOVD $743, R11
+	BR   callbackasm1(SB)
+	MOVD $744, R11
+	BR   callbackasm1(SB)
+	MOVD $745, R11
+	BR   callbackasm1(SB)
+	MOVD $746, R11
+	BR   callbackasm1(SB)
+	MOVD $747, R11
+	BR   callbackasm1(SB)
+	MOVD $748, R11
+	BR   callbackasm1(SB)
+	MOVD $749, R11
+	BR   callbackasm1(SB)
+	MOVD $750, R11
+	BR   callbackasm1(SB)
+	MOVD $751, R11
+	BR   callbackasm1(SB)
+	MOVD $752, R11
+	BR   callbackasm1(SB)
+	MOVD $753, R11
+	BR   callbackasm1(SB)
+	MOVD $754, R11
+	BR   callbackasm1(SB)
+	MOVD $755, R11
+	BR   callbackasm1(SB)
+	MOVD $756, R11
+	BR   callbackasm1(SB)
+	MOVD $757, R11
+	BR   callbackasm1(SB)
+	MOVD $758, R11
+	BR   callbackasm1(SB)
+	MOVD $759, R11
+	BR   callbackasm1(SB)
+	MOVD $760, R11
+	BR   callbackasm1(SB)
+	MOVD $761, R11
+	BR   callbackasm1(SB)
+	MOVD $762, R11
+	BR   callbackasm1(SB)
+	MOVD $763, R11
+	BR   callbackasm1(SB)
+	MOVD $764, R11
+	BR   callbackasm1(SB)
+	MOVD $765, R11
+	BR   callbackasm1(SB)
+	MOVD $766, R11
+	BR   callbackasm1(SB)
+	MOVD $767, R11
+	BR   callbackasm1(SB)
+	MOVD $768, R11
+	BR   callbackasm1(SB)
+	MOVD $769, R11
+	BR   callbackasm1(SB)
+	MOVD $770, R11
+	BR   callbackasm1(SB)
+	MOVD $771, R11
+	BR   callbackasm1(SB)
+	MOVD $772, R11
+	BR   callbackasm1(SB)
+	MOVD $773, R11
+	BR   callbackasm1(SB)
+	MOVD $774, R11
+	BR   callbackasm1(SB)
+	MOVD $775, R11
+	BR   callbackasm1(SB)
+	MOVD $776, R11
+	BR   callbackasm1(SB)
+	MOVD $777, R11
+	BR   callbackasm1(SB)
+	MOVD $778, R11
+	BR   callbackasm1(SB)
+	MOVD $779, R11
+	BR   callbackasm1(SB)
+	MOVD $780, R11
+	BR   callbackasm1(SB)
+	MOVD $781, R11
+	BR   callbackasm1(SB)
+	MOVD $782, R11
+	BR   callbackasm1(SB)
+	MOVD $783, R11
+	BR   callbackasm1(SB)
+	MOVD $784, R11
+	BR   callbackasm1(SB)
+	MOVD $785, R11
+	BR   callbackasm1(SB)
+	MOVD $786, R11
+	BR   callbackasm1(SB)
+	MOVD $787, R11
+	BR   callbackasm1(SB)
+	MOVD $788, R11
+	BR   callbackasm1(SB)
+	MOVD $789, R11
+	BR   callbackasm1(SB)
+	MOVD $790, R11
+	BR   callbackasm1(SB)
+	MOVD $791, R11
+	BR   callbackasm1(SB)
+	MOVD $792, R11
+	BR   callbackasm1(SB)
+	MOVD $793, R11
+	BR   callbackasm1(SB)
+	MOVD $794, R11
+	BR   callbackasm1(SB)
+	MOVD $795, R11
+	BR   callbackasm1(SB)
+	MOVD $796, R11
+	BR   callbackasm1(SB)
+	MOVD $797, R11
+	BR   callbackasm1(SB)
+	MOVD $798, R11
+	BR   callbackasm1(SB)
+	MOVD $799, R11
+	BR   callbackasm1(SB)
+	MOVD $800, R11
+	BR   callbackasm1(SB)
+	MOVD $801, R11
+	BR   callbackasm1(SB)
+	MOVD $802, R11
+	BR   callbackasm1(SB)
+	MOVD $803, R11
+	BR   callbackasm1(SB)
+	MOVD $804, R11
+	BR   callbackasm1(SB)
+	MOVD $805, R11
+	BR   callbackasm1(SB)
+	MOVD $806, R11
+	BR   callbackasm1(SB)
+	MOVD $807, R11
+	BR   callbackasm1(SB)
+	MOVD $808, R11
+	BR   callbackasm1(SB)
+	MOVD $809, R11
+	BR   callbackasm1(SB)
+	MOVD $810, R11
+	BR   callbackasm1(SB)
+	MOVD $811, R11
+	BR   callbackasm1(SB)
+	MOVD $812, R11
+	BR   callbackasm1(SB)
+	MOVD $813, R11
+	BR   callbackasm1(SB)
+	MOVD $814, R11
+	BR   callbackasm1(SB)
+	MOVD $815, R11
+	BR   callbackasm1(SB)
+	MOVD $816, R11
+	BR   callbackasm1(SB)
+	MOVD $817, R11
+	BR   callbackasm1(SB)
+	MOVD $818, R11
+	BR   callbackasm1(SB)
+	MOVD $819, R11
+	BR   callbackasm1(SB)
+	MOVD $820, R11
+	BR   callbackasm1(SB)
+	MOVD $821, R11
+	BR   callbackasm1(SB)
+	MOVD $822, R11
+	BR   callbackasm1(SB)
+	MOVD $823, R11
+	BR   callbackasm1(SB)
+	MOVD $824, R11
+	BR   callbackasm1(SB)
+	MOVD $825, R11
+	BR   callbackasm1(SB)
+	MOVD $826, R11
+	BR   callbackasm1(SB)
+	MOVD $827, R11
+	BR   callbackasm1(SB)
+	MOVD $828, R11
+	BR   callbackasm1(SB)
+	MOVD $829, R11
+	BR   callbackasm1(SB)
+	MOVD $830, R11
+	BR   callbackasm1(SB)
+	MOVD $831, R11
+	BR   callbackasm1(SB)
+	MOVD $832, R11
+	BR   callbackasm1(SB)
+	MOVD $833, R11
+	BR   callbackasm1(SB)
+	MOVD $834, R11
+	BR   callbackasm1(SB)
+	MOVD $835, R11
+	BR   callbackasm1(SB)
+	MOVD $836, R11
+	BR   callbackasm1(SB)
+	MOVD $837, R11
+	BR   callbackasm1(SB)
+	MOVD $838, R11
+	BR   callbackasm1(SB)
+	MOVD $839, R11
+	BR   callbackasm1(SB)
+	MOVD $840, R11
+	BR   callbackasm1(SB)
+	MOVD $841, R11
+	BR   callbackasm1(SB)
+	MOVD $842, R11
+	BR   callbackasm1(SB)
+	MOVD $843, R11
+	BR   callbackasm1(SB)
+	MOVD $844, R11
+	BR   callbackasm1(SB)
+	MOVD $845, R11
+	BR   callbackasm1(SB)
+	MOVD $846, R11
+	BR   callbackasm1(SB)
+	MOVD $847, R11
+	BR   callbackasm1(SB)
+	MOVD $848, R11
+	BR   callbackasm1(SB)
+	MOVD $849, R11
+	BR   callbackasm1(SB)
+	MOVD $850, R11
+	BR   callbackasm1(SB)
+	MOVD $851, R11
+	BR   callbackasm1(SB)
+	MOVD $852, R11
+	BR   callbackasm1(SB)
+	MOVD $853, R11
+	BR   callbackasm1(SB)
+	MOVD $854, R11
+	BR   callbackasm1(SB)
+	MOVD $855, R11
+	BR   callbackasm1(SB)
+	MOVD $856, R11
+	BR   callbackasm1(SB)
+	MOVD $857, R11
+	BR   callbackasm1(SB)
+	MOVD $858, R11
+	BR   callbackasm1(SB)
+	MOVD $859, R11
+	BR   callbackasm1(SB)
+	MOVD $860, R11
+	BR   callbackasm1(SB)
+	MOVD $861, R11
+	BR   callbackasm1(SB)
+	MOVD $862, R11
+	BR   callbackasm1(SB)
+	MOVD $863, R11
+	BR   callbackasm1(SB)
+	MOVD $864, R11
+	BR   callbackasm1(SB)
+	MOVD $865, R11
+	BR   callbackasm1(SB)
+	MOVD $866, R11
+	BR   callbackasm1(SB)
+	MOVD $867, R11
+	BR   callbackasm1(SB)
+	MOVD $868, R11
+	BR   callbackasm1(SB)
+	MOVD $869, R11
+	BR   callbackasm1(SB)
+	MOVD $870, R11
+	BR   callbackasm1(SB)
+	MOVD $871, R11
+	BR   callbackasm1(SB)
+	MOVD $872, R11
+	BR   callbackasm1(SB)
+	MOVD $873, R11
+	BR   callbackasm1(SB)
+	MOVD $874, R11
+	BR   callbackasm1(SB)
+	MOVD $875, R11
+	BR   callbackasm1(SB)
+	MOVD $876, R11
+	BR   callbackasm1(SB)
+	MOVD $877, R11
+	BR   callbackasm1(SB)
+	MOVD $878, R11
+	BR   callbackasm1(SB)
+	MOVD $879, R11
+	BR   callbackasm1(SB)
+	MOVD $880, R11
+	BR   callbackasm1(SB)
+	MOVD $881, R11
+	BR   callbackasm1(SB)
+	MOVD $882, R11
+	BR   callbackasm1(SB)
+	MOVD $883, R11
+	BR   callbackasm1(SB)
+	MOVD $884, R11
+	BR   callbackasm1(SB)
+	MOVD $885, R11
+	BR   callbackasm1(SB)
+	MOVD $886, R11
+	BR   callbackasm1(SB)
+	MOVD $887, R11
+	BR   callbackasm1(SB)
+	MOVD $888, R11
+	BR   callbackasm1(SB)
+	MOVD $889, R11
+	BR   callbackasm1(SB)
+	MOVD $890, R11
+	BR   callbackasm1(SB)
+	MOVD $891, R11
+	BR   callbackasm1(SB)
+	MOVD $892, R11
+	BR   callbackasm1(SB)
+	MOVD $893, R11
+	BR   callbackasm1(SB)
+	MOVD $894, R11
+	BR   callbackasm1(SB)
+	MOVD $895, R11
+	BR   callbackasm1(SB)
+	MOVD $896, R11
+	BR   callbackasm1(SB)
+	MOVD $897, R11
+	BR   callbackasm1(SB)
+	MOVD $898, R11
+	BR   callbackasm1(SB)
+	MOVD $899, R11
+	BR   callbackasm1(SB)
+	MOVD $900, R11
+	BR   callbackasm1(SB)
+	MOVD $901, R11
+	BR   callbackasm1(SB)
+	MOVD $902, R11
+	BR   callbackasm1(SB)
+	MOVD $903, R11
+	BR   callbackasm1(SB)
+	MOVD $904, R11
+	BR   callbackasm1(SB)
+	MOVD $905, R11
+	BR   callbackasm1(SB)
+	MOVD $906, R11
+	BR   callbackasm1(SB)
+	MOVD $907, R11
+	BR   callbackasm1(SB)
+	MOVD $908, R11
+	BR   callbackasm1(SB)
+	MOVD $909, R11
+	BR   callbackasm1(SB)
+	MOVD $910, R11
+	BR   callbackasm1(SB)
+	MOVD $911, R11
+	BR   callbackasm1(SB)
+	MOVD $912, R11
+	BR   callbackasm1(SB)
+	MOVD $913, R11
+	BR   callbackasm1(SB)
+	MOVD $914, R11
+	BR   callbackasm1(SB)
+	MOVD $915, R11
+	BR   callbackasm1(SB)
+	MOVD $916, R11
+	BR   callbackasm1(SB)
+	MOVD $917, R11
+	BR   callbackasm1(SB)
+	MOVD $918, R11
+	BR   callbackasm1(SB)
+	MOVD $919, R11
+	BR   callbackasm1(SB)
+	MOVD $920, R11
+	BR   callbackasm1(SB)
+	MOVD $921, R11
+	BR   callbackasm1(SB)
+	MOVD $922, R11
+	BR   callbackasm1(SB)
+	MOVD $923, R11
+	BR   callbackasm1(SB)
+	MOVD $924, R11
+	BR   callbackasm1(SB)
+	MOVD $925, R11
+	BR   callbackasm1(SB)
+	MOVD $926, R11
+	BR   callbackasm1(SB)
+	MOVD $927, R11
+	BR   callbackasm1(SB)
+	MOVD $928, R11
+	BR   callbackasm1(SB)
+	MOVD $929, R11
+	BR   callbackasm1(SB)
+	MOVD $930, R11
+	BR   callbackasm1(SB)
+	MOVD $931, R11
+	BR   callbackasm1(SB)
+	MOVD $932, R11
+	BR   callbackasm1(SB)
+	MOVD $933, R11
+	BR   callbackasm1(SB)
+	MOVD $934, R11
+	BR   callbackasm1(SB)
+	MOVD $935, R11
+	BR   callbackasm1(SB)
+	MOVD $936, R11
+	BR   callbackasm1(SB)
+	MOVD $937, R11
+	BR   callbackasm1(SB)
+	MOVD $938, R11
+	BR   callbackasm1(SB)
+	MOVD $939, R11
+	BR   callbackasm1(SB)
+	MOVD $940, R11
+	BR   callbackasm1(SB)
+	MOVD $941, R11
+	BR   callbackasm1(SB)
+	MOVD $942, R11
+	BR   callbackasm1(SB)
+	MOVD $943, R11
+	BR   callbackasm1(SB)
+	MOVD $944, R11
+	BR   callbackasm1(SB)
+	MOVD $945, R11
+	BR   callbackasm1(SB)
+	MOVD $946, R11
+	BR   callbackasm1(SB)
+	MOVD $947, R11
+	BR   callbackasm1(SB)
+	MOVD $948, R11
+	BR   callbackasm1(SB)
+	MOVD $949, R11
+	BR   callbackasm1(SB)
+	MOVD $950, R11
+	BR   callbackasm1(SB)
+	MOVD $951, R11
+	BR   callbackasm1(SB)
+	MOVD $952, R11
+	BR   callbackasm1(SB)
+	MOVD $953, R11
+	BR   callbackasm1(SB)
+	MOVD $954, R11
+	BR   callbackasm1(SB)
+	MOVD $955, R11
+	BR   callbackasm1(SB)
+	MOVD $956, R11
+	BR   callbackasm1(SB)
+	MOVD $957, R11
+	BR   callbackasm1(SB)
+	MOVD $958, R11
+	BR   callbackasm1(SB)
+	MOVD $959, R11
+	BR   callbackasm1(SB)
+	MOVD $960, R11
+	BR   callbackasm1(SB)
+	MOVD $961, R11
+	BR   callbackasm1(SB)
+	MOVD $962, R11
+	BR   callbackasm1(SB)
+	MOVD $963, R11
+	BR   callbackasm1(SB)
+	MOVD $964, R11
+	BR   callbackasm1(SB)
+	MOVD $965, R11
+	BR   callbackasm1(SB)
+	MOVD $966, R11
+	BR   callbackasm1(SB)
+	MOVD $967, R11
+	BR   callbackasm1(SB)
+	MOVD $968, R11
+	BR   callbackasm1(SB)
+	MOVD $969, R11
+	BR   callbackasm1(SB)
+	MOVD $970, R11
+	BR   callbackasm1(SB)
+	MOVD $971, R11
+	BR   callbackasm1(SB)
+	MOVD $972, R11
+	BR   callbackasm1(SB)
+	MOVD $973, R11
+	BR   callbackasm1(SB)
+	MOVD $974, R11
+	BR   callbackasm1(SB)
+	MOVD $975, R11
+	BR   callbackasm1(SB)
+	MOVD $976, R11
+	BR   callbackasm1(SB)
+	MOVD $977, R11
+	BR   callbackasm1(SB)
+	MOVD $978, R11
+	BR   callbackasm1(SB)
+	MOVD $979, R11
+	BR   callbackasm1(SB)
+	MOVD $980, R11
+	BR   callbackasm1(SB)
+	MOVD $981, R11
+	BR   callbackasm1(SB)
+	MOVD $982, R11
+	BR   callbackasm1(SB)
+	MOVD $983, R11
+	BR   callbackasm1(SB)
+	MOVD $984, R11
+	BR   callbackasm1(SB)
+	MOVD $985, R11
+	BR   callbackasm1(SB)
+	MOVD $986, R11
+	BR   callbackasm1(SB)
+	MOVD $987, R11
+	BR   callbackasm1(SB)
+	MOVD $988, R11
+	BR   callbackasm1(SB)
+	MOVD $989, R11
+	BR   callbackasm1(SB)
+	MOVD $990, R11
+	BR   callbackasm1(SB)
+	MOVD $991, R11
+	BR   callbackasm1(SB)
+	MOVD $992, R11
+	BR   callbackasm1(SB)
+	MOVD $993, R11
+	BR   callbackasm1(SB)
+	MOVD $994, R11
+	BR   callbackasm1(SB)
+	MOVD $995, R11
+	BR   callbackasm1(SB)
+	MOVD $996, R11
+	BR   callbackasm1(SB)
+	MOVD $997, R11
+	BR   callbackasm1(SB)
+	MOVD $998, R11
+	BR   callbackasm1(SB)
+	MOVD $999, R11
+	BR   callbackasm1(SB)
+	MOVD $1000, R11
+	BR   callbackasm1(SB)
+	MOVD $1001, R11
+	BR   callbackasm1(SB)
+	MOVD $1002, R11
+	BR   callbackasm1(SB)
+	MOVD $1003, R11
+	BR   callbackasm1(SB)
+	MOVD $1004, R11
+	BR   callbackasm1(SB)
+	MOVD $1005, R11
+	BR   callbackasm1(SB)
+	MOVD $1006, R11
+	BR   callbackasm1(SB)
+	MOVD $1007, R11
+	BR   callbackasm1(SB)
+	MOVD $1008, R11
+	BR   callbackasm1(SB)
+	MOVD $1009, R11
+	BR   callbackasm1(SB)
+	MOVD $1010, R11
+	BR   callbackasm1(SB)
+	MOVD $1011, R11
+	BR   callbackasm1(SB)
+	MOVD $1012, R11
+	BR   callbackasm1(SB)
+	MOVD $1013, R11
+	BR   callbackasm1(SB)
+	MOVD $1014, R11
+	BR   callbackasm1(SB)
+	MOVD $1015, R11
+	BR   callbackasm1(SB)
+	MOVD $1016, R11
+	BR   callbackasm1(SB)
+	MOVD $1017, R11
+	BR   callbackasm1(SB)
+	MOVD $1018, R11
+	BR   callbackasm1(SB)
+	MOVD $1019, R11
+	BR   callbackasm1(SB)
+	MOVD $1020, R11
+	BR   callbackasm1(SB)
+	MOVD $1021, R11
+	BR   callbackasm1(SB)
+	MOVD $1022, R11
+	BR   callbackasm1(SB)
+	MOVD $1023, R11
+	BR   callbackasm1(SB)
+	MOVD $1024, R11
+	BR   callbackasm1(SB)
+	MOVD $1025, R11
+	BR   callbackasm1(SB)
+	MOVD $1026, R11
+	BR   callbackasm1(SB)
+	MOVD $1027, R11
+	BR   callbackasm1(SB)
+	MOVD $1028, R11
+	BR   callbackasm1(SB)
+	MOVD $1029, R11
+	BR   callbackasm1(SB)
+	MOVD $1030, R11
+	BR   callbackasm1(SB)
+	MOVD $1031, R11
+	BR   callbackasm1(SB)
+	MOVD $1032, R11
+	BR   callbackasm1(SB)
+	MOVD $1033, R11
+	BR   callbackasm1(SB)
+	MOVD $1034, R11
+	BR   callbackasm1(SB)
+	MOVD $1035, R11
+	BR   callbackasm1(SB)
+	MOVD $1036, R11
+	BR   callbackasm1(SB)
+	MOVD $1037, R11
+	BR   callbackasm1(SB)
+	MOVD $1038, R11
+	BR   callbackasm1(SB)
+	MOVD $1039, R11
+	BR   callbackasm1(SB)
+	MOVD $1040, R11
+	BR   callbackasm1(SB)
+	MOVD $1041, R11
+	BR   callbackasm1(SB)
+	MOVD $1042, R11
+	BR   callbackasm1(SB)
+	MOVD $1043, R11
+	BR   callbackasm1(SB)
+	MOVD $1044, R11
+	BR   callbackasm1(SB)
+	MOVD $1045, R11
+	BR   callbackasm1(SB)
+	MOVD $1046, R11
+	BR   callbackasm1(SB)
+	MOVD $1047, R11
+	BR   callbackasm1(SB)
+	MOVD $1048, R11
+	BR   callbackasm1(SB)
+	MOVD $1049, R11
+	BR   callbackasm1(SB)
+	MOVD $1050, R11
+	BR   callbackasm1(SB)
+	MOVD $1051, R11
+	BR   callbackasm1(SB)
+	MOVD $1052, R11
+	BR   callbackasm1(SB)
+	MOVD $1053, R11
+	BR   callbackasm1(SB)
+	MOVD $1054, R11
+	BR   callbackasm1(SB)
+	MOVD $1055, R11
+	BR   callbackasm1(SB)
+	MOVD $1056, R11
+	BR   callbackasm1(SB)
+	MOVD $1057, R11
+	BR   callbackasm1(SB)
+	MOVD $1058, R11
+	BR   callbackasm1(SB)
+	MOVD $1059, R11
+	BR   callbackasm1(SB)
+	MOVD $1060, R11
+	BR   callbackasm1(SB)
+	MOVD $1061, R11
+	BR   callbackasm1(SB)
+	MOVD $1062, R11
+	BR   callbackasm1(SB)
+	MOVD $1063, R11
+	BR   callbackasm1(SB)
+	MOVD $1064, R11
+	BR   callbackasm1(SB)
+	MOVD $1065, R11
+	BR   callbackasm1(SB)
+	MOVD $1066, R11
+	BR   callbackasm1(SB)
+	MOVD $1067, R11
+	BR   callbackasm1(SB)
+	MOVD $1068, R11
+	BR   callbackasm1(SB)
+	MOVD $1069, R11
+	BR   callbackasm1(SB)
+	MOVD $1070, R11
+	BR   callbackasm1(SB)
+	MOVD $1071, R11
+	BR   callbackasm1(SB)
+	MOVD $1072, R11
+	BR   callbackasm1(SB)
+	MOVD $1073, R11
+	BR   callbackasm1(SB)
+	MOVD $1074, R11
+	BR   callbackasm1(SB)
+	MOVD $1075, R11
+	BR   callbackasm1(SB)
+	MOVD $1076, R11
+	BR   callbackasm1(SB)
+	MOVD $1077, R11
+	BR   callbackasm1(SB)
+	MOVD $1078, R11
+	BR   callbackasm1(SB)
+	MOVD $1079, R11
+	BR   callbackasm1(SB)
+	MOVD $1080, R11
+	BR   callbackasm1(SB)
+	MOVD $1081, R11
+	BR   callbackasm1(SB)
+	MOVD $1082, R11
+	BR   callbackasm1(SB)
+	MOVD $1083, R11
+	BR   callbackasm1(SB)
+	MOVD $1084, R11
+	BR   callbackasm1(SB)
+	MOVD $1085, R11
+	BR   callbackasm1(SB)
+	MOVD $1086, R11
+	BR   callbackasm1(SB)
+	MOVD $1087, R11
+	BR   callbackasm1(SB)
+	MOVD $1088, R11
+	BR   callbackasm1(SB)
+	MOVD $1089, R11
+	BR   callbackasm1(SB)
+	MOVD $1090, R11
+	BR   callbackasm1(SB)
+	MOVD $1091, R11
+	BR   callbackasm1(SB)
+	MOVD $1092, R11
+	BR   callbackasm1(SB)
+	MOVD $1093, R11
+	BR   callbackasm1(SB)
+	MOVD $1094, R11
+	BR   callbackasm1(SB)
+	MOVD $1095, R11
+	BR   callbackasm1(SB)
+	MOVD $1096, R11
+	BR   callbackasm1(SB)
+	MOVD $1097, R11
+	BR   callbackasm1(SB)
+	MOVD $1098, R11
+	BR   callbackasm1(SB)
+	MOVD $1099, R11
+	BR   callbackasm1(SB)
+	MOVD $1100, R11
+	BR   callbackasm1(SB)
+	MOVD $1101, R11
+	BR   callbackasm1(SB)
+	MOVD $1102, R11
+	BR   callbackasm1(SB)
+	MOVD $1103, R11
+	BR   callbackasm1(SB)
+	MOVD $1104, R11
+	BR   callbackasm1(SB)
+	MOVD $1105, R11
+	BR   callbackasm1(SB)
+	MOVD $1106, R11
+	BR   callbackasm1(SB)
+	MOVD $1107, R11
+	BR   callbackasm1(SB)
+	MOVD $1108, R11
+	BR   callbackasm1(SB)
+	MOVD $1109, R11
+	BR   callbackasm1(SB)
+	MOVD $1110, R11
+	BR   callbackasm1(SB)
+	MOVD $1111, R11
+	BR   callbackasm1(SB)
+	MOVD $1112, R11
+	BR   callbackasm1(SB)
+	MOVD $1113, R11
+	BR   callbackasm1(SB)
+	MOVD $1114, R11
+	BR   callbackasm1(SB)
+	MOVD $1115, R11
+	BR   callbackasm1(SB)
+	MOVD $1116, R11
+	BR   callbackasm1(SB)
+	MOVD $1117, R11
+	BR   callbackasm1(SB)
+	MOVD $1118, R11
+	BR   callbackasm1(SB)
+	MOVD $1119, R11
+	BR   callbackasm1(SB)
+	MOVD $1120, R11
+	BR   callbackasm1(SB)
+	MOVD $1121, R11
+	BR   callbackasm1(SB)
+	MOVD $1122, R11
+	BR   callbackasm1(SB)
+	MOVD $1123, R11
+	BR   callbackasm1(SB)
+	MOVD $1124, R11
+	BR   callbackasm1(SB)
+	MOVD $1125, R11
+	BR   callbackasm1(SB)
+	MOVD $1126, R11
+	BR   callbackasm1(SB)
+	MOVD $1127, R11
+	BR   callbackasm1(SB)
+	MOVD $1128, R11
+	BR   callbackasm1(SB)
+	MOVD $1129, R11
+	BR   callbackasm1(SB)
+	MOVD $1130, R11
+	BR   callbackasm1(SB)
+	MOVD $1131, R11
+	BR   callbackasm1(SB)
+	MOVD $1132, R11
+	BR   callbackasm1(SB)
+	MOVD $1133, R11
+	BR   callbackasm1(SB)
+	MOVD $1134, R11
+	BR   callbackasm1(SB)
+	MOVD $1135, R11
+	BR   callbackasm1(SB)
+	MOVD $1136, R11
+	BR   callbackasm1(SB)
+	MOVD $1137, R11
+	BR   callbackasm1(SB)
+	MOVD $1138, R11
+	BR   callbackasm1(SB)
+	MOVD $1139, R11
+	BR   callbackasm1(SB)
+	MOVD $1140, R11
+	BR   callbackasm1(SB)
+	MOVD $1141, R11
+	BR   callbackasm1(SB)
+	MOVD $1142, R11
+	BR   callbackasm1(SB)
+	MOVD $1143, R11
+	BR   callbackasm1(SB)
+	MOVD $1144, R11
+	BR   callbackasm1(SB)
+	MOVD $1145, R11
+	BR   callbackasm1(SB)
+	MOVD $1146, R11
+	BR   callbackasm1(SB)
+	MOVD $1147, R11
+	BR   callbackasm1(SB)
+	MOVD $1148, R11
+	BR   callbackasm1(SB)
+	MOVD $1149, R11
+	BR   callbackasm1(SB)
+	MOVD $1150, R11
+	BR   callbackasm1(SB)
+	MOVD $1151, R11
+	BR   callbackasm1(SB)
+	MOVD $1152, R11
+	BR   callbackasm1(SB)
+	MOVD $1153, R11
+	BR   callbackasm1(SB)
+	MOVD $1154, R11
+	BR   callbackasm1(SB)
+	MOVD $1155, R11
+	BR   callbackasm1(SB)
+	MOVD $1156, R11
+	BR   callbackasm1(SB)
+	MOVD $1157, R11
+	BR   callbackasm1(SB)
+	MOVD $1158, R11
+	BR   callbackasm1(SB)
+	MOVD $1159, R11
+	BR   callbackasm1(SB)
+	MOVD $1160, R11
+	BR   callbackasm1(SB)
+	MOVD $1161, R11
+	BR   callbackasm1(SB)
+	MOVD $1162, R11
+	BR   callbackasm1(SB)
+	MOVD $1163, R11
+	BR   callbackasm1(SB)
+	MOVD $1164, R11
+	BR   callbackasm1(SB)
+	MOVD $1165, R11
+	BR   callbackasm1(SB)
+	MOVD $1166, R11
+	BR   callbackasm1(SB)
+	MOVD $1167, R11
+	BR   callbackasm1(SB)
+	MOVD $1168, R11
+	BR   callbackasm1(SB)
+	MOVD $1169, R11
+	BR   callbackasm1(SB)
+	MOVD $1170, R11
+	BR   callbackasm1(SB)
+	MOVD $1171, R11
+	BR   callbackasm1(SB)
+	MOVD $1172, R11
+	BR   callbackasm1(SB)
+	MOVD $1173, R11
+	BR   callbackasm1(SB)
+	MOVD $1174, R11
+	BR   callbackasm1(SB)
+	MOVD $1175, R11
+	BR   callbackasm1(SB)
+	MOVD $1176, R11
+	BR   callbackasm1(SB)
+	MOVD $1177, R11
+	BR   callbackasm1(SB)
+	MOVD $1178, R11
+	BR   callbackasm1(SB)
+	MOVD $1179, R11
+	BR   callbackasm1(SB)
+	MOVD $1180, R11
+	BR   callbackasm1(SB)
+	MOVD $1181, R11
+	BR   callbackasm1(SB)
+	MOVD $1182, R11
+	BR   callbackasm1(SB)
+	MOVD $1183, R11
+	BR   callbackasm1(SB)
+	MOVD $1184, R11
+	BR   callbackasm1(SB)
+	MOVD $1185, R11
+	BR   callbackasm1(SB)
+	MOVD $1186, R11
+	BR   callbackasm1(SB)
+	MOVD $1187, R11
+	BR   callbackasm1(SB)
+	MOVD $1188, R11
+	BR   callbackasm1(SB)
+	MOVD $1189, R11
+	BR   callbackasm1(SB)
+	MOVD $1190, R11
+	BR   callbackasm1(SB)
+	MOVD $1191, R11
+	BR   callbackasm1(SB)
+	MOVD $1192, R11
+	BR   callbackasm1(SB)
+	MOVD $1193, R11
+	BR   callbackasm1(SB)
+	MOVD $1194, R11
+	BR   callbackasm1(SB)
+	MOVD $1195, R11
+	BR   callbackasm1(SB)
+	MOVD $1196, R11
+	BR   callbackasm1(SB)
+	MOVD $1197, R11
+	BR   callbackasm1(SB)
+	MOVD $1198, R11
+	BR   callbackasm1(SB)
+	MOVD $1199, R11
+	BR   callbackasm1(SB)
+	MOVD $1200, R11
+	BR   callbackasm1(SB)
+	MOVD $1201, R11
+	BR   callbackasm1(SB)
+	MOVD $1202, R11
+	BR   callbackasm1(SB)
+	MOVD $1203, R11
+	BR   callbackasm1(SB)
+	MOVD $1204, R11
+	BR   callbackasm1(SB)
+	MOVD $1205, R11
+	BR   callbackasm1(SB)
+	MOVD $1206, R11
+	BR   callbackasm1(SB)
+	MOVD $1207, R11
+	BR   callbackasm1(SB)
+	MOVD $1208, R11
+	BR   callbackasm1(SB)
+	MOVD $1209, R11
+	BR   callbackasm1(SB)
+	MOVD $1210, R11
+	BR   callbackasm1(SB)
+	MOVD $1211, R11
+	BR   callbackasm1(SB)
+	MOVD $1212, R11
+	BR   callbackasm1(SB)
+	MOVD $1213, R11
+	BR   callbackasm1(SB)
+	MOVD $1214, R11
+	BR   callbackasm1(SB)
+	MOVD $1215, R11
+	BR   callbackasm1(SB)
+	MOVD $1216, R11
+	BR   callbackasm1(SB)
+	MOVD $1217, R11
+	BR   callbackasm1(SB)
+	MOVD $1218, R11
+	BR   callbackasm1(SB)
+	MOVD $1219, R11
+	BR   callbackasm1(SB)
+	MOVD $1220, R11
+	BR   callbackasm1(SB)
+	MOVD $1221, R11
+	BR   callbackasm1(SB)
+	MOVD $1222, R11
+	BR   callbackasm1(SB)
+	MOVD $1223, R11
+	BR   callbackasm1(SB)
+	MOVD $1224, R11
+	BR   callbackasm1(SB)
+	MOVD $1225, R11
+	BR   callbackasm1(SB)
+	MOVD $1226, R11
+	BR   callbackasm1(SB)
+	MOVD $1227, R11
+	BR   callbackasm1(SB)
+	MOVD $1228, R11
+	BR   callbackasm1(SB)
+	MOVD $1229, R11
+	BR   callbackasm1(SB)
+	MOVD $1230, R11
+	BR   callbackasm1(SB)
+	MOVD $1231, R11
+	BR   callbackasm1(SB)
+	MOVD $1232, R11
+	BR   callbackasm1(SB)
+	MOVD $1233, R11
+	BR   callbackasm1(SB)
+	MOVD $1234, R11
+	BR   callbackasm1(SB)
+	MOVD $1235, R11
+	BR   callbackasm1(SB)
+	MOVD $1236, R11
+	BR   callbackasm1(SB)
+	MOVD $1237, R11
+	BR   callbackasm1(SB)
+	MOVD $1238, R11
+	BR   callbackasm1(SB)
+	MOVD $1239, R11
+	BR   callbackasm1(SB)
+	MOVD $1240, R11
+	BR   callbackasm1(SB)
+	MOVD $1241, R11
+	BR   callbackasm1(SB)
+	MOVD $1242, R11
+	BR   callbackasm1(SB)
+	MOVD $1243, R11
+	BR   callbackasm1(SB)
+	MOVD $1244, R11
+	BR   callbackasm1(SB)
+	MOVD $1245, R11
+	BR   callbackasm1(SB)
+	MOVD $1246, R11
+	BR   callbackasm1(SB)
+	MOVD $1247, R11
+	BR   callbackasm1(SB)
+	MOVD $1248, R11
+	BR   callbackasm1(SB)
+	MOVD $1249, R11
+	BR   callbackasm1(SB)
+	MOVD $1250, R11
+	BR   callbackasm1(SB)
+	MOVD $1251, R11
+	BR   callbackasm1(SB)
+	MOVD $1252, R11
+	BR   callbackasm1(SB)
+	MOVD $1253, R11
+	BR   callbackasm1(SB)
+	MOVD $1254, R11
+	BR   callbackasm1(SB)
+	MOVD $1255, R11
+	BR   callbackasm1(SB)
+	MOVD $1256, R11
+	BR   callbackasm1(SB)
+	MOVD $1257, R11
+	BR   callbackasm1(SB)
+	MOVD $1258, R11
+	BR   callbackasm1(SB)
+	MOVD $1259, R11
+	BR   callbackasm1(SB)
+	MOVD $1260, R11
+	BR   callbackasm1(SB)
+	MOVD $1261, R11
+	BR   callbackasm1(SB)
+	MOVD $1262, R11
+	BR   callbackasm1(SB)
+	MOVD $1263, R11
+	BR   callbackasm1(SB)
+	MOVD $1264, R11
+	BR   callbackasm1(SB)
+	MOVD $1265, R11
+	BR   callbackasm1(SB)
+	MOVD $1266, R11
+	BR   callbackasm1(SB)
+	MOVD $1267, R11
+	BR   callbackasm1(SB)
+	MOVD $1268, R11
+	BR   callbackasm1(SB)
+	MOVD $1269, R11
+	BR   callbackasm1(SB)
+	MOVD $1270, R11
+	BR   callbackasm1(SB)
+	MOVD $1271, R11
+	BR   callbackasm1(SB)
+	MOVD $1272, R11
+	BR   callbackasm1(SB)
+	MOVD $1273, R11
+	BR   callbackasm1(SB)
+	MOVD $1274, R11
+	BR   callbackasm1(SB)
+	MOVD $1275, R11
+	BR   callbackasm1(SB)
+	MOVD $1276, R11
+	BR   callbackasm1(SB)
+	MOVD $1277, R11
+	BR   callbackasm1(SB)
+	MOVD $1278, R11
+	BR   callbackasm1(SB)
+	MOVD $1279, R11
+	BR   callbackasm1(SB)
+	MOVD $1280, R11
+	BR   callbackasm1(SB)
+	MOVD $1281, R11
+	BR   callbackasm1(SB)
+	MOVD $1282, R11
+	BR   callbackasm1(SB)
+	MOVD $1283, R11
+	BR   callbackasm1(SB)
+	MOVD $1284, R11
+	BR   callbackasm1(SB)
+	MOVD $1285, R11
+	BR   callbackasm1(SB)
+	MOVD $1286, R11
+	BR   callbackasm1(SB)
+	MOVD $1287, R11
+	BR   callbackasm1(SB)
+	MOVD $1288, R11
+	BR   callbackasm1(SB)
+	MOVD $1289, R11
+	BR   callbackasm1(SB)
+	MOVD $1290, R11
+	BR   callbackasm1(SB)
+	MOVD $1291, R11
+	BR   callbackasm1(SB)
+	MOVD $1292, R11
+	BR   callbackasm1(SB)
+	MOVD $1293, R11
+	BR   callbackasm1(SB)
+	MOVD $1294, R11
+	BR   callbackasm1(SB)
+	MOVD $1295, R11
+	BR   callbackasm1(SB)
+	MOVD $1296, R11
+	BR   callbackasm1(SB)
+	MOVD $1297, R11
+	BR   callbackasm1(SB)
+	MOVD $1298, R11
+	BR   callbackasm1(SB)
+	MOVD $1299, R11
+	BR   callbackasm1(SB)
+	MOVD $1300, R11
+	BR   callbackasm1(SB)
+	MOVD $1301, R11
+	BR   callbackasm1(SB)
+	MOVD $1302, R11
+	BR   callbackasm1(SB)
+	MOVD $1303, R11
+	BR   callbackasm1(SB)
+	MOVD $1304, R11
+	BR   callbackasm1(SB)
+	MOVD $1305, R11
+	BR   callbackasm1(SB)
+	MOVD $1306, R11
+	BR   callbackasm1(SB)
+	MOVD $1307, R11
+	BR   callbackasm1(SB)
+	MOVD $1308, R11
+	BR   callbackasm1(SB)
+	MOVD $1309, R11
+	BR   callbackasm1(SB)
+	MOVD $1310, R11
+	BR   callbackasm1(SB)
+	MOVD $1311, R11
+	BR   callbackasm1(SB)
+	MOVD $1312, R11
+	BR   callbackasm1(SB)
+	MOVD $1313, R11
+	BR   callbackasm1(SB)
+	MOVD $1314, R11
+	BR   callbackasm1(SB)
+	MOVD $1315, R11
+	BR   callbackasm1(SB)
+	MOVD $1316, R11
+	BR   callbackasm1(SB)
+	MOVD $1317, R11
+	BR   callbackasm1(SB)
+	MOVD $1318, R11
+	BR   callbackasm1(SB)
+	MOVD $1319, R11
+	BR   callbackasm1(SB)
+	MOVD $1320, R11
+	BR   callbackasm1(SB)
+	MOVD $1321, R11
+	BR   callbackasm1(SB)
+	MOVD $1322, R11
+	BR   callbackasm1(SB)
+	MOVD $1323, R11
+	BR   callbackasm1(SB)
+	MOVD $1324, R11
+	BR   callbackasm1(SB)
+	MOVD $1325, R11
+	BR   callbackasm1(SB)
+	MOVD $1326, R11
+	BR   callbackasm1(SB)
+	MOVD $1327, R11
+	BR   callbackasm1(SB)
+	MOVD $1328, R11
+	BR   callbackasm1(SB)
+	MOVD $1329, R11
+	BR   callbackasm1(SB)
+	MOVD $1330, R11
+	BR   callbackasm1(SB)
+	MOVD $1331, R11
+	BR   callbackasm1(SB)
+	MOVD $1332, R11
+	BR   callbackasm1(SB)
+	MOVD $1333, R11
+	BR   callbackasm1(SB)
+	MOVD $1334, R11
+	BR   callbackasm1(SB)
+	MOVD $1335, R11
+	BR   callbackasm1(SB)
+	MOVD $1336, R11
+	BR   callbackasm1(SB)
+	MOVD $1337, R11
+	BR   callbackasm1(SB)
+	MOVD $1338, R11
+	BR   callbackasm1(SB)
+	MOVD $1339, R11
+	BR   callbackasm1(SB)
+	MOVD $1340, R11
+	BR   callbackasm1(SB)
+	MOVD $1341, R11
+	BR   callbackasm1(SB)
+	MOVD $1342, R11
+	BR   callbackasm1(SB)
+	MOVD $1343, R11
+	BR   callbackasm1(SB)
+	MOVD $1344, R11
+	BR   callbackasm1(SB)
+	MOVD $1345, R11
+	BR   callbackasm1(SB)
+	MOVD $1346, R11
+	BR   callbackasm1(SB)
+	MOVD $1347, R11
+	BR   callbackasm1(SB)
+	MOVD $1348, R11
+	BR   callbackasm1(SB)
+	MOVD $1349, R11
+	BR   callbackasm1(SB)
+	MOVD $1350, R11
+	BR   callbackasm1(SB)
+	MOVD $1351, R11
+	BR   callbackasm1(SB)
+	MOVD $1352, R11
+	BR   callbackasm1(SB)
+	MOVD $1353, R11
+	BR   callbackasm1(SB)
+	MOVD $1354, R11
+	BR   callbackasm1(SB)
+	MOVD $1355, R11
+	BR   callbackasm1(SB)
+	MOVD $1356, R11
+	BR   callbackasm1(SB)
+	MOVD $1357, R11
+	BR   callbackasm1(SB)
+	MOVD $1358, R11
+	BR   callbackasm1(SB)
+	MOVD $1359, R11
+	BR   callbackasm1(SB)
+	MOVD $1360, R11
+	BR   callbackasm1(SB)
+	MOVD $1361, R11
+	BR   callbackasm1(SB)
+	MOVD $1362, R11
+	BR   callbackasm1(SB)
+	MOVD $1363, R11
+	BR   callbackasm1(SB)
+	MOVD $1364, R11
+	BR   callbackasm1(SB)
+	MOVD $1365, R11
+	BR   callbackasm1(SB)
+	MOVD $1366, R11
+	BR   callbackasm1(SB)
+	MOVD $1367, R11
+	BR   callbackasm1(SB)
+	MOVD $1368, R11
+	BR   callbackasm1(SB)
+	MOVD $1369, R11
+	BR   callbackasm1(SB)
+	MOVD $1370, R11
+	BR   callbackasm1(SB)
+	MOVD $1371, R11
+	BR   callbackasm1(SB)
+	MOVD $1372, R11
+	BR   callbackasm1(SB)
+	MOVD $1373, R11
+	BR   callbackasm1(SB)
+	MOVD $1374, R11
+	BR   callbackasm1(SB)
+	MOVD $1375, R11
+	BR   callbackasm1(SB)
+	MOVD $1376, R11
+	BR   callbackasm1(SB)
+	MOVD $1377, R11
+	BR   callbackasm1(SB)
+	MOVD $1378, R11
+	BR   callbackasm1(SB)
+	MOVD $1379, R11
+	BR   callbackasm1(SB)
+	MOVD $1380, R11
+	BR   callbackasm1(SB)
+	MOVD $1381, R11
+	BR   callbackasm1(SB)
+	MOVD $1382, R11
+	BR   callbackasm1(SB)
+	MOVD $1383, R11
+	BR   callbackasm1(SB)
+	MOVD $1384, R11
+	BR   callbackasm1(SB)
+	MOVD $1385, R11
+	BR   callbackasm1(SB)
+	MOVD $1386, R11
+	BR   callbackasm1(SB)
+	MOVD $1387, R11
+	BR   callbackasm1(SB)
+	MOVD $1388, R11
+	BR   callbackasm1(SB)
+	MOVD $1389, R11
+	BR   callbackasm1(SB)
+	MOVD $1390, R11
+	BR   callbackasm1(SB)
+	MOVD $1391, R11
+	BR   callbackasm1(SB)
+	MOVD $1392, R11
+	BR   callbackasm1(SB)
+	MOVD $1393, R11
+	BR   callbackasm1(SB)
+	MOVD $1394, R11
+	BR   callbackasm1(SB)
+	MOVD $1395, R11
+	BR   callbackasm1(SB)
+	MOVD $1396, R11
+	BR   callbackasm1(SB)
+	MOVD $1397, R11
+	BR   callbackasm1(SB)
+	MOVD $1398, R11
+	BR   callbackasm1(SB)
+	MOVD $1399, R11
+	BR   callbackasm1(SB)
+	MOVD $1400, R11
+	BR   callbackasm1(SB)
+	MOVD $1401, R11
+	BR   callbackasm1(SB)
+	MOVD $1402, R11
+	BR   callbackasm1(SB)
+	MOVD $1403, R11
+	BR   callbackasm1(SB)
+	MOVD $1404, R11
+	BR   callbackasm1(SB)
+	MOVD $1405, R11
+	BR   callbackasm1(SB)
+	MOVD $1406, R11
+	BR   callbackasm1(SB)
+	MOVD $1407, R11
+	BR   callbackasm1(SB)
+	MOVD $1408, R11
+	BR   callbackasm1(SB)
+	MOVD $1409, R11
+	BR   callbackasm1(SB)
+	MOVD $1410, R11
+	BR   callbackasm1(SB)
+	MOVD $1411, R11
+	BR   callbackasm1(SB)
+	MOVD $1412, R11
+	BR   callbackasm1(SB)
+	MOVD $1413, R11
+	BR   callbackasm1(SB)
+	MOVD $1414, R11
+	BR   callbackasm1(SB)
+	MOVD $1415, R11
+	BR   callbackasm1(SB)
+	MOVD $1416, R11
+	BR   callbackasm1(SB)
+	MOVD $1417, R11
+	BR   callbackasm1(SB)
+	MOVD $1418, R11
+	BR   callbackasm1(SB)
+	MOVD $1419, R11
+	BR   callbackasm1(SB)
+	MOVD $1420, R11
+	BR   callbackasm1(SB)
+	MOVD $1421, R11
+	BR   callbackasm1(SB)
+	MOVD $1422, R11
+	BR   callbackasm1(SB)
+	MOVD $1423, R11
+	BR   callbackasm1(SB)
+	MOVD $1424, R11
+	BR   callbackasm1(SB)
+	MOVD $1425, R11
+	BR   callbackasm1(SB)
+	MOVD $1426, R11
+	BR   callbackasm1(SB)
+	MOVD $1427, R11
+	BR   callbackasm1(SB)
+	MOVD $1428, R11
+	BR   callbackasm1(SB)
+	MOVD $1429, R11
+	BR   callbackasm1(SB)
+	MOVD $1430, R11
+	BR   callbackasm1(SB)
+	MOVD $1431, R11
+	BR   callbackasm1(SB)
+	MOVD $1432, R11
+	BR   callbackasm1(SB)
+	MOVD $1433, R11
+	BR   callbackasm1(SB)
+	MOVD $1434, R11
+	BR   callbackasm1(SB)
+	MOVD $1435, R11
+	BR   callbackasm1(SB)
+	MOVD $1436, R11
+	BR   callbackasm1(SB)
+	MOVD $1437, R11
+	BR   callbackasm1(SB)
+	MOVD $1438, R11
+	BR   callbackasm1(SB)
+	MOVD $1439, R11
+	BR   callbackasm1(SB)
+	MOVD $1440, R11
+	BR   callbackasm1(SB)
+	MOVD $1441, R11
+	BR   callbackasm1(SB)
+	MOVD $1442, R11
+	BR   callbackasm1(SB)
+	MOVD $1443, R11
+	BR   callbackasm1(SB)
+	MOVD $1444, R11
+	BR   callbackasm1(SB)
+	MOVD $1445, R11
+	BR   callbackasm1(SB)
+	MOVD $1446, R11
+	BR   callbackasm1(SB)
+	MOVD $1447, R11
+	BR   callbackasm1(SB)
+	MOVD $1448, R11
+	BR   callbackasm1(SB)
+	MOVD $1449, R11
+	BR   callbackasm1(SB)
+	MOVD $1450, R11
+	BR   callbackasm1(SB)
+	MOVD $1451, R11
+	BR   callbackasm1(SB)
+	MOVD $1452, R11
+	BR   callbackasm1(SB)
+	MOVD $1453, R11
+	BR   callbackasm1(SB)
+	MOVD $1454, R11
+	BR   callbackasm1(SB)
+	MOVD $1455, R11
+	BR   callbackasm1(SB)
+	MOVD $1456, R11
+	BR   callbackasm1(SB)
+	MOVD $1457, R11
+	BR   callbackasm1(SB)
+	MOVD $1458, R11
+	BR   callbackasm1(SB)
+	MOVD $1459, R11
+	BR   callbackasm1(SB)
+	MOVD $1460, R11
+	BR   callbackasm1(SB)
+	MOVD $1461, R11
+	BR   callbackasm1(SB)
+	MOVD $1462, R11
+	BR   callbackasm1(SB)
+	MOVD $1463, R11
+	BR   callbackasm1(SB)
+	MOVD $1464, R11
+	BR   callbackasm1(SB)
+	MOVD $1465, R11
+	BR   callbackasm1(SB)
+	MOVD $1466, R11
+	BR   callbackasm1(SB)
+	MOVD $1467, R11
+	BR   callbackasm1(SB)
+	MOVD $1468, R11
+	BR   callbackasm1(SB)
+	MOVD $1469, R11
+	BR   callbackasm1(SB)
+	MOVD $1470, R11
+	BR   callbackasm1(SB)
+	MOVD $1471, R11
+	BR   callbackasm1(SB)
+	MOVD $1472, R11
+	BR   callbackasm1(SB)
+	MOVD $1473, R11
+	BR   callbackasm1(SB)
+	MOVD $1474, R11
+	BR   callbackasm1(SB)
+	MOVD $1475, R11
+	BR   callbackasm1(SB)
+	MOVD $1476, R11
+	BR   callbackasm1(SB)
+	MOVD $1477, R11
+	BR   callbackasm1(SB)
+	MOVD $1478, R11
+	BR   callbackasm1(SB)
+	MOVD $1479, R11
+	BR   callbackasm1(SB)
+	MOVD $1480, R11
+	BR   callbackasm1(SB)
+	MOVD $1481, R11
+	BR   callbackasm1(SB)
+	MOVD $1482, R11
+	BR   callbackasm1(SB)
+	MOVD $1483, R11
+	BR   callbackasm1(SB)
+	MOVD $1484, R11
+	BR   callbackasm1(SB)
+	MOVD $1485, R11
+	BR   callbackasm1(SB)
+	MOVD $1486, R11
+	BR   callbackasm1(SB)
+	MOVD $1487, R11
+	BR   callbackasm1(SB)
+	MOVD $1488, R11
+	BR   callbackasm1(SB)
+	MOVD $1489, R11
+	BR   callbackasm1(SB)
+	MOVD $1490, R11
+	BR   callbackasm1(SB)
+	MOVD $1491, R11
+	BR   callbackasm1(SB)
+	MOVD $1492, R11
+	BR   callbackasm1(SB)
+	MOVD $1493, R11
+	BR   callbackasm1(SB)
+	MOVD $1494, R11
+	BR   callbackasm1(SB)
+	MOVD $1495, R11
+	BR   callbackasm1(SB)
+	MOVD $1496, R11
+	BR   callbackasm1(SB)
+	MOVD $1497, R11
+	BR   callbackasm1(SB)
+	MOVD $1498, R11
+	BR   callbackasm1(SB)
+	MOVD $1499, R11
+	BR   callbackasm1(SB)
+	MOVD $1500, R11
+	BR   callbackasm1(SB)
+	MOVD $1501, R11
+	BR   callbackasm1(SB)
+	MOVD $1502, R11
+	BR   callbackasm1(SB)
+	MOVD $1503, R11
+	BR   callbackasm1(SB)
+	MOVD $1504, R11
+	BR   callbackasm1(SB)
+	MOVD $1505, R11
+	BR   callbackasm1(SB)
+	MOVD $1506, R11
+	BR   callbackasm1(SB)
+	MOVD $1507, R11
+	BR   callbackasm1(SB)
+	MOVD $1508, R11
+	BR   callbackasm1(SB)
+	MOVD $1509, R11
+	BR   callbackasm1(SB)
+	MOVD $1510, R11
+	BR   callbackasm1(SB)
+	MOVD $1511, R11
+	BR   callbackasm1(SB)
+	MOVD $1512, R11
+	BR   callbackasm1(SB)
+	MOVD $1513, R11
+	BR   callbackasm1(SB)
+	MOVD $1514, R11
+	BR   callbackasm1(SB)
+	MOVD $1515, R11
+	BR   callbackasm1(SB)
+	MOVD $1516, R11
+	BR   callbackasm1(SB)
+	MOVD $1517, R11
+	BR   callbackasm1(SB)
+	MOVD $1518, R11
+	BR   callbackasm1(SB)
+	MOVD $1519, R11
+	BR   callbackasm1(SB)
+	MOVD $1520, R11
+	BR   callbackasm1(SB)
+	MOVD $1521, R11
+	BR   callbackasm1(SB)
+	MOVD $1522, R11
+	BR   callbackasm1(SB)
+	MOVD $1523, R11
+	BR   callbackasm1(SB)
+	MOVD $1524, R11
+	BR   callbackasm1(SB)
+	MOVD $1525, R11
+	BR   callbackasm1(SB)
+	MOVD $1526, R11
+	BR   callbackasm1(SB)
+	MOVD $1527, R11
+	BR   callbackasm1(SB)
+	MOVD $1528, R11
+	BR   callbackasm1(SB)
+	MOVD $1529, R11
+	BR   callbackasm1(SB)
+	MOVD $1530, R11
+	BR   callbackasm1(SB)
+	MOVD $1531, R11
+	BR   callbackasm1(SB)
+	MOVD $1532, R11
+	BR   callbackasm1(SB)
+	MOVD $1533, R11
+	BR   callbackasm1(SB)
+	MOVD $1534, R11
+	BR   callbackasm1(SB)
+	MOVD $1535, R11
+	BR   callbackasm1(SB)
+	MOVD $1536, R11
+	BR   callbackasm1(SB)
+	MOVD $1537, R11
+	BR   callbackasm1(SB)
+	MOVD $1538, R11
+	BR   callbackasm1(SB)
+	MOVD $1539, R11
+	BR   callbackasm1(SB)
+	MOVD $1540, R11
+	BR   callbackasm1(SB)
+	MOVD $1541, R11
+	BR   callbackasm1(SB)
+	MOVD $1542, R11
+	BR   callbackasm1(SB)
+	MOVD $1543, R11
+	BR   callbackasm1(SB)
+	MOVD $1544, R11
+	BR   callbackasm1(SB)
+	MOVD $1545, R11
+	BR   callbackasm1(SB)
+	MOVD $1546, R11
+	BR   callbackasm1(SB)
+	MOVD $1547, R11
+	BR   callbackasm1(SB)
+	MOVD $1548, R11
+	BR   callbackasm1(SB)
+	MOVD $1549, R11
+	BR   callbackasm1(SB)
+	MOVD $1550, R11
+	BR   callbackasm1(SB)
+	MOVD $1551, R11
+	BR   callbackasm1(SB)
+	MOVD $1552, R11
+	BR   callbackasm1(SB)
+	MOVD $1553, R11
+	BR   callbackasm1(SB)
+	MOVD $1554, R11
+	BR   callbackasm1(SB)
+	MOVD $1555, R11
+	BR   callbackasm1(SB)
+	MOVD $1556, R11
+	BR   callbackasm1(SB)
+	MOVD $1557, R11
+	BR   callbackasm1(SB)
+	MOVD $1558, R11
+	BR   callbackasm1(SB)
+	MOVD $1559, R11
+	BR   callbackasm1(SB)
+	MOVD $1560, R11
+	BR   callbackasm1(SB)
+	MOVD $1561, R11
+	BR   callbackasm1(SB)
+	MOVD $1562, R11
+	BR   callbackasm1(SB)
+	MOVD $1563, R11
+	BR   callbackasm1(SB)
+	MOVD $1564, R11
+	BR   callbackasm1(SB)
+	MOVD $1565, R11
+	BR   callbackasm1(SB)
+	MOVD $1566, R11
+	BR   callbackasm1(SB)
+	MOVD $1567, R11
+	BR   callbackasm1(SB)
+	MOVD $1568, R11
+	BR   callbackasm1(SB)
+	MOVD $1569, R11
+	BR   callbackasm1(SB)
+	MOVD $1570, R11
+	BR   callbackasm1(SB)
+	MOVD $1571, R11
+	BR   callbackasm1(SB)
+	MOVD $1572, R11
+	BR   callbackasm1(SB)
+	MOVD $1573, R11
+	BR   callbackasm1(SB)
+	MOVD $1574, R11
+	BR   callbackasm1(SB)
+	MOVD $1575, R11
+	BR   callbackasm1(SB)
+	MOVD $1576, R11
+	BR   callbackasm1(SB)
+	MOVD $1577, R11
+	BR   callbackasm1(SB)
+	MOVD $1578, R11
+	BR   callbackasm1(SB)
+	MOVD $1579, R11
+	BR   callbackasm1(SB)
+	MOVD $1580, R11
+	BR   callbackasm1(SB)
+	MOVD $1581, R11
+	BR   callbackasm1(SB)
+	MOVD $1582, R11
+	BR   callbackasm1(SB)
+	MOVD $1583, R11
+	BR   callbackasm1(SB)
+	MOVD $1584, R11
+	BR   callbackasm1(SB)
+	MOVD $1585, R11
+	BR   callbackasm1(SB)
+	MOVD $1586, R11
+	BR   callbackasm1(SB)
+	MOVD $1587, R11
+	BR   callbackasm1(SB)
+	MOVD $1588, R11
+	BR   callbackasm1(SB)
+	MOVD $1589, R11
+	BR   callbackasm1(SB)
+	MOVD $1590, R11
+	BR   callbackasm1(SB)
+	MOVD $1591, R11
+	BR   callbackasm1(SB)
+	MOVD $1592, R11
+	BR   callbackasm1(SB)
+	MOVD $1593, R11
+	BR   callbackasm1(SB)
+	MOVD $1594, R11
+	BR   callbackasm1(SB)
+	MOVD $1595, R11
+	BR   callbackasm1(SB)
+	MOVD $1596, R11
+	BR   callbackasm1(SB)
+	MOVD $1597, R11
+	BR   callbackasm1(SB)
+	MOVD $1598, R11
+	BR   callbackasm1(SB)
+	MOVD $1599, R11
+	BR   callbackasm1(SB)
+	MOVD $1600, R11
+	BR   callbackasm1(SB)
+	MOVD $1601, R11
+	BR   callbackasm1(SB)
+	MOVD $1602, R11
+	BR   callbackasm1(SB)
+	MOVD $1603, R11
+	BR   callbackasm1(SB)
+	MOVD $1604, R11
+	BR   callbackasm1(SB)
+	MOVD $1605, R11
+	BR   callbackasm1(SB)
+	MOVD $1606, R11
+	BR   callbackasm1(SB)
+	MOVD $1607, R11
+	BR   callbackasm1(SB)
+	MOVD $1608, R11
+	BR   callbackasm1(SB)
+	MOVD $1609, R11
+	BR   callbackasm1(SB)
+	MOVD $1610, R11
+	BR   callbackasm1(SB)
+	MOVD $1611, R11
+	BR   callbackasm1(SB)
+	MOVD $1612, R11
+	BR   callbackasm1(SB)
+	MOVD $1613, R11
+	BR   callbackasm1(SB)
+	MOVD $1614, R11
+	BR   callbackasm1(SB)
+	MOVD $1615, R11
+	BR   callbackasm1(SB)
+	MOVD $1616, R11
+	BR   callbackasm1(SB)
+	MOVD $1617, R11
+	BR   callbackasm1(SB)
+	MOVD $1618, R11
+	BR   callbackasm1(SB)
+	MOVD $1619, R11
+	BR   callbackasm1(SB)
+	MOVD $1620, R11
+	BR   callbackasm1(SB)
+	MOVD $1621, R11
+	BR   callbackasm1(SB)
+	MOVD $1622, R11
+	BR   callbackasm1(SB)
+	MOVD $1623, R11
+	BR   callbackasm1(SB)
+	MOVD $1624, R11
+	BR   callbackasm1(SB)
+	MOVD $1625, R11
+	BR   callbackasm1(SB)
+	MOVD $1626, R11
+	BR   callbackasm1(SB)
+	MOVD $1627, R11
+	BR   callbackasm1(SB)
+	MOVD $1628, R11
+	BR   callbackasm1(SB)
+	MOVD $1629, R11
+	BR   callbackasm1(SB)
+	MOVD $1630, R11
+	BR   callbackasm1(SB)
+	MOVD $1631, R11
+	BR   callbackasm1(SB)
+	MOVD $1632, R11
+	BR   callbackasm1(SB)
+	MOVD $1633, R11
+	BR   callbackasm1(SB)
+	MOVD $1634, R11
+	BR   callbackasm1(SB)
+	MOVD $1635, R11
+	BR   callbackasm1(SB)
+	MOVD $1636, R11
+	BR   callbackasm1(SB)
+	MOVD $1637, R11
+	BR   callbackasm1(SB)
+	MOVD $1638, R11
+	BR   callbackasm1(SB)
+	MOVD $1639, R11
+	BR   callbackasm1(SB)
+	MOVD $1640, R11
+	BR   callbackasm1(SB)
+	MOVD $1641, R11
+	BR   callbackasm1(SB)
+	MOVD $1642, R11
+	BR   callbackasm1(SB)
+	MOVD $1643, R11
+	BR   callbackasm1(SB)
+	MOVD $1644, R11
+	BR   callbackasm1(SB)
+	MOVD $1645, R11
+	BR   callbackasm1(SB)
+	MOVD $1646, R11
+	BR   callbackasm1(SB)
+	MOVD $1647, R11
+	BR   callbackasm1(SB)
+	MOVD $1648, R11
+	BR   callbackasm1(SB)
+	MOVD $1649, R11
+	BR   callbackasm1(SB)
+	MOVD $1650, R11
+	BR   callbackasm1(SB)
+	MOVD $1651, R11
+	BR   callbackasm1(SB)
+	MOVD $1652, R11
+	BR   callbackasm1(SB)
+	MOVD $1653, R11
+	BR   callbackasm1(SB)
+	MOVD $1654, R11
+	BR   callbackasm1(SB)
+	MOVD $1655, R11
+	BR   callbackasm1(SB)
+	MOVD $1656, R11
+	BR   callbackasm1(SB)
+	MOVD $1657, R11
+	BR   callbackasm1(SB)
+	MOVD $1658, R11
+	BR   callbackasm1(SB)
+	MOVD $1659, R11
+	BR   callbackasm1(SB)
+	MOVD $1660, R11
+	BR   callbackasm1(SB)
+	MOVD $1661, R11
+	BR   callbackasm1(SB)
+	MOVD $1662, R11
+	BR   callbackasm1(SB)
+	MOVD $1663, R11
+	BR   callbackasm1(SB)
+	MOVD $1664, R11
+	BR   callbackasm1(SB)
+	MOVD $1665, R11
+	BR   callbackasm1(SB)
+	MOVD $1666, R11
+	BR   callbackasm1(SB)
+	MOVD $1667, R11
+	BR   callbackasm1(SB)
+	MOVD $1668, R11
+	BR   callbackasm1(SB)
+	MOVD $1669, R11
+	BR   callbackasm1(SB)
+	MOVD $1670, R11
+	BR   callbackasm1(SB)
+	MOVD $1671, R11
+	BR   callbackasm1(SB)
+	MOVD $1672, R11
+	BR   callbackasm1(SB)
+	MOVD $1673, R11
+	BR   callbackasm1(SB)
+	MOVD $1674, R11
+	BR   callbackasm1(SB)
+	MOVD $1675, R11
+	BR   callbackasm1(SB)
+	MOVD $1676, R11
+	BR   callbackasm1(SB)
+	MOVD $1677, R11
+	BR   callbackasm1(SB)
+	MOVD $1678, R11
+	BR   callbackasm1(SB)
+	MOVD $1679, R11
+	BR   callbackasm1(SB)
+	MOVD $1680, R11
+	BR   callbackasm1(SB)
+	MOVD $1681, R11
+	BR   callbackasm1(SB)
+	MOVD $1682, R11
+	BR   callbackasm1(SB)
+	MOVD $1683, R11
+	BR   callbackasm1(SB)
+	MOVD $1684, R11
+	BR   callbackasm1(SB)
+	MOVD $1685, R11
+	BR   callbackasm1(SB)
+	MOVD $1686, R11
+	BR   callbackasm1(SB)
+	MOVD $1687, R11
+	BR   callbackasm1(SB)
+	MOVD $1688, R11
+	BR   callbackasm1(SB)
+	MOVD $1689, R11
+	BR   callbackasm1(SB)
+	MOVD $1690, R11
+	BR   callbackasm1(SB)
+	MOVD $1691, R11
+	BR   callbackasm1(SB)
+	MOVD $1692, R11
+	BR   callbackasm1(SB)
+	MOVD $1693, R11
+	BR   callbackasm1(SB)
+	MOVD $1694, R11
+	BR   callbackasm1(SB)
+	MOVD $1695, R11
+	BR   callbackasm1(SB)
+	MOVD $1696, R11
+	BR   callbackasm1(SB)
+	MOVD $1697, R11
+	BR   callbackasm1(SB)
+	MOVD $1698, R11
+	BR   callbackasm1(SB)
+	MOVD $1699, R11
+	BR   callbackasm1(SB)
+	MOVD $1700, R11
+	BR   callbackasm1(SB)
+	MOVD $1701, R11
+	BR   callbackasm1(SB)
+	MOVD $1702, R11
+	BR   callbackasm1(SB)
+	MOVD $1703, R11
+	BR   callbackasm1(SB)
+	MOVD $1704, R11
+	BR   callbackasm1(SB)
+	MOVD $1705, R11
+	BR   callbackasm1(SB)
+	MOVD $1706, R11
+	BR   callbackasm1(SB)
+	MOVD $1707, R11
+	BR   callbackasm1(SB)
+	MOVD $1708, R11
+	BR   callbackasm1(SB)
+	MOVD $1709, R11
+	BR   callbackasm1(SB)
+	MOVD $1710, R11
+	BR   callbackasm1(SB)
+	MOVD $1711, R11
+	BR   callbackasm1(SB)
+	MOVD $1712, R11
+	BR   callbackasm1(SB)
+	MOVD $1713, R11
+	BR   callbackasm1(SB)
+	MOVD $1714, R11
+	BR   callbackasm1(SB)
+	MOVD $1715, R11
+	BR   callbackasm1(SB)
+	MOVD $1716, R11
+	BR   callbackasm1(SB)
+	MOVD $1717, R11
+	BR   callbackasm1(SB)
+	MOVD $1718, R11
+	BR   callbackasm1(SB)
+	MOVD $1719, R11
+	BR   callbackasm1(SB)
+	MOVD $1720, R11
+	BR   callbackasm1(SB)
+	MOVD $1721, R11
+	BR   callbackasm1(SB)
+	MOVD $1722, R11
+	BR   callbackasm1(SB)
+	MOVD $1723, R11
+	BR   callbackasm1(SB)
+	MOVD $1724, R11
+	BR   callbackasm1(SB)
+	MOVD $1725, R11
+	BR   callbackasm1(SB)
+	MOVD $1726, R11
+	BR   callbackasm1(SB)
+	MOVD $1727, R11
+	BR   callbackasm1(SB)
+	MOVD $1728, R11
+	BR   callbackasm1(SB)
+	MOVD $1729, R11
+	BR   callbackasm1(SB)
+	MOVD $1730, R11
+	BR   callbackasm1(SB)
+	MOVD $1731, R11
+	BR   callbackasm1(SB)
+	MOVD $1732, R11
+	BR   callbackasm1(SB)
+	MOVD $1733, R11
+	BR   callbackasm1(SB)
+	MOVD $1734, R11
+	BR   callbackasm1(SB)
+	MOVD $1735, R11
+	BR   callbackasm1(SB)
+	MOVD $1736, R11
+	BR   callbackasm1(SB)
+	MOVD $1737, R11
+	BR   callbackasm1(SB)
+	MOVD $1738, R11
+	BR   callbackasm1(SB)
+	MOVD $1739, R11
+	BR   callbackasm1(SB)
+	MOVD $1740, R11
+	BR   callbackasm1(SB)
+	MOVD $1741, R11
+	BR   callbackasm1(SB)
+	MOVD $1742, R11
+	BR   callbackasm1(SB)
+	MOVD $1743, R11
+	BR   callbackasm1(SB)
+	MOVD $1744, R11
+	BR   callbackasm1(SB)
+	MOVD $1745, R11
+	BR   callbackasm1(SB)
+	MOVD $1746, R11
+	BR   callbackasm1(SB)
+	MOVD $1747, R11
+	BR   callbackasm1(SB)
+	MOVD $1748, R11
+	BR   callbackasm1(SB)
+	MOVD $1749, R11
+	BR   callbackasm1(SB)
+	MOVD $1750, R11
+	BR   callbackasm1(SB)
+	MOVD $1751, R11
+	BR   callbackasm1(SB)
+	MOVD $1752, R11
+	BR   callbackasm1(SB)
+	MOVD $1753, R11
+	BR   callbackasm1(SB)
+	MOVD $1754, R11
+	BR   callbackasm1(SB)
+	MOVD $1755, R11
+	BR   callbackasm1(SB)
+	MOVD $1756, R11
+	BR   callbackasm1(SB)
+	MOVD $1757, R11
+	BR   callbackasm1(SB)
+	MOVD $1758, R11
+	BR   callbackasm1(SB)
+	MOVD $1759, R11
+	BR   callbackasm1(SB)
+	MOVD $1760, R11
+	BR   callbackasm1(SB)
+	MOVD $1761, R11
+	BR   callbackasm1(SB)
+	MOVD $1762, R11
+	BR   callbackasm1(SB)
+	MOVD $1763, R11
+	BR   callbackasm1(SB)
+	MOVD $1764, R11
+	BR   callbackasm1(SB)
+	MOVD $1765, R11
+	BR   callbackasm1(SB)
+	MOVD $1766, R11
+	BR   callbackasm1(SB)
+	MOVD $1767, R11
+	BR   callbackasm1(SB)
+	MOVD $1768, R11
+	BR   callbackasm1(SB)
+	MOVD $1769, R11
+	BR   callbackasm1(SB)
+	MOVD $1770, R11
+	BR   callbackasm1(SB)
+	MOVD $1771, R11
+	BR   callbackasm1(SB)
+	MOVD $1772, R11
+	BR   callbackasm1(SB)
+	MOVD $1773, R11
+	BR   callbackasm1(SB)
+	MOVD $1774, R11
+	BR   callbackasm1(SB)
+	MOVD $1775, R11
+	BR   callbackasm1(SB)
+	MOVD $1776, R11
+	BR   callbackasm1(SB)
+	MOVD $1777, R11
+	BR   callbackasm1(SB)
+	MOVD $1778, R11
+	BR   callbackasm1(SB)
+	MOVD $1779, R11
+	BR   callbackasm1(SB)
+	MOVD $1780, R11
+	BR   callbackasm1(SB)
+	MOVD $1781, R11
+	BR   callbackasm1(SB)
+	MOVD $1782, R11
+	BR   callbackasm1(SB)
+	MOVD $1783, R11
+	BR   callbackasm1(SB)
+	MOVD $1784, R11
+	BR   callbackasm1(SB)
+	MOVD $1785, R11
+	BR   callbackasm1(SB)
+	MOVD $1786, R11
+	BR   callbackasm1(SB)
+	MOVD $1787, R11
+	BR   callbackasm1(SB)
+	MOVD $1788, R11
+	BR   callbackasm1(SB)
+	MOVD $1789, R11
+	BR   callbackasm1(SB)
+	MOVD $1790, R11
+	BR   callbackasm1(SB)
+	MOVD $1791, R11
+	BR   callbackasm1(SB)
+	MOVD $1792, R11
+	BR   callbackasm1(SB)
+	MOVD $1793, R11
+	BR   callbackasm1(SB)
+	MOVD $1794, R11
+	BR   callbackasm1(SB)
+	MOVD $1795, R11
+	BR   callbackasm1(SB)
+	MOVD $1796, R11
+	BR   callbackasm1(SB)
+	MOVD $1797, R11
+	BR   callbackasm1(SB)
+	MOVD $1798, R11
+	BR   callbackasm1(SB)
+	MOVD $1799, R11
+	BR   callbackasm1(SB)
+	MOVD $1800, R11
+	BR   callbackasm1(SB)
+	MOVD $1801, R11
+	BR   callbackasm1(SB)
+	MOVD $1802, R11
+	BR   callbackasm1(SB)
+	MOVD $1803, R11
+	BR   callbackasm1(SB)
+	MOVD $1804, R11
+	BR   callbackasm1(SB)
+	MOVD $1805, R11
+	BR   callbackasm1(SB)
+	MOVD $1806, R11
+	BR   callbackasm1(SB)
+	MOVD $1807, R11
+	BR   callbackasm1(SB)
+	MOVD $1808, R11
+	BR   callbackasm1(SB)
+	MOVD $1809, R11
+	BR   callbackasm1(SB)
+	MOVD $1810, R11
+	BR   callbackasm1(SB)
+	MOVD $1811, R11
+	BR   callbackasm1(SB)
+	MOVD $1812, R11
+	BR   callbackasm1(SB)
+	MOVD $1813, R11
+	BR   callbackasm1(SB)
+	MOVD $1814, R11
+	BR   callbackasm1(SB)
+	MOVD $1815, R11
+	BR   callbackasm1(SB)
+	MOVD $1816, R11
+	BR   callbackasm1(SB)
+	MOVD $1817, R11
+	BR   callbackasm1(SB)
+	MOVD $1818, R11
+	BR   callbackasm1(SB)
+	MOVD $1819, R11
+	BR   callbackasm1(SB)
+	MOVD $1820, R11
+	BR   callbackasm1(SB)
+	MOVD $1821, R11
+	BR   callbackasm1(SB)
+	MOVD $1822, R11
+	BR   callbackasm1(SB)
+	MOVD $1823, R11
+	BR   callbackasm1(SB)
+	MOVD $1824, R11
+	BR   callbackasm1(SB)
+	MOVD $1825, R11
+	BR   callbackasm1(SB)
+	MOVD $1826, R11
+	BR   callbackasm1(SB)
+	MOVD $1827, R11
+	BR   callbackasm1(SB)
+	MOVD $1828, R11
+	BR   callbackasm1(SB)
+	MOVD $1829, R11
+	BR   callbackasm1(SB)
+	MOVD $1830, R11
+	BR   callbackasm1(SB)
+	MOVD $1831, R11
+	BR   callbackasm1(SB)
+	MOVD $1832, R11
+	BR   callbackasm1(SB)
+	MOVD $1833, R11
+	BR   callbackasm1(SB)
+	MOVD $1834, R11
+	BR   callbackasm1(SB)
+	MOVD $1835, R11
+	BR   callbackasm1(SB)
+	MOVD $1836, R11
+	BR   callbackasm1(SB)
+	MOVD $1837, R11
+	BR   callbackasm1(SB)
+	MOVD $1838, R11
+	BR   callbackasm1(SB)
+	MOVD $1839, R11
+	BR   callbackasm1(SB)
+	MOVD $1840, R11
+	BR   callbackasm1(SB)
+	MOVD $1841, R11
+	BR   callbackasm1(SB)
+	MOVD $1842, R11
+	BR   callbackasm1(SB)
+	MOVD $1843, R11
+	BR   callbackasm1(SB)
+	MOVD $1844, R11
+	BR   callbackasm1(SB)
+	MOVD $1845, R11
+	BR   callbackasm1(SB)
+	MOVD $1846, R11
+	BR   callbackasm1(SB)
+	MOVD $1847, R11
+	BR   callbackasm1(SB)
+	MOVD $1848, R11
+	BR   callbackasm1(SB)
+	MOVD $1849, R11
+	BR   callbackasm1(SB)
+	MOVD $1850, R11
+	BR   callbackasm1(SB)
+	MOVD $1851, R11
+	BR   callbackasm1(SB)
+	MOVD $1852, R11
+	BR   callbackasm1(SB)
+	MOVD $1853, R11
+	BR   callbackasm1(SB)
+	MOVD $1854, R11
+	BR   callbackasm1(SB)
+	MOVD $1855, R11
+	BR   callbackasm1(SB)
+	MOVD $1856, R11
+	BR   callbackasm1(SB)
+	MOVD $1857, R11
+	BR   callbackasm1(SB)
+	MOVD $1858, R11
+	BR   callbackasm1(SB)
+	MOVD $1859, R11
+	BR   callbackasm1(SB)
+	MOVD $1860, R11
+	BR   callbackasm1(SB)
+	MOVD $1861, R11
+	BR   callbackasm1(SB)
+	MOVD $1862, R11
+	BR   callbackasm1(SB)
+	MOVD $1863, R11
+	BR   callbackasm1(SB)
+	MOVD $1864, R11
+	BR   callbackasm1(SB)
+	MOVD $1865, R11
+	BR   callbackasm1(SB)
+	MOVD $1866, R11
+	BR   callbackasm1(SB)
+	MOVD $1867, R11
+	BR   callbackasm1(SB)
+	MOVD $1868, R11
+	BR   callbackasm1(SB)
+	MOVD $1869, R11
+	BR   callbackasm1(SB)
+	MOVD $1870, R11
+	BR   callbackasm1(SB)
+	MOVD $1871, R11
+	BR   callbackasm1(SB)
+	MOVD $1872, R11
+	BR   callbackasm1(SB)
+	MOVD $1873, R11
+	BR   callbackasm1(SB)
+	MOVD $1874, R11
+	BR   callbackasm1(SB)
+	MOVD $1875, R11
+	BR   callbackasm1(SB)
+	MOVD $1876, R11
+	BR   callbackasm1(SB)
+	MOVD $1877, R11
+	BR   callbackasm1(SB)
+	MOVD $1878, R11
+	BR   callbackasm1(SB)
+	MOVD $1879, R11
+	BR   callbackasm1(SB)
+	MOVD $1880, R11
+	BR   callbackasm1(SB)
+	MOVD $1881, R11
+	BR   callbackasm1(SB)
+	MOVD $1882, R11
+	BR   callbackasm1(SB)
+	MOVD $1883, R11
+	BR   callbackasm1(SB)
+	MOVD $1884, R11
+	BR   callbackasm1(SB)
+	MOVD $1885, R11
+	BR   callbackasm1(SB)
+	MOVD $1886, R11
+	BR   callbackasm1(SB)
+	MOVD $1887, R11
+	BR   callbackasm1(SB)
+	MOVD $1888, R11
+	BR   callbackasm1(SB)
+	MOVD $1889, R11
+	BR   callbackasm1(SB)
+	MOVD $1890, R11
+	BR   callbackasm1(SB)
+	MOVD $1891, R11
+	BR   callbackasm1(SB)
+	MOVD $1892, R11
+	BR   callbackasm1(SB)
+	MOVD $1893, R11
+	BR   callbackasm1(SB)
+	MOVD $1894, R11
+	BR   callbackasm1(SB)
+	MOVD $1895, R11
+	BR   callbackasm1(SB)
+	MOVD $1896, R11
+	BR   callbackasm1(SB)
+	MOVD $1897, R11
+	BR   callbackasm1(SB)
+	MOVD $1898, R11
+	BR   callbackasm1(SB)
+	MOVD $1899, R11
+	BR   callbackasm1(SB)
+	MOVD $1900, R11
+	BR   callbackasm1(SB)
+	MOVD $1901, R11
+	BR   callbackasm1(SB)
+	MOVD $1902, R11
+	BR   callbackasm1(SB)
+	MOVD $1903, R11
+	BR   callbackasm1(SB)
+	MOVD $1904, R11
+	BR   callbackasm1(SB)
+	MOVD $1905, R11
+	BR   callbackasm1(SB)
+	MOVD $1906, R11
+	BR   callbackasm1(SB)
+	MOVD $1907, R11
+	BR   callbackasm1(SB)
+	MOVD $1908, R11
+	BR   callbackasm1(SB)
+	MOVD $1909, R11
+	BR   callbackasm1(SB)
+	MOVD $1910, R11
+	BR   callbackasm1(SB)
+	MOVD $1911, R11
+	BR   callbackasm1(SB)
+	MOVD $1912, R11
+	BR   callbackasm1(SB)
+	MOVD $1913, R11
+	BR   callbackasm1(SB)
+	MOVD $1914, R11
+	BR   callbackasm1(SB)
+	MOVD $1915, R11
+	BR   callbackasm1(SB)
+	MOVD $1916, R11
+	BR   callbackasm1(SB)
+	MOVD $1917, R11
+	BR   callbackasm1(SB)
+	MOVD $1918, R11
+	BR   callbackasm1(SB)
+	MOVD $1919, R11
+	BR   callbackasm1(SB)
+	MOVD $1920, R11
+	BR   callbackasm1(SB)
+	MOVD $1921, R11
+	BR   callbackasm1(SB)
+	MOVD $1922, R11
+	BR   callbackasm1(SB)
+	MOVD $1923, R11
+	BR   callbackasm1(SB)
+	MOVD $1924, R11
+	BR   callbackasm1(SB)
+	MOVD $1925, R11
+	BR   callbackasm1(SB)
+	MOVD $1926, R11
+	BR   callbackasm1(SB)
+	MOVD $1927, R11
+	BR   callbackasm1(SB)
+	MOVD $1928, R11
+	BR   callbackasm1(SB)
+	MOVD $1929, R11
+	BR   callbackasm1(SB)
+	MOVD $1930, R11
+	BR   callbackasm1(SB)
+	MOVD $1931, R11
+	BR   callbackasm1(SB)
+	MOVD $1932, R11
+	BR   callbackasm1(SB)
+	MOVD $1933, R11
+	BR   callbackasm1(SB)
+	MOVD $1934, R11
+	BR   callbackasm1(SB)
+	MOVD $1935, R11
+	BR   callbackasm1(SB)
+	MOVD $1936, R11
+	BR   callbackasm1(SB)
+	MOVD $1937, R11
+	BR   callbackasm1(SB)
+	MOVD $1938, R11
+	BR   callbackasm1(SB)
+	MOVD $1939, R11
+	BR   callbackasm1(SB)
+	MOVD $1940, R11
+	BR   callbackasm1(SB)
+	MOVD $1941, R11
+	BR   callbackasm1(SB)
+	MOVD $1942, R11
+	BR   callbackasm1(SB)
+	MOVD $1943, R11
+	BR   callbackasm1(SB)
+	MOVD $1944, R11
+	BR   callbackasm1(SB)
+	MOVD $1945, R11
+	BR   callbackasm1(SB)
+	MOVD $1946, R11
+	BR   callbackasm1(SB)
+	MOVD $1947, R11
+	BR   callbackasm1(SB)
+	MOVD $1948, R11
+	BR   callbackasm1(SB)
+	MOVD $1949, R11
+	BR   callbackasm1(SB)
+	MOVD $1950, R11
+	BR   callbackasm1(SB)
+	MOVD $1951, R11
+	BR   callbackasm1(SB)
+	MOVD $1952, R11
+	BR   callbackasm1(SB)
+	MOVD $1953, R11
+	BR   callbackasm1(SB)
+	MOVD $1954, R11
+	BR   callbackasm1(SB)
+	MOVD $1955, R11
+	BR   callbackasm1(SB)
+	MOVD $1956, R11
+	BR   callbackasm1(SB)
+	MOVD $1957, R11
+	BR   callbackasm1(SB)
+	MOVD $1958, R11
+	BR   callbackasm1(SB)
+	MOVD $1959, R11
+	BR   callbackasm1(SB)
+	MOVD $1960, R11
+	BR   callbackasm1(SB)
+	MOVD $1961, R11
+	BR   callbackasm1(SB)
+	MOVD $1962, R11
+	BR   callbackasm1(SB)
+	MOVD $1963, R11
+	BR   callbackasm1(SB)
+	MOVD $1964, R11
+	BR   callbackasm1(SB)
+	MOVD $1965, R11
+	BR   callbackasm1(SB)
+	MOVD $1966, R11
+	BR   callbackasm1(SB)
+	MOVD $1967, R11
+	BR   callbackasm1(SB)
+	MOVD $1968, R11
+	BR   callbackasm1(SB)
+	MOVD $1969, R11
+	BR   callbackasm1(SB)
+	MOVD $1970, R11
+	BR   callbackasm1(SB)
+	MOVD $1971, R11
+	BR   callbackasm1(SB)
+	MOVD $1972, R11
+	BR   callbackasm1(SB)
+	MOVD $1973, R11
+	BR   callbackasm1(SB)
+	MOVD $1974, R11
+	BR   callbackasm1(SB)
+	MOVD $1975, R11
+	BR   callbackasm1(SB)
+	MOVD $1976, R11
+	BR   callbackasm1(SB)
+	MOVD $1977, R11
+	BR   callbackasm1(SB)
+	MOVD $1978, R11
+	BR   callbackasm1(SB)
+	MOVD $1979, R11
+	BR   callbackasm1(SB)
+	MOVD $1980, R11
+	BR   callbackasm1(SB)
+	MOVD $1981, R11
+	BR   callbackasm1(SB)
+	MOVD $1982, R11
+	BR   callbackasm1(SB)
+	MOVD $1983, R11
+	BR   callbackasm1(SB)
+	MOVD $1984, R11
+	BR   callbackasm1(SB)
+	MOVD $1985, R11
+	BR   callbackasm1(SB)
+	MOVD $1986, R11
+	BR   callbackasm1(SB)
+	MOVD $1987, R11
+	BR   callbackasm1(SB)
+	MOVD $1988, R11
+	BR   callbackasm1(SB)
+	MOVD $1989, R11
+	BR   callbackasm1(SB)
+	MOVD $1990, R11
+	BR   callbackasm1(SB)
+	MOVD $1991, R11
+	BR   callbackasm1(SB)
+	MOVD $1992, R11
+	BR   callbackasm1(SB)
+	MOVD $1993, R11
+	BR   callbackasm1(SB)
+	MOVD $1994, R11
+	BR   callbackasm1(SB)
+	MOVD $1995, R11
+	BR   callbackasm1(SB)
+	MOVD $1996, R11
+	BR   callbackasm1(SB)
+	MOVD $1997, R11
+	BR   callbackasm1(SB)
+	MOVD $1998, R11
+	BR   callbackasm1(SB)
+	MOVD $1999, R11
+	BR   callbackasm1(SB)
diff --git a/vendor/github.com/ebitengine/purego/zcallback_riscv64.s b/vendor/github.com/ebitengine/purego/zcallback_riscv64.s
new file mode 100644
index 000000000..f341a87ee
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/zcallback_riscv64.s
@@ -0,0 +1,4051 @@
+// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+
+//go:build darwin || freebsd || linux || netbsd
+
+// External code calls into callbackasm at an offset corresponding
+// to the callback index. Callbackasm is a table of MOV and JMP instructions.
+// Since Go 1.26, MOV instructions with immediate values lower than or equal to 32
+// are encoded in 2 bytes rather than 4 bytes, which breaks the assumption that each
+// callback entry is 8 bytes long. Therefore, for callback indices less than or equal to 32,
+// add a PCALIGN directive to align the next instruction to an 8-byte boundary.
+// The MOV instruction loads X7 with the callback index, and the
+// JMP instruction branches to callbackasm1.
+// callbackasm1 takes the callback index from X7 and
+// indexes into an array that stores information about each callback.
+// It then calls the Go implementation for that callback.
+#include "textflag.h"
+
+TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
+	PCALIGN $8
+	MOV     $0, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $1, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $2, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $3, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $4, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $5, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $6, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $7, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $8, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $9, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $10, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $11, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $12, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $13, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $14, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $15, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $16, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $17, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $18, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $19, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $20, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $21, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $22, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $23, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $24, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $25, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $26, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $27, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $28, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $29, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $30, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $31, X7
+	JMP     callbackasm1(SB)
+	PCALIGN $8
+	MOV     $32, X7
+	JMP     callbackasm1(SB)
+	MOV $33, X7
+	JMP callbackasm1(SB)
+	MOV $34, X7
+	JMP callbackasm1(SB)
+	MOV $35, X7
+	JMP callbackasm1(SB)
+	MOV $36, X7
+	JMP callbackasm1(SB)
+	MOV $37, X7
+	JMP callbackasm1(SB)
+	MOV $38, X7
+	JMP callbackasm1(SB)
+	MOV $39, X7
+	JMP callbackasm1(SB)
+	MOV $40, X7
+	JMP callbackasm1(SB)
+	MOV $41, X7
+	JMP callbackasm1(SB)
+	MOV $42, X7
+	JMP callbackasm1(SB)
+	MOV $43, X7
+	JMP callbackasm1(SB)
+	MOV $44, X7
+	JMP callbackasm1(SB)
+	MOV $45, X7
+	JMP callbackasm1(SB)
+	MOV $46, X7
+	JMP callbackasm1(SB)
+	MOV $47, X7
+	JMP callbackasm1(SB)
+	MOV $48, X7
+	JMP callbackasm1(SB)
+	MOV $49, X7
+	JMP callbackasm1(SB)
+	MOV $50, X7
+	JMP callbackasm1(SB)
+	MOV $51, X7
+	JMP callbackasm1(SB)
+	MOV $52, X7
+	JMP callbackasm1(SB)
+	MOV $53, X7
+	JMP callbackasm1(SB)
+	MOV $54, X7
+	JMP callbackasm1(SB)
+	MOV $55, X7
+	JMP callbackasm1(SB)
+	MOV $56, X7
+	JMP callbackasm1(SB)
+	MOV $57, X7
+	JMP callbackasm1(SB)
+	MOV $58, X7
+	JMP callbackasm1(SB)
+	MOV $59, X7
+	JMP callbackasm1(SB)
+	MOV $60, X7
+	JMP callbackasm1(SB)
+	MOV $61, X7
+	JMP callbackasm1(SB)
+	MOV $62, X7
+	JMP callbackasm1(SB)
+	MOV $63, X7
+	JMP callbackasm1(SB)
+	MOV $64, X7
+	JMP callbackasm1(SB)
+	MOV $65, X7
+	JMP callbackasm1(SB)
+	MOV $66, X7
+	JMP callbackasm1(SB)
+	MOV $67, X7
+	JMP callbackasm1(SB)
+	MOV $68, X7
+	JMP callbackasm1(SB)
+	MOV $69, X7
+	JMP callbackasm1(SB)
+	MOV $70, X7
+	JMP callbackasm1(SB)
+	MOV $71, X7
+	JMP callbackasm1(SB)
+	MOV $72, X7
+	JMP callbackasm1(SB)
+	MOV $73, X7
+	JMP callbackasm1(SB)
+	MOV $74, X7
+	JMP callbackasm1(SB)
+	MOV $75, X7
+	JMP callbackasm1(SB)
+	MOV $76, X7
+	JMP callbackasm1(SB)
+	MOV $77, X7
+	JMP callbackasm1(SB)
+	MOV $78, X7
+	JMP callbackasm1(SB)
+	MOV $79, X7
+	JMP callbackasm1(SB)
+	MOV $80, X7
+	JMP callbackasm1(SB)
+	MOV $81, X7
+	JMP callbackasm1(SB)
+	MOV $82, X7
+	JMP callbackasm1(SB)
+	MOV $83, X7
+	JMP callbackasm1(SB)
+	MOV $84, X7
+	JMP callbackasm1(SB)
+	MOV $85, X7
+	JMP callbackasm1(SB)
+	MOV $86, X7
+	JMP callbackasm1(SB)
+	MOV $87, X7
+	JMP callbackasm1(SB)
+	MOV $88, X7
+	JMP callbackasm1(SB)
+	MOV $89, X7
+	JMP callbackasm1(SB)
+	MOV $90, X7
+	JMP callbackasm1(SB)
+	MOV $91, X7
+	JMP callbackasm1(SB)
+	MOV $92, X7
+	JMP callbackasm1(SB)
+	MOV $93, X7
+	JMP callbackasm1(SB)
+	MOV $94, X7
+	JMP callbackasm1(SB)
+	MOV $95, X7
+	JMP callbackasm1(SB)
+	MOV $96, X7
+	JMP callbackasm1(SB)
+	MOV $97, X7
+	JMP callbackasm1(SB)
+	MOV $98, X7
+	JMP callbackasm1(SB)
+	MOV $99, X7
+	JMP callbackasm1(SB)
+	MOV $100, X7
+	JMP callbackasm1(SB)
+	MOV $101, X7
+	JMP callbackasm1(SB)
+	MOV $102, X7
+	JMP callbackasm1(SB)
+	MOV $103, X7
+	JMP callbackasm1(SB)
+	MOV $104, X7
+	JMP callbackasm1(SB)
+	MOV $105, X7
+	JMP callbackasm1(SB)
+	MOV $106, X7
+	JMP callbackasm1(SB)
+	MOV $107, X7
+	JMP callbackasm1(SB)
+	MOV $108, X7
+	JMP callbackasm1(SB)
+	MOV $109, X7
+	JMP callbackasm1(SB)
+	MOV $110, X7
+	JMP callbackasm1(SB)
+	MOV $111, X7
+	JMP callbackasm1(SB)
+	MOV $112, X7
+	JMP callbackasm1(SB)
+	MOV $113, X7
+	JMP callbackasm1(SB)
+	MOV $114, X7
+	JMP callbackasm1(SB)
+	MOV $115, X7
+	JMP callbackasm1(SB)
+	MOV $116, X7
+	JMP callbackasm1(SB)
+	MOV $117, X7
+	JMP callbackasm1(SB)
+	MOV $118, X7
+	JMP callbackasm1(SB)
+	MOV $119, X7
+	JMP callbackasm1(SB)
+	MOV $120, X7
+	JMP callbackasm1(SB)
+	MOV $121, X7
+	JMP callbackasm1(SB)
+	MOV $122, X7
+	JMP callbackasm1(SB)
+	MOV $123, X7
+	JMP callbackasm1(SB)
+	MOV $124, X7
+	JMP callbackasm1(SB)
+	MOV $125, X7
+	JMP callbackasm1(SB)
+	MOV $126, X7
+	JMP callbackasm1(SB)
+	MOV $127, X7
+	JMP callbackasm1(SB)
+	MOV $128, X7
+	JMP callbackasm1(SB)
+	MOV $129, X7
+	JMP callbackasm1(SB)
+	MOV $130, X7
+	JMP callbackasm1(SB)
+	MOV $131, X7
+	JMP callbackasm1(SB)
+	MOV $132, X7
+	JMP callbackasm1(SB)
+	MOV $133, X7
+	JMP callbackasm1(SB)
+	MOV $134, X7
+	JMP callbackasm1(SB)
+	MOV $135, X7
+	JMP callbackasm1(SB)
+	MOV $136, X7
+	JMP callbackasm1(SB)
+	MOV $137, X7
+	JMP callbackasm1(SB)
+	MOV $138, X7
+	JMP callbackasm1(SB)
+	MOV $139, X7
+	JMP callbackasm1(SB)
+	MOV $140, X7
+	JMP callbackasm1(SB)
+	MOV $141, X7
+	JMP callbackasm1(SB)
+	MOV $142, X7
+	JMP callbackasm1(SB)
+	MOV $143, X7
+	JMP callbackasm1(SB)
+	MOV $144, X7
+	JMP callbackasm1(SB)
+	MOV $145, X7
+	JMP callbackasm1(SB)
+	MOV $146, X7
+	JMP callbackasm1(SB)
+	MOV $147, X7
+	JMP callbackasm1(SB)
+	MOV $148, X7
+	JMP callbackasm1(SB)
+	MOV $149, X7
+	JMP callbackasm1(SB)
+	MOV $150, X7
+	JMP callbackasm1(SB)
+	MOV $151, X7
+	JMP callbackasm1(SB)
+	MOV $152, X7
+	JMP callbackasm1(SB)
+	MOV $153, X7
+	JMP callbackasm1(SB)
+	MOV $154, X7
+	JMP callbackasm1(SB)
+	MOV $155, X7
+	JMP callbackasm1(SB)
+	MOV $156, X7
+	JMP callbackasm1(SB)
+	MOV $157, X7
+	JMP callbackasm1(SB)
+	MOV $158, X7
+	JMP callbackasm1(SB)
+	MOV $159, X7
+	JMP callbackasm1(SB)
+	MOV $160, X7
+	JMP callbackasm1(SB)
+	MOV $161, X7
+	JMP callbackasm1(SB)
+	MOV $162, X7
+	JMP callbackasm1(SB)
+	MOV $163, X7
+	JMP callbackasm1(SB)
+	MOV $164, X7
+	JMP callbackasm1(SB)
+	MOV $165, X7
+	JMP callbackasm1(SB)
+	MOV $166, X7
+	JMP callbackasm1(SB)
+	MOV $167, X7
+	JMP callbackasm1(SB)
+	MOV $168, X7
+	JMP callbackasm1(SB)
+	MOV $169, X7
+	JMP callbackasm1(SB)
+	MOV $170, X7
+	JMP callbackasm1(SB)
+	MOV $171, X7
+	JMP callbackasm1(SB)
+	MOV $172, X7
+	JMP callbackasm1(SB)
+	MOV $173, X7
+	JMP callbackasm1(SB)
+	MOV $174, X7
+	JMP callbackasm1(SB)
+	MOV $175, X7
+	JMP callbackasm1(SB)
+	MOV $176, X7
+	JMP callbackasm1(SB)
+	MOV $177, X7
+	JMP callbackasm1(SB)
+	MOV $178, X7
+	JMP callbackasm1(SB)
+	MOV $179, X7
+	JMP callbackasm1(SB)
+	MOV $180, X7
+	JMP callbackasm1(SB)
+	MOV $181, X7
+	JMP callbackasm1(SB)
+	MOV $182, X7
+	JMP callbackasm1(SB)
+	MOV $183, X7
+	JMP callbackasm1(SB)
+	MOV $184, X7
+	JMP callbackasm1(SB)
+	MOV $185, X7
+	JMP callbackasm1(SB)
+	MOV $186, X7
+	JMP callbackasm1(SB)
+	MOV $187, X7
+	JMP callbackasm1(SB)
+	MOV $188, X7
+	JMP callbackasm1(SB)
+	MOV $189, X7
+	JMP callbackasm1(SB)
+	MOV $190, X7
+	JMP callbackasm1(SB)
+	MOV $191, X7
+	JMP callbackasm1(SB)
+	MOV $192, X7
+	JMP callbackasm1(SB)
+	MOV $193, X7
+	JMP callbackasm1(SB)
+	MOV $194, X7
+	JMP callbackasm1(SB)
+	MOV $195, X7
+	JMP callbackasm1(SB)
+	MOV $196, X7
+	JMP callbackasm1(SB)
+	MOV $197, X7
+	JMP callbackasm1(SB)
+	MOV $198, X7
+	JMP callbackasm1(SB)
+	MOV $199, X7
+	JMP callbackasm1(SB)
+	MOV $200, X7
+	JMP callbackasm1(SB)
+	MOV $201, X7
+	JMP callbackasm1(SB)
+	MOV $202, X7
+	JMP callbackasm1(SB)
+	MOV $203, X7
+	JMP callbackasm1(SB)
+	MOV $204, X7
+	JMP callbackasm1(SB)
+	MOV $205, X7
+	JMP callbackasm1(SB)
+	MOV $206, X7
+	JMP callbackasm1(SB)
+	MOV $207, X7
+	JMP callbackasm1(SB)
+	MOV $208, X7
+	JMP callbackasm1(SB)
+	MOV $209, X7
+	JMP callbackasm1(SB)
+	MOV $210, X7
+	JMP callbackasm1(SB)
+	MOV $211, X7
+	JMP callbackasm1(SB)
+	MOV $212, X7
+	JMP callbackasm1(SB)
+	MOV $213, X7
+	JMP callbackasm1(SB)
+	MOV $214, X7
+	JMP callbackasm1(SB)
+	MOV $215, X7
+	JMP callbackasm1(SB)
+	MOV $216, X7
+	JMP callbackasm1(SB)
+	MOV $217, X7
+	JMP callbackasm1(SB)
+	MOV $218, X7
+	JMP callbackasm1(SB)
+	MOV $219, X7
+	JMP callbackasm1(SB)
+	MOV $220, X7
+	JMP callbackasm1(SB)
+	MOV $221, X7
+	JMP callbackasm1(SB)
+	MOV $222, X7
+	JMP callbackasm1(SB)
+	MOV $223, X7
+	JMP callbackasm1(SB)
+	MOV $224, X7
+	JMP callbackasm1(SB)
+	MOV $225, X7
+	JMP callbackasm1(SB)
+	MOV $226, X7
+	JMP callbackasm1(SB)
+	MOV $227, X7
+	JMP callbackasm1(SB)
+	MOV $228, X7
+	JMP callbackasm1(SB)
+	MOV $229, X7
+	JMP callbackasm1(SB)
+	MOV $230, X7
+	JMP callbackasm1(SB)
+	MOV $231, X7
+	JMP callbackasm1(SB)
+	MOV $232, X7
+	JMP callbackasm1(SB)
+	MOV $233, X7
+	JMP callbackasm1(SB)
+	MOV $234, X7
+	JMP callbackasm1(SB)
+	MOV $235, X7
+	JMP callbackasm1(SB)
+	MOV $236, X7
+	JMP callbackasm1(SB)
+	MOV $237, X7
+	JMP callbackasm1(SB)
+	MOV $238, X7
+	JMP callbackasm1(SB)
+	MOV $239, X7
+	JMP callbackasm1(SB)
+	MOV $240, X7
+	JMP callbackasm1(SB)
+	MOV $241, X7
+	JMP callbackasm1(SB)
+	MOV $242, X7
+	JMP callbackasm1(SB)
+	MOV $243, X7
+	JMP callbackasm1(SB)
+	MOV $244, X7
+	JMP callbackasm1(SB)
+	MOV $245, X7
+	JMP callbackasm1(SB)
+	MOV $246, X7
+	JMP callbackasm1(SB)
+	MOV $247, X7
+	JMP callbackasm1(SB)
+	MOV $248, X7
+	JMP callbackasm1(SB)
+	MOV $249, X7
+	JMP callbackasm1(SB)
+	MOV $250, X7
+	JMP callbackasm1(SB)
+	MOV $251, X7
+	JMP callbackasm1(SB)
+	MOV $252, X7
+	JMP callbackasm1(SB)
+	MOV $253, X7
+	JMP callbackasm1(SB)
+	MOV $254, X7
+	JMP callbackasm1(SB)
+	MOV $255, X7
+	JMP callbackasm1(SB)
+	MOV $256, X7
+	JMP callbackasm1(SB)
+	MOV $257, X7
+	JMP callbackasm1(SB)
+	MOV $258, X7
+	JMP callbackasm1(SB)
+	MOV $259, X7
+	JMP callbackasm1(SB)
+	MOV $260, X7
+	JMP callbackasm1(SB)
+	MOV $261, X7
+	JMP callbackasm1(SB)
+	MOV $262, X7
+	JMP callbackasm1(SB)
+	MOV $263, X7
+	JMP callbackasm1(SB)
+	MOV $264, X7
+	JMP callbackasm1(SB)
+	MOV $265, X7
+	JMP callbackasm1(SB)
+	MOV $266, X7
+	JMP callbackasm1(SB)
+	MOV $267, X7
+	JMP callbackasm1(SB)
+	MOV $268, X7
+	JMP callbackasm1(SB)
+	MOV $269, X7
+	JMP callbackasm1(SB)
+	MOV $270, X7
+	JMP callbackasm1(SB)
+	MOV $271, X7
+	JMP callbackasm1(SB)
+	MOV $272, X7
+	JMP callbackasm1(SB)
+	MOV $273, X7
+	JMP callbackasm1(SB)
+	MOV $274, X7
+	JMP callbackasm1(SB)
+	MOV $275, X7
+	JMP callbackasm1(SB)
+	MOV $276, X7
+	JMP callbackasm1(SB)
+	MOV $277, X7
+	JMP callbackasm1(SB)
+	MOV $278, X7
+	JMP callbackasm1(SB)
+	MOV $279, X7
+	JMP callbackasm1(SB)
+	MOV $280, X7
+	JMP callbackasm1(SB)
+	MOV $281, X7
+	JMP callbackasm1(SB)
+	MOV $282, X7
+	JMP callbackasm1(SB)
+	MOV $283, X7
+	JMP callbackasm1(SB)
+	MOV $284, X7
+	JMP callbackasm1(SB)
+	MOV $285, X7
+	JMP callbackasm1(SB)
+	MOV $286, X7
+	JMP callbackasm1(SB)
+	MOV $287, X7
+	JMP callbackasm1(SB)
+	MOV $288, X7
+	JMP callbackasm1(SB)
+	MOV $289, X7
+	JMP callbackasm1(SB)
+	MOV $290, X7
+	JMP callbackasm1(SB)
+	MOV $291, X7
+	JMP callbackasm1(SB)
+	MOV $292, X7
+	JMP callbackasm1(SB)
+	MOV $293, X7
+	JMP callbackasm1(SB)
+	MOV $294, X7
+	JMP callbackasm1(SB)
+	MOV $295, X7
+	JMP callbackasm1(SB)
+	MOV $296, X7
+	JMP callbackasm1(SB)
+	MOV $297, X7
+	JMP callbackasm1(SB)
+	MOV $298, X7
+	JMP callbackasm1(SB)
+	MOV $299, X7
+	JMP callbackasm1(SB)
+	MOV $300, X7
+	JMP callbackasm1(SB)
+	MOV $301, X7
+	JMP callbackasm1(SB)
+	MOV $302, X7
+	JMP callbackasm1(SB)
+	MOV $303, X7
+	JMP callbackasm1(SB)
+	MOV $304, X7
+	JMP callbackasm1(SB)
+	MOV $305, X7
+	JMP callbackasm1(SB)
+	MOV $306, X7
+	JMP callbackasm1(SB)
+	MOV $307, X7
+	JMP callbackasm1(SB)
+	MOV $308, X7
+	JMP callbackasm1(SB)
+	MOV $309, X7
+	JMP callbackasm1(SB)
+	MOV $310, X7
+	JMP callbackasm1(SB)
+	MOV $311, X7
+	JMP callbackasm1(SB)
+	MOV $312, X7
+	JMP callbackasm1(SB)
+	MOV $313, X7
+	JMP callbackasm1(SB)
+	MOV $314, X7
+	JMP callbackasm1(SB)
+	MOV $315, X7
+	JMP callbackasm1(SB)
+	MOV $316, X7
+	JMP callbackasm1(SB)
+	MOV $317, X7
+	JMP callbackasm1(SB)
+	MOV $318, X7
+	JMP callbackasm1(SB)
+	MOV $319, X7
+	JMP callbackasm1(SB)
+	MOV $320, X7
+	JMP callbackasm1(SB)
+	MOV $321, X7
+	JMP callbackasm1(SB)
+	MOV $322, X7
+	JMP callbackasm1(SB)
+	MOV $323, X7
+	JMP callbackasm1(SB)
+	MOV $324, X7
+	JMP callbackasm1(SB)
+	MOV $325, X7
+	JMP callbackasm1(SB)
+	MOV $326, X7
+	JMP callbackasm1(SB)
+	MOV $327, X7
+	JMP callbackasm1(SB)
+	MOV $328, X7
+	JMP callbackasm1(SB)
+	MOV $329, X7
+	JMP callbackasm1(SB)
+	MOV $330, X7
+	JMP callbackasm1(SB)
+	MOV $331, X7
+	JMP callbackasm1(SB)
+	MOV $332, X7
+	JMP callbackasm1(SB)
+	MOV $333, X7
+	JMP callbackasm1(SB)
+	MOV $334, X7
+	JMP callbackasm1(SB)
+	MOV $335, X7
+	JMP callbackasm1(SB)
+	MOV $336, X7
+	JMP callbackasm1(SB)
+	MOV $337, X7
+	JMP callbackasm1(SB)
+	MOV $338, X7
+	JMP callbackasm1(SB)
+	MOV $339, X7
+	JMP callbackasm1(SB)
+	MOV $340, X7
+	JMP callbackasm1(SB)
+	MOV $341, X7
+	JMP callbackasm1(SB)
+	MOV $342, X7
+	JMP callbackasm1(SB)
+	MOV $343, X7
+	JMP callbackasm1(SB)
+	MOV $344, X7
+	JMP callbackasm1(SB)
+	MOV $345, X7
+	JMP callbackasm1(SB)
+	MOV $346, X7
+	JMP callbackasm1(SB)
+	MOV $347, X7
+	JMP callbackasm1(SB)
+	MOV $348, X7
+	JMP callbackasm1(SB)
+	MOV $349, X7
+	JMP callbackasm1(SB)
+	MOV $350, X7
+	JMP callbackasm1(SB)
+	MOV $351, X7
+	JMP callbackasm1(SB)
+	MOV $352, X7
+	JMP callbackasm1(SB)
+	MOV $353, X7
+	JMP callbackasm1(SB)
+	MOV $354, X7
+	JMP callbackasm1(SB)
+	MOV $355, X7
+	JMP callbackasm1(SB)
+	MOV $356, X7
+	JMP callbackasm1(SB)
+	MOV $357, X7
+	JMP callbackasm1(SB)
+	MOV $358, X7
+	JMP callbackasm1(SB)
+	MOV $359, X7
+	JMP callbackasm1(SB)
+	MOV $360, X7
+	JMP callbackasm1(SB)
+	MOV $361, X7
+	JMP callbackasm1(SB)
+	MOV $362, X7
+	JMP callbackasm1(SB)
+	MOV $363, X7
+	JMP callbackasm1(SB)
+	MOV $364, X7
+	JMP callbackasm1(SB)
+	MOV $365, X7
+	JMP callbackasm1(SB)
+	MOV $366, X7
+	JMP callbackasm1(SB)
+	MOV $367, X7
+	JMP callbackasm1(SB)
+	MOV $368, X7
+	JMP callbackasm1(SB)
+	MOV $369, X7
+	JMP callbackasm1(SB)
+	MOV $370, X7
+	JMP callbackasm1(SB)
+	MOV $371, X7
+	JMP callbackasm1(SB)
+	MOV $372, X7
+	JMP callbackasm1(SB)
+	MOV $373, X7
+	JMP callbackasm1(SB)
+	MOV $374, X7
+	JMP callbackasm1(SB)
+	MOV $375, X7
+	JMP callbackasm1(SB)
+	MOV $376, X7
+	JMP callbackasm1(SB)
+	MOV $377, X7
+	JMP callbackasm1(SB)
+	MOV $378, X7
+	JMP callbackasm1(SB)
+	MOV $379, X7
+	JMP callbackasm1(SB)
+	MOV $380, X7
+	JMP callbackasm1(SB)
+	MOV $381, X7
+	JMP callbackasm1(SB)
+	MOV $382, X7
+	JMP callbackasm1(SB)
+	MOV $383, X7
+	JMP callbackasm1(SB)
+	MOV $384, X7
+	JMP callbackasm1(SB)
+	MOV $385, X7
+	JMP callbackasm1(SB)
+	MOV $386, X7
+	JMP callbackasm1(SB)
+	MOV $387, X7
+	JMP callbackasm1(SB)
+	MOV $388, X7
+	JMP callbackasm1(SB)
+	MOV $389, X7
+	JMP callbackasm1(SB)
+	MOV $390, X7
+	JMP callbackasm1(SB)
+	MOV $391, X7
+	JMP callbackasm1(SB)
+	MOV $392, X7
+	JMP callbackasm1(SB)
+	MOV $393, X7
+	JMP callbackasm1(SB)
+	MOV $394, X7
+	JMP callbackasm1(SB)
+	MOV $395, X7
+	JMP callbackasm1(SB)
+	MOV $396, X7
+	JMP callbackasm1(SB)
+	MOV $397, X7
+	JMP callbackasm1(SB)
+	MOV $398, X7
+	JMP callbackasm1(SB)
+	MOV $399, X7
+	JMP callbackasm1(SB)
+	MOV $400, X7
+	JMP callbackasm1(SB)
+	MOV $401, X7
+	JMP callbackasm1(SB)
+	MOV $402, X7
+	JMP callbackasm1(SB)
+	MOV $403, X7
+	JMP callbackasm1(SB)
+	MOV $404, X7
+	JMP callbackasm1(SB)
+	MOV $405, X7
+	JMP callbackasm1(SB)
+	MOV $406, X7
+	JMP callbackasm1(SB)
+	MOV $407, X7
+	JMP callbackasm1(SB)
+	MOV $408, X7
+	JMP callbackasm1(SB)
+	MOV $409, X7
+	JMP callbackasm1(SB)
+	MOV $410, X7
+	JMP callbackasm1(SB)
+	MOV $411, X7
+	JMP callbackasm1(SB)
+	MOV $412, X7
+	JMP callbackasm1(SB)
+	MOV $413, X7
+	JMP callbackasm1(SB)
+	MOV $414, X7
+	JMP callbackasm1(SB)
+	MOV $415, X7
+	JMP callbackasm1(SB)
+	MOV $416, X7
+	JMP callbackasm1(SB)
+	MOV $417, X7
+	JMP callbackasm1(SB)
+	MOV $418, X7
+	JMP callbackasm1(SB)
+	MOV $419, X7
+	JMP callbackasm1(SB)
+	MOV $420, X7
+	JMP callbackasm1(SB)
+	MOV $421, X7
+	JMP callbackasm1(SB)
+	MOV $422, X7
+	JMP callbackasm1(SB)
+	MOV $423, X7
+	JMP callbackasm1(SB)
+	MOV $424, X7
+	JMP callbackasm1(SB)
+	MOV $425, X7
+	JMP callbackasm1(SB)
+	MOV $426, X7
+	JMP callbackasm1(SB)
+	MOV $427, X7
+	JMP callbackasm1(SB)
+	MOV $428, X7
+	JMP callbackasm1(SB)
+	MOV $429, X7
+	JMP callbackasm1(SB)
+	MOV $430, X7
+	JMP callbackasm1(SB)
+	MOV $431, X7
+	JMP callbackasm1(SB)
+	MOV $432, X7
+	JMP callbackasm1(SB)
+	MOV $433, X7
+	JMP callbackasm1(SB)
+	MOV $434, X7
+	JMP callbackasm1(SB)
+	MOV $435, X7
+	JMP callbackasm1(SB)
+	MOV $436, X7
+	JMP callbackasm1(SB)
+	MOV $437, X7
+	JMP callbackasm1(SB)
+	MOV $438, X7
+	JMP callbackasm1(SB)
+	MOV $439, X7
+	JMP callbackasm1(SB)
+	MOV $440, X7
+	JMP callbackasm1(SB)
+	MOV $441, X7
+	JMP callbackasm1(SB)
+	MOV $442, X7
+	JMP callbackasm1(SB)
+	MOV $443, X7
+	JMP callbackasm1(SB)
+	MOV $444, X7
+	JMP callbackasm1(SB)
+	MOV $445, X7
+	JMP callbackasm1(SB)
+	MOV $446, X7
+	JMP callbackasm1(SB)
+	MOV $447, X7
+	JMP callbackasm1(SB)
+	MOV $448, X7
+	JMP callbackasm1(SB)
+	MOV $449, X7
+	JMP callbackasm1(SB)
+	MOV $450, X7
+	JMP callbackasm1(SB)
+	MOV $451, X7
+	JMP callbackasm1(SB)
+	MOV $452, X7
+	JMP callbackasm1(SB)
+	MOV $453, X7
+	JMP callbackasm1(SB)
+	MOV $454, X7
+	JMP callbackasm1(SB)
+	MOV $455, X7
+	JMP callbackasm1(SB)
+	MOV $456, X7
+	JMP callbackasm1(SB)
+	MOV $457, X7
+	JMP callbackasm1(SB)
+	MOV $458, X7
+	JMP callbackasm1(SB)
+	MOV $459, X7
+	JMP callbackasm1(SB)
+	MOV $460, X7
+	JMP callbackasm1(SB)
+	MOV $461, X7
+	JMP callbackasm1(SB)
+	MOV $462, X7
+	JMP callbackasm1(SB)
+	MOV $463, X7
+	JMP callbackasm1(SB)
+	MOV $464, X7
+	JMP callbackasm1(SB)
+	MOV $465, X7
+	JMP callbackasm1(SB)
+	MOV $466, X7
+	JMP callbackasm1(SB)
+	MOV $467, X7
+	JMP callbackasm1(SB)
+	MOV $468, X7
+	JMP callbackasm1(SB)
+	MOV $469, X7
+	JMP callbackasm1(SB)
+	MOV $470, X7
+	JMP callbackasm1(SB)
+	MOV $471, X7
+	JMP callbackasm1(SB)
+	MOV $472, X7
+	JMP callbackasm1(SB)
+	MOV $473, X7
+	JMP callbackasm1(SB)
+	MOV $474, X7
+	JMP callbackasm1(SB)
+	MOV $475, X7
+	JMP callbackasm1(SB)
+	MOV $476, X7
+	JMP callbackasm1(SB)
+	MOV $477, X7
+	JMP callbackasm1(SB)
+	MOV $478, X7
+	JMP callbackasm1(SB)
+	MOV $479, X7
+	JMP callbackasm1(SB)
+	MOV $480, X7
+	JMP callbackasm1(SB)
+	MOV $481, X7
+	JMP callbackasm1(SB)
+	MOV $482, X7
+	JMP callbackasm1(SB)
+	MOV $483, X7
+	JMP callbackasm1(SB)
+	MOV $484, X7
+	JMP callbackasm1(SB)
+	MOV $485, X7
+	JMP callbackasm1(SB)
+	MOV $486, X7
+	JMP callbackasm1(SB)
+	MOV $487, X7
+	JMP callbackasm1(SB)
+	MOV $488, X7
+	JMP callbackasm1(SB)
+	MOV $489, X7
+	JMP callbackasm1(SB)
+	MOV $490, X7
+	JMP callbackasm1(SB)
+	MOV $491, X7
+	JMP callbackasm1(SB)
+	MOV $492, X7
+	JMP callbackasm1(SB)
+	MOV $493, X7
+	JMP callbackasm1(SB)
+	MOV $494, X7
+	JMP callbackasm1(SB)
+	MOV $495, X7
+	JMP callbackasm1(SB)
+	MOV $496, X7
+	JMP callbackasm1(SB)
+	MOV $497, X7
+	JMP callbackasm1(SB)
+	MOV $498, X7
+	JMP callbackasm1(SB)
+	MOV $499, X7
+	JMP callbackasm1(SB)
+	MOV $500, X7
+	JMP callbackasm1(SB)
+	MOV $501, X7
+	JMP callbackasm1(SB)
+	MOV $502, X7
+	JMP callbackasm1(SB)
+	MOV $503, X7
+	JMP callbackasm1(SB)
+	MOV $504, X7
+	JMP callbackasm1(SB)
+	MOV $505, X7
+	JMP callbackasm1(SB)
+	MOV $506, X7
+	JMP callbackasm1(SB)
+	MOV $507, X7
+	JMP callbackasm1(SB)
+	MOV $508, X7
+	JMP callbackasm1(SB)
+	MOV $509, X7
+	JMP callbackasm1(SB)
+	MOV $510, X7
+	JMP callbackasm1(SB)
+	MOV $511, X7
+	JMP callbackasm1(SB)
+	MOV $512, X7
+	JMP callbackasm1(SB)
+	MOV $513, X7
+	JMP callbackasm1(SB)
+	MOV $514, X7
+	JMP callbackasm1(SB)
+	MOV $515, X7
+	JMP callbackasm1(SB)
+	MOV $516, X7
+	JMP callbackasm1(SB)
+	MOV $517, X7
+	JMP callbackasm1(SB)
+	MOV $518, X7
+	JMP callbackasm1(SB)
+	MOV $519, X7
+	JMP callbackasm1(SB)
+	MOV $520, X7
+	JMP callbackasm1(SB)
+	MOV $521, X7
+	JMP callbackasm1(SB)
+	MOV $522, X7
+	JMP callbackasm1(SB)
+	MOV $523, X7
+	JMP callbackasm1(SB)
+	MOV $524, X7
+	JMP callbackasm1(SB)
+	MOV $525, X7
+	JMP callbackasm1(SB)
+	MOV $526, X7
+	JMP callbackasm1(SB)
+	MOV $527, X7
+	JMP callbackasm1(SB)
+	MOV $528, X7
+	JMP callbackasm1(SB)
+	MOV $529, X7
+	JMP callbackasm1(SB)
+	MOV $530, X7
+	JMP callbackasm1(SB)
+	MOV $531, X7
+	JMP callbackasm1(SB)
+	MOV $532, X7
+	JMP callbackasm1(SB)
+	MOV $533, X7
+	JMP callbackasm1(SB)
+	MOV $534, X7
+	JMP callbackasm1(SB)
+	MOV $535, X7
+	JMP callbackasm1(SB)
+	MOV $536, X7
+	JMP callbackasm1(SB)
+	MOV $537, X7
+	JMP callbackasm1(SB)
+	MOV $538, X7
+	JMP callbackasm1(SB)
+	MOV $539, X7
+	JMP callbackasm1(SB)
+	MOV $540, X7
+	JMP callbackasm1(SB)
+	MOV $541, X7
+	JMP callbackasm1(SB)
+	MOV $542, X7
+	JMP callbackasm1(SB)
+	MOV $543, X7
+	JMP callbackasm1(SB)
+	MOV $544, X7
+	JMP callbackasm1(SB)
+	MOV $545, X7
+	JMP callbackasm1(SB)
+	MOV $546, X7
+	JMP callbackasm1(SB)
+	MOV $547, X7
+	JMP callbackasm1(SB)
+	MOV $548, X7
+	JMP callbackasm1(SB)
+	MOV $549, X7
+	JMP callbackasm1(SB)
+	MOV $550, X7
+	JMP callbackasm1(SB)
+	MOV $551, X7
+	JMP callbackasm1(SB)
+	MOV $552, X7
+	JMP callbackasm1(SB)
+	MOV $553, X7
+	JMP callbackasm1(SB)
+	MOV $554, X7
+	JMP callbackasm1(SB)
+	MOV $555, X7
+	JMP callbackasm1(SB)
+	MOV $556, X7
+	JMP callbackasm1(SB)
+	MOV $557, X7
+	JMP callbackasm1(SB)
+	MOV $558, X7
+	JMP callbackasm1(SB)
+	MOV $559, X7
+	JMP callbackasm1(SB)
+	MOV $560, X7
+	JMP callbackasm1(SB)
+	MOV $561, X7
+	JMP callbackasm1(SB)
+	MOV $562, X7
+	JMP callbackasm1(SB)
+	MOV $563, X7
+	JMP callbackasm1(SB)
+	MOV $564, X7
+	JMP callbackasm1(SB)
+	MOV $565, X7
+	JMP callbackasm1(SB)
+	MOV $566, X7
+	JMP callbackasm1(SB)
+	MOV $567, X7
+	JMP callbackasm1(SB)
+	MOV $568, X7
+	JMP callbackasm1(SB)
+	MOV $569, X7
+	JMP callbackasm1(SB)
+	MOV $570, X7
+	JMP callbackasm1(SB)
+	MOV $571, X7
+	JMP callbackasm1(SB)
+	MOV $572, X7
+	JMP callbackasm1(SB)
+	MOV $573, X7
+	JMP callbackasm1(SB)
+	MOV $574, X7
+	JMP callbackasm1(SB)
+	MOV $575, X7
+	JMP callbackasm1(SB)
+	MOV $576, X7
+	JMP callbackasm1(SB)
+	MOV $577, X7
+	JMP callbackasm1(SB)
+	MOV $578, X7
+	JMP callbackasm1(SB)
+	MOV $579, X7
+	JMP callbackasm1(SB)
+	MOV $580, X7
+	JMP callbackasm1(SB)
+	MOV $581, X7
+	JMP callbackasm1(SB)
+	MOV $582, X7
+	JMP callbackasm1(SB)
+	MOV $583, X7
+	JMP callbackasm1(SB)
+	MOV $584, X7
+	JMP callbackasm1(SB)
+	MOV $585, X7
+	JMP callbackasm1(SB)
+	MOV $586, X7
+	JMP callbackasm1(SB)
+	MOV $587, X7
+	JMP callbackasm1(SB)
+	MOV $588, X7
+	JMP callbackasm1(SB)
+	MOV $589, X7
+	JMP callbackasm1(SB)
+	MOV $590, X7
+	JMP callbackasm1(SB)
+	MOV $591, X7
+	JMP callbackasm1(SB)
+	MOV $592, X7
+	JMP callbackasm1(SB)
+	MOV $593, X7
+	JMP callbackasm1(SB)
+	MOV $594, X7
+	JMP callbackasm1(SB)
+	MOV $595, X7
+	JMP callbackasm1(SB)
+	MOV $596, X7
+	JMP callbackasm1(SB)
+	MOV $597, X7
+	JMP callbackasm1(SB)
+	MOV $598, X7
+	JMP callbackasm1(SB)
+	MOV $599, X7
+	JMP callbackasm1(SB)
+	MOV $600, X7
+	JMP callbackasm1(SB)
+	MOV $601, X7
+	JMP callbackasm1(SB)
+	MOV $602, X7
+	JMP callbackasm1(SB)
+	MOV $603, X7
+	JMP callbackasm1(SB)
+	MOV $604, X7
+	JMP callbackasm1(SB)
+	MOV $605, X7
+	JMP callbackasm1(SB)
+	MOV $606, X7
+	JMP callbackasm1(SB)
+	MOV $607, X7
+	JMP callbackasm1(SB)
+	MOV $608, X7
+	JMP callbackasm1(SB)
+	MOV $609, X7
+	JMP callbackasm1(SB)
+	MOV $610, X7
+	JMP callbackasm1(SB)
+	MOV $611, X7
+	JMP callbackasm1(SB)
+	MOV $612, X7
+	JMP callbackasm1(SB)
+	MOV $613, X7
+	JMP callbackasm1(SB)
+	MOV $614, X7
+	JMP callbackasm1(SB)
+	MOV $615, X7
+	JMP callbackasm1(SB)
+	MOV $616, X7
+	JMP callbackasm1(SB)
+	MOV $617, X7
+	JMP callbackasm1(SB)
+	MOV $618, X7
+	JMP callbackasm1(SB)
+	MOV $619, X7
+	JMP callbackasm1(SB)
+	MOV $620, X7
+	JMP callbackasm1(SB)
+	MOV $621, X7
+	JMP callbackasm1(SB)
+	MOV $622, X7
+	JMP callbackasm1(SB)
+	MOV $623, X7
+	JMP callbackasm1(SB)
+	MOV $624, X7
+	JMP callbackasm1(SB)
+	MOV $625, X7
+	JMP callbackasm1(SB)
+	MOV $626, X7
+	JMP callbackasm1(SB)
+	MOV $627, X7
+	JMP callbackasm1(SB)
+	MOV $628, X7
+	JMP callbackasm1(SB)
+	MOV $629, X7
+	JMP callbackasm1(SB)
+	MOV $630, X7
+	JMP callbackasm1(SB)
+	MOV $631, X7
+	JMP callbackasm1(SB)
+	MOV $632, X7
+	JMP callbackasm1(SB)
+	MOV $633, X7
+	JMP callbackasm1(SB)
+	MOV $634, X7
+	JMP callbackasm1(SB)
+	MOV $635, X7
+	JMP callbackasm1(SB)
+	MOV $636, X7
+	JMP callbackasm1(SB)
+	MOV $637, X7
+	JMP callbackasm1(SB)
+	MOV $638, X7
+	JMP callbackasm1(SB)
+	MOV $639, X7
+	JMP callbackasm1(SB)
+	MOV $640, X7
+	JMP callbackasm1(SB)
+	MOV $641, X7
+	JMP callbackasm1(SB)
+	MOV $642, X7
+	JMP callbackasm1(SB)
+	MOV $643, X7
+	JMP callbackasm1(SB)
+	MOV $644, X7
+	JMP callbackasm1(SB)
+	MOV $645, X7
+	JMP callbackasm1(SB)
+	MOV $646, X7
+	JMP callbackasm1(SB)
+	MOV $647, X7
+	JMP callbackasm1(SB)
+	MOV $648, X7
+	JMP callbackasm1(SB)
+	MOV $649, X7
+	JMP callbackasm1(SB)
+	MOV $650, X7
+	JMP callbackasm1(SB)
+	MOV $651, X7
+	JMP callbackasm1(SB)
+	MOV $652, X7
+	JMP callbackasm1(SB)
+	MOV $653, X7
+	JMP callbackasm1(SB)
+	MOV $654, X7
+	JMP callbackasm1(SB)
+	MOV $655, X7
+	JMP callbackasm1(SB)
+	MOV $656, X7
+	JMP callbackasm1(SB)
+	MOV $657, X7
+	JMP callbackasm1(SB)
+	MOV $658, X7
+	JMP callbackasm1(SB)
+	MOV $659, X7
+	JMP callbackasm1(SB)
+	MOV $660, X7
+	JMP callbackasm1(SB)
+	MOV $661, X7
+	JMP callbackasm1(SB)
+	MOV $662, X7
+	JMP callbackasm1(SB)
+	MOV $663, X7
+	JMP callbackasm1(SB)
+	MOV $664, X7
+	JMP callbackasm1(SB)
+	MOV $665, X7
+	JMP callbackasm1(SB)
+	MOV $666, X7
+	JMP callbackasm1(SB)
+	MOV $667, X7
+	JMP callbackasm1(SB)
+	MOV $668, X7
+	JMP callbackasm1(SB)
+	MOV $669, X7
+	JMP callbackasm1(SB)
+	MOV $670, X7
+	JMP callbackasm1(SB)
+	MOV $671, X7
+	JMP callbackasm1(SB)
+	MOV $672, X7
+	JMP callbackasm1(SB)
+	MOV $673, X7
+	JMP callbackasm1(SB)
+	MOV $674, X7
+	JMP callbackasm1(SB)
+	MOV $675, X7
+	JMP callbackasm1(SB)
+	MOV $676, X7
+	JMP callbackasm1(SB)
+	MOV $677, X7
+	JMP callbackasm1(SB)
+	MOV $678, X7
+	JMP callbackasm1(SB)
+	MOV $679, X7
+	JMP callbackasm1(SB)
+	MOV $680, X7
+	JMP callbackasm1(SB)
+	MOV $681, X7
+	JMP callbackasm1(SB)
+	MOV $682, X7
+	JMP callbackasm1(SB)
+	MOV $683, X7
+	JMP callbackasm1(SB)
+	MOV $684, X7
+	JMP callbackasm1(SB)
+	MOV $685, X7
+	JMP callbackasm1(SB)
+	MOV $686, X7
+	JMP callbackasm1(SB)
+	MOV $687, X7
+	JMP callbackasm1(SB)
+	MOV $688, X7
+	JMP callbackasm1(SB)
+	MOV $689, X7
+	JMP callbackasm1(SB)
+	MOV $690, X7
+	JMP callbackasm1(SB)
+	MOV $691, X7
+	JMP callbackasm1(SB)
+	MOV $692, X7
+	JMP callbackasm1(SB)
+	MOV $693, X7
+	JMP callbackasm1(SB)
+	MOV $694, X7
+	JMP callbackasm1(SB)
+	MOV $695, X7
+	JMP callbackasm1(SB)
+	MOV $696, X7
+	JMP callbackasm1(SB)
+	MOV $697, X7
+	JMP callbackasm1(SB)
+	MOV $698, X7
+	JMP callbackasm1(SB)
+	MOV $699, X7
+	JMP callbackasm1(SB)
+	MOV $700, X7
+	JMP callbackasm1(SB)
+	MOV $701, X7
+	JMP callbackasm1(SB)
+	MOV $702, X7
+	JMP callbackasm1(SB)
+	MOV $703, X7
+	JMP callbackasm1(SB)
+	MOV $704, X7
+	JMP callbackasm1(SB)
+	MOV $705, X7
+	JMP callbackasm1(SB)
+	MOV $706, X7
+	JMP callbackasm1(SB)
+	MOV $707, X7
+	JMP callbackasm1(SB)
+	MOV $708, X7
+	JMP callbackasm1(SB)
+	MOV $709, X7
+	JMP callbackasm1(SB)
+	MOV $710, X7
+	JMP callbackasm1(SB)
+	MOV $711, X7
+	JMP callbackasm1(SB)
+	MOV $712, X7
+	JMP callbackasm1(SB)
+	MOV $713, X7
+	JMP callbackasm1(SB)
+	MOV $714, X7
+	JMP callbackasm1(SB)
+	MOV $715, X7
+	JMP callbackasm1(SB)
+	MOV $716, X7
+	JMP callbackasm1(SB)
+	MOV $717, X7
+	JMP callbackasm1(SB)
+	MOV $718, X7
+	JMP callbackasm1(SB)
+	MOV $719, X7
+	JMP callbackasm1(SB)
+	MOV $720, X7
+	JMP callbackasm1(SB)
+	MOV $721, X7
+	JMP callbackasm1(SB)
+	MOV $722, X7
+	JMP callbackasm1(SB)
+	MOV $723, X7
+	JMP callbackasm1(SB)
+	MOV $724, X7
+	JMP callbackasm1(SB)
+	MOV $725, X7
+	JMP callbackasm1(SB)
+	MOV $726, X7
+	JMP callbackasm1(SB)
+	MOV $727, X7
+	JMP callbackasm1(SB)
+	MOV $728, X7
+	JMP callbackasm1(SB)
+	MOV $729, X7
+	JMP callbackasm1(SB)
+	MOV $730, X7
+	JMP callbackasm1(SB)
+	MOV $731, X7
+	JMP callbackasm1(SB)
+	MOV $732, X7
+	JMP callbackasm1(SB)
+	MOV $733, X7
+	JMP callbackasm1(SB)
+	MOV $734, X7
+	JMP callbackasm1(SB)
+	MOV $735, X7
+	JMP callbackasm1(SB)
+	MOV $736, X7
+	JMP callbackasm1(SB)
+	MOV $737, X7
+	JMP callbackasm1(SB)
+	MOV $738, X7
+	JMP callbackasm1(SB)
+	MOV $739, X7
+	JMP callbackasm1(SB)
+	MOV $740, X7
+	JMP callbackasm1(SB)
+	MOV $741, X7
+	JMP callbackasm1(SB)
+	MOV $742, X7
+	JMP callbackasm1(SB)
+	MOV $743, X7
+	JMP callbackasm1(SB)
+	MOV $744, X7
+	JMP callbackasm1(SB)
+	MOV $745, X7
+	JMP callbackasm1(SB)
+	MOV $746, X7
+	JMP callbackasm1(SB)
+	MOV $747, X7
+	JMP callbackasm1(SB)
+	MOV $748, X7
+	JMP callbackasm1(SB)
+	MOV $749, X7
+	JMP callbackasm1(SB)
+	MOV $750, X7
+	JMP callbackasm1(SB)
+	MOV $751, X7
+	JMP callbackasm1(SB)
+	MOV $752, X7
+	JMP callbackasm1(SB)
+	MOV $753, X7
+	JMP callbackasm1(SB)
+	MOV $754, X7
+	JMP callbackasm1(SB)
+	MOV $755, X7
+	JMP callbackasm1(SB)
+	MOV $756, X7
+	JMP callbackasm1(SB)
+	MOV $757, X7
+	JMP callbackasm1(SB)
+	MOV $758, X7
+	JMP callbackasm1(SB)
+	MOV $759, X7
+	JMP callbackasm1(SB)
+	MOV $760, X7
+	JMP callbackasm1(SB)
+	MOV $761, X7
+	JMP callbackasm1(SB)
+	MOV $762, X7
+	JMP callbackasm1(SB)
+	MOV $763, X7
+	JMP callbackasm1(SB)
+	MOV $764, X7
+	JMP callbackasm1(SB)
+	MOV $765, X7
+	JMP callbackasm1(SB)
+	MOV $766, X7
+	JMP callbackasm1(SB)
+	MOV $767, X7
+	JMP callbackasm1(SB)
+	MOV $768, X7
+	JMP callbackasm1(SB)
+	MOV $769, X7
+	JMP callbackasm1(SB)
+	MOV $770, X7
+	JMP callbackasm1(SB)
+	MOV $771, X7
+	JMP callbackasm1(SB)
+	MOV $772, X7
+	JMP callbackasm1(SB)
+	MOV $773, X7
+	JMP callbackasm1(SB)
+	MOV $774, X7
+	JMP callbackasm1(SB)
+	MOV $775, X7
+	JMP callbackasm1(SB)
+	MOV $776, X7
+	JMP callbackasm1(SB)
+	MOV $777, X7
+	JMP callbackasm1(SB)
+	MOV $778, X7
+	JMP callbackasm1(SB)
+	MOV $779, X7
+	JMP callbackasm1(SB)
+	MOV $780, X7
+	JMP callbackasm1(SB)
+	MOV $781, X7
+	JMP callbackasm1(SB)
+	MOV $782, X7
+	JMP callbackasm1(SB)
+	MOV $783, X7
+	JMP callbackasm1(SB)
+	MOV $784, X7
+	JMP callbackasm1(SB)
+	MOV $785, X7
+	JMP callbackasm1(SB)
+	MOV $786, X7
+	JMP callbackasm1(SB)
+	MOV $787, X7
+	JMP callbackasm1(SB)
+	MOV $788, X7
+	JMP callbackasm1(SB)
+	MOV $789, X7
+	JMP callbackasm1(SB)
+	MOV $790, X7
+	JMP callbackasm1(SB)
+	MOV $791, X7
+	JMP callbackasm1(SB)
+	MOV $792, X7
+	JMP callbackasm1(SB)
+	MOV $793, X7
+	JMP callbackasm1(SB)
+	MOV $794, X7
+	JMP callbackasm1(SB)
+	MOV $795, X7
+	JMP callbackasm1(SB)
+	MOV $796, X7
+	JMP callbackasm1(SB)
+	MOV $797, X7
+	JMP callbackasm1(SB)
+	MOV $798, X7
+	JMP callbackasm1(SB)
+	MOV $799, X7
+	JMP callbackasm1(SB)
+	MOV $800, X7
+	JMP callbackasm1(SB)
+	MOV $801, X7
+	JMP callbackasm1(SB)
+	MOV $802, X7
+	JMP callbackasm1(SB)
+	MOV $803, X7
+	JMP callbackasm1(SB)
+	MOV $804, X7
+	JMP callbackasm1(SB)
+	MOV $805, X7
+	JMP callbackasm1(SB)
+	MOV $806, X7
+	JMP callbackasm1(SB)
+	MOV $807, X7
+	JMP callbackasm1(SB)
+	MOV $808, X7
+	JMP callbackasm1(SB)
+	MOV $809, X7
+	JMP callbackasm1(SB)
+	MOV $810, X7
+	JMP callbackasm1(SB)
+	MOV $811, X7
+	JMP callbackasm1(SB)
+	MOV $812, X7
+	JMP callbackasm1(SB)
+	MOV $813, X7
+	JMP callbackasm1(SB)
+	MOV $814, X7
+	JMP callbackasm1(SB)
+	MOV $815, X7
+	JMP callbackasm1(SB)
+	MOV $816, X7
+	JMP callbackasm1(SB)
+	MOV $817, X7
+	JMP callbackasm1(SB)
+	MOV $818, X7
+	JMP callbackasm1(SB)
+	MOV $819, X7
+	JMP callbackasm1(SB)
+	MOV $820, X7
+	JMP callbackasm1(SB)
+	MOV $821, X7
+	JMP callbackasm1(SB)
+	MOV $822, X7
+	JMP callbackasm1(SB)
+	MOV $823, X7
+	JMP callbackasm1(SB)
+	MOV $824, X7
+	JMP callbackasm1(SB)
+	MOV $825, X7
+	JMP callbackasm1(SB)
+	MOV $826, X7
+	JMP callbackasm1(SB)
+	MOV $827, X7
+	JMP callbackasm1(SB)
+	MOV $828, X7
+	JMP callbackasm1(SB)
+	MOV $829, X7
+	JMP callbackasm1(SB)
+	MOV $830, X7
+	JMP callbackasm1(SB)
+	MOV $831, X7
+	JMP callbackasm1(SB)
+	MOV $832, X7
+	JMP callbackasm1(SB)
+	MOV $833, X7
+	JMP callbackasm1(SB)
+	MOV $834, X7
+	JMP callbackasm1(SB)
+	MOV $835, X7
+	JMP callbackasm1(SB)
+	MOV $836, X7
+	JMP callbackasm1(SB)
+	MOV $837, X7
+	JMP callbackasm1(SB)
+	MOV $838, X7
+	JMP callbackasm1(SB)
+	MOV $839, X7
+	JMP callbackasm1(SB)
+	MOV $840, X7
+	JMP callbackasm1(SB)
+	MOV $841, X7
+	JMP callbackasm1(SB)
+	MOV $842, X7
+	JMP callbackasm1(SB)
+	MOV $843, X7
+	JMP callbackasm1(SB)
+	MOV $844, X7
+	JMP callbackasm1(SB)
+	MOV $845, X7
+	JMP callbackasm1(SB)
+	MOV $846, X7
+	JMP callbackasm1(SB)
+	MOV $847, X7
+	JMP callbackasm1(SB)
+	MOV $848, X7
+	JMP callbackasm1(SB)
+	MOV $849, X7
+	JMP callbackasm1(SB)
+	MOV $850, X7
+	JMP callbackasm1(SB)
+	MOV $851, X7
+	JMP callbackasm1(SB)
+	MOV $852, X7
+	JMP callbackasm1(SB)
+	MOV $853, X7
+	JMP callbackasm1(SB)
+	MOV $854, X7
+	JMP callbackasm1(SB)
+	MOV $855, X7
+	JMP callbackasm1(SB)
+	MOV $856, X7
+	JMP callbackasm1(SB)
+	MOV $857, X7
+	JMP callbackasm1(SB)
+	MOV $858, X7
+	JMP callbackasm1(SB)
+	MOV $859, X7
+	JMP callbackasm1(SB)
+	MOV $860, X7
+	JMP callbackasm1(SB)
+	MOV $861, X7
+	JMP callbackasm1(SB)
+	MOV $862, X7
+	JMP callbackasm1(SB)
+	MOV $863, X7
+	JMP callbackasm1(SB)
+	MOV $864, X7
+	JMP callbackasm1(SB)
+	MOV $865, X7
+	JMP callbackasm1(SB)
+	MOV $866, X7
+	JMP callbackasm1(SB)
+	MOV $867, X7
+	JMP callbackasm1(SB)
+	MOV $868, X7
+	JMP callbackasm1(SB)
+	MOV $869, X7
+	JMP callbackasm1(SB)
+	MOV $870, X7
+	JMP callbackasm1(SB)
+	MOV $871, X7
+	JMP callbackasm1(SB)
+	MOV $872, X7
+	JMP callbackasm1(SB)
+	MOV $873, X7
+	JMP callbackasm1(SB)
+	MOV $874, X7
+	JMP callbackasm1(SB)
+	MOV $875, X7
+	JMP callbackasm1(SB)
+	MOV $876, X7
+	JMP callbackasm1(SB)
+	MOV $877, X7
+	JMP callbackasm1(SB)
+	MOV $878, X7
+	JMP callbackasm1(SB)
+	MOV $879, X7
+	JMP callbackasm1(SB)
+	MOV $880, X7
+	JMP callbackasm1(SB)
+	MOV $881, X7
+	JMP callbackasm1(SB)
+	MOV $882, X7
+	JMP callbackasm1(SB)
+	MOV $883, X7
+	JMP callbackasm1(SB)
+	MOV $884, X7
+	JMP callbackasm1(SB)
+	MOV $885, X7
+	JMP callbackasm1(SB)
+	MOV $886, X7
+	JMP callbackasm1(SB)
+	MOV $887, X7
+	JMP callbackasm1(SB)
+	MOV $888, X7
+	JMP callbackasm1(SB)
+	MOV $889, X7
+	JMP callbackasm1(SB)
+	MOV $890, X7
+	JMP callbackasm1(SB)
+	MOV $891, X7
+	JMP callbackasm1(SB)
+	MOV $892, X7
+	JMP callbackasm1(SB)
+	MOV $893, X7
+	JMP callbackasm1(SB)
+	MOV $894, X7
+	JMP callbackasm1(SB)
+	MOV $895, X7
+	JMP callbackasm1(SB)
+	MOV $896, X7
+	JMP callbackasm1(SB)
+	MOV $897, X7
+	JMP callbackasm1(SB)
+	MOV $898, X7
+	JMP callbackasm1(SB)
+	MOV $899, X7
+	JMP callbackasm1(SB)
+	MOV $900, X7
+	JMP callbackasm1(SB)
+	MOV $901, X7
+	JMP callbackasm1(SB)
+	MOV $902, X7
+	JMP callbackasm1(SB)
+	MOV $903, X7
+	JMP callbackasm1(SB)
+	MOV $904, X7
+	JMP callbackasm1(SB)
+	MOV $905, X7
+	JMP callbackasm1(SB)
+	MOV $906, X7
+	JMP callbackasm1(SB)
+	MOV $907, X7
+	JMP callbackasm1(SB)
+	MOV $908, X7
+	JMP callbackasm1(SB)
+	MOV $909, X7
+	JMP callbackasm1(SB)
+	MOV $910, X7
+	JMP callbackasm1(SB)
+	MOV $911, X7
+	JMP callbackasm1(SB)
+	MOV $912, X7
+	JMP callbackasm1(SB)
+	MOV $913, X7
+	JMP callbackasm1(SB)
+	MOV $914, X7
+	JMP callbackasm1(SB)
+	MOV $915, X7
+	JMP callbackasm1(SB)
+	MOV $916, X7
+	JMP callbackasm1(SB)
+	MOV $917, X7
+	JMP callbackasm1(SB)
+	MOV $918, X7
+	JMP callbackasm1(SB)
+	MOV $919, X7
+	JMP callbackasm1(SB)
+	MOV $920, X7
+	JMP callbackasm1(SB)
+	MOV $921, X7
+	JMP callbackasm1(SB)
+	MOV $922, X7
+	JMP callbackasm1(SB)
+	MOV $923, X7
+	JMP callbackasm1(SB)
+	MOV $924, X7
+	JMP callbackasm1(SB)
+	MOV $925, X7
+	JMP callbackasm1(SB)
+	MOV $926, X7
+	JMP callbackasm1(SB)
+	MOV $927, X7
+	JMP callbackasm1(SB)
+	MOV $928, X7
+	JMP callbackasm1(SB)
+	MOV $929, X7
+	JMP callbackasm1(SB)
+	MOV $930, X7
+	JMP callbackasm1(SB)
+	MOV $931, X7
+	JMP callbackasm1(SB)
+	MOV $932, X7
+	JMP callbackasm1(SB)
+	MOV $933, X7
+	JMP callbackasm1(SB)
+	MOV $934, X7
+	JMP callbackasm1(SB)
+	MOV $935, X7
+	JMP callbackasm1(SB)
+	MOV $936, X7
+	JMP callbackasm1(SB)
+	MOV $937, X7
+	JMP callbackasm1(SB)
+	MOV $938, X7
+	JMP callbackasm1(SB)
+	MOV $939, X7
+	JMP callbackasm1(SB)
+	MOV $940, X7
+	JMP callbackasm1(SB)
+	MOV $941, X7
+	JMP callbackasm1(SB)
+	MOV $942, X7
+	JMP callbackasm1(SB)
+	MOV $943, X7
+	JMP callbackasm1(SB)
+	MOV $944, X7
+	JMP callbackasm1(SB)
+	MOV $945, X7
+	JMP callbackasm1(SB)
+	MOV $946, X7
+	JMP callbackasm1(SB)
+	MOV $947, X7
+	JMP callbackasm1(SB)
+	MOV $948, X7
+	JMP callbackasm1(SB)
+	MOV $949, X7
+	JMP callbackasm1(SB)
+	MOV $950, X7
+	JMP callbackasm1(SB)
+	MOV $951, X7
+	JMP callbackasm1(SB)
+	MOV $952, X7
+	JMP callbackasm1(SB)
+	MOV $953, X7
+	JMP callbackasm1(SB)
+	MOV $954, X7
+	JMP callbackasm1(SB)
+	MOV $955, X7
+	JMP callbackasm1(SB)
+	MOV $956, X7
+	JMP callbackasm1(SB)
+	MOV $957, X7
+	JMP callbackasm1(SB)
+	MOV $958, X7
+	JMP callbackasm1(SB)
+	MOV $959, X7
+	JMP callbackasm1(SB)
+	MOV $960, X7
+	JMP callbackasm1(SB)
+	MOV $961, X7
+	JMP callbackasm1(SB)
+	MOV $962, X7
+	JMP callbackasm1(SB)
+	MOV $963, X7
+	JMP callbackasm1(SB)
+	MOV $964, X7
+	JMP callbackasm1(SB)
+	MOV $965, X7
+	JMP callbackasm1(SB)
+	MOV $966, X7
+	JMP callbackasm1(SB)
+	MOV $967, X7
+	JMP callbackasm1(SB)
+	MOV $968, X7
+	JMP callbackasm1(SB)
+	MOV $969, X7
+	JMP callbackasm1(SB)
+	MOV $970, X7
+	JMP callbackasm1(SB)
+	MOV $971, X7
+	JMP callbackasm1(SB)
+	MOV $972, X7
+	JMP callbackasm1(SB)
+	MOV $973, X7
+	JMP callbackasm1(SB)
+	MOV $974, X7
+	JMP callbackasm1(SB)
+	MOV $975, X7
+	JMP callbackasm1(SB)
+	MOV $976, X7
+	JMP callbackasm1(SB)
+	MOV $977, X7
+	JMP callbackasm1(SB)
+	MOV $978, X7
+	JMP callbackasm1(SB)
+	MOV $979, X7
+	JMP callbackasm1(SB)
+	MOV $980, X7
+	JMP callbackasm1(SB)
+	MOV $981, X7
+	JMP callbackasm1(SB)
+	MOV $982, X7
+	JMP callbackasm1(SB)
+	MOV $983, X7
+	JMP callbackasm1(SB)
+	MOV $984, X7
+	JMP callbackasm1(SB)
+	MOV $985, X7
+	JMP callbackasm1(SB)
+	MOV $986, X7
+	JMP callbackasm1(SB)
+	MOV $987, X7
+	JMP callbackasm1(SB)
+	MOV $988, X7
+	JMP callbackasm1(SB)
+	MOV $989, X7
+	JMP callbackasm1(SB)
+	MOV $990, X7
+	JMP callbackasm1(SB)
+	MOV $991, X7
+	JMP callbackasm1(SB)
+	MOV $992, X7
+	JMP callbackasm1(SB)
+	MOV $993, X7
+	JMP callbackasm1(SB)
+	MOV $994, X7
+	JMP callbackasm1(SB)
+	MOV $995, X7
+	JMP callbackasm1(SB)
+	MOV $996, X7
+	JMP callbackasm1(SB)
+	MOV $997, X7
+	JMP callbackasm1(SB)
+	MOV $998, X7
+	JMP callbackasm1(SB)
+	MOV $999, X7
+	JMP callbackasm1(SB)
+	MOV $1000, X7
+	JMP callbackasm1(SB)
+	MOV $1001, X7
+	JMP callbackasm1(SB)
+	MOV $1002, X7
+	JMP callbackasm1(SB)
+	MOV $1003, X7
+	JMP callbackasm1(SB)
+	MOV $1004, X7
+	JMP callbackasm1(SB)
+	MOV $1005, X7
+	JMP callbackasm1(SB)
+	MOV $1006, X7
+	JMP callbackasm1(SB)
+	MOV $1007, X7
+	JMP callbackasm1(SB)
+	MOV $1008, X7
+	JMP callbackasm1(SB)
+	MOV $1009, X7
+	JMP callbackasm1(SB)
+	MOV $1010, X7
+	JMP callbackasm1(SB)
+	MOV $1011, X7
+	JMP callbackasm1(SB)
+	MOV $1012, X7
+	JMP callbackasm1(SB)
+	MOV $1013, X7
+	JMP callbackasm1(SB)
+	MOV $1014, X7
+	JMP callbackasm1(SB)
+	MOV $1015, X7
+	JMP callbackasm1(SB)
+	MOV $1016, X7
+	JMP callbackasm1(SB)
+	MOV $1017, X7
+	JMP callbackasm1(SB)
+	MOV $1018, X7
+	JMP callbackasm1(SB)
+	MOV $1019, X7
+	JMP callbackasm1(SB)
+	MOV $1020, X7
+	JMP callbackasm1(SB)
+	MOV $1021, X7
+	JMP callbackasm1(SB)
+	MOV $1022, X7
+	JMP callbackasm1(SB)
+	MOV $1023, X7
+	JMP callbackasm1(SB)
+	MOV $1024, X7
+	JMP callbackasm1(SB)
+	MOV $1025, X7
+	JMP callbackasm1(SB)
+	MOV $1026, X7
+	JMP callbackasm1(SB)
+	MOV $1027, X7
+	JMP callbackasm1(SB)
+	MOV $1028, X7
+	JMP callbackasm1(SB)
+	MOV $1029, X7
+	JMP callbackasm1(SB)
+	MOV $1030, X7
+	JMP callbackasm1(SB)
+	MOV $1031, X7
+	JMP callbackasm1(SB)
+	MOV $1032, X7
+	JMP callbackasm1(SB)
+	MOV $1033, X7
+	JMP callbackasm1(SB)
+	MOV $1034, X7
+	JMP callbackasm1(SB)
+	MOV $1035, X7
+	JMP callbackasm1(SB)
+	MOV $1036, X7
+	JMP callbackasm1(SB)
+	MOV $1037, X7
+	JMP callbackasm1(SB)
+	MOV $1038, X7
+	JMP callbackasm1(SB)
+	MOV $1039, X7
+	JMP callbackasm1(SB)
+	MOV $1040, X7
+	JMP callbackasm1(SB)
+	MOV $1041, X7
+	JMP callbackasm1(SB)
+	MOV $1042, X7
+	JMP callbackasm1(SB)
+	MOV $1043, X7
+	JMP callbackasm1(SB)
+	MOV $1044, X7
+	JMP callbackasm1(SB)
+	MOV $1045, X7
+	JMP callbackasm1(SB)
+	MOV $1046, X7
+	JMP callbackasm1(SB)
+	MOV $1047, X7
+	JMP callbackasm1(SB)
+	MOV $1048, X7
+	JMP callbackasm1(SB)
+	MOV $1049, X7
+	JMP callbackasm1(SB)
+	MOV $1050, X7
+	JMP callbackasm1(SB)
+	MOV $1051, X7
+	JMP callbackasm1(SB)
+	MOV $1052, X7
+	JMP callbackasm1(SB)
+	MOV $1053, X7
+	JMP callbackasm1(SB)
+	MOV $1054, X7
+	JMP callbackasm1(SB)
+	MOV $1055, X7
+	JMP callbackasm1(SB)
+	MOV $1056, X7
+	JMP callbackasm1(SB)
+	MOV $1057, X7
+	JMP callbackasm1(SB)
+	MOV $1058, X7
+	JMP callbackasm1(SB)
+	MOV $1059, X7
+	JMP callbackasm1(SB)
+	MOV $1060, X7
+	JMP callbackasm1(SB)
+	MOV $1061, X7
+	JMP callbackasm1(SB)
+	MOV $1062, X7
+	JMP callbackasm1(SB)
+	MOV $1063, X7
+	JMP callbackasm1(SB)
+	MOV $1064, X7
+	JMP callbackasm1(SB)
+	MOV $1065, X7
+	JMP callbackasm1(SB)
+	MOV $1066, X7
+	JMP callbackasm1(SB)
+	MOV $1067, X7
+	JMP callbackasm1(SB)
+	MOV $1068, X7
+	JMP callbackasm1(SB)
+	MOV $1069, X7
+	JMP callbackasm1(SB)
+	MOV $1070, X7
+	JMP callbackasm1(SB)
+	MOV $1071, X7
+	JMP callbackasm1(SB)
+	MOV $1072, X7
+	JMP callbackasm1(SB)
+	MOV $1073, X7
+	JMP callbackasm1(SB)
+	MOV $1074, X7
+	JMP callbackasm1(SB)
+	MOV $1075, X7
+	JMP callbackasm1(SB)
+	MOV $1076, X7
+	JMP callbackasm1(SB)
+	MOV $1077, X7
+	JMP callbackasm1(SB)
+	MOV $1078, X7
+	JMP callbackasm1(SB)
+	MOV $1079, X7
+	JMP callbackasm1(SB)
+	MOV $1080, X7
+	JMP callbackasm1(SB)
+	MOV $1081, X7
+	JMP callbackasm1(SB)
+	MOV $1082, X7
+	JMP callbackasm1(SB)
+	MOV $1083, X7
+	JMP callbackasm1(SB)
+	MOV $1084, X7
+	JMP callbackasm1(SB)
+	MOV $1085, X7
+	JMP callbackasm1(SB)
+	MOV $1086, X7
+	JMP callbackasm1(SB)
+	MOV $1087, X7
+	JMP callbackasm1(SB)
+	MOV $1088, X7
+	JMP callbackasm1(SB)
+	MOV $1089, X7
+	JMP callbackasm1(SB)
+	MOV $1090, X7
+	JMP callbackasm1(SB)
+	MOV $1091, X7
+	JMP callbackasm1(SB)
+	MOV $1092, X7
+	JMP callbackasm1(SB)
+	MOV $1093, X7
+	JMP callbackasm1(SB)
+	MOV $1094, X7
+	JMP callbackasm1(SB)
+	MOV $1095, X7
+	JMP callbackasm1(SB)
+	MOV $1096, X7
+	JMP callbackasm1(SB)
+	MOV $1097, X7
+	JMP callbackasm1(SB)
+	MOV $1098, X7
+	JMP callbackasm1(SB)
+	MOV $1099, X7
+	JMP callbackasm1(SB)
+	MOV $1100, X7
+	JMP callbackasm1(SB)
+	MOV $1101, X7
+	JMP callbackasm1(SB)
+	MOV $1102, X7
+	JMP callbackasm1(SB)
+	MOV $1103, X7
+	JMP callbackasm1(SB)
+	MOV $1104, X7
+	JMP callbackasm1(SB)
+	MOV $1105, X7
+	JMP callbackasm1(SB)
+	MOV $1106, X7
+	JMP callbackasm1(SB)
+	MOV $1107, X7
+	JMP callbackasm1(SB)
+	MOV $1108, X7
+	JMP callbackasm1(SB)
+	MOV $1109, X7
+	JMP callbackasm1(SB)
+	MOV $1110, X7
+	JMP callbackasm1(SB)
+	MOV $1111, X7
+	JMP callbackasm1(SB)
+	MOV $1112, X7
+	JMP callbackasm1(SB)
+	MOV $1113, X7
+	JMP callbackasm1(SB)
+	MOV $1114, X7
+	JMP callbackasm1(SB)
+	MOV $1115, X7
+	JMP callbackasm1(SB)
+	MOV $1116, X7
+	JMP callbackasm1(SB)
+	MOV $1117, X7
+	JMP callbackasm1(SB)
+	MOV $1118, X7
+	JMP callbackasm1(SB)
+	MOV $1119, X7
+	JMP callbackasm1(SB)
+	MOV $1120, X7
+	JMP callbackasm1(SB)
+	MOV $1121, X7
+	JMP callbackasm1(SB)
+	MOV $1122, X7
+	JMP callbackasm1(SB)
+	MOV $1123, X7
+	JMP callbackasm1(SB)
+	MOV $1124, X7
+	JMP callbackasm1(SB)
+	MOV $1125, X7
+	JMP callbackasm1(SB)
+	MOV $1126, X7
+	JMP callbackasm1(SB)
+	MOV $1127, X7
+	JMP callbackasm1(SB)
+	MOV $1128, X7
+	JMP callbackasm1(SB)
+	MOV $1129, X7
+	JMP callbackasm1(SB)
+	MOV $1130, X7
+	JMP callbackasm1(SB)
+	MOV $1131, X7
+	JMP callbackasm1(SB)
+	MOV $1132, X7
+	JMP callbackasm1(SB)
+	MOV $1133, X7
+	JMP callbackasm1(SB)
+	MOV $1134, X7
+	JMP callbackasm1(SB)
+	MOV $1135, X7
+	JMP callbackasm1(SB)
+	MOV $1136, X7
+	JMP callbackasm1(SB)
+	MOV $1137, X7
+	JMP callbackasm1(SB)
+	MOV $1138, X7
+	JMP callbackasm1(SB)
+	MOV $1139, X7
+	JMP callbackasm1(SB)
+	MOV $1140, X7
+	JMP callbackasm1(SB)
+	MOV $1141, X7
+	JMP callbackasm1(SB)
+	MOV $1142, X7
+	JMP callbackasm1(SB)
+	MOV $1143, X7
+	JMP callbackasm1(SB)
+	MOV $1144, X7
+	JMP callbackasm1(SB)
+	MOV $1145, X7
+	JMP callbackasm1(SB)
+	MOV $1146, X7
+	JMP callbackasm1(SB)
+	MOV $1147, X7
+	JMP callbackasm1(SB)
+	MOV $1148, X7
+	JMP callbackasm1(SB)
+	MOV $1149, X7
+	JMP callbackasm1(SB)
+	MOV $1150, X7
+	JMP callbackasm1(SB)
+	MOV $1151, X7
+	JMP callbackasm1(SB)
+	MOV $1152, X7
+	JMP callbackasm1(SB)
+	MOV $1153, X7
+	JMP callbackasm1(SB)
+	MOV $1154, X7
+	JMP callbackasm1(SB)
+	MOV $1155, X7
+	JMP callbackasm1(SB)
+	MOV $1156, X7
+	JMP callbackasm1(SB)
+	MOV $1157, X7
+	JMP callbackasm1(SB)
+	MOV $1158, X7
+	JMP callbackasm1(SB)
+	MOV $1159, X7
+	JMP callbackasm1(SB)
+	MOV $1160, X7
+	JMP callbackasm1(SB)
+	MOV $1161, X7
+	JMP callbackasm1(SB)
+	MOV $1162, X7
+	JMP callbackasm1(SB)
+	MOV $1163, X7
+	JMP callbackasm1(SB)
+	MOV $1164, X7
+	JMP callbackasm1(SB)
+	MOV $1165, X7
+	JMP callbackasm1(SB)
+	MOV $1166, X7
+	JMP callbackasm1(SB)
+	MOV $1167, X7
+	JMP callbackasm1(SB)
+	MOV $1168, X7
+	JMP callbackasm1(SB)
+	MOV $1169, X7
+	JMP callbackasm1(SB)
+	MOV $1170, X7
+	JMP callbackasm1(SB)
+	MOV $1171, X7
+	JMP callbackasm1(SB)
+	MOV $1172, X7
+	JMP callbackasm1(SB)
+	MOV $1173, X7
+	JMP callbackasm1(SB)
+	MOV $1174, X7
+	JMP callbackasm1(SB)
+	MOV $1175, X7
+	JMP callbackasm1(SB)
+	MOV $1176, X7
+	JMP callbackasm1(SB)
+	MOV $1177, X7
+	JMP callbackasm1(SB)
+	MOV $1178, X7
+	JMP callbackasm1(SB)
+	MOV $1179, X7
+	JMP callbackasm1(SB)
+	MOV $1180, X7
+	JMP callbackasm1(SB)
+	MOV $1181, X7
+	JMP callbackasm1(SB)
+	MOV $1182, X7
+	JMP callbackasm1(SB)
+	MOV $1183, X7
+	JMP callbackasm1(SB)
+	MOV $1184, X7
+	JMP callbackasm1(SB)
+	MOV $1185, X7
+	JMP callbackasm1(SB)
+	MOV $1186, X7
+	JMP callbackasm1(SB)
+	MOV $1187, X7
+	JMP callbackasm1(SB)
+	MOV $1188, X7
+	JMP callbackasm1(SB)
+	MOV $1189, X7
+	JMP callbackasm1(SB)
+	MOV $1190, X7
+	JMP callbackasm1(SB)
+	MOV $1191, X7
+	JMP callbackasm1(SB)
+	MOV $1192, X7
+	JMP callbackasm1(SB)
+	MOV $1193, X7
+	JMP callbackasm1(SB)
+	MOV $1194, X7
+	JMP callbackasm1(SB)
+	MOV $1195, X7
+	JMP callbackasm1(SB)
+	MOV $1196, X7
+	JMP callbackasm1(SB)
+	MOV $1197, X7
+	JMP callbackasm1(SB)
+	MOV $1198, X7
+	JMP callbackasm1(SB)
+	MOV $1199, X7
+	JMP callbackasm1(SB)
+	MOV $1200, X7
+	JMP callbackasm1(SB)
+	MOV $1201, X7
+	JMP callbackasm1(SB)
+	MOV $1202, X7
+	JMP callbackasm1(SB)
+	MOV $1203, X7
+	JMP callbackasm1(SB)
+	MOV $1204, X7
+	JMP callbackasm1(SB)
+	MOV $1205, X7
+	JMP callbackasm1(SB)
+	MOV $1206, X7
+	JMP callbackasm1(SB)
+	MOV $1207, X7
+	JMP callbackasm1(SB)
+	MOV $1208, X7
+	JMP callbackasm1(SB)
+	MOV $1209, X7
+	JMP callbackasm1(SB)
+	MOV $1210, X7
+	JMP callbackasm1(SB)
+	MOV $1211, X7
+	JMP callbackasm1(SB)
+	MOV $1212, X7
+	JMP callbackasm1(SB)
+	MOV $1213, X7
+	JMP callbackasm1(SB)
+	MOV $1214, X7
+	JMP callbackasm1(SB)
+	MOV $1215, X7
+	JMP callbackasm1(SB)
+	MOV $1216, X7
+	JMP callbackasm1(SB)
+	MOV $1217, X7
+	JMP callbackasm1(SB)
+	MOV $1218, X7
+	JMP callbackasm1(SB)
+	MOV $1219, X7
+	JMP callbackasm1(SB)
+	MOV $1220, X7
+	JMP callbackasm1(SB)
+	MOV $1221, X7
+	JMP callbackasm1(SB)
+	MOV $1222, X7
+	JMP callbackasm1(SB)
+	MOV $1223, X7
+	JMP callbackasm1(SB)
+	MOV $1224, X7
+	JMP callbackasm1(SB)
+	MOV $1225, X7
+	JMP callbackasm1(SB)
+	MOV $1226, X7
+	JMP callbackasm1(SB)
+	MOV $1227, X7
+	JMP callbackasm1(SB)
+	MOV $1228, X7
+	JMP callbackasm1(SB)
+	MOV $1229, X7
+	JMP callbackasm1(SB)
+	MOV $1230, X7
+	JMP callbackasm1(SB)
+	MOV $1231, X7
+	JMP callbackasm1(SB)
+	MOV $1232, X7
+	JMP callbackasm1(SB)
+	MOV $1233, X7
+	JMP callbackasm1(SB)
+	MOV $1234, X7
+	JMP callbackasm1(SB)
+	MOV $1235, X7
+	JMP callbackasm1(SB)
+	MOV $1236, X7
+	JMP callbackasm1(SB)
+	MOV $1237, X7
+	JMP callbackasm1(SB)
+	MOV $1238, X7
+	JMP callbackasm1(SB)
+	MOV $1239, X7
+	JMP callbackasm1(SB)
+	MOV $1240, X7
+	JMP callbackasm1(SB)
+	MOV $1241, X7
+	JMP callbackasm1(SB)
+	MOV $1242, X7
+	JMP callbackasm1(SB)
+	MOV $1243, X7
+	JMP callbackasm1(SB)
+	MOV $1244, X7
+	JMP callbackasm1(SB)
+	MOV $1245, X7
+	JMP callbackasm1(SB)
+	MOV $1246, X7
+	JMP callbackasm1(SB)
+	MOV $1247, X7
+	JMP callbackasm1(SB)
+	MOV $1248, X7
+	JMP callbackasm1(SB)
+	MOV $1249, X7
+	JMP callbackasm1(SB)
+	MOV $1250, X7
+	JMP callbackasm1(SB)
+	MOV $1251, X7
+	JMP callbackasm1(SB)
+	MOV $1252, X7
+	JMP callbackasm1(SB)
+	MOV $1253, X7
+	JMP callbackasm1(SB)
+	MOV $1254, X7
+	JMP callbackasm1(SB)
+	MOV $1255, X7
+	JMP callbackasm1(SB)
+	MOV $1256, X7
+	JMP callbackasm1(SB)
+	MOV $1257, X7
+	JMP callbackasm1(SB)
+	MOV $1258, X7
+	JMP callbackasm1(SB)
+	MOV $1259, X7
+	JMP callbackasm1(SB)
+	MOV $1260, X7
+	JMP callbackasm1(SB)
+	MOV $1261, X7
+	JMP callbackasm1(SB)
+	MOV $1262, X7
+	JMP callbackasm1(SB)
+	MOV $1263, X7
+	JMP callbackasm1(SB)
+	MOV $1264, X7
+	JMP callbackasm1(SB)
+	MOV $1265, X7
+	JMP callbackasm1(SB)
+	MOV $1266, X7
+	JMP callbackasm1(SB)
+	MOV $1267, X7
+	JMP callbackasm1(SB)
+	MOV $1268, X7
+	JMP callbackasm1(SB)
+	MOV $1269, X7
+	JMP callbackasm1(SB)
+	MOV $1270, X7
+	JMP callbackasm1(SB)
+	MOV $1271, X7
+	JMP callbackasm1(SB)
+	MOV $1272, X7
+	JMP callbackasm1(SB)
+	MOV $1273, X7
+	JMP callbackasm1(SB)
+	MOV $1274, X7
+	JMP callbackasm1(SB)
+	MOV $1275, X7
+	JMP callbackasm1(SB)
+	MOV $1276, X7
+	JMP callbackasm1(SB)
+	MOV $1277, X7
+	JMP callbackasm1(SB)
+	MOV $1278, X7
+	JMP callbackasm1(SB)
+	MOV $1279, X7
+	JMP callbackasm1(SB)
+	MOV $1280, X7
+	JMP callbackasm1(SB)
+	MOV $1281, X7
+	JMP callbackasm1(SB)
+	MOV $1282, X7
+	JMP callbackasm1(SB)
+	MOV $1283, X7
+	JMP callbackasm1(SB)
+	MOV $1284, X7
+	JMP callbackasm1(SB)
+	MOV $1285, X7
+	JMP callbackasm1(SB)
+	MOV $1286, X7
+	JMP callbackasm1(SB)
+	MOV $1287, X7
+	JMP callbackasm1(SB)
+	MOV $1288, X7
+	JMP callbackasm1(SB)
+	MOV $1289, X7
+	JMP callbackasm1(SB)
+	MOV $1290, X7
+	JMP callbackasm1(SB)
+	MOV $1291, X7
+	JMP callbackasm1(SB)
+	MOV $1292, X7
+	JMP callbackasm1(SB)
+	MOV $1293, X7
+	JMP callbackasm1(SB)
+	MOV $1294, X7
+	JMP callbackasm1(SB)
+	MOV $1295, X7
+	JMP callbackasm1(SB)
+	MOV $1296, X7
+	JMP callbackasm1(SB)
+	MOV $1297, X7
+	JMP callbackasm1(SB)
+	MOV $1298, X7
+	JMP callbackasm1(SB)
+	MOV $1299, X7
+	JMP callbackasm1(SB)
+	MOV $1300, X7
+	JMP callbackasm1(SB)
+	MOV $1301, X7
+	JMP callbackasm1(SB)
+	MOV $1302, X7
+	JMP callbackasm1(SB)
+	MOV $1303, X7
+	JMP callbackasm1(SB)
+	MOV $1304, X7
+	JMP callbackasm1(SB)
+	MOV $1305, X7
+	JMP callbackasm1(SB)
+	MOV $1306, X7
+	JMP callbackasm1(SB)
+	MOV $1307, X7
+	JMP callbackasm1(SB)
+	MOV $1308, X7
+	JMP callbackasm1(SB)
+	MOV $1309, X7
+	JMP callbackasm1(SB)
+	MOV $1310, X7
+	JMP callbackasm1(SB)
+	MOV $1311, X7
+	JMP callbackasm1(SB)
+	MOV $1312, X7
+	JMP callbackasm1(SB)
+	MOV $1313, X7
+	JMP callbackasm1(SB)
+	MOV $1314, X7
+	JMP callbackasm1(SB)
+	MOV $1315, X7
+	JMP callbackasm1(SB)
+	MOV $1316, X7
+	JMP callbackasm1(SB)
+	MOV $1317, X7
+	JMP callbackasm1(SB)
+	MOV $1318, X7
+	JMP callbackasm1(SB)
+	MOV $1319, X7
+	JMP callbackasm1(SB)
+	MOV $1320, X7
+	JMP callbackasm1(SB)
+	MOV $1321, X7
+	JMP callbackasm1(SB)
+	MOV $1322, X7
+	JMP callbackasm1(SB)
+	MOV $1323, X7
+	JMP callbackasm1(SB)
+	MOV $1324, X7
+	JMP callbackasm1(SB)
+	MOV $1325, X7
+	JMP callbackasm1(SB)
+	MOV $1326, X7
+	JMP callbackasm1(SB)
+	MOV $1327, X7
+	JMP callbackasm1(SB)
+	MOV $1328, X7
+	JMP callbackasm1(SB)
+	MOV $1329, X7
+	JMP callbackasm1(SB)
+	MOV $1330, X7
+	JMP callbackasm1(SB)
+	MOV $1331, X7
+	JMP callbackasm1(SB)
+	MOV $1332, X7
+	JMP callbackasm1(SB)
+	MOV $1333, X7
+	JMP callbackasm1(SB)
+	MOV $1334, X7
+	JMP callbackasm1(SB)
+	MOV $1335, X7
+	JMP callbackasm1(SB)
+	MOV $1336, X7
+	JMP callbackasm1(SB)
+	MOV $1337, X7
+	JMP callbackasm1(SB)
+	MOV $1338, X7
+	JMP callbackasm1(SB)
+	MOV $1339, X7
+	JMP callbackasm1(SB)
+	MOV $1340, X7
+	JMP callbackasm1(SB)
+	MOV $1341, X7
+	JMP callbackasm1(SB)
+	MOV $1342, X7
+	JMP callbackasm1(SB)
+	MOV $1343, X7
+	JMP callbackasm1(SB)
+	MOV $1344, X7
+	JMP callbackasm1(SB)
+	MOV $1345, X7
+	JMP callbackasm1(SB)
+	MOV $1346, X7
+	JMP callbackasm1(SB)
+	MOV $1347, X7
+	JMP callbackasm1(SB)
+	MOV $1348, X7
+	JMP callbackasm1(SB)
+	MOV $1349, X7
+	JMP callbackasm1(SB)
+	MOV $1350, X7
+	JMP callbackasm1(SB)
+	MOV $1351, X7
+	JMP callbackasm1(SB)
+	MOV $1352, X7
+	JMP callbackasm1(SB)
+	MOV $1353, X7
+	JMP callbackasm1(SB)
+	MOV $1354, X7
+	JMP callbackasm1(SB)
+	MOV $1355, X7
+	JMP callbackasm1(SB)
+	MOV $1356, X7
+	JMP callbackasm1(SB)
+	MOV $1357, X7
+	JMP callbackasm1(SB)
+	MOV $1358, X7
+	JMP callbackasm1(SB)
+	MOV $1359, X7
+	JMP callbackasm1(SB)
+	MOV $1360, X7
+	JMP callbackasm1(SB)
+	MOV $1361, X7
+	JMP callbackasm1(SB)
+	MOV $1362, X7
+	JMP callbackasm1(SB)
+	MOV $1363, X7
+	JMP callbackasm1(SB)
+	MOV $1364, X7
+	JMP callbackasm1(SB)
+	MOV $1365, X7
+	JMP callbackasm1(SB)
+	MOV $1366, X7
+	JMP callbackasm1(SB)
+	MOV $1367, X7
+	JMP callbackasm1(SB)
+	MOV $1368, X7
+	JMP callbackasm1(SB)
+	MOV $1369, X7
+	JMP callbackasm1(SB)
+	MOV $1370, X7
+	JMP callbackasm1(SB)
+	MOV $1371, X7
+	JMP callbackasm1(SB)
+	MOV $1372, X7
+	JMP callbackasm1(SB)
+	MOV $1373, X7
+	JMP callbackasm1(SB)
+	MOV $1374, X7
+	JMP callbackasm1(SB)
+	MOV $1375, X7
+	JMP callbackasm1(SB)
+	MOV $1376, X7
+	JMP callbackasm1(SB)
+	MOV $1377, X7
+	JMP callbackasm1(SB)
+	MOV $1378, X7
+	JMP callbackasm1(SB)
+	MOV $1379, X7
+	JMP callbackasm1(SB)
+	MOV $1380, X7
+	JMP callbackasm1(SB)
+	MOV $1381, X7
+	JMP callbackasm1(SB)
+	MOV $1382, X7
+	JMP callbackasm1(SB)
+	MOV $1383, X7
+	JMP callbackasm1(SB)
+	MOV $1384, X7
+	JMP callbackasm1(SB)
+	MOV $1385, X7
+	JMP callbackasm1(SB)
+	MOV $1386, X7
+	JMP callbackasm1(SB)
+	MOV $1387, X7
+	JMP callbackasm1(SB)
+	MOV $1388, X7
+	JMP callbackasm1(SB)
+	MOV $1389, X7
+	JMP callbackasm1(SB)
+	MOV $1390, X7
+	JMP callbackasm1(SB)
+	MOV $1391, X7
+	JMP callbackasm1(SB)
+	MOV $1392, X7
+	JMP callbackasm1(SB)
+	MOV $1393, X7
+	JMP callbackasm1(SB)
+	MOV $1394, X7
+	JMP callbackasm1(SB)
+	MOV $1395, X7
+	JMP callbackasm1(SB)
+	MOV $1396, X7
+	JMP callbackasm1(SB)
+	MOV $1397, X7
+	JMP callbackasm1(SB)
+	MOV $1398, X7
+	JMP callbackasm1(SB)
+	MOV $1399, X7
+	JMP callbackasm1(SB)
+	MOV $1400, X7
+	JMP callbackasm1(SB)
+	MOV $1401, X7
+	JMP callbackasm1(SB)
+	MOV $1402, X7
+	JMP callbackasm1(SB)
+	MOV $1403, X7
+	JMP callbackasm1(SB)
+	MOV $1404, X7
+	JMP callbackasm1(SB)
+	MOV $1405, X7
+	JMP callbackasm1(SB)
+	MOV $1406, X7
+	JMP callbackasm1(SB)
+	MOV $1407, X7
+	JMP callbackasm1(SB)
+	MOV $1408, X7
+	JMP callbackasm1(SB)
+	MOV $1409, X7
+	JMP callbackasm1(SB)
+	MOV $1410, X7
+	JMP callbackasm1(SB)
+	MOV $1411, X7
+	JMP callbackasm1(SB)
+	MOV $1412, X7
+	JMP callbackasm1(SB)
+	MOV $1413, X7
+	JMP callbackasm1(SB)
+	MOV $1414, X7
+	JMP callbackasm1(SB)
+	MOV $1415, X7
+	JMP callbackasm1(SB)
+	MOV $1416, X7
+	JMP callbackasm1(SB)
+	MOV $1417, X7
+	JMP callbackasm1(SB)
+	MOV $1418, X7
+	JMP callbackasm1(SB)
+	MOV $1419, X7
+	JMP callbackasm1(SB)
+	MOV $1420, X7
+	JMP callbackasm1(SB)
+	MOV $1421, X7
+	JMP callbackasm1(SB)
+	MOV $1422, X7
+	JMP callbackasm1(SB)
+	MOV $1423, X7
+	JMP callbackasm1(SB)
+	MOV $1424, X7
+	JMP callbackasm1(SB)
+	MOV $1425, X7
+	JMP callbackasm1(SB)
+	MOV $1426, X7
+	JMP callbackasm1(SB)
+	MOV $1427, X7
+	JMP callbackasm1(SB)
+	MOV $1428, X7
+	JMP callbackasm1(SB)
+	MOV $1429, X7
+	JMP callbackasm1(SB)
+	MOV $1430, X7
+	JMP callbackasm1(SB)
+	MOV $1431, X7
+	JMP callbackasm1(SB)
+	MOV $1432, X7
+	JMP callbackasm1(SB)
+	MOV $1433, X7
+	JMP callbackasm1(SB)
+	MOV $1434, X7
+	JMP callbackasm1(SB)
+	MOV $1435, X7
+	JMP callbackasm1(SB)
+	MOV $1436, X7
+	JMP callbackasm1(SB)
+	MOV $1437, X7
+	JMP callbackasm1(SB)
+	MOV $1438, X7
+	JMP callbackasm1(SB)
+	MOV $1439, X7
+	JMP callbackasm1(SB)
+	MOV $1440, X7
+	JMP callbackasm1(SB)
+	MOV $1441, X7
+	JMP callbackasm1(SB)
+	MOV $1442, X7
+	JMP callbackasm1(SB)
+	MOV $1443, X7
+	JMP callbackasm1(SB)
+	MOV $1444, X7
+	JMP callbackasm1(SB)
+	MOV $1445, X7
+	JMP callbackasm1(SB)
+	MOV $1446, X7
+	JMP callbackasm1(SB)
+	MOV $1447, X7
+	JMP callbackasm1(SB)
+	MOV $1448, X7
+	JMP callbackasm1(SB)
+	MOV $1449, X7
+	JMP callbackasm1(SB)
+	MOV $1450, X7
+	JMP callbackasm1(SB)
+	MOV $1451, X7
+	JMP callbackasm1(SB)
+	MOV $1452, X7
+	JMP callbackasm1(SB)
+	MOV $1453, X7
+	JMP callbackasm1(SB)
+	MOV $1454, X7
+	JMP callbackasm1(SB)
+	MOV $1455, X7
+	JMP callbackasm1(SB)
+	MOV $1456, X7
+	JMP callbackasm1(SB)
+	MOV $1457, X7
+	JMP callbackasm1(SB)
+	MOV $1458, X7
+	JMP callbackasm1(SB)
+	MOV $1459, X7
+	JMP callbackasm1(SB)
+	MOV $1460, X7
+	JMP callbackasm1(SB)
+	MOV $1461, X7
+	JMP callbackasm1(SB)
+	MOV $1462, X7
+	JMP callbackasm1(SB)
+	MOV $1463, X7
+	JMP callbackasm1(SB)
+	MOV $1464, X7
+	JMP callbackasm1(SB)
+	MOV $1465, X7
+	JMP callbackasm1(SB)
+	MOV $1466, X7
+	JMP callbackasm1(SB)
+	MOV $1467, X7
+	JMP callbackasm1(SB)
+	MOV $1468, X7
+	JMP callbackasm1(SB)
+	MOV $1469, X7
+	JMP callbackasm1(SB)
+	MOV $1470, X7
+	JMP callbackasm1(SB)
+	MOV $1471, X7
+	JMP callbackasm1(SB)
+	MOV $1472, X7
+	JMP callbackasm1(SB)
+	MOV $1473, X7
+	JMP callbackasm1(SB)
+	MOV $1474, X7
+	JMP callbackasm1(SB)
+	MOV $1475, X7
+	JMP callbackasm1(SB)
+	MOV $1476, X7
+	JMP callbackasm1(SB)
+	MOV $1477, X7
+	JMP callbackasm1(SB)
+	MOV $1478, X7
+	JMP callbackasm1(SB)
+	MOV $1479, X7
+	JMP callbackasm1(SB)
+	MOV $1480, X7
+	JMP callbackasm1(SB)
+	MOV $1481, X7
+	JMP callbackasm1(SB)
+	MOV $1482, X7
+	JMP callbackasm1(SB)
+	MOV $1483, X7
+	JMP callbackasm1(SB)
+	MOV $1484, X7
+	JMP callbackasm1(SB)
+	MOV $1485, X7
+	JMP callbackasm1(SB)
+	MOV $1486, X7
+	JMP callbackasm1(SB)
+	MOV $1487, X7
+	JMP callbackasm1(SB)
+	MOV $1488, X7
+	JMP callbackasm1(SB)
+	MOV $1489, X7
+	JMP callbackasm1(SB)
+	MOV $1490, X7
+	JMP callbackasm1(SB)
+	MOV $1491, X7
+	JMP callbackasm1(SB)
+	MOV $1492, X7
+	JMP callbackasm1(SB)
+	MOV $1493, X7
+	JMP callbackasm1(SB)
+	MOV $1494, X7
+	JMP callbackasm1(SB)
+	MOV $1495, X7
+	JMP callbackasm1(SB)
+	MOV $1496, X7
+	JMP callbackasm1(SB)
+	MOV $1497, X7
+	JMP callbackasm1(SB)
+	MOV $1498, X7
+	JMP callbackasm1(SB)
+	MOV $1499, X7
+	JMP callbackasm1(SB)
+	MOV $1500, X7
+	JMP callbackasm1(SB)
+	MOV $1501, X7
+	JMP callbackasm1(SB)
+	MOV $1502, X7
+	JMP callbackasm1(SB)
+	MOV $1503, X7
+	JMP callbackasm1(SB)
+	MOV $1504, X7
+	JMP callbackasm1(SB)
+	MOV $1505, X7
+	JMP callbackasm1(SB)
+	MOV $1506, X7
+	JMP callbackasm1(SB)
+	MOV $1507, X7
+	JMP callbackasm1(SB)
+	MOV $1508, X7
+	JMP callbackasm1(SB)
+	MOV $1509, X7
+	JMP callbackasm1(SB)
+	MOV $1510, X7
+	JMP callbackasm1(SB)
+	MOV $1511, X7
+	JMP callbackasm1(SB)
+	MOV $1512, X7
+	JMP callbackasm1(SB)
+	MOV $1513, X7
+	JMP callbackasm1(SB)
+	MOV $1514, X7
+	JMP callbackasm1(SB)
+	MOV $1515, X7
+	JMP callbackasm1(SB)
+	MOV $1516, X7
+	JMP callbackasm1(SB)
+	MOV $1517, X7
+	JMP callbackasm1(SB)
+	MOV $1518, X7
+	JMP callbackasm1(SB)
+	MOV $1519, X7
+	JMP callbackasm1(SB)
+	MOV $1520, X7
+	JMP callbackasm1(SB)
+	MOV $1521, X7
+	JMP callbackasm1(SB)
+	MOV $1522, X7
+	JMP callbackasm1(SB)
+	MOV $1523, X7
+	JMP callbackasm1(SB)
+	MOV $1524, X7
+	JMP callbackasm1(SB)
+	MOV $1525, X7
+	JMP callbackasm1(SB)
+	MOV $1526, X7
+	JMP callbackasm1(SB)
+	MOV $1527, X7
+	JMP callbackasm1(SB)
+	MOV $1528, X7
+	JMP callbackasm1(SB)
+	MOV $1529, X7
+	JMP callbackasm1(SB)
+	MOV $1530, X7
+	JMP callbackasm1(SB)
+	MOV $1531, X7
+	JMP callbackasm1(SB)
+	MOV $1532, X7
+	JMP callbackasm1(SB)
+	MOV $1533, X7
+	JMP callbackasm1(SB)
+	MOV $1534, X7
+	JMP callbackasm1(SB)
+	MOV $1535, X7
+	JMP callbackasm1(SB)
+	MOV $1536, X7
+	JMP callbackasm1(SB)
+	MOV $1537, X7
+	JMP callbackasm1(SB)
+	MOV $1538, X7
+	JMP callbackasm1(SB)
+	MOV $1539, X7
+	JMP callbackasm1(SB)
+	MOV $1540, X7
+	JMP callbackasm1(SB)
+	MOV $1541, X7
+	JMP callbackasm1(SB)
+	MOV $1542, X7
+	JMP callbackasm1(SB)
+	MOV $1543, X7
+	JMP callbackasm1(SB)
+	MOV $1544, X7
+	JMP callbackasm1(SB)
+	MOV $1545, X7
+	JMP callbackasm1(SB)
+	MOV $1546, X7
+	JMP callbackasm1(SB)
+	MOV $1547, X7
+	JMP callbackasm1(SB)
+	MOV $1548, X7
+	JMP callbackasm1(SB)
+	MOV $1549, X7
+	JMP callbackasm1(SB)
+	MOV $1550, X7
+	JMP callbackasm1(SB)
+	MOV $1551, X7
+	JMP callbackasm1(SB)
+	MOV $1552, X7
+	JMP callbackasm1(SB)
+	MOV $1553, X7
+	JMP callbackasm1(SB)
+	MOV $1554, X7
+	JMP callbackasm1(SB)
+	MOV $1555, X7
+	JMP callbackasm1(SB)
+	MOV $1556, X7
+	JMP callbackasm1(SB)
+	MOV $1557, X7
+	JMP callbackasm1(SB)
+	MOV $1558, X7
+	JMP callbackasm1(SB)
+	MOV $1559, X7
+	JMP callbackasm1(SB)
+	MOV $1560, X7
+	JMP callbackasm1(SB)
+	MOV $1561, X7
+	JMP callbackasm1(SB)
+	MOV $1562, X7
+	JMP callbackasm1(SB)
+	MOV $1563, X7
+	JMP callbackasm1(SB)
+	MOV $1564, X7
+	JMP callbackasm1(SB)
+	MOV $1565, X7
+	JMP callbackasm1(SB)
+	MOV $1566, X7
+	JMP callbackasm1(SB)
+	MOV $1567, X7
+	JMP callbackasm1(SB)
+	MOV $1568, X7
+	JMP callbackasm1(SB)
+	MOV $1569, X7
+	JMP callbackasm1(SB)
+	MOV $1570, X7
+	JMP callbackasm1(SB)
+	MOV $1571, X7
+	JMP callbackasm1(SB)
+	MOV $1572, X7
+	JMP callbackasm1(SB)
+	MOV $1573, X7
+	JMP callbackasm1(SB)
+	MOV $1574, X7
+	JMP callbackasm1(SB)
+	MOV $1575, X7
+	JMP callbackasm1(SB)
+	MOV $1576, X7
+	JMP callbackasm1(SB)
+	MOV $1577, X7
+	JMP callbackasm1(SB)
+	MOV $1578, X7
+	JMP callbackasm1(SB)
+	MOV $1579, X7
+	JMP callbackasm1(SB)
+	MOV $1580, X7
+	JMP callbackasm1(SB)
+	MOV $1581, X7
+	JMP callbackasm1(SB)
+	MOV $1582, X7
+	JMP callbackasm1(SB)
+	MOV $1583, X7
+	JMP callbackasm1(SB)
+	MOV $1584, X7
+	JMP callbackasm1(SB)
+	MOV $1585, X7
+	JMP callbackasm1(SB)
+	MOV $1586, X7
+	JMP callbackasm1(SB)
+	MOV $1587, X7
+	JMP callbackasm1(SB)
+	MOV $1588, X7
+	JMP callbackasm1(SB)
+	MOV $1589, X7
+	JMP callbackasm1(SB)
+	MOV $1590, X7
+	JMP callbackasm1(SB)
+	MOV $1591, X7
+	JMP callbackasm1(SB)
+	MOV $1592, X7
+	JMP callbackasm1(SB)
+	MOV $1593, X7
+	JMP callbackasm1(SB)
+	MOV $1594, X7
+	JMP callbackasm1(SB)
+	MOV $1595, X7
+	JMP callbackasm1(SB)
+	MOV $1596, X7
+	JMP callbackasm1(SB)
+	MOV $1597, X7
+	JMP callbackasm1(SB)
+	MOV $1598, X7
+	JMP callbackasm1(SB)
+	MOV $1599, X7
+	JMP callbackasm1(SB)
+	MOV $1600, X7
+	JMP callbackasm1(SB)
+	MOV $1601, X7
+	JMP callbackasm1(SB)
+	MOV $1602, X7
+	JMP callbackasm1(SB)
+	MOV $1603, X7
+	JMP callbackasm1(SB)
+	MOV $1604, X7
+	JMP callbackasm1(SB)
+	MOV $1605, X7
+	JMP callbackasm1(SB)
+	MOV $1606, X7
+	JMP callbackasm1(SB)
+	MOV $1607, X7
+	JMP callbackasm1(SB)
+	MOV $1608, X7
+	JMP callbackasm1(SB)
+	MOV $1609, X7
+	JMP callbackasm1(SB)
+	MOV $1610, X7
+	JMP callbackasm1(SB)
+	MOV $1611, X7
+	JMP callbackasm1(SB)
+	MOV $1612, X7
+	JMP callbackasm1(SB)
+	MOV $1613, X7
+	JMP callbackasm1(SB)
+	MOV $1614, X7
+	JMP callbackasm1(SB)
+	MOV $1615, X7
+	JMP callbackasm1(SB)
+	MOV $1616, X7
+	JMP callbackasm1(SB)
+	MOV $1617, X7
+	JMP callbackasm1(SB)
+	MOV $1618, X7
+	JMP callbackasm1(SB)
+	MOV $1619, X7
+	JMP callbackasm1(SB)
+	MOV $1620, X7
+	JMP callbackasm1(SB)
+	MOV $1621, X7
+	JMP callbackasm1(SB)
+	MOV $1622, X7
+	JMP callbackasm1(SB)
+	MOV $1623, X7
+	JMP callbackasm1(SB)
+	MOV $1624, X7
+	JMP callbackasm1(SB)
+	MOV $1625, X7
+	JMP callbackasm1(SB)
+	MOV $1626, X7
+	JMP callbackasm1(SB)
+	MOV $1627, X7
+	JMP callbackasm1(SB)
+	MOV $1628, X7
+	JMP callbackasm1(SB)
+	MOV $1629, X7
+	JMP callbackasm1(SB)
+	MOV $1630, X7
+	JMP callbackasm1(SB)
+	MOV $1631, X7
+	JMP callbackasm1(SB)
+	MOV $1632, X7
+	JMP callbackasm1(SB)
+	MOV $1633, X7
+	JMP callbackasm1(SB)
+	MOV $1634, X7
+	JMP callbackasm1(SB)
+	MOV $1635, X7
+	JMP callbackasm1(SB)
+	MOV $1636, X7
+	JMP callbackasm1(SB)
+	MOV $1637, X7
+	JMP callbackasm1(SB)
+	MOV $1638, X7
+	JMP callbackasm1(SB)
+	MOV $1639, X7
+	JMP callbackasm1(SB)
+	MOV $1640, X7
+	JMP callbackasm1(SB)
+	MOV $1641, X7
+	JMP callbackasm1(SB)
+	MOV $1642, X7
+	JMP callbackasm1(SB)
+	MOV $1643, X7
+	JMP callbackasm1(SB)
+	MOV $1644, X7
+	JMP callbackasm1(SB)
+	MOV $1645, X7
+	JMP callbackasm1(SB)
+	MOV $1646, X7
+	JMP callbackasm1(SB)
+	MOV $1647, X7
+	JMP callbackasm1(SB)
+	MOV $1648, X7
+	JMP callbackasm1(SB)
+	MOV $1649, X7
+	JMP callbackasm1(SB)
+	MOV $1650, X7
+	JMP callbackasm1(SB)
+	MOV $1651, X7
+	JMP callbackasm1(SB)
+	MOV $1652, X7
+	JMP callbackasm1(SB)
+	MOV $1653, X7
+	JMP callbackasm1(SB)
+	MOV $1654, X7
+	JMP callbackasm1(SB)
+	MOV $1655, X7
+	JMP callbackasm1(SB)
+	MOV $1656, X7
+	JMP callbackasm1(SB)
+	MOV $1657, X7
+	JMP callbackasm1(SB)
+	MOV $1658, X7
+	JMP callbackasm1(SB)
+	MOV $1659, X7
+	JMP callbackasm1(SB)
+	MOV $1660, X7
+	JMP callbackasm1(SB)
+	MOV $1661, X7
+	JMP callbackasm1(SB)
+	MOV $1662, X7
+	JMP callbackasm1(SB)
+	MOV $1663, X7
+	JMP callbackasm1(SB)
+	MOV $1664, X7
+	JMP callbackasm1(SB)
+	MOV $1665, X7
+	JMP callbackasm1(SB)
+	MOV $1666, X7
+	JMP callbackasm1(SB)
+	MOV $1667, X7
+	JMP callbackasm1(SB)
+	MOV $1668, X7
+	JMP callbackasm1(SB)
+	MOV $1669, X7
+	JMP callbackasm1(SB)
+	MOV $1670, X7
+	JMP callbackasm1(SB)
+	MOV $1671, X7
+	JMP callbackasm1(SB)
+	MOV $1672, X7
+	JMP callbackasm1(SB)
+	MOV $1673, X7
+	JMP callbackasm1(SB)
+	MOV $1674, X7
+	JMP callbackasm1(SB)
+	MOV $1675, X7
+	JMP callbackasm1(SB)
+	MOV $1676, X7
+	JMP callbackasm1(SB)
+	MOV $1677, X7
+	JMP callbackasm1(SB)
+	MOV $1678, X7
+	JMP callbackasm1(SB)
+	MOV $1679, X7
+	JMP callbackasm1(SB)
+	MOV $1680, X7
+	JMP callbackasm1(SB)
+	MOV $1681, X7
+	JMP callbackasm1(SB)
+	MOV $1682, X7
+	JMP callbackasm1(SB)
+	MOV $1683, X7
+	JMP callbackasm1(SB)
+	MOV $1684, X7
+	JMP callbackasm1(SB)
+	MOV $1685, X7
+	JMP callbackasm1(SB)
+	MOV $1686, X7
+	JMP callbackasm1(SB)
+	MOV $1687, X7
+	JMP callbackasm1(SB)
+	MOV $1688, X7
+	JMP callbackasm1(SB)
+	MOV $1689, X7
+	JMP callbackasm1(SB)
+	MOV $1690, X7
+	JMP callbackasm1(SB)
+	MOV $1691, X7
+	JMP callbackasm1(SB)
+	MOV $1692, X7
+	JMP callbackasm1(SB)
+	MOV $1693, X7
+	JMP callbackasm1(SB)
+	MOV $1694, X7
+	JMP callbackasm1(SB)
+	MOV $1695, X7
+	JMP callbackasm1(SB)
+	MOV $1696, X7
+	JMP callbackasm1(SB)
+	MOV $1697, X7
+	JMP callbackasm1(SB)
+	MOV $1698, X7
+	JMP callbackasm1(SB)
+	MOV $1699, X7
+	JMP callbackasm1(SB)
+	MOV $1700, X7
+	JMP callbackasm1(SB)
+	MOV $1701, X7
+	JMP callbackasm1(SB)
+	MOV $1702, X7
+	JMP callbackasm1(SB)
+	MOV $1703, X7
+	JMP callbackasm1(SB)
+	MOV $1704, X7
+	JMP callbackasm1(SB)
+	MOV $1705, X7
+	JMP callbackasm1(SB)
+	MOV $1706, X7
+	JMP callbackasm1(SB)
+	MOV $1707, X7
+	JMP callbackasm1(SB)
+	MOV $1708, X7
+	JMP callbackasm1(SB)
+	MOV $1709, X7
+	JMP callbackasm1(SB)
+	MOV $1710, X7
+	JMP callbackasm1(SB)
+	MOV $1711, X7
+	JMP callbackasm1(SB)
+	MOV $1712, X7
+	JMP callbackasm1(SB)
+	MOV $1713, X7
+	JMP callbackasm1(SB)
+	MOV $1714, X7
+	JMP callbackasm1(SB)
+	MOV $1715, X7
+	JMP callbackasm1(SB)
+	MOV $1716, X7
+	JMP callbackasm1(SB)
+	MOV $1717, X7
+	JMP callbackasm1(SB)
+	MOV $1718, X7
+	JMP callbackasm1(SB)
+	MOV $1719, X7
+	JMP callbackasm1(SB)
+	MOV $1720, X7
+	JMP callbackasm1(SB)
+	MOV $1721, X7
+	JMP callbackasm1(SB)
+	MOV $1722, X7
+	JMP callbackasm1(SB)
+	MOV $1723, X7
+	JMP callbackasm1(SB)
+	MOV $1724, X7
+	JMP callbackasm1(SB)
+	MOV $1725, X7
+	JMP callbackasm1(SB)
+	MOV $1726, X7
+	JMP callbackasm1(SB)
+	MOV $1727, X7
+	JMP callbackasm1(SB)
+	MOV $1728, X7
+	JMP callbackasm1(SB)
+	MOV $1729, X7
+	JMP callbackasm1(SB)
+	MOV $1730, X7
+	JMP callbackasm1(SB)
+	MOV $1731, X7
+	JMP callbackasm1(SB)
+	MOV $1732, X7
+	JMP callbackasm1(SB)
+	MOV $1733, X7
+	JMP callbackasm1(SB)
+	MOV $1734, X7
+	JMP callbackasm1(SB)
+	MOV $1735, X7
+	JMP callbackasm1(SB)
+	MOV $1736, X7
+	JMP callbackasm1(SB)
+	MOV $1737, X7
+	JMP callbackasm1(SB)
+	MOV $1738, X7
+	JMP callbackasm1(SB)
+	MOV $1739, X7
+	JMP callbackasm1(SB)
+	MOV $1740, X7
+	JMP callbackasm1(SB)
+	MOV $1741, X7
+	JMP callbackasm1(SB)
+	MOV $1742, X7
+	JMP callbackasm1(SB)
+	MOV $1743, X7
+	JMP callbackasm1(SB)
+	MOV $1744, X7
+	JMP callbackasm1(SB)
+	MOV $1745, X7
+	JMP callbackasm1(SB)
+	MOV $1746, X7
+	JMP callbackasm1(SB)
+	MOV $1747, X7
+	JMP callbackasm1(SB)
+	MOV $1748, X7
+	JMP callbackasm1(SB)
+	MOV $1749, X7
+	JMP callbackasm1(SB)
+	MOV $1750, X7
+	JMP callbackasm1(SB)
+	MOV $1751, X7
+	JMP callbackasm1(SB)
+	MOV $1752, X7
+	JMP callbackasm1(SB)
+	MOV $1753, X7
+	JMP callbackasm1(SB)
+	MOV $1754, X7
+	JMP callbackasm1(SB)
+	MOV $1755, X7
+	JMP callbackasm1(SB)
+	MOV $1756, X7
+	JMP callbackasm1(SB)
+	MOV $1757, X7
+	JMP callbackasm1(SB)
+	MOV $1758, X7
+	JMP callbackasm1(SB)
+	MOV $1759, X7
+	JMP callbackasm1(SB)
+	MOV $1760, X7
+	JMP callbackasm1(SB)
+	MOV $1761, X7
+	JMP callbackasm1(SB)
+	MOV $1762, X7
+	JMP callbackasm1(SB)
+	MOV $1763, X7
+	JMP callbackasm1(SB)
+	MOV $1764, X7
+	JMP callbackasm1(SB)
+	MOV $1765, X7
+	JMP callbackasm1(SB)
+	MOV $1766, X7
+	JMP callbackasm1(SB)
+	MOV $1767, X7
+	JMP callbackasm1(SB)
+	MOV $1768, X7
+	JMP callbackasm1(SB)
+	MOV $1769, X7
+	JMP callbackasm1(SB)
+	MOV $1770, X7
+	JMP callbackasm1(SB)
+	MOV $1771, X7
+	JMP callbackasm1(SB)
+	MOV $1772, X7
+	JMP callbackasm1(SB)
+	MOV $1773, X7
+	JMP callbackasm1(SB)
+	MOV $1774, X7
+	JMP callbackasm1(SB)
+	MOV $1775, X7
+	JMP callbackasm1(SB)
+	MOV $1776, X7
+	JMP callbackasm1(SB)
+	MOV $1777, X7
+	JMP callbackasm1(SB)
+	MOV $1778, X7
+	JMP callbackasm1(SB)
+	MOV $1779, X7
+	JMP callbackasm1(SB)
+	MOV $1780, X7
+	JMP callbackasm1(SB)
+	MOV $1781, X7
+	JMP callbackasm1(SB)
+	MOV $1782, X7
+	JMP callbackasm1(SB)
+	MOV $1783, X7
+	JMP callbackasm1(SB)
+	MOV $1784, X7
+	JMP callbackasm1(SB)
+	MOV $1785, X7
+	JMP callbackasm1(SB)
+	MOV $1786, X7
+	JMP callbackasm1(SB)
+	MOV $1787, X7
+	JMP callbackasm1(SB)
+	MOV $1788, X7
+	JMP callbackasm1(SB)
+	MOV $1789, X7
+	JMP callbackasm1(SB)
+	MOV $1790, X7
+	JMP callbackasm1(SB)
+	MOV $1791, X7
+	JMP callbackasm1(SB)
+	MOV $1792, X7
+	JMP callbackasm1(SB)
+	MOV $1793, X7
+	JMP callbackasm1(SB)
+	MOV $1794, X7
+	JMP callbackasm1(SB)
+	MOV $1795, X7
+	JMP callbackasm1(SB)
+	MOV $1796, X7
+	JMP callbackasm1(SB)
+	MOV $1797, X7
+	JMP callbackasm1(SB)
+	MOV $1798, X7
+	JMP callbackasm1(SB)
+	MOV $1799, X7
+	JMP callbackasm1(SB)
+	MOV $1800, X7
+	JMP callbackasm1(SB)
+	MOV $1801, X7
+	JMP callbackasm1(SB)
+	MOV $1802, X7
+	JMP callbackasm1(SB)
+	MOV $1803, X7
+	JMP callbackasm1(SB)
+	MOV $1804, X7
+	JMP callbackasm1(SB)
+	MOV $1805, X7
+	JMP callbackasm1(SB)
+	MOV $1806, X7
+	JMP callbackasm1(SB)
+	MOV $1807, X7
+	JMP callbackasm1(SB)
+	MOV $1808, X7
+	JMP callbackasm1(SB)
+	MOV $1809, X7
+	JMP callbackasm1(SB)
+	MOV $1810, X7
+	JMP callbackasm1(SB)
+	MOV $1811, X7
+	JMP callbackasm1(SB)
+	MOV $1812, X7
+	JMP callbackasm1(SB)
+	MOV $1813, X7
+	JMP callbackasm1(SB)
+	MOV $1814, X7
+	JMP callbackasm1(SB)
+	MOV $1815, X7
+	JMP callbackasm1(SB)
+	MOV $1816, X7
+	JMP callbackasm1(SB)
+	MOV $1817, X7
+	JMP callbackasm1(SB)
+	MOV $1818, X7
+	JMP callbackasm1(SB)
+	MOV $1819, X7
+	JMP callbackasm1(SB)
+	MOV $1820, X7
+	JMP callbackasm1(SB)
+	MOV $1821, X7
+	JMP callbackasm1(SB)
+	MOV $1822, X7
+	JMP callbackasm1(SB)
+	MOV $1823, X7
+	JMP callbackasm1(SB)
+	MOV $1824, X7
+	JMP callbackasm1(SB)
+	MOV $1825, X7
+	JMP callbackasm1(SB)
+	MOV $1826, X7
+	JMP callbackasm1(SB)
+	MOV $1827, X7
+	JMP callbackasm1(SB)
+	MOV $1828, X7
+	JMP callbackasm1(SB)
+	MOV $1829, X7
+	JMP callbackasm1(SB)
+	MOV $1830, X7
+	JMP callbackasm1(SB)
+	MOV $1831, X7
+	JMP callbackasm1(SB)
+	MOV $1832, X7
+	JMP callbackasm1(SB)
+	MOV $1833, X7
+	JMP callbackasm1(SB)
+	MOV $1834, X7
+	JMP callbackasm1(SB)
+	MOV $1835, X7
+	JMP callbackasm1(SB)
+	MOV $1836, X7
+	JMP callbackasm1(SB)
+	MOV $1837, X7
+	JMP callbackasm1(SB)
+	MOV $1838, X7
+	JMP callbackasm1(SB)
+	MOV $1839, X7
+	JMP callbackasm1(SB)
+	MOV $1840, X7
+	JMP callbackasm1(SB)
+	MOV $1841, X7
+	JMP callbackasm1(SB)
+	MOV $1842, X7
+	JMP callbackasm1(SB)
+	MOV $1843, X7
+	JMP callbackasm1(SB)
+	MOV $1844, X7
+	JMP callbackasm1(SB)
+	MOV $1845, X7
+	JMP callbackasm1(SB)
+	MOV $1846, X7
+	JMP callbackasm1(SB)
+	MOV $1847, X7
+	JMP callbackasm1(SB)
+	MOV $1848, X7
+	JMP callbackasm1(SB)
+	MOV $1849, X7
+	JMP callbackasm1(SB)
+	MOV $1850, X7
+	JMP callbackasm1(SB)
+	MOV $1851, X7
+	JMP callbackasm1(SB)
+	MOV $1852, X7
+	JMP callbackasm1(SB)
+	MOV $1853, X7
+	JMP callbackasm1(SB)
+	MOV $1854, X7
+	JMP callbackasm1(SB)
+	MOV $1855, X7
+	JMP callbackasm1(SB)
+	MOV $1856, X7
+	JMP callbackasm1(SB)
+	MOV $1857, X7
+	JMP callbackasm1(SB)
+	MOV $1858, X7
+	JMP callbackasm1(SB)
+	MOV $1859, X7
+	JMP callbackasm1(SB)
+	MOV $1860, X7
+	JMP callbackasm1(SB)
+	MOV $1861, X7
+	JMP callbackasm1(SB)
+	MOV $1862, X7
+	JMP callbackasm1(SB)
+	MOV $1863, X7
+	JMP callbackasm1(SB)
+	MOV $1864, X7
+	JMP callbackasm1(SB)
+	MOV $1865, X7
+	JMP callbackasm1(SB)
+	MOV $1866, X7
+	JMP callbackasm1(SB)
+	MOV $1867, X7
+	JMP callbackasm1(SB)
+	MOV $1868, X7
+	JMP callbackasm1(SB)
+	MOV $1869, X7
+	JMP callbackasm1(SB)
+	MOV $1870, X7
+	JMP callbackasm1(SB)
+	MOV $1871, X7
+	JMP callbackasm1(SB)
+	MOV $1872, X7
+	JMP callbackasm1(SB)
+	MOV $1873, X7
+	JMP callbackasm1(SB)
+	MOV $1874, X7
+	JMP callbackasm1(SB)
+	MOV $1875, X7
+	JMP callbackasm1(SB)
+	MOV $1876, X7
+	JMP callbackasm1(SB)
+	MOV $1877, X7
+	JMP callbackasm1(SB)
+	MOV $1878, X7
+	JMP callbackasm1(SB)
+	MOV $1879, X7
+	JMP callbackasm1(SB)
+	MOV $1880, X7
+	JMP callbackasm1(SB)
+	MOV $1881, X7
+	JMP callbackasm1(SB)
+	MOV $1882, X7
+	JMP callbackasm1(SB)
+	MOV $1883, X7
+	JMP callbackasm1(SB)
+	MOV $1884, X7
+	JMP callbackasm1(SB)
+	MOV $1885, X7
+	JMP callbackasm1(SB)
+	MOV $1886, X7
+	JMP callbackasm1(SB)
+	MOV $1887, X7
+	JMP callbackasm1(SB)
+	MOV $1888, X7
+	JMP callbackasm1(SB)
+	MOV $1889, X7
+	JMP callbackasm1(SB)
+	MOV $1890, X7
+	JMP callbackasm1(SB)
+	MOV $1891, X7
+	JMP callbackasm1(SB)
+	MOV $1892, X7
+	JMP callbackasm1(SB)
+	MOV $1893, X7
+	JMP callbackasm1(SB)
+	MOV $1894, X7
+	JMP callbackasm1(SB)
+	MOV $1895, X7
+	JMP callbackasm1(SB)
+	MOV $1896, X7
+	JMP callbackasm1(SB)
+	MOV $1897, X7
+	JMP callbackasm1(SB)
+	MOV $1898, X7
+	JMP callbackasm1(SB)
+	MOV $1899, X7
+	JMP callbackasm1(SB)
+	MOV $1900, X7
+	JMP callbackasm1(SB)
+	MOV $1901, X7
+	JMP callbackasm1(SB)
+	MOV $1902, X7
+	JMP callbackasm1(SB)
+	MOV $1903, X7
+	JMP callbackasm1(SB)
+	MOV $1904, X7
+	JMP callbackasm1(SB)
+	MOV $1905, X7
+	JMP callbackasm1(SB)
+	MOV $1906, X7
+	JMP callbackasm1(SB)
+	MOV $1907, X7
+	JMP callbackasm1(SB)
+	MOV $1908, X7
+	JMP callbackasm1(SB)
+	MOV $1909, X7
+	JMP callbackasm1(SB)
+	MOV $1910, X7
+	JMP callbackasm1(SB)
+	MOV $1911, X7
+	JMP callbackasm1(SB)
+	MOV $1912, X7
+	JMP callbackasm1(SB)
+	MOV $1913, X7
+	JMP callbackasm1(SB)
+	MOV $1914, X7
+	JMP callbackasm1(SB)
+	MOV $1915, X7
+	JMP callbackasm1(SB)
+	MOV $1916, X7
+	JMP callbackasm1(SB)
+	MOV $1917, X7
+	JMP callbackasm1(SB)
+	MOV $1918, X7
+	JMP callbackasm1(SB)
+	MOV $1919, X7
+	JMP callbackasm1(SB)
+	MOV $1920, X7
+	JMP callbackasm1(SB)
+	MOV $1921, X7
+	JMP callbackasm1(SB)
+	MOV $1922, X7
+	JMP callbackasm1(SB)
+	MOV $1923, X7
+	JMP callbackasm1(SB)
+	MOV $1924, X7
+	JMP callbackasm1(SB)
+	MOV $1925, X7
+	JMP callbackasm1(SB)
+	MOV $1926, X7
+	JMP callbackasm1(SB)
+	MOV $1927, X7
+	JMP callbackasm1(SB)
+	MOV $1928, X7
+	JMP callbackasm1(SB)
+	MOV $1929, X7
+	JMP callbackasm1(SB)
+	MOV $1930, X7
+	JMP callbackasm1(SB)
+	MOV $1931, X7
+	JMP callbackasm1(SB)
+	MOV $1932, X7
+	JMP callbackasm1(SB)
+	MOV $1933, X7
+	JMP callbackasm1(SB)
+	MOV $1934, X7
+	JMP callbackasm1(SB)
+	MOV $1935, X7
+	JMP callbackasm1(SB)
+	MOV $1936, X7
+	JMP callbackasm1(SB)
+	MOV $1937, X7
+	JMP callbackasm1(SB)
+	MOV $1938, X7
+	JMP callbackasm1(SB)
+	MOV $1939, X7
+	JMP callbackasm1(SB)
+	MOV $1940, X7
+	JMP callbackasm1(SB)
+	MOV $1941, X7
+	JMP callbackasm1(SB)
+	MOV $1942, X7
+	JMP callbackasm1(SB)
+	MOV $1943, X7
+	JMP callbackasm1(SB)
+	MOV $1944, X7
+	JMP callbackasm1(SB)
+	MOV $1945, X7
+	JMP callbackasm1(SB)
+	MOV $1946, X7
+	JMP callbackasm1(SB)
+	MOV $1947, X7
+	JMP callbackasm1(SB)
+	MOV $1948, X7
+	JMP callbackasm1(SB)
+	MOV $1949, X7
+	JMP callbackasm1(SB)
+	MOV $1950, X7
+	JMP callbackasm1(SB)
+	MOV $1951, X7
+	JMP callbackasm1(SB)
+	MOV $1952, X7
+	JMP callbackasm1(SB)
+	MOV $1953, X7
+	JMP callbackasm1(SB)
+	MOV $1954, X7
+	JMP callbackasm1(SB)
+	MOV $1955, X7
+	JMP callbackasm1(SB)
+	MOV $1956, X7
+	JMP callbackasm1(SB)
+	MOV $1957, X7
+	JMP callbackasm1(SB)
+	MOV $1958, X7
+	JMP callbackasm1(SB)
+	MOV $1959, X7
+	JMP callbackasm1(SB)
+	MOV $1960, X7
+	JMP callbackasm1(SB)
+	MOV $1961, X7
+	JMP callbackasm1(SB)
+	MOV $1962, X7
+	JMP callbackasm1(SB)
+	MOV $1963, X7
+	JMP callbackasm1(SB)
+	MOV $1964, X7
+	JMP callbackasm1(SB)
+	MOV $1965, X7
+	JMP callbackasm1(SB)
+	MOV $1966, X7
+	JMP callbackasm1(SB)
+	MOV $1967, X7
+	JMP callbackasm1(SB)
+	MOV $1968, X7
+	JMP callbackasm1(SB)
+	MOV $1969, X7
+	JMP callbackasm1(SB)
+	MOV $1970, X7
+	JMP callbackasm1(SB)
+	MOV $1971, X7
+	JMP callbackasm1(SB)
+	MOV $1972, X7
+	JMP callbackasm1(SB)
+	MOV $1973, X7
+	JMP callbackasm1(SB)
+	MOV $1974, X7
+	JMP callbackasm1(SB)
+	MOV $1975, X7
+	JMP callbackasm1(SB)
+	MOV $1976, X7
+	JMP callbackasm1(SB)
+	MOV $1977, X7
+	JMP callbackasm1(SB)
+	MOV $1978, X7
+	JMP callbackasm1(SB)
+	MOV $1979, X7
+	JMP callbackasm1(SB)
+	MOV $1980, X7
+	JMP callbackasm1(SB)
+	MOV $1981, X7
+	JMP callbackasm1(SB)
+	MOV $1982, X7
+	JMP callbackasm1(SB)
+	MOV $1983, X7
+	JMP callbackasm1(SB)
+	MOV $1984, X7
+	JMP callbackasm1(SB)
+	MOV $1985, X7
+	JMP callbackasm1(SB)
+	MOV $1986, X7
+	JMP callbackasm1(SB)
+	MOV $1987, X7
+	JMP callbackasm1(SB)
+	MOV $1988, X7
+	JMP callbackasm1(SB)
+	MOV $1989, X7
+	JMP callbackasm1(SB)
+	MOV $1990, X7
+	JMP callbackasm1(SB)
+	MOV $1991, X7
+	JMP callbackasm1(SB)
+	MOV $1992, X7
+	JMP callbackasm1(SB)
+	MOV $1993, X7
+	JMP callbackasm1(SB)
+	MOV $1994, X7
+	JMP callbackasm1(SB)
+	MOV $1995, X7
+	JMP callbackasm1(SB)
+	MOV $1996, X7
+	JMP callbackasm1(SB)
+	MOV $1997, X7
+	JMP callbackasm1(SB)
+	MOV $1998, X7
+	JMP callbackasm1(SB)
+	MOV $1999, X7
+	JMP callbackasm1(SB)
diff --git a/vendor/github.com/ebitengine/purego/zcallback_s390x.s b/vendor/github.com/ebitengine/purego/zcallback_s390x.s
new file mode 100644
index 000000000..6b5e2b038
--- /dev/null
+++ b/vendor/github.com/ebitengine/purego/zcallback_s390x.s
@@ -0,0 +1,4015 @@
+// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+
+//go:build linux
+
+// External code calls into callbackasm at an offset corresponding
+// to the callback index. Callbackasm is a table of MOVD and BR instructions.
+// The MOVD instruction loads R0 with the callback index, and the
+// BR instruction branches to callbackasm1.
+// callbackasm1 takes the callback index from R0 and
+// indexes into an array that stores information about each callback.
+// It then calls the Go implementation for that callback.
+// NOTE: We use R0 instead of R11 because R11 is callee-saved on S390X.
+#include "textflag.h"
+
+TEXT callbackasm(SB), NOSPLIT|NOFRAME, $0
+	MOVD $0, R0
+	BR   callbackasm1(SB)
+	MOVD $1, R0
+	BR   callbackasm1(SB)
+	MOVD $2, R0
+	BR   callbackasm1(SB)
+	MOVD $3, R0
+	BR   callbackasm1(SB)
+	MOVD $4, R0
+	BR   callbackasm1(SB)
+	MOVD $5, R0
+	BR   callbackasm1(SB)
+	MOVD $6, R0
+	BR   callbackasm1(SB)
+	MOVD $7, R0
+	BR   callbackasm1(SB)
+	MOVD $8, R0
+	BR   callbackasm1(SB)
+	MOVD $9, R0
+	BR   callbackasm1(SB)
+	MOVD $10, R0
+	BR   callbackasm1(SB)
+	MOVD $11, R0
+	BR   callbackasm1(SB)
+	MOVD $12, R0
+	BR   callbackasm1(SB)
+	MOVD $13, R0
+	BR   callbackasm1(SB)
+	MOVD $14, R0
+	BR   callbackasm1(SB)
+	MOVD $15, R0
+	BR   callbackasm1(SB)
+	MOVD $16, R0
+	BR   callbackasm1(SB)
+	MOVD $17, R0
+	BR   callbackasm1(SB)
+	MOVD $18, R0
+	BR   callbackasm1(SB)
+	MOVD $19, R0
+	BR   callbackasm1(SB)
+	MOVD $20, R0
+	BR   callbackasm1(SB)
+	MOVD $21, R0
+	BR   callbackasm1(SB)
+	MOVD $22, R0
+	BR   callbackasm1(SB)
+	MOVD $23, R0
+	BR   callbackasm1(SB)
+	MOVD $24, R0
+	BR   callbackasm1(SB)
+	MOVD $25, R0
+	BR   callbackasm1(SB)
+	MOVD $26, R0
+	BR   callbackasm1(SB)
+	MOVD $27, R0
+	BR   callbackasm1(SB)
+	MOVD $28, R0
+	BR   callbackasm1(SB)
+	MOVD $29, R0
+	BR   callbackasm1(SB)
+	MOVD $30, R0
+	BR   callbackasm1(SB)
+	MOVD $31, R0
+	BR   callbackasm1(SB)
+	MOVD $32, R0
+	BR   callbackasm1(SB)
+	MOVD $33, R0
+	BR   callbackasm1(SB)
+	MOVD $34, R0
+	BR   callbackasm1(SB)
+	MOVD $35, R0
+	BR   callbackasm1(SB)
+	MOVD $36, R0
+	BR   callbackasm1(SB)
+	MOVD $37, R0
+	BR   callbackasm1(SB)
+	MOVD $38, R0
+	BR   callbackasm1(SB)
+	MOVD $39, R0
+	BR   callbackasm1(SB)
+	MOVD $40, R0
+	BR   callbackasm1(SB)
+	MOVD $41, R0
+	BR   callbackasm1(SB)
+	MOVD $42, R0
+	BR   callbackasm1(SB)
+	MOVD $43, R0
+	BR   callbackasm1(SB)
+	MOVD $44, R0
+	BR   callbackasm1(SB)
+	MOVD $45, R0
+	BR   callbackasm1(SB)
+	MOVD $46, R0
+	BR   callbackasm1(SB)
+	MOVD $47, R0
+	BR   callbackasm1(SB)
+	MOVD $48, R0
+	BR   callbackasm1(SB)
+	MOVD $49, R0
+	BR   callbackasm1(SB)
+	MOVD $50, R0
+	BR   callbackasm1(SB)
+	MOVD $51, R0
+	BR   callbackasm1(SB)
+	MOVD $52, R0
+	BR   callbackasm1(SB)
+	MOVD $53, R0
+	BR   callbackasm1(SB)
+	MOVD $54, R0
+	BR   callbackasm1(SB)
+	MOVD $55, R0
+	BR   callbackasm1(SB)
+	MOVD $56, R0
+	BR   callbackasm1(SB)
+	MOVD $57, R0
+	BR   callbackasm1(SB)
+	MOVD $58, R0
+	BR   callbackasm1(SB)
+	MOVD $59, R0
+	BR   callbackasm1(SB)
+	MOVD $60, R0
+	BR   callbackasm1(SB)
+	MOVD $61, R0
+	BR   callbackasm1(SB)
+	MOVD $62, R0
+	BR   callbackasm1(SB)
+	MOVD $63, R0
+	BR   callbackasm1(SB)
+	MOVD $64, R0
+	BR   callbackasm1(SB)
+	MOVD $65, R0
+	BR   callbackasm1(SB)
+	MOVD $66, R0
+	BR   callbackasm1(SB)
+	MOVD $67, R0
+	BR   callbackasm1(SB)
+	MOVD $68, R0
+	BR   callbackasm1(SB)
+	MOVD $69, R0
+	BR   callbackasm1(SB)
+	MOVD $70, R0
+	BR   callbackasm1(SB)
+	MOVD $71, R0
+	BR   callbackasm1(SB)
+	MOVD $72, R0
+	BR   callbackasm1(SB)
+	MOVD $73, R0
+	BR   callbackasm1(SB)
+	MOVD $74, R0
+	BR   callbackasm1(SB)
+	MOVD $75, R0
+	BR   callbackasm1(SB)
+	MOVD $76, R0
+	BR   callbackasm1(SB)
+	MOVD $77, R0
+	BR   callbackasm1(SB)
+	MOVD $78, R0
+	BR   callbackasm1(SB)
+	MOVD $79, R0
+	BR   callbackasm1(SB)
+	MOVD $80, R0
+	BR   callbackasm1(SB)
+	MOVD $81, R0
+	BR   callbackasm1(SB)
+	MOVD $82, R0
+	BR   callbackasm1(SB)
+	MOVD $83, R0
+	BR   callbackasm1(SB)
+	MOVD $84, R0
+	BR   callbackasm1(SB)
+	MOVD $85, R0
+	BR   callbackasm1(SB)
+	MOVD $86, R0
+	BR   callbackasm1(SB)
+	MOVD $87, R0
+	BR   callbackasm1(SB)
+	MOVD $88, R0
+	BR   callbackasm1(SB)
+	MOVD $89, R0
+	BR   callbackasm1(SB)
+	MOVD $90, R0
+	BR   callbackasm1(SB)
+	MOVD $91, R0
+	BR   callbackasm1(SB)
+	MOVD $92, R0
+	BR   callbackasm1(SB)
+	MOVD $93, R0
+	BR   callbackasm1(SB)
+	MOVD $94, R0
+	BR   callbackasm1(SB)
+	MOVD $95, R0
+	BR   callbackasm1(SB)
+	MOVD $96, R0
+	BR   callbackasm1(SB)
+	MOVD $97, R0
+	BR   callbackasm1(SB)
+	MOVD $98, R0
+	BR   callbackasm1(SB)
+	MOVD $99, R0
+	BR   callbackasm1(SB)
+	MOVD $100, R0
+	BR   callbackasm1(SB)
+	MOVD $101, R0
+	BR   callbackasm1(SB)
+	MOVD $102, R0
+	BR   callbackasm1(SB)
+	MOVD $103, R0
+	BR   callbackasm1(SB)
+	MOVD $104, R0
+	BR   callbackasm1(SB)
+	MOVD $105, R0
+	BR   callbackasm1(SB)
+	MOVD $106, R0
+	BR   callbackasm1(SB)
+	MOVD $107, R0
+	BR   callbackasm1(SB)
+	MOVD $108, R0
+	BR   callbackasm1(SB)
+	MOVD $109, R0
+	BR   callbackasm1(SB)
+	MOVD $110, R0
+	BR   callbackasm1(SB)
+	MOVD $111, R0
+	BR   callbackasm1(SB)
+	MOVD $112, R0
+	BR   callbackasm1(SB)
+	MOVD $113, R0
+	BR   callbackasm1(SB)
+	MOVD $114, R0
+	BR   callbackasm1(SB)
+	MOVD $115, R0
+	BR   callbackasm1(SB)
+	MOVD $116, R0
+	BR   callbackasm1(SB)
+	MOVD $117, R0
+	BR   callbackasm1(SB)
+	MOVD $118, R0
+	BR   callbackasm1(SB)
+	MOVD $119, R0
+	BR   callbackasm1(SB)
+	MOVD $120, R0
+	BR   callbackasm1(SB)
+	MOVD $121, R0
+	BR   callbackasm1(SB)
+	MOVD $122, R0
+	BR   callbackasm1(SB)
+	MOVD $123, R0
+	BR   callbackasm1(SB)
+	MOVD $124, R0
+	BR   callbackasm1(SB)
+	MOVD $125, R0
+	BR   callbackasm1(SB)
+	MOVD $126, R0
+	BR   callbackasm1(SB)
+	MOVD $127, R0
+	BR   callbackasm1(SB)
+	MOVD $128, R0
+	BR   callbackasm1(SB)
+	MOVD $129, R0
+	BR   callbackasm1(SB)
+	MOVD $130, R0
+	BR   callbackasm1(SB)
+	MOVD $131, R0
+	BR   callbackasm1(SB)
+	MOVD $132, R0
+	BR   callbackasm1(SB)
+	MOVD $133, R0
+	BR   callbackasm1(SB)
+	MOVD $134, R0
+	BR   callbackasm1(SB)
+	MOVD $135, R0
+	BR   callbackasm1(SB)
+	MOVD $136, R0
+	BR   callbackasm1(SB)
+	MOVD $137, R0
+	BR   callbackasm1(SB)
+	MOVD $138, R0
+	BR   callbackasm1(SB)
+	MOVD $139, R0
+	BR   callbackasm1(SB)
+	MOVD $140, R0
+	BR   callbackasm1(SB)
+	MOVD $141, R0
+	BR   callbackasm1(SB)
+	MOVD $142, R0
+	BR   callbackasm1(SB)
+	MOVD $143, R0
+	BR   callbackasm1(SB)
+	MOVD $144, R0
+	BR   callbackasm1(SB)
+	MOVD $145, R0
+	BR   callbackasm1(SB)
+	MOVD $146, R0
+	BR   callbackasm1(SB)
+	MOVD $147, R0
+	BR   callbackasm1(SB)
+	MOVD $148, R0
+	BR   callbackasm1(SB)
+	MOVD $149, R0
+	BR   callbackasm1(SB)
+	MOVD $150, R0
+	BR   callbackasm1(SB)
+	MOVD $151, R0
+	BR   callbackasm1(SB)
+	MOVD $152, R0
+	BR   callbackasm1(SB)
+	MOVD $153, R0
+	BR   callbackasm1(SB)
+	MOVD $154, R0
+	BR   callbackasm1(SB)
+	MOVD $155, R0
+	BR   callbackasm1(SB)
+	MOVD $156, R0
+	BR   callbackasm1(SB)
+	MOVD $157, R0
+	BR   callbackasm1(SB)
+	MOVD $158, R0
+	BR   callbackasm1(SB)
+	MOVD $159, R0
+	BR   callbackasm1(SB)
+	MOVD $160, R0
+	BR   callbackasm1(SB)
+	MOVD $161, R0
+	BR   callbackasm1(SB)
+	MOVD $162, R0
+	BR   callbackasm1(SB)
+	MOVD $163, R0
+	BR   callbackasm1(SB)
+	MOVD $164, R0
+	BR   callbackasm1(SB)
+	MOVD $165, R0
+	BR   callbackasm1(SB)
+	MOVD $166, R0
+	BR   callbackasm1(SB)
+	MOVD $167, R0
+	BR   callbackasm1(SB)
+	MOVD $168, R0
+	BR   callbackasm1(SB)
+	MOVD $169, R0
+	BR   callbackasm1(SB)
+	MOVD $170, R0
+	BR   callbackasm1(SB)
+	MOVD $171, R0
+	BR   callbackasm1(SB)
+	MOVD $172, R0
+	BR   callbackasm1(SB)
+	MOVD $173, R0
+	BR   callbackasm1(SB)
+	MOVD $174, R0
+	BR   callbackasm1(SB)
+	MOVD $175, R0
+	BR   callbackasm1(SB)
+	MOVD $176, R0
+	BR   callbackasm1(SB)
+	MOVD $177, R0
+	BR   callbackasm1(SB)
+	MOVD $178, R0
+	BR   callbackasm1(SB)
+	MOVD $179, R0
+	BR   callbackasm1(SB)
+	MOVD $180, R0
+	BR   callbackasm1(SB)
+	MOVD $181, R0
+	BR   callbackasm1(SB)
+	MOVD $182, R0
+	BR   callbackasm1(SB)
+	MOVD $183, R0
+	BR   callbackasm1(SB)
+	MOVD $184, R0
+	BR   callbackasm1(SB)
+	MOVD $185, R0
+	BR   callbackasm1(SB)
+	MOVD $186, R0
+	BR   callbackasm1(SB)
+	MOVD $187, R0
+	BR   callbackasm1(SB)
+	MOVD $188, R0
+	BR   callbackasm1(SB)
+	MOVD $189, R0
+	BR   callbackasm1(SB)
+	MOVD $190, R0
+	BR   callbackasm1(SB)
+	MOVD $191, R0
+	BR   callbackasm1(SB)
+	MOVD $192, R0
+	BR   callbackasm1(SB)
+	MOVD $193, R0
+	BR   callbackasm1(SB)
+	MOVD $194, R0
+	BR   callbackasm1(SB)
+	MOVD $195, R0
+	BR   callbackasm1(SB)
+	MOVD $196, R0
+	BR   callbackasm1(SB)
+	MOVD $197, R0
+	BR   callbackasm1(SB)
+	MOVD $198, R0
+	BR   callbackasm1(SB)
+	MOVD $199, R0
+	BR   callbackasm1(SB)
+	MOVD $200, R0
+	BR   callbackasm1(SB)
+	MOVD $201, R0
+	BR   callbackasm1(SB)
+	MOVD $202, R0
+	BR   callbackasm1(SB)
+	MOVD $203, R0
+	BR   callbackasm1(SB)
+	MOVD $204, R0
+	BR   callbackasm1(SB)
+	MOVD $205, R0
+	BR   callbackasm1(SB)
+	MOVD $206, R0
+	BR   callbackasm1(SB)
+	MOVD $207, R0
+	BR   callbackasm1(SB)
+	MOVD $208, R0
+	BR   callbackasm1(SB)
+	MOVD $209, R0
+	BR   callbackasm1(SB)
+	MOVD $210, R0
+	BR   callbackasm1(SB)
+	MOVD $211, R0
+	BR   callbackasm1(SB)
+	MOVD $212, R0
+	BR   callbackasm1(SB)
+	MOVD $213, R0
+	BR   callbackasm1(SB)
+	MOVD $214, R0
+	BR   callbackasm1(SB)
+	MOVD $215, R0
+	BR   callbackasm1(SB)
+	MOVD $216, R0
+	BR   callbackasm1(SB)
+	MOVD $217, R0
+	BR   callbackasm1(SB)
+	MOVD $218, R0
+	BR   callbackasm1(SB)
+	MOVD $219, R0
+	BR   callbackasm1(SB)
+	MOVD $220, R0
+	BR   callbackasm1(SB)
+	MOVD $221, R0
+	BR   callbackasm1(SB)
+	MOVD $222, R0
+	BR   callbackasm1(SB)
+	MOVD $223, R0
+	BR   callbackasm1(SB)
+	MOVD $224, R0
+	BR   callbackasm1(SB)
+	MOVD $225, R0
+	BR   callbackasm1(SB)
+	MOVD $226, R0
+	BR   callbackasm1(SB)
+	MOVD $227, R0
+	BR   callbackasm1(SB)
+	MOVD $228, R0
+	BR   callbackasm1(SB)
+	MOVD $229, R0
+	BR   callbackasm1(SB)
+	MOVD $230, R0
+	BR   callbackasm1(SB)
+	MOVD $231, R0
+	BR   callbackasm1(SB)
+	MOVD $232, R0
+	BR   callbackasm1(SB)
+	MOVD $233, R0
+	BR   callbackasm1(SB)
+	MOVD $234, R0
+	BR   callbackasm1(SB)
+	MOVD $235, R0
+	BR   callbackasm1(SB)
+	MOVD $236, R0
+	BR   callbackasm1(SB)
+	MOVD $237, R0
+	BR   callbackasm1(SB)
+	MOVD $238, R0
+	BR   callbackasm1(SB)
+	MOVD $239, R0
+	BR   callbackasm1(SB)
+	MOVD $240, R0
+	BR   callbackasm1(SB)
+	MOVD $241, R0
+	BR   callbackasm1(SB)
+	MOVD $242, R0
+	BR   callbackasm1(SB)
+	MOVD $243, R0
+	BR   callbackasm1(SB)
+	MOVD $244, R0
+	BR   callbackasm1(SB)
+	MOVD $245, R0
+	BR   callbackasm1(SB)
+	MOVD $246, R0
+	BR   callbackasm1(SB)
+	MOVD $247, R0
+	BR   callbackasm1(SB)
+	MOVD $248, R0
+	BR   callbackasm1(SB)
+	MOVD $249, R0
+	BR   callbackasm1(SB)
+	MOVD $250, R0
+	BR   callbackasm1(SB)
+	MOVD $251, R0
+	BR   callbackasm1(SB)
+	MOVD $252, R0
+	BR   callbackasm1(SB)
+	MOVD $253, R0
+	BR   callbackasm1(SB)
+	MOVD $254, R0
+	BR   callbackasm1(SB)
+	MOVD $255, R0
+	BR   callbackasm1(SB)
+	MOVD $256, R0
+	BR   callbackasm1(SB)
+	MOVD $257, R0
+	BR   callbackasm1(SB)
+	MOVD $258, R0
+	BR   callbackasm1(SB)
+	MOVD $259, R0
+	BR   callbackasm1(SB)
+	MOVD $260, R0
+	BR   callbackasm1(SB)
+	MOVD $261, R0
+	BR   callbackasm1(SB)
+	MOVD $262, R0
+	BR   callbackasm1(SB)
+	MOVD $263, R0
+	BR   callbackasm1(SB)
+	MOVD $264, R0
+	BR   callbackasm1(SB)
+	MOVD $265, R0
+	BR   callbackasm1(SB)
+	MOVD $266, R0
+	BR   callbackasm1(SB)
+	MOVD $267, R0
+	BR   callbackasm1(SB)
+	MOVD $268, R0
+	BR   callbackasm1(SB)
+	MOVD $269, R0
+	BR   callbackasm1(SB)
+	MOVD $270, R0
+	BR   callbackasm1(SB)
+	MOVD $271, R0
+	BR   callbackasm1(SB)
+	MOVD $272, R0
+	BR   callbackasm1(SB)
+	MOVD $273, R0
+	BR   callbackasm1(SB)
+	MOVD $274, R0
+	BR   callbackasm1(SB)
+	MOVD $275, R0
+	BR   callbackasm1(SB)
+	MOVD $276, R0
+	BR   callbackasm1(SB)
+	MOVD $277, R0
+	BR   callbackasm1(SB)
+	MOVD $278, R0
+	BR   callbackasm1(SB)
+	MOVD $279, R0
+	BR   callbackasm1(SB)
+	MOVD $280, R0
+	BR   callbackasm1(SB)
+	MOVD $281, R0
+	BR   callbackasm1(SB)
+	MOVD $282, R0
+	BR   callbackasm1(SB)
+	MOVD $283, R0
+	BR   callbackasm1(SB)
+	MOVD $284, R0
+	BR   callbackasm1(SB)
+	MOVD $285, R0
+	BR   callbackasm1(SB)
+	MOVD $286, R0
+	BR   callbackasm1(SB)
+	MOVD $287, R0
+	BR   callbackasm1(SB)
+	MOVD $288, R0
+	BR   callbackasm1(SB)
+	MOVD $289, R0
+	BR   callbackasm1(SB)
+	MOVD $290, R0
+	BR   callbackasm1(SB)
+	MOVD $291, R0
+	BR   callbackasm1(SB)
+	MOVD $292, R0
+	BR   callbackasm1(SB)
+	MOVD $293, R0
+	BR   callbackasm1(SB)
+	MOVD $294, R0
+	BR   callbackasm1(SB)
+	MOVD $295, R0
+	BR   callbackasm1(SB)
+	MOVD $296, R0
+	BR   callbackasm1(SB)
+	MOVD $297, R0
+	BR   callbackasm1(SB)
+	MOVD $298, R0
+	BR   callbackasm1(SB)
+	MOVD $299, R0
+	BR   callbackasm1(SB)
+	MOVD $300, R0
+	BR   callbackasm1(SB)
+	MOVD $301, R0
+	BR   callbackasm1(SB)
+	MOVD $302, R0
+	BR   callbackasm1(SB)
+	MOVD $303, R0
+	BR   callbackasm1(SB)
+	MOVD $304, R0
+	BR   callbackasm1(SB)
+	MOVD $305, R0
+	BR   callbackasm1(SB)
+	MOVD $306, R0
+	BR   callbackasm1(SB)
+	MOVD $307, R0
+	BR   callbackasm1(SB)
+	MOVD $308, R0
+	BR   callbackasm1(SB)
+	MOVD $309, R0
+	BR   callbackasm1(SB)
+	MOVD $310, R0
+	BR   callbackasm1(SB)
+	MOVD $311, R0
+	BR   callbackasm1(SB)
+	MOVD $312, R0
+	BR   callbackasm1(SB)
+	MOVD $313, R0
+	BR   callbackasm1(SB)
+	MOVD $314, R0
+	BR   callbackasm1(SB)
+	MOVD $315, R0
+	BR   callbackasm1(SB)
+	MOVD $316, R0
+	BR   callbackasm1(SB)
+	MOVD $317, R0
+	BR   callbackasm1(SB)
+	MOVD $318, R0
+	BR   callbackasm1(SB)
+	MOVD $319, R0
+	BR   callbackasm1(SB)
+	MOVD $320, R0
+	BR   callbackasm1(SB)
+	MOVD $321, R0
+	BR   callbackasm1(SB)
+	MOVD $322, R0
+	BR   callbackasm1(SB)
+	MOVD $323, R0
+	BR   callbackasm1(SB)
+	MOVD $324, R0
+	BR   callbackasm1(SB)
+	MOVD $325, R0
+	BR   callbackasm1(SB)
+	MOVD $326, R0
+	BR   callbackasm1(SB)
+	MOVD $327, R0
+	BR   callbackasm1(SB)
+	MOVD $328, R0
+	BR   callbackasm1(SB)
+	MOVD $329, R0
+	BR   callbackasm1(SB)
+	MOVD $330, R0
+	BR   callbackasm1(SB)
+	MOVD $331, R0
+	BR   callbackasm1(SB)
+	MOVD $332, R0
+	BR   callbackasm1(SB)
+	MOVD $333, R0
+	BR   callbackasm1(SB)
+	MOVD $334, R0
+	BR   callbackasm1(SB)
+	MOVD $335, R0
+	BR   callbackasm1(SB)
+	MOVD $336, R0
+	BR   callbackasm1(SB)
+	MOVD $337, R0
+	BR   callbackasm1(SB)
+	MOVD $338, R0
+	BR   callbackasm1(SB)
+	MOVD $339, R0
+	BR   callbackasm1(SB)
+	MOVD $340, R0
+	BR   callbackasm1(SB)
+	MOVD $341, R0
+	BR   callbackasm1(SB)
+	MOVD $342, R0
+	BR   callbackasm1(SB)
+	MOVD $343, R0
+	BR   callbackasm1(SB)
+	MOVD $344, R0
+	BR   callbackasm1(SB)
+	MOVD $345, R0
+	BR   callbackasm1(SB)
+	MOVD $346, R0
+	BR   callbackasm1(SB)
+	MOVD $347, R0
+	BR   callbackasm1(SB)
+	MOVD $348, R0
+	BR   callbackasm1(SB)
+	MOVD $349, R0
+	BR   callbackasm1(SB)
+	MOVD $350, R0
+	BR   callbackasm1(SB)
+	MOVD $351, R0
+	BR   callbackasm1(SB)
+	MOVD $352, R0
+	BR   callbackasm1(SB)
+	MOVD $353, R0
+	BR   callbackasm1(SB)
+	MOVD $354, R0
+	BR   callbackasm1(SB)
+	MOVD $355, R0
+	BR   callbackasm1(SB)
+	MOVD $356, R0
+	BR   callbackasm1(SB)
+	MOVD $357, R0
+	BR   callbackasm1(SB)
+	MOVD $358, R0
+	BR   callbackasm1(SB)
+	MOVD $359, R0
+	BR   callbackasm1(SB)
+	MOVD $360, R0
+	BR   callbackasm1(SB)
+	MOVD $361, R0
+	BR   callbackasm1(SB)
+	MOVD $362, R0
+	BR   callbackasm1(SB)
+	MOVD $363, R0
+	BR   callbackasm1(SB)
+	MOVD $364, R0
+	BR   callbackasm1(SB)
+	MOVD $365, R0
+	BR   callbackasm1(SB)
+	MOVD $366, R0
+	BR   callbackasm1(SB)
+	MOVD $367, R0
+	BR   callbackasm1(SB)
+	MOVD $368, R0
+	BR   callbackasm1(SB)
+	MOVD $369, R0
+	BR   callbackasm1(SB)
+	MOVD $370, R0
+	BR   callbackasm1(SB)
+	MOVD $371, R0
+	BR   callbackasm1(SB)
+	MOVD $372, R0
+	BR   callbackasm1(SB)
+	MOVD $373, R0
+	BR   callbackasm1(SB)
+	MOVD $374, R0
+	BR   callbackasm1(SB)
+	MOVD $375, R0
+	BR   callbackasm1(SB)
+	MOVD $376, R0
+	BR   callbackasm1(SB)
+	MOVD $377, R0
+	BR   callbackasm1(SB)
+	MOVD $378, R0
+	BR   callbackasm1(SB)
+	MOVD $379, R0
+	BR   callbackasm1(SB)
+	MOVD $380, R0
+	BR   callbackasm1(SB)
+	MOVD $381, R0
+	BR   callbackasm1(SB)
+	MOVD $382, R0
+	BR   callbackasm1(SB)
+	MOVD $383, R0
+	BR   callbackasm1(SB)
+	MOVD $384, R0
+	BR   callbackasm1(SB)
+	MOVD $385, R0
+	BR   callbackasm1(SB)
+	MOVD $386, R0
+	BR   callbackasm1(SB)
+	MOVD $387, R0
+	BR   callbackasm1(SB)
+	MOVD $388, R0
+	BR   callbackasm1(SB)
+	MOVD $389, R0
+	BR   callbackasm1(SB)
+	MOVD $390, R0
+	BR   callbackasm1(SB)
+	MOVD $391, R0
+	BR   callbackasm1(SB)
+	MOVD $392, R0
+	BR   callbackasm1(SB)
+	MOVD $393, R0
+	BR   callbackasm1(SB)
+	MOVD $394, R0
+	BR   callbackasm1(SB)
+	MOVD $395, R0
+	BR   callbackasm1(SB)
+	MOVD $396, R0
+	BR   callbackasm1(SB)
+	MOVD $397, R0
+	BR   callbackasm1(SB)
+	MOVD $398, R0
+	BR   callbackasm1(SB)
+	MOVD $399, R0
+	BR   callbackasm1(SB)
+	MOVD $400, R0
+	BR   callbackasm1(SB)
+	MOVD $401, R0
+	BR   callbackasm1(SB)
+	MOVD $402, R0
+	BR   callbackasm1(SB)
+	MOVD $403, R0
+	BR   callbackasm1(SB)
+	MOVD $404, R0
+	BR   callbackasm1(SB)
+	MOVD $405, R0
+	BR   callbackasm1(SB)
+	MOVD $406, R0
+	BR   callbackasm1(SB)
+	MOVD $407, R0
+	BR   callbackasm1(SB)
+	MOVD $408, R0
+	BR   callbackasm1(SB)
+	MOVD $409, R0
+	BR   callbackasm1(SB)
+	MOVD $410, R0
+	BR   callbackasm1(SB)
+	MOVD $411, R0
+	BR   callbackasm1(SB)
+	MOVD $412, R0
+	BR   callbackasm1(SB)
+	MOVD $413, R0
+	BR   callbackasm1(SB)
+	MOVD $414, R0
+	BR   callbackasm1(SB)
+	MOVD $415, R0
+	BR   callbackasm1(SB)
+	MOVD $416, R0
+	BR   callbackasm1(SB)
+	MOVD $417, R0
+	BR   callbackasm1(SB)
+	MOVD $418, R0
+	BR   callbackasm1(SB)
+	MOVD $419, R0
+	BR   callbackasm1(SB)
+	MOVD $420, R0
+	BR   callbackasm1(SB)
+	MOVD $421, R0
+	BR   callbackasm1(SB)
+	MOVD $422, R0
+	BR   callbackasm1(SB)
+	MOVD $423, R0
+	BR   callbackasm1(SB)
+	MOVD $424, R0
+	BR   callbackasm1(SB)
+	MOVD $425, R0
+	BR   callbackasm1(SB)
+	MOVD $426, R0
+	BR   callbackasm1(SB)
+	MOVD $427, R0
+	BR   callbackasm1(SB)
+	MOVD $428, R0
+	BR   callbackasm1(SB)
+	MOVD $429, R0
+	BR   callbackasm1(SB)
+	MOVD $430, R0
+	BR   callbackasm1(SB)
+	MOVD $431, R0
+	BR   callbackasm1(SB)
+	MOVD $432, R0
+	BR   callbackasm1(SB)
+	MOVD $433, R0
+	BR   callbackasm1(SB)
+	MOVD $434, R0
+	BR   callbackasm1(SB)
+	MOVD $435, R0
+	BR   callbackasm1(SB)
+	MOVD $436, R0
+	BR   callbackasm1(SB)
+	MOVD $437, R0
+	BR   callbackasm1(SB)
+	MOVD $438, R0
+	BR   callbackasm1(SB)
+	MOVD $439, R0
+	BR   callbackasm1(SB)
+	MOVD $440, R0
+	BR   callbackasm1(SB)
+	MOVD $441, R0
+	BR   callbackasm1(SB)
+	MOVD $442, R0
+	BR   callbackasm1(SB)
+	MOVD $443, R0
+	BR   callbackasm1(SB)
+	MOVD $444, R0
+	BR   callbackasm1(SB)
+	MOVD $445, R0
+	BR   callbackasm1(SB)
+	MOVD $446, R0
+	BR   callbackasm1(SB)
+	MOVD $447, R0
+	BR   callbackasm1(SB)
+	MOVD $448, R0
+	BR   callbackasm1(SB)
+	MOVD $449, R0
+	BR   callbackasm1(SB)
+	MOVD $450, R0
+	BR   callbackasm1(SB)
+	MOVD $451, R0
+	BR   callbackasm1(SB)
+	MOVD $452, R0
+	BR   callbackasm1(SB)
+	MOVD $453, R0
+	BR   callbackasm1(SB)
+	MOVD $454, R0
+	BR   callbackasm1(SB)
+	MOVD $455, R0
+	BR   callbackasm1(SB)
+	MOVD $456, R0
+	BR   callbackasm1(SB)
+	MOVD $457, R0
+	BR   callbackasm1(SB)
+	MOVD $458, R0
+	BR   callbackasm1(SB)
+	MOVD $459, R0
+	BR   callbackasm1(SB)
+	MOVD $460, R0
+	BR   callbackasm1(SB)
+	MOVD $461, R0
+	BR   callbackasm1(SB)
+	MOVD $462, R0
+	BR   callbackasm1(SB)
+	MOVD $463, R0
+	BR   callbackasm1(SB)
+	MOVD $464, R0
+	BR   callbackasm1(SB)
+	MOVD $465, R0
+	BR   callbackasm1(SB)
+	MOVD $466, R0
+	BR   callbackasm1(SB)
+	MOVD $467, R0
+	BR   callbackasm1(SB)
+	MOVD $468, R0
+	BR   callbackasm1(SB)
+	MOVD $469, R0
+	BR   callbackasm1(SB)
+	MOVD $470, R0
+	BR   callbackasm1(SB)
+	MOVD $471, R0
+	BR   callbackasm1(SB)
+	MOVD $472, R0
+	BR   callbackasm1(SB)
+	MOVD $473, R0
+	BR   callbackasm1(SB)
+	MOVD $474, R0
+	BR   callbackasm1(SB)
+	MOVD $475, R0
+	BR   callbackasm1(SB)
+	MOVD $476, R0
+	BR   callbackasm1(SB)
+	MOVD $477, R0
+	BR   callbackasm1(SB)
+	MOVD $478, R0
+	BR   callbackasm1(SB)
+	MOVD $479, R0
+	BR   callbackasm1(SB)
+	MOVD $480, R0
+	BR   callbackasm1(SB)
+	MOVD $481, R0
+	BR   callbackasm1(SB)
+	MOVD $482, R0
+	BR   callbackasm1(SB)
+	MOVD $483, R0
+	BR   callbackasm1(SB)
+	MOVD $484, R0
+	BR   callbackasm1(SB)
+	MOVD $485, R0
+	BR   callbackasm1(SB)
+	MOVD $486, R0
+	BR   callbackasm1(SB)
+	MOVD $487, R0
+	BR   callbackasm1(SB)
+	MOVD $488, R0
+	BR   callbackasm1(SB)
+	MOVD $489, R0
+	BR   callbackasm1(SB)
+	MOVD $490, R0
+	BR   callbackasm1(SB)
+	MOVD $491, R0
+	BR   callbackasm1(SB)
+	MOVD $492, R0
+	BR   callbackasm1(SB)
+	MOVD $493, R0
+	BR   callbackasm1(SB)
+	MOVD $494, R0
+	BR   callbackasm1(SB)
+	MOVD $495, R0
+	BR   callbackasm1(SB)
+	MOVD $496, R0
+	BR   callbackasm1(SB)
+	MOVD $497, R0
+	BR   callbackasm1(SB)
+	MOVD $498, R0
+	BR   callbackasm1(SB)
+	MOVD $499, R0
+	BR   callbackasm1(SB)
+	MOVD $500, R0
+	BR   callbackasm1(SB)
+	MOVD $501, R0
+	BR   callbackasm1(SB)
+	MOVD $502, R0
+	BR   callbackasm1(SB)
+	MOVD $503, R0
+	BR   callbackasm1(SB)
+	MOVD $504, R0
+	BR   callbackasm1(SB)
+	MOVD $505, R0
+	BR   callbackasm1(SB)
+	MOVD $506, R0
+	BR   callbackasm1(SB)
+	MOVD $507, R0
+	BR   callbackasm1(SB)
+	MOVD $508, R0
+	BR   callbackasm1(SB)
+	MOVD $509, R0
+	BR   callbackasm1(SB)
+	MOVD $510, R0
+	BR   callbackasm1(SB)
+	MOVD $511, R0
+	BR   callbackasm1(SB)
+	MOVD $512, R0
+	BR   callbackasm1(SB)
+	MOVD $513, R0
+	BR   callbackasm1(SB)
+	MOVD $514, R0
+	BR   callbackasm1(SB)
+	MOVD $515, R0
+	BR   callbackasm1(SB)
+	MOVD $516, R0
+	BR   callbackasm1(SB)
+	MOVD $517, R0
+	BR   callbackasm1(SB)
+	MOVD $518, R0
+	BR   callbackasm1(SB)
+	MOVD $519, R0
+	BR   callbackasm1(SB)
+	MOVD $520, R0
+	BR   callbackasm1(SB)
+	MOVD $521, R0
+	BR   callbackasm1(SB)
+	MOVD $522, R0
+	BR   callbackasm1(SB)
+	MOVD $523, R0
+	BR   callbackasm1(SB)
+	MOVD $524, R0
+	BR   callbackasm1(SB)
+	MOVD $525, R0
+	BR   callbackasm1(SB)
+	MOVD $526, R0
+	BR   callbackasm1(SB)
+	MOVD $527, R0
+	BR   callbackasm1(SB)
+	MOVD $528, R0
+	BR   callbackasm1(SB)
+	MOVD $529, R0
+	BR   callbackasm1(SB)
+	MOVD $530, R0
+	BR   callbackasm1(SB)
+	MOVD $531, R0
+	BR   callbackasm1(SB)
+	MOVD $532, R0
+	BR   callbackasm1(SB)
+	MOVD $533, R0
+	BR   callbackasm1(SB)
+	MOVD $534, R0
+	BR   callbackasm1(SB)
+	MOVD $535, R0
+	BR   callbackasm1(SB)
+	MOVD $536, R0
+	BR   callbackasm1(SB)
+	MOVD $537, R0
+	BR   callbackasm1(SB)
+	MOVD $538, R0
+	BR   callbackasm1(SB)
+	MOVD $539, R0
+	BR   callbackasm1(SB)
+	MOVD $540, R0
+	BR   callbackasm1(SB)
+	MOVD $541, R0
+	BR   callbackasm1(SB)
+	MOVD $542, R0
+	BR   callbackasm1(SB)
+	MOVD $543, R0
+	BR   callbackasm1(SB)
+	MOVD $544, R0
+	BR   callbackasm1(SB)
+	MOVD $545, R0
+	BR   callbackasm1(SB)
+	MOVD $546, R0
+	BR   callbackasm1(SB)
+	MOVD $547, R0
+	BR   callbackasm1(SB)
+	MOVD $548, R0
+	BR   callbackasm1(SB)
+	MOVD $549, R0
+	BR   callbackasm1(SB)
+	MOVD $550, R0
+	BR   callbackasm1(SB)
+	MOVD $551, R0
+	BR   callbackasm1(SB)
+	MOVD $552, R0
+	BR   callbackasm1(SB)
+	MOVD $553, R0
+	BR   callbackasm1(SB)
+	MOVD $554, R0
+	BR   callbackasm1(SB)
+	MOVD $555, R0
+	BR   callbackasm1(SB)
+	MOVD $556, R0
+	BR   callbackasm1(SB)
+	MOVD $557, R0
+	BR   callbackasm1(SB)
+	MOVD $558, R0
+	BR   callbackasm1(SB)
+	MOVD $559, R0
+	BR   callbackasm1(SB)
+	MOVD $560, R0
+	BR   callbackasm1(SB)
+	MOVD $561, R0
+	BR   callbackasm1(SB)
+	MOVD $562, R0
+	BR   callbackasm1(SB)
+	MOVD $563, R0
+	BR   callbackasm1(SB)
+	MOVD $564, R0
+	BR   callbackasm1(SB)
+	MOVD $565, R0
+	BR   callbackasm1(SB)
+	MOVD $566, R0
+	BR   callbackasm1(SB)
+	MOVD $567, R0
+	BR   callbackasm1(SB)
+	MOVD $568, R0
+	BR   callbackasm1(SB)
+	MOVD $569, R0
+	BR   callbackasm1(SB)
+	MOVD $570, R0
+	BR   callbackasm1(SB)
+	MOVD $571, R0
+	BR   callbackasm1(SB)
+	MOVD $572, R0
+	BR   callbackasm1(SB)
+	MOVD $573, R0
+	BR   callbackasm1(SB)
+	MOVD $574, R0
+	BR   callbackasm1(SB)
+	MOVD $575, R0
+	BR   callbackasm1(SB)
+	MOVD $576, R0
+	BR   callbackasm1(SB)
+	MOVD $577, R0
+	BR   callbackasm1(SB)
+	MOVD $578, R0
+	BR   callbackasm1(SB)
+	MOVD $579, R0
+	BR   callbackasm1(SB)
+	MOVD $580, R0
+	BR   callbackasm1(SB)
+	MOVD $581, R0
+	BR   callbackasm1(SB)
+	MOVD $582, R0
+	BR   callbackasm1(SB)
+	MOVD $583, R0
+	BR   callbackasm1(SB)
+	MOVD $584, R0
+	BR   callbackasm1(SB)
+	MOVD $585, R0
+	BR   callbackasm1(SB)
+	MOVD $586, R0
+	BR   callbackasm1(SB)
+	MOVD $587, R0
+	BR   callbackasm1(SB)
+	MOVD $588, R0
+	BR   callbackasm1(SB)
+	MOVD $589, R0
+	BR   callbackasm1(SB)
+	MOVD $590, R0
+	BR   callbackasm1(SB)
+	MOVD $591, R0
+	BR   callbackasm1(SB)
+	MOVD $592, R0
+	BR   callbackasm1(SB)
+	MOVD $593, R0
+	BR   callbackasm1(SB)
+	MOVD $594, R0
+	BR   callbackasm1(SB)
+	MOVD $595, R0
+	BR   callbackasm1(SB)
+	MOVD $596, R0
+	BR   callbackasm1(SB)
+	MOVD $597, R0
+	BR   callbackasm1(SB)
+	MOVD $598, R0
+	BR   callbackasm1(SB)
+	MOVD $599, R0
+	BR   callbackasm1(SB)
+	MOVD $600, R0
+	BR   callbackasm1(SB)
+	MOVD $601, R0
+	BR   callbackasm1(SB)
+	MOVD $602, R0
+	BR   callbackasm1(SB)
+	MOVD $603, R0
+	BR   callbackasm1(SB)
+	MOVD $604, R0
+	BR   callbackasm1(SB)
+	MOVD $605, R0
+	BR   callbackasm1(SB)
+	MOVD $606, R0
+	BR   callbackasm1(SB)
+	MOVD $607, R0
+	BR   callbackasm1(SB)
+	MOVD $608, R0
+	BR   callbackasm1(SB)
+	MOVD $609, R0
+	BR   callbackasm1(SB)
+	MOVD $610, R0
+	BR   callbackasm1(SB)
+	MOVD $611, R0
+	BR   callbackasm1(SB)
+	MOVD $612, R0
+	BR   callbackasm1(SB)
+	MOVD $613, R0
+	BR   callbackasm1(SB)
+	MOVD $614, R0
+	BR   callbackasm1(SB)
+	MOVD $615, R0
+	BR   callbackasm1(SB)
+	MOVD $616, R0
+	BR   callbackasm1(SB)
+	MOVD $617, R0
+	BR   callbackasm1(SB)
+	MOVD $618, R0
+	BR   callbackasm1(SB)
+	MOVD $619, R0
+	BR   callbackasm1(SB)
+	MOVD $620, R0
+	BR   callbackasm1(SB)
+	MOVD $621, R0
+	BR   callbackasm1(SB)
+	MOVD $622, R0
+	BR   callbackasm1(SB)
+	MOVD $623, R0
+	BR   callbackasm1(SB)
+	MOVD $624, R0
+	BR   callbackasm1(SB)
+	MOVD $625, R0
+	BR   callbackasm1(SB)
+	MOVD $626, R0
+	BR   callbackasm1(SB)
+	MOVD $627, R0
+	BR   callbackasm1(SB)
+	MOVD $628, R0
+	BR   callbackasm1(SB)
+	MOVD $629, R0
+	BR   callbackasm1(SB)
+	MOVD $630, R0
+	BR   callbackasm1(SB)
+	MOVD $631, R0
+	BR   callbackasm1(SB)
+	MOVD $632, R0
+	BR   callbackasm1(SB)
+	MOVD $633, R0
+	BR   callbackasm1(SB)
+	MOVD $634, R0
+	BR   callbackasm1(SB)
+	MOVD $635, R0
+	BR   callbackasm1(SB)
+	MOVD $636, R0
+	BR   callbackasm1(SB)
+	MOVD $637, R0
+	BR   callbackasm1(SB)
+	MOVD $638, R0
+	BR   callbackasm1(SB)
+	MOVD $639, R0
+	BR   callbackasm1(SB)
+	MOVD $640, R0
+	BR   callbackasm1(SB)
+	MOVD $641, R0
+	BR   callbackasm1(SB)
+	MOVD $642, R0
+	BR   callbackasm1(SB)
+	MOVD $643, R0
+	BR   callbackasm1(SB)
+	MOVD $644, R0
+	BR   callbackasm1(SB)
+	MOVD $645, R0
+	BR   callbackasm1(SB)
+	MOVD $646, R0
+	BR   callbackasm1(SB)
+	MOVD $647, R0
+	BR   callbackasm1(SB)
+	MOVD $648, R0
+	BR   callbackasm1(SB)
+	MOVD $649, R0
+	BR   callbackasm1(SB)
+	MOVD $650, R0
+	BR   callbackasm1(SB)
+	MOVD $651, R0
+	BR   callbackasm1(SB)
+	MOVD $652, R0
+	BR   callbackasm1(SB)
+	MOVD $653, R0
+	BR   callbackasm1(SB)
+	MOVD $654, R0
+	BR   callbackasm1(SB)
+	MOVD $655, R0
+	BR   callbackasm1(SB)
+	MOVD $656, R0
+	BR   callbackasm1(SB)
+	MOVD $657, R0
+	BR   callbackasm1(SB)
+	MOVD $658, R0
+	BR   callbackasm1(SB)
+	MOVD $659, R0
+	BR   callbackasm1(SB)
+	MOVD $660, R0
+	BR   callbackasm1(SB)
+	MOVD $661, R0
+	BR   callbackasm1(SB)
+	MOVD $662, R0
+	BR   callbackasm1(SB)
+	MOVD $663, R0
+	BR   callbackasm1(SB)
+	MOVD $664, R0
+	BR   callbackasm1(SB)
+	MOVD $665, R0
+	BR   callbackasm1(SB)
+	MOVD $666, R0
+	BR   callbackasm1(SB)
+	MOVD $667, R0
+	BR   callbackasm1(SB)
+	MOVD $668, R0
+	BR   callbackasm1(SB)
+	MOVD $669, R0
+	BR   callbackasm1(SB)
+	MOVD $670, R0
+	BR   callbackasm1(SB)
+	MOVD $671, R0
+	BR   callbackasm1(SB)
+	MOVD $672, R0
+	BR   callbackasm1(SB)
+	MOVD $673, R0
+	BR   callbackasm1(SB)
+	MOVD $674, R0
+	BR   callbackasm1(SB)
+	MOVD $675, R0
+	BR   callbackasm1(SB)
+	MOVD $676, R0
+	BR   callbackasm1(SB)
+	MOVD $677, R0
+	BR   callbackasm1(SB)
+	MOVD $678, R0
+	BR   callbackasm1(SB)
+	MOVD $679, R0
+	BR   callbackasm1(SB)
+	MOVD $680, R0
+	BR   callbackasm1(SB)
+	MOVD $681, R0
+	BR   callbackasm1(SB)
+	MOVD $682, R0
+	BR   callbackasm1(SB)
+	MOVD $683, R0
+	BR   callbackasm1(SB)
+	MOVD $684, R0
+	BR   callbackasm1(SB)
+	MOVD $685, R0
+	BR   callbackasm1(SB)
+	MOVD $686, R0
+	BR   callbackasm1(SB)
+	MOVD $687, R0
+	BR   callbackasm1(SB)
+	MOVD $688, R0
+	BR   callbackasm1(SB)
+	MOVD $689, R0
+	BR   callbackasm1(SB)
+	MOVD $690, R0
+	BR   callbackasm1(SB)
+	MOVD $691, R0
+	BR   callbackasm1(SB)
+	MOVD $692, R0
+	BR   callbackasm1(SB)
+	MOVD $693, R0
+	BR   callbackasm1(SB)
+	MOVD $694, R0
+	BR   callbackasm1(SB)
+	MOVD $695, R0
+	BR   callbackasm1(SB)
+	MOVD $696, R0
+	BR   callbackasm1(SB)
+	MOVD $697, R0
+	BR   callbackasm1(SB)
+	MOVD $698, R0
+	BR   callbackasm1(SB)
+	MOVD $699, R0
+	BR   callbackasm1(SB)
+	MOVD $700, R0
+	BR   callbackasm1(SB)
+	MOVD $701, R0
+	BR   callbackasm1(SB)
+	MOVD $702, R0
+	BR   callbackasm1(SB)
+	MOVD $703, R0
+	BR   callbackasm1(SB)
+	MOVD $704, R0
+	BR   callbackasm1(SB)
+	MOVD $705, R0
+	BR   callbackasm1(SB)
+	MOVD $706, R0
+	BR   callbackasm1(SB)
+	MOVD $707, R0
+	BR   callbackasm1(SB)
+	MOVD $708, R0
+	BR   callbackasm1(SB)
+	MOVD $709, R0
+	BR   callbackasm1(SB)
+	MOVD $710, R0
+	BR   callbackasm1(SB)
+	MOVD $711, R0
+	BR   callbackasm1(SB)
+	MOVD $712, R0
+	BR   callbackasm1(SB)
+	MOVD $713, R0
+	BR   callbackasm1(SB)
+	MOVD $714, R0
+	BR   callbackasm1(SB)
+	MOVD $715, R0
+	BR   callbackasm1(SB)
+	MOVD $716, R0
+	BR   callbackasm1(SB)
+	MOVD $717, R0
+	BR   callbackasm1(SB)
+	MOVD $718, R0
+	BR   callbackasm1(SB)
+	MOVD $719, R0
+	BR   callbackasm1(SB)
+	MOVD $720, R0
+	BR   callbackasm1(SB)
+	MOVD $721, R0
+	BR   callbackasm1(SB)
+	MOVD $722, R0
+	BR   callbackasm1(SB)
+	MOVD $723, R0
+	BR   callbackasm1(SB)
+	MOVD $724, R0
+	BR   callbackasm1(SB)
+	MOVD $725, R0
+	BR   callbackasm1(SB)
+	MOVD $726, R0
+	BR   callbackasm1(SB)
+	MOVD $727, R0
+	BR   callbackasm1(SB)
+	MOVD $728, R0
+	BR   callbackasm1(SB)
+	MOVD $729, R0
+	BR   callbackasm1(SB)
+	MOVD $730, R0
+	BR   callbackasm1(SB)
+	MOVD $731, R0
+	BR   callbackasm1(SB)
+	MOVD $732, R0
+	BR   callbackasm1(SB)
+	MOVD $733, R0
+	BR   callbackasm1(SB)
+	MOVD $734, R0
+	BR   callbackasm1(SB)
+	MOVD $735, R0
+	BR   callbackasm1(SB)
+	MOVD $736, R0
+	BR   callbackasm1(SB)
+	MOVD $737, R0
+	BR   callbackasm1(SB)
+	MOVD $738, R0
+	BR   callbackasm1(SB)
+	MOVD $739, R0
+	BR   callbackasm1(SB)
+	MOVD $740, R0
+	BR   callbackasm1(SB)
+	MOVD $741, R0
+	BR   callbackasm1(SB)
+	MOVD $742, R0
+	BR   callbackasm1(SB)
+	MOVD $743, R0
+	BR   callbackasm1(SB)
+	MOVD $744, R0
+	BR   callbackasm1(SB)
+	MOVD $745, R0
+	BR   callbackasm1(SB)
+	MOVD $746, R0
+	BR   callbackasm1(SB)
+	MOVD $747, R0
+	BR   callbackasm1(SB)
+	MOVD $748, R0
+	BR   callbackasm1(SB)
+	MOVD $749, R0
+	BR   callbackasm1(SB)
+	MOVD $750, R0
+	BR   callbackasm1(SB)
+	MOVD $751, R0
+	BR   callbackasm1(SB)
+	MOVD $752, R0
+	BR   callbackasm1(SB)
+	MOVD $753, R0
+	BR   callbackasm1(SB)
+	MOVD $754, R0
+	BR   callbackasm1(SB)
+	MOVD $755, R0
+	BR   callbackasm1(SB)
+	MOVD $756, R0
+	BR   callbackasm1(SB)
+	MOVD $757, R0
+	BR   callbackasm1(SB)
+	MOVD $758, R0
+	BR   callbackasm1(SB)
+	MOVD $759, R0
+	BR   callbackasm1(SB)
+	MOVD $760, R0
+	BR   callbackasm1(SB)
+	MOVD $761, R0
+	BR   callbackasm1(SB)
+	MOVD $762, R0
+	BR   callbackasm1(SB)
+	MOVD $763, R0
+	BR   callbackasm1(SB)
+	MOVD $764, R0
+	BR   callbackasm1(SB)
+	MOVD $765, R0
+	BR   callbackasm1(SB)
+	MOVD $766, R0
+	BR   callbackasm1(SB)
+	MOVD $767, R0
+	BR   callbackasm1(SB)
+	MOVD $768, R0
+	BR   callbackasm1(SB)
+	MOVD $769, R0
+	BR   callbackasm1(SB)
+	MOVD $770, R0
+	BR   callbackasm1(SB)
+	MOVD $771, R0
+	BR   callbackasm1(SB)
+	MOVD $772, R0
+	BR   callbackasm1(SB)
+	MOVD $773, R0
+	BR   callbackasm1(SB)
+	MOVD $774, R0
+	BR   callbackasm1(SB)
+	MOVD $775, R0
+	BR   callbackasm1(SB)
+	MOVD $776, R0
+	BR   callbackasm1(SB)
+	MOVD $777, R0
+	BR   callbackasm1(SB)
+	MOVD $778, R0
+	BR   callbackasm1(SB)
+	MOVD $779, R0
+	BR   callbackasm1(SB)
+	MOVD $780, R0
+	BR   callbackasm1(SB)
+	MOVD $781, R0
+	BR   callbackasm1(SB)
+	MOVD $782, R0
+	BR   callbackasm1(SB)
+	MOVD $783, R0
+	BR   callbackasm1(SB)
+	MOVD $784, R0
+	BR   callbackasm1(SB)
+	MOVD $785, R0
+	BR   callbackasm1(SB)
+	MOVD $786, R0
+	BR   callbackasm1(SB)
+	MOVD $787, R0
+	BR   callbackasm1(SB)
+	MOVD $788, R0
+	BR   callbackasm1(SB)
+	MOVD $789, R0
+	BR   callbackasm1(SB)
+	MOVD $790, R0
+	BR   callbackasm1(SB)
+	MOVD $791, R0
+	BR   callbackasm1(SB)
+	MOVD $792, R0
+	BR   callbackasm1(SB)
+	MOVD $793, R0
+	BR   callbackasm1(SB)
+	MOVD $794, R0
+	BR   callbackasm1(SB)
+	MOVD $795, R0
+	BR   callbackasm1(SB)
+	MOVD $796, R0
+	BR   callbackasm1(SB)
+	MOVD $797, R0
+	BR   callbackasm1(SB)
+	MOVD $798, R0
+	BR   callbackasm1(SB)
+	MOVD $799, R0
+	BR   callbackasm1(SB)
+	MOVD $800, R0
+	BR   callbackasm1(SB)
+	MOVD $801, R0
+	BR   callbackasm1(SB)
+	MOVD $802, R0
+	BR   callbackasm1(SB)
+	MOVD $803, R0
+	BR   callbackasm1(SB)
+	MOVD $804, R0
+	BR   callbackasm1(SB)
+	MOVD $805, R0
+	BR   callbackasm1(SB)
+	MOVD $806, R0
+	BR   callbackasm1(SB)
+	MOVD $807, R0
+	BR   callbackasm1(SB)
+	MOVD $808, R0
+	BR   callbackasm1(SB)
+	MOVD $809, R0
+	BR   callbackasm1(SB)
+	MOVD $810, R0
+	BR   callbackasm1(SB)
+	MOVD $811, R0
+	BR   callbackasm1(SB)
+	MOVD $812, R0
+	BR   callbackasm1(SB)
+	MOVD $813, R0
+	BR   callbackasm1(SB)
+	MOVD $814, R0
+	BR   callbackasm1(SB)
+	MOVD $815, R0
+	BR   callbackasm1(SB)
+	MOVD $816, R0
+	BR   callbackasm1(SB)
+	MOVD $817, R0
+	BR   callbackasm1(SB)
+	MOVD $818, R0
+	BR   callbackasm1(SB)
+	MOVD $819, R0
+	BR   callbackasm1(SB)
+	MOVD $820, R0
+	BR   callbackasm1(SB)
+	MOVD $821, R0
+	BR   callbackasm1(SB)
+	MOVD $822, R0
+	BR   callbackasm1(SB)
+	MOVD $823, R0
+	BR   callbackasm1(SB)
+	MOVD $824, R0
+	BR   callbackasm1(SB)
+	MOVD $825, R0
+	BR   callbackasm1(SB)
+	MOVD $826, R0
+	BR   callbackasm1(SB)
+	MOVD $827, R0
+	BR   callbackasm1(SB)
+	MOVD $828, R0
+	BR   callbackasm1(SB)
+	MOVD $829, R0
+	BR   callbackasm1(SB)
+	MOVD $830, R0
+	BR   callbackasm1(SB)
+	MOVD $831, R0
+	BR   callbackasm1(SB)
+	MOVD $832, R0
+	BR   callbackasm1(SB)
+	MOVD $833, R0
+	BR   callbackasm1(SB)
+	MOVD $834, R0
+	BR   callbackasm1(SB)
+	MOVD $835, R0
+	BR   callbackasm1(SB)
+	MOVD $836, R0
+	BR   callbackasm1(SB)
+	MOVD $837, R0
+	BR   callbackasm1(SB)
+	MOVD $838, R0
+	BR   callbackasm1(SB)
+	MOVD $839, R0
+	BR   callbackasm1(SB)
+	MOVD $840, R0
+	BR   callbackasm1(SB)
+	MOVD $841, R0
+	BR   callbackasm1(SB)
+	MOVD $842, R0
+	BR   callbackasm1(SB)
+	MOVD $843, R0
+	BR   callbackasm1(SB)
+	MOVD $844, R0
+	BR   callbackasm1(SB)
+	MOVD $845, R0
+	BR   callbackasm1(SB)
+	MOVD $846, R0
+	BR   callbackasm1(SB)
+	MOVD $847, R0
+	BR   callbackasm1(SB)
+	MOVD $848, R0
+	BR   callbackasm1(SB)
+	MOVD $849, R0
+	BR   callbackasm1(SB)
+	MOVD $850, R0
+	BR   callbackasm1(SB)
+	MOVD $851, R0
+	BR   callbackasm1(SB)
+	MOVD $852, R0
+	BR   callbackasm1(SB)
+	MOVD $853, R0
+	BR   callbackasm1(SB)
+	MOVD $854, R0
+	BR   callbackasm1(SB)
+	MOVD $855, R0
+	BR   callbackasm1(SB)
+	MOVD $856, R0
+	BR   callbackasm1(SB)
+	MOVD $857, R0
+	BR   callbackasm1(SB)
+	MOVD $858, R0
+	BR   callbackasm1(SB)
+	MOVD $859, R0
+	BR   callbackasm1(SB)
+	MOVD $860, R0
+	BR   callbackasm1(SB)
+	MOVD $861, R0
+	BR   callbackasm1(SB)
+	MOVD $862, R0
+	BR   callbackasm1(SB)
+	MOVD $863, R0
+	BR   callbackasm1(SB)
+	MOVD $864, R0
+	BR   callbackasm1(SB)
+	MOVD $865, R0
+	BR   callbackasm1(SB)
+	MOVD $866, R0
+	BR   callbackasm1(SB)
+	MOVD $867, R0
+	BR   callbackasm1(SB)
+	MOVD $868, R0
+	BR   callbackasm1(SB)
+	MOVD $869, R0
+	BR   callbackasm1(SB)
+	MOVD $870, R0
+	BR   callbackasm1(SB)
+	MOVD $871, R0
+	BR   callbackasm1(SB)
+	MOVD $872, R0
+	BR   callbackasm1(SB)
+	MOVD $873, R0
+	BR   callbackasm1(SB)
+	MOVD $874, R0
+	BR   callbackasm1(SB)
+	MOVD $875, R0
+	BR   callbackasm1(SB)
+	MOVD $876, R0
+	BR   callbackasm1(SB)
+	MOVD $877, R0
+	BR   callbackasm1(SB)
+	MOVD $878, R0
+	BR   callbackasm1(SB)
+	MOVD $879, R0
+	BR   callbackasm1(SB)
+	MOVD $880, R0
+	BR   callbackasm1(SB)
+	MOVD $881, R0
+	BR   callbackasm1(SB)
+	MOVD $882, R0
+	BR   callbackasm1(SB)
+	MOVD $883, R0
+	BR   callbackasm1(SB)
+	MOVD $884, R0
+	BR   callbackasm1(SB)
+	MOVD $885, R0
+	BR   callbackasm1(SB)
+	MOVD $886, R0
+	BR   callbackasm1(SB)
+	MOVD $887, R0
+	BR   callbackasm1(SB)
+	MOVD $888, R0
+	BR   callbackasm1(SB)
+	MOVD $889, R0
+	BR   callbackasm1(SB)
+	MOVD $890, R0
+	BR   callbackasm1(SB)
+	MOVD $891, R0
+	BR   callbackasm1(SB)
+	MOVD $892, R0
+	BR   callbackasm1(SB)
+	MOVD $893, R0
+	BR   callbackasm1(SB)
+	MOVD $894, R0
+	BR   callbackasm1(SB)
+	MOVD $895, R0
+	BR   callbackasm1(SB)
+	MOVD $896, R0
+	BR   callbackasm1(SB)
+	MOVD $897, R0
+	BR   callbackasm1(SB)
+	MOVD $898, R0
+	BR   callbackasm1(SB)
+	MOVD $899, R0
+	BR   callbackasm1(SB)
+	MOVD $900, R0
+	BR   callbackasm1(SB)
+	MOVD $901, R0
+	BR   callbackasm1(SB)
+	MOVD $902, R0
+	BR   callbackasm1(SB)
+	MOVD $903, R0
+	BR   callbackasm1(SB)
+	MOVD $904, R0
+	BR   callbackasm1(SB)
+	MOVD $905, R0
+	BR   callbackasm1(SB)
+	MOVD $906, R0
+	BR   callbackasm1(SB)
+	MOVD $907, R0
+	BR   callbackasm1(SB)
+	MOVD $908, R0
+	BR   callbackasm1(SB)
+	MOVD $909, R0
+	BR   callbackasm1(SB)
+	MOVD $910, R0
+	BR   callbackasm1(SB)
+	MOVD $911, R0
+	BR   callbackasm1(SB)
+	MOVD $912, R0
+	BR   callbackasm1(SB)
+	MOVD $913, R0
+	BR   callbackasm1(SB)
+	MOVD $914, R0
+	BR   callbackasm1(SB)
+	MOVD $915, R0
+	BR   callbackasm1(SB)
+	MOVD $916, R0
+	BR   callbackasm1(SB)
+	MOVD $917, R0
+	BR   callbackasm1(SB)
+	MOVD $918, R0
+	BR   callbackasm1(SB)
+	MOVD $919, R0
+	BR   callbackasm1(SB)
+	MOVD $920, R0
+	BR   callbackasm1(SB)
+	MOVD $921, R0
+	BR   callbackasm1(SB)
+	MOVD $922, R0
+	BR   callbackasm1(SB)
+	MOVD $923, R0
+	BR   callbackasm1(SB)
+	MOVD $924, R0
+	BR   callbackasm1(SB)
+	MOVD $925, R0
+	BR   callbackasm1(SB)
+	MOVD $926, R0
+	BR   callbackasm1(SB)
+	MOVD $927, R0
+	BR   callbackasm1(SB)
+	MOVD $928, R0
+	BR   callbackasm1(SB)
+	MOVD $929, R0
+	BR   callbackasm1(SB)
+	MOVD $930, R0
+	BR   callbackasm1(SB)
+	MOVD $931, R0
+	BR   callbackasm1(SB)
+	MOVD $932, R0
+	BR   callbackasm1(SB)
+	MOVD $933, R0
+	BR   callbackasm1(SB)
+	MOVD $934, R0
+	BR   callbackasm1(SB)
+	MOVD $935, R0
+	BR   callbackasm1(SB)
+	MOVD $936, R0
+	BR   callbackasm1(SB)
+	MOVD $937, R0
+	BR   callbackasm1(SB)
+	MOVD $938, R0
+	BR   callbackasm1(SB)
+	MOVD $939, R0
+	BR   callbackasm1(SB)
+	MOVD $940, R0
+	BR   callbackasm1(SB)
+	MOVD $941, R0
+	BR   callbackasm1(SB)
+	MOVD $942, R0
+	BR   callbackasm1(SB)
+	MOVD $943, R0
+	BR   callbackasm1(SB)
+	MOVD $944, R0
+	BR   callbackasm1(SB)
+	MOVD $945, R0
+	BR   callbackasm1(SB)
+	MOVD $946, R0
+	BR   callbackasm1(SB)
+	MOVD $947, R0
+	BR   callbackasm1(SB)
+	MOVD $948, R0
+	BR   callbackasm1(SB)
+	MOVD $949, R0
+	BR   callbackasm1(SB)
+	MOVD $950, R0
+	BR   callbackasm1(SB)
+	MOVD $951, R0
+	BR   callbackasm1(SB)
+	MOVD $952, R0
+	BR   callbackasm1(SB)
+	MOVD $953, R0
+	BR   callbackasm1(SB)
+	MOVD $954, R0
+	BR   callbackasm1(SB)
+	MOVD $955, R0
+	BR   callbackasm1(SB)
+	MOVD $956, R0
+	BR   callbackasm1(SB)
+	MOVD $957, R0
+	BR   callbackasm1(SB)
+	MOVD $958, R0
+	BR   callbackasm1(SB)
+	MOVD $959, R0
+	BR   callbackasm1(SB)
+	MOVD $960, R0
+	BR   callbackasm1(SB)
+	MOVD $961, R0
+	BR   callbackasm1(SB)
+	MOVD $962, R0
+	BR   callbackasm1(SB)
+	MOVD $963, R0
+	BR   callbackasm1(SB)
+	MOVD $964, R0
+	BR   callbackasm1(SB)
+	MOVD $965, R0
+	BR   callbackasm1(SB)
+	MOVD $966, R0
+	BR   callbackasm1(SB)
+	MOVD $967, R0
+	BR   callbackasm1(SB)
+	MOVD $968, R0
+	BR   callbackasm1(SB)
+	MOVD $969, R0
+	BR   callbackasm1(SB)
+	MOVD $970, R0
+	BR   callbackasm1(SB)
+	MOVD $971, R0
+	BR   callbackasm1(SB)
+	MOVD $972, R0
+	BR   callbackasm1(SB)
+	MOVD $973, R0
+	BR   callbackasm1(SB)
+	MOVD $974, R0
+	BR   callbackasm1(SB)
+	MOVD $975, R0
+	BR   callbackasm1(SB)
+	MOVD $976, R0
+	BR   callbackasm1(SB)
+	MOVD $977, R0
+	BR   callbackasm1(SB)
+	MOVD $978, R0
+	BR   callbackasm1(SB)
+	MOVD $979, R0
+	BR   callbackasm1(SB)
+	MOVD $980, R0
+	BR   callbackasm1(SB)
+	MOVD $981, R0
+	BR   callbackasm1(SB)
+	MOVD $982, R0
+	BR   callbackasm1(SB)
+	MOVD $983, R0
+	BR   callbackasm1(SB)
+	MOVD $984, R0
+	BR   callbackasm1(SB)
+	MOVD $985, R0
+	BR   callbackasm1(SB)
+	MOVD $986, R0
+	BR   callbackasm1(SB)
+	MOVD $987, R0
+	BR   callbackasm1(SB)
+	MOVD $988, R0
+	BR   callbackasm1(SB)
+	MOVD $989, R0
+	BR   callbackasm1(SB)
+	MOVD $990, R0
+	BR   callbackasm1(SB)
+	MOVD $991, R0
+	BR   callbackasm1(SB)
+	MOVD $992, R0
+	BR   callbackasm1(SB)
+	MOVD $993, R0
+	BR   callbackasm1(SB)
+	MOVD $994, R0
+	BR   callbackasm1(SB)
+	MOVD $995, R0
+	BR   callbackasm1(SB)
+	MOVD $996, R0
+	BR   callbackasm1(SB)
+	MOVD $997, R0
+	BR   callbackasm1(SB)
+	MOVD $998, R0
+	BR   callbackasm1(SB)
+	MOVD $999, R0
+	BR   callbackasm1(SB)
+	MOVD $1000, R0
+	BR   callbackasm1(SB)
+	MOVD $1001, R0
+	BR   callbackasm1(SB)
+	MOVD $1002, R0
+	BR   callbackasm1(SB)
+	MOVD $1003, R0
+	BR   callbackasm1(SB)
+	MOVD $1004, R0
+	BR   callbackasm1(SB)
+	MOVD $1005, R0
+	BR   callbackasm1(SB)
+	MOVD $1006, R0
+	BR   callbackasm1(SB)
+	MOVD $1007, R0
+	BR   callbackasm1(SB)
+	MOVD $1008, R0
+	BR   callbackasm1(SB)
+	MOVD $1009, R0
+	BR   callbackasm1(SB)
+	MOVD $1010, R0
+	BR   callbackasm1(SB)
+	MOVD $1011, R0
+	BR   callbackasm1(SB)
+	MOVD $1012, R0
+	BR   callbackasm1(SB)
+	MOVD $1013, R0
+	BR   callbackasm1(SB)
+	MOVD $1014, R0
+	BR   callbackasm1(SB)
+	MOVD $1015, R0
+	BR   callbackasm1(SB)
+	MOVD $1016, R0
+	BR   callbackasm1(SB)
+	MOVD $1017, R0
+	BR   callbackasm1(SB)
+	MOVD $1018, R0
+	BR   callbackasm1(SB)
+	MOVD $1019, R0
+	BR   callbackasm1(SB)
+	MOVD $1020, R0
+	BR   callbackasm1(SB)
+	MOVD $1021, R0
+	BR   callbackasm1(SB)
+	MOVD $1022, R0
+	BR   callbackasm1(SB)
+	MOVD $1023, R0
+	BR   callbackasm1(SB)
+	MOVD $1024, R0
+	BR   callbackasm1(SB)
+	MOVD $1025, R0
+	BR   callbackasm1(SB)
+	MOVD $1026, R0
+	BR   callbackasm1(SB)
+	MOVD $1027, R0
+	BR   callbackasm1(SB)
+	MOVD $1028, R0
+	BR   callbackasm1(SB)
+	MOVD $1029, R0
+	BR   callbackasm1(SB)
+	MOVD $1030, R0
+	BR   callbackasm1(SB)
+	MOVD $1031, R0
+	BR   callbackasm1(SB)
+	MOVD $1032, R0
+	BR   callbackasm1(SB)
+	MOVD $1033, R0
+	BR   callbackasm1(SB)
+	MOVD $1034, R0
+	BR   callbackasm1(SB)
+	MOVD $1035, R0
+	BR   callbackasm1(SB)
+	MOVD $1036, R0
+	BR   callbackasm1(SB)
+	MOVD $1037, R0
+	BR   callbackasm1(SB)
+	MOVD $1038, R0
+	BR   callbackasm1(SB)
+	MOVD $1039, R0
+	BR   callbackasm1(SB)
+	MOVD $1040, R0
+	BR   callbackasm1(SB)
+	MOVD $1041, R0
+	BR   callbackasm1(SB)
+	MOVD $1042, R0
+	BR   callbackasm1(SB)
+	MOVD $1043, R0
+	BR   callbackasm1(SB)
+	MOVD $1044, R0
+	BR   callbackasm1(SB)
+	MOVD $1045, R0
+	BR   callbackasm1(SB)
+	MOVD $1046, R0
+	BR   callbackasm1(SB)
+	MOVD $1047, R0
+	BR   callbackasm1(SB)
+	MOVD $1048, R0
+	BR   callbackasm1(SB)
+	MOVD $1049, R0
+	BR   callbackasm1(SB)
+	MOVD $1050, R0
+	BR   callbackasm1(SB)
+	MOVD $1051, R0
+	BR   callbackasm1(SB)
+	MOVD $1052, R0
+	BR   callbackasm1(SB)
+	MOVD $1053, R0
+	BR   callbackasm1(SB)
+	MOVD $1054, R0
+	BR   callbackasm1(SB)
+	MOVD $1055, R0
+	BR   callbackasm1(SB)
+	MOVD $1056, R0
+	BR   callbackasm1(SB)
+	MOVD $1057, R0
+	BR   callbackasm1(SB)
+	MOVD $1058, R0
+	BR   callbackasm1(SB)
+	MOVD $1059, R0
+	BR   callbackasm1(SB)
+	MOVD $1060, R0
+	BR   callbackasm1(SB)
+	MOVD $1061, R0
+	BR   callbackasm1(SB)
+	MOVD $1062, R0
+	BR   callbackasm1(SB)
+	MOVD $1063, R0
+	BR   callbackasm1(SB)
+	MOVD $1064, R0
+	BR   callbackasm1(SB)
+	MOVD $1065, R0
+	BR   callbackasm1(SB)
+	MOVD $1066, R0
+	BR   callbackasm1(SB)
+	MOVD $1067, R0
+	BR   callbackasm1(SB)
+	MOVD $1068, R0
+	BR   callbackasm1(SB)
+	MOVD $1069, R0
+	BR   callbackasm1(SB)
+	MOVD $1070, R0
+	BR   callbackasm1(SB)
+	MOVD $1071, R0
+	BR   callbackasm1(SB)
+	MOVD $1072, R0
+	BR   callbackasm1(SB)
+	MOVD $1073, R0
+	BR   callbackasm1(SB)
+	MOVD $1074, R0
+	BR   callbackasm1(SB)
+	MOVD $1075, R0
+	BR   callbackasm1(SB)
+	MOVD $1076, R0
+	BR   callbackasm1(SB)
+	MOVD $1077, R0
+	BR   callbackasm1(SB)
+	MOVD $1078, R0
+	BR   callbackasm1(SB)
+	MOVD $1079, R0
+	BR   callbackasm1(SB)
+	MOVD $1080, R0
+	BR   callbackasm1(SB)
+	MOVD $1081, R0
+	BR   callbackasm1(SB)
+	MOVD $1082, R0
+	BR   callbackasm1(SB)
+	MOVD $1083, R0
+	BR   callbackasm1(SB)
+	MOVD $1084, R0
+	BR   callbackasm1(SB)
+	MOVD $1085, R0
+	BR   callbackasm1(SB)
+	MOVD $1086, R0
+	BR   callbackasm1(SB)
+	MOVD $1087, R0
+	BR   callbackasm1(SB)
+	MOVD $1088, R0
+	BR   callbackasm1(SB)
+	MOVD $1089, R0
+	BR   callbackasm1(SB)
+	MOVD $1090, R0
+	BR   callbackasm1(SB)
+	MOVD $1091, R0
+	BR   callbackasm1(SB)
+	MOVD $1092, R0
+	BR   callbackasm1(SB)
+	MOVD $1093, R0
+	BR   callbackasm1(SB)
+	MOVD $1094, R0
+	BR   callbackasm1(SB)
+	MOVD $1095, R0
+	BR   callbackasm1(SB)
+	MOVD $1096, R0
+	BR   callbackasm1(SB)
+	MOVD $1097, R0
+	BR   callbackasm1(SB)
+	MOVD $1098, R0
+	BR   callbackasm1(SB)
+	MOVD $1099, R0
+	BR   callbackasm1(SB)
+	MOVD $1100, R0
+	BR   callbackasm1(SB)
+	MOVD $1101, R0
+	BR   callbackasm1(SB)
+	MOVD $1102, R0
+	BR   callbackasm1(SB)
+	MOVD $1103, R0
+	BR   callbackasm1(SB)
+	MOVD $1104, R0
+	BR   callbackasm1(SB)
+	MOVD $1105, R0
+	BR   callbackasm1(SB)
+	MOVD $1106, R0
+	BR   callbackasm1(SB)
+	MOVD $1107, R0
+	BR   callbackasm1(SB)
+	MOVD $1108, R0
+	BR   callbackasm1(SB)
+	MOVD $1109, R0
+	BR   callbackasm1(SB)
+	MOVD $1110, R0
+	BR   callbackasm1(SB)
+	MOVD $1111, R0
+	BR   callbackasm1(SB)
+	MOVD $1112, R0
+	BR   callbackasm1(SB)
+	MOVD $1113, R0
+	BR   callbackasm1(SB)
+	MOVD $1114, R0
+	BR   callbackasm1(SB)
+	MOVD $1115, R0
+	BR   callbackasm1(SB)
+	MOVD $1116, R0
+	BR   callbackasm1(SB)
+	MOVD $1117, R0
+	BR   callbackasm1(SB)
+	MOVD $1118, R0
+	BR   callbackasm1(SB)
+	MOVD $1119, R0
+	BR   callbackasm1(SB)
+	MOVD $1120, R0
+	BR   callbackasm1(SB)
+	MOVD $1121, R0
+	BR   callbackasm1(SB)
+	MOVD $1122, R0
+	BR   callbackasm1(SB)
+	MOVD $1123, R0
+	BR   callbackasm1(SB)
+	MOVD $1124, R0
+	BR   callbackasm1(SB)
+	MOVD $1125, R0
+	BR   callbackasm1(SB)
+	MOVD $1126, R0
+	BR   callbackasm1(SB)
+	MOVD $1127, R0
+	BR   callbackasm1(SB)
+	MOVD $1128, R0
+	BR   callbackasm1(SB)
+	MOVD $1129, R0
+	BR   callbackasm1(SB)
+	MOVD $1130, R0
+	BR   callbackasm1(SB)
+	MOVD $1131, R0
+	BR   callbackasm1(SB)
+	MOVD $1132, R0
+	BR   callbackasm1(SB)
+	MOVD $1133, R0
+	BR   callbackasm1(SB)
+	MOVD $1134, R0
+	BR   callbackasm1(SB)
+	MOVD $1135, R0
+	BR   callbackasm1(SB)
+	MOVD $1136, R0
+	BR   callbackasm1(SB)
+	MOVD $1137, R0
+	BR   callbackasm1(SB)
+	MOVD $1138, R0
+	BR   callbackasm1(SB)
+	MOVD $1139, R0
+	BR   callbackasm1(SB)
+	MOVD $1140, R0
+	BR   callbackasm1(SB)
+	MOVD $1141, R0
+	BR   callbackasm1(SB)
+	MOVD $1142, R0
+	BR   callbackasm1(SB)
+	MOVD $1143, R0
+	BR   callbackasm1(SB)
+	MOVD $1144, R0
+	BR   callbackasm1(SB)
+	MOVD $1145, R0
+	BR   callbackasm1(SB)
+	MOVD $1146, R0
+	BR   callbackasm1(SB)
+	MOVD $1147, R0
+	BR   callbackasm1(SB)
+	MOVD $1148, R0
+	BR   callbackasm1(SB)
+	MOVD $1149, R0
+	BR   callbackasm1(SB)
+	MOVD $1150, R0
+	BR   callbackasm1(SB)
+	MOVD $1151, R0
+	BR   callbackasm1(SB)
+	MOVD $1152, R0
+	BR   callbackasm1(SB)
+	MOVD $1153, R0
+	BR   callbackasm1(SB)
+	MOVD $1154, R0
+	BR   callbackasm1(SB)
+	MOVD $1155, R0
+	BR   callbackasm1(SB)
+	MOVD $1156, R0
+	BR   callbackasm1(SB)
+	MOVD $1157, R0
+	BR   callbackasm1(SB)
+	MOVD $1158, R0
+	BR   callbackasm1(SB)
+	MOVD $1159, R0
+	BR   callbackasm1(SB)
+	MOVD $1160, R0
+	BR   callbackasm1(SB)
+	MOVD $1161, R0
+	BR   callbackasm1(SB)
+	MOVD $1162, R0
+	BR   callbackasm1(SB)
+	MOVD $1163, R0
+	BR   callbackasm1(SB)
+	MOVD $1164, R0
+	BR   callbackasm1(SB)
+	MOVD $1165, R0
+	BR   callbackasm1(SB)
+	MOVD $1166, R0
+	BR   callbackasm1(SB)
+	MOVD $1167, R0
+	BR   callbackasm1(SB)
+	MOVD $1168, R0
+	BR   callbackasm1(SB)
+	MOVD $1169, R0
+	BR   callbackasm1(SB)
+	MOVD $1170, R0
+	BR   callbackasm1(SB)
+	MOVD $1171, R0
+	BR   callbackasm1(SB)
+	MOVD $1172, R0
+	BR   callbackasm1(SB)
+	MOVD $1173, R0
+	BR   callbackasm1(SB)
+	MOVD $1174, R0
+	BR   callbackasm1(SB)
+	MOVD $1175, R0
+	BR   callbackasm1(SB)
+	MOVD $1176, R0
+	BR   callbackasm1(SB)
+	MOVD $1177, R0
+	BR   callbackasm1(SB)
+	MOVD $1178, R0
+	BR   callbackasm1(SB)
+	MOVD $1179, R0
+	BR   callbackasm1(SB)
+	MOVD $1180, R0
+	BR   callbackasm1(SB)
+	MOVD $1181, R0
+	BR   callbackasm1(SB)
+	MOVD $1182, R0
+	BR   callbackasm1(SB)
+	MOVD $1183, R0
+	BR   callbackasm1(SB)
+	MOVD $1184, R0
+	BR   callbackasm1(SB)
+	MOVD $1185, R0
+	BR   callbackasm1(SB)
+	MOVD $1186, R0
+	BR   callbackasm1(SB)
+	MOVD $1187, R0
+	BR   callbackasm1(SB)
+	MOVD $1188, R0
+	BR   callbackasm1(SB)
+	MOVD $1189, R0
+	BR   callbackasm1(SB)
+	MOVD $1190, R0
+	BR   callbackasm1(SB)
+	MOVD $1191, R0
+	BR   callbackasm1(SB)
+	MOVD $1192, R0
+	BR   callbackasm1(SB)
+	MOVD $1193, R0
+	BR   callbackasm1(SB)
+	MOVD $1194, R0
+	BR   callbackasm1(SB)
+	MOVD $1195, R0
+	BR   callbackasm1(SB)
+	MOVD $1196, R0
+	BR   callbackasm1(SB)
+	MOVD $1197, R0
+	BR   callbackasm1(SB)
+	MOVD $1198, R0
+	BR   callbackasm1(SB)
+	MOVD $1199, R0
+	BR   callbackasm1(SB)
+	MOVD $1200, R0
+	BR   callbackasm1(SB)
+	MOVD $1201, R0
+	BR   callbackasm1(SB)
+	MOVD $1202, R0
+	BR   callbackasm1(SB)
+	MOVD $1203, R0
+	BR   callbackasm1(SB)
+	MOVD $1204, R0
+	BR   callbackasm1(SB)
+	MOVD $1205, R0
+	BR   callbackasm1(SB)
+	MOVD $1206, R0
+	BR   callbackasm1(SB)
+	MOVD $1207, R0
+	BR   callbackasm1(SB)
+	MOVD $1208, R0
+	BR   callbackasm1(SB)
+	MOVD $1209, R0
+	BR   callbackasm1(SB)
+	MOVD $1210, R0
+	BR   callbackasm1(SB)
+	MOVD $1211, R0
+	BR   callbackasm1(SB)
+	MOVD $1212, R0
+	BR   callbackasm1(SB)
+	MOVD $1213, R0
+	BR   callbackasm1(SB)
+	MOVD $1214, R0
+	BR   callbackasm1(SB)
+	MOVD $1215, R0
+	BR   callbackasm1(SB)
+	MOVD $1216, R0
+	BR   callbackasm1(SB)
+	MOVD $1217, R0
+	BR   callbackasm1(SB)
+	MOVD $1218, R0
+	BR   callbackasm1(SB)
+	MOVD $1219, R0
+	BR   callbackasm1(SB)
+	MOVD $1220, R0
+	BR   callbackasm1(SB)
+	MOVD $1221, R0
+	BR   callbackasm1(SB)
+	MOVD $1222, R0
+	BR   callbackasm1(SB)
+	MOVD $1223, R0
+	BR   callbackasm1(SB)
+	MOVD $1224, R0
+	BR   callbackasm1(SB)
+	MOVD $1225, R0
+	BR   callbackasm1(SB)
+	MOVD $1226, R0
+	BR   callbackasm1(SB)
+	MOVD $1227, R0
+	BR   callbackasm1(SB)
+	MOVD $1228, R0
+	BR   callbackasm1(SB)
+	MOVD $1229, R0
+	BR   callbackasm1(SB)
+	MOVD $1230, R0
+	BR   callbackasm1(SB)
+	MOVD $1231, R0
+	BR   callbackasm1(SB)
+	MOVD $1232, R0
+	BR   callbackasm1(SB)
+	MOVD $1233, R0
+	BR   callbackasm1(SB)
+	MOVD $1234, R0
+	BR   callbackasm1(SB)
+	MOVD $1235, R0
+	BR   callbackasm1(SB)
+	MOVD $1236, R0
+	BR   callbackasm1(SB)
+	MOVD $1237, R0
+	BR   callbackasm1(SB)
+	MOVD $1238, R0
+	BR   callbackasm1(SB)
+	MOVD $1239, R0
+	BR   callbackasm1(SB)
+	MOVD $1240, R0
+	BR   callbackasm1(SB)
+	MOVD $1241, R0
+	BR   callbackasm1(SB)
+	MOVD $1242, R0
+	BR   callbackasm1(SB)
+	MOVD $1243, R0
+	BR   callbackasm1(SB)
+	MOVD $1244, R0
+	BR   callbackasm1(SB)
+	MOVD $1245, R0
+	BR   callbackasm1(SB)
+	MOVD $1246, R0
+	BR   callbackasm1(SB)
+	MOVD $1247, R0
+	BR   callbackasm1(SB)
+	MOVD $1248, R0
+	BR   callbackasm1(SB)
+	MOVD $1249, R0
+	BR   callbackasm1(SB)
+	MOVD $1250, R0
+	BR   callbackasm1(SB)
+	MOVD $1251, R0
+	BR   callbackasm1(SB)
+	MOVD $1252, R0
+	BR   callbackasm1(SB)
+	MOVD $1253, R0
+	BR   callbackasm1(SB)
+	MOVD $1254, R0
+	BR   callbackasm1(SB)
+	MOVD $1255, R0
+	BR   callbackasm1(SB)
+	MOVD $1256, R0
+	BR   callbackasm1(SB)
+	MOVD $1257, R0
+	BR   callbackasm1(SB)
+	MOVD $1258, R0
+	BR   callbackasm1(SB)
+	MOVD $1259, R0
+	BR   callbackasm1(SB)
+	MOVD $1260, R0
+	BR   callbackasm1(SB)
+	MOVD $1261, R0
+	BR   callbackasm1(SB)
+	MOVD $1262, R0
+	BR   callbackasm1(SB)
+	MOVD $1263, R0
+	BR   callbackasm1(SB)
+	MOVD $1264, R0
+	BR   callbackasm1(SB)
+	MOVD $1265, R0
+	BR   callbackasm1(SB)
+	MOVD $1266, R0
+	BR   callbackasm1(SB)
+	MOVD $1267, R0
+	BR   callbackasm1(SB)
+	MOVD $1268, R0
+	BR   callbackasm1(SB)
+	MOVD $1269, R0
+	BR   callbackasm1(SB)
+	MOVD $1270, R0
+	BR   callbackasm1(SB)
+	MOVD $1271, R0
+	BR   callbackasm1(SB)
+	MOVD $1272, R0
+	BR   callbackasm1(SB)
+	MOVD $1273, R0
+	BR   callbackasm1(SB)
+	MOVD $1274, R0
+	BR   callbackasm1(SB)
+	MOVD $1275, R0
+	BR   callbackasm1(SB)
+	MOVD $1276, R0
+	BR   callbackasm1(SB)
+	MOVD $1277, R0
+	BR   callbackasm1(SB)
+	MOVD $1278, R0
+	BR   callbackasm1(SB)
+	MOVD $1279, R0
+	BR   callbackasm1(SB)
+	MOVD $1280, R0
+	BR   callbackasm1(SB)
+	MOVD $1281, R0
+	BR   callbackasm1(SB)
+	MOVD $1282, R0
+	BR   callbackasm1(SB)
+	MOVD $1283, R0
+	BR   callbackasm1(SB)
+	MOVD $1284, R0
+	BR   callbackasm1(SB)
+	MOVD $1285, R0
+	BR   callbackasm1(SB)
+	MOVD $1286, R0
+	BR   callbackasm1(SB)
+	MOVD $1287, R0
+	BR   callbackasm1(SB)
+	MOVD $1288, R0
+	BR   callbackasm1(SB)
+	MOVD $1289, R0
+	BR   callbackasm1(SB)
+	MOVD $1290, R0
+	BR   callbackasm1(SB)
+	MOVD $1291, R0
+	BR   callbackasm1(SB)
+	MOVD $1292, R0
+	BR   callbackasm1(SB)
+	MOVD $1293, R0
+	BR   callbackasm1(SB)
+	MOVD $1294, R0
+	BR   callbackasm1(SB)
+	MOVD $1295, R0
+	BR   callbackasm1(SB)
+	MOVD $1296, R0
+	BR   callbackasm1(SB)
+	MOVD $1297, R0
+	BR   callbackasm1(SB)
+	MOVD $1298, R0
+	BR   callbackasm1(SB)
+	MOVD $1299, R0
+	BR   callbackasm1(SB)
+	MOVD $1300, R0
+	BR   callbackasm1(SB)
+	MOVD $1301, R0
+	BR   callbackasm1(SB)
+	MOVD $1302, R0
+	BR   callbackasm1(SB)
+	MOVD $1303, R0
+	BR   callbackasm1(SB)
+	MOVD $1304, R0
+	BR   callbackasm1(SB)
+	MOVD $1305, R0
+	BR   callbackasm1(SB)
+	MOVD $1306, R0
+	BR   callbackasm1(SB)
+	MOVD $1307, R0
+	BR   callbackasm1(SB)
+	MOVD $1308, R0
+	BR   callbackasm1(SB)
+	MOVD $1309, R0
+	BR   callbackasm1(SB)
+	MOVD $1310, R0
+	BR   callbackasm1(SB)
+	MOVD $1311, R0
+	BR   callbackasm1(SB)
+	MOVD $1312, R0
+	BR   callbackasm1(SB)
+	MOVD $1313, R0
+	BR   callbackasm1(SB)
+	MOVD $1314, R0
+	BR   callbackasm1(SB)
+	MOVD $1315, R0
+	BR   callbackasm1(SB)
+	MOVD $1316, R0
+	BR   callbackasm1(SB)
+	MOVD $1317, R0
+	BR   callbackasm1(SB)
+	MOVD $1318, R0
+	BR   callbackasm1(SB)
+	MOVD $1319, R0
+	BR   callbackasm1(SB)
+	MOVD $1320, R0
+	BR   callbackasm1(SB)
+	MOVD $1321, R0
+	BR   callbackasm1(SB)
+	MOVD $1322, R0
+	BR   callbackasm1(SB)
+	MOVD $1323, R0
+	BR   callbackasm1(SB)
+	MOVD $1324, R0
+	BR   callbackasm1(SB)
+	MOVD $1325, R0
+	BR   callbackasm1(SB)
+	MOVD $1326, R0
+	BR   callbackasm1(SB)
+	MOVD $1327, R0
+	BR   callbackasm1(SB)
+	MOVD $1328, R0
+	BR   callbackasm1(SB)
+	MOVD $1329, R0
+	BR   callbackasm1(SB)
+	MOVD $1330, R0
+	BR   callbackasm1(SB)
+	MOVD $1331, R0
+	BR   callbackasm1(SB)
+	MOVD $1332, R0
+	BR   callbackasm1(SB)
+	MOVD $1333, R0
+	BR   callbackasm1(SB)
+	MOVD $1334, R0
+	BR   callbackasm1(SB)
+	MOVD $1335, R0
+	BR   callbackasm1(SB)
+	MOVD $1336, R0
+	BR   callbackasm1(SB)
+	MOVD $1337, R0
+	BR   callbackasm1(SB)
+	MOVD $1338, R0
+	BR   callbackasm1(SB)
+	MOVD $1339, R0
+	BR   callbackasm1(SB)
+	MOVD $1340, R0
+	BR   callbackasm1(SB)
+	MOVD $1341, R0
+	BR   callbackasm1(SB)
+	MOVD $1342, R0
+	BR   callbackasm1(SB)
+	MOVD $1343, R0
+	BR   callbackasm1(SB)
+	MOVD $1344, R0
+	BR   callbackasm1(SB)
+	MOVD $1345, R0
+	BR   callbackasm1(SB)
+	MOVD $1346, R0
+	BR   callbackasm1(SB)
+	MOVD $1347, R0
+	BR   callbackasm1(SB)
+	MOVD $1348, R0
+	BR   callbackasm1(SB)
+	MOVD $1349, R0
+	BR   callbackasm1(SB)
+	MOVD $1350, R0
+	BR   callbackasm1(SB)
+	MOVD $1351, R0
+	BR   callbackasm1(SB)
+	MOVD $1352, R0
+	BR   callbackasm1(SB)
+	MOVD $1353, R0
+	BR   callbackasm1(SB)
+	MOVD $1354, R0
+	BR   callbackasm1(SB)
+	MOVD $1355, R0
+	BR   callbackasm1(SB)
+	MOVD $1356, R0
+	BR   callbackasm1(SB)
+	MOVD $1357, R0
+	BR   callbackasm1(SB)
+	MOVD $1358, R0
+	BR   callbackasm1(SB)
+	MOVD $1359, R0
+	BR   callbackasm1(SB)
+	MOVD $1360, R0
+	BR   callbackasm1(SB)
+	MOVD $1361, R0
+	BR   callbackasm1(SB)
+	MOVD $1362, R0
+	BR   callbackasm1(SB)
+	MOVD $1363, R0
+	BR   callbackasm1(SB)
+	MOVD $1364, R0
+	BR   callbackasm1(SB)
+	MOVD $1365, R0
+	BR   callbackasm1(SB)
+	MOVD $1366, R0
+	BR   callbackasm1(SB)
+	MOVD $1367, R0
+	BR   callbackasm1(SB)
+	MOVD $1368, R0
+	BR   callbackasm1(SB)
+	MOVD $1369, R0
+	BR   callbackasm1(SB)
+	MOVD $1370, R0
+	BR   callbackasm1(SB)
+	MOVD $1371, R0
+	BR   callbackasm1(SB)
+	MOVD $1372, R0
+	BR   callbackasm1(SB)
+	MOVD $1373, R0
+	BR   callbackasm1(SB)
+	MOVD $1374, R0
+	BR   callbackasm1(SB)
+	MOVD $1375, R0
+	BR   callbackasm1(SB)
+	MOVD $1376, R0
+	BR   callbackasm1(SB)
+	MOVD $1377, R0
+	BR   callbackasm1(SB)
+	MOVD $1378, R0
+	BR   callbackasm1(SB)
+	MOVD $1379, R0
+	BR   callbackasm1(SB)
+	MOVD $1380, R0
+	BR   callbackasm1(SB)
+	MOVD $1381, R0
+	BR   callbackasm1(SB)
+	MOVD $1382, R0
+	BR   callbackasm1(SB)
+	MOVD $1383, R0
+	BR   callbackasm1(SB)
+	MOVD $1384, R0
+	BR   callbackasm1(SB)
+	MOVD $1385, R0
+	BR   callbackasm1(SB)
+	MOVD $1386, R0
+	BR   callbackasm1(SB)
+	MOVD $1387, R0
+	BR   callbackasm1(SB)
+	MOVD $1388, R0
+	BR   callbackasm1(SB)
+	MOVD $1389, R0
+	BR   callbackasm1(SB)
+	MOVD $1390, R0
+	BR   callbackasm1(SB)
+	MOVD $1391, R0
+	BR   callbackasm1(SB)
+	MOVD $1392, R0
+	BR   callbackasm1(SB)
+	MOVD $1393, R0
+	BR   callbackasm1(SB)
+	MOVD $1394, R0
+	BR   callbackasm1(SB)
+	MOVD $1395, R0
+	BR   callbackasm1(SB)
+	MOVD $1396, R0
+	BR   callbackasm1(SB)
+	MOVD $1397, R0
+	BR   callbackasm1(SB)
+	MOVD $1398, R0
+	BR   callbackasm1(SB)
+	MOVD $1399, R0
+	BR   callbackasm1(SB)
+	MOVD $1400, R0
+	BR   callbackasm1(SB)
+	MOVD $1401, R0
+	BR   callbackasm1(SB)
+	MOVD $1402, R0
+	BR   callbackasm1(SB)
+	MOVD $1403, R0
+	BR   callbackasm1(SB)
+	MOVD $1404, R0
+	BR   callbackasm1(SB)
+	MOVD $1405, R0
+	BR   callbackasm1(SB)
+	MOVD $1406, R0
+	BR   callbackasm1(SB)
+	MOVD $1407, R0
+	BR   callbackasm1(SB)
+	MOVD $1408, R0
+	BR   callbackasm1(SB)
+	MOVD $1409, R0
+	BR   callbackasm1(SB)
+	MOVD $1410, R0
+	BR   callbackasm1(SB)
+	MOVD $1411, R0
+	BR   callbackasm1(SB)
+	MOVD $1412, R0
+	BR   callbackasm1(SB)
+	MOVD $1413, R0
+	BR   callbackasm1(SB)
+	MOVD $1414, R0
+	BR   callbackasm1(SB)
+	MOVD $1415, R0
+	BR   callbackasm1(SB)
+	MOVD $1416, R0
+	BR   callbackasm1(SB)
+	MOVD $1417, R0
+	BR   callbackasm1(SB)
+	MOVD $1418, R0
+	BR   callbackasm1(SB)
+	MOVD $1419, R0
+	BR   callbackasm1(SB)
+	MOVD $1420, R0
+	BR   callbackasm1(SB)
+	MOVD $1421, R0
+	BR   callbackasm1(SB)
+	MOVD $1422, R0
+	BR   callbackasm1(SB)
+	MOVD $1423, R0
+	BR   callbackasm1(SB)
+	MOVD $1424, R0
+	BR   callbackasm1(SB)
+	MOVD $1425, R0
+	BR   callbackasm1(SB)
+	MOVD $1426, R0
+	BR   callbackasm1(SB)
+	MOVD $1427, R0
+	BR   callbackasm1(SB)
+	MOVD $1428, R0
+	BR   callbackasm1(SB)
+	MOVD $1429, R0
+	BR   callbackasm1(SB)
+	MOVD $1430, R0
+	BR   callbackasm1(SB)
+	MOVD $1431, R0
+	BR   callbackasm1(SB)
+	MOVD $1432, R0
+	BR   callbackasm1(SB)
+	MOVD $1433, R0
+	BR   callbackasm1(SB)
+	MOVD $1434, R0
+	BR   callbackasm1(SB)
+	MOVD $1435, R0
+	BR   callbackasm1(SB)
+	MOVD $1436, R0
+	BR   callbackasm1(SB)
+	MOVD $1437, R0
+	BR   callbackasm1(SB)
+	MOVD $1438, R0
+	BR   callbackasm1(SB)
+	MOVD $1439, R0
+	BR   callbackasm1(SB)
+	MOVD $1440, R0
+	BR   callbackasm1(SB)
+	MOVD $1441, R0
+	BR   callbackasm1(SB)
+	MOVD $1442, R0
+	BR   callbackasm1(SB)
+	MOVD $1443, R0
+	BR   callbackasm1(SB)
+	MOVD $1444, R0
+	BR   callbackasm1(SB)
+	MOVD $1445, R0
+	BR   callbackasm1(SB)
+	MOVD $1446, R0
+	BR   callbackasm1(SB)
+	MOVD $1447, R0
+	BR   callbackasm1(SB)
+	MOVD $1448, R0
+	BR   callbackasm1(SB)
+	MOVD $1449, R0
+	BR   callbackasm1(SB)
+	MOVD $1450, R0
+	BR   callbackasm1(SB)
+	MOVD $1451, R0
+	BR   callbackasm1(SB)
+	MOVD $1452, R0
+	BR   callbackasm1(SB)
+	MOVD $1453, R0
+	BR   callbackasm1(SB)
+	MOVD $1454, R0
+	BR   callbackasm1(SB)
+	MOVD $1455, R0
+	BR   callbackasm1(SB)
+	MOVD $1456, R0
+	BR   callbackasm1(SB)
+	MOVD $1457, R0
+	BR   callbackasm1(SB)
+	MOVD $1458, R0
+	BR   callbackasm1(SB)
+	MOVD $1459, R0
+	BR   callbackasm1(SB)
+	MOVD $1460, R0
+	BR   callbackasm1(SB)
+	MOVD $1461, R0
+	BR   callbackasm1(SB)
+	MOVD $1462, R0
+	BR   callbackasm1(SB)
+	MOVD $1463, R0
+	BR   callbackasm1(SB)
+	MOVD $1464, R0
+	BR   callbackasm1(SB)
+	MOVD $1465, R0
+	BR   callbackasm1(SB)
+	MOVD $1466, R0
+	BR   callbackasm1(SB)
+	MOVD $1467, R0
+	BR   callbackasm1(SB)
+	MOVD $1468, R0
+	BR   callbackasm1(SB)
+	MOVD $1469, R0
+	BR   callbackasm1(SB)
+	MOVD $1470, R0
+	BR   callbackasm1(SB)
+	MOVD $1471, R0
+	BR   callbackasm1(SB)
+	MOVD $1472, R0
+	BR   callbackasm1(SB)
+	MOVD $1473, R0
+	BR   callbackasm1(SB)
+	MOVD $1474, R0
+	BR   callbackasm1(SB)
+	MOVD $1475, R0
+	BR   callbackasm1(SB)
+	MOVD $1476, R0
+	BR   callbackasm1(SB)
+	MOVD $1477, R0
+	BR   callbackasm1(SB)
+	MOVD $1478, R0
+	BR   callbackasm1(SB)
+	MOVD $1479, R0
+	BR   callbackasm1(SB)
+	MOVD $1480, R0
+	BR   callbackasm1(SB)
+	MOVD $1481, R0
+	BR   callbackasm1(SB)
+	MOVD $1482, R0
+	BR   callbackasm1(SB)
+	MOVD $1483, R0
+	BR   callbackasm1(SB)
+	MOVD $1484, R0
+	BR   callbackasm1(SB)
+	MOVD $1485, R0
+	BR   callbackasm1(SB)
+	MOVD $1486, R0
+	BR   callbackasm1(SB)
+	MOVD $1487, R0
+	BR   callbackasm1(SB)
+	MOVD $1488, R0
+	BR   callbackasm1(SB)
+	MOVD $1489, R0
+	BR   callbackasm1(SB)
+	MOVD $1490, R0
+	BR   callbackasm1(SB)
+	MOVD $1491, R0
+	BR   callbackasm1(SB)
+	MOVD $1492, R0
+	BR   callbackasm1(SB)
+	MOVD $1493, R0
+	BR   callbackasm1(SB)
+	MOVD $1494, R0
+	BR   callbackasm1(SB)
+	MOVD $1495, R0
+	BR   callbackasm1(SB)
+	MOVD $1496, R0
+	BR   callbackasm1(SB)
+	MOVD $1497, R0
+	BR   callbackasm1(SB)
+	MOVD $1498, R0
+	BR   callbackasm1(SB)
+	MOVD $1499, R0
+	BR   callbackasm1(SB)
+	MOVD $1500, R0
+	BR   callbackasm1(SB)
+	MOVD $1501, R0
+	BR   callbackasm1(SB)
+	MOVD $1502, R0
+	BR   callbackasm1(SB)
+	MOVD $1503, R0
+	BR   callbackasm1(SB)
+	MOVD $1504, R0
+	BR   callbackasm1(SB)
+	MOVD $1505, R0
+	BR   callbackasm1(SB)
+	MOVD $1506, R0
+	BR   callbackasm1(SB)
+	MOVD $1507, R0
+	BR   callbackasm1(SB)
+	MOVD $1508, R0
+	BR   callbackasm1(SB)
+	MOVD $1509, R0
+	BR   callbackasm1(SB)
+	MOVD $1510, R0
+	BR   callbackasm1(SB)
+	MOVD $1511, R0
+	BR   callbackasm1(SB)
+	MOVD $1512, R0
+	BR   callbackasm1(SB)
+	MOVD $1513, R0
+	BR   callbackasm1(SB)
+	MOVD $1514, R0
+	BR   callbackasm1(SB)
+	MOVD $1515, R0
+	BR   callbackasm1(SB)
+	MOVD $1516, R0
+	BR   callbackasm1(SB)
+	MOVD $1517, R0
+	BR   callbackasm1(SB)
+	MOVD $1518, R0
+	BR   callbackasm1(SB)
+	MOVD $1519, R0
+	BR   callbackasm1(SB)
+	MOVD $1520, R0
+	BR   callbackasm1(SB)
+	MOVD $1521, R0
+	BR   callbackasm1(SB)
+	MOVD $1522, R0
+	BR   callbackasm1(SB)
+	MOVD $1523, R0
+	BR   callbackasm1(SB)
+	MOVD $1524, R0
+	BR   callbackasm1(SB)
+	MOVD $1525, R0
+	BR   callbackasm1(SB)
+	MOVD $1526, R0
+	BR   callbackasm1(SB)
+	MOVD $1527, R0
+	BR   callbackasm1(SB)
+	MOVD $1528, R0
+	BR   callbackasm1(SB)
+	MOVD $1529, R0
+	BR   callbackasm1(SB)
+	MOVD $1530, R0
+	BR   callbackasm1(SB)
+	MOVD $1531, R0
+	BR   callbackasm1(SB)
+	MOVD $1532, R0
+	BR   callbackasm1(SB)
+	MOVD $1533, R0
+	BR   callbackasm1(SB)
+	MOVD $1534, R0
+	BR   callbackasm1(SB)
+	MOVD $1535, R0
+	BR   callbackasm1(SB)
+	MOVD $1536, R0
+	BR   callbackasm1(SB)
+	MOVD $1537, R0
+	BR   callbackasm1(SB)
+	MOVD $1538, R0
+	BR   callbackasm1(SB)
+	MOVD $1539, R0
+	BR   callbackasm1(SB)
+	MOVD $1540, R0
+	BR   callbackasm1(SB)
+	MOVD $1541, R0
+	BR   callbackasm1(SB)
+	MOVD $1542, R0
+	BR   callbackasm1(SB)
+	MOVD $1543, R0
+	BR   callbackasm1(SB)
+	MOVD $1544, R0
+	BR   callbackasm1(SB)
+	MOVD $1545, R0
+	BR   callbackasm1(SB)
+	MOVD $1546, R0
+	BR   callbackasm1(SB)
+	MOVD $1547, R0
+	BR   callbackasm1(SB)
+	MOVD $1548, R0
+	BR   callbackasm1(SB)
+	MOVD $1549, R0
+	BR   callbackasm1(SB)
+	MOVD $1550, R0
+	BR   callbackasm1(SB)
+	MOVD $1551, R0
+	BR   callbackasm1(SB)
+	MOVD $1552, R0
+	BR   callbackasm1(SB)
+	MOVD $1553, R0
+	BR   callbackasm1(SB)
+	MOVD $1554, R0
+	BR   callbackasm1(SB)
+	MOVD $1555, R0
+	BR   callbackasm1(SB)
+	MOVD $1556, R0
+	BR   callbackasm1(SB)
+	MOVD $1557, R0
+	BR   callbackasm1(SB)
+	MOVD $1558, R0
+	BR   callbackasm1(SB)
+	MOVD $1559, R0
+	BR   callbackasm1(SB)
+	MOVD $1560, R0
+	BR   callbackasm1(SB)
+	MOVD $1561, R0
+	BR   callbackasm1(SB)
+	MOVD $1562, R0
+	BR   callbackasm1(SB)
+	MOVD $1563, R0
+	BR   callbackasm1(SB)
+	MOVD $1564, R0
+	BR   callbackasm1(SB)
+	MOVD $1565, R0
+	BR   callbackasm1(SB)
+	MOVD $1566, R0
+	BR   callbackasm1(SB)
+	MOVD $1567, R0
+	BR   callbackasm1(SB)
+	MOVD $1568, R0
+	BR   callbackasm1(SB)
+	MOVD $1569, R0
+	BR   callbackasm1(SB)
+	MOVD $1570, R0
+	BR   callbackasm1(SB)
+	MOVD $1571, R0
+	BR   callbackasm1(SB)
+	MOVD $1572, R0
+	BR   callbackasm1(SB)
+	MOVD $1573, R0
+	BR   callbackasm1(SB)
+	MOVD $1574, R0
+	BR   callbackasm1(SB)
+	MOVD $1575, R0
+	BR   callbackasm1(SB)
+	MOVD $1576, R0
+	BR   callbackasm1(SB)
+	MOVD $1577, R0
+	BR   callbackasm1(SB)
+	MOVD $1578, R0
+	BR   callbackasm1(SB)
+	MOVD $1579, R0
+	BR   callbackasm1(SB)
+	MOVD $1580, R0
+	BR   callbackasm1(SB)
+	MOVD $1581, R0
+	BR   callbackasm1(SB)
+	MOVD $1582, R0
+	BR   callbackasm1(SB)
+	MOVD $1583, R0
+	BR   callbackasm1(SB)
+	MOVD $1584, R0
+	BR   callbackasm1(SB)
+	MOVD $1585, R0
+	BR   callbackasm1(SB)
+	MOVD $1586, R0
+	BR   callbackasm1(SB)
+	MOVD $1587, R0
+	BR   callbackasm1(SB)
+	MOVD $1588, R0
+	BR   callbackasm1(SB)
+	MOVD $1589, R0
+	BR   callbackasm1(SB)
+	MOVD $1590, R0
+	BR   callbackasm1(SB)
+	MOVD $1591, R0
+	BR   callbackasm1(SB)
+	MOVD $1592, R0
+	BR   callbackasm1(SB)
+	MOVD $1593, R0
+	BR   callbackasm1(SB)
+	MOVD $1594, R0
+	BR   callbackasm1(SB)
+	MOVD $1595, R0
+	BR   callbackasm1(SB)
+	MOVD $1596, R0
+	BR   callbackasm1(SB)
+	MOVD $1597, R0
+	BR   callbackasm1(SB)
+	MOVD $1598, R0
+	BR   callbackasm1(SB)
+	MOVD $1599, R0
+	BR   callbackasm1(SB)
+	MOVD $1600, R0
+	BR   callbackasm1(SB)
+	MOVD $1601, R0
+	BR   callbackasm1(SB)
+	MOVD $1602, R0
+	BR   callbackasm1(SB)
+	MOVD $1603, R0
+	BR   callbackasm1(SB)
+	MOVD $1604, R0
+	BR   callbackasm1(SB)
+	MOVD $1605, R0
+	BR   callbackasm1(SB)
+	MOVD $1606, R0
+	BR   callbackasm1(SB)
+	MOVD $1607, R0
+	BR   callbackasm1(SB)
+	MOVD $1608, R0
+	BR   callbackasm1(SB)
+	MOVD $1609, R0
+	BR   callbackasm1(SB)
+	MOVD $1610, R0
+	BR   callbackasm1(SB)
+	MOVD $1611, R0
+	BR   callbackasm1(SB)
+	MOVD $1612, R0
+	BR   callbackasm1(SB)
+	MOVD $1613, R0
+	BR   callbackasm1(SB)
+	MOVD $1614, R0
+	BR   callbackasm1(SB)
+	MOVD $1615, R0
+	BR   callbackasm1(SB)
+	MOVD $1616, R0
+	BR   callbackasm1(SB)
+	MOVD $1617, R0
+	BR   callbackasm1(SB)
+	MOVD $1618, R0
+	BR   callbackasm1(SB)
+	MOVD $1619, R0
+	BR   callbackasm1(SB)
+	MOVD $1620, R0
+	BR   callbackasm1(SB)
+	MOVD $1621, R0
+	BR   callbackasm1(SB)
+	MOVD $1622, R0
+	BR   callbackasm1(SB)
+	MOVD $1623, R0
+	BR   callbackasm1(SB)
+	MOVD $1624, R0
+	BR   callbackasm1(SB)
+	MOVD $1625, R0
+	BR   callbackasm1(SB)
+	MOVD $1626, R0
+	BR   callbackasm1(SB)
+	MOVD $1627, R0
+	BR   callbackasm1(SB)
+	MOVD $1628, R0
+	BR   callbackasm1(SB)
+	MOVD $1629, R0
+	BR   callbackasm1(SB)
+	MOVD $1630, R0
+	BR   callbackasm1(SB)
+	MOVD $1631, R0
+	BR   callbackasm1(SB)
+	MOVD $1632, R0
+	BR   callbackasm1(SB)
+	MOVD $1633, R0
+	BR   callbackasm1(SB)
+	MOVD $1634, R0
+	BR   callbackasm1(SB)
+	MOVD $1635, R0
+	BR   callbackasm1(SB)
+	MOVD $1636, R0
+	BR   callbackasm1(SB)
+	MOVD $1637, R0
+	BR   callbackasm1(SB)
+	MOVD $1638, R0
+	BR   callbackasm1(SB)
+	MOVD $1639, R0
+	BR   callbackasm1(SB)
+	MOVD $1640, R0
+	BR   callbackasm1(SB)
+	MOVD $1641, R0
+	BR   callbackasm1(SB)
+	MOVD $1642, R0
+	BR   callbackasm1(SB)
+	MOVD $1643, R0
+	BR   callbackasm1(SB)
+	MOVD $1644, R0
+	BR   callbackasm1(SB)
+	MOVD $1645, R0
+	BR   callbackasm1(SB)
+	MOVD $1646, R0
+	BR   callbackasm1(SB)
+	MOVD $1647, R0
+	BR   callbackasm1(SB)
+	MOVD $1648, R0
+	BR   callbackasm1(SB)
+	MOVD $1649, R0
+	BR   callbackasm1(SB)
+	MOVD $1650, R0
+	BR   callbackasm1(SB)
+	MOVD $1651, R0
+	BR   callbackasm1(SB)
+	MOVD $1652, R0
+	BR   callbackasm1(SB)
+	MOVD $1653, R0
+	BR   callbackasm1(SB)
+	MOVD $1654, R0
+	BR   callbackasm1(SB)
+	MOVD $1655, R0
+	BR   callbackasm1(SB)
+	MOVD $1656, R0
+	BR   callbackasm1(SB)
+	MOVD $1657, R0
+	BR   callbackasm1(SB)
+	MOVD $1658, R0
+	BR   callbackasm1(SB)
+	MOVD $1659, R0
+	BR   callbackasm1(SB)
+	MOVD $1660, R0
+	BR   callbackasm1(SB)
+	MOVD $1661, R0
+	BR   callbackasm1(SB)
+	MOVD $1662, R0
+	BR   callbackasm1(SB)
+	MOVD $1663, R0
+	BR   callbackasm1(SB)
+	MOVD $1664, R0
+	BR   callbackasm1(SB)
+	MOVD $1665, R0
+	BR   callbackasm1(SB)
+	MOVD $1666, R0
+	BR   callbackasm1(SB)
+	MOVD $1667, R0
+	BR   callbackasm1(SB)
+	MOVD $1668, R0
+	BR   callbackasm1(SB)
+	MOVD $1669, R0
+	BR   callbackasm1(SB)
+	MOVD $1670, R0
+	BR   callbackasm1(SB)
+	MOVD $1671, R0
+	BR   callbackasm1(SB)
+	MOVD $1672, R0
+	BR   callbackasm1(SB)
+	MOVD $1673, R0
+	BR   callbackasm1(SB)
+	MOVD $1674, R0
+	BR   callbackasm1(SB)
+	MOVD $1675, R0
+	BR   callbackasm1(SB)
+	MOVD $1676, R0
+	BR   callbackasm1(SB)
+	MOVD $1677, R0
+	BR   callbackasm1(SB)
+	MOVD $1678, R0
+	BR   callbackasm1(SB)
+	MOVD $1679, R0
+	BR   callbackasm1(SB)
+	MOVD $1680, R0
+	BR   callbackasm1(SB)
+	MOVD $1681, R0
+	BR   callbackasm1(SB)
+	MOVD $1682, R0
+	BR   callbackasm1(SB)
+	MOVD $1683, R0
+	BR   callbackasm1(SB)
+	MOVD $1684, R0
+	BR   callbackasm1(SB)
+	MOVD $1685, R0
+	BR   callbackasm1(SB)
+	MOVD $1686, R0
+	BR   callbackasm1(SB)
+	MOVD $1687, R0
+	BR   callbackasm1(SB)
+	MOVD $1688, R0
+	BR   callbackasm1(SB)
+	MOVD $1689, R0
+	BR   callbackasm1(SB)
+	MOVD $1690, R0
+	BR   callbackasm1(SB)
+	MOVD $1691, R0
+	BR   callbackasm1(SB)
+	MOVD $1692, R0
+	BR   callbackasm1(SB)
+	MOVD $1693, R0
+	BR   callbackasm1(SB)
+	MOVD $1694, R0
+	BR   callbackasm1(SB)
+	MOVD $1695, R0
+	BR   callbackasm1(SB)
+	MOVD $1696, R0
+	BR   callbackasm1(SB)
+	MOVD $1697, R0
+	BR   callbackasm1(SB)
+	MOVD $1698, R0
+	BR   callbackasm1(SB)
+	MOVD $1699, R0
+	BR   callbackasm1(SB)
+	MOVD $1700, R0
+	BR   callbackasm1(SB)
+	MOVD $1701, R0
+	BR   callbackasm1(SB)
+	MOVD $1702, R0
+	BR   callbackasm1(SB)
+	MOVD $1703, R0
+	BR   callbackasm1(SB)
+	MOVD $1704, R0
+	BR   callbackasm1(SB)
+	MOVD $1705, R0
+	BR   callbackasm1(SB)
+	MOVD $1706, R0
+	BR   callbackasm1(SB)
+	MOVD $1707, R0
+	BR   callbackasm1(SB)
+	MOVD $1708, R0
+	BR   callbackasm1(SB)
+	MOVD $1709, R0
+	BR   callbackasm1(SB)
+	MOVD $1710, R0
+	BR   callbackasm1(SB)
+	MOVD $1711, R0
+	BR   callbackasm1(SB)
+	MOVD $1712, R0
+	BR   callbackasm1(SB)
+	MOVD $1713, R0
+	BR   callbackasm1(SB)
+	MOVD $1714, R0
+	BR   callbackasm1(SB)
+	MOVD $1715, R0
+	BR   callbackasm1(SB)
+	MOVD $1716, R0
+	BR   callbackasm1(SB)
+	MOVD $1717, R0
+	BR   callbackasm1(SB)
+	MOVD $1718, R0
+	BR   callbackasm1(SB)
+	MOVD $1719, R0
+	BR   callbackasm1(SB)
+	MOVD $1720, R0
+	BR   callbackasm1(SB)
+	MOVD $1721, R0
+	BR   callbackasm1(SB)
+	MOVD $1722, R0
+	BR   callbackasm1(SB)
+	MOVD $1723, R0
+	BR   callbackasm1(SB)
+	MOVD $1724, R0
+	BR   callbackasm1(SB)
+	MOVD $1725, R0
+	BR   callbackasm1(SB)
+	MOVD $1726, R0
+	BR   callbackasm1(SB)
+	MOVD $1727, R0
+	BR   callbackasm1(SB)
+	MOVD $1728, R0
+	BR   callbackasm1(SB)
+	MOVD $1729, R0
+	BR   callbackasm1(SB)
+	MOVD $1730, R0
+	BR   callbackasm1(SB)
+	MOVD $1731, R0
+	BR   callbackasm1(SB)
+	MOVD $1732, R0
+	BR   callbackasm1(SB)
+	MOVD $1733, R0
+	BR   callbackasm1(SB)
+	MOVD $1734, R0
+	BR   callbackasm1(SB)
+	MOVD $1735, R0
+	BR   callbackasm1(SB)
+	MOVD $1736, R0
+	BR   callbackasm1(SB)
+	MOVD $1737, R0
+	BR   callbackasm1(SB)
+	MOVD $1738, R0
+	BR   callbackasm1(SB)
+	MOVD $1739, R0
+	BR   callbackasm1(SB)
+	MOVD $1740, R0
+	BR   callbackasm1(SB)
+	MOVD $1741, R0
+	BR   callbackasm1(SB)
+	MOVD $1742, R0
+	BR   callbackasm1(SB)
+	MOVD $1743, R0
+	BR   callbackasm1(SB)
+	MOVD $1744, R0
+	BR   callbackasm1(SB)
+	MOVD $1745, R0
+	BR   callbackasm1(SB)
+	MOVD $1746, R0
+	BR   callbackasm1(SB)
+	MOVD $1747, R0
+	BR   callbackasm1(SB)
+	MOVD $1748, R0
+	BR   callbackasm1(SB)
+	MOVD $1749, R0
+	BR   callbackasm1(SB)
+	MOVD $1750, R0
+	BR   callbackasm1(SB)
+	MOVD $1751, R0
+	BR   callbackasm1(SB)
+	MOVD $1752, R0
+	BR   callbackasm1(SB)
+	MOVD $1753, R0
+	BR   callbackasm1(SB)
+	MOVD $1754, R0
+	BR   callbackasm1(SB)
+	MOVD $1755, R0
+	BR   callbackasm1(SB)
+	MOVD $1756, R0
+	BR   callbackasm1(SB)
+	MOVD $1757, R0
+	BR   callbackasm1(SB)
+	MOVD $1758, R0
+	BR   callbackasm1(SB)
+	MOVD $1759, R0
+	BR   callbackasm1(SB)
+	MOVD $1760, R0
+	BR   callbackasm1(SB)
+	MOVD $1761, R0
+	BR   callbackasm1(SB)
+	MOVD $1762, R0
+	BR   callbackasm1(SB)
+	MOVD $1763, R0
+	BR   callbackasm1(SB)
+	MOVD $1764, R0
+	BR   callbackasm1(SB)
+	MOVD $1765, R0
+	BR   callbackasm1(SB)
+	MOVD $1766, R0
+	BR   callbackasm1(SB)
+	MOVD $1767, R0
+	BR   callbackasm1(SB)
+	MOVD $1768, R0
+	BR   callbackasm1(SB)
+	MOVD $1769, R0
+	BR   callbackasm1(SB)
+	MOVD $1770, R0
+	BR   callbackasm1(SB)
+	MOVD $1771, R0
+	BR   callbackasm1(SB)
+	MOVD $1772, R0
+	BR   callbackasm1(SB)
+	MOVD $1773, R0
+	BR   callbackasm1(SB)
+	MOVD $1774, R0
+	BR   callbackasm1(SB)
+	MOVD $1775, R0
+	BR   callbackasm1(SB)
+	MOVD $1776, R0
+	BR   callbackasm1(SB)
+	MOVD $1777, R0
+	BR   callbackasm1(SB)
+	MOVD $1778, R0
+	BR   callbackasm1(SB)
+	MOVD $1779, R0
+	BR   callbackasm1(SB)
+	MOVD $1780, R0
+	BR   callbackasm1(SB)
+	MOVD $1781, R0
+	BR   callbackasm1(SB)
+	MOVD $1782, R0
+	BR   callbackasm1(SB)
+	MOVD $1783, R0
+	BR   callbackasm1(SB)
+	MOVD $1784, R0
+	BR   callbackasm1(SB)
+	MOVD $1785, R0
+	BR   callbackasm1(SB)
+	MOVD $1786, R0
+	BR   callbackasm1(SB)
+	MOVD $1787, R0
+	BR   callbackasm1(SB)
+	MOVD $1788, R0
+	BR   callbackasm1(SB)
+	MOVD $1789, R0
+	BR   callbackasm1(SB)
+	MOVD $1790, R0
+	BR   callbackasm1(SB)
+	MOVD $1791, R0
+	BR   callbackasm1(SB)
+	MOVD $1792, R0
+	BR   callbackasm1(SB)
+	MOVD $1793, R0
+	BR   callbackasm1(SB)
+	MOVD $1794, R0
+	BR   callbackasm1(SB)
+	MOVD $1795, R0
+	BR   callbackasm1(SB)
+	MOVD $1796, R0
+	BR   callbackasm1(SB)
+	MOVD $1797, R0
+	BR   callbackasm1(SB)
+	MOVD $1798, R0
+	BR   callbackasm1(SB)
+	MOVD $1799, R0
+	BR   callbackasm1(SB)
+	MOVD $1800, R0
+	BR   callbackasm1(SB)
+	MOVD $1801, R0
+	BR   callbackasm1(SB)
+	MOVD $1802, R0
+	BR   callbackasm1(SB)
+	MOVD $1803, R0
+	BR   callbackasm1(SB)
+	MOVD $1804, R0
+	BR   callbackasm1(SB)
+	MOVD $1805, R0
+	BR   callbackasm1(SB)
+	MOVD $1806, R0
+	BR   callbackasm1(SB)
+	MOVD $1807, R0
+	BR   callbackasm1(SB)
+	MOVD $1808, R0
+	BR   callbackasm1(SB)
+	MOVD $1809, R0
+	BR   callbackasm1(SB)
+	MOVD $1810, R0
+	BR   callbackasm1(SB)
+	MOVD $1811, R0
+	BR   callbackasm1(SB)
+	MOVD $1812, R0
+	BR   callbackasm1(SB)
+	MOVD $1813, R0
+	BR   callbackasm1(SB)
+	MOVD $1814, R0
+	BR   callbackasm1(SB)
+	MOVD $1815, R0
+	BR   callbackasm1(SB)
+	MOVD $1816, R0
+	BR   callbackasm1(SB)
+	MOVD $1817, R0
+	BR   callbackasm1(SB)
+	MOVD $1818, R0
+	BR   callbackasm1(SB)
+	MOVD $1819, R0
+	BR   callbackasm1(SB)
+	MOVD $1820, R0
+	BR   callbackasm1(SB)
+	MOVD $1821, R0
+	BR   callbackasm1(SB)
+	MOVD $1822, R0
+	BR   callbackasm1(SB)
+	MOVD $1823, R0
+	BR   callbackasm1(SB)
+	MOVD $1824, R0
+	BR   callbackasm1(SB)
+	MOVD $1825, R0
+	BR   callbackasm1(SB)
+	MOVD $1826, R0
+	BR   callbackasm1(SB)
+	MOVD $1827, R0
+	BR   callbackasm1(SB)
+	MOVD $1828, R0
+	BR   callbackasm1(SB)
+	MOVD $1829, R0
+	BR   callbackasm1(SB)
+	MOVD $1830, R0
+	BR   callbackasm1(SB)
+	MOVD $1831, R0
+	BR   callbackasm1(SB)
+	MOVD $1832, R0
+	BR   callbackasm1(SB)
+	MOVD $1833, R0
+	BR   callbackasm1(SB)
+	MOVD $1834, R0
+	BR   callbackasm1(SB)
+	MOVD $1835, R0
+	BR   callbackasm1(SB)
+	MOVD $1836, R0
+	BR   callbackasm1(SB)
+	MOVD $1837, R0
+	BR   callbackasm1(SB)
+	MOVD $1838, R0
+	BR   callbackasm1(SB)
+	MOVD $1839, R0
+	BR   callbackasm1(SB)
+	MOVD $1840, R0
+	BR   callbackasm1(SB)
+	MOVD $1841, R0
+	BR   callbackasm1(SB)
+	MOVD $1842, R0
+	BR   callbackasm1(SB)
+	MOVD $1843, R0
+	BR   callbackasm1(SB)
+	MOVD $1844, R0
+	BR   callbackasm1(SB)
+	MOVD $1845, R0
+	BR   callbackasm1(SB)
+	MOVD $1846, R0
+	BR   callbackasm1(SB)
+	MOVD $1847, R0
+	BR   callbackasm1(SB)
+	MOVD $1848, R0
+	BR   callbackasm1(SB)
+	MOVD $1849, R0
+	BR   callbackasm1(SB)
+	MOVD $1850, R0
+	BR   callbackasm1(SB)
+	MOVD $1851, R0
+	BR   callbackasm1(SB)
+	MOVD $1852, R0
+	BR   callbackasm1(SB)
+	MOVD $1853, R0
+	BR   callbackasm1(SB)
+	MOVD $1854, R0
+	BR   callbackasm1(SB)
+	MOVD $1855, R0
+	BR   callbackasm1(SB)
+	MOVD $1856, R0
+	BR   callbackasm1(SB)
+	MOVD $1857, R0
+	BR   callbackasm1(SB)
+	MOVD $1858, R0
+	BR   callbackasm1(SB)
+	MOVD $1859, R0
+	BR   callbackasm1(SB)
+	MOVD $1860, R0
+	BR   callbackasm1(SB)
+	MOVD $1861, R0
+	BR   callbackasm1(SB)
+	MOVD $1862, R0
+	BR   callbackasm1(SB)
+	MOVD $1863, R0
+	BR   callbackasm1(SB)
+	MOVD $1864, R0
+	BR   callbackasm1(SB)
+	MOVD $1865, R0
+	BR   callbackasm1(SB)
+	MOVD $1866, R0
+	BR   callbackasm1(SB)
+	MOVD $1867, R0
+	BR   callbackasm1(SB)
+	MOVD $1868, R0
+	BR   callbackasm1(SB)
+	MOVD $1869, R0
+	BR   callbackasm1(SB)
+	MOVD $1870, R0
+	BR   callbackasm1(SB)
+	MOVD $1871, R0
+	BR   callbackasm1(SB)
+	MOVD $1872, R0
+	BR   callbackasm1(SB)
+	MOVD $1873, R0
+	BR   callbackasm1(SB)
+	MOVD $1874, R0
+	BR   callbackasm1(SB)
+	MOVD $1875, R0
+	BR   callbackasm1(SB)
+	MOVD $1876, R0
+	BR   callbackasm1(SB)
+	MOVD $1877, R0
+	BR   callbackasm1(SB)
+	MOVD $1878, R0
+	BR   callbackasm1(SB)
+	MOVD $1879, R0
+	BR   callbackasm1(SB)
+	MOVD $1880, R0
+	BR   callbackasm1(SB)
+	MOVD $1881, R0
+	BR   callbackasm1(SB)
+	MOVD $1882, R0
+	BR   callbackasm1(SB)
+	MOVD $1883, R0
+	BR   callbackasm1(SB)
+	MOVD $1884, R0
+	BR   callbackasm1(SB)
+	MOVD $1885, R0
+	BR   callbackasm1(SB)
+	MOVD $1886, R0
+	BR   callbackasm1(SB)
+	MOVD $1887, R0
+	BR   callbackasm1(SB)
+	MOVD $1888, R0
+	BR   callbackasm1(SB)
+	MOVD $1889, R0
+	BR   callbackasm1(SB)
+	MOVD $1890, R0
+	BR   callbackasm1(SB)
+	MOVD $1891, R0
+	BR   callbackasm1(SB)
+	MOVD $1892, R0
+	BR   callbackasm1(SB)
+	MOVD $1893, R0
+	BR   callbackasm1(SB)
+	MOVD $1894, R0
+	BR   callbackasm1(SB)
+	MOVD $1895, R0
+	BR   callbackasm1(SB)
+	MOVD $1896, R0
+	BR   callbackasm1(SB)
+	MOVD $1897, R0
+	BR   callbackasm1(SB)
+	MOVD $1898, R0
+	BR   callbackasm1(SB)
+	MOVD $1899, R0
+	BR   callbackasm1(SB)
+	MOVD $1900, R0
+	BR   callbackasm1(SB)
+	MOVD $1901, R0
+	BR   callbackasm1(SB)
+	MOVD $1902, R0
+	BR   callbackasm1(SB)
+	MOVD $1903, R0
+	BR   callbackasm1(SB)
+	MOVD $1904, R0
+	BR   callbackasm1(SB)
+	MOVD $1905, R0
+	BR   callbackasm1(SB)
+	MOVD $1906, R0
+	BR   callbackasm1(SB)
+	MOVD $1907, R0
+	BR   callbackasm1(SB)
+	MOVD $1908, R0
+	BR   callbackasm1(SB)
+	MOVD $1909, R0
+	BR   callbackasm1(SB)
+	MOVD $1910, R0
+	BR   callbackasm1(SB)
+	MOVD $1911, R0
+	BR   callbackasm1(SB)
+	MOVD $1912, R0
+	BR   callbackasm1(SB)
+	MOVD $1913, R0
+	BR   callbackasm1(SB)
+	MOVD $1914, R0
+	BR   callbackasm1(SB)
+	MOVD $1915, R0
+	BR   callbackasm1(SB)
+	MOVD $1916, R0
+	BR   callbackasm1(SB)
+	MOVD $1917, R0
+	BR   callbackasm1(SB)
+	MOVD $1918, R0
+	BR   callbackasm1(SB)
+	MOVD $1919, R0
+	BR   callbackasm1(SB)
+	MOVD $1920, R0
+	BR   callbackasm1(SB)
+	MOVD $1921, R0
+	BR   callbackasm1(SB)
+	MOVD $1922, R0
+	BR   callbackasm1(SB)
+	MOVD $1923, R0
+	BR   callbackasm1(SB)
+	MOVD $1924, R0
+	BR   callbackasm1(SB)
+	MOVD $1925, R0
+	BR   callbackasm1(SB)
+	MOVD $1926, R0
+	BR   callbackasm1(SB)
+	MOVD $1927, R0
+	BR   callbackasm1(SB)
+	MOVD $1928, R0
+	BR   callbackasm1(SB)
+	MOVD $1929, R0
+	BR   callbackasm1(SB)
+	MOVD $1930, R0
+	BR   callbackasm1(SB)
+	MOVD $1931, R0
+	BR   callbackasm1(SB)
+	MOVD $1932, R0
+	BR   callbackasm1(SB)
+	MOVD $1933, R0
+	BR   callbackasm1(SB)
+	MOVD $1934, R0
+	BR   callbackasm1(SB)
+	MOVD $1935, R0
+	BR   callbackasm1(SB)
+	MOVD $1936, R0
+	BR   callbackasm1(SB)
+	MOVD $1937, R0
+	BR   callbackasm1(SB)
+	MOVD $1938, R0
+	BR   callbackasm1(SB)
+	MOVD $1939, R0
+	BR   callbackasm1(SB)
+	MOVD $1940, R0
+	BR   callbackasm1(SB)
+	MOVD $1941, R0
+	BR   callbackasm1(SB)
+	MOVD $1942, R0
+	BR   callbackasm1(SB)
+	MOVD $1943, R0
+	BR   callbackasm1(SB)
+	MOVD $1944, R0
+	BR   callbackasm1(SB)
+	MOVD $1945, R0
+	BR   callbackasm1(SB)
+	MOVD $1946, R0
+	BR   callbackasm1(SB)
+	MOVD $1947, R0
+	BR   callbackasm1(SB)
+	MOVD $1948, R0
+	BR   callbackasm1(SB)
+	MOVD $1949, R0
+	BR   callbackasm1(SB)
+	MOVD $1950, R0
+	BR   callbackasm1(SB)
+	MOVD $1951, R0
+	BR   callbackasm1(SB)
+	MOVD $1952, R0
+	BR   callbackasm1(SB)
+	MOVD $1953, R0
+	BR   callbackasm1(SB)
+	MOVD $1954, R0
+	BR   callbackasm1(SB)
+	MOVD $1955, R0
+	BR   callbackasm1(SB)
+	MOVD $1956, R0
+	BR   callbackasm1(SB)
+	MOVD $1957, R0
+	BR   callbackasm1(SB)
+	MOVD $1958, R0
+	BR   callbackasm1(SB)
+	MOVD $1959, R0
+	BR   callbackasm1(SB)
+	MOVD $1960, R0
+	BR   callbackasm1(SB)
+	MOVD $1961, R0
+	BR   callbackasm1(SB)
+	MOVD $1962, R0
+	BR   callbackasm1(SB)
+	MOVD $1963, R0
+	BR   callbackasm1(SB)
+	MOVD $1964, R0
+	BR   callbackasm1(SB)
+	MOVD $1965, R0
+	BR   callbackasm1(SB)
+	MOVD $1966, R0
+	BR   callbackasm1(SB)
+	MOVD $1967, R0
+	BR   callbackasm1(SB)
+	MOVD $1968, R0
+	BR   callbackasm1(SB)
+	MOVD $1969, R0
+	BR   callbackasm1(SB)
+	MOVD $1970, R0
+	BR   callbackasm1(SB)
+	MOVD $1971, R0
+	BR   callbackasm1(SB)
+	MOVD $1972, R0
+	BR   callbackasm1(SB)
+	MOVD $1973, R0
+	BR   callbackasm1(SB)
+	MOVD $1974, R0
+	BR   callbackasm1(SB)
+	MOVD $1975, R0
+	BR   callbackasm1(SB)
+	MOVD $1976, R0
+	BR   callbackasm1(SB)
+	MOVD $1977, R0
+	BR   callbackasm1(SB)
+	MOVD $1978, R0
+	BR   callbackasm1(SB)
+	MOVD $1979, R0
+	BR   callbackasm1(SB)
+	MOVD $1980, R0
+	BR   callbackasm1(SB)
+	MOVD $1981, R0
+	BR   callbackasm1(SB)
+	MOVD $1982, R0
+	BR   callbackasm1(SB)
+	MOVD $1983, R0
+	BR   callbackasm1(SB)
+	MOVD $1984, R0
+	BR   callbackasm1(SB)
+	MOVD $1985, R0
+	BR   callbackasm1(SB)
+	MOVD $1986, R0
+	BR   callbackasm1(SB)
+	MOVD $1987, R0
+	BR   callbackasm1(SB)
+	MOVD $1988, R0
+	BR   callbackasm1(SB)
+	MOVD $1989, R0
+	BR   callbackasm1(SB)
+	MOVD $1990, R0
+	BR   callbackasm1(SB)
+	MOVD $1991, R0
+	BR   callbackasm1(SB)
+	MOVD $1992, R0
+	BR   callbackasm1(SB)
+	MOVD $1993, R0
+	BR   callbackasm1(SB)
+	MOVD $1994, R0
+	BR   callbackasm1(SB)
+	MOVD $1995, R0
+	BR   callbackasm1(SB)
+	MOVD $1996, R0
+	BR   callbackasm1(SB)
+	MOVD $1997, R0
+	BR   callbackasm1(SB)
+	MOVD $1998, R0
+	BR   callbackasm1(SB)
+	MOVD $1999, R0
+	BR   callbackasm1(SB)
diff --git a/vendor/github.com/jackc/pgpassfile/.travis.yml b/vendor/github.com/jackc/pgpassfile/.travis.yml
new file mode 100644
index 000000000..e176228e8
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+
+go:
+  - 1.x
+  - tip
+
+matrix:
+  allow_failures:
+    - go: tip
diff --git a/vendor/github.com/jackc/pgpassfile/LICENSE b/vendor/github.com/jackc/pgpassfile/LICENSE
new file mode 100644
index 000000000..c1c4f50fc
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2019 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgpassfile/README.md b/vendor/github.com/jackc/pgpassfile/README.md
new file mode 100644
index 000000000..661289ed8
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/README.md
@@ -0,0 +1,8 @@
+[![](https://godoc.org/github.com/jackc/pgpassfile?status.svg)](https://godoc.org/github.com/jackc/pgpassfile)
+[![Build Status](https://travis-ci.org/jackc/pgpassfile.svg)](https://travis-ci.org/jackc/pgpassfile)
+
+# pgpassfile
+
+Package pgpassfile is a parser PostgreSQL .pgpass files.
+
+Extracted and rewritten from original implementation in https://github.com/jackc/pgx.
diff --git a/vendor/github.com/jackc/pgpassfile/pgpass.go b/vendor/github.com/jackc/pgpassfile/pgpass.go
new file mode 100644
index 000000000..f7eed3c84
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/pgpass.go
@@ -0,0 +1,110 @@
+// Package pgpassfile is a parser PostgreSQL .pgpass files.
+package pgpassfile
+
+import (
+	"bufio"
+	"io"
+	"os"
+	"regexp"
+	"strings"
+)
+
+// Entry represents a line in a PG passfile.
+type Entry struct {
+	Hostname string
+	Port     string
+	Database string
+	Username string
+	Password string
+}
+
+// Passfile is the in memory data structure representing a PG passfile.
+type Passfile struct {
+	Entries []*Entry
+}
+
+// ReadPassfile reads the file at path and parses it into a Passfile.
+func ReadPassfile(path string) (*Passfile, error) {
+	f, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	return ParsePassfile(f)
+}
+
+// ParsePassfile reads r and parses it into a Passfile.
+func ParsePassfile(r io.Reader) (*Passfile, error) {
+	passfile := &Passfile{}
+
+	scanner := bufio.NewScanner(r)
+	for scanner.Scan() {
+		entry := parseLine(scanner.Text())
+		if entry != nil {
+			passfile.Entries = append(passfile.Entries, entry)
+		}
+	}
+
+	return passfile, scanner.Err()
+}
+
+// Match (not colons or escaped colon or escaped backslash)+. Essentially gives a split on unescaped
+// colon.
+var colonSplitterRegexp = regexp.MustCompile("(([^:]|(\\:)))+")
+
+// var colonSplitterRegexp = regexp.MustCompile("((?:[^:]|(?:\\:)|(?:\\\\))+)")
+
+// parseLine parses a line into an *Entry. It returns nil on comment lines or any other unparsable
+// line.
+func parseLine(line string) *Entry {
+	const (
+		tmpBackslash = "\r"
+		tmpColon     = "\n"
+	)
+
+	line = strings.TrimSpace(line)
+
+	if strings.HasPrefix(line, "#") {
+		return nil
+	}
+
+	line = strings.Replace(line, `\\`, tmpBackslash, -1)
+	line = strings.Replace(line, `\:`, tmpColon, -1)
+
+	parts := strings.Split(line, ":")
+	if len(parts) != 5 {
+		return nil
+	}
+
+	// Unescape escaped colons and backslashes
+	for i := range parts {
+		parts[i] = strings.Replace(parts[i], tmpBackslash, `\`, -1)
+		parts[i] = strings.Replace(parts[i], tmpColon, `:`, -1)
+	}
+
+	return &Entry{
+		Hostname: parts[0],
+		Port:     parts[1],
+		Database: parts[2],
+		Username: parts[3],
+		Password: parts[4],
+	}
+}
+
+// FindPassword finds the password for the provided hostname, port, database, and username. For a
+// Unix domain socket hostname must be set to "localhost". An empty string will be returned if no
+// match is found.
+//
+// See https://www.postgresql.org/docs/current/libpq-pgpass.html for more password file information.
+func (pf *Passfile) FindPassword(hostname, port, database, username string) (password string) {
+	for _, e := range pf.Entries {
+		if (e.Hostname == "*" || e.Hostname == hostname) &&
+			(e.Port == "*" || e.Port == port) &&
+			(e.Database == "*" || e.Database == database) &&
+			(e.Username == "*" || e.Username == username) {
+			return e.Password
+		}
+	}
+	return ""
+}
diff --git a/vendor/github.com/jackc/pgservicefile/LICENSE b/vendor/github.com/jackc/pgservicefile/LICENSE
new file mode 100644
index 000000000..f1b4c2892
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2020 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgservicefile/README.md b/vendor/github.com/jackc/pgservicefile/README.md
new file mode 100644
index 000000000..2fc7e012c
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/README.md
@@ -0,0 +1,7 @@
+[![Go Reference](https://pkg.go.dev/badge/github.com/jackc/pgservicefile.svg)](https://pkg.go.dev/github.com/jackc/pgservicefile)
+[![Build Status](https://github.com/jackc/pgservicefile/actions/workflows/ci.yml/badge.svg)](https://github.com/jackc/pgservicefile/actions/workflows/ci.yml)
+
+
+# pgservicefile
+
+Package pgservicefile is a parser for PostgreSQL service files (e.g. `.pg_service.conf`).
diff --git a/vendor/github.com/jackc/pgservicefile/pgservicefile.go b/vendor/github.com/jackc/pgservicefile/pgservicefile.go
new file mode 100644
index 000000000..c62caa7fe
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/pgservicefile.go
@@ -0,0 +1,81 @@
+// Package pgservicefile is a parser for PostgreSQL service files (e.g. .pg_service.conf).
+package pgservicefile
+
+import (
+	"bufio"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+)
+
+type Service struct {
+	Name     string
+	Settings map[string]string
+}
+
+type Servicefile struct {
+	Services       []*Service
+	servicesByName map[string]*Service
+}
+
+// GetService returns the named service.
+func (sf *Servicefile) GetService(name string) (*Service, error) {
+	service, present := sf.servicesByName[name]
+	if !present {
+		return nil, errors.New("not found")
+	}
+	return service, nil
+}
+
+// ReadServicefile reads the file at path and parses it into a Servicefile.
+func ReadServicefile(path string) (*Servicefile, error) {
+	f, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	return ParseServicefile(f)
+}
+
+// ParseServicefile reads r and parses it into a Servicefile.
+func ParseServicefile(r io.Reader) (*Servicefile, error) {
+	servicefile := &Servicefile{}
+
+	var service *Service
+	scanner := bufio.NewScanner(r)
+	lineNum := 0
+	for scanner.Scan() {
+		lineNum += 1
+		line := scanner.Text()
+		line = strings.TrimSpace(line)
+
+		if line == "" || strings.HasPrefix(line, "#") {
+			// ignore comments and empty lines
+		} else if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
+			service = &Service{Name: line[1 : len(line)-1], Settings: make(map[string]string)}
+			servicefile.Services = append(servicefile.Services, service)
+		} else if service != nil {
+			parts := strings.SplitN(line, "=", 2)
+			if len(parts) != 2 {
+				return nil, fmt.Errorf("unable to parse line %d", lineNum)
+			}
+
+			key := strings.TrimSpace(parts[0])
+			value := strings.TrimSpace(parts[1])
+
+			service.Settings[key] = value
+		} else {
+			return nil, fmt.Errorf("line %d is not in a section", lineNum)
+		}
+	}
+
+	servicefile.servicesByName = make(map[string]*Service, len(servicefile.Services))
+	for _, service := range servicefile.Services {
+		servicefile.servicesByName[service.Name] = service
+	}
+
+	return servicefile, scanner.Err()
+}
diff --git a/vendor/github.com/jackc/pgx/v5/.gitignore b/vendor/github.com/jackc/pgx/v5/.gitignore
new file mode 100644
index 000000000..a2ebbe9c6
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/.gitignore
@@ -0,0 +1,27 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+.envrc
+/.testdb
+
+.DS_Store
diff --git a/vendor/github.com/jackc/pgx/v5/.golangci.yml b/vendor/github.com/jackc/pgx/v5/.golangci.yml
new file mode 100644
index 000000000..ec98840f5
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/.golangci.yml
@@ -0,0 +1,28 @@
+# See for configurations: https://golangci-lint.run/usage/configuration/
+version: "2"
+
+linters:
+  default: none
+  enable:
+    - govet
+    - ineffassign
+    - unconvert
+    - gocritic
+
+# See: https://golangci-lint.run/usage/formatters/
+formatters:
+  enable:
+    - gofmt # https://pkg.go.dev/cmd/gofmt
+    - gofumpt # https://github.com/mvdan/gofumpt
+
+  settings:
+    gofmt:
+      simplify: true # Simplify code: gofmt with `-s` option.
+
+    gofumpt:
+      # Module path which contains the source code being formatted.
+      # Default: ""
+      module-path: github.com/jackc/pgx/v5 # Should match with module in go.mod
+      # Choose whether to use the extra rules.
+      # Default: false
+      extra-rules: true
diff --git a/vendor/github.com/jackc/pgx/v5/CHANGELOG.md b/vendor/github.com/jackc/pgx/v5/CHANGELOG.md
new file mode 100644
index 000000000..12e633a4b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/CHANGELOG.md
@@ -0,0 +1,605 @@
+# 5.10.0 (June 3, 2026)
+
+This release includes a significant amount of hardening against malicious or compromised PostgreSQL servers,
+contributed by Sean Chittenden at CrowdStrike, Inc. This work bounds binary decoders against attacker-controlled
+message sizes, caps server-supplied SCRAM iteration counts, adds `require_auth` to restrict which authentication
+methods a server may use (mitigating downgrade attacks under `sslmode=prefer`), and ensures cancellation requests are
+sent over TLS when the original connection used TLS.
+
+## Features
+
+* Add `require_auth` to restrict accepted server authentication methods (Sean Chittenden at CrowdStrike, Inc.)
+* Add `ParseConfigOptions.ConnStringAllowedKeys` to restrict allowed connection string keys (Sean Chittenden at CrowdStrike, Inc.)
+* Add `StructArgs` and `StrictStructArgs` for `@`-named queries (Tubelight30)
+* Add `ErrConnClosed` sentinel error and unwrap it from `connLockError` (Charlie Tonneslan)
+* pgxpool: check if connection is expired before acquire (arthurdotwork)
+
+## Security Hardening
+
+* Encrypt `CancelRequest` connection when the primary connection used TLS (Sean Chittenden at CrowdStrike, Inc.)
+* Cap server-supplied SCRAM iteration count (Sean Chittenden at CrowdStrike, Inc.)
+* Default Frontend max message body length to ~1 GiB (Sean Chittenden at CrowdStrike, Inc.)
+* Bound hstore binary decode against malicious server input (Sean Chittenden at CrowdStrike, Inc.)
+* Bound array binary decode element length against remaining message bytes (Sean Chittenden at CrowdStrike, Inc.)
+* Bound array element count against remaining message bytes (Sean Chittenden at CrowdStrike, Inc.)
+* Bound range, multirange, and tsvector binary decoders (Sean Chittenden at CrowdStrike, Inc.)
+* Document secure connection configuration (Sean Chittenden at CrowdStrike, Inc.)
+* Fix panic on malformed geometric text; return an error instead (MaIII)
+
+## Fixes
+
+* Fix scanning `"char"` (OID 18) into `*string` in binary format (luongs3)
+* Fix handling of typed-nil `driver.Valuer` in array and composite codecs (Donncha Fahy)
+* Fix `CopyData.Data` hex decoding in `UnmarshalJSON` (Charlie Tonneslan)
+* Fix data race when context is cancelled during connect
+* Fix `parseKeywordValueSettings` rejecting trailing whitespace (alliasgher)
+* pgconn: preserve full error chain in `normalizeTimeoutError` (Charlie Tonneslan)
+* pgconn: use a fresh context for the fallback connection in `connectPreferred` (Charlie Tonneslan)
+* pgxpool: fix `MaxLifetimeDestroyCount` and ping order for acquire-time expiry check
+* Add missing error check of `rows.Err` to load types (Jen Altavilla)
+
+# 5.9.2 (April 18, 2026)
+
+Fix SQL Injection via placeholder confusion with dollar quoted string literals (GHSA-j88v-2chj-qfwx)
+
+SQL injection can occur when:
+
+1. The non-default simple protocol is used.
+2. A dollar quoted string literal is used in the SQL query.
+3. That query contains text that would be would be interpreted outside as a placeholder outside of a string literal.
+4. The value of that placeholder is controllable by the attacker.
+
+e.g.
+
+```go
+attackValue := `$tag$; drop table canary; --`
+_, err = tx.Exec(ctx, `select $tag$ $1 $tag$, $1`, pgx.QueryExecModeSimpleProtocol, attackValue)
+```
+
+This is unlikely to occur outside of a contrived scenario.
+
+# 5.9.1 (March 22, 2026)
+
+* Fix: batch result format corruption when using cached prepared statements (reported by Dirkjan Bussink)
+
+# 5.9.0 (March 21, 2026)
+
+This release includes a number of new features such as SCRAM-SHA-256-PLUS support, OAuth authentication support, and
+PostgreSQL protocol 3.2 support.
+
+It significantly reduces the amount of network traffic when using prepared statements (which are used automatically by
+default) by avoiding unnecessary Describe Portal messages. This also reduces local memory usage.
+
+It also includes multiple fixes for potential DoS due to panic or OOM if connected to a malicious server that sends
+deliberately malformed messages.
+
+* Require Go 1.25+
+* Add SCRAM-SHA-256-PLUS support (Adam Brightwell)
+* Add OAuth authentication support for PostgreSQL 18 (David Schneider)
+* Add PostgreSQL protocol 3.2 support (Dirkjan Bussink)
+* Add tsvector type support (Adam Brightwell)
+* Skip Describe Portal for cached prepared statements reducing network round trips
+* Make LoadTypes query easier to support on "postgres-like" servers (Jelte Fennema-Nio)
+* Default empty user to current OS user matching libpq behavior (ShivangSrivastava)
+* Optimize LRU statement cache with custom linked list and node pooling (Mathias Bogaert)
+* Optimize date scanning by replacing regex with manual parsing (Mathias Bogaert)
+* Optimize pgio append/set functions with direct byte shifts (Mathias Bogaert)
+* Make RowsAffected faster (Abhishek Chanda)
+* Fix: Pipeline.Close panic when server sends multiple FATAL errors (Varun Chawla)
+* Fix: ContextWatcher goroutine leak (Hank Donnay)
+* Fix: stdlib discard connections with open transactions in ResetSession (Jeremy Schneider)
+* Fix: pipelineBatchResults.Exec silently swallowing lastRows error
+* Fix: ColumnTypeLength using BPCharArrayOID instead of BPCharOID
+* Fix: TSVector text encoding returning nil for valid empty tsvector
+* Fix: wrong error messages for Int2 and Int4 underflow
+* Fix: Numeric nil Int pointer dereference with Valid: true
+* Fix: reversed strings.ContainsAny arguments in Numeric.ScanScientific
+* Fix: message length parsing on 32-bit platforms
+* Fix: FunctionCallResponse.Decode mishandling of signed result size
+* Fix: returning wrong error in configTLS when DecryptPEMBlock fails (Maxim Motyshen)
+* Fix: misleading ParseConfig error when default_query_exec_mode is invalid (Skarm)
+* Fix: missed Unwatch in Pipeline error paths
+* Clarify too many failed acquire attempts error message
+* Better error wrapping with context and SQL statement (Aneesh Makala)
+* Enable govet and ineffassign linters (Federico Guerinoni)
+* Guard against various malformed binary messages (arrays, hstore, multirange, protocol messages)
+* Fix various godoc comments (ferhat elmas)
+* Fix typos in comments (Oleksandr Redko)
+
+# 5.8.0 (December 26, 2025)
+
+* Require Go 1.24+
+* Remove golang.org/x/crypto dependency
+* Add OptionShouldPing to control ResetSession ping behavior (ilyam8)
+* Fix: Avoid overflow when MaxConns is set to MaxInt32
+* Fix: Close batch pipeline after a query error (Anthonin Bonnefoy)
+* Faster shutdown of pgxpool.Pool background goroutines (Blake Gentry)
+* Add pgxpool ping timeout (Amirsalar Safaei)
+* Fix: Rows.FieldDescriptions for empty query
+* Scan unknown types into *any as string or []byte based on format code
+* Optimize pgtype.Numeric (Philip Dubé)
+* Add AfterNetConnect hook to pgconn.Config
+* Fix: Handle for preparing statements that fail during the Describe phase
+* Fix overflow in numeric scanning (Ilia Demianenko)
+* Fix: json/jsonb sql.Scanner source type is []byte
+* Migrate from math/rand to math/rand/v2 (Mathias Bogaert)
+* Optimize internal iobufpool (Mathias Bogaert)
+* Optimize stmtcache invalidation (Mathias Bogaert)
+* Fix: missing error case in interval parsing (Maxime Soulé)
+* Fix: invalidate statement/description cache in Exec (James Hartig)
+* ColumnTypeLength method return the type length for varbit type (DengChan)
+* Array and Composite codecs handle typed nils
+
+# 5.7.6 (September 8, 2025)
+
+* Use ParseConfigError in pgx.ParseConfig and pgxpool.ParseConfig (Yurasov Ilia)
+* Add PrepareConn hook to pgxpool (Jonathan Hall)
+* Reduce allocations in QueryContext (Dominique Lefevre)
+* Add MarshalJSON and UnmarshalJSON for pgtype.Uint32 (Panos Koutsovasilis)
+* Configure ping behavior on pgxpool with ShouldPing (Christian Kiely)
+* zeronull int types implement Int64Valuer and Int64Scanner (Li Zeghong)
+* Fix panic when receiving terminate connection message during CopyFrom (Michal Drausowski)
+* Fix statement cache not being invalidated on error during batch (Muhammadali Nazarov)
+
+# 5.7.5 (May 17, 2025)
+
+* Support sslnegotiation connection option (divyam234)
+* Update golang.org/x/crypto to v0.37.0. This placates security scanners that were unable to see that pgx did not use the behavior affected by https://pkg.go.dev/vuln/GO-2025-3487.
+* TraceLog now logs Acquire and Release at the debug level (dave sinclair)
+* Add support for PGTZ environment variable
+* Add support for PGOPTIONS environment variable
+* Unpin memory used by Rows quicker
+* Remove PlanScan memoization. This resolves a rare issue where scanning could be broken for one type by first scanning another. The problem was in the memoization system and benchmarking revealed that memoization was not providing any meaningful benefit.
+
+# 5.7.4 (March 24, 2025)
+
+* Fix / revert change to scanning JSON `null` (Felix Röhrich)
+
+# 5.7.3 (March 21, 2025)
+
+* Expose EmptyAcquireWaitTime in pgxpool.Stat (vamshiaruru32)
+* Improve SQL sanitizer performance (ninedraft)
+* Fix Scan confusion with json(b), sql.Scanner, and automatic dereferencing (moukoublen, felix-roehrich)
+* Fix Values() for xml type always returning nil instead of []byte
+* Add ability to send Flush message in pipeline mode (zenkovev)
+* Fix pgtype.Timestamp's JSON behavior to match PostgreSQL (pconstantinou)
+* Better error messages when scanning structs (logicbomb)
+* Fix handling of error on batch write (bonnefoa)
+* Match libpq's connection fallback behavior more closely (felix-roehrich)
+* Add MinIdleConns to pgxpool (djahandarie)
+
+# 5.7.2 (December 21, 2024)
+
+* Fix prepared statement already exists on batch prepare failure
+* Add commit query to tx options (Lucas Hild)
+* Fix pgtype.Timestamp json unmarshal (Shean de Montigny-Desautels)
+* Add message body size limits in frontend and backend (zene)
+* Add xid8 type
+* Ensure planning encodes and scans cannot infinitely recurse
+* Implement pgtype.UUID.String() (Konstantin Grachev)
+* Switch from ExecParams to Exec in ValidateConnectTargetSessionAttrs functions (Alexander Rumyantsev)
+* Update golang.org/x/crypto
+* Fix json(b) columns prefer sql.Scanner interface like database/sql (Ludovico Russo)
+
+# 5.7.1 (September 10, 2024)
+
+* Fix data race in tracelog.TraceLog
+* Update puddle to v2.2.2. This removes the import of nanotime via linkname.
+* Update golang.org/x/crypto and golang.org/x/text
+
+# 5.7.0 (September 7, 2024)
+
+* Add support for sslrootcert=system (Yann Soubeyrand)
+* Add LoadTypes to load multiple types in a single SQL query (Nick Farrell)
+* Add XMLCodec supports encoding + scanning XML column type like json (nickcruess-soda)
+* Add MultiTrace (Stepan Rabotkin)
+* Add TraceLogConfig with customizable TimeKey (stringintech)
+* pgx.ErrNoRows wraps sql.ErrNoRows to aid in database/sql compatibility with native pgx functions (merlin)
+* Support scanning binary formatted uint32 into string / TextScanner (jennifersp)
+* Fix interval encoding to allow 0s and avoid extra spaces (Carlos Pérez-Aradros Herce)
+* Update pgservicefile - fixes panic when parsing invalid file
+* Better error message when reading past end of batch
+* Don't print url when url.Parse returns an error (Kevin Biju)
+* Fix snake case name normalization collision in RowToStructByName with db tag (nolandseigler)
+* Fix: Scan and encode types with underlying types of arrays
+
+# 5.6.0 (May 25, 2024)
+
+* Add StrictNamedArgs (Tomas Zahradnicek)
+* Add support for macaddr8 type (Carlos Pérez-Aradros Herce)
+* Add SeverityUnlocalized field to PgError / Notice
+* Performance optimization of RowToStructByPos/Name (Zach Olstein)
+* Allow customizing context canceled behavior for pgconn
+* Add ScanLocation to pgtype.Timestamp[tz]Codec
+* Add custom data to pgconn.PgConn
+* Fix ResultReader.Read() to handle nil values
+* Do not encode interval microseconds when they are 0 (Carlos Pérez-Aradros Herce)
+* pgconn.SafeToRetry checks for wrapped errors (tjasko)
+* Failed connection attempts include all errors
+* Optimize LargeObject.Read (Mitar)
+* Add tracing for connection acquire and release from pool (ngavinsir)
+* Fix encode driver.Valuer not called when nil
+* Add support for custom JSON marshal and unmarshal (Mitar)
+* Use Go default keepalive for TCP connections (Hans-Joachim Kliemeck)
+
+# 5.5.5 (March 9, 2024)
+
+Use spaces instead of parentheses for SQL sanitization.
+
+This still solves the problem of negative numbers creating a line comment, but this avoids breaking edge cases such as
+`set foo to $1` where the substitution is taking place in a location where an arbitrary expression is not allowed.
+
+# 5.5.4 (March 4, 2024)
+
+Fix CVE-2024-27304
+
+SQL injection can occur if an attacker can cause a single query or bind message to exceed 4 GB in size. An integer
+overflow in the calculated message size can cause the one large message to be sent as multiple messages under the
+attacker's control.
+
+Thanks to Paul Gerste for reporting this issue.
+
+* Fix behavior of CollectRows to return empty slice if Rows are empty (Felix)
+* Fix simple protocol encoding of json.RawMessage
+* Fix *Pipeline.getResults should close pipeline on error
+* Fix panic in TryFindUnderlyingTypeScanPlan (David Kurman)
+* Fix deallocation of invalidated cached statements in a transaction
+* Handle invalid sslkey file
+* Fix scan float4 into sql.Scanner
+* Fix pgtype.Bits not making copy of data from read buffer. This would cause the data to be corrupted by future reads.
+
+# 5.5.3 (February 3, 2024)
+
+* Fix: prepared statement already exists
+* Improve CopyFrom auto-conversion of text-ish values
+* Add ltree type support (Florent Viel)
+* Make some properties of Batch and QueuedQuery public (Pavlo Golub)
+* Add AppendRows function (Edoardo Spadolini)
+* Optimize convert UUID [16]byte to string (Kirill Malikov)
+* Fix: LargeObject Read and Write of more than ~1GB at a time (Mitar)
+
+# 5.5.2 (January 13, 2024)
+
+* Allow NamedArgs to start with underscore
+* pgproto3: Maximum message body length support (jeremy.spriet)
+* Upgrade golang.org/x/crypto to v0.17.0
+* Add snake_case support to RowToStructByName (Tikhon Fedulov)
+* Fix: update description cache after exec prepare (James Hartig)
+* Fix: pipeline checks if it is closed (James Hartig and Ryan Fowler)
+* Fix: normalize timeout / context errors during TLS startup (Samuel Stauffer)
+* Add OnPgError for easier centralized error handling (James Hartig)
+
+# 5.5.1 (December 9, 2023)
+
+* Add CopyFromFunc helper function. (robford)
+* Add PgConn.Deallocate method that uses PostgreSQL protocol Close message.
+* pgx uses new PgConn.Deallocate method. This allows deallocating statements to work in a failed transaction. This fixes a case where the prepared statement map could become invalid.
+* Fix: Prefer driver.Valuer over json.Marshaler for json fields. (Jacopo)
+* Fix: simple protocol SQL sanitizer previously panicked if an invalid $0 placeholder was used. This now returns an error instead. (maksymnevajdev)
+* Add pgtype.Numeric.ScanScientific (Eshton Robateau)
+
+# 5.5.0 (November 4, 2023)
+
+* Add CollectExactlyOneRow. (Julien GOTTELAND)
+* Add OpenDBFromPool to create *database/sql.DB from *pgxpool.Pool. (Lev Zakharov)
+* Prepare can automatically choose statement name based on sql. This makes it easier to explicitly manage prepared statements.
+* Statement cache now uses deterministic, stable statement names.
+* database/sql prepared statement names are deterministically generated.
+* Fix: SendBatch wasn't respecting context cancellation.
+* Fix: Timeout error from pipeline is now normalized.
+* Fix: database/sql encoding json.RawMessage to []byte.
+* CancelRequest: Wait for the cancel request to be acknowledged by the server. This should improve PgBouncer compatibility. (Anton Levakin)
+* stdlib: Use Ping instead of CheckConn in ResetSession
+* Add json.Marshaler and json.Unmarshaler for Float4, Float8 (Kirill Mironov)
+
+# 5.4.3 (August 5, 2023)
+
+* Fix: QCharArrayOID was defined with the wrong OID (Christoph Engelbert)
+* Fix: connect_timeout for sslmode=allow|prefer (smaher-edb)
+* Fix: pgxpool: background health check cannot overflow pool
+* Fix: Check for nil in defer when sending batch (recover properly from panic)
+* Fix: json scan of non-string pointer to pointer
+* Fix: zeronull.Timestamptz should use pgtype.Timestamptz
+* Fix: NewConnsCount was not correctly counting connections created by Acquire directly. (James Hartig)
+* RowTo(AddrOf)StructByPos ignores fields with "-" db tag
+* Optimization: improve text format numeric parsing (horpto)
+
+# 5.4.2 (July 11, 2023)
+
+* Fix: RowScanner errors are fatal to Rows
+* Fix: Enable failover efforts when pg_hba.conf disallows non-ssl connections (Brandon Kauffman)
+* Hstore text codec internal improvements (Evan Jones)
+* Fix: Stop timers for background reader when not in use. Fixes memory leak when closing connections (Adrian-Stefan Mares)
+* Fix: Stop background reader as soon as possible.
+* Add PgConn.SyncConn(). This combined with the above fix makes it safe to directly use the underlying net.Conn.
+
+# 5.4.1 (June 18, 2023)
+
+* Fix: concurrency bug with pgtypeDefaultMap and simple protocol (Lev Zakharov)
+* Add TxOptions.BeginQuery to allow overriding the default BEGIN query
+
+# 5.4.0 (June 14, 2023)
+
+* Replace platform specific syscalls for non-blocking IO with more traditional goroutines and deadlines. This returns to the v4 approach with some additional improvements and fixes. This restores the ability to use a pgx.Conn over an ssh.Conn as well as other non-TCP or Unix socket connections. In addition, it is a significantly simpler implementation that is less likely to have cross platform issues.
+* Optimization: The default type registrations are now shared among all connections. This saves about 100KB of memory per connection. `pgtype.Type` and `pgtype.Codec` values are now required to be immutable after registration. This was already necessary in most cases but wasn't documented until now. (Lev Zakharov)
+* Fix: Ensure pgxpool.Pool.QueryRow.Scan releases connection on panic
+* CancelRequest: don't try to read the reply (Nicola Murino)
+* Fix: correctly handle bool type aliases (Wichert Akkerman)
+* Fix: pgconn.CancelRequest: Fix unix sockets: don't use RemoteAddr()
+* Fix: pgx.Conn memory leak with prepared statement caching (Evan Jones)
+* Add BeforeClose to pgxpool.Pool (Evan Cordell)
+* Fix: various hstore fixes and optimizations (Evan Jones)
+* Fix: RowToStructByPos with embedded unexported struct
+* Support different bool string representations (Lev Zakharov)
+* Fix: error when using BatchResults.Exec on a select that returns an error after some rows.
+* Fix: pipelineBatchResults.Exec() not returning error from ResultReader
+* Fix: pipeline batch results not closing pipeline when error occurs while reading directly from results instead of using
+    a callback.
+* Fix: scanning a table type into a struct
+* Fix: scan array of record to pointer to slice of struct
+* Fix: handle null for json (Cemre Mengu)
+* Batch Query callback is called even when there is an error
+* Add RowTo(AddrOf)StructByNameLax (Audi P. Risa P)
+
+# 5.3.1 (February 27, 2023)
+
+* Fix: Support v4 and v5 stdlib in same program (Tomáš Procházka)
+* Fix: sql.Scanner not being used in certain cases
+* Add text format jsonpath support
+* Fix: fake non-blocking read adaptive wait time
+
+# 5.3.0 (February 11, 2023)
+
+* Fix: json values work with sql.Scanner
+* Fixed / improved error messages (Mark Chambers and Yevgeny Pats)
+* Fix: support scan into single dimensional arrays
+* Fix: MaxConnLifetimeJitter setting actually jitter (Ben Weintraub)
+* Fix: driver.Value representation of bytea should be []byte not string
+* Fix: better handling of unregistered OIDs
+* CopyFrom can use query cache to avoid extra round trip to get OIDs (Alejandro Do Nascimento Mora)
+* Fix: encode to json ignoring driver.Valuer
+* Support sql.Scanner on renamed base type
+* Fix: pgtype.Numeric text encoding of negative numbers (Mark Chambers)
+* Fix: connect with multiple hostnames when one can't be resolved
+* Upgrade puddle to remove dependency on uber/atomic and fix alignment issue on 32-bit platform
+* Fix: scanning json column into **string
+* Multiple reductions in memory allocations
+* Fake non-blocking read adapts its max wait time
+* Improve CopyFrom performance and reduce memory usage
+* Fix: encode []any to array
+* Fix: LoadType for composite with dropped attributes (Felix Röhrich)
+* Support v4 and v5 stdlib in same program
+* Fix: text format array decoding with string of "NULL"
+* Prefer binary format for arrays
+
+# 5.2.0 (December 5, 2022)
+
+* `tracelog.TraceLog` implements the pgx.PrepareTracer interface. (Vitalii Solodilov)
+* Optimize creating begin transaction SQL string (Petr Evdokimov and ksco)
+* `Conn.LoadType` supports range and multirange types (Vitalii Solodilov)
+* Fix scan `uint` and `uint64` `ScanNumeric`. This resolves a PostgreSQL `numeric` being incorrectly scanned into `uint` and `uint64`.
+
+# 5.1.1 (November 17, 2022)
+
+* Fix simple query sanitizer where query text contains a Unicode replacement character.
+* Remove erroneous `name` argument from `DeallocateAll()`. Technically, this is a breaking change, but given that method was only added 5 days ago this change was accepted. (Bodo Kaiser)
+
+# 5.1.0 (November 12, 2022)
+
+* Update puddle to v2.1.2. This resolves a race condition and a deadlock in pgxpool.
+* `QueryRewriter.RewriteQuery` now returns an error. Technically, this is a breaking change for any external implementers, but given the minimal likelihood that there are actually any external implementers this change was accepted.
+* Expose `GetSSLPassword` support to pgx.
+* Fix encode `ErrorResponse` unknown field handling. This would only affect pgproto3 being used directly as a proxy with a non-PostgreSQL server that included additional error fields.
+* Fix date text format encoding with 5 digit years.
+* Fix date values passed to a `sql.Scanner` as `string` instead of `time.Time`.
+* DateCodec.DecodeValue can return `pgtype.InfinityModifier` instead of `string` for infinite values. This now matches the behavior of the timestamp types.
+* Add domain type support to `Conn.LoadType()`.
+* Add `RowToStructByName` and `RowToAddrOfStructByName`. (Pavlo Golub)
+* Add `Conn.DeallocateAll()` to clear all prepared statements including the statement cache. (Bodo Kaiser)
+
+# 5.0.4 (October 24, 2022)
+
+* Fix: CollectOneRow prefers PostgreSQL error over pgx.ErrorNoRows
+* Fix: some reflect Kind checks to first check for nil
+* Bump golang.org/x/text dependency to placate snyk
+* Fix: RowToStructByPos on structs with multiple anonymous sub-structs (Baptiste Fontaine)
+* Fix: Exec checks if tx is closed
+
+# 5.0.3 (October 14, 2022)
+
+* Fix `driver.Valuer` handling edge cases that could cause infinite loop or crash
+
+# v5.0.2 (October 8, 2022)
+
+* Fix date encoding in text format to always use 2 digits for month and day
+* Prefer driver.Valuer over wrap plans when encoding
+* Fix scan to pointer to pointer to renamed type
+* Allow scanning NULL even if PG and Go types are incompatible
+
+# v5.0.1 (September 24, 2022)
+
+* Fix 32-bit atomic usage
+* Add MarshalJSON for Float8 (yogipristiawan)
+* Add `[` and `]` to text encoding of `Lseg`
+* Fix sqlScannerWrapper NULL handling
+
+# v5.0.0 (September 17, 2022)
+
+## Merged Packages
+
+`github.com/jackc/pgtype`, `github.com/jackc/pgconn`, and `github.com/jackc/pgproto3` are now included in the main
+`github.com/jackc/pgx` repository. Previously there was confusion as to where issues should be reported, additional
+release work due to releasing multiple packages, and less clear changelogs.
+
+## pgconn
+
+`CommandTag` is now an opaque type instead of directly exposing an underlying `[]byte`.
+
+The return value `ResultReader.Values()` is no longer safe to retain a reference to after a subsequent call to `NextRow()` or `Close()`.
+
+`Trace()` method adds low level message tracing similar to the `PQtrace` function in `libpq`.
+
+pgconn now uses non-blocking IO. This is a significant internal restructuring, but it should not cause any visible changes on its own. However, it is important in implementing other new features.
+
+`CheckConn()` checks a connection's liveness by doing a non-blocking read. This can be used to detect database restarts or network interruptions without executing a query or a ping.
+
+pgconn now supports pipeline mode.
+
+`*PgConn.ReceiveResults` removed. Use pipeline mode instead.
+
+`Timeout()` no longer considers `context.Canceled` as a timeout error. `context.DeadlineExceeded` still is considered a timeout error.
+
+## pgxpool
+
+`Connect` and `ConnectConfig` have been renamed to `New` and `NewWithConfig` respectively. The `LazyConnect` option has been removed. Pools always lazily connect.
+
+## pgtype
+
+The `pgtype` package has been significantly changed.
+
+### NULL Representation
+
+Previously, types had a `Status` field that could be `Undefined`, `Null`, or `Present`. This has been changed to a
+`Valid` `bool` field to harmonize with how `database/sql` represents `NULL` and to make the zero value useable.
+
+Previously, a type that implemented `driver.Valuer` would have the `Value` method called even on a nil pointer. All nils
+whether typed or untyped now represent `NULL`.
+
+### Codec and Value Split
+
+Previously, the type system combined decoding and encoding values with the value types. e.g. Type `Int8` both handled
+encoding and decoding the PostgreSQL representation and acted as a value object. This caused some difficulties when
+there was not an exact 1 to 1 relationship between the Go types and the PostgreSQL types For example, scanning a
+PostgreSQL binary `numeric` into a Go `float64` was awkward (see https://github.com/jackc/pgtype/issues/147). This
+concepts have been separated. A `Codec` only has responsibility for encoding and decoding values. Value types are
+generally defined by implementing an interface that a particular `Codec` understands (e.g. `PointScanner` and
+`PointValuer` for the PostgreSQL `point` type).
+
+### Array Types
+
+All array types are now handled by `ArrayCodec` instead of using code generation for each new array type. This also
+means that less common array types such as `point[]` are now supported. `Array[T]` supports PostgreSQL multi-dimensional
+arrays.
+
+### Composite Types
+
+Composite types must be registered before use. `CompositeFields` may still be used to construct and destruct composite
+values, but any type may now implement `CompositeIndexGetter` and `CompositeIndexScanner` to be used as a composite.
+
+### Range Types
+
+Range types are now handled with types `RangeCodec` and `Range[T]`. This allows additional user defined range types to
+easily be handled. Multirange types are handled similarly with `MultirangeCodec` and `Multirange[T]`.
+
+### pgxtype
+
+`LoadDataType` moved to `*Conn` as `LoadType`.
+
+### Bytea
+
+The `Bytea` and `GenericBinary` types have been replaced. Use the following instead:
+
+* `[]byte` - For normal usage directly use `[]byte`.
+* `DriverBytes` - Uses driver memory only available until next database method call. Avoids a copy and an allocation.
+* `PreallocBytes` - Uses preallocated byte slice to avoid an allocation.
+* `UndecodedBytes` - Avoids any decoding. Allows working with raw bytes.
+
+### Dropped lib/pq Support
+
+`pgtype` previously supported and was tested against [lib/pq](https://github.com/lib/pq). While it will continue to work
+in most cases this is no longer supported.
+
+### database/sql Scan
+
+Previously, most `Scan` implementations would convert `[]byte` to `string` automatically to decode a text value. Now
+only `string` is handled. This is to allow the possibility of future binary support in `database/sql` mode by
+considering `[]byte` to be binary format and `string` text format. This change should have no effect for any use with
+`pgx`. The previous behavior was only necessary for `lib/pq` compatibility.
+
+Added `*Map.SQLScanner` to create a `sql.Scanner` for types such as `[]int32` and `Range[T]` that do not implement
+`sql.Scanner` directly.
+
+### Number Type Fields Include Bit size
+
+`Int2`, `Int4`, `Int8`, `Float4`, `Float8`, and `Uint32` fields now include bit size. e.g. `Int` is renamed to `Int64`.
+This matches the convention set by `database/sql`. In addition, for comparable types like `pgtype.Int8` and
+`sql.NullInt64` the structures are identical. This means they can be directly converted one to another.
+
+### 3rd Party Type Integrations
+
+* Extracted integrations with https://github.com/shopspring/decimal and https://github.com/gofrs/uuid to
+  https://github.com/jackc/pgx-shopspring-decimal and https://github.com/jackc/pgx-gofrs-uuid respectively. This trims
+  the pgx dependency tree.
+
+### Other Changes
+
+* `Bit` and `Varbit` are both replaced by the `Bits` type.
+* `CID`, `OID`, `OIDValue`, and `XID` are replaced by the `Uint32` type.
+* `Hstore` is now defined as `map[string]*string`.
+* `JSON` and `JSONB` types removed. Use `[]byte` or `string` directly.
+* `QChar` type removed. Use `rune` or `byte` directly.
+* `Inet` and `Cidr` types removed. Use `netip.Addr` and `netip.Prefix` directly. These types are more memory efficient than the previous `net.IPNet`.
+* `Macaddr` type removed. Use `net.HardwareAddr` directly.
+* Renamed `pgtype.ConnInfo` to `pgtype.Map`.
+* Renamed `pgtype.DataType` to `pgtype.Type`.
+* Renamed `pgtype.None` to `pgtype.Finite`.
+* `RegisterType` now accepts a `*Type` instead of `Type`.
+* Assorted array helper methods and types made private.
+
+## stdlib
+
+* Removed `AcquireConn` and `ReleaseConn` as that functionality has been built in since Go 1.13.
+
+## Reduced Memory Usage by Reusing Read Buffers
+
+Previously, the connection read buffer would allocate large chunks of memory and never reuse them. This allowed
+transferring ownership to anything such as scanned values without incurring an additional allocation and memory copy.
+However, this came at the cost of overall increased memory allocation size. But worse it was also possible to pin large
+chunks of memory by retaining a reference to a small value that originally came directly from the read buffer. Now
+ownership remains with the read buffer and anything needing to retain a value must make a copy.
+
+## Query Execution Modes
+
+Control over automatic prepared statement caching and simple protocol use are now combined into query execution mode.
+See documentation for `QueryExecMode`.
+
+## QueryRewriter Interface and NamedArgs
+
+pgx now supports named arguments with the `NamedArgs` type. This is implemented via the new `QueryRewriter` interface which
+allows arbitrary rewriting of query SQL and arguments.
+
+## RowScanner Interface
+
+The `RowScanner` interface allows a single argument to Rows.Scan to scan the entire row.
+
+## Rows Result Helpers
+
+* `CollectRows` and `RowTo*` functions simplify collecting results into a slice.
+* `CollectOneRow` collects one row using `RowTo*` functions.
+* `ForEachRow` simplifies scanning each row and executing code using the scanned values. `ForEachRow` replaces `QueryFunc`.
+
+## Tx Helpers
+
+Rather than every type that implemented `Begin` or `BeginTx` methods also needing to implement `BeginFunc` and
+`BeginTxFunc` these methods have been converted to functions that take a db that implements `Begin` or `BeginTx`.
+
+## Improved Batch Query Ergonomics
+
+Previously, the code for building a batch went in one place before the call to `SendBatch`, and the code for reading the
+results went in one place after the call to `SendBatch`. This could make it difficult to match up the query and the code
+to handle the results. Now `Queue` returns a `QueuedQuery` which has methods `Query`, `QueryRow`, and `Exec` which can
+be used to register a callback function that will handle the result. Callback functions are called automatically when
+`BatchResults.Close` is called.
+
+## SendBatch Uses Pipeline Mode When Appropriate
+
+Previously, a batch with 10 unique parameterized statements executed 100 times would entail 11 network round trips. 1
+for each prepare / describe and 1 for executing them all. Now pipeline mode is used to prepare / describe all statements
+in a single network round trip. So it would only take 2 round trips.
+
+## Tracing and Logging
+
+Internal logging support has been replaced with tracing hooks. This allows custom tracing integration with tools like OpenTelemetry. Package tracelog provides an adapter for pgx v4 loggers to act as a tracer.
+
+All integrations with 3rd party loggers have been extracted to separate repositories. This trims the pgx dependency
+tree.
diff --git a/vendor/github.com/jackc/pgx/v5/CLAUDE.md b/vendor/github.com/jackc/pgx/v5/CLAUDE.md
new file mode 100644
index 000000000..71a8fc164
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/CLAUDE.md
@@ -0,0 +1,73 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Project Overview
+
+pgx is a PostgreSQL driver and toolkit for Go (`github.com/jackc/pgx/v5`). It provides both a native PostgreSQL interface and a `database/sql` compatible driver. Requires Go 1.25+ and supports PostgreSQL 14+ and CockroachDB.
+
+## Build & Test Commands
+
+```bash
+# Run all tests (requires PGX_TEST_DATABASE to be set)
+go test ./...
+
+# Run a specific test
+go test -run TestFunctionName ./...
+
+# Run tests for a specific package
+go test ./pgconn/...
+
+# Run tests with race detector
+go test -race ./...
+
+# DevContainer: run tests against specific PostgreSQL versions
+./test.sh pg18                      # Default: PostgreSQL 18
+./test.sh pg16 -run TestConnect     # Specific test against PG16
+./test.sh crdb                      # CockroachDB
+./test.sh all                       # All targets (pg14-18 + crdb)
+
+# Format (always run after making changes)
+goimports -w .
+
+# Lint
+golangci-lint run ./...
+```
+
+## Test Database Setup
+
+Tests require `PGX_TEST_DATABASE` environment variable. In the devcontainer, `test.sh` handles this. For local development:
+
+```bash
+export PGX_TEST_DATABASE="host=localhost user=postgres password=postgres dbname=pgx_test"
+```
+
+The test database needs extensions: `hstore`, `ltree`, and a `uint64` domain. See `testsetup/postgresql_setup.sql` for full setup. Many tests are skipped unless additional `PGX_TEST_*` env vars are set (for TLS, SCRAM, MD5, unix socket, PgBouncer testing).
+
+## Architecture
+
+The codebase is a layered architecture, bottom-up:
+
+- **pgproto3/** — PostgreSQL wire protocol v3 encoder/decoder. Defines `FrontendMessage` and `BackendMessage` types for every protocol message.
+- **pgconn/** — Low-level connection layer (roughly libpq-equivalent). Handles authentication, TLS, query execution, COPY protocol, and notifications. `PgConn` is the core type.
+- **pgx** (root package) — High-level query interface built on `pgconn`. Provides `Conn`, `Rows`, `Tx`, `Batch`, `CopyFrom`, and generic helpers like `CollectRows`/`ForEachRow`. Includes automatic statement caching (LRU).
+- **pgtype/** — Type system mapping between Go and PostgreSQL types (70+ types). Key interfaces: `Codec`, `Type`, `TypeMap`. Custom types (enums, composites, domains) are registered through `TypeMap`.
+- **pgxpool/** — Concurrency-safe connection pool built on `puddle/v2`. `Pool` is the main type; wraps `pgx.Conn`.
+- **stdlib/** — `database/sql` compatibility adapter.
+
+Supporting packages:
+- **internal/stmtcache/** — Prepared statement cache with LRU eviction
+- **internal/sanitize/** — SQL query sanitization
+- **tracelog/** — Logging adapter that implements tracer interfaces
+- **multitracer/** — Composes multiple tracers into one
+- **pgxtest/** — Test helpers for running tests across connection types
+
+## Key Design Conventions
+
+- **Semantic versioning** — strictly followed. Do not break the public API (no removing or renaming exported types, functions, methods, or fields; no changing function signatures).
+- **Minimal dependencies** — adding new dependencies is strongly discouraged (see CONTRIBUTING.md).
+- **Context-based** — all blocking operations take `context.Context`.
+- **Tracer interfaces** — observability via `QueryTracer`, `BatchTracer`, `CopyFromTracer`, `PrepareTracer` on `ConnConfig.Tracer`.
+- **Formatting** — always run `goimports -w .` after making changes to ensure code is properly formatted. CI checks formatting via `gofmt -l -s -w . && git diff --exit-code`. `gofumpt` with extra rules is also enforced via `golangci-lint`.
+- **Linters** — `govet`, `ineffassign`, and `unconvert` only (configured in `.golangci.yml`).
+- **CI matrix** — tests run against Go 1.25/1.26 × PostgreSQL 14-18 + CockroachDB, on Linux and Windows. Race detector enabled on Linux only.
diff --git a/vendor/github.com/jackc/pgx/v5/CONTRIBUTING.md b/vendor/github.com/jackc/pgx/v5/CONTRIBUTING.md
new file mode 100644
index 000000000..2283ae670
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/CONTRIBUTING.md
@@ -0,0 +1,139 @@
+# Contributing
+
+## Discuss Significant Changes
+
+Before you invest a significant amount of time on a change, please create a discussion or issue describing your
+proposal. This will help to ensure your proposed change has a reasonable chance of being merged.
+
+## Avoid Dependencies
+
+Adding a dependency is a big deal. While on occasion a new dependency may be accepted, the default answer to any change
+that adds a dependency is no.
+
+## AI
+
+Using AI is acceptable (not that it can really be stopped) under one the following conditions.
+
+* AI was used, but you deeply understand the code and you can answer questions regarding your change. You are not going
+  to answer questions with "I don't know", AI did it. You are not going to "answer" questions by relaying them to your
+  agent. This is wasteful of the code reviewer's time.
+* AI was used to solve a problem without your deep understanding. This can still be a good starting point for a fix or
+  feature. But you need to clearly state that this is an AI proposal. You should include additional information such as
+  the AI used and what prompts were used. You should also be aware that large, complicated, or subtle changes may be
+  rejected simply because the reviewer is not confident in a change that no human understands.
+
+## Development Environment Setup
+
+pgx tests naturally require a PostgreSQL database. It will connect to the database specified in the `PGX_TEST_DATABASE`
+environment variable. The `PGX_TEST_DATABASE` environment variable can either be a URL or key-value pairs. In addition,
+the standard `PG*` environment variables will be respected. Consider using [direnv](https://github.com/direnv/direnv) to
+simplify environment variable handling.
+
+### Devcontainer
+
+The easiest way to start development is with the included devcontainer. It includes containers for each supported
+PostgreSQL version as well as CockroachDB. `./test.sh all` will run the tests against all database types.
+
+### Using an Existing PostgreSQL Cluster Outside of a Devcontainer
+
+If you already have a PostgreSQL development server this is the quickest way to start and run the majority of the pgx
+test suite. Some tests will be skipped that require server configuration changes (e.g. those testing different
+authentication methods).
+
+Create and setup a test database:
+
+```
+export PGDATABASE=pgx_test
+createdb
+psql -c 'create extension hstore;'
+psql -c 'create extension ltree;'
+psql -c 'create domain uint64 as numeric(20,0);'
+```
+
+Ensure a `postgres` user exists. This happens by default in normal PostgreSQL installs, but some installation methods
+such as Homebrew do not.
+
+```
+createuser -s postgres
+```
+
+Ensure your `PGX_TEST_DATABASE` environment variable points to the database you just created and run the tests.
+
+```
+export PGX_TEST_DATABASE="host=/private/tmp database=pgx_test"
+go test ./...
+```
+
+This will run the vast majority of the tests, but some tests will be skipped (e.g. those testing different connection methods).
+
+### Creating a New PostgreSQL Cluster Exclusively for Testing Outside of a Devcontainer
+
+The following environment variables need to be set both for initial setup and whenever the tests are run. (direnv is
+highly recommended). Depending on your platform, you may need to change the host for `PGX_TEST_UNIX_SOCKET_CONN_STRING`.
+
+```
+export PGPORT=5015
+export PGUSER=postgres
+export PGDATABASE=pgx_test
+export POSTGRESQL_DATA_DIR=postgresql
+
+export PGX_TEST_DATABASE="host=127.0.0.1 database=pgx_test user=pgx_md5 password=secret"
+export PGX_TEST_UNIX_SOCKET_CONN_STRING="host=/private/tmp database=pgx_test"
+export PGX_TEST_TCP_CONN_STRING="host=127.0.0.1 database=pgx_test user=pgx_md5 password=secret"
+export PGX_TEST_SCRAM_PASSWORD_CONN_STRING="host=127.0.0.1 user=pgx_scram password=secret database=pgx_test channel_binding=disable"
+export PGX_TEST_SCRAM_PLUS_CONN_STRING="host=localhost user=pgx_ssl password=secret sslmode=verify-full sslrootcert=`pwd`/.testdb/ca.pem database=pgx_test channel_binding=require"
+export PGX_TEST_MD5_PASSWORD_CONN_STRING="host=127.0.0.1 database=pgx_test user=pgx_md5 password=secret"
+export PGX_TEST_PLAIN_PASSWORD_CONN_STRING="host=127.0.0.1 user=pgx_pw password=secret"
+export PGX_TEST_TLS_CONN_STRING="host=localhost user=pgx_ssl password=secret sslmode=verify-full sslrootcert=`pwd`/.testdb/ca.pem channel_binding=disable"
+export PGX_SSL_PASSWORD=certpw
+export PGX_TEST_TLS_CLIENT_CONN_STRING="host=localhost user=pgx_sslcert sslmode=verify-full sslrootcert=`pwd`/.testdb/ca.pem database=pgx_test sslcert=`pwd`/.testdb/pgx_sslcert.crt sslkey=`pwd`/.testdb/pgx_sslcert.key"
+```
+
+Create a new database cluster.
+
+```
+initdb --locale=en_US -E UTF-8 --username=postgres .testdb/$POSTGRESQL_DATA_DIR
+
+echo "listen_addresses = '127.0.0.1'" >> .testdb/$POSTGRESQL_DATA_DIR/postgresql.conf
+echo "port = $PGPORT" >> .testdb/$POSTGRESQL_DATA_DIR/postgresql.conf
+cat testsetup/postgresql_ssl.conf >> .testdb/$POSTGRESQL_DATA_DIR/postgresql.conf
+cp testsetup/pg_hba.conf .testdb/$POSTGRESQL_DATA_DIR/pg_hba.conf
+
+cd .testdb
+
+# Generate CA, server, and encrypted client certificates.
+go run ../testsetup/generate_certs.go
+
+# Copy certificates to server directory and set permissions.
+cp ca.pem $POSTGRESQL_DATA_DIR/root.crt
+cp localhost.key $POSTGRESQL_DATA_DIR/server.key
+chmod 600 $POSTGRESQL_DATA_DIR/server.key
+cp localhost.crt $POSTGRESQL_DATA_DIR/server.crt
+
+cd ..
+```
+
+
+Start the new cluster. This will be necessary whenever you are running pgx tests.
+
+```
+postgres -D .testdb/$POSTGRESQL_DATA_DIR
+```
+
+Setup the test database in the new cluster.
+
+```
+createdb
+psql --no-psqlrc -f testsetup/postgresql_setup.sql
+```
+
+### PgBouncer
+
+There are tests specific for PgBouncer that will be executed if `PGX_TEST_PGBOUNCER_CONN_STRING` is set.
+
+### Optional Tests
+
+pgx supports multiple connection types and means of authentication. These tests are optional. They will only run if the
+appropriate environment variables are set. In addition, there may be tests specific to particular PostgreSQL versions,
+non-PostgreSQL servers (e.g. CockroachDB), or connection poolers (e.g. PgBouncer). `go test ./... -v | grep SKIP` to see
+if any tests are being skipped.
diff --git a/vendor/github.com/jackc/pgx/v5/LICENSE b/vendor/github.com/jackc/pgx/v5/LICENSE
new file mode 100644
index 000000000..5c486c39a
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2013-2021 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgx/v5/README.md b/vendor/github.com/jackc/pgx/v5/README.md
new file mode 100644
index 000000000..aa35e4a3d
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/README.md
@@ -0,0 +1,192 @@
+[![Go Reference](https://pkg.go.dev/badge/github.com/jackc/pgx/v5.svg)](https://pkg.go.dev/github.com/jackc/pgx/v5)
+[![Build Status](https://github.com/jackc/pgx/actions/workflows/ci.yml/badge.svg)](https://github.com/jackc/pgx/actions/workflows/ci.yml)
+
+# pgx - PostgreSQL Driver and Toolkit
+
+pgx is a pure Go driver and toolkit for PostgreSQL.
+
+The pgx driver is a low-level, high performance interface that exposes PostgreSQL-specific features such as `LISTEN` /
+`NOTIFY` and `COPY`. It also includes an adapter for the standard `database/sql` interface.
+
+The toolkit component is a related set of packages that implement PostgreSQL functionality such as parsing the wire protocol
+and type mapping between PostgreSQL and Go. These underlying packages can be used to implement alternative drivers,
+proxies, load balancers, logical replication clients, etc.
+
+## Example Usage
+
+```go
+package main
+
+import (
+	"context"
+	"fmt"
+	"os"
+
+	"github.com/jackc/pgx/v5"
+)
+
+func main() {
+	// urlExample := "postgres://username:password@localhost:5432/database_name"
+	conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
+		os.Exit(1)
+	}
+	defer conn.Close(context.Background())
+
+	var name string
+	var weight int64
+	err = conn.QueryRow(context.Background(), "select name, weight from widgets where id=$1", 42).Scan(&name, &weight)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
+		os.Exit(1)
+	}
+
+	fmt.Println(name, weight)
+}
+```
+
+See the [getting started guide](https://github.com/jackc/pgx/wiki/Getting-started-with-pgx) for more information.
+
+## Features
+
+* Support for approximately 70 different PostgreSQL types
+* Automatic statement preparation and caching
+* Batch queries
+* Single-round trip query mode
+* Full TLS connection control
+* Binary format support for custom types (allows for much quicker encoding/decoding)
+* `COPY` protocol support for faster bulk data loads
+* Tracing and logging support
+* Connection pool with after-connect hook for arbitrary connection setup
+* `LISTEN` / `NOTIFY`
+* Conversion of PostgreSQL arrays to Go slice mappings for integers, floats, and strings
+* `hstore` support
+* `json` and `jsonb` support
+* Maps `inet` and `cidr` PostgreSQL types to `netip.Addr` and `netip.Prefix`
+* Large object support
+* NULL mapping to pointer to pointer
+* Supports `database/sql.Scanner` and `database/sql/driver.Valuer` interfaces for custom types
+* Notice response handling
+* Simulated nested transactions with savepoints
+
+## Choosing Between the pgx and database/sql Interfaces
+
+The pgx interface is faster. Many PostgreSQL specific features such as `LISTEN` / `NOTIFY` and `COPY` are not available
+through the `database/sql` interface.
+
+The pgx interface is recommended when:
+
+1. The application only targets PostgreSQL.
+2. No other libraries that require `database/sql` are in use.
+
+It is also possible to use the `database/sql` interface and convert a connection to the lower-level pgx interface as needed.
+
+## Testing
+
+See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions.
+
+## Architecture
+
+See the presentation at Golang Estonia, [PGX Top to Bottom](https://www.youtube.com/watch?v=sXMSWhcHCf8) for a description of pgx architecture.
+
+## Supported Go and PostgreSQL Versions
+
+pgx supports the same versions of Go and PostgreSQL that are supported by their respective teams. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases and for [PostgreSQL](https://www.postgresql.org/support/versioning/) the major releases in the last 5 years. This means pgx supports Go 1.25 and higher and PostgreSQL 14 and higher. pgx also is tested against the latest version of [CockroachDB](https://www.cockroachlabs.com/product/).
+
+## Version Policy
+
+pgx follows semantic versioning for the documented public API on stable releases. `v5` is the latest stable major version.
+
+## PGX Family Libraries
+
+### [github.com/jackc/pglogrepl](https://github.com/jackc/pglogrepl)
+
+pglogrepl provides functionality to act as a client for PostgreSQL logical replication.
+
+### [github.com/jackc/pgmock](https://github.com/jackc/pgmock)
+
+pgmock offers the ability to create a server that mocks the PostgreSQL wire protocol. This is used internally to test pgx by purposely inducing unusual errors. pgproto3 and pgmock together provide most of the foundational tooling required to implement a PostgreSQL proxy or MitM (such as for a custom connection pooler).
+
+### [github.com/jackc/tern](https://github.com/jackc/tern)
+
+tern is a stand-alone SQL migration system.
+
+### [github.com/jackc/pgerrcode](https://github.com/jackc/pgerrcode)
+
+pgerrcode contains constants for the PostgreSQL error codes.
+
+## Adapters for 3rd Party Types
+
+* [github.com/jackc/pgx-gofrs-uuid](https://github.com/jackc/pgx-gofrs-uuid)
+* [github.com/jackc/pgx-shopspring-decimal](https://github.com/jackc/pgx-shopspring-decimal)
+* [github.com/ColeBurch/pgx-govalues-decimal](https://github.com/ColeBurch/pgx-govalues-decimal)
+* [github.com/twpayne/pgx-geos](https://github.com/twpayne/pgx-geos) ([PostGIS](https://postgis.net/) and [GEOS](https://libgeos.org/) via [go-geos](https://github.com/twpayne/go-geos))
+* [github.com/vgarvardt/pgx-google-uuid](https://github.com/vgarvardt/pgx-google-uuid)
+
+
+## Adapters for 3rd Party Tracers
+
+* [github.com/jackhopner/pgx-xray-tracer](https://github.com/jackhopner/pgx-xray-tracer)
+* [github.com/exaring/otelpgx](https://github.com/exaring/otelpgx)
+
+## Adapters for 3rd Party Loggers
+
+These adapters can be used with the tracelog package.
+
+* [github.com/jackc/pgx-go-kit-log](https://github.com/jackc/pgx-go-kit-log)
+* [github.com/jackc/pgx-log15](https://github.com/jackc/pgx-log15)
+* [github.com/jackc/pgx-logrus](https://github.com/jackc/pgx-logrus)
+* [github.com/jackc/pgx-zap](https://github.com/jackc/pgx-zap)
+* [github.com/jackc/pgx-zerolog](https://github.com/jackc/pgx-zerolog)
+* [github.com/mcosta74/pgx-slog](https://github.com/mcosta74/pgx-slog)
+* [github.com/kataras/pgx-golog](https://github.com/kataras/pgx-golog)
+
+## 3rd Party Libraries with PGX Support
+
+### [github.com/pashagolub/pgxmock](https://github.com/pashagolub/pgxmock)
+
+pgxmock is a mock library implementing pgx interfaces.
+pgxmock has one and only purpose - to simulate pgx behavior in tests, without needing a real database connection.
+
+### [github.com/georgysavva/scany](https://github.com/georgysavva/scany)
+
+Library for scanning data from a database into Go structs and more.
+
+### [github.com/vingarcia/ksql](https://github.com/vingarcia/ksql)
+
+A carefully designed SQL client for making using SQL easier,
+more productive, and less error-prone on Golang.
+
+### [github.com/otan/gopgkrb5](https://github.com/otan/gopgkrb5)
+
+Adds GSSAPI / Kerberos authentication support.
+
+### [github.com/wcamarao/pmx](https://github.com/wcamarao/pmx)
+
+Explicit data mapping and scanning library for Go structs and slices.
+
+### [github.com/stephenafamo/scan](https://github.com/stephenafamo/scan)
+
+Type safe and flexible package for scanning database data into Go types.
+Supports, structs, maps, slices and custom mapping functions.
+
+### [github.com/z0ne-dev/mgx](https://github.com/z0ne-dev/mgx)
+
+Code first migration library for native pgx (no database/sql abstraction).
+
+### [github.com/amirsalarsafaei/sqlc-pgx-monitoring](https://github.com/amirsalarsafaei/sqlc-pgx-monitoring)
+
+A database monitoring/metrics library for pgx and sqlc. Trace, log and monitor your sqlc query performance using OpenTelemetry.
+
+### [https://github.com/nikolayk812/pgx-outbox](https://github.com/nikolayk812/pgx-outbox)
+
+Simple Golang implementation for transactional outbox pattern for PostgreSQL using jackc/pgx driver.
+
+### [https://github.com/Arlandaren/pgxWrappy](https://github.com/Arlandaren/pgxWrappy)
+
+Simplifies working with the pgx library, providing convenient scanning of nested structures.
+
+### [https://github.com/KoNekoD/pgx-colon-query-rewriter](https://github.com/KoNekoD/pgx-colon-query-rewriter)
+
+Implementation of the pgx query rewriter to use ':' instead of '@' in named query parameters.
diff --git a/vendor/github.com/jackc/pgx/v5/Rakefile b/vendor/github.com/jackc/pgx/v5/Rakefile
new file mode 100644
index 000000000..3e3aa5030
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/Rakefile
@@ -0,0 +1,18 @@
+require "erb"
+
+rule '.go' => '.go.erb' do |task|
+  erb = ERB.new(File.read(task.source))
+  File.write(task.name, "// Code generated from #{task.source}. DO NOT EDIT.\n\n" + erb.result(binding))
+  sh "goimports", "-w", task.name
+end
+
+generated_code_files = [
+  "pgtype/int.go",
+  "pgtype/int_test.go",
+  "pgtype/integration_benchmark_test.go",
+  "pgtype/zeronull/int.go",
+  "pgtype/zeronull/int_test.go"
+]
+
+desc "Generate code"
+task generate: generated_code_files
diff --git a/vendor/github.com/jackc/pgx/v5/batch.go b/vendor/github.com/jackc/pgx/v5/batch.go
new file mode 100644
index 000000000..805cc39ef
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/batch.go
@@ -0,0 +1,537 @@
+package pgx
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+// QueuedQuery is a query that has been queued for execution via a [Batch].
+type QueuedQuery struct {
+	SQL       string
+	Arguments []any
+	Fn        batchItemFunc
+	sd        *pgconn.StatementDescription
+}
+
+type batchItemFunc func(br BatchResults) error
+
+// Query sets fn to be called when the response to qq is received.
+func (qq *QueuedQuery) Query(fn func(rows Rows) error) {
+	qq.Fn = func(br BatchResults) error {
+		rows, _ := br.Query()
+		defer rows.Close()
+
+		err := fn(rows)
+		if err != nil {
+			return err
+		}
+		rows.Close()
+
+		return rows.Err()
+	}
+}
+
+// Query sets fn to be called when the response to qq is received.
+func (qq *QueuedQuery) QueryRow(fn func(row Row) error) {
+	qq.Fn = func(br BatchResults) error {
+		row := br.QueryRow()
+		return fn(row)
+	}
+}
+
+// Exec sets fn to be called when the response to qq is received.
+//
+// Note: for simple batch insert uses where it is not required to handle
+// each potential error individually, it's sufficient to not set any callbacks,
+// and just handle the return value of [BatchResults.Close].
+func (qq *QueuedQuery) Exec(fn func(ct pgconn.CommandTag) error) {
+	qq.Fn = func(br BatchResults) error {
+		ct, err := br.Exec()
+		if err != nil {
+			return err
+		}
+
+		return fn(ct)
+	}
+}
+
+// Batch queries are a way of bundling multiple queries together to avoid
+// unnecessary network round trips. A Batch must only be sent once.
+type Batch struct {
+	QueuedQueries []*QueuedQuery
+}
+
+// Queue queues a query to batch b. query can be an SQL query or the name of a prepared statement. The only pgx option
+// argument that is supported is [QueryRewriter]. Queries are executed using the connection's DefaultQueryExecMode
+// (see [ConnConfig.DefaultQueryExecMode]).
+//
+// While query can contain multiple statements if the connection's DefaultQueryExecMode is [QueryExecModeSimpleProtocol],
+// this should be avoided. QueuedQuery.Fn must not be set as it will only be called for the first query. That is,
+// [QueuedQuery.Query], [QueuedQuery.QueryRow], and [QueuedQuery.Exec] must not be called. In addition, any error
+// messages or tracing that include the current query may reference the wrong query.
+func (b *Batch) Queue(query string, arguments ...any) *QueuedQuery {
+	qq := &QueuedQuery{
+		SQL:       query,
+		Arguments: arguments,
+	}
+	b.QueuedQueries = append(b.QueuedQueries, qq)
+	return qq
+}
+
+// Len returns number of queries that have been queued so far.
+func (b *Batch) Len() int {
+	return len(b.QueuedQueries)
+}
+
+type BatchResults interface {
+	// Exec reads the results from the next query in the batch as if the query has been sent with [Conn.Exec]. Prefer
+	// calling Exec on the QueuedQuery, or just calling Close.
+	Exec() (pgconn.CommandTag, error)
+
+	// Query reads the results from the next query in the batch as if the query has been sent with [Conn.Query]. Prefer
+	// calling [QueuedQuery.Query].
+	Query() (Rows, error)
+
+	// QueryRow reads the results from the next query in the batch as if the query has been sent with [Conn.QueryRow].
+	// Prefer calling [QueuedQuery.QueryRow].
+	QueryRow() Row
+
+	// Close closes the batch operation. All unread results are read and any callback functions registered with
+	// [QueuedQuery.Query], [QueuedQuery.QueryRow], or [QueuedQuery.Exec] will be called. If a callback function returns an
+	// error or the batch encounters an error subsequent callback functions will not be called.
+	//
+	// For simple batch inserts inside a transaction or similar queries, it's sufficient to not set any callbacks,
+	// and just handle the return value of Close.
+	//
+	// Close must be called before the underlying connection can be used again. Any error that occurred during a batch
+	// operation may have made it impossible to resyncronize the connection with the server. In this case the underlying
+	// connection will have been closed.
+	//
+	// Close is safe to call multiple times. If it returns an error subsequent calls will return the same error. Callback
+	// functions will not be rerun.
+	Close() error
+}
+
+type batchResults struct {
+	ctx       context.Context
+	conn      *Conn
+	mrr       *pgconn.MultiResultReader
+	err       error
+	b         *Batch
+	qqIdx     int
+	closed    bool
+	endTraced bool
+}
+
+// Exec reads the results from the next query in the batch as if the query has been sent with Exec.
+func (br *batchResults) Exec() (pgconn.CommandTag, error) {
+	if br.err != nil {
+		return pgconn.CommandTag{}, br.err
+	}
+	if br.closed {
+		return pgconn.CommandTag{}, fmt.Errorf("batch already closed")
+	}
+
+	query, arguments, _ := br.nextQueryAndArgs()
+
+	if !br.mrr.NextResult() {
+		err := br.mrr.Close()
+		if err == nil {
+			err = errors.New("no more results in batch")
+		}
+		if br.conn.batchTracer != nil {
+			br.conn.batchTracer.TraceBatchQuery(br.ctx, br.conn, TraceBatchQueryData{
+				SQL:  query,
+				Args: arguments,
+				Err:  err,
+			})
+		}
+		return pgconn.CommandTag{}, err
+	}
+
+	commandTag, err := br.mrr.ResultReader().Close()
+	if err != nil {
+		br.err = err
+		br.mrr.Close()
+	}
+
+	if br.conn.batchTracer != nil {
+		br.conn.batchTracer.TraceBatchQuery(br.ctx, br.conn, TraceBatchQueryData{
+			SQL:        query,
+			Args:       arguments,
+			CommandTag: commandTag,
+			Err:        br.err,
+		})
+	}
+
+	return commandTag, br.err
+}
+
+// Query reads the results from the next query in the batch as if the query has been sent with Query.
+func (br *batchResults) Query() (Rows, error) {
+	query, arguments, ok := br.nextQueryAndArgs()
+	if !ok {
+		query = "batch query"
+	}
+
+	if br.err != nil {
+		return &baseRows{err: br.err, closed: true}, br.err
+	}
+
+	if br.closed {
+		alreadyClosedErr := fmt.Errorf("batch already closed")
+		return &baseRows{err: alreadyClosedErr, closed: true}, alreadyClosedErr
+	}
+
+	rows := br.conn.getRows(br.ctx, query, arguments)
+	rows.batchTracer = br.conn.batchTracer
+
+	if !br.mrr.NextResult() {
+		rows.err = br.mrr.Close()
+		if rows.err == nil {
+			rows.err = errors.New("no more results in batch")
+		}
+		rows.closed = true
+
+		if br.conn.batchTracer != nil {
+			br.conn.batchTracer.TraceBatchQuery(br.ctx, br.conn, TraceBatchQueryData{
+				SQL:  query,
+				Args: arguments,
+				Err:  rows.err,
+			})
+		}
+
+		return rows, rows.err
+	}
+
+	rows.resultReader = br.mrr.ResultReader()
+	return rows, nil
+}
+
+// QueryRow reads the results from the next query in the batch as if the query has been sent with QueryRow.
+func (br *batchResults) QueryRow() Row {
+	rows, _ := br.Query()
+	return (*connRow)(rows.(*baseRows))
+}
+
+// Close closes the batch operation. Any error that occurred during a batch operation may have made it impossible to
+// resyncronize the connection with the server. In this case the underlying connection will have been closed.
+func (br *batchResults) Close() error {
+	defer func() {
+		if !br.endTraced {
+			if br.conn != nil && br.conn.batchTracer != nil {
+				br.conn.batchTracer.TraceBatchEnd(br.ctx, br.conn, TraceBatchEndData{Err: br.err})
+			}
+			br.endTraced = true
+		}
+
+		invalidateCachesOnBatchResultsError(br.conn, br.b, br.err)
+	}()
+
+	if br.err != nil {
+		return br.err
+	}
+
+	if br.closed {
+		return nil
+	}
+
+	// Read and run fn for all remaining items
+	for br.err == nil && !br.closed && br.b != nil && br.qqIdx < len(br.b.QueuedQueries) {
+		if br.b.QueuedQueries[br.qqIdx].Fn != nil {
+			err := br.b.QueuedQueries[br.qqIdx].Fn(br)
+			if err != nil {
+				br.err = err
+			}
+		} else {
+			br.Exec()
+		}
+	}
+
+	br.closed = true
+
+	err := br.mrr.Close()
+	if br.err == nil {
+		br.err = err
+	}
+
+	return br.err
+}
+
+func (br *batchResults) earlyError() error {
+	return br.err
+}
+
+func (br *batchResults) nextQueryAndArgs() (query string, args []any, ok bool) {
+	if br.b != nil && br.qqIdx < len(br.b.QueuedQueries) {
+		bi := br.b.QueuedQueries[br.qqIdx]
+		query = bi.SQL
+		args = bi.Arguments
+		ok = true
+		br.qqIdx++
+	}
+	return query, args, ok
+}
+
+type pipelineBatchResults struct {
+	ctx       context.Context
+	conn      *Conn
+	pipeline  *pgconn.Pipeline
+	lastRows  *baseRows
+	err       error
+	b         *Batch
+	qqIdx     int
+	closed    bool
+	endTraced bool
+}
+
+// Exec reads the results from the next query in the batch as if the query has been sent with Exec.
+func (br *pipelineBatchResults) Exec() (pgconn.CommandTag, error) {
+	if br.err != nil {
+		return pgconn.CommandTag{}, br.err
+	}
+	if br.closed {
+		return pgconn.CommandTag{}, fmt.Errorf("batch already closed")
+	}
+	if br.lastRows != nil && br.lastRows.err != nil {
+		br.err = br.lastRows.err
+		return pgconn.CommandTag{}, br.err
+	}
+
+	query, arguments, err := br.nextQueryAndArgs()
+	if err != nil {
+		return pgconn.CommandTag{}, err
+	}
+
+	results, err := br.pipeline.GetResults()
+	if err != nil {
+		br.err = err
+		return pgconn.CommandTag{}, br.err
+	}
+	var commandTag pgconn.CommandTag
+	switch results := results.(type) {
+	case *pgconn.ResultReader:
+		commandTag, br.err = results.Close()
+	default:
+		return pgconn.CommandTag{}, fmt.Errorf("unexpected pipeline result: %T", results)
+	}
+
+	if br.conn.batchTracer != nil {
+		br.conn.batchTracer.TraceBatchQuery(br.ctx, br.conn, TraceBatchQueryData{
+			SQL:        query,
+			Args:       arguments,
+			CommandTag: commandTag,
+			Err:        br.err,
+		})
+	}
+
+	return commandTag, br.err
+}
+
+// Query reads the results from the next query in the batch as if the query has been sent with Query.
+func (br *pipelineBatchResults) Query() (Rows, error) {
+	if br.err != nil {
+		return &baseRows{err: br.err, closed: true}, br.err
+	}
+
+	if br.closed {
+		alreadyClosedErr := fmt.Errorf("batch already closed")
+		return &baseRows{err: alreadyClosedErr, closed: true}, alreadyClosedErr
+	}
+
+	if br.lastRows != nil && br.lastRows.err != nil {
+		br.err = br.lastRows.err
+		return &baseRows{err: br.err, closed: true}, br.err
+	}
+
+	query, arguments, err := br.nextQueryAndArgs()
+	if err != nil {
+		return &baseRows{err: err, closed: true}, err
+	}
+
+	rows := br.conn.getRows(br.ctx, query, arguments)
+	rows.batchTracer = br.conn.batchTracer
+	br.lastRows = rows
+
+	results, err := br.pipeline.GetResults()
+	if err != nil {
+		br.err = err
+		rows.err = err
+		rows.closed = true
+
+		if br.conn.batchTracer != nil {
+			br.conn.batchTracer.TraceBatchQuery(br.ctx, br.conn, TraceBatchQueryData{
+				SQL:  query,
+				Args: arguments,
+				Err:  err,
+			})
+		}
+	} else {
+		switch results := results.(type) {
+		case *pgconn.ResultReader:
+			rows.resultReader = results
+		default:
+			err = fmt.Errorf("unexpected pipeline result: %T", results)
+			br.err = err
+			rows.err = err
+			rows.closed = true
+		}
+	}
+
+	return rows, rows.err
+}
+
+// QueryRow reads the results from the next query in the batch as if the query has been sent with QueryRow.
+func (br *pipelineBatchResults) QueryRow() Row {
+	rows, _ := br.Query()
+	return (*connRow)(rows.(*baseRows))
+}
+
+// Close closes the batch operation. Any error that occurred during a batch operation may have made it impossible to
+// resyncronize the connection with the server. In this case the underlying connection will have been closed.
+func (br *pipelineBatchResults) Close() error {
+	defer func() {
+		if !br.endTraced {
+			if br.conn.batchTracer != nil {
+				br.conn.batchTracer.TraceBatchEnd(br.ctx, br.conn, TraceBatchEndData{Err: br.err})
+			}
+			br.endTraced = true
+		}
+
+		invalidateCachesOnBatchResultsError(br.conn, br.b, br.err)
+	}()
+
+	if br.err == nil && br.lastRows != nil && br.lastRows.err != nil {
+		br.err = br.lastRows.err
+	}
+
+	if br.closed {
+		return br.err
+	}
+
+	// Read and run fn for all remaining items
+	for br.err == nil && !br.closed && br.b != nil && br.qqIdx < len(br.b.QueuedQueries) {
+		if br.b.QueuedQueries[br.qqIdx].Fn != nil {
+			err := br.b.QueuedQueries[br.qqIdx].Fn(br)
+			if err != nil {
+				br.err = err
+			}
+		} else {
+			br.Exec()
+		}
+	}
+
+	br.closed = true
+
+	err := br.pipeline.Close()
+	if br.err == nil {
+		br.err = err
+	}
+
+	return br.err
+}
+
+func (br *pipelineBatchResults) earlyError() error {
+	return br.err
+}
+
+func (br *pipelineBatchResults) nextQueryAndArgs() (query string, args []any, err error) {
+	if br.b == nil {
+		return "", nil, errors.New("no reference to batch")
+	}
+
+	if br.qqIdx >= len(br.b.QueuedQueries) {
+		return "", nil, errors.New("no more results in batch")
+	}
+
+	bi := br.b.QueuedQueries[br.qqIdx]
+	br.qqIdx++
+	return bi.SQL, bi.Arguments, nil
+}
+
+type emptyBatchResults struct {
+	conn   *Conn
+	closed bool
+}
+
+// Exec reads the results from the next query in the batch as if the query has been sent with Exec.
+func (br *emptyBatchResults) Exec() (pgconn.CommandTag, error) {
+	if br.closed {
+		return pgconn.CommandTag{}, fmt.Errorf("batch already closed")
+	}
+	return pgconn.CommandTag{}, errors.New("no more results in batch")
+}
+
+// Query reads the results from the next query in the batch as if the query has been sent with Query.
+func (br *emptyBatchResults) Query() (Rows, error) {
+	if br.closed {
+		alreadyClosedErr := fmt.Errorf("batch already closed")
+		return &baseRows{err: alreadyClosedErr, closed: true}, alreadyClosedErr
+	}
+
+	rows := br.conn.getRows(context.Background(), "", nil)
+	rows.err = errors.New("no more results in batch")
+	rows.closed = true
+	return rows, rows.err
+}
+
+// QueryRow reads the results from the next query in the batch as if the query has been sent with QueryRow.
+func (br *emptyBatchResults) QueryRow() Row {
+	rows, _ := br.Query()
+	return (*connRow)(rows.(*baseRows))
+}
+
+// Close closes the batch operation. Any error that occurred during a batch operation may have made it impossible to
+// resyncronize the connection with the server. In this case the underlying connection will have been closed.
+func (br *emptyBatchResults) Close() error {
+	br.closed = true
+	return nil
+}
+
+// invalidates statement and description caches on batch results error
+func invalidateCachesOnBatchResultsError(conn *Conn, b *Batch, err error) {
+	if err != nil && conn != nil && b != nil {
+		if sc := conn.statementCache; sc != nil {
+			for _, bi := range b.QueuedQueries {
+				sc.Invalidate(bi.SQL)
+			}
+		}
+
+		if sc := conn.descriptionCache; sc != nil {
+			for _, bi := range b.QueuedQueries {
+				sc.Invalidate(bi.SQL)
+			}
+		}
+	}
+}
+
+// ErrPreprocessingBatch occurs when an error is encountered while preprocessing a batch.
+// The two preprocessing steps are "prepare" (server-side SQL parse/plan) and
+// "build" (client-side argument encoding).
+type ErrPreprocessingBatch struct {
+	step string // "prepare" or "build"
+	sql  string
+	err  error
+}
+
+func newErrPreprocessingBatch(step, sql string, err error) ErrPreprocessingBatch {
+	return ErrPreprocessingBatch{step: step, sql: sql, err: err}
+}
+
+func (e ErrPreprocessingBatch) Error() string {
+	// intentionally not including the SQL query in the error message
+	// to avoid leaking potentially sensitive information into logs.
+	// If the user wants the SQL, they can call SQL().
+	return fmt.Sprintf("error preprocessing batch (%s): %v", e.step, e.err)
+}
+
+func (e ErrPreprocessingBatch) Unwrap() error {
+	return e.err
+}
+
+func (e ErrPreprocessingBatch) SQL() string {
+	return e.sql
+}
diff --git a/vendor/github.com/jackc/pgx/v5/conn.go b/vendor/github.com/jackc/pgx/v5/conn.go
new file mode 100644
index 000000000..bc5d06493
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/conn.go
@@ -0,0 +1,1472 @@
+package pgx
+
+import (
+	"context"
+	"crypto/sha256"
+	"database/sql"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/jackc/pgx/v5/internal/sanitize"
+	"github.com/jackc/pgx/v5/internal/stmtcache"
+	"github.com/jackc/pgx/v5/pgconn"
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+// ConnConfig contains all the options used to establish a connection. It must be created by [ParseConfig] and
+// then it can be modified. A manually initialized ConnConfig will cause [ConnectConfig] to panic.
+type ConnConfig struct {
+	pgconn.Config
+
+	Tracer QueryTracer
+
+	// Original connection string that was parsed into config.
+	connString string
+
+	// StatementCacheCapacity is maximum size of the statement cache used when executing a query with "cache_statement"
+	// query exec mode.
+	StatementCacheCapacity int
+
+	// DescriptionCacheCapacity is the maximum size of the description cache used when executing a query with
+	// "cache_describe" query exec mode.
+	DescriptionCacheCapacity int
+
+	// DefaultQueryExecMode controls the default mode for executing queries. By default pgx uses the extended protocol
+	// and automatically prepares and caches prepared statements. However, this may be incompatible with proxies such as
+	// PGBouncer. In this case it may be preferable to use [QueryExecModeExec] or [QueryExecModeSimpleProtocol]. The same
+	// functionality can be controlled on a per query basis by passing a [QueryExecMode] as the first query argument.
+	DefaultQueryExecMode QueryExecMode
+
+	createdByParseConfig bool // Used to enforce created by ParseConfig rule.
+}
+
+// ParseConfigOptions contains options that control how a config is built such as getsslpassword.
+type ParseConfigOptions struct {
+	pgconn.ParseConfigOptions
+}
+
+// Copy returns a deep copy of the config that is safe to use and modify.
+// The only exception is the tls.Config:
+// according to the tls.Config docs it must not be modified after creation.
+func (cc *ConnConfig) Copy() *ConnConfig {
+	newConfig := new(ConnConfig)
+	*newConfig = *cc
+	newConfig.Config = *newConfig.Config.Copy()
+	return newConfig
+}
+
+// ConnString returns the connection string as parsed by pgx.ParseConfig into pgx.ConnConfig.
+func (cc *ConnConfig) ConnString() string { return cc.connString }
+
+// Conn is a PostgreSQL connection handle. It is not safe for concurrent usage. Use a connection pool to manage access
+// to multiple database connections from multiple goroutines.
+type Conn struct {
+	pgConn                  *pgconn.PgConn
+	config                  *ConnConfig // config used when establishing this connection
+	preparedStatements      map[string]*pgconn.StatementDescription
+	failedDescribeStatement string
+	statementCache          stmtcache.Cache
+	descriptionCache        stmtcache.Cache
+
+	queryTracer    QueryTracer
+	batchTracer    BatchTracer
+	copyFromTracer CopyFromTracer
+	prepareTracer  PrepareTracer
+
+	notifications []*pgconn.Notification
+
+	doneChan   chan struct{}
+	closedChan chan error
+
+	typeMap *pgtype.Map
+
+	wbuf []byte
+	eqb  ExtendedQueryBuilder
+}
+
+// Identifier a PostgreSQL identifier or name. Identifiers can be composed of
+// multiple parts such as ["schema", "table"] or ["table", "column"].
+type Identifier []string
+
+// Sanitize returns a sanitized string safe for SQL interpolation.
+func (ident Identifier) Sanitize() string {
+	parts := make([]string, len(ident))
+	for i := range ident {
+		s := strings.ReplaceAll(ident[i], string([]byte{0}), "")
+		parts[i] = `"` + strings.ReplaceAll(s, `"`, `""`) + `"`
+	}
+	return strings.Join(parts, ".")
+}
+
+var (
+	// ErrNoRows occurs when rows are expected but none are returned.
+	ErrNoRows = newProxyErr(sql.ErrNoRows, "no rows in result set")
+	// ErrTooManyRows occurs when more rows than expected are returned.
+	ErrTooManyRows = errors.New("too many rows in result set")
+)
+
+func newProxyErr(background error, msg string) error {
+	return &proxyError{
+		msg:        msg,
+		background: background,
+	}
+}
+
+type proxyError struct {
+	msg        string
+	background error
+}
+
+func (err *proxyError) Error() string { return err.msg }
+
+func (err *proxyError) Unwrap() error { return err.background }
+
+var (
+	errDisabledStatementCache   = fmt.Errorf("cannot use QueryExecModeCacheStatement with disabled statement cache")
+	errDisabledDescriptionCache = fmt.Errorf("cannot use QueryExecModeCacheDescribe with disabled description cache")
+)
+
+// Connect establishes a connection with a PostgreSQL server with a connection string. See
+// [pgconn.Connect] for details.
+func Connect(ctx context.Context, connString string) (*Conn, error) {
+	connConfig, err := ParseConfig(connString)
+	if err != nil {
+		return nil, err
+	}
+	return connect(ctx, connConfig)
+}
+
+// ConnectWithOptions behaves exactly like Connect with the addition of options. At the present options is only used to
+// provide a [pgconn.GetSSLPasswordFunc] function.
+func ConnectWithOptions(ctx context.Context, connString string, options ParseConfigOptions) (*Conn, error) {
+	connConfig, err := ParseConfigWithOptions(connString, options)
+	if err != nil {
+		return nil, err
+	}
+	return connect(ctx, connConfig)
+}
+
+// ConnectConfig establishes a connection with a PostgreSQL server with a configuration struct.
+// connConfig must have been created by [ParseConfig].
+func ConnectConfig(ctx context.Context, connConfig *ConnConfig) (*Conn, error) {
+	// In general this improves safety. In particular avoid the config.Config.OnNotification mutation from affecting other
+	// connections with the same config. See https://github.com/jackc/pgx/issues/618.
+	connConfig = connConfig.Copy()
+
+	return connect(ctx, connConfig)
+}
+
+// ParseConfigWithOptions behaves exactly as [ParseConfig] does with the addition of options. At the present options is
+// only used to provide a [pgconn.GetSSLPasswordFunc] function.
+func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*ConnConfig, error) {
+	config, err := pgconn.ParseConfigWithOptions(connString, options.ParseConfigOptions)
+	if err != nil {
+		return nil, err
+	}
+
+	statementCacheCapacity := 512
+	if s, ok := config.RuntimeParams["statement_cache_capacity"]; ok {
+		delete(config.RuntimeParams, "statement_cache_capacity")
+		n, err := strconv.ParseInt(s, 10, 32)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse statement_cache_capacity", err)
+		}
+		statementCacheCapacity = int(n)
+	}
+
+	descriptionCacheCapacity := 512
+	if s, ok := config.RuntimeParams["description_cache_capacity"]; ok {
+		delete(config.RuntimeParams, "description_cache_capacity")
+		n, err := strconv.ParseInt(s, 10, 32)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse description_cache_capacity", err)
+		}
+		descriptionCacheCapacity = int(n)
+	}
+
+	defaultQueryExecMode := QueryExecModeCacheStatement
+	if s, ok := config.RuntimeParams["default_query_exec_mode"]; ok {
+		delete(config.RuntimeParams, "default_query_exec_mode")
+		switch s {
+		case "cache_statement":
+			defaultQueryExecMode = QueryExecModeCacheStatement
+		case "cache_describe":
+			defaultQueryExecMode = QueryExecModeCacheDescribe
+		case "describe_exec":
+			defaultQueryExecMode = QueryExecModeDescribeExec
+		case "exec":
+			defaultQueryExecMode = QueryExecModeExec
+		case "simple_protocol":
+			defaultQueryExecMode = QueryExecModeSimpleProtocol
+		default:
+			return nil, pgconn.NewParseConfigError(
+				connString, "invalid default_query_exec_mode", fmt.Errorf("unknown value %q", s),
+			)
+		}
+	}
+
+	connConfig := &ConnConfig{
+		Config:                   *config,
+		createdByParseConfig:     true,
+		StatementCacheCapacity:   statementCacheCapacity,
+		DescriptionCacheCapacity: descriptionCacheCapacity,
+		DefaultQueryExecMode:     defaultQueryExecMode,
+		connString:               connString,
+	}
+
+	return connConfig, nil
+}
+
+// ParseConfig creates a ConnConfig from a connection string. ParseConfig handles all options that [pgconn.ParseConfig]
+// does. In addition, it accepts the following options:
+//
+//   - default_query_exec_mode.
+//     Possible values: "cache_statement", "cache_describe", "describe_exec", "exec", and "simple_protocol". See
+//     QueryExecMode constant documentation for the meaning of these values. Default: "cache_statement".
+//
+//   - statement_cache_capacity.
+//     The maximum size of the statement cache used when executing a query with "cache_statement" query exec mode.
+//     Default: 512.
+//
+//   - description_cache_capacity.
+//     The maximum size of the description cache used when executing a query with "cache_describe" query exec mode.
+//     Default: 512.
+func ParseConfig(connString string) (*ConnConfig, error) {
+	return ParseConfigWithOptions(connString, ParseConfigOptions{})
+}
+
+// connect connects to a database. connect takes ownership of config. The caller must not use or access it again.
+func connect(ctx context.Context, config *ConnConfig) (c *Conn, err error) {
+	if connectTracer, ok := config.Tracer.(ConnectTracer); ok {
+		ctx = connectTracer.TraceConnectStart(ctx, TraceConnectStartData{ConnConfig: config})
+		defer func() {
+			connectTracer.TraceConnectEnd(ctx, TraceConnectEndData{Conn: c, Err: err})
+		}()
+	}
+
+	// Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from
+	// zero values.
+	if !config.createdByParseConfig {
+		panic("config must be created by ParseConfig")
+	}
+
+	c = &Conn{
+		config:      config,
+		typeMap:     pgtype.NewMap(),
+		queryTracer: config.Tracer,
+	}
+
+	if t, ok := c.queryTracer.(BatchTracer); ok {
+		c.batchTracer = t
+	}
+	if t, ok := c.queryTracer.(CopyFromTracer); ok {
+		c.copyFromTracer = t
+	}
+	if t, ok := c.queryTracer.(PrepareTracer); ok {
+		c.prepareTracer = t
+	}
+
+	// Only install pgx notification system if no other callback handler is present.
+	if config.Config.OnNotification == nil {
+		config.Config.OnNotification = c.bufferNotifications
+	}
+
+	c.pgConn, err = pgconn.ConnectConfig(ctx, &config.Config)
+	if err != nil {
+		return nil, err
+	}
+
+	c.preparedStatements = make(map[string]*pgconn.StatementDescription)
+	c.doneChan = make(chan struct{})
+	c.closedChan = make(chan error)
+	c.wbuf = make([]byte, 0, 1024)
+
+	if c.config.StatementCacheCapacity > 0 {
+		c.statementCache = stmtcache.NewLRUCache(c.config.StatementCacheCapacity)
+	}
+
+	if c.config.DescriptionCacheCapacity > 0 {
+		c.descriptionCache = stmtcache.NewLRUCache(c.config.DescriptionCacheCapacity)
+	}
+
+	return c, nil
+}
+
+// Close closes a connection. It is safe to call Close on an already closed
+// connection.
+func (c *Conn) Close(ctx context.Context) error {
+	if c.IsClosed() {
+		return nil
+	}
+
+	err := c.pgConn.Close(ctx)
+	return err
+}
+
+// Prepare creates a prepared statement with name and sql. sql can contain placeholders for bound parameters. These
+// placeholders are referenced positionally as $1, $2, etc. name can be used instead of sql with [Conn.Query],
+// [Conn.QueryRow], and [Conn.Exec] to execute the statement. It can also be used with [Batch.Queue].
+//
+// The underlying PostgreSQL identifier for the prepared statement will be name if name != sql or a digest of sql if
+// name == sql.
+//
+// Prepare is idempotent; i.e. it is safe to call Prepare multiple times with the same name and sql arguments. This
+// allows a code path to Prepare and Query/Exec without concern for if the statement has already been prepared.
+func (c *Conn) Prepare(ctx context.Context, name, sql string) (sd *pgconn.StatementDescription, err error) {
+	if c.failedDescribeStatement != "" {
+		err = c.Deallocate(ctx, c.failedDescribeStatement)
+		if err != nil {
+			return nil, fmt.Errorf("failed to deallocate previously failed statement %q: %w", c.failedDescribeStatement, err)
+		}
+		c.failedDescribeStatement = ""
+	}
+
+	if c.prepareTracer != nil {
+		ctx = c.prepareTracer.TracePrepareStart(ctx, c, TracePrepareStartData{Name: name, SQL: sql})
+	}
+
+	if name != "" {
+		var ok bool
+		if sd, ok = c.preparedStatements[name]; ok && sd.SQL == sql {
+			if c.prepareTracer != nil {
+				c.prepareTracer.TracePrepareEnd(ctx, c, TracePrepareEndData{AlreadyPrepared: true})
+			}
+			return sd, nil
+		}
+	}
+
+	if c.prepareTracer != nil {
+		defer func() {
+			c.prepareTracer.TracePrepareEnd(ctx, c, TracePrepareEndData{Err: err})
+		}()
+	}
+
+	var psName, psKey string
+	if name == sql {
+		digest := sha256.Sum256([]byte(sql))
+		psName = "stmt_" + hex.EncodeToString(digest[0:24])
+		psKey = sql
+	} else {
+		psName = name
+		psKey = name
+	}
+
+	sd, err = c.pgConn.Prepare(ctx, psName, sql, nil)
+	if err != nil {
+		var pErr *pgconn.PrepareError
+		if errors.As(err, &pErr) {
+			c.failedDescribeStatement = psKey
+		}
+		return nil, err
+	}
+
+	if psKey != "" {
+		c.preparedStatements[psKey] = sd
+	}
+
+	return sd, nil
+}
+
+// Deallocate releases a prepared statement. Calling Deallocate on a non-existent prepared statement will succeed.
+func (c *Conn) Deallocate(ctx context.Context, name string) error {
+	var psName string
+	sd := c.preparedStatements[name]
+	if sd != nil {
+		psName = sd.Name
+	} else {
+		psName = name
+	}
+
+	err := c.pgConn.Deallocate(ctx, psName)
+	if err != nil {
+		return err
+	}
+
+	if sd != nil {
+		delete(c.preparedStatements, name)
+	}
+
+	return nil
+}
+
+// DeallocateAll releases all previously prepared statements from the server and client, where it also resets the statement and description cache.
+func (c *Conn) DeallocateAll(ctx context.Context) error {
+	c.preparedStatements = map[string]*pgconn.StatementDescription{}
+	if c.config.StatementCacheCapacity > 0 {
+		c.statementCache = stmtcache.NewLRUCache(c.config.StatementCacheCapacity)
+	}
+	if c.config.DescriptionCacheCapacity > 0 {
+		c.descriptionCache = stmtcache.NewLRUCache(c.config.DescriptionCacheCapacity)
+	}
+	_, err := c.pgConn.Exec(ctx, "deallocate all").ReadAll()
+	return err
+}
+
+func (c *Conn) bufferNotifications(_ *pgconn.PgConn, n *pgconn.Notification) {
+	c.notifications = append(c.notifications, n)
+}
+
+// WaitForNotification waits for a PostgreSQL notification. It wraps the underlying pgconn notification system in a
+// slightly more convenient form.
+func (c *Conn) WaitForNotification(ctx context.Context) (*pgconn.Notification, error) {
+	var n *pgconn.Notification
+
+	// Return already received notification immediately
+	if len(c.notifications) > 0 {
+		n = c.notifications[0]
+		c.notifications = c.notifications[1:]
+		return n, nil
+	}
+
+	err := c.pgConn.WaitForNotification(ctx)
+	if len(c.notifications) > 0 {
+		n = c.notifications[0]
+		c.notifications = c.notifications[1:]
+	}
+	return n, err
+}
+
+// IsClosed reports if the connection has been closed.
+func (c *Conn) IsClosed() bool {
+	return c.pgConn.IsClosed()
+}
+
+func (c *Conn) die() {
+	if c.IsClosed() {
+		return
+	}
+
+	ctx, cancel := context.WithCancel(context.Background())
+	cancel() // force immediate hard cancel
+	c.pgConn.Close(ctx)
+}
+
+func quoteIdentifier(s string) string {
+	return `"` + strings.ReplaceAll(s, `"`, `""`) + `"`
+}
+
+// Ping delegates to the underlying *pgconn.PgConn.Ping.
+func (c *Conn) Ping(ctx context.Context) error {
+	return c.pgConn.Ping(ctx)
+}
+
+// PgConn returns the underlying *pgconn.PgConn. This is an escape hatch method that allows lower level access to the
+// PostgreSQL connection than pgx exposes.
+//
+// It is strongly recommended that the connection be idle (no in-progress queries) before the underlying *pgconn.PgConn
+// is used and the connection must be returned to the same state before any *pgx.Conn methods are again used.
+func (c *Conn) PgConn() *pgconn.PgConn { return c.pgConn }
+
+// TypeMap returns the connection info used for this connection.
+func (c *Conn) TypeMap() *pgtype.Map { return c.typeMap }
+
+// Config returns a copy of config that was used to establish this connection.
+func (c *Conn) Config() *ConnConfig { return c.config.Copy() }
+
+// Exec executes sql. sql can be either a prepared statement name or an SQL string. arguments should be referenced
+// positionally from the sql string as $1, $2, etc.
+func (c *Conn) Exec(ctx context.Context, sql string, arguments ...any) (pgconn.CommandTag, error) {
+	if c.queryTracer != nil {
+		ctx = c.queryTracer.TraceQueryStart(ctx, c, TraceQueryStartData{SQL: sql, Args: arguments})
+	}
+
+	if err := c.deallocateInvalidatedCachedStatements(ctx); err != nil {
+		return pgconn.CommandTag{}, err
+	}
+
+	commandTag, err := c.exec(ctx, sql, arguments...)
+
+	if c.queryTracer != nil {
+		c.queryTracer.TraceQueryEnd(ctx, c, TraceQueryEndData{CommandTag: commandTag, Err: err})
+	}
+
+	return commandTag, err
+}
+
+func (c *Conn) exec(ctx context.Context, sql string, arguments ...any) (commandTag pgconn.CommandTag, err error) {
+	mode := c.config.DefaultQueryExecMode
+	var queryRewriter QueryRewriter
+
+optionLoop:
+	for len(arguments) > 0 {
+		switch arg := arguments[0].(type) {
+		case QueryExecMode:
+			mode = arg
+			arguments = arguments[1:]
+		case QueryRewriter:
+			queryRewriter = arg
+			arguments = arguments[1:]
+		default:
+			break optionLoop
+		}
+	}
+
+	if queryRewriter != nil {
+		sql, arguments, err = queryRewriter.RewriteQuery(ctx, c, sql, arguments)
+		if err != nil {
+			return pgconn.CommandTag{}, fmt.Errorf("rewrite query failed: %w", err)
+		}
+	}
+
+	// Always use simple protocol when there are no arguments.
+	if len(arguments) == 0 {
+		mode = QueryExecModeSimpleProtocol
+	}
+
+	defer func() {
+		if err != nil {
+			if sc := c.statementCache; sc != nil {
+				sc.Invalidate(sql)
+			}
+
+			if sc := c.descriptionCache; sc != nil {
+				sc.Invalidate(sql)
+			}
+		}
+	}()
+
+	if sd, ok := c.preparedStatements[sql]; ok {
+		return c.execPrepared(ctx, sd, arguments)
+	}
+
+	switch mode {
+	case QueryExecModeCacheStatement:
+		if c.statementCache == nil {
+			return pgconn.CommandTag{}, errDisabledStatementCache
+		}
+		sd := c.statementCache.Get(sql)
+		if sd == nil {
+			sd, err = c.Prepare(ctx, stmtcache.StatementName(sql), sql)
+			if err != nil {
+				return pgconn.CommandTag{}, err
+			}
+			c.statementCache.Put(sd)
+		}
+
+		return c.execPrepared(ctx, sd, arguments)
+	case QueryExecModeCacheDescribe:
+		if c.descriptionCache == nil {
+			return pgconn.CommandTag{}, errDisabledDescriptionCache
+		}
+		sd := c.descriptionCache.Get(sql)
+		if sd == nil {
+			sd, err = c.Prepare(ctx, "", sql)
+			if err != nil {
+				return pgconn.CommandTag{}, err
+			}
+			c.descriptionCache.Put(sd)
+		}
+
+		return c.execParams(ctx, sd, arguments)
+	case QueryExecModeDescribeExec:
+		sd, err := c.Prepare(ctx, "", sql)
+		if err != nil {
+			return pgconn.CommandTag{}, err
+		}
+		return c.execPrepared(ctx, sd, arguments)
+	case QueryExecModeExec:
+		return c.execSQLParams(ctx, sql, arguments)
+	case QueryExecModeSimpleProtocol:
+		return c.execSimpleProtocol(ctx, sql, arguments)
+	default:
+		return pgconn.CommandTag{}, fmt.Errorf("unknown QueryExecMode: %v", mode)
+	}
+}
+
+func (c *Conn) execSimpleProtocol(ctx context.Context, sql string, arguments []any) (commandTag pgconn.CommandTag, err error) {
+	if len(arguments) > 0 {
+		sql, err = c.sanitizeForSimpleQuery(sql, arguments...)
+		if err != nil {
+			return pgconn.CommandTag{}, err
+		}
+	}
+
+	mrr := c.pgConn.Exec(ctx, sql)
+	for mrr.NextResult() {
+		commandTag, _ = mrr.ResultReader().Close()
+	}
+	err = mrr.Close()
+	return commandTag, err
+}
+
+func (c *Conn) execParams(ctx context.Context, sd *pgconn.StatementDescription, arguments []any) (pgconn.CommandTag, error) {
+	err := c.eqb.Build(c.typeMap, sd, arguments)
+	if err != nil {
+		return pgconn.CommandTag{}, err
+	}
+
+	result := c.pgConn.ExecParams(ctx, sd.SQL, c.eqb.ParamValues, sd.ParamOIDs, c.eqb.ParamFormats, c.eqb.ResultFormats).Read()
+	c.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.
+	return result.CommandTag, result.Err
+}
+
+func (c *Conn) execPrepared(ctx context.Context, sd *pgconn.StatementDescription, arguments []any) (pgconn.CommandTag, error) {
+	err := c.eqb.Build(c.typeMap, sd, arguments)
+	if err != nil {
+		return pgconn.CommandTag{}, err
+	}
+
+	result := c.pgConn.ExecStatement(ctx, sd, c.eqb.ParamValues, c.eqb.ParamFormats, c.eqb.ResultFormats).Read()
+	c.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.
+	return result.CommandTag, result.Err
+}
+
+func (c *Conn) execSQLParams(ctx context.Context, sql string, args []any) (pgconn.CommandTag, error) {
+	err := c.eqb.Build(c.typeMap, nil, args)
+	if err != nil {
+		return pgconn.CommandTag{}, err
+	}
+
+	result := c.pgConn.ExecParams(ctx, sql, c.eqb.ParamValues, nil, c.eqb.ParamFormats, c.eqb.ResultFormats).Read()
+	c.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.
+	return result.CommandTag, result.Err
+}
+
+func (c *Conn) getRows(ctx context.Context, sql string, args []any) *baseRows {
+	r := &baseRows{}
+
+	r.ctx = ctx
+	r.queryTracer = c.queryTracer
+	r.typeMap = c.typeMap
+	r.startTime = time.Now()
+	r.sql = sql
+	r.args = args
+	r.conn = c
+
+	return r
+}
+
+type QueryExecMode int32
+
+const (
+	_ QueryExecMode = iota
+
+	// Automatically prepare and cache statements. This uses the extended protocol. Queries are executed in a single round
+	// trip after the statement is cached. This is the default. If the database schema is modified or the search_path is
+	// changed after a statement is cached then the first execution of a previously cached query may fail. e.g. If the
+	// number of columns returned by a "SELECT *" changes or the type of a column is changed.
+	QueryExecModeCacheStatement
+
+	// Cache statement descriptions (i.e. argument and result types) and assume they do not change. This uses the extended
+	// protocol. Queries are executed in a single round trip after the description is cached. If the database schema is
+	// modified or the search_path is changed after a statement is cached then the first execution of a previously cached
+	// query may fail. e.g. If the number of columns returned by a "SELECT *" changes or the type of a column is changed.
+	QueryExecModeCacheDescribe
+
+	// Get the statement description on every execution. This uses the extended protocol. Queries require two round trips
+	// to execute. It does not use named prepared statements. But it does use the unnamed prepared statement to get the
+	// statement description on the first round trip and then uses it to execute the query on the second round trip. This
+	// may cause problems with connection poolers that switch the underlying connection between round trips. It is safe
+	// even when the database schema is modified concurrently.
+	QueryExecModeDescribeExec
+
+	// Assume the PostgreSQL query parameter types based on the Go type of the arguments. This uses the extended protocol
+	// with text formatted parameters and results. Queries are executed in a single round trip. Type mappings can be
+	// registered with pgtype.Map.RegisterDefaultPgType. Queries will be rejected that have arguments that are
+	// unregistered or ambiguous. e.g. A map[string]string may have the PostgreSQL type json or hstore. Modes that know
+	// the PostgreSQL type can use a map[string]string directly as an argument. This mode cannot.
+	//
+	// On rare occasions user defined types may behave differently when encoded in the text format instead of the binary
+	// format. For example, this could happen if a "type RomanNumeral int32" implements fmt.Stringer to format integers as
+	// Roman numerals (e.g. 7 is VII). The binary format would properly encode the integer 7 as the binary value for 7.
+	// But the text format would encode the integer 7 as the string "VII". As QueryExecModeExec uses the text format, it
+	// is possible that changing query mode from another mode to QueryExecModeExec could change the behavior of the query.
+	// This should not occur with types pgx supports directly and can be avoided by registering the types with
+	// pgtype.Map.RegisterDefaultPgType and implementing the appropriate type interfaces. In the cas of RomanNumeral, it
+	// should implement pgtype.Int64Valuer.
+	QueryExecModeExec
+
+	// Use the simple protocol. Assume the PostgreSQL query parameter types based on the Go type of the arguments. This is
+	// especially significant for []byte values. []byte values are encoded as PostgreSQL bytea. string must be used
+	// instead for text type values including json and jsonb. Type mappings can be registered with
+	// pgtype.Map.RegisterDefaultPgType. Queries will be rejected that have arguments that are unregistered or ambiguous.
+	// e.g. A map[string]string may have the PostgreSQL type json or hstore. Modes that know the PostgreSQL type can use a
+	// map[string]string directly as an argument. This mode cannot. Queries are executed in a single round trip.
+	//
+	// QueryExecModeSimpleProtocol should have the user application visible behavior as QueryExecModeExec. This includes
+	// the warning regarding differences in text format and binary format encoding with user defined types. There may be
+	// other minor exceptions such as behavior when multiple result returning queries are erroneously sent in a single
+	// string.
+	//
+	// QueryExecModeSimpleProtocol uses client side parameter interpolation. All values are quoted and escaped. Prefer
+	// QueryExecModeExec over QueryExecModeSimpleProtocol whenever possible. In general QueryExecModeSimpleProtocol should
+	// only be used if connecting to a proxy server, connection pool server, or non-PostgreSQL server that does not
+	// support the extended protocol.
+	QueryExecModeSimpleProtocol
+)
+
+func (m QueryExecMode) String() string {
+	switch m {
+	case QueryExecModeCacheStatement:
+		return "cache statement"
+	case QueryExecModeCacheDescribe:
+		return "cache describe"
+	case QueryExecModeDescribeExec:
+		return "describe exec"
+	case QueryExecModeExec:
+		return "exec"
+	case QueryExecModeSimpleProtocol:
+		return "simple protocol"
+	default:
+		return "invalid"
+	}
+}
+
+// QueryResultFormats controls the result format (text=0, binary=1) of a query by result column position.
+type QueryResultFormats []int16
+
+// QueryResultFormatsByOID controls the result format (text=0, binary=1) of a query by the result column OID.
+type QueryResultFormatsByOID map[uint32]int16
+
+// QueryRewriter rewrites a query when used as the first arguments to a query method.
+type QueryRewriter interface {
+	RewriteQuery(ctx context.Context, conn *Conn, sql string, args []any) (newSQL string, newArgs []any, err error)
+}
+
+// Query sends a query to the server and returns a Rows to read the results. Only errors encountered sending the query
+// and initializing Rows will be returned. Err() on the returned Rows must be checked after the Rows is closed to
+// determine if the query executed successfully.
+//
+// The returned Rows must be closed before the connection can be used again. It is safe to attempt to read from the
+// returned Rows even if an error is returned. The error will be the available in rows.Err() after rows are closed. It
+// is allowed to ignore the error returned from Query and handle it in Rows.
+//
+// It is possible for a call of FieldDescriptions on the returned Rows to return nil even if the Query call did not
+// return an error.
+//
+// It is possible for a query to return one or more rows before encountering an error. In most cases the rows should be
+// collected before processing rather than processed while receiving each row. This avoids the possibility of the
+// application processing rows from a query that the server rejected. The CollectRows function is useful here.
+//
+// An implementor of QueryRewriter may be passed as the first element of args. It can rewrite the sql and change or
+// replace args. For example, NamedArgs is QueryRewriter that implements named arguments.
+//
+// For extra control over how the query is executed, the types QueryExecMode, QueryResultFormats, and
+// QueryResultFormatsByOID may be used as the first args to control exactly how the query is executed. This is rarely
+// needed. See the documentation for those types for details.
+func (c *Conn) Query(ctx context.Context, sql string, args ...any) (Rows, error) {
+	if c.queryTracer != nil {
+		ctx = c.queryTracer.TraceQueryStart(ctx, c, TraceQueryStartData{SQL: sql, Args: args})
+	}
+
+	if err := c.deallocateInvalidatedCachedStatements(ctx); err != nil {
+		if c.queryTracer != nil {
+			c.queryTracer.TraceQueryEnd(ctx, c, TraceQueryEndData{Err: err})
+		}
+		return &baseRows{err: err, closed: true}, err
+	}
+
+	var resultFormats QueryResultFormats
+	var resultFormatsByOID QueryResultFormatsByOID
+	mode := c.config.DefaultQueryExecMode
+	var queryRewriter QueryRewriter
+
+optionLoop:
+	for len(args) > 0 {
+		switch arg := args[0].(type) {
+		case QueryResultFormats:
+			resultFormats = arg
+			args = args[1:]
+		case QueryResultFormatsByOID:
+			resultFormatsByOID = arg
+			args = args[1:]
+		case QueryExecMode:
+			mode = arg
+			args = args[1:]
+		case QueryRewriter:
+			queryRewriter = arg
+			args = args[1:]
+		default:
+			break optionLoop
+		}
+	}
+
+	if queryRewriter != nil {
+		var err error
+		originalSQL := sql
+		originalArgs := args
+		sql, args, err = queryRewriter.RewriteQuery(ctx, c, sql, args)
+		if err != nil {
+			rows := c.getRows(ctx, originalSQL, originalArgs)
+			err = fmt.Errorf("rewrite query failed: %w", err)
+			rows.fatal(err)
+			return rows, err
+		}
+	}
+
+	// Bypass any statement caching.
+	if sql == "" {
+		mode = QueryExecModeSimpleProtocol
+	}
+
+	c.eqb.reset()
+	rows := c.getRows(ctx, sql, args)
+
+	var err error
+	sd, explicitPreparedStatement := c.preparedStatements[sql]
+	switch {
+	case sd != nil || mode == QueryExecModeCacheStatement || mode == QueryExecModeCacheDescribe || mode == QueryExecModeDescribeExec:
+		if sd == nil {
+			sd, err = c.getStatementDescription(ctx, mode, sql)
+			if err != nil {
+				rows.fatal(err)
+				return rows, err
+			}
+		}
+
+		if len(sd.ParamOIDs) != len(args) {
+			rows.fatal(fmt.Errorf("expected %d arguments, got %d", len(sd.ParamOIDs), len(args)))
+			return rows, rows.err
+		}
+
+		rows.sql = sd.SQL
+
+		err = c.eqb.Build(c.typeMap, sd, args)
+		if err != nil {
+			rows.fatal(err)
+			return rows, rows.err
+		}
+
+		if resultFormatsByOID != nil {
+			resultFormats = make([]int16, len(sd.Fields))
+			for i := range resultFormats {
+				resultFormats[i] = resultFormatsByOID[sd.Fields[i].DataTypeOID]
+			}
+		}
+
+		if resultFormats == nil {
+			resultFormats = c.eqb.ResultFormats
+		}
+
+		if !explicitPreparedStatement && mode == QueryExecModeCacheDescribe {
+			rows.resultReader = c.pgConn.ExecParams(ctx, sql, c.eqb.ParamValues, sd.ParamOIDs, c.eqb.ParamFormats, resultFormats)
+		} else {
+			rows.resultReader = c.pgConn.ExecStatement(ctx, sd, c.eqb.ParamValues, c.eqb.ParamFormats, resultFormats)
+		}
+	case mode == QueryExecModeExec:
+		err := c.eqb.Build(c.typeMap, nil, args)
+		if err != nil {
+			rows.fatal(err)
+			return rows, rows.err
+		}
+
+		rows.resultReader = c.pgConn.ExecParams(ctx, sql, c.eqb.ParamValues, nil, c.eqb.ParamFormats, c.eqb.ResultFormats)
+	case mode == QueryExecModeSimpleProtocol:
+		sql, err = c.sanitizeForSimpleQuery(sql, args...)
+		if err != nil {
+			rows.fatal(err)
+			return rows, err
+		}
+
+		mrr := c.pgConn.Exec(ctx, sql)
+		if mrr.NextResult() {
+			rows.resultReader = mrr.ResultReader()
+			rows.multiResultReader = mrr
+		} else {
+			err = mrr.Close()
+			rows.fatal(err)
+			return rows, err
+		}
+
+		return rows, nil
+	default:
+		err = fmt.Errorf("unknown QueryExecMode: %v", mode)
+		rows.fatal(err)
+		return rows, rows.err
+	}
+
+	c.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.
+
+	return rows, rows.err
+}
+
+// getStatementDescription returns the statement description of the sql query
+// according to the given mode.
+//
+// If the mode is one that doesn't require to know the param and result OIDs
+// then nil is returned without error.
+func (c *Conn) getStatementDescription(
+	ctx context.Context,
+	mode QueryExecMode,
+	sql string,
+) (sd *pgconn.StatementDescription, err error) {
+	switch mode {
+	case QueryExecModeCacheStatement:
+		if c.statementCache == nil {
+			return nil, errDisabledStatementCache
+		}
+		sd = c.statementCache.Get(sql)
+		if sd == nil {
+			sd, err = c.Prepare(ctx, stmtcache.StatementName(sql), sql)
+			if err != nil {
+				return nil, err
+			}
+			c.statementCache.Put(sd)
+		}
+	case QueryExecModeCacheDescribe:
+		if c.descriptionCache == nil {
+			return nil, errDisabledDescriptionCache
+		}
+		sd = c.descriptionCache.Get(sql)
+		if sd == nil {
+			sd, err = c.Prepare(ctx, "", sql)
+			if err != nil {
+				return nil, err
+			}
+			c.descriptionCache.Put(sd)
+		}
+	case QueryExecModeDescribeExec:
+		return c.Prepare(ctx, "", sql)
+	}
+	return sd, err
+}
+
+// QueryRow is a convenience wrapper over Query. Any error that occurs while
+// querying is deferred until calling Scan on the returned Row. That Row will
+// error with ErrNoRows if no rows are returned.
+func (c *Conn) QueryRow(ctx context.Context, sql string, args ...any) Row {
+	rows, _ := c.Query(ctx, sql, args...)
+	return (*connRow)(rows.(*baseRows))
+}
+
+// SendBatch sends all queued queries to the server at once. All queries are run in an implicit transaction unless
+// explicit transaction control statements are executed. The returned [BatchResults] must be closed before the connection
+// is used again.
+//
+// Depending on the QueryExecMode, all queries may be prepared before any are executed. This means that creating a table
+// and using it in a subsequent query in the same batch can fail.
+func (c *Conn) SendBatch(ctx context.Context, b *Batch) (br BatchResults) {
+	if len(b.QueuedQueries) == 0 {
+		return &emptyBatchResults{conn: c}
+	}
+
+	if c.batchTracer != nil {
+		ctx = c.batchTracer.TraceBatchStart(ctx, c, TraceBatchStartData{Batch: b})
+		defer func() {
+			err := br.(interface{ earlyError() error }).earlyError()
+			if err != nil {
+				c.batchTracer.TraceBatchEnd(ctx, c, TraceBatchEndData{Err: err})
+			}
+		}()
+	}
+
+	if err := c.deallocateInvalidatedCachedStatements(ctx); err != nil {
+		return &batchResults{ctx: ctx, conn: c, err: err}
+	}
+
+	for _, bi := range b.QueuedQueries {
+		var queryRewriter QueryRewriter
+		sql := bi.SQL
+		arguments := bi.Arguments
+
+	optionLoop:
+		for len(arguments) > 0 {
+			// Update Batch.Queue function comment when additional options are implemented
+			switch arg := arguments[0].(type) {
+			case QueryRewriter:
+				queryRewriter = arg
+				arguments = arguments[1:]
+			default:
+				break optionLoop
+			}
+		}
+
+		if queryRewriter != nil {
+			var err error
+			sql, arguments, err = queryRewriter.RewriteQuery(ctx, c, sql, arguments)
+			if err != nil {
+				return &batchResults{ctx: ctx, conn: c, err: fmt.Errorf("rewrite query failed: %w", err)}
+			}
+		}
+
+		bi.SQL = sql
+		bi.Arguments = arguments
+	}
+
+	// TODO: changing mode per batch? Update Batch.Queue function comment when implemented
+	mode := c.config.DefaultQueryExecMode
+	if mode == QueryExecModeSimpleProtocol {
+		return c.sendBatchQueryExecModeSimpleProtocol(ctx, b)
+	}
+
+	// All other modes use extended protocol and thus can use prepared statements.
+	for _, bi := range b.QueuedQueries {
+		if sd, ok := c.preparedStatements[bi.SQL]; ok {
+			bi.sd = sd
+		}
+	}
+
+	switch mode {
+	case QueryExecModeExec:
+		return c.sendBatchQueryExecModeExec(ctx, b)
+	case QueryExecModeCacheStatement:
+		return c.sendBatchQueryExecModeCacheStatement(ctx, b)
+	case QueryExecModeCacheDescribe:
+		return c.sendBatchQueryExecModeCacheDescribe(ctx, b)
+	case QueryExecModeDescribeExec:
+		return c.sendBatchQueryExecModeDescribeExec(ctx, b)
+	default:
+		panic("unknown QueryExecMode")
+	}
+}
+
+func (c *Conn) sendBatchQueryExecModeSimpleProtocol(ctx context.Context, b *Batch) *batchResults {
+	var sb strings.Builder
+	for i, bi := range b.QueuedQueries {
+		if i > 0 {
+			sb.WriteByte(';')
+		}
+		sql, err := c.sanitizeForSimpleQuery(bi.SQL, bi.Arguments...)
+		if err != nil {
+			return &batchResults{ctx: ctx, conn: c, err: err}
+		}
+		sb.WriteString(sql)
+	}
+	mrr := c.pgConn.Exec(ctx, sb.String())
+	return &batchResults{
+		ctx:   ctx,
+		conn:  c,
+		mrr:   mrr,
+		b:     b,
+		qqIdx: 0,
+	}
+}
+
+func (c *Conn) sendBatchQueryExecModeExec(ctx context.Context, b *Batch) *batchResults {
+	batch := &pgconn.Batch{}
+
+	for _, bi := range b.QueuedQueries {
+		sd := bi.sd
+		if sd != nil {
+			err := c.eqb.Build(c.typeMap, sd, bi.Arguments)
+			if err != nil {
+				return &batchResults{ctx: ctx, conn: c, err: err}
+			}
+
+			batch.ExecPrepared(sd.Name, c.eqb.ParamValues, c.eqb.ParamFormats, c.eqb.ResultFormats)
+		} else {
+			err := c.eqb.Build(c.typeMap, nil, bi.Arguments)
+			if err != nil {
+				return &batchResults{ctx: ctx, conn: c, err: err}
+			}
+			batch.ExecParams(bi.SQL, c.eqb.ParamValues, nil, c.eqb.ParamFormats, c.eqb.ResultFormats)
+		}
+	}
+
+	c.eqb.reset() // Allow c.eqb internal memory to be GC'ed as soon as possible.
+
+	mrr := c.pgConn.ExecBatch(ctx, batch)
+
+	return &batchResults{
+		ctx:   ctx,
+		conn:  c,
+		mrr:   mrr,
+		b:     b,
+		qqIdx: 0,
+	}
+}
+
+func (c *Conn) sendBatchQueryExecModeCacheStatement(ctx context.Context, b *Batch) (pbr *pipelineBatchResults) {
+	if c.statementCache == nil {
+		return &pipelineBatchResults{ctx: ctx, conn: c, err: errDisabledStatementCache, closed: true}
+	}
+
+	distinctNewQueries := []*pgconn.StatementDescription{}
+	distinctNewQueriesIdxMap := make(map[string]int)
+
+	for _, bi := range b.QueuedQueries {
+		if bi.sd == nil {
+			sd := c.statementCache.Get(bi.SQL)
+			if sd != nil {
+				bi.sd = sd
+			} else {
+				if idx, present := distinctNewQueriesIdxMap[bi.SQL]; present {
+					bi.sd = distinctNewQueries[idx]
+				} else {
+					sd = &pgconn.StatementDescription{
+						Name: stmtcache.StatementName(bi.SQL),
+						SQL:  bi.SQL,
+					}
+					distinctNewQueriesIdxMap[sd.SQL] = len(distinctNewQueries)
+					distinctNewQueries = append(distinctNewQueries, sd)
+					bi.sd = sd
+				}
+			}
+		}
+	}
+
+	return c.sendBatchExtendedWithDescription(ctx, b, distinctNewQueries, c.statementCache)
+}
+
+func (c *Conn) sendBatchQueryExecModeCacheDescribe(ctx context.Context, b *Batch) (pbr *pipelineBatchResults) {
+	if c.descriptionCache == nil {
+		return &pipelineBatchResults{ctx: ctx, conn: c, err: errDisabledDescriptionCache, closed: true}
+	}
+
+	distinctNewQueries := []*pgconn.StatementDescription{}
+	distinctNewQueriesIdxMap := make(map[string]int)
+
+	for _, bi := range b.QueuedQueries {
+		if bi.sd == nil {
+			sd := c.descriptionCache.Get(bi.SQL)
+			if sd != nil {
+				bi.sd = sd
+			} else {
+				if idx, present := distinctNewQueriesIdxMap[bi.SQL]; present {
+					bi.sd = distinctNewQueries[idx]
+				} else {
+					sd = &pgconn.StatementDescription{
+						SQL: bi.SQL,
+					}
+					distinctNewQueriesIdxMap[sd.SQL] = len(distinctNewQueries)
+					distinctNewQueries = append(distinctNewQueries, sd)
+					bi.sd = sd
+				}
+			}
+		}
+	}
+
+	return c.sendBatchExtendedWithDescription(ctx, b, distinctNewQueries, c.descriptionCache)
+}
+
+func (c *Conn) sendBatchQueryExecModeDescribeExec(ctx context.Context, b *Batch) (pbr *pipelineBatchResults) {
+	distinctNewQueries := []*pgconn.StatementDescription{}
+	distinctNewQueriesIdxMap := make(map[string]int)
+
+	for _, bi := range b.QueuedQueries {
+		if bi.sd == nil {
+			if idx, present := distinctNewQueriesIdxMap[bi.SQL]; present {
+				bi.sd = distinctNewQueries[idx]
+			} else {
+				sd := &pgconn.StatementDescription{
+					SQL: bi.SQL,
+				}
+				distinctNewQueriesIdxMap[sd.SQL] = len(distinctNewQueries)
+				distinctNewQueries = append(distinctNewQueries, sd)
+				bi.sd = sd
+			}
+		}
+	}
+
+	return c.sendBatchExtendedWithDescription(ctx, b, distinctNewQueries, nil)
+}
+
+func (c *Conn) sendBatchExtendedWithDescription(ctx context.Context, b *Batch, distinctNewQueries []*pgconn.StatementDescription, sdCache stmtcache.Cache) (pbr *pipelineBatchResults) {
+	pipeline := c.pgConn.StartPipeline(ctx)
+	defer func() {
+		if pbr != nil && pbr.err != nil {
+			pipeline.Close()
+		}
+	}()
+
+	// Prepare any needed queries
+	if len(distinctNewQueries) > 0 {
+		err := func() (err error) {
+			for _, sd := range distinctNewQueries {
+				pipeline.SendPrepare(sd.Name, sd.SQL, nil)
+			}
+
+			// Store all statements we are preparing into the cache. It's fine if it overflows because HandleInvalidated will
+			// clean them up later.
+			if sdCache != nil {
+				for _, sd := range distinctNewQueries {
+					sdCache.Put(sd)
+				}
+			}
+
+			// If something goes wrong preparing the statements, we need to invalidate the cache entries we just added.
+			defer func() {
+				if err != nil && sdCache != nil {
+					for _, sd := range distinctNewQueries {
+						sdCache.Invalidate(sd.SQL)
+					}
+				}
+			}()
+
+			err = pipeline.Sync()
+			if err != nil {
+				return err
+			}
+
+			for _, sd := range distinctNewQueries {
+				results, err := pipeline.GetResults()
+				if err != nil {
+					return newErrPreprocessingBatch("prepare", sd.SQL, err)
+				}
+
+				resultSD, ok := results.(*pgconn.StatementDescription)
+				if !ok {
+					return fmt.Errorf("expected statement description, got %T", results)
+				}
+
+				// Fill in the previously empty / pending statement descriptions.
+				sd.ParamOIDs = resultSD.ParamOIDs
+				sd.Fields = resultSD.Fields
+			}
+
+			results, err := pipeline.GetResults()
+			if err != nil {
+				return err
+			}
+
+			_, ok := results.(*pgconn.PipelineSync)
+			if !ok {
+				return fmt.Errorf("expected sync, got %T", results)
+			}
+
+			return nil
+		}()
+		if err != nil {
+			return &pipelineBatchResults{ctx: ctx, conn: c, err: err, closed: true}
+		}
+	}
+
+	// Queue the queries.
+	for _, bi := range b.QueuedQueries {
+		err := c.eqb.Build(c.typeMap, bi.sd, bi.Arguments)
+		if err != nil {
+			err = newErrPreprocessingBatch("build", bi.SQL, err)
+			return &pipelineBatchResults{ctx: ctx, conn: c, err: err, closed: true}
+		}
+
+		if bi.sd.Name == "" {
+			pipeline.SendQueryParams(bi.sd.SQL, c.eqb.ParamValues, bi.sd.ParamOIDs, c.eqb.ParamFormats, c.eqb.ResultFormats)
+		} else {
+			// Copy ResultFormats because SendQueryStatement stores the slice for later use, and eqb.Build reuses the
+			// backing array on the next iteration.
+			resultFormats := make([]int16, len(c.eqb.ResultFormats))
+			copy(resultFormats, c.eqb.ResultFormats)
+			pipeline.SendQueryStatement(bi.sd, c.eqb.ParamValues, c.eqb.ParamFormats, resultFormats)
+		}
+	}
+
+	err := pipeline.Sync()
+	if err != nil {
+		return &pipelineBatchResults{ctx: ctx, conn: c, err: err, closed: true}
+	}
+
+	return &pipelineBatchResults{
+		ctx:      ctx,
+		conn:     c,
+		pipeline: pipeline,
+		b:        b,
+	}
+}
+
+func (c *Conn) sanitizeForSimpleQuery(sql string, args ...any) (string, error) {
+	if c.pgConn.ParameterStatus("standard_conforming_strings") != "on" {
+		return "", errors.New("simple protocol queries must be run with standard_conforming_strings=on")
+	}
+
+	if c.pgConn.ParameterStatus("client_encoding") != "UTF8" {
+		return "", errors.New("simple protocol queries must be run with client_encoding=UTF8")
+	}
+
+	var err error
+	valueArgs := make([]any, len(args))
+	for i, a := range args {
+		valueArgs[i], err = convertSimpleArgument(c.typeMap, a)
+		if err != nil {
+			return "", err
+		}
+	}
+
+	return sanitize.SanitizeSQL(sql, valueArgs...)
+}
+
+// LoadType inspects the database for typeName and produces a [pgtype.Type] suitable for registration. typeName must be
+// the name of a type where the underlying type(s) is already understood by pgx. It is for derived types. In particular,
+// typeName must be one of the following:
+//   - An array type name of a type that is already registered. e.g. "_foo" when "foo" is registered.
+//   - A composite type name where all field types are already registered.
+//   - A domain type name where the base type is already registered.
+//   - An enum type name.
+//   - A range type name where the element type is already registered.
+//   - A multirange type name where the element type is already registered.
+func (c *Conn) LoadType(ctx context.Context, typeName string) (*pgtype.Type, error) {
+	var oid uint32
+
+	err := c.QueryRow(ctx, "select $1::text::regtype::oid;", typeName).Scan(&oid)
+	if err != nil {
+		return nil, err
+	}
+
+	var typtype string
+	var typbasetype uint32
+
+	err = c.QueryRow(ctx, "select typtype::text, typbasetype from pg_type where oid=$1", oid).Scan(&typtype, &typbasetype)
+	if err != nil {
+		return nil, err
+	}
+
+	switch typtype {
+	case "b": // array
+		elementOID, err := c.getArrayElementOID(ctx, oid)
+		if err != nil {
+			return nil, err
+		}
+
+		dt, ok := c.TypeMap().TypeForOID(elementOID)
+		if !ok {
+			return nil, errors.New("array element OID not registered")
+		}
+
+		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.ArrayCodec{ElementType: dt}}, nil
+	case "c": // composite
+		fields, err := c.getCompositeFields(ctx, oid)
+		if err != nil {
+			return nil, err
+		}
+
+		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.CompositeCodec{Fields: fields}}, nil
+	case "d": // domain
+		dt, ok := c.TypeMap().TypeForOID(typbasetype)
+		if !ok {
+			return nil, errors.New("domain base type OID not registered")
+		}
+
+		return &pgtype.Type{Name: typeName, OID: oid, Codec: dt.Codec}, nil
+	case "e": // enum
+		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.EnumCodec{}}, nil
+	case "r": // range
+		elementOID, err := c.getRangeElementOID(ctx, oid)
+		if err != nil {
+			return nil, err
+		}
+
+		dt, ok := c.TypeMap().TypeForOID(elementOID)
+		if !ok {
+			return nil, errors.New("range element OID not registered")
+		}
+
+		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.RangeCodec{ElementType: dt}}, nil
+	case "m": // multirange
+		elementOID, err := c.getMultiRangeElementOID(ctx, oid)
+		if err != nil {
+			return nil, err
+		}
+
+		dt, ok := c.TypeMap().TypeForOID(elementOID)
+		if !ok {
+			return nil, errors.New("multirange element OID not registered")
+		}
+
+		return &pgtype.Type{Name: typeName, OID: oid, Codec: &pgtype.MultirangeCodec{ElementType: dt}}, nil
+	default:
+		return &pgtype.Type{}, errors.New("unknown typtype")
+	}
+}
+
+func (c *Conn) getArrayElementOID(ctx context.Context, oid uint32) (uint32, error) {
+	var typelem uint32
+
+	err := c.QueryRow(ctx, "select typelem from pg_type where oid=$1", oid).Scan(&typelem)
+	if err != nil {
+		return 0, err
+	}
+
+	return typelem, nil
+}
+
+func (c *Conn) getRangeElementOID(ctx context.Context, oid uint32) (uint32, error) {
+	var typelem uint32
+
+	err := c.QueryRow(ctx, "select rngsubtype from pg_range where rngtypid=$1", oid).Scan(&typelem)
+	if err != nil {
+		return 0, err
+	}
+
+	return typelem, nil
+}
+
+func (c *Conn) getMultiRangeElementOID(ctx context.Context, oid uint32) (uint32, error) {
+	var typelem uint32
+
+	err := c.QueryRow(ctx, "select rngtypid from pg_range where rngmultitypid=$1", oid).Scan(&typelem)
+	if err != nil {
+		return 0, err
+	}
+
+	return typelem, nil
+}
+
+func (c *Conn) getCompositeFields(ctx context.Context, oid uint32) ([]pgtype.CompositeCodecField, error) {
+	var typrelid uint32
+
+	err := c.QueryRow(ctx, "select typrelid from pg_type where oid=$1", oid).Scan(&typrelid)
+	if err != nil {
+		return nil, err
+	}
+
+	var fields []pgtype.CompositeCodecField
+	var fieldName string
+	var fieldOID uint32
+	rows, _ := c.Query(ctx, `select attname, atttypid
+from pg_attribute
+where attrelid=$1
+	and not attisdropped
+	and attnum > 0
+order by attnum`,
+		typrelid,
+	)
+	_, err = ForEachRow(rows, []any{&fieldName, &fieldOID}, func() error {
+		dt, ok := c.TypeMap().TypeForOID(fieldOID)
+		if !ok {
+			return fmt.Errorf("unknown composite type field OID: %v", fieldOID)
+		}
+		fields = append(fields, pgtype.CompositeCodecField{Name: fieldName, Type: dt})
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return fields, nil
+}
+
+func (c *Conn) deallocateInvalidatedCachedStatements(ctx context.Context) error {
+	if txStatus := c.pgConn.TxStatus(); txStatus != 'I' && txStatus != 'T' {
+		return nil
+	}
+
+	if c.descriptionCache != nil {
+		c.descriptionCache.RemoveInvalidated()
+	}
+
+	var invalidatedStatements []*pgconn.StatementDescription
+	if c.statementCache != nil {
+		invalidatedStatements = c.statementCache.GetInvalidated()
+	}
+
+	if len(invalidatedStatements) == 0 {
+		return nil
+	}
+
+	pipeline := c.pgConn.StartPipeline(ctx)
+	defer pipeline.Close()
+
+	for _, sd := range invalidatedStatements {
+		pipeline.SendDeallocate(sd.Name)
+	}
+
+	err := pipeline.Sync()
+	if err != nil {
+		return fmt.Errorf("failed to deallocate cached statement(s): %w", err)
+	}
+
+	err = pipeline.Close()
+	if err != nil {
+		return fmt.Errorf("failed to deallocate cached statement(s): %w", err)
+	}
+
+	c.statementCache.RemoveInvalidated()
+	for _, sd := range invalidatedStatements {
+		delete(c.preparedStatements, sd.Name)
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/copy_from.go b/vendor/github.com/jackc/pgx/v5/copy_from.go
new file mode 100644
index 000000000..038c568cf
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/copy_from.go
@@ -0,0 +1,276 @@
+package pgx
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"io"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+// CopyFromRows returns a [CopyFromSource] interface over the provided rows slice
+// making it usable by [Conn.CopyFrom].
+func CopyFromRows(rows [][]any) CopyFromSource {
+	return &copyFromRows{rows: rows, idx: -1}
+}
+
+type copyFromRows struct {
+	rows [][]any
+	idx  int
+}
+
+func (ctr *copyFromRows) Next() bool {
+	ctr.idx++
+	return ctr.idx < len(ctr.rows)
+}
+
+func (ctr *copyFromRows) Values() ([]any, error) {
+	return ctr.rows[ctr.idx], nil
+}
+
+func (ctr *copyFromRows) Err() error {
+	return nil
+}
+
+// CopyFromSlice returns a [CopyFromSource] interface over a dynamic func
+// making it usable by [Conn.CopyFrom].
+func CopyFromSlice(length int, next func(int) ([]any, error)) CopyFromSource {
+	return &copyFromSlice{next: next, idx: -1, len: length}
+}
+
+type copyFromSlice struct {
+	next func(int) ([]any, error)
+	idx  int
+	len  int
+	err  error
+}
+
+func (cts *copyFromSlice) Next() bool {
+	cts.idx++
+	return cts.idx < cts.len
+}
+
+func (cts *copyFromSlice) Values() ([]any, error) {
+	values, err := cts.next(cts.idx)
+	if err != nil {
+		cts.err = err
+	}
+	return values, err
+}
+
+func (cts *copyFromSlice) Err() error {
+	return cts.err
+}
+
+// CopyFromFunc returns a [CopyFromSource] interface that relies on nxtf for values.
+// nxtf returns rows until it either signals an 'end of data' by returning row=nil and err=nil,
+// or it returns an error. If nxtf returns an error, the copy is aborted.
+func CopyFromFunc(nxtf func() (row []any, err error)) CopyFromSource {
+	return &copyFromFunc{next: nxtf}
+}
+
+type copyFromFunc struct {
+	next     func() ([]any, error)
+	valueRow []any
+	err      error
+}
+
+func (g *copyFromFunc) Next() bool {
+	g.valueRow, g.err = g.next()
+	// only return true if valueRow exists and no error
+	return g.valueRow != nil && g.err == nil
+}
+
+func (g *copyFromFunc) Values() ([]any, error) {
+	return g.valueRow, g.err
+}
+
+func (g *copyFromFunc) Err() error {
+	return g.err
+}
+
+// CopyFromSource is the interface used by [Conn.CopyFrom] as the source for copy data.
+type CopyFromSource interface {
+	// Next returns true if there is another row and makes the next row data
+	// available to Values(). When there are no more rows available or an error
+	// has occurred it returns false.
+	Next() bool
+
+	// Values returns the values for the current row.
+	Values() ([]any, error)
+
+	// Err returns any error that has been encountered by the CopyFromSource. If
+	// this is not nil *Conn.CopyFrom will abort the copy.
+	Err() error
+}
+
+type copyFrom struct {
+	conn          *Conn
+	tableName     Identifier
+	columnNames   []string
+	rowSrc        CopyFromSource
+	readerErrChan chan error
+	mode          QueryExecMode
+}
+
+func (ct *copyFrom) run(ctx context.Context) (int64, error) {
+	if ct.conn.copyFromTracer != nil {
+		ctx = ct.conn.copyFromTracer.TraceCopyFromStart(ctx, ct.conn, TraceCopyFromStartData{
+			TableName:   ct.tableName,
+			ColumnNames: ct.columnNames,
+		})
+	}
+
+	quotedTableName := ct.tableName.Sanitize()
+	cbuf := &bytes.Buffer{}
+	for i, cn := range ct.columnNames {
+		if i != 0 {
+			cbuf.WriteString(", ")
+		}
+		cbuf.WriteString(quoteIdentifier(cn))
+	}
+	quotedColumnNames := cbuf.String()
+
+	var sd *pgconn.StatementDescription
+	switch ct.mode {
+	case QueryExecModeExec, QueryExecModeSimpleProtocol:
+		// These modes don't support the binary format. Before the inclusion of the
+		// QueryExecModes, Conn.Prepare was called on every COPY operation to get
+		// the OIDs. These prepared statements were not cached.
+		//
+		// Since that's the same behavior provided by QueryExecModeDescribeExec,
+		// we'll default to that mode.
+		ct.mode = QueryExecModeDescribeExec
+		fallthrough
+	case QueryExecModeCacheStatement, QueryExecModeCacheDescribe, QueryExecModeDescribeExec:
+		var err error
+		sd, err = ct.conn.getStatementDescription(
+			ctx,
+			ct.mode,
+			fmt.Sprintf("select %s from %s", quotedColumnNames, quotedTableName),
+		)
+		if err != nil {
+			return 0, fmt.Errorf("statement description failed: %w", err)
+		}
+	default:
+		return 0, fmt.Errorf("unknown QueryExecMode: %v", ct.mode)
+	}
+
+	r, w := io.Pipe()
+	doneChan := make(chan struct{})
+
+	go func() {
+		defer close(doneChan)
+
+		// Purposely NOT using defer w.Close(). See https://github.com/golang/go/issues/24283.
+		buf := ct.conn.wbuf
+
+		buf = append(buf, "PGCOPY\n\377\r\n\000"...)
+		buf = pgio.AppendInt32(buf, 0)
+		buf = pgio.AppendInt32(buf, 0)
+
+		moreRows := true
+		for moreRows {
+			var err error
+			moreRows, buf, err = ct.buildCopyBuf(buf, sd)
+			if err != nil {
+				w.CloseWithError(err)
+				return
+			}
+
+			if ct.rowSrc.Err() != nil {
+				w.CloseWithError(ct.rowSrc.Err())
+				return
+			}
+
+			if len(buf) > 0 {
+				_, err = w.Write(buf)
+				if err != nil {
+					w.Close()
+					return
+				}
+			}
+
+			buf = buf[:0]
+		}
+
+		w.Close()
+	}()
+
+	commandTag, err := ct.conn.pgConn.CopyFrom(ctx, r, fmt.Sprintf("copy %s ( %s ) from stdin binary;", quotedTableName, quotedColumnNames))
+
+	r.Close()
+	<-doneChan
+
+	if ct.conn.copyFromTracer != nil {
+		ct.conn.copyFromTracer.TraceCopyFromEnd(ctx, ct.conn, TraceCopyFromEndData{
+			CommandTag: commandTag,
+			Err:        err,
+		})
+	}
+
+	return commandTag.RowsAffected(), err
+}
+
+func (ct *copyFrom) buildCopyBuf(buf []byte, sd *pgconn.StatementDescription) (bool, []byte, error) {
+	const sendBufSize = 65536 - 5 // The packet has a 5-byte header
+	lastBufLen := 0
+	largestRowLen := 0
+
+	for ct.rowSrc.Next() {
+		lastBufLen = len(buf)
+
+		values, err := ct.rowSrc.Values()
+		if err != nil {
+			return false, nil, err
+		}
+		if len(values) != len(ct.columnNames) {
+			return false, nil, fmt.Errorf("expected %d values, got %d values", len(ct.columnNames), len(values))
+		}
+
+		buf = pgio.AppendInt16(buf, int16(len(ct.columnNames)))
+		for i, val := range values {
+			buf, err = encodeCopyValue(ct.conn.typeMap, buf, sd.Fields[i].DataTypeOID, val)
+			if err != nil {
+				return false, nil, err
+			}
+		}
+
+		rowLen := len(buf) - lastBufLen
+		if rowLen > largestRowLen {
+			largestRowLen = rowLen
+		}
+
+		// Try not to overflow size of the buffer PgConn.CopyFrom will be reading into. If that happens then the nature of
+		// io.Pipe means that the next Read will be short. This can lead to pathological send sizes such as 65531, 13, 65531
+		// 13, 65531, 13, 65531, 13.
+		if len(buf) > sendBufSize-largestRowLen {
+			return true, buf, nil
+		}
+	}
+
+	return false, buf, nil
+}
+
+// CopyFrom uses the PostgreSQL copy protocol to perform bulk data insertion. It returns the number of rows copied and
+// an error.
+//
+// CopyFrom requires all values use the binary format. A pgtype.Type that supports the binary format must be registered
+// for the type of each column. Almost all types implemented by pgx support the binary format.
+//
+// Even though enum types appear to be strings they still must be registered to use with [Conn.CopyFrom]. This can be done with
+// [Conn.LoadType] and [pgtype.Map.RegisterType].
+func (c *Conn) CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error) {
+	ct := &copyFrom{
+		conn:          c,
+		tableName:     tableName,
+		columnNames:   columnNames,
+		rowSrc:        rowSrc,
+		readerErrChan: make(chan error),
+		mode:          c.config.DefaultQueryExecMode,
+	}
+
+	return ct.run(ctx)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/derived_types.go b/vendor/github.com/jackc/pgx/v5/derived_types.go
new file mode 100644
index 000000000..3916006be
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/derived_types.go
@@ -0,0 +1,261 @@
+package pgx
+
+import (
+	"context"
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+/*
+buildLoadDerivedTypesSQL generates the correct query for retrieving type information.
+
+	pgVersion: the major version of the PostgreSQL server
+	typeNames: the names of the types to load. If nil, load all types.
+*/
+func buildLoadDerivedTypesSQL(pgVersion int64, typeNames []string) string {
+	supportsMultirange := (pgVersion >= 14)
+	var typeNamesClause string
+
+	if typeNames == nil {
+		// This should not occur; this will not return any types
+		typeNamesClause = "= ''"
+	} else {
+		typeNamesClause = "= ANY($1::text[])"
+	}
+	parts := make([]string, 0, 10)
+
+	// Each of the type names provided might be found in pg_class or pg_type.
+	// Additionally, it may or may not include a schema portion.
+	parts = append(parts, `
+WITH RECURSIVE
+-- find the OIDs in pg_class which match one of the provided type names
+selected_classes(oid,reltype) AS (
+    -- this query uses the namespace search path, so will match type names without a schema prefix
+    SELECT pg_class.oid, pg_class.reltype
+    FROM pg_catalog.pg_class
+        LEFT JOIN pg_catalog.pg_namespace n ON n.oid = pg_class.relnamespace
+    WHERE pg_catalog.pg_table_is_visible(pg_class.oid)
+      AND relname `, typeNamesClause, `
+UNION ALL
+    -- this query will only match type names which include the schema prefix
+    SELECT pg_class.oid, pg_class.reltype
+    FROM pg_class
+    INNER JOIN pg_namespace ON (pg_class.relnamespace = pg_namespace.oid)
+    WHERE nspname || '.' || relname `, typeNamesClause, `
+),
+selected_types(oid) AS (
+    -- collect the OIDs from pg_types which correspond to the selected classes
+    SELECT reltype AS oid
+    FROM selected_classes
+UNION ALL
+    -- as well as any other type names which match our criteria
+    SELECT pg_type.oid
+    FROM pg_type
+    LEFT OUTER JOIN pg_namespace ON (pg_type.typnamespace = pg_namespace.oid)
+    WHERE typname `, typeNamesClause, `
+        OR nspname || '.' || typname `, typeNamesClause, `
+),
+-- this builds a parent/child mapping of objects, allowing us to know
+-- all the child (ie: dependent) types that a parent (type) requires
+-- As can be seen, there are 3 ways this can occur (the last of which
+-- is due to being a composite class, where the composite fields are children)
+pc(parent, child) AS (
+    SELECT parent.oid, parent.typelem
+    FROM pg_type parent
+    WHERE parent.typtype = 'b' AND parent.typelem != 0
+UNION ALL
+    SELECT parent.oid, parent.typbasetype
+    FROM pg_type parent
+    WHERE parent.typtypmod = -1 AND parent.typbasetype != 0
+UNION ALL
+    SELECT pg_type.oid, atttypid
+    FROM pg_attribute
+    INNER JOIN pg_class ON (pg_class.oid = pg_attribute.attrelid)
+    INNER JOIN pg_type ON (pg_type.oid = pg_class.reltype)
+    WHERE NOT attisdropped
+      AND attnum > 0
+),
+-- Now construct a recursive query which includes a 'depth' element.
+-- This is used to ensure that the "youngest" children are registered before
+-- their parents.
+relationships(parent, child, depth) AS (
+    SELECT DISTINCT 0::OID, selected_types.oid, 0
+    FROM selected_types
+UNION ALL
+    SELECT pg_type.oid AS parent, pg_attribute.atttypid AS child, 1
+    FROM selected_classes c
+    inner join pg_type ON (c.reltype = pg_type.oid)
+    inner join pg_attribute on (c.oid = pg_attribute.attrelid)
+UNION ALL
+    SELECT pc.parent, pc.child, relationships.depth + 1
+    FROM pc
+    INNER JOIN relationships ON (pc.parent = relationships.child)
+),
+-- composite fields need to be encapsulated as a couple of arrays to provide the required information for registration
+composite AS (
+    SELECT pg_type.oid, ARRAY_AGG(attname ORDER BY attnum) AS attnames, ARRAY_AGG(atttypid ORDER BY ATTNUM) AS atttypids
+    FROM pg_attribute
+    INNER JOIN pg_class ON (pg_class.oid = pg_attribute.attrelid)
+    INNER JOIN pg_type ON (pg_type.oid = pg_class.reltype)
+    WHERE NOT attisdropped
+      AND attnum > 0
+    GROUP BY pg_type.oid
+)
+-- Bring together this information, showing all the information which might possibly be required
+-- to complete the registration, applying filters to only show the items which relate to the selected
+-- types/classes.
+SELECT typname,
+       pg_namespace.nspname,
+       typtype,
+       typbasetype,
+       typelem,
+       pg_type.oid,`)
+	if supportsMultirange {
+		parts = append(parts, `
+       COALESCE(multirange.rngtypid, 0) AS rngtypid,`)
+	} else {
+		parts = append(parts, `
+       0 AS rngtypid,`)
+	}
+	parts = append(parts, `
+       COALESCE(pg_range.rngsubtype, 0) AS rngsubtype,
+       attnames, atttypids
+    FROM relationships
+    INNER JOIN pg_type ON (pg_type.oid = relationships.child)
+    LEFT OUTER JOIN pg_range ON (pg_type.oid = pg_range.rngtypid)`)
+	if supportsMultirange {
+		parts = append(parts, `
+    LEFT OUTER JOIN pg_range multirange ON (pg_type.oid = multirange.rngmultitypid)`)
+	}
+
+	parts = append(parts, `
+    LEFT OUTER JOIN composite USING (oid)
+    LEFT OUTER JOIN pg_namespace ON (pg_type.typnamespace = pg_namespace.oid)
+    WHERE NOT (typtype = 'b' AND typelem = 0)`)
+	parts = append(parts, `
+    GROUP BY typname, pg_namespace.nspname, typtype, typbasetype, typelem, pg_type.oid, pg_range.rngsubtype,`)
+	if supportsMultirange {
+		parts = append(parts, `
+        multirange.rngtypid,`)
+	}
+	parts = append(parts, `
+        attnames, atttypids
+    ORDER BY MAX(depth) desc, typname;`)
+	return strings.Join(parts, "")
+}
+
+type derivedTypeInfo struct {
+	Oid, Typbasetype, Typelem, Rngsubtype, Rngtypid uint32
+	TypeName, Typtype, NspName                      string
+	Attnames                                        []string
+	Atttypids                                       []uint32
+}
+
+// LoadTypes performs a single (complex) query, returning all the required
+// information to register the named types, as well as any other types directly
+// or indirectly required to complete the registration.
+// The result of this call can be passed into RegisterTypes to complete the process.
+func (c *Conn) LoadTypes(ctx context.Context, typeNames []string) ([]*pgtype.Type, error) {
+	m := c.TypeMap()
+	if len(typeNames) == 0 {
+		return nil, fmt.Errorf("No type names were supplied.")
+	}
+
+	// Disregard server version errors. This will result in
+	// the SQL not support recent structures such as multirange
+	serverVersion, _ := serverVersion(c)
+	sql := buildLoadDerivedTypesSQL(serverVersion, typeNames)
+	rows, err := c.Query(ctx, sql, QueryResultFormats{TextFormatCode}, typeNames)
+	if err != nil {
+		return nil, fmt.Errorf("While generating load types query: %w", err)
+	}
+	defer rows.Close()
+	result := make([]*pgtype.Type, 0, 100)
+	for rows.Next() {
+		ti := derivedTypeInfo{}
+		err = rows.Scan(&ti.TypeName, &ti.NspName, &ti.Typtype, &ti.Typbasetype, &ti.Typelem, &ti.Oid, &ti.Rngtypid, &ti.Rngsubtype, &ti.Attnames, &ti.Atttypids)
+		if err != nil {
+			return nil, fmt.Errorf("While scanning type information: %w", err)
+		}
+		var type_ *pgtype.Type
+		switch ti.Typtype {
+		case "b": // array
+			dt, ok := m.TypeForOID(ti.Typelem)
+			if !ok {
+				return nil, fmt.Errorf("Array element OID %v not registered while loading pgtype %q", ti.Typelem, ti.TypeName)
+			}
+			type_ = &pgtype.Type{Name: ti.TypeName, OID: ti.Oid, Codec: &pgtype.ArrayCodec{ElementType: dt}}
+		case "c": // composite
+			var fields []pgtype.CompositeCodecField
+			for i, fieldName := range ti.Attnames {
+				dt, ok := m.TypeForOID(ti.Atttypids[i])
+				if !ok {
+					return nil, fmt.Errorf("Unknown field for composite type %q:  field %q (OID %v) is not already registered.", ti.TypeName, fieldName, ti.Atttypids[i])
+				}
+				fields = append(fields, pgtype.CompositeCodecField{Name: fieldName, Type: dt})
+			}
+
+			type_ = &pgtype.Type{Name: ti.TypeName, OID: ti.Oid, Codec: &pgtype.CompositeCodec{Fields: fields}}
+		case "d": // domain
+			dt, ok := m.TypeForOID(ti.Typbasetype)
+			if !ok {
+				return nil, fmt.Errorf("Domain base type OID %v was not already registered, needed for %q", ti.Typbasetype, ti.TypeName)
+			}
+
+			type_ = &pgtype.Type{Name: ti.TypeName, OID: ti.Oid, Codec: dt.Codec}
+		case "e": // enum
+			type_ = &pgtype.Type{Name: ti.TypeName, OID: ti.Oid, Codec: &pgtype.EnumCodec{}}
+		case "r": // range
+			dt, ok := m.TypeForOID(ti.Rngsubtype)
+			if !ok {
+				return nil, fmt.Errorf("Range element OID %v was not already registered, needed for %q", ti.Rngsubtype, ti.TypeName)
+			}
+
+			type_ = &pgtype.Type{Name: ti.TypeName, OID: ti.Oid, Codec: &pgtype.RangeCodec{ElementType: dt}}
+		case "m": // multirange
+			dt, ok := m.TypeForOID(ti.Rngtypid)
+			if !ok {
+				return nil, fmt.Errorf("Multirange element OID %v was not already registered, needed for %q", ti.Rngtypid, ti.TypeName)
+			}
+
+			type_ = &pgtype.Type{Name: ti.TypeName, OID: ti.Oid, Codec: &pgtype.MultirangeCodec{ElementType: dt}}
+		default:
+			return nil, fmt.Errorf("Unknown typtype %q was found while registering %q", ti.Typtype, ti.TypeName)
+		}
+
+		// the type_ is impossible to be null
+		m.RegisterType(type_)
+		if ti.NspName != "" {
+			nspType := &pgtype.Type{Name: ti.NspName + "." + type_.Name, OID: type_.OID, Codec: type_.Codec}
+			m.RegisterType(nspType)
+			result = append(result, nspType)
+		}
+		result = append(result, type_)
+	}
+
+	if err := rows.Err(); err != nil {
+		return nil, fmt.Errorf("While processing rows: %w", err)
+	}
+
+	return result, nil
+}
+
+// serverVersion returns the postgresql server version.
+func serverVersion(c *Conn) (int64, error) {
+	serverVersionStr := c.PgConn().ParameterStatus("server_version")
+	serverVersionStr = regexp.MustCompile(`^[0-9]+`).FindString(serverVersionStr)
+	// if not PostgreSQL do nothing
+	if serverVersionStr == "" {
+		return 0, fmt.Errorf("Cannot identify server version in %q", serverVersionStr)
+	}
+
+	version, err := strconv.ParseInt(serverVersionStr, 10, 64)
+	if err != nil {
+		return 0, fmt.Errorf("postgres version parsing failed: %w", err)
+	}
+	return version, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/doc.go b/vendor/github.com/jackc/pgx/v5/doc.go
new file mode 100644
index 000000000..5e4870191
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/doc.go
@@ -0,0 +1,220 @@
+// Package pgx is a PostgreSQL database driver.
+/*
+pgx provides a native PostgreSQL driver and can act as a [database/sql/driver]. The native PostgreSQL interface is similar
+to the [database/sql] interface while providing better speed and access to PostgreSQL specific features. Use
+[github.com/jackc/pgx/v5/stdlib] to use pgx as a database/sql compatible driver. See that package's documentation for
+details.
+
+Establishing a Connection
+
+The primary way of establishing a connection is with [pgx.Connect]:
+
+    conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
+
+The database connection string can be in URL or key/value format. Both PostgreSQL settings and pgx settings can be
+specified here. In addition, a config struct can be created by [ParseConfig] and modified before establishing the
+connection with [ConnectConfig] to configure settings such as tracing that cannot be configured with a connection
+string.
+
+Connection Pool
+
+[*pgx.Conn] represents a single connection to the database and is not concurrency safe. Use package
+[github.com/jackc/pgx/v5/pgxpool] for a concurrency safe connection pool.
+
+Query Interface
+
+pgx implements [Conn.Query] in the familiar database/sql style. However, pgx provides generic functions such as [CollectRows] and
+[ForEachRow] that are a simpler and safer way of processing rows than manually calling defer [Rows.Close], [Rows.Next],
+[Rows.Scan], and [Rows.Err].
+
+[CollectRows] can be used collect all returned rows into a slice.
+
+    rows, _ := conn.Query(context.Background(), "select generate_series(1,$1)", 5)
+    numbers, err := pgx.CollectRows(rows, pgx.RowTo[int32])
+    if err != nil {
+      return err
+    }
+    // numbers => [1 2 3 4 5]
+
+[ForEachRow] can be used to execute a callback function for every row. This is often easier than iterating over rows
+directly.
+
+    var sum, n int32
+    rows, _ := conn.Query(context.Background(), "select generate_series(1,$1)", 10)
+    _, err := pgx.ForEachRow(rows, []any{&n}, func() error {
+      sum += n
+      return nil
+    })
+    if err != nil {
+      return err
+    }
+
+pgx also implements [Conn.QueryRow] in the same style as database/sql.
+
+    var name string
+    var weight int64
+    err := conn.QueryRow(context.Background(), "select name, weight from widgets where id=$1", 42).Scan(&name, &weight)
+    if err != nil {
+        return err
+    }
+
+Use [Conn.Exec] to execute a query that does not return a result set.
+
+    commandTag, err := conn.Exec(context.Background(), "delete from widgets where id=$1", 42)
+    if err != nil {
+        return err
+    }
+    if commandTag.RowsAffected() != 1 {
+        return errors.New("No row found to delete")
+    }
+
+PostgreSQL Data Types
+
+pgx uses the [pgtype] package to converting Go values to and from PostgreSQL values. It supports many PostgreSQL types
+directly and is customizable and extendable. User defined data types such as enums, domains,  and composite types may
+require type registration. See that package's documentation for details.
+
+PostgreSQL arrays (including results from set-returning aggregates such as array_agg)
+can be scanned directly into a matching Go slice. For scalar columns, pass the slice
+as the scan destination:
+
+    var ids []int64
+    err := conn.QueryRow(ctx, "select array_agg(id) from things").Scan(&ids)
+
+For a column that is part of a row, combine the slice with the usual row-to-struct
+helpers. A struct field of slice type will pick up the array_agg column when
+collected via [CollectRows] and [RowToStructByName] (or
+[RowToAddrOfStructByPos]):
+
+    type ThingEntry struct {
+        GroupID  int64
+        ThingIDs []int64 `db:"thing_ids"`
+    }
+
+    rows, _ := conn.Query(ctx,
+        "select group_id, array_agg(thing_id) as thing_ids from things group by group_id")
+    entries, err := pgx.CollectRows(rows, pgx.RowToStructByName[ThingEntry])
+
+Transactions
+
+Transactions are started by calling [Conn.Begin].
+
+    tx, err := conn.Begin(context.Background())
+    if err != nil {
+        return err
+    }
+    // Rollback is safe to call even if the tx is already closed, so if
+    // the tx commits successfully, this is a no-op
+    defer tx.Rollback(context.Background())
+
+    _, err = tx.Exec(context.Background(), "insert into foo(id) values (1)")
+    if err != nil {
+        return err
+    }
+
+    err = tx.Commit(context.Background())
+    if err != nil {
+        return err
+    }
+
+The [Tx] returned from [Conn.Begin] also implements the [Tx.Begin] method. This can be used to implement pseudo nested transactions.
+These are internally implemented with savepoints.
+
+Use [Conn.BeginTx] to control the transaction mode. [Conn.BeginTx] also can be used to ensure a new transaction is created instead of
+a pseudo nested transaction.
+
+[BeginFunc] and [BeginTxFunc] are functions that begin a transaction, execute a function, and commit or rollback the
+transaction depending on the return value of the function. These can be simpler and less error prone to use.
+
+    err = pgx.BeginFunc(context.Background(), conn, func(tx pgx.Tx) error {
+        _, err := tx.Exec(context.Background(), "insert into foo(id) values (1)")
+        return err
+    })
+    if err != nil {
+        return err
+    }
+
+Prepared Statements
+
+Prepared statements can be manually created with the [Conn.Prepare] method. However, this is rarely necessary because pgx
+includes an automatic statement cache by default. Queries run through the normal [Conn.Query], [Conn.QueryRow], and [Conn.Exec]
+functions are automatically prepared on first execution and the prepared statement is reused on subsequent executions.
+See [ParseConfig] for information on how to customize or disable the statement cache.
+
+Copy Protocol
+
+Use [Conn.CopyFrom] to efficiently insert multiple rows at a time using the PostgreSQL copy protocol. [Conn.CopyFrom] accepts a
+[CopyFromSource] interface. If the data is already in a [][]any use [CopyFromRows] to wrap it in a [CopyFromSource] interface.
+Or implement [CopyFromSource] to avoid buffering the entire data set in memory.
+
+    rows := [][]any{
+        {"John", "Smith", int32(36)},
+        {"Jane", "Doe", int32(29)},
+    }
+
+    copyCount, err := conn.CopyFrom(
+        context.Background(),
+        pgx.Identifier{"people"},
+        []string{"first_name", "last_name", "age"},
+        pgx.CopyFromRows(rows),
+    )
+
+When you already have a typed array using [CopyFromSlice] can be more convenient.
+
+    rows := []User{
+        {"John", "Smith", 36},
+        {"Jane", "Doe", 29},
+    }
+
+    copyCount, err := conn.CopyFrom(
+        context.Background(),
+        pgx.Identifier{"people"},
+        []string{"first_name", "last_name", "age"},
+        pgx.CopyFromSlice(len(rows), func(i int) ([]any, error) {
+            return []any{rows[i].FirstName, rows[i].LastName, rows[i].Age}, nil
+        }),
+    )
+
+CopyFrom can be faster than an insert with as few as 5 rows.
+
+Listen and Notify
+
+pgx can listen to the PostgreSQL notification system with the [Conn.WaitForNotification] method. It blocks until a
+notification is received or the context is canceled.
+
+    _, err := conn.Exec(context.Background(), "listen channelname")
+    if err != nil {
+        return err
+    }
+
+    notification, err := conn.WaitForNotification(context.Background())
+    if err != nil {
+        return err
+    }
+    // do something with notification
+
+
+Tracing and Logging
+
+pgx supports tracing by setting [ConnConfig.Tracer]. To combine several tracers you can use the [github.com/jackc/pgx/v5/multitracer.Tracer].
+
+In addition, the [github.com/jackc/pgx/v5/tracelog] package provides the [github.com/jackc/pgx/v5/tracelog.TraceLog] type which lets a
+traditional logger act as a [QueryTracer].
+
+For debug tracing of the actual PostgreSQL wire protocol messages see [github.com/jackc/pgx/v5/pgproto3].
+
+Lower Level PostgreSQL Functionality
+
+[github.com/jackc/pgx/v5/pgconn] contains a lower level PostgreSQL driver roughly at the level of libpq. [Conn] is
+implemented on top of [pgconn.PgConn]. The [Conn.PgConn] method can be used to access this lower layer.
+
+PgBouncer
+
+By default pgx automatically uses prepared statements. Prepared statements are incompatible with PgBouncer. This can be
+disabled by setting a different [QueryExecMode] in [ConnConfig.DefaultQueryExecMode].
+*/
+package pgx
+
+import (
+	_ "github.com/jackc/pgx/v5/pgconn" // Just for allowing godoc to resolve "pgconn"
+)
diff --git a/vendor/github.com/jackc/pgx/v5/extended_query_builder.go b/vendor/github.com/jackc/pgx/v5/extended_query_builder.go
new file mode 100644
index 000000000..526b0e953
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/extended_query_builder.go
@@ -0,0 +1,146 @@
+package pgx
+
+import (
+	"fmt"
+
+	"github.com/jackc/pgx/v5/pgconn"
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+// ExtendedQueryBuilder is used to choose the parameter formats, to format the parameters and to choose the result
+// formats for an extended query.
+type ExtendedQueryBuilder struct {
+	ParamValues     [][]byte
+	paramValueBytes []byte
+	ParamFormats    []int16
+	ResultFormats   []int16
+}
+
+// Build sets ParamValues, ParamFormats, and ResultFormats for use with *PgConn.ExecParams or *PgConn.ExecPrepared. If
+// sd is nil then QueryExecModeExec behavior will be used.
+func (eqb *ExtendedQueryBuilder) Build(m *pgtype.Map, sd *pgconn.StatementDescription, args []any) error {
+	eqb.reset()
+
+	if sd == nil {
+		for i := range args {
+			err := eqb.appendParam(m, 0, pgtype.TextFormatCode, args[i])
+			if err != nil {
+				err = fmt.Errorf("failed to encode args[%d]: %w", i, err)
+				return err
+			}
+		}
+		return nil
+	}
+
+	if len(sd.ParamOIDs) != len(args) {
+		return fmt.Errorf("mismatched param and argument count")
+	}
+
+	for i := range args {
+		err := eqb.appendParam(m, sd.ParamOIDs[i], -1, args[i])
+		if err != nil {
+			err = fmt.Errorf("failed to encode args[%d]: %w", i, err)
+			return err
+		}
+	}
+
+	for i := range sd.Fields {
+		eqb.appendResultFormat(m.FormatCodeForOID(sd.Fields[i].DataTypeOID))
+	}
+
+	return nil
+}
+
+// appendParam appends a parameter to the query. format may be -1 to automatically choose the format. If arg is nil it
+// must be an untyped nil.
+func (eqb *ExtendedQueryBuilder) appendParam(m *pgtype.Map, oid uint32, format int16, arg any) error {
+	if format == -1 {
+		preferredFormat := eqb.chooseParameterFormatCode(m, oid, arg)
+		preferredErr := eqb.appendParam(m, oid, preferredFormat, arg)
+		if preferredErr == nil {
+			return nil
+		}
+
+		var otherFormat int16
+		if preferredFormat == TextFormatCode {
+			otherFormat = BinaryFormatCode
+		} else {
+			otherFormat = TextFormatCode
+		}
+
+		otherErr := eqb.appendParam(m, oid, otherFormat, arg)
+		if otherErr == nil {
+			return nil
+		}
+
+		return preferredErr // return the error from the preferred format
+	}
+
+	v, err := eqb.encodeExtendedParamValue(m, oid, format, arg)
+	if err != nil {
+		return err
+	}
+
+	eqb.ParamFormats = append(eqb.ParamFormats, format)
+	eqb.ParamValues = append(eqb.ParamValues, v)
+
+	return nil
+}
+
+// appendResultFormat appends a result format to the query.
+func (eqb *ExtendedQueryBuilder) appendResultFormat(format int16) {
+	eqb.ResultFormats = append(eqb.ResultFormats, format)
+}
+
+// reset readies eqb to build another query.
+func (eqb *ExtendedQueryBuilder) reset() {
+	eqb.ParamValues = eqb.ParamValues[0:0]
+	eqb.paramValueBytes = eqb.paramValueBytes[0:0]
+	eqb.ParamFormats = eqb.ParamFormats[0:0]
+	eqb.ResultFormats = eqb.ResultFormats[0:0]
+
+	if cap(eqb.ParamValues) > 64 {
+		eqb.ParamValues = make([][]byte, 0, 64)
+	}
+
+	if cap(eqb.paramValueBytes) > 256 {
+		eqb.paramValueBytes = make([]byte, 0, 256)
+	}
+
+	if cap(eqb.ParamFormats) > 64 {
+		eqb.ParamFormats = make([]int16, 0, 64)
+	}
+	if cap(eqb.ResultFormats) > 64 {
+		eqb.ResultFormats = make([]int16, 0, 64)
+	}
+}
+
+func (eqb *ExtendedQueryBuilder) encodeExtendedParamValue(m *pgtype.Map, oid uint32, formatCode int16, arg any) ([]byte, error) {
+	if eqb.paramValueBytes == nil {
+		eqb.paramValueBytes = make([]byte, 0, 128)
+	}
+
+	pos := len(eqb.paramValueBytes)
+
+	buf, err := m.Encode(oid, formatCode, arg, eqb.paramValueBytes)
+	if err != nil {
+		return nil, err
+	}
+	if buf == nil {
+		return nil, nil
+	}
+	eqb.paramValueBytes = buf
+	return eqb.paramValueBytes[pos:], nil
+}
+
+// chooseParameterFormatCode determines the correct format code for an
+// argument to a prepared statement. It defaults to TextFormatCode if no
+// determination can be made.
+func (eqb *ExtendedQueryBuilder) chooseParameterFormatCode(m *pgtype.Map, oid uint32, arg any) int16 {
+	switch arg.(type) {
+	case string, *string:
+		return TextFormatCode
+	}
+
+	return m.FormatCodeForOID(oid)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/internal/iobufpool/iobufpool.go b/vendor/github.com/jackc/pgx/v5/internal/iobufpool/iobufpool.go
new file mode 100644
index 000000000..abc41f657
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/iobufpool/iobufpool.go
@@ -0,0 +1,78 @@
+// Package iobufpool implements a global segregated-fit pool of buffers for IO.
+//
+// It uses *[]byte instead of []byte to avoid the sync.Pool allocation with Put. Unfortunately, using a pointer to avoid
+// an allocation is purposely not documented. https://github.com/golang/go/issues/16323
+package iobufpool
+
+import (
+	"math/bits"
+	"sync"
+)
+
+const minPoolExpOf2 = 8
+
+var pools [18]*sync.Pool
+
+func init() {
+	for i := range pools {
+		bufLen := 1 << (minPoolExpOf2 + i)
+		pools[i] = &sync.Pool{
+			New: func() any {
+				buf := make([]byte, bufLen)
+				return &buf
+			},
+		}
+	}
+}
+
+// Get gets a []byte of len size with cap <= size*2.
+func Get(size int) *[]byte {
+	i := getPoolIdx(size)
+	if i >= len(pools) {
+		buf := make([]byte, size)
+		return &buf
+	}
+
+	ptrBuf := (pools[i].Get().(*[]byte))
+	*ptrBuf = (*ptrBuf)[:size]
+
+	return ptrBuf
+}
+
+func getPoolIdx(size int) int {
+	if size < 2 {
+		return 0
+	}
+	idx := bits.Len(uint(size-1)) - minPoolExpOf2
+	if idx < 0 {
+		return 0
+	}
+	return idx
+}
+
+// Put returns buf to the pool.
+func Put(buf *[]byte) {
+	i := putPoolIdx(cap(*buf))
+	if i < 0 {
+		return
+	}
+
+	pools[i].Put(buf)
+}
+
+func putPoolIdx(size int) int {
+	// Only exact power-of-2 sizes match pool buckets
+	if size&(size-1) != 0 {
+		return -1
+	}
+
+	// Calculate log2(size) using trailing zeros count
+	exp := bits.TrailingZeros(uint(size))
+	idx := exp - minPoolExpOf2
+
+	if idx < 0 || idx >= len(pools) {
+		return -1
+	}
+
+	return idx
+}
diff --git a/vendor/github.com/jackc/pgx/v5/internal/pgio/README.md b/vendor/github.com/jackc/pgx/v5/internal/pgio/README.md
new file mode 100644
index 000000000..b2fc58014
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/pgio/README.md
@@ -0,0 +1,6 @@
+# pgio
+
+Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol.
+
+pgio provides functions for appending integers to a []byte while doing byte
+order conversion.
diff --git a/vendor/github.com/jackc/pgx/v5/internal/pgio/doc.go b/vendor/github.com/jackc/pgx/v5/internal/pgio/doc.go
new file mode 100644
index 000000000..ef2dcc7f7
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/pgio/doc.go
@@ -0,0 +1,6 @@
+// Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol.
+/*
+pgio provides functions for appending integers to a []byte while doing byte
+order conversion.
+*/
+package pgio
diff --git a/vendor/github.com/jackc/pgx/v5/internal/pgio/write.go b/vendor/github.com/jackc/pgx/v5/internal/pgio/write.go
new file mode 100644
index 000000000..3a6700dc4
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/pgio/write.go
@@ -0,0 +1,32 @@
+package pgio
+
+func AppendUint16(buf []byte, n uint16) []byte {
+	return append(buf, byte(n>>8), byte(n))
+}
+
+func AppendUint32(buf []byte, n uint32) []byte {
+	return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
+}
+
+func AppendUint64(buf []byte, n uint64) []byte {
+	return append(buf,
+		byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
+		byte(n>>24), byte(n>>16), byte(n>>8), byte(n),
+	)
+}
+
+func AppendInt16(buf []byte, n int16) []byte {
+	return AppendUint16(buf, uint16(n))
+}
+
+func AppendInt32(buf []byte, n int32) []byte {
+	return AppendUint32(buf, uint32(n))
+}
+
+func AppendInt64(buf []byte, n int64) []byte {
+	return AppendUint64(buf, uint64(n))
+}
+
+func SetInt32(buf []byte, n int32) {
+	*(*[4]byte)(buf) = [4]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/internal/sanitize/benchmark.sh b/vendor/github.com/jackc/pgx/v5/internal/sanitize/benchmark.sh
new file mode 100644
index 000000000..b4ee3fe74
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/sanitize/benchmark.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+
+current_branch=$(git rev-parse --abbrev-ref HEAD)
+if [ "$current_branch" == "HEAD" ]; then
+    current_branch=$(git rev-parse HEAD)
+fi
+
+restore_branch() {
+    echo "Restoring original branch/commit: $current_branch"
+    git checkout "$current_branch"
+}
+trap restore_branch EXIT
+
+# Check if there are uncommitted changes
+if ! git diff --quiet || ! git diff --cached --quiet; then
+    echo "There are uncommitted changes. Please commit or stash them before running this script."
+    exit 1
+fi
+
+# Ensure that at least one commit argument is passed
+if [ "$#" -lt 1 ]; then
+    echo "Usage: $0 <commit1> <commit2> ... <commitN>"
+    exit 1
+fi
+
+commits=("$@")
+benchmarks_dir=benchmarks
+
+if ! mkdir -p "${benchmarks_dir}"; then
+    echo "Unable to create dir for benchmarks data"
+    exit 1
+fi
+
+# Benchmark results
+bench_files=()
+
+# Run benchmark for each listed commit
+for i in "${!commits[@]}"; do
+    commit="${commits[i]}"
+    git checkout "$commit" || {
+        echo "Failed to checkout $commit"
+        exit 1
+    }
+
+    # Sanitized commit message
+    commit_message=$(git log -1 --pretty=format:"%s" | tr -c '[:alnum:]-_' '_')
+
+    # Benchmark data will go there
+    bench_file="${benchmarks_dir}/${i}_${commit_message}.bench"
+
+    if ! go test -bench=. -count=10 >"$bench_file"; then
+        echo "Benchmarking failed for commit $commit"
+        exit 1
+    fi
+
+    bench_files+=("$bench_file")
+done
+
+# go install golang.org/x/perf/cmd/benchstat[@latest]
+benchstat "${bench_files[@]}"
diff --git a/vendor/github.com/jackc/pgx/v5/internal/sanitize/sanitize.go b/vendor/github.com/jackc/pgx/v5/internal/sanitize/sanitize.go
new file mode 100644
index 000000000..033a4143b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/sanitize/sanitize.go
@@ -0,0 +1,541 @@
+package sanitize
+
+import (
+	"bytes"
+	"encoding/hex"
+	"fmt"
+	"math"
+	"slices"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+	"unicode/utf8"
+)
+
+// Part is either a string or an int. A string is raw SQL. An int is a
+// argument placeholder.
+type Part any
+
+type Query struct {
+	Parts []Part
+}
+
+// utf.DecodeRune returns the utf8.RuneError for errors. But that is actually rune U+FFFD -- the unicode replacement
+// character. utf8.RuneError is not an error if it is also width 3.
+//
+// https://github.com/jackc/pgx/issues/1380
+const replacementcharacterwidth = 3
+
+const maxBufSize = 16384 // 16 Ki
+
+var bufPool = &pool[*bytes.Buffer]{
+	new: func() *bytes.Buffer {
+		return &bytes.Buffer{}
+	},
+	reset: func(b *bytes.Buffer) bool {
+		n := b.Len()
+		b.Reset()
+		return n < maxBufSize
+	},
+}
+
+var null = []byte("null")
+
+func (q *Query) Sanitize(args ...any) (string, error) {
+	argUse := make([]bool, len(args))
+	buf := bufPool.get()
+	defer bufPool.put(buf)
+
+	for _, part := range q.Parts {
+		switch part := part.(type) {
+		case string:
+			buf.WriteString(part)
+		case int:
+			argIdx := part - 1
+			var p []byte
+			if argIdx < 0 {
+				return "", fmt.Errorf("first sql argument must be > 0")
+			}
+
+			if argIdx >= len(args) {
+				return "", fmt.Errorf("insufficient arguments")
+			}
+
+			// Prevent SQL injection via Line Comment Creation
+			// https://github.com/jackc/pgx/security/advisories/GHSA-m7wr-2xf7-cm9p
+			buf.WriteByte(' ')
+
+			arg := args[argIdx]
+			switch arg := arg.(type) {
+			case nil:
+				p = null
+			case int64:
+				p = strconv.AppendInt(buf.AvailableBuffer(), arg, 10)
+			case float64:
+				p = strconv.AppendFloat(buf.AvailableBuffer(), arg, 'f', -1, 64)
+			case bool:
+				p = strconv.AppendBool(buf.AvailableBuffer(), arg)
+			case []byte:
+				p = QuoteBytes(buf.AvailableBuffer(), arg)
+			case string:
+				p = QuoteString(buf.AvailableBuffer(), arg)
+			case time.Time:
+				p = arg.Truncate(time.Microsecond).
+					AppendFormat(buf.AvailableBuffer(), "'2006-01-02 15:04:05.999999999Z07:00:00'")
+			default:
+				return "", fmt.Errorf("invalid arg type: %T", arg)
+			}
+			argUse[argIdx] = true
+
+			buf.Write(p)
+
+			// Prevent SQL injection via Line Comment Creation
+			// https://github.com/jackc/pgx/security/advisories/GHSA-m7wr-2xf7-cm9p
+			buf.WriteByte(' ')
+		default:
+			return "", fmt.Errorf("invalid Part type: %T", part)
+		}
+	}
+
+	for i, used := range argUse {
+		if !used {
+			return "", fmt.Errorf("unused argument: %d", i)
+		}
+	}
+	return buf.String(), nil
+}
+
+func NewQuery(sql string) (*Query, error) {
+	query := &Query{}
+	query.init(sql)
+
+	return query, nil
+}
+
+var sqlLexerPool = &pool[*sqlLexer]{
+	new: func() *sqlLexer {
+		return &sqlLexer{}
+	},
+	reset: func(sl *sqlLexer) bool {
+		*sl = sqlLexer{}
+		return true
+	},
+}
+
+func (q *Query) init(sql string) {
+	parts := q.Parts[:0]
+	if parts == nil {
+		// dirty, but fast heuristic to preallocate for ~90% usecases
+		n := strings.Count(sql, "$") + strings.Count(sql, "--") + 1
+		parts = make([]Part, 0, n)
+	}
+
+	l := sqlLexerPool.get()
+	defer sqlLexerPool.put(l)
+
+	l.src = sql
+	l.stateFn = rawState
+	l.parts = parts
+
+	for l.stateFn != nil {
+		l.stateFn = l.stateFn(l)
+	}
+
+	q.Parts = l.parts
+}
+
+func QuoteString(dst []byte, str string) []byte {
+	const quote = '\''
+
+	// Preallocate space for the worst case scenario
+	dst = slices.Grow(dst, len(str)*2+2)
+
+	// Add opening quote
+	dst = append(dst, quote)
+
+	// Iterate through the string without allocating
+	for i := 0; i < len(str); i++ {
+		if str[i] == quote {
+			dst = append(dst, quote, quote)
+		} else {
+			dst = append(dst, str[i])
+		}
+	}
+
+	// Add closing quote
+	dst = append(dst, quote)
+
+	return dst
+}
+
+func QuoteBytes(dst, buf []byte) []byte {
+	if len(buf) == 0 {
+		return append(dst, `'\x'`...)
+	}
+
+	// Calculate required length
+	requiredLen := 3 + hex.EncodedLen(len(buf)) + 1
+
+	// Ensure dst has enough capacity
+	if cap(dst)-len(dst) < requiredLen {
+		newDst := make([]byte, len(dst), len(dst)+requiredLen)
+		copy(newDst, dst)
+		dst = newDst
+	}
+
+	// Record original length and extend slice
+	origLen := len(dst)
+	dst = dst[:origLen+requiredLen]
+
+	// Add prefix
+	dst[origLen] = '\''
+	dst[origLen+1] = '\\'
+	dst[origLen+2] = 'x'
+
+	// Encode bytes directly into dst
+	hex.Encode(dst[origLen+3:len(dst)-1], buf)
+
+	// Add suffix
+	dst[len(dst)-1] = '\''
+
+	return dst
+}
+
+type sqlLexer struct {
+	src       string
+	start     int
+	pos       int
+	nested    int    // multiline comment nesting level.
+	dollarTag string // active tag while inside a dollar-quoted string (may be empty for $$).
+	stateFn   stateFn
+	parts     []Part
+}
+
+type stateFn func(*sqlLexer) stateFn
+
+func rawState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case 'e', 'E':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune == '\'' {
+				l.pos += width
+				return escapeStringState
+			}
+		case '\'':
+			return singleQuoteState
+		case '"':
+			return doubleQuoteState
+		case '$':
+			nextRune, _ := utf8.DecodeRuneInString(l.src[l.pos:])
+			if '0' <= nextRune && nextRune <= '9' {
+				if l.pos-l.start > 0 {
+					l.parts = append(l.parts, l.src[l.start:l.pos-width])
+				}
+				l.start = l.pos
+				return placeholderState
+			}
+			// PostgreSQL dollar-quoted string: $[tag]$...$[tag]$. The $ was
+			// just consumed; try to match the rest of the opening tag.
+			// Without this, placeholders embedded inside dollar-quoted
+			// literals would be incorrectly substituted.
+			if tagLen, ok := scanDollarQuoteTag(l.src[l.pos:]); ok {
+				l.dollarTag = l.src[l.pos : l.pos+tagLen]
+				l.pos += tagLen + 1 // advance past tag and closing '$'
+				return dollarQuoteState
+			}
+		case '-':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune == '-' {
+				l.pos += width
+				return oneLineCommentState
+			}
+		case '/':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune == '*' {
+				l.pos += width
+				return multilineCommentState
+			}
+		case utf8.RuneError:
+			if width != replacementcharacterwidth {
+				if l.pos-l.start > 0 {
+					l.parts = append(l.parts, l.src[l.start:l.pos])
+					l.start = l.pos
+				}
+				return nil
+			}
+		}
+	}
+}
+
+func singleQuoteState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '\'':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune != '\'' {
+				return rawState
+			}
+			l.pos += width
+		case utf8.RuneError:
+			if width != replacementcharacterwidth {
+				if l.pos-l.start > 0 {
+					l.parts = append(l.parts, l.src[l.start:l.pos])
+					l.start = l.pos
+				}
+				return nil
+			}
+		}
+	}
+}
+
+func doubleQuoteState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '"':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune != '"' {
+				return rawState
+			}
+			l.pos += width
+		case utf8.RuneError:
+			if width != replacementcharacterwidth {
+				if l.pos-l.start > 0 {
+					l.parts = append(l.parts, l.src[l.start:l.pos])
+					l.start = l.pos
+				}
+				return nil
+			}
+		}
+	}
+}
+
+// placeholderState consumes a placeholder value. The $ must have already has
+// already been consumed. The first rune must be a digit.
+func placeholderState(l *sqlLexer) stateFn {
+	num := 0
+
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		if '0' <= r && r <= '9' {
+			// Clamp rather than silently wrap on pathological input like
+			// "$92233720368547758070" which would otherwise overflow int and
+			// could land on a valid args index. Any value above MaxInt32 far
+			// exceeds any plausible args length, so Sanitize will correctly
+			// return "insufficient arguments".
+			if num > (math.MaxInt32-9)/10 {
+				num = math.MaxInt32
+			} else {
+				num = num*10 + int(r-'0')
+			}
+		} else {
+			l.parts = append(l.parts, num)
+			l.pos -= width
+			l.start = l.pos
+			return rawState
+		}
+	}
+}
+
+// dollarQuoteState consumes the body of a PostgreSQL dollar-quoted string
+// ($[tag]$...$[tag]$). The opening tag (including its terminating '$') has
+// already been consumed.
+func dollarQuoteState(l *sqlLexer) stateFn {
+	closer := "$" + l.dollarTag + "$"
+	idx := strings.Index(l.src[l.pos:], closer)
+	if idx < 0 {
+		// Unterminated — mirror the behavior of other quoted-string states by
+		// consuming the remaining input into the current part and stopping.
+		if len(l.src)-l.start > 0 {
+			l.parts = append(l.parts, l.src[l.start:])
+			l.start = len(l.src)
+		}
+		l.pos = len(l.src)
+		return nil
+	}
+	l.pos += idx + len(closer)
+	l.dollarTag = ""
+	return rawState
+}
+
+// scanDollarQuoteTag checks whether src begins with an optional dollar-quoted
+// string tag followed by a closing '$'. src must point just past the opening
+// '$'. Returns the byte length of the tag (zero for an anonymous $$) and
+// whether a valid tag was found.
+//
+// Tag grammar matches the PostgreSQL lexer (scan.l):
+//
+//	dolq_start: [A-Za-z_\x80-\xff]
+//	dolq_cont:  [A-Za-z0-9_\x80-\xff]
+func scanDollarQuoteTag(src string) (int, bool) {
+	first := true
+	for i := 0; i < len(src); {
+		r, w := utf8.DecodeRuneInString(src[i:])
+		if r == '$' {
+			return i, true
+		}
+		if !isDollarTagRune(r, first) {
+			return 0, false
+		}
+		first = false
+		i += w
+	}
+	return 0, false
+}
+
+func isDollarTagRune(r rune, first bool) bool {
+	switch {
+	case r == '_':
+		return true
+	case 'a' <= r && r <= 'z':
+		return true
+	case 'A' <= r && r <= 'Z':
+		return true
+	case !first && '0' <= r && r <= '9':
+		return true
+	case r >= 0x80 && r != utf8.RuneError:
+		return true
+	}
+	return false
+}
+
+func escapeStringState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '\\':
+			_, width = utf8.DecodeRuneInString(l.src[l.pos:])
+			l.pos += width
+		case '\'':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune != '\'' {
+				return rawState
+			}
+			l.pos += width
+		case utf8.RuneError:
+			if width != replacementcharacterwidth {
+				if l.pos-l.start > 0 {
+					l.parts = append(l.parts, l.src[l.start:l.pos])
+					l.start = l.pos
+				}
+				return nil
+			}
+		}
+	}
+}
+
+func oneLineCommentState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '\\':
+			_, width = utf8.DecodeRuneInString(l.src[l.pos:])
+			l.pos += width
+		case '\n', '\r':
+			return rawState
+		case utf8.RuneError:
+			if width != replacementcharacterwidth {
+				if l.pos-l.start > 0 {
+					l.parts = append(l.parts, l.src[l.start:l.pos])
+					l.start = l.pos
+				}
+				return nil
+			}
+		}
+	}
+}
+
+func multilineCommentState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '/':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune == '*' {
+				l.pos += width
+				l.nested++
+			}
+		case '*':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune != '/' {
+				continue
+			}
+
+			l.pos += width
+			if l.nested == 0 {
+				return rawState
+			}
+			l.nested--
+
+		case utf8.RuneError:
+			if width != replacementcharacterwidth {
+				if l.pos-l.start > 0 {
+					l.parts = append(l.parts, l.src[l.start:l.pos])
+					l.start = l.pos
+				}
+				return nil
+			}
+		}
+	}
+}
+
+var queryPool = &pool[*Query]{
+	new: func() *Query {
+		return &Query{}
+	},
+	reset: func(q *Query) bool {
+		n := len(q.Parts)
+		q.Parts = q.Parts[:0]
+		return n < 64 // drop too large queries
+	},
+}
+
+// SanitizeSQL replaces placeholder values with args. It quotes and escapes args
+// as necessary. This function is only safe when standard_conforming_strings is
+// on.
+func SanitizeSQL(sql string, args ...any) (string, error) {
+	query := queryPool.get()
+	query.init(sql)
+	defer queryPool.put(query)
+
+	return query.Sanitize(args...)
+}
+
+type pool[E any] struct {
+	p     sync.Pool
+	new   func() E
+	reset func(E) bool
+}
+
+func (pool *pool[E]) get() E {
+	v, ok := pool.p.Get().(E)
+	if !ok {
+		v = pool.new()
+	}
+
+	return v
+}
+
+func (p *pool[E]) put(v E) {
+	if p.reset(v) {
+		p.p.Put(v)
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/internal/stmtcache/lru_cache.go b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/lru_cache.go
new file mode 100644
index 000000000..b677d29cb
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/lru_cache.go
@@ -0,0 +1,187 @@
+package stmtcache
+
+import (
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+// lruNode is a typed doubly-linked list node with freelist support.
+type lruNode struct {
+	sd   *pgconn.StatementDescription
+	prev *lruNode
+	next *lruNode
+}
+
+// LRUCache implements Cache with a Least Recently Used (LRU) cache.
+type LRUCache struct {
+	m    map[string]*lruNode
+	head *lruNode
+
+	tail     *lruNode
+	len      int
+	cap      int
+	freelist *lruNode
+
+	invalidStmts []*pgconn.StatementDescription
+	invalidSet   map[string]struct{}
+}
+
+// NewLRUCache creates a new LRUCache. cap is the maximum size of the cache.
+func NewLRUCache(cap int) *LRUCache {
+	head := &lruNode{}
+	tail := &lruNode{}
+	head.next = tail
+	tail.prev = head
+
+	return &LRUCache{
+		cap:        cap,
+		m:          make(map[string]*lruNode, cap),
+		head:       head,
+		tail:       tail,
+		invalidSet: make(map[string]struct{}),
+	}
+}
+
+// Get returns the statement description for sql. Returns nil if not found.
+func (c *LRUCache) Get(key string) *pgconn.StatementDescription {
+	node, ok := c.m[key]
+	if !ok {
+		return nil
+	}
+	c.moveToFront(node)
+	return node.sd
+}
+
+// Put stores sd in the cache. Put panics if sd.SQL is "". Put does nothing if sd.SQL already exists in the cache or
+// sd.SQL has been invalidated and HandleInvalidated has not been called yet.
+func (c *LRUCache) Put(sd *pgconn.StatementDescription) {
+	if sd.SQL == "" {
+		panic("cannot store statement description with empty SQL")
+	}
+
+	if _, present := c.m[sd.SQL]; present {
+		return
+	}
+
+	// The statement may have been invalidated but not yet handled. Do not readd it to the cache.
+	if _, invalidated := c.invalidSet[sd.SQL]; invalidated {
+		return
+	}
+
+	if c.len == c.cap {
+		c.invalidateOldest()
+	}
+
+	node := c.allocNode()
+	node.sd = sd
+	c.insertAfter(c.head, node)
+	c.m[sd.SQL] = node
+	c.len++
+}
+
+// Invalidate invalidates statement description identified by sql. Does nothing if not found.
+func (c *LRUCache) Invalidate(sql string) {
+	node, ok := c.m[sql]
+	if !ok {
+		return
+	}
+	delete(c.m, sql)
+	c.invalidStmts = append(c.invalidStmts, node.sd)
+	c.invalidSet[sql] = struct{}{}
+	c.unlink(node)
+	c.len--
+	c.freeNode(node)
+}
+
+// InvalidateAll invalidates all statement descriptions.
+func (c *LRUCache) InvalidateAll() {
+	for node := c.head.next; node != c.tail; {
+		next := node.next
+		c.invalidStmts = append(c.invalidStmts, node.sd)
+		c.invalidSet[node.sd.SQL] = struct{}{}
+		c.freeNode(node)
+		node = next
+	}
+
+	clear(c.m)
+	c.head.next = c.tail
+	c.tail.prev = c.head
+	c.len = 0
+}
+
+// GetInvalidated returns a slice of all statement descriptions invalidated since the last call to RemoveInvalidated.
+func (c *LRUCache) GetInvalidated() []*pgconn.StatementDescription {
+	return c.invalidStmts
+}
+
+// RemoveInvalidated removes all invalidated statement descriptions. No other calls to Cache must be made between a
+// call to GetInvalidated and RemoveInvalidated or RemoveInvalidated may remove statement descriptions that were
+// never seen by the call to GetInvalidated.
+func (c *LRUCache) RemoveInvalidated() {
+	c.invalidStmts = c.invalidStmts[:0]
+	clear(c.invalidSet)
+}
+
+// Len returns the number of cached prepared statement descriptions.
+func (c *LRUCache) Len() int {
+	return c.len
+}
+
+// Cap returns the maximum number of cached prepared statement descriptions.
+func (c *LRUCache) Cap() int {
+	return c.cap
+}
+
+func (c *LRUCache) invalidateOldest() {
+	node := c.tail.prev
+	if node == c.head {
+		return
+	}
+	c.invalidStmts = append(c.invalidStmts, node.sd)
+	c.invalidSet[node.sd.SQL] = struct{}{}
+	delete(c.m, node.sd.SQL)
+	c.unlink(node)
+	c.len--
+	c.freeNode(node)
+}
+
+// List operations - sentinel nodes eliminate nil checks
+
+func (c *LRUCache) insertAfter(at, node *lruNode) {
+	node.prev = at
+	node.next = at.next
+	at.next.prev = node
+	at.next = node
+}
+
+func (c *LRUCache) unlink(node *lruNode) {
+	node.prev.next = node.next
+	node.next.prev = node.prev
+}
+
+func (c *LRUCache) moveToFront(node *lruNode) {
+	if node.prev == c.head {
+		return
+	}
+	c.unlink(node)
+	c.insertAfter(c.head, node)
+}
+
+// Node pool operations - reuse evicted nodes to avoid allocations
+
+func (c *LRUCache) allocNode() *lruNode {
+	if c.freelist != nil {
+		node := c.freelist
+		c.freelist = node.next
+		node.next = nil
+		node.prev = nil
+		return node
+	}
+	return &lruNode{}
+}
+
+func (c *LRUCache) freeNode(node *lruNode) {
+	node.sd = nil
+	node.prev = nil
+	node.next = c.freelist
+	c.freelist = node
+}
diff --git a/vendor/github.com/jackc/pgx/v5/internal/stmtcache/stmtcache.go b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/stmtcache.go
new file mode 100644
index 000000000..d57bdd29e
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/stmtcache.go
@@ -0,0 +1,45 @@
+// Package stmtcache is a cache for statement descriptions.
+package stmtcache
+
+import (
+	"crypto/sha256"
+	"encoding/hex"
+
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+// StatementName returns a statement name that will be stable for sql across multiple connections and program
+// executions.
+func StatementName(sql string) string {
+	digest := sha256.Sum256([]byte(sql))
+	return "stmtcache_" + hex.EncodeToString(digest[0:24])
+}
+
+// Cache caches statement descriptions.
+type Cache interface {
+	// Get returns the statement description for sql. Returns nil if not found.
+	Get(sql string) *pgconn.StatementDescription
+
+	// Put stores sd in the cache. Put panics if sd.SQL is "". Put does nothing if sd.SQL already exists in the cache.
+	Put(sd *pgconn.StatementDescription)
+
+	// Invalidate invalidates statement description identified by sql. Does nothing if not found.
+	Invalidate(sql string)
+
+	// InvalidateAll invalidates all statement descriptions.
+	InvalidateAll()
+
+	// GetInvalidated returns a slice of all statement descriptions invalidated since the last call to RemoveInvalidated.
+	GetInvalidated() []*pgconn.StatementDescription
+
+	// RemoveInvalidated removes all invalidated statement descriptions. No other calls to Cache must be made between a
+	// call to GetInvalidated and RemoveInvalidated or RemoveInvalidated may remove statement descriptions that were
+	// never seen by the call to GetInvalidated.
+	RemoveInvalidated()
+
+	// Len returns the number of cached prepared statement descriptions.
+	Len() int
+
+	// Cap returns the maximum number of cached prepared statement descriptions.
+	Cap() int
+}
diff --git a/vendor/github.com/jackc/pgx/v5/large_objects.go b/vendor/github.com/jackc/pgx/v5/large_objects.go
new file mode 100644
index 000000000..9d21afdce
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/large_objects.go
@@ -0,0 +1,161 @@
+package pgx
+
+import (
+	"context"
+	"errors"
+	"io"
+
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+// The PostgreSQL wire protocol has a limit of 1 GB - 1 per message. See definition of
+// PQ_LARGE_MESSAGE_LIMIT in the PostgreSQL source code. To allow for the other data
+// in the message,maxLargeObjectMessageLength should be no larger than 1 GB - 1 KB.
+var maxLargeObjectMessageLength = 1024*1024*1024 - 1024
+
+// LargeObjects is a structure used to access the large objects API. It is only valid within the transaction where it
+// was created.
+//
+// For more details see: http://www.postgresql.org/docs/current/static/largeobjects.html
+type LargeObjects struct {
+	tx Tx
+}
+
+type LargeObjectMode int32
+
+const (
+	LargeObjectModeWrite LargeObjectMode = 0x20000
+	LargeObjectModeRead  LargeObjectMode = 0x40000
+)
+
+// Create creates a new large object. If oid is zero, the server assigns an unused OID.
+func (o *LargeObjects) Create(ctx context.Context, oid uint32) (uint32, error) {
+	err := o.tx.QueryRow(ctx, "select lo_create($1)", oid).Scan(&oid)
+	return oid, err
+}
+
+// Open opens an existing large object with the given mode. ctx will also be used for all operations on the opened large
+// object.
+func (o *LargeObjects) Open(ctx context.Context, oid uint32, mode LargeObjectMode) (*LargeObject, error) {
+	var fd int32
+	err := o.tx.QueryRow(ctx, "select lo_open($1, $2)", oid, mode).Scan(&fd)
+	if err != nil {
+		return nil, err
+	}
+	return &LargeObject{fd: fd, tx: o.tx, ctx: ctx}, nil
+}
+
+// Unlink removes a large object from the database.
+func (o *LargeObjects) Unlink(ctx context.Context, oid uint32) error {
+	var result int32
+	err := o.tx.QueryRow(ctx, "select lo_unlink($1)", oid).Scan(&result)
+	if err != nil {
+		return err
+	}
+
+	if result != 1 {
+		return errors.New("failed to remove large object")
+	}
+
+	return nil
+}
+
+// A LargeObject is a large object stored on the server. It is only valid within the transaction that it was initialized
+// in. It uses the context it was initialized with for all operations. It implements these interfaces:
+//
+//	io.Writer
+//	io.Reader
+//	io.Seeker
+//	io.Closer
+type LargeObject struct {
+	ctx context.Context
+	tx  Tx
+	fd  int32
+}
+
+// Write writes p to the large object and returns the number of bytes written and an error if not all of p was written.
+func (o *LargeObject) Write(p []byte) (int, error) {
+	nTotal := 0
+	for {
+		expected := len(p) - nTotal
+		if expected == 0 {
+			break
+		} else if expected > maxLargeObjectMessageLength {
+			expected = maxLargeObjectMessageLength
+		}
+
+		var n int
+		err := o.tx.QueryRow(o.ctx, "select lowrite($1, $2)", o.fd, p[nTotal:nTotal+expected]).Scan(&n)
+		if err != nil {
+			return nTotal, err
+		}
+
+		if n < 0 {
+			return nTotal, errors.New("failed to write to large object")
+		}
+
+		nTotal += n
+
+		if n < expected {
+			return nTotal, errors.New("short write to large object")
+		} else if n > expected {
+			return nTotal, errors.New("invalid write to large object")
+		}
+	}
+
+	return nTotal, nil
+}
+
+// Read reads up to len(p) bytes into p returning the number of bytes read.
+func (o *LargeObject) Read(p []byte) (int, error) {
+	nTotal := 0
+	for {
+		expected := len(p) - nTotal
+		if expected == 0 {
+			break
+		} else if expected > maxLargeObjectMessageLength {
+			expected = maxLargeObjectMessageLength
+		}
+
+		res := pgtype.PreallocBytes(p[nTotal:])
+		err := o.tx.QueryRow(o.ctx, "select loread($1, $2)", o.fd, expected).Scan(&res)
+		// We compute expected so that it always fits into p, so it should never happen
+		// that PreallocBytes's ScanBytes had to allocate a new slice.
+		nTotal += len(res)
+		if err != nil {
+			return nTotal, err
+		}
+
+		if len(res) < expected {
+			return nTotal, io.EOF
+		} else if len(res) > expected {
+			return nTotal, errors.New("invalid read of large object")
+		}
+	}
+
+	return nTotal, nil
+}
+
+// Seek moves the current location pointer to the new location specified by offset.
+func (o *LargeObject) Seek(offset int64, whence int) (n int64, err error) {
+	err = o.tx.QueryRow(o.ctx, "select lo_lseek64($1, $2, $3)", o.fd, offset, whence).Scan(&n)
+	return n, err
+}
+
+// Tell returns the current read or write location of the large object descriptor.
+func (o *LargeObject) Tell() (n int64, err error) {
+	err = o.tx.QueryRow(o.ctx, "select lo_tell64($1)", o.fd).Scan(&n)
+	return n, err
+}
+
+// Truncate the large object to size.
+func (o *LargeObject) Truncate(size int64) (err error) {
+	_, err = o.tx.Exec(o.ctx, "select lo_truncate64($1, $2)", o.fd, size)
+	return err
+}
+
+// Close the large object descriptor.
+func (o *LargeObject) Close() error {
+	_, err := o.tx.Exec(o.ctx, "select lo_close($1)", o.fd)
+	return err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/mise.toml b/vendor/github.com/jackc/pgx/v5/mise.toml
new file mode 100644
index 000000000..78610d4cc
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/mise.toml
@@ -0,0 +1,8 @@
+[tools]
+go = '1.26.3'
+"go:github.com/go-critic/go-critic/cmd/gocritic" = "latest"
+"go:github.com/gordonklaus/ineffassign" = "latest"
+"go:github.com/mdempsky/unconvert" = "latest"
+"go:golang.org/x/tools/cmd/goimports" = "latest"
+"go:mvdan.cc/gofumpt" = "latest"
+ruby = '4.0.4'
diff --git a/vendor/github.com/jackc/pgx/v5/named_args.go b/vendor/github.com/jackc/pgx/v5/named_args.go
new file mode 100644
index 000000000..1300c91c0
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/named_args.go
@@ -0,0 +1,410 @@
+package pgx
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"unicode/utf8"
+)
+
+// NamedArgs can be used as the first argument to a query method. It will replace every '@' named placeholder with a '$'
+// ordinal placeholder and construct the appropriate arguments.
+//
+// For example, the following two queries are equivalent:
+//
+//	conn.Query(ctx, "select * from widgets where foo = @foo and bar = @bar", pgx.NamedArgs{"foo": 1, "bar": 2})
+//	conn.Query(ctx, "select * from widgets where foo = $1 and bar = $2", 1, 2)
+//
+// Named placeholders are case sensitive and must start with a letter or underscore. Subsequent characters can be
+// letters, numbers, or underscores.
+
+type NamedArgs map[string]any
+
+// RewriteQuery implements the QueryRewriter interface.
+func (na NamedArgs) RewriteQuery(ctx context.Context, conn *Conn, sql string, args []any) (newSQL string, newArgs []any, err error) {
+	return rewriteQuery(na, sql, false)
+}
+
+// StrictNamedArgs can be used in the same way as NamedArgs, but provided arguments are also checked to include all
+// named arguments that the sql query uses, and no extra arguments.
+type StrictNamedArgs map[string]any
+
+// RewriteQuery implements the QueryRewriter interface.
+func (sna StrictNamedArgs) RewriteQuery(ctx context.Context, conn *Conn, sql string, args []any) (newSQL string, newArgs []any, err error) {
+	return rewriteQuery(sna, sql, true)
+}
+
+type errorQueryRewriter struct {
+	err error
+}
+
+func (r errorQueryRewriter) RewriteQuery(ctx context.Context, conn *Conn, sql string, args []any) (newSQL string, newArgs []any, err error) {
+	return "", nil, r.err
+}
+
+// StructArgs converts exported fields of a struct into a QueryRewriter so it can
+// be used as the first argument to a query method (e.g. "where id=@id").
+//
+// Field names are taken from the `db` struct tag if present. Tag values may
+// include comma-separated options (e.g. `db:"id,omitempty"`). A `db:"-"` field is
+// ignored. If no `db` tag is present, the Go field name is used.
+//
+// sa may be a struct or a pointer to a struct.
+func StructArgs(sa any) QueryRewriter {
+	args, err := structArgs(sa)
+	if err != nil {
+		return errorQueryRewriter{err: err}
+	}
+	return NamedArgs(args)
+}
+
+// StrictStructArgs is like StructArgs but uses StrictNamedArgs rewriting
+// semantics (i.e. errors if the SQL query references missing arguments or if
+// extra arguments are provided).
+func StrictStructArgs(sa any) QueryRewriter {
+	args, err := structArgs(sa)
+	if err != nil {
+		return errorQueryRewriter{err: err}
+	}
+	return StrictNamedArgs(args)
+}
+
+func structArgs(sa any) (map[string]any, error) {
+	if sa == nil {
+		return nil, fmt.Errorf("StructArgs requires a struct or pointer to struct, got nil")
+	}
+
+	v := reflect.ValueOf(sa)
+	t := v.Type()
+
+	if t.Kind() == reflect.Pointer {
+		if v.IsNil() {
+			return nil, fmt.Errorf("StructArgs requires a non-nil pointer to struct")
+		}
+		v = v.Elem()
+		t = v.Type()
+	}
+
+	if t.Kind() != reflect.Struct {
+		return nil, fmt.Errorf("StructArgs requires a struct or pointer to struct, got %s", t)
+	}
+
+	out := make(map[string]any, t.NumField())
+	for i := 0; i < t.NumField(); i++ {
+		sf := t.Field(i)
+
+		// Ignore unexported fields.
+		if sf.PkgPath != "" {
+			continue
+		}
+
+		key, ok, err := dbTagKey(sf)
+		if err != nil {
+			return nil, err
+		}
+		if !ok {
+			continue
+		}
+
+		if _, exists := out[key]; exists {
+			return nil, fmt.Errorf("duplicate StructArgs key %q", key)
+		}
+
+		out[key] = v.Field(i).Interface()
+	}
+
+	return out, nil
+}
+
+// dbTagKey derives the named-argument key for a struct field. Tag parsing matches
+// RowToStructByName* in rows.go (structTagKey, Lookup, comma options, db:"-").
+// Anonymous embedded structs are skipped without flattening (unlike row scanning).
+func dbTagKey(sf reflect.StructField) (key string, ok bool, err error) {
+	if sf.Anonymous {
+		ft := sf.Type
+		if ft.Kind() == reflect.Pointer {
+			ft = ft.Elem()
+		}
+		if ft.Kind() == reflect.Struct {
+			return "", false, nil
+		}
+	}
+
+	dbTag, dbTagPresent := sf.Tag.Lookup(structTagKey)
+	if dbTagPresent {
+		dbTag, _, _ = strings.Cut(dbTag, ",")
+	}
+	if dbTag == "-" {
+		return "", false, nil
+	}
+	if dbTagPresent {
+		if dbTag == "" {
+			return "", false, fmt.Errorf("field %s has empty `%s` tag", sf.Name, structTagKey)
+		}
+		return dbTag, true, nil
+	}
+
+	return sf.Name, true, nil
+}
+
+type namedArg string
+
+type sqlLexer struct {
+	src     string
+	start   int
+	pos     int
+	nested  int // multiline comment nesting level.
+	stateFn stateFn
+	parts   []any
+
+	nameToOrdinal map[namedArg]int
+}
+
+type stateFn func(*sqlLexer) stateFn
+
+func rewriteQuery(na map[string]any, sql string, isStrict bool) (newSQL string, newArgs []any, err error) {
+	l := &sqlLexer{
+		src:           sql,
+		stateFn:       rawState,
+		nameToOrdinal: make(map[namedArg]int, len(na)),
+	}
+
+	for l.stateFn != nil {
+		l.stateFn = l.stateFn(l)
+	}
+
+	sb := strings.Builder{}
+	for _, p := range l.parts {
+		switch p := p.(type) {
+		case string:
+			sb.WriteString(p)
+		case namedArg:
+			sb.WriteRune('$')
+			sb.WriteString(strconv.Itoa(l.nameToOrdinal[p]))
+		}
+	}
+
+	newArgs = make([]any, len(l.nameToOrdinal))
+	for name, ordinal := range l.nameToOrdinal {
+		var found bool
+		newArgs[ordinal-1], found = na[string(name)]
+		if isStrict && !found {
+			return "", nil, fmt.Errorf("argument %s found in sql query but not present in StrictNamedArgs", name)
+		}
+	}
+
+	if isStrict {
+		for name := range na {
+			if _, found := l.nameToOrdinal[namedArg(name)]; !found {
+				return "", nil, fmt.Errorf("argument %s of StrictNamedArgs not found in sql query", name)
+			}
+		}
+	}
+
+	return sb.String(), newArgs, nil
+}
+
+func rawState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case 'e', 'E':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune == '\'' {
+				l.pos += width
+				return escapeStringState
+			}
+		case '\'':
+			return singleQuoteState
+		case '"':
+			return doubleQuoteState
+		case '@':
+			nextRune, _ := utf8.DecodeRuneInString(l.src[l.pos:])
+			if isLetter(nextRune) || nextRune == '_' {
+				if l.pos-l.start > 0 {
+					l.parts = append(l.parts, l.src[l.start:l.pos-width])
+				}
+				l.start = l.pos
+				return namedArgState
+			}
+		case '-':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune == '-' {
+				l.pos += width
+				return oneLineCommentState
+			}
+		case '/':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune == '*' {
+				l.pos += width
+				return multilineCommentState
+			}
+		case utf8.RuneError:
+			if l.pos-l.start > 0 {
+				l.parts = append(l.parts, l.src[l.start:l.pos])
+				l.start = l.pos
+			}
+			return nil
+		}
+	}
+}
+
+func isLetter(r rune) bool {
+	return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')
+}
+
+func namedArgState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		if r == utf8.RuneError {
+			if l.pos-l.start > 0 {
+				na := namedArg(l.src[l.start:l.pos])
+				if _, found := l.nameToOrdinal[na]; !found {
+					l.nameToOrdinal[na] = len(l.nameToOrdinal) + 1
+				}
+				l.parts = append(l.parts, na)
+				l.start = l.pos
+			}
+			return nil
+		} else if !(isLetter(r) || (r >= '0' && r <= '9') || r == '_') {
+			l.pos -= width
+			na := namedArg(l.src[l.start:l.pos])
+			if _, found := l.nameToOrdinal[na]; !found {
+				l.nameToOrdinal[na] = len(l.nameToOrdinal) + 1
+			}
+			l.parts = append(l.parts, na)
+			l.start = l.pos
+			return rawState
+		}
+	}
+}
+
+func singleQuoteState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '\'':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune != '\'' {
+				return rawState
+			}
+			l.pos += width
+		case utf8.RuneError:
+			if l.pos-l.start > 0 {
+				l.parts = append(l.parts, l.src[l.start:l.pos])
+				l.start = l.pos
+			}
+			return nil
+		}
+	}
+}
+
+func doubleQuoteState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '"':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune != '"' {
+				return rawState
+			}
+			l.pos += width
+		case utf8.RuneError:
+			if l.pos-l.start > 0 {
+				l.parts = append(l.parts, l.src[l.start:l.pos])
+				l.start = l.pos
+			}
+			return nil
+		}
+	}
+}
+
+func escapeStringState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '\\':
+			_, width = utf8.DecodeRuneInString(l.src[l.pos:])
+			l.pos += width
+		case '\'':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune != '\'' {
+				return rawState
+			}
+			l.pos += width
+		case utf8.RuneError:
+			if l.pos-l.start > 0 {
+				l.parts = append(l.parts, l.src[l.start:l.pos])
+				l.start = l.pos
+			}
+			return nil
+		}
+	}
+}
+
+func oneLineCommentState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '\\':
+			_, width = utf8.DecodeRuneInString(l.src[l.pos:])
+			l.pos += width
+		case '\n', '\r':
+			return rawState
+		case utf8.RuneError:
+			if l.pos-l.start > 0 {
+				l.parts = append(l.parts, l.src[l.start:l.pos])
+				l.start = l.pos
+			}
+			return nil
+		}
+	}
+}
+
+func multilineCommentState(l *sqlLexer) stateFn {
+	for {
+		r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+		l.pos += width
+
+		switch r {
+		case '/':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune == '*' {
+				l.pos += width
+				l.nested++
+			}
+		case '*':
+			nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+			if nextRune != '/' {
+				continue
+			}
+
+			l.pos += width
+			if l.nested == 0 {
+				return rawState
+			}
+			l.nested--
+
+		case utf8.RuneError:
+			if l.pos-l.start > 0 {
+				l.parts = append(l.parts, l.src[l.start:l.pos])
+				l.start = l.pos
+			}
+			return nil
+		}
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/README.md b/vendor/github.com/jackc/pgx/v5/pgconn/README.md
new file mode 100644
index 000000000..1fe15c268
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/README.md
@@ -0,0 +1,29 @@
+# pgconn
+
+Package pgconn is a low-level PostgreSQL database driver. It operates at nearly the same level as the C library libpq.
+It is primarily intended to serve as the foundation for higher level libraries such as https://github.com/jackc/pgx.
+Applications should handle normal queries with a higher level library and only use pgconn directly when required for
+low-level access to PostgreSQL functionality.
+
+## Example Usage
+
+```go
+pgConn, err := pgconn.Connect(context.Background(), os.Getenv("DATABASE_URL"))
+if err != nil {
+	log.Fatalln("pgconn failed to connect:", err)
+}
+defer pgConn.Close(context.Background())
+
+result := pgConn.ExecParams(context.Background(), "SELECT email FROM users WHERE id=$1", [][]byte{[]byte("123")}, nil, nil, nil)
+for result.NextRow() {
+	fmt.Println("User 123 has email:", string(result.Values()[0]))
+}
+_, err = result.Close()
+if err != nil {
+	log.Fatalln("failed reading result:", err)
+}
+```
+
+## Testing
+
+See CONTRIBUTING.md for setup instructions.
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/auth_oauth.go b/vendor/github.com/jackc/pgx/v5/pgconn/auth_oauth.go
new file mode 100644
index 000000000..991f6585d
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/auth_oauth.go
@@ -0,0 +1,67 @@
+package pgconn
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+
+	"github.com/jackc/pgx/v5/pgproto3"
+)
+
+func (c *PgConn) oauthAuth(ctx context.Context) error {
+	if c.config.OAuthTokenProvider == nil {
+		return errors.New("OAuth authentication required but no token provider configured")
+	}
+
+	token, err := c.config.OAuthTokenProvider(ctx)
+	if err != nil {
+		return fmt.Errorf("failed to obtain OAuth token: %w", err)
+	}
+
+	// https://www.rfc-editor.org/rfc/rfc7628.html#section-3.1
+	initialResponse := []byte("n,,\x01auth=Bearer " + token + "\x01\x01")
+
+	saslInitialResponse := &pgproto3.SASLInitialResponse{
+		AuthMechanism: "OAUTHBEARER",
+		Data:          initialResponse,
+	}
+	c.frontend.Send(saslInitialResponse)
+	err = c.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		return err
+	}
+
+	msg, err := c.receiveMessage()
+	if err != nil {
+		return err
+	}
+
+	switch m := msg.(type) {
+	case *pgproto3.AuthenticationOk:
+		return nil
+	case *pgproto3.AuthenticationSASLContinue:
+		// Server sent error response in SASL continue
+		// https://www.rfc-editor.org/rfc/rfc7628.html#section-3.2.2
+		// https://www.rfc-editor.org/rfc/rfc7628.html#section-3.2.3
+		errResponse := struct {
+			Status              string `json:"status"`
+			Scope               string `json:"scope"`
+			OpenIDConfiguration string `json:"openid-configuration"`
+		}{}
+		err := json.Unmarshal(m.Data, &errResponse)
+		if err != nil {
+			return fmt.Errorf("invalid OAuth error response from server: %w", err)
+		}
+
+		// Per RFC 7628 section 3.2.3, we should send a SASLResponse which only contains \x01.
+		// However, since the connection will be closed anyway, we can skip this
+		return fmt.Errorf("OAuth authentication failed: %s", errResponse.Status)
+
+	case *pgproto3.ErrorResponse:
+		return ErrorResponseToPgError(m)
+
+	default:
+		return fmt.Errorf("unexpected message type during OAuth auth: %T", msg)
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/auth_scram.go b/vendor/github.com/jackc/pgx/v5/pgconn/auth_scram.go
new file mode 100644
index 000000000..aeaf8cb1c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/auth_scram.go
@@ -0,0 +1,407 @@
+// SCRAM-SHA-256 and SCRAM-SHA-256-PLUS authentication
+//
+// Resources:
+//   https://tools.ietf.org/html/rfc5802
+//   https://tools.ietf.org/html/rfc5929
+//   https://tools.ietf.org/html/rfc8265
+//   https://www.postgresql.org/docs/current/sasl-authentication.html
+//
+// Inspiration drawn from other implementations:
+//   https://github.com/lib/pq/pull/608
+//   https://github.com/lib/pq/pull/788
+//   https://github.com/lib/pq/pull/833
+
+package pgconn
+
+import (
+	"bytes"
+	"crypto/hmac"
+	"crypto/pbkdf2"
+	"crypto/rand"
+	"crypto/sha256"
+	"crypto/sha512"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"hash"
+	"slices"
+	"strconv"
+
+	"github.com/jackc/pgx/v5/pgproto3"
+	"golang.org/x/text/secure/precis"
+)
+
+const (
+	clientNonceLen      = 18
+	scramSHA256Name     = "SCRAM-SHA-256"
+	scramSHA256PlusName = "SCRAM-SHA-256-PLUS"
+)
+
+// Perform SCRAM authentication.
+func (c *PgConn) scramAuth(serverAuthMechanisms []string) error {
+	sc, err := newScramClient(serverAuthMechanisms, c.config.Password)
+	if err != nil {
+		return err
+	}
+
+	serverHasPlus := slices.Contains(sc.serverAuthMechanisms, scramSHA256PlusName)
+	if c.config.ChannelBinding == "require" && !serverHasPlus {
+		return errors.New("channel binding required but server does not support SCRAM-SHA-256-PLUS")
+	}
+
+	// If we have a TLS connection and channel binding is not disabled, attempt to
+	// extract the server certificate hash for tls-server-end-point channel binding.
+	if tlsConn, ok := c.conn.(*tls.Conn); ok && c.config.ChannelBinding != "disable" {
+		certHash, err := getTLSCertificateHash(tlsConn)
+		if err != nil && c.config.ChannelBinding == "require" {
+			return fmt.Errorf("channel binding required but failed to get server certificate hash: %w", err)
+		}
+
+		// Upgrade to SCRAM-SHA-256-PLUS if we have binding data and the server supports it.
+		if certHash != nil && serverHasPlus {
+			sc.authMechanism = scramSHA256PlusName
+		}
+
+		sc.channelBindingData = certHash
+		sc.hasTLS = true
+	}
+
+	if c.config.ChannelBinding == "require" && sc.channelBindingData == nil {
+		return errors.New("channel binding required but channel binding data is not available")
+	}
+
+	// Send client-first-message in a SASLInitialResponse
+	saslInitialResponse := &pgproto3.SASLInitialResponse{
+		AuthMechanism: sc.authMechanism,
+		Data:          sc.clientFirstMessage(),
+	}
+	c.frontend.Send(saslInitialResponse)
+	err = c.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		return err
+	}
+
+	// Receive server-first-message payload in an AuthenticationSASLContinue.
+	saslContinue, err := c.rxSASLContinue()
+	if err != nil {
+		return err
+	}
+	err = sc.recvServerFirstMessage(saslContinue.Data)
+	if err != nil {
+		return err
+	}
+
+	// Send client-final-message in a SASLResponse
+	saslResponse := &pgproto3.SASLResponse{
+		Data: []byte(sc.clientFinalMessage()),
+	}
+	c.frontend.Send(saslResponse)
+	err = c.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		return err
+	}
+
+	// Receive server-final-message payload in an AuthenticationSASLFinal.
+	saslFinal, err := c.rxSASLFinal()
+	if err != nil {
+		return err
+	}
+	return sc.recvServerFinalMessage(saslFinal.Data)
+}
+
+func (c *PgConn) rxSASLContinue() (*pgproto3.AuthenticationSASLContinue, error) {
+	msg, err := c.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+	switch m := msg.(type) {
+	case *pgproto3.AuthenticationSASLContinue:
+		return m, nil
+	case *pgproto3.ErrorResponse:
+		return nil, ErrorResponseToPgError(m)
+	}
+
+	return nil, fmt.Errorf("expected AuthenticationSASLContinue message but received unexpected message %T", msg)
+}
+
+func (c *PgConn) rxSASLFinal() (*pgproto3.AuthenticationSASLFinal, error) {
+	msg, err := c.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+	switch m := msg.(type) {
+	case *pgproto3.AuthenticationSASLFinal:
+		return m, nil
+	case *pgproto3.ErrorResponse:
+		return nil, ErrorResponseToPgError(m)
+	}
+
+	return nil, fmt.Errorf("expected AuthenticationSASLFinal message but received unexpected message %T", msg)
+}
+
+type scramClient struct {
+	serverAuthMechanisms []string
+	password             string
+	clientNonce          []byte
+
+	// authMechanism is the selected SASL mechanism for the client. Must be
+	// either SCRAM-SHA-256 (default) or SCRAM-SHA-256-PLUS.
+	//
+	// Upgraded to SCRAM-SHA-256-PLUS during authentication when channel binding
+	// is not disabled, channel binding data is available (TLS connection with
+	// an obtainable server certificate hash) and the server advertises
+	// SCRAM-SHA-256-PLUS.
+	authMechanism string
+
+	// hasTLS indicates whether the connection is using TLS. This is
+	// needed because the GS2 header must distinguish between a client that
+	// supports channel binding but the server does not ("y,,") versus one
+	// that does not support it at all ("n,,").
+	hasTLS bool
+
+	// channelBindingData is the hash of the server's TLS certificate, computed
+	// per the tls-server-end-point channel binding type (RFC 5929). Used as
+	// the binding input in SCRAM-SHA-256-PLUS. nil when not in use.
+	channelBindingData []byte
+
+	clientFirstMessageBare []byte
+	clientGS2Header        []byte
+
+	serverFirstMessage   []byte
+	clientAndServerNonce []byte
+	salt                 []byte
+	iterations           int
+
+	saltedPassword []byte
+	authMessage    []byte
+}
+
+func newScramClient(serverAuthMechanisms []string, password string) (*scramClient, error) {
+	sc := &scramClient{
+		serverAuthMechanisms: serverAuthMechanisms,
+		authMechanism:        scramSHA256Name,
+	}
+
+	// Ensure the server supports SCRAM-SHA-256. SCRAM-SHA-256-PLUS is the
+	// channel binding variant and is only advertised when the server supports
+	// SSL. PostgreSQL always advertises the base SCRAM-SHA-256 mechanism
+	// regardless of SSL.
+	if !slices.Contains(sc.serverAuthMechanisms, scramSHA256Name) {
+		return nil, errors.New("server does not support SCRAM-SHA-256")
+	}
+
+	// precis.OpaqueString is equivalent to SASLprep for password.
+	var err error
+	sc.password, err = precis.OpaqueString.String(password)
+	if err != nil {
+		// PostgreSQL allows passwords invalid according to SCRAM / SASLprep.
+		sc.password = password
+	}
+
+	buf := make([]byte, clientNonceLen)
+	_, err = rand.Read(buf)
+	if err != nil {
+		return nil, err
+	}
+	sc.clientNonce = make([]byte, base64.RawStdEncoding.EncodedLen(len(buf)))
+	base64.RawStdEncoding.Encode(sc.clientNonce, buf)
+
+	return sc, nil
+}
+
+func (sc *scramClient) clientFirstMessage() []byte {
+	// The client-first-message is the GS2 header concatenated with the bare
+	// message (username + client nonce). The GS2 header communicates the
+	// client's channel binding capability to the server:
+	//
+	//   "n,,"                      - client is not using TLS (channel binding not possible)
+	//   "y,,"                      - client is using TLS but channel binding is not
+	//                                in use (e.g., server did not advertise SCRAM-SHA-256-PLUS
+	//                                or the server certificate hash was not obtainable)
+	//   "p=tls-server-end-point,," - channel binding is active via SCRAM-SHA-256-PLUS
+	//
+	// See:
+	//   https://www.rfc-editor.org/rfc/rfc5802#section-6
+	//   https://www.rfc-editor.org/rfc/rfc5929#section-4
+	//   https://www.postgresql.org/docs/current/sasl-authentication.html#SASL-SCRAM-SHA-256
+
+	sc.clientFirstMessageBare = fmt.Appendf(nil, "n=,r=%s", sc.clientNonce)
+
+	switch {
+	case sc.authMechanism == scramSHA256PlusName:
+		sc.clientGS2Header = []byte("p=tls-server-end-point,,")
+	case sc.hasTLS:
+		sc.clientGS2Header = []byte("y,,")
+	default:
+		sc.clientGS2Header = []byte("n,,")
+	}
+
+	return append(sc.clientGS2Header, sc.clientFirstMessageBare...)
+}
+
+func (sc *scramClient) recvServerFirstMessage(serverFirstMessage []byte) error {
+	sc.serverFirstMessage = serverFirstMessage
+	buf := serverFirstMessage
+	if !bytes.HasPrefix(buf, []byte("r=")) {
+		return errors.New("invalid SCRAM server-first-message received from server: did not include r=")
+	}
+	buf = buf[2:]
+
+	idx := bytes.IndexByte(buf, ',')
+	if idx == -1 {
+		return errors.New("invalid SCRAM server-first-message received from server: did not include s=")
+	}
+	sc.clientAndServerNonce = buf[:idx]
+	buf = buf[idx+1:]
+
+	if !bytes.HasPrefix(buf, []byte("s=")) {
+		return errors.New("invalid SCRAM server-first-message received from server: did not include s=")
+	}
+	buf = buf[2:]
+
+	idx = bytes.IndexByte(buf, ',')
+	if idx == -1 {
+		return errors.New("invalid SCRAM server-first-message received from server: did not include i=")
+	}
+	saltStr := buf[:idx]
+	buf = buf[idx+1:]
+
+	if !bytes.HasPrefix(buf, []byte("i=")) {
+		return errors.New("invalid SCRAM server-first-message received from server: did not include i=")
+	}
+	buf = buf[2:]
+	iterationsStr := buf
+
+	var err error
+	sc.salt, err = base64.StdEncoding.DecodeString(string(saltStr))
+	if err != nil {
+		return fmt.Errorf("invalid SCRAM salt received from server: %w", err)
+	}
+
+	sc.iterations, err = strconv.Atoi(string(iterationsStr))
+	if err != nil || sc.iterations <= 0 {
+		return fmt.Errorf("invalid SCRAM iteration count received from server: %w", err)
+	}
+	// Bound server-supplied iteration count to prevent a malicious server from forcing the client
+	// to spend unbounded CPU in PBKDF2. PostgreSQL's scram_iterations defaults to 4096; this ceiling
+	// is ~2500x that.
+	const maxScramIterations = 10_000_000
+	if sc.iterations > maxScramIterations {
+		return fmt.Errorf("SCRAM iteration count from server too high: %d (max %d)", sc.iterations, maxScramIterations)
+	}
+
+	if !bytes.HasPrefix(sc.clientAndServerNonce, sc.clientNonce) {
+		return errors.New("invalid SCRAM nonce: did not start with client nonce")
+	}
+
+	if len(sc.clientAndServerNonce) <= len(sc.clientNonce) {
+		return errors.New("invalid SCRAM nonce: did not include server nonce")
+	}
+
+	return nil
+}
+
+func (sc *scramClient) clientFinalMessage() string {
+	// The c= attribute carries the base64-encoded channel binding input.
+	//
+	// Without channel binding this is just the GS2 header alone ("biws" for
+	// "n,," or "eSws" for "y,,").
+	//
+	// With channel binding, this is the GS2 header with the channel binding data
+	// (certificate hash) appended.
+	channelBindInput := sc.clientGS2Header
+	if sc.authMechanism == scramSHA256PlusName {
+		channelBindInput = slices.Concat(sc.clientGS2Header, sc.channelBindingData)
+	}
+	channelBindingEncoded := base64.StdEncoding.EncodeToString(channelBindInput)
+	clientFinalMessageWithoutProof := fmt.Appendf(nil, "c=%s,r=%s", channelBindingEncoded, sc.clientAndServerNonce)
+
+	var err error
+	sc.saltedPassword, err = pbkdf2.Key(sha256.New, sc.password, sc.salt, sc.iterations, 32)
+	if err != nil {
+		panic(err) // This should never happen.
+	}
+	sc.authMessage = bytes.Join([][]byte{sc.clientFirstMessageBare, sc.serverFirstMessage, clientFinalMessageWithoutProof}, []byte(","))
+
+	clientProof := computeClientProof(sc.saltedPassword, sc.authMessage)
+
+	return fmt.Sprintf("%s,p=%s", clientFinalMessageWithoutProof, clientProof)
+}
+
+func (sc *scramClient) recvServerFinalMessage(serverFinalMessage []byte) error {
+	if !bytes.HasPrefix(serverFinalMessage, []byte("v=")) {
+		return errors.New("invalid SCRAM server-final-message received from server")
+	}
+
+	serverSignature := serverFinalMessage[2:]
+
+	if !hmac.Equal(serverSignature, computeServerSignature(sc.saltedPassword, sc.authMessage)) {
+		return errors.New("invalid SCRAM ServerSignature received from server")
+	}
+
+	return nil
+}
+
+func computeHMAC(key, msg []byte) []byte {
+	mac := hmac.New(sha256.New, key)
+	mac.Write(msg)
+	return mac.Sum(nil)
+}
+
+func computeClientProof(saltedPassword, authMessage []byte) []byte {
+	clientKey := computeHMAC(saltedPassword, []byte("Client Key"))
+	storedKey := sha256.Sum256(clientKey)
+	clientSignature := computeHMAC(storedKey[:], authMessage)
+
+	clientProof := make([]byte, len(clientSignature))
+	for i := range clientSignature {
+		clientProof[i] = clientKey[i] ^ clientSignature[i]
+	}
+
+	buf := make([]byte, base64.StdEncoding.EncodedLen(len(clientProof)))
+	base64.StdEncoding.Encode(buf, clientProof)
+	return buf
+}
+
+func computeServerSignature(saltedPassword, authMessage []byte) []byte {
+	serverKey := computeHMAC(saltedPassword, []byte("Server Key"))
+	serverSignature := computeHMAC(serverKey, authMessage)
+	buf := make([]byte, base64.StdEncoding.EncodedLen(len(serverSignature)))
+	base64.StdEncoding.Encode(buf, serverSignature)
+	return buf
+}
+
+// Get the server certificate hash for SCRAM channel binding type
+// tls-server-end-point.
+func getTLSCertificateHash(conn *tls.Conn) ([]byte, error) {
+	state := conn.ConnectionState()
+	if len(state.PeerCertificates) == 0 {
+		return nil, errors.New("no peer certificates for channel binding")
+	}
+
+	cert := state.PeerCertificates[0]
+
+	// Per RFC 5929 section 4.1: If the certificate's signatureAlgorithm uses
+	// MD5 or SHA-1, use SHA-256. Otherwise use the hash from the signature
+	// algorithm.
+	//
+	// See: https://www.rfc-editor.org/rfc/rfc5929.html#section-4.1
+	var h hash.Hash
+	switch cert.SignatureAlgorithm {
+	case x509.MD5WithRSA, x509.SHA1WithRSA, x509.ECDSAWithSHA1:
+		h = sha256.New()
+	case x509.SHA256WithRSA, x509.SHA256WithRSAPSS, x509.ECDSAWithSHA256:
+		h = sha256.New()
+	case x509.SHA384WithRSA, x509.SHA384WithRSAPSS, x509.ECDSAWithSHA384:
+		h = sha512.New384()
+	case x509.SHA512WithRSA, x509.SHA512WithRSAPSS, x509.ECDSAWithSHA512:
+		h = sha512.New()
+	default:
+		return nil, fmt.Errorf("tls-server-end-point channel binding is undefined for certificate signature algorithm %v", cert.SignatureAlgorithm)
+	}
+
+	h.Write(cert.Raw)
+	return h.Sum(nil), nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/config.go b/vendor/github.com/jackc/pgx/v5/pgconn/config.go
new file mode 100644
index 000000000..eec7de639
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/config.go
@@ -0,0 +1,1088 @@
+package pgconn
+
+import (
+	"context"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"maps"
+	"math"
+	"net"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/jackc/pgpassfile"
+	"github.com/jackc/pgservicefile"
+	"github.com/jackc/pgx/v5/pgconn/ctxwatch"
+	"github.com/jackc/pgx/v5/pgproto3"
+)
+
+type (
+	AfterConnectFunc    func(ctx context.Context, pgconn *PgConn) error
+	ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error
+	GetSSLPasswordFunc  func(ctx context.Context) string
+)
+
+// Config is the settings used to establish a connection to a PostgreSQL server. It must be created by [ParseConfig]. A
+// manually initialized Config will cause ConnectConfig to panic.
+type Config struct {
+	Host           string // host (e.g. localhost) or absolute path to unix domain socket directory (e.g. /private/tmp)
+	Port           uint16
+	Database       string
+	User           string
+	Password       string
+	TLSConfig      *tls.Config // nil disables TLS
+	ConnectTimeout time.Duration
+	DialFunc       DialFunc   // e.g. net.Dialer.DialContext
+	LookupFunc     LookupFunc // e.g. net.Resolver.LookupHost
+	BuildFrontend  BuildFrontendFunc
+
+	// BuildContextWatcherHandler is called to create a ContextWatcherHandler for a connection. The handler is called
+	// when a context passed to a PgConn method is canceled.
+	BuildContextWatcherHandler func(*PgConn) ctxwatch.Handler
+
+	RuntimeParams map[string]string // Run-time parameters to set on connection as session default values (e.g. search_path or application_name)
+
+	KerberosSrvName string
+	KerberosSpn     string
+	Fallbacks       []*FallbackConfig
+
+	SSLNegotiation string // sslnegotiation=postgres or sslnegotiation=direct
+
+	// AfterNetConnect is called after the network connection, including TLS if applicable, is established but before any
+	// PostgreSQL protocol communication. It takes the established net.Conn and returns a net.Conn that will be used in
+	// its place. It can be used to wrap the net.Conn (e.g. for logging, diagnostics, or testing). Its functionality has
+	// some overlap with DialFunc. However, DialFunc takes place before TLS is established and cannot be used to control
+	// the final net.Conn used for PostgreSQL protocol communication while AfterNetConnect can.
+	AfterNetConnect func(ctx context.Context, config *Config, conn net.Conn) (net.Conn, error)
+
+	// ValidateConnect is called during a connection attempt after a successful authentication with the PostgreSQL server.
+	// It can be used to validate that the server is acceptable. If this returns an error the connection is closed and the next
+	// fallback config is tried. This allows implementing high availability behavior such as libpq does with target_session_attrs.
+	ValidateConnect ValidateConnectFunc
+
+	// AfterConnect is called after ValidateConnect. It can be used to set up the connection (e.g. Set session variables
+	// or prepare statements). If this returns an error the connection attempt fails.
+	AfterConnect AfterConnectFunc
+
+	// OnNotice is a callback function called when a notice response is received.
+	OnNotice NoticeHandler
+
+	// OnNotification is a callback function called when a notification from the LISTEN/NOTIFY system is received.
+	OnNotification NotificationHandler
+
+	// OnPgError is a callback function called when a Postgres error is received by the server. The default handler will close
+	// the connection on any FATAL errors. If you override this handler you should call the previously set handler or ensure
+	// that you close on FATAL errors by returning false.
+	OnPgError PgErrorHandler
+
+	// OAuthTokenProvider is a function that returns an OAuth token for authentication. If set, it will be used for
+	// OAUTHBEARER SASL authentication when the server requests it.
+	OAuthTokenProvider func(context.Context) (string, error)
+
+	// MinProtocolVersion is the minimum acceptable PostgreSQL protocol version.
+	// If the server does not support at least this version, the connection will fail.
+	// Valid values: "3.0", "3.2", "latest". Defaults to "3.0".
+	MinProtocolVersion string
+
+	// MaxProtocolVersion is the maximum PostgreSQL protocol version to request from the server.
+	// Valid values: "3.0", "3.2", "latest". Defaults to "3.0" for compatibility.
+	MaxProtocolVersion string
+
+	// ChannelBinding is the channel_binding parameter for SCRAM-SHA-256-PLUS authentication.
+	// Valid values: "disable", "prefer", "require". Defaults to "prefer".
+	ChannelBinding string
+
+	// RequireAuth restricts which authentication methods the client will accept from the server,
+	// matching libpq's require_auth parameter. It is a comma-separated list of method names
+	// (password, md5, gss, sspi, scram-sha-256, oauth, none). A leading "!" on every entry negates
+	// the list (forbid these methods, allow all others). Empty (the default) means all methods are
+	// accepted.
+	RequireAuth string
+
+	createdByParseConfig bool // Used to enforce created by ParseConfig rule.
+}
+
+// connStringKeyAliases maps libpq parameter keywords to the canonical key names this package
+// uses internally in the parsed-settings map. Most keywords are already canonical; this map
+// holds only those whose pgx-internal name differs from the libpq spelling.
+var connStringKeyAliases = map[string]string{
+	"dbname": "database",
+}
+
+// canonicalConnStringKey returns the canonical settings-map key for a libpq parameter keyword.
+func canonicalConnStringKey(k string) string {
+	if c, ok := connStringKeyAliases[k]; ok {
+		return c
+	}
+	return k
+}
+
+// ParseConfigOptions contains options that control how a config is built such as GetSSLPassword.
+type ParseConfigOptions struct {
+	// GetSSLPassword gets the password to decrypt a SSL client certificate. This is analogous to the libpq function
+	// PQsetSSLKeyPassHook_OpenSSL.
+	GetSSLPassword GetSSLPasswordFunc
+
+	// ConnStringAllowedKeys, if non-nil, restricts which parameter keys may appear in connString
+	// itself. Any other key (whether connString is in keyword/value or URL form) causes
+	// ParseConfigWithOptions to return an error before any filesystem access or network
+	// resolution is attempted. Environment variables (PGHOST, PGSERVICEFILE, ...) and built-in
+	// defaults are not checked: only keys that originate from the connString argument.
+	//
+	// Keys may be given in either their libpq spelling ("dbname") or pgx-internal spelling
+	// ("database"); both are accepted.
+	//
+	// A nil slice (the default) applies no restriction and matches libpq behaviour. An empty
+	// non-nil slice rejects every key, i.e. connString must be empty.
+	//
+	// Use this when any part of connString is built from input the application does not fully
+	// control (tenant configuration, RPC parameters, admin UI fields). List only the keys that
+	// input is expected to supply. This fails closed: a future libpq parameter that pgconn learns
+	// to parse will be rejected unless the application has explicitly allowed it, rather than
+	// silently passing through.
+	ConnStringAllowedKeys []string
+}
+
+// Copy returns a deep copy of the config that is safe to use and modify.
+// The only exception is the TLSConfig field:
+// according to the tls.Config docs it must not be modified after creation.
+func (c *Config) Copy() *Config {
+	newConf := new(Config)
+	*newConf = *c
+	if newConf.TLSConfig != nil {
+		newConf.TLSConfig = c.TLSConfig.Clone()
+	}
+	if newConf.RuntimeParams != nil {
+		newConf.RuntimeParams = make(map[string]string, len(c.RuntimeParams))
+		maps.Copy(newConf.RuntimeParams, c.RuntimeParams)
+	}
+	if newConf.Fallbacks != nil {
+		newConf.Fallbacks = make([]*FallbackConfig, len(c.Fallbacks))
+		for i, fallback := range c.Fallbacks {
+			newFallback := new(FallbackConfig)
+			*newFallback = *fallback
+			if newFallback.TLSConfig != nil {
+				newFallback.TLSConfig = fallback.TLSConfig.Clone()
+			}
+			newConf.Fallbacks[i] = newFallback
+		}
+	}
+	return newConf
+}
+
+// FallbackConfig is additional settings to attempt a connection with when the primary Config fails to establish a
+// network connection. It is used for TLS fallback such as sslmode=prefer and high availability (HA) connections.
+type FallbackConfig struct {
+	Host      string // host (e.g. localhost) or path to unix domain socket directory (e.g. /private/tmp)
+	Port      uint16
+	TLSConfig *tls.Config // nil disables TLS
+}
+
+// connectOneConfig is the configuration for a single attempt to connect to a single host.
+type connectOneConfig struct {
+	network          string
+	address          string
+	originalHostname string      // original hostname before resolving
+	tlsConfig        *tls.Config // nil disables TLS
+}
+
+// isAbsolutePath checks if the provided value is an absolute path either
+// beginning with a forward slash (as on Linux-based systems) or with a capital
+// letter A-Z followed by a colon and a backslash, e.g., "C:\", (as on Windows).
+func isAbsolutePath(path string) bool {
+	isWindowsPath := func(p string) bool {
+		if len(p) < 3 {
+			return false
+		}
+		drive := p[0]
+		colon := p[1]
+		backslash := p[2]
+		if drive >= 'A' && drive <= 'Z' && colon == ':' && backslash == '\\' {
+			return true
+		}
+		return false
+	}
+	return strings.HasPrefix(path, "/") || isWindowsPath(path)
+}
+
+// NetworkAddress converts a PostgreSQL host and port into network and address suitable for use with
+// net.Dial.
+func NetworkAddress(host string, port uint16) (network, address string) {
+	if isAbsolutePath(host) {
+		network = "unix"
+		address = filepath.Join(host, ".s.PGSQL.") + strconv.FormatInt(int64(port), 10)
+	} else {
+		network = "tcp"
+		address = net.JoinHostPort(host, strconv.Itoa(int(port)))
+	}
+	return network, address
+}
+
+// ParseConfig builds a *Config from connString with similar behavior to the PostgreSQL standard C library libpq. It
+// uses the same defaults as libpq (e.g. port=5432) and understands most PG* environment variables. ParseConfig closely
+// matches the parsing behavior of libpq. connString may either be in URL format or keyword = value format. See
+// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING for details. connString also may be empty
+// to only read from the environment. If a password is not supplied it will attempt to read the .pgpass file.
+//
+//	# Example Keyword/Value
+//	user=jack password=secret host=pg.example.com port=5432 dbname=mydb sslmode=verify-ca
+//
+//	# Example URL
+//	postgres://jack:secret@pg.example.com:5432/mydb?sslmode=verify-ca
+//
+// The returned *Config may be modified. However, it is strongly recommended that any configuration that can be done
+// through the connection string be done there. In particular the fields Host, Port, TLSConfig, and Fallbacks can be
+// interdependent (e.g. TLSConfig needs knowledge of the host to validate the server certificate). These fields should
+// not be modified individually. They should all be modified or all left unchanged.
+//
+// ParseConfig supports specifying multiple hosts in similar manner to libpq. Host and port may include comma separated
+// values that will be tried in order. This can be used as part of a high availability system. See
+// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS for more information.
+//
+//	# Example URL
+//	postgres://jack:secret@foo.example.com:5432,bar.example.com:5432/mydb
+//
+// ParseConfig currently recognizes the following environment variable and their parameter key word equivalents passed
+// via database URL or keyword/value:
+//
+//	PGHOST
+//	PGPORT
+//	PGDATABASE
+//	PGUSER
+//	PGPASSWORD
+//	PGPASSFILE
+//	PGSERVICE
+//	PGSERVICEFILE
+//	PGSSLMODE
+//	PGSSLCERT
+//	PGSSLKEY
+//	PGSSLROOTCERT
+//	PGSSLPASSWORD
+//	PGOPTIONS
+//	PGAPPNAME
+//	PGCONNECT_TIMEOUT
+//	PGTARGETSESSIONATTRS
+//	PGTZ
+//	PGMINPROTOCOLVERSION
+//	PGMAXPROTOCOLVERSION
+//
+// See http://www.postgresql.org/docs/current/static/libpq-envars.html for details on the meaning of environment variables.
+//
+// See https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS for parameter key word names. They are
+// usually but not always the environment variable name downcased and without the "PG" prefix.
+//
+// Important Security Notes:
+//
+// ParseConfig tries to match libpq behavior with regard to PGSSLMODE. This includes defaulting to "prefer" behavior if
+// not set.
+//
+// See http://www.postgresql.org/docs/current/static/libpq-ssl.html#LIBPQ-SSL-PROTECTION for details on what level of
+// security each sslmode provides.
+//
+// The sslmode "prefer" (the default), sslmode "allow", and multiple hosts are implemented via the Fallbacks field of
+// the Config struct. If TLSConfig is manually changed it will not affect the fallbacks. For example, in the case of
+// sslmode "prefer" this means it will first try the main Config settings which use TLS, then it will try the fallback
+// which does not use TLS. This can lead to an unexpected unencrypted connection if the main TLS config is manually
+// changed later but the unencrypted fallback is present. Ensure there are no stale fallbacks when manually setting
+// TLSConfig.
+//
+// Several connection parameters cause ParseConfig to read files from the local filesystem: servicefile, passfile,
+// sslkey, sslcert, and sslrootcert. Applications that build connection strings from untrusted input must not allow
+// these keys to be set by that input. In particular, servicefile (which pgconn accepts in the connection string;
+// libpq does not) is read as an INI file whose entries override other connection settings including host, port, and
+// sslmode, so an attacker who controls servicefile and service can redirect the connection. If any portion of the
+// connection string is externally supplied, use ParseConfigWithOptions and set ParseConfigOptions.ConnStringAllowedKeys
+// to an allow-list of the keys that input is expected to supply; any other key in the connection string is then
+// rejected before any filesystem access occurs.
+//
+// Other known differences with libpq:
+//
+// When multiple hosts are specified, libpq allows them to have different passwords set via the .pgpass file. pgconn
+// does not.
+//
+// In addition, ParseConfig accepts the following options:
+//
+//   - servicefile.
+//     libpq only reads servicefile from the PGSERVICEFILE environment variable. ParseConfig accepts servicefile as a
+//     part of the connection string.
+func ParseConfig(connString string) (*Config, error) {
+	var parseConfigOptions ParseConfigOptions
+	return ParseConfigWithOptions(connString, parseConfigOptions)
+}
+
+// ParseConfigWithOptions builds a *Config from connString and options with similar behavior to the PostgreSQL standard
+// C library libpq. options contains settings that cannot be specified in a connString such as providing a function to
+// get the SSL password.
+func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*Config, error) {
+	defaultSettings := defaultSettings()
+	envSettings := parseEnvSettings()
+
+	connStringSettings := make(map[string]string)
+	if connString != "" {
+		var err error
+		// connString may be a database URL or in PostgreSQL keyword/value format
+		if strings.HasPrefix(connString, "postgres://") || strings.HasPrefix(connString, "postgresql://") {
+			connStringSettings, err = parseURLSettings(connString)
+			if err != nil {
+				return nil, &ParseConfigError{ConnString: connString, msg: "failed to parse as URL", err: err}
+			}
+		} else {
+			connStringSettings, err = parseKeywordValueSettings(connString)
+			if err != nil {
+				return nil, &ParseConfigError{ConnString: connString, msg: "failed to parse as keyword/value", err: err}
+			}
+		}
+	}
+
+	if options.ConnStringAllowedKeys != nil {
+		allowed := make(map[string]struct{}, len(options.ConnStringAllowedKeys))
+		for _, k := range options.ConnStringAllowedKeys {
+			allowed[canonicalConnStringKey(k)] = struct{}{}
+		}
+		for k := range connStringSettings {
+			if _, ok := allowed[k]; !ok {
+				return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("connection string key %q is not in ConnStringAllowedKeys", k)}
+			}
+		}
+	}
+
+	settings := mergeSettings(defaultSettings, envSettings, connStringSettings)
+	if service, present := settings["service"]; present {
+		serviceSettings, err := parseServiceSettings(settings["servicefile"], service)
+		if err != nil {
+			return nil, &ParseConfigError{ConnString: connString, msg: "failed to read service", err: err}
+		}
+
+		settings = mergeSettings(defaultSettings, envSettings, serviceSettings, connStringSettings)
+	}
+
+	config := &Config{
+		createdByParseConfig: true,
+		Database:             settings["database"],
+		User:                 settings["user"],
+		Password:             settings["password"],
+		RuntimeParams:        make(map[string]string),
+		BuildFrontend:        pgproto3.NewFrontend,
+		BuildContextWatcherHandler: func(pgConn *PgConn) ctxwatch.Handler {
+			return &DeadlineContextWatcherHandler{Conn: pgConn.conn}
+		},
+		OnPgError: func(_ *PgConn, pgErr *PgError) bool {
+			// we want to automatically close any fatal errors
+			if strings.EqualFold(pgErr.Severity, "FATAL") {
+				return false
+			}
+			return true
+		},
+	}
+
+	if connectTimeoutSetting, present := settings["connect_timeout"]; present {
+		connectTimeout, err := parseConnectTimeoutSetting(connectTimeoutSetting)
+		if err != nil {
+			return nil, &ParseConfigError{ConnString: connString, msg: "invalid connect_timeout", err: err}
+		}
+		config.ConnectTimeout = connectTimeout
+		config.DialFunc = makeConnectTimeoutDialFunc(connectTimeout)
+	} else {
+		defaultDialer := makeDefaultDialer()
+		config.DialFunc = defaultDialer.DialContext
+	}
+
+	config.LookupFunc = makeDefaultResolver().LookupHost
+
+	notRuntimeParams := map[string]struct{}{
+		"host":                 {},
+		"port":                 {},
+		"database":             {},
+		"user":                 {},
+		"password":             {},
+		"passfile":             {},
+		"connect_timeout":      {},
+		"sslmode":              {},
+		"sslkey":               {},
+		"sslcert":              {},
+		"sslrootcert":          {},
+		"sslnegotiation":       {},
+		"sslpassword":          {},
+		"sslsni":               {},
+		"krbspn":               {},
+		"krbsrvname":           {},
+		"target_session_attrs": {},
+		"service":              {},
+		"servicefile":          {},
+		"min_protocol_version": {},
+		"max_protocol_version": {},
+		"channel_binding":      {},
+		"require_auth":         {},
+	}
+
+	// Adding kerberos configuration
+	if _, present := settings["krbsrvname"]; present {
+		config.KerberosSrvName = settings["krbsrvname"]
+	}
+	if _, present := settings["krbspn"]; present {
+		config.KerberosSpn = settings["krbspn"]
+	}
+
+	for k, v := range settings {
+		if _, present := notRuntimeParams[k]; present {
+			continue
+		}
+		config.RuntimeParams[k] = v
+	}
+
+	fallbacks := []*FallbackConfig{}
+
+	hosts := strings.Split(settings["host"], ",")
+	ports := strings.Split(settings["port"], ",")
+
+	for i, host := range hosts {
+		var portStr string
+		if i < len(ports) {
+			portStr = ports[i]
+		} else {
+			portStr = ports[0]
+		}
+
+		port, err := parsePort(portStr)
+		if err != nil {
+			return nil, &ParseConfigError{ConnString: connString, msg: "invalid port", err: err}
+		}
+
+		var tlsConfigs []*tls.Config
+
+		// Ignore TLS settings if Unix domain socket like libpq
+		if network, _ := NetworkAddress(host, port); network == "unix" {
+			tlsConfigs = append(tlsConfigs, nil)
+		} else {
+			var err error
+			tlsConfigs, err = configTLS(settings, host, options)
+			if err != nil {
+				return nil, &ParseConfigError{ConnString: connString, msg: "failed to configure TLS", err: err}
+			}
+		}
+
+		for _, tlsConfig := range tlsConfigs {
+			fallbacks = append(fallbacks, &FallbackConfig{
+				Host:      host,
+				Port:      port,
+				TLSConfig: tlsConfig,
+			})
+		}
+	}
+
+	config.Host = fallbacks[0].Host
+	config.Port = fallbacks[0].Port
+	config.TLSConfig = fallbacks[0].TLSConfig
+	config.Fallbacks = fallbacks[1:]
+	config.SSLNegotiation = settings["sslnegotiation"]
+
+	passfile, err := pgpassfile.ReadPassfile(settings["passfile"])
+	if err == nil {
+		if config.Password == "" {
+			host := config.Host
+			if network, _ := NetworkAddress(config.Host, config.Port); network == "unix" {
+				host = "localhost"
+			}
+
+			config.Password = passfile.FindPassword(host, strconv.Itoa(int(config.Port)), config.Database, config.User)
+		}
+	}
+
+	switch tsa := settings["target_session_attrs"]; tsa {
+	case "read-write":
+		config.ValidateConnect = ValidateConnectTargetSessionAttrsReadWrite
+	case "read-only":
+		config.ValidateConnect = ValidateConnectTargetSessionAttrsReadOnly
+	case "primary":
+		config.ValidateConnect = ValidateConnectTargetSessionAttrsPrimary
+	case "standby":
+		config.ValidateConnect = ValidateConnectTargetSessionAttrsStandby
+	case "prefer-standby":
+		config.ValidateConnect = ValidateConnectTargetSessionAttrsPreferStandby
+	case "any":
+		// do nothing
+	default:
+		return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("unknown target_session_attrs value: %v", tsa)}
+	}
+
+	minProto, err := parseProtocolVersion(settings["min_protocol_version"])
+	if err != nil {
+		return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("invalid min_protocol_version: %q", settings["min_protocol_version"]), err: err}
+	}
+	maxProto, err := parseProtocolVersion(settings["max_protocol_version"])
+	if err != nil {
+		return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("invalid max_protocol_version: %q", settings["max_protocol_version"]), err: err}
+	}
+
+	config.MinProtocolVersion = settings["min_protocol_version"]
+	config.MaxProtocolVersion = settings["max_protocol_version"]
+
+	if config.MinProtocolVersion == "" {
+		config.MinProtocolVersion = "3.0"
+	}
+
+	// When max_protocol_version is not explicitly set, default based on
+	// min_protocol_version. This matches libpq behavior: if min > 3.0,
+	// default max to latest; otherwise default to 3.0 for compatibility
+	// with older servers/poolers that don't support NegotiateProtocolVersion.
+	if config.MaxProtocolVersion == "" {
+		if minProto > pgproto3.ProtocolVersion30 {
+			config.MaxProtocolVersion = "latest"
+		} else {
+			config.MaxProtocolVersion = "3.0"
+		}
+	}
+
+	// Only error when max_protocol_version was explicitly set and conflicts
+	// with min_protocol_version. When max_protocol_version is not explicitly
+	// set, the auto-raise logic above already ensures a valid default.
+	if minProto > maxProto && settings["max_protocol_version"] != "" {
+		return nil, &ParseConfigError{ConnString: connString, msg: "min_protocol_version cannot be greater than max_protocol_version"}
+	}
+
+	switch channelBinding := settings["channel_binding"]; channelBinding {
+	case "", "prefer":
+		config.ChannelBinding = "prefer"
+	case "disable":
+		config.ChannelBinding = "disable"
+	case "require":
+		config.ChannelBinding = "require"
+	default:
+		return nil, &ParseConfigError{ConnString: connString, msg: fmt.Sprintf("unknown channel_binding value: %v", channelBinding)}
+	}
+
+	config.RequireAuth = settings["require_auth"]
+	if _, err := parseRequireAuth(config.RequireAuth); err != nil {
+		return nil, &ParseConfigError{ConnString: connString, msg: "invalid require_auth", err: err}
+	}
+
+	return config, nil
+}
+
+func mergeSettings(settingSets ...map[string]string) map[string]string {
+	settings := make(map[string]string)
+
+	for _, s2 := range settingSets {
+		maps.Copy(settings, s2)
+	}
+
+	return settings
+}
+
+func parseEnvSettings() map[string]string {
+	settings := make(map[string]string)
+
+	nameMap := map[string]string{
+		"PGHOST":               "host",
+		"PGPORT":               "port",
+		"PGDATABASE":           "database",
+		"PGUSER":               "user",
+		"PGPASSWORD":           "password",
+		"PGPASSFILE":           "passfile",
+		"PGAPPNAME":            "application_name",
+		"PGCONNECT_TIMEOUT":    "connect_timeout",
+		"PGSSLMODE":            "sslmode",
+		"PGSSLKEY":             "sslkey",
+		"PGSSLCERT":            "sslcert",
+		"PGSSLSNI":             "sslsni",
+		"PGSSLROOTCERT":        "sslrootcert",
+		"PGSSLPASSWORD":        "sslpassword",
+		"PGSSLNEGOTIATION":     "sslnegotiation",
+		"PGTARGETSESSIONATTRS": "target_session_attrs",
+		"PGSERVICE":            "service",
+		"PGSERVICEFILE":        "servicefile",
+		"PGTZ":                 "timezone",
+		"PGOPTIONS":            "options",
+		"PGMINPROTOCOLVERSION": "min_protocol_version",
+		"PGMAXPROTOCOLVERSION": "max_protocol_version",
+		"PGCHANNELBINDING":     "channel_binding",
+		"PGREQUIREAUTH":        "require_auth",
+	}
+
+	for envname, realname := range nameMap {
+		value := os.Getenv(envname)
+		if value != "" {
+			settings[realname] = value
+		}
+	}
+
+	return settings
+}
+
+func parseURLSettings(connString string) (map[string]string, error) {
+	settings := make(map[string]string)
+
+	parsedURL, err := url.Parse(connString)
+	if err != nil {
+		if urlErr := new(url.Error); errors.As(err, &urlErr) {
+			return nil, urlErr.Err
+		}
+		return nil, err
+	}
+
+	if parsedURL.User != nil {
+		if u := parsedURL.User.Username(); u != "" {
+			settings["user"] = u
+		}
+		if password, present := parsedURL.User.Password(); present {
+			settings["password"] = password
+		}
+	}
+
+	// Handle multiple host:port's in url.Host by splitting them into host,host,host and port,port,port.
+	var hosts []string
+	var ports []string
+	for host := range strings.SplitSeq(parsedURL.Host, ",") {
+		if host == "" {
+			continue
+		}
+		if isIPOnly(host) {
+			hosts = append(hosts, strings.Trim(host, "[]"))
+			continue
+		}
+		h, p, err := net.SplitHostPort(host)
+		if err != nil {
+			return nil, fmt.Errorf("failed to split host:port in '%s', err: %w", host, err)
+		}
+		if h != "" {
+			hosts = append(hosts, h)
+		}
+		if p != "" {
+			ports = append(ports, p)
+		}
+	}
+	if len(hosts) > 0 {
+		settings["host"] = strings.Join(hosts, ",")
+	}
+	if len(ports) > 0 {
+		settings["port"] = strings.Join(ports, ",")
+	}
+
+	database := strings.TrimLeft(parsedURL.Path, "/")
+	if database != "" {
+		settings["database"] = database
+	}
+
+	for k, v := range parsedURL.Query() {
+		settings[canonicalConnStringKey(k)] = v[0]
+	}
+
+	return settings, nil
+}
+
+func isIPOnly(host string) bool {
+	return net.ParseIP(strings.Trim(host, "[]")) != nil || !strings.Contains(host, ":")
+}
+
+var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
+
+func parseKeywordValueSettings(s string) (map[string]string, error) {
+	settings := make(map[string]string)
+
+	// Trim any leading whitespace so that the loop exits cleanly when only
+	// spaces remain (e.g. trailing spaces after the last value).
+	s = strings.TrimLeft(s, " \t\n\r\v\f")
+	for len(s) > 0 {
+		var key, val string
+		eqIdx := strings.IndexRune(s, '=')
+		if eqIdx < 0 {
+			return nil, errors.New("invalid keyword/value")
+		}
+
+		key = strings.Trim(s[:eqIdx], " \t\n\r\v\f")
+		s = strings.TrimLeft(s[eqIdx+1:], " \t\n\r\v\f")
+		switch {
+		case len(s) == 0:
+		case s[0] != '\'':
+			end := 0
+			for ; end < len(s); end++ {
+				if asciiSpace[s[end]] == 1 {
+					break
+				}
+				if s[end] == '\\' {
+					end++
+					if end == len(s) {
+						return nil, errors.New("invalid backslash")
+					}
+				}
+			}
+			val = strings.ReplaceAll(strings.ReplaceAll(s[:end], "\\\\", "\\"), "\\'", "'")
+			// Consume the value and trim any subsequent whitespace so that
+			// multiple trailing spaces don't cause a spurious parse failure.
+			s = strings.TrimLeft(s[end:], " \t\n\r\v\f")
+		default: // quoted string
+			s = s[1:]
+			end := 0
+			for ; end < len(s); end++ {
+				if s[end] == '\'' {
+					break
+				}
+				if s[end] == '\\' {
+					end++
+				}
+			}
+			if end == len(s) {
+				return nil, errors.New("unterminated quoted string in connection info string")
+			}
+			val = strings.ReplaceAll(strings.ReplaceAll(s[:end], "\\\\", "\\"), "\\'", "'")
+			// Consume the closing quote and any subsequent whitespace.
+			s = strings.TrimLeft(s[end+1:], " \t\n\r\v\f")
+		}
+
+		key = canonicalConnStringKey(key)
+
+		if key == "" {
+			return nil, errors.New("invalid keyword/value")
+		}
+
+		if key == "user" && val == "" {
+			continue
+		}
+		settings[key] = val
+	}
+
+	return settings, nil
+}
+
+func parseServiceSettings(servicefilePath, serviceName string) (map[string]string, error) {
+	servicefile, err := pgservicefile.ReadServicefile(servicefilePath)
+	if err != nil {
+		return nil, fmt.Errorf("failed to read service file: %v", servicefilePath)
+	}
+
+	service, err := servicefile.GetService(serviceName)
+	if err != nil {
+		return nil, fmt.Errorf("unable to find service: %v", serviceName)
+	}
+
+	settings := make(map[string]string, len(service.Settings))
+	for k, v := range service.Settings {
+		settings[canonicalConnStringKey(k)] = v
+	}
+
+	return settings, nil
+}
+
+// configTLS uses libpq's TLS parameters to construct  []*tls.Config. It is
+// necessary to allow returning multiple TLS configs as sslmode "allow" and
+// "prefer" allow fallback.
+func configTLS(settings map[string]string, thisHost string, parseConfigOptions ParseConfigOptions) ([]*tls.Config, error) {
+	host := thisHost
+	sslmode := settings["sslmode"]
+	sslrootcert := settings["sslrootcert"]
+	sslcert := settings["sslcert"]
+	sslkey := settings["sslkey"]
+	sslpassword := settings["sslpassword"]
+	sslsni := settings["sslsni"]
+	sslnegotiation := settings["sslnegotiation"]
+
+	// Match libpq default behavior
+	if sslmode == "" {
+		sslmode = "prefer"
+	}
+	if sslsni == "" {
+		sslsni = "1"
+	}
+
+	tlsConfig := &tls.Config{}
+
+	if sslnegotiation == "direct" {
+		tlsConfig.NextProtos = []string{"postgresql"}
+		if sslmode == "prefer" {
+			sslmode = "require"
+		}
+	}
+
+	if sslrootcert != "" {
+		var caCertPool *x509.CertPool
+
+		if sslrootcert == "system" {
+			var err error
+
+			caCertPool, err = x509.SystemCertPool()
+			if err != nil {
+				return nil, fmt.Errorf("unable to load system certificate pool: %w", err)
+			}
+
+			sslmode = "verify-full"
+		} else {
+			caCertPool = x509.NewCertPool()
+
+			caPath := sslrootcert
+			caCert, err := os.ReadFile(caPath)
+			if err != nil {
+				return nil, fmt.Errorf("unable to read CA file: %w", err)
+			}
+
+			if !caCertPool.AppendCertsFromPEM(caCert) {
+				return nil, errors.New("unable to add CA to cert pool")
+			}
+		}
+
+		tlsConfig.RootCAs = caCertPool
+		tlsConfig.ClientCAs = caCertPool
+	}
+
+	switch sslmode {
+	case "disable":
+		return []*tls.Config{nil}, nil
+	case "allow", "prefer":
+		tlsConfig.InsecureSkipVerify = true
+	case "require":
+		// According to PostgreSQL documentation, if a root CA file exists,
+		// the behavior of sslmode=require should be the same as that of verify-ca
+		//
+		// See https://www.postgresql.org/docs/current/libpq-ssl.html
+		if sslrootcert != "" {
+			goto nextCase
+		}
+		tlsConfig.InsecureSkipVerify = true
+		break
+	nextCase:
+		fallthrough
+	case "verify-ca":
+		// Don't perform the default certificate verification because it
+		// will verify the hostname. Instead, verify the server's
+		// certificate chain ourselves in VerifyPeerCertificate and
+		// ignore the server name. This emulates libpq's verify-ca
+		// behavior.
+		//
+		// See https://github.com/golang/go/issues/21971#issuecomment-332693931
+		// and https://pkg.go.dev/crypto/tls?tab=doc#example-Config-VerifyPeerCertificate
+		// for more info.
+		tlsConfig.InsecureSkipVerify = true
+		tlsConfig.VerifyPeerCertificate = func(certificates [][]byte, _ [][]*x509.Certificate) error {
+			certs := make([]*x509.Certificate, len(certificates))
+			for i, asn1Data := range certificates {
+				cert, err := x509.ParseCertificate(asn1Data)
+				if err != nil {
+					return errors.New("failed to parse certificate from server: " + err.Error())
+				}
+				certs[i] = cert
+			}
+
+			// Leave DNSName empty to skip hostname verification.
+			opts := x509.VerifyOptions{
+				Roots:         tlsConfig.RootCAs,
+				Intermediates: x509.NewCertPool(),
+			}
+			// Skip the first cert because it's the leaf. All others
+			// are intermediates.
+			for _, cert := range certs[1:] {
+				opts.Intermediates.AddCert(cert)
+			}
+			_, err := certs[0].Verify(opts)
+			return err
+		}
+	case "verify-full":
+		tlsConfig.ServerName = host
+	default:
+		return nil, errors.New("sslmode is invalid")
+	}
+
+	if (sslcert != "" && sslkey == "") || (sslcert == "" && sslkey != "") {
+		return nil, errors.New(`both "sslcert" and "sslkey" are required`)
+	}
+
+	if sslcert != "" && sslkey != "" {
+		buf, err := os.ReadFile(sslkey)
+		if err != nil {
+			return nil, fmt.Errorf("unable to read sslkey: %w", err)
+		}
+		block, _ := pem.Decode(buf)
+		if block == nil {
+			return nil, errors.New("failed to decode sslkey")
+		}
+		var pemKey []byte
+		var decryptedKey []byte
+		var decryptedError error
+		// If PEM is encrypted, attempt to decrypt using pass phrase
+		if x509.IsEncryptedPEMBlock(block) {
+			// Attempt decryption with pass phrase
+			// NOTE: only supports RSA (PKCS#1)
+			if sslpassword != "" {
+				decryptedKey, decryptedError = x509.DecryptPEMBlock(block, []byte(sslpassword)) //nolint:ineffassign
+			}
+			// if sslpassword not provided or has decryption error when use it
+			// try to find sslpassword with callback function
+			if sslpassword == "" || decryptedError != nil {
+				if parseConfigOptions.GetSSLPassword != nil {
+					sslpassword = parseConfigOptions.GetSSLPassword(context.Background())
+				}
+				if sslpassword == "" {
+					return nil, fmt.Errorf("unable to find sslpassword")
+				}
+			}
+			decryptedKey, decryptedError = x509.DecryptPEMBlock(block, []byte(sslpassword))
+			// Should we also provide warning for PKCS#1 needed?
+			if decryptedError != nil {
+				return nil, fmt.Errorf("unable to decrypt key: %w", decryptedError)
+			}
+
+			pemBytes := pem.Block{
+				Type:  "RSA PRIVATE KEY",
+				Bytes: decryptedKey,
+			}
+			pemKey = pem.EncodeToMemory(&pemBytes)
+		} else {
+			pemKey = pem.EncodeToMemory(block)
+		}
+		certfile, err := os.ReadFile(sslcert)
+		if err != nil {
+			return nil, fmt.Errorf("unable to read cert: %w", err)
+		}
+		cert, err := tls.X509KeyPair(certfile, pemKey)
+		if err != nil {
+			return nil, fmt.Errorf("unable to load cert: %w", err)
+		}
+		tlsConfig.Certificates = []tls.Certificate{cert}
+	}
+
+	// Set Server Name Indication (SNI), if enabled by connection parameters.
+	// Per RFC 6066, do not set it if the host is a literal IP address (IPv4
+	// or IPv6).
+	if sslsni == "1" && net.ParseIP(host) == nil {
+		tlsConfig.ServerName = host
+	}
+
+	switch sslmode {
+	case "allow":
+		return []*tls.Config{nil, tlsConfig}, nil
+	case "prefer":
+		return []*tls.Config{tlsConfig, nil}, nil
+	case "require", "verify-ca", "verify-full":
+		return []*tls.Config{tlsConfig}, nil
+	default:
+		panic("BUG: bad sslmode should already have been caught")
+	}
+}
+
+func parsePort(s string) (uint16, error) {
+	port, err := strconv.ParseUint(s, 10, 16)
+	if err != nil {
+		return 0, err
+	}
+	if port < 1 || port > math.MaxUint16 {
+		return 0, errors.New("outside range")
+	}
+	return uint16(port), nil
+}
+
+func makeDefaultDialer() *net.Dialer {
+	// rely on GOLANG KeepAlive settings
+	return &net.Dialer{}
+}
+
+func makeDefaultResolver() *net.Resolver {
+	return net.DefaultResolver
+}
+
+func parseConnectTimeoutSetting(s string) (time.Duration, error) {
+	timeout, err := strconv.ParseInt(s, 10, 64)
+	if err != nil {
+		return 0, err
+	}
+	if timeout < 0 {
+		return 0, errors.New("negative timeout")
+	}
+	return time.Duration(timeout) * time.Second, nil
+}
+
+func makeConnectTimeoutDialFunc(timeout time.Duration) DialFunc {
+	d := makeDefaultDialer()
+	d.Timeout = timeout
+	return d.DialContext
+}
+
+// ValidateConnectTargetSessionAttrsReadWrite is a ValidateConnectFunc that implements libpq compatible
+// target_session_attrs=read-write.
+func ValidateConnectTargetSessionAttrsReadWrite(ctx context.Context, pgConn *PgConn) error {
+	result, err := pgConn.Exec(ctx, "show transaction_read_only").ReadAll()
+	if err != nil {
+		return err
+	}
+
+	if string(result[0].Rows[0][0]) == "on" {
+		return errors.New("read only connection")
+	}
+
+	return nil
+}
+
+// ValidateConnectTargetSessionAttrsReadOnly is a ValidateConnectFunc that implements libpq compatible
+// target_session_attrs=read-only.
+func ValidateConnectTargetSessionAttrsReadOnly(ctx context.Context, pgConn *PgConn) error {
+	result, err := pgConn.Exec(ctx, "show transaction_read_only").ReadAll()
+	if err != nil {
+		return err
+	}
+
+	if string(result[0].Rows[0][0]) != "on" {
+		return errors.New("connection is not read only")
+	}
+
+	return nil
+}
+
+// ValidateConnectTargetSessionAttrsStandby is a ValidateConnectFunc that implements libpq compatible
+// target_session_attrs=standby.
+func ValidateConnectTargetSessionAttrsStandby(ctx context.Context, pgConn *PgConn) error {
+	result, err := pgConn.Exec(ctx, "select pg_is_in_recovery()").ReadAll()
+	if err != nil {
+		return err
+	}
+
+	if string(result[0].Rows[0][0]) != "t" {
+		return errors.New("server is not in hot standby mode")
+	}
+
+	return nil
+}
+
+// ValidateConnectTargetSessionAttrsPrimary is a ValidateConnectFunc that implements libpq compatible
+// target_session_attrs=primary.
+func ValidateConnectTargetSessionAttrsPrimary(ctx context.Context, pgConn *PgConn) error {
+	result, err := pgConn.Exec(ctx, "select pg_is_in_recovery()").ReadAll()
+	if err != nil {
+		return err
+	}
+
+	if string(result[0].Rows[0][0]) == "t" {
+		return errors.New("server is in standby mode")
+	}
+
+	return nil
+}
+
+// ValidateConnectTargetSessionAttrsPreferStandby is a ValidateConnectFunc that implements libpq compatible
+// target_session_attrs=prefer-standby.
+func ValidateConnectTargetSessionAttrsPreferStandby(ctx context.Context, pgConn *PgConn) error {
+	result, err := pgConn.Exec(ctx, "select pg_is_in_recovery()").ReadAll()
+	if err != nil {
+		return err
+	}
+
+	if string(result[0].Rows[0][0]) != "t" {
+		return &NotPreferredError{err: errors.New("server is not in hot standby mode")}
+	}
+
+	return nil
+}
+
+func parseProtocolVersion(s string) (uint32, error) {
+	switch s {
+	case "", "3.0":
+		return pgproto3.ProtocolVersion30, nil
+	case "3.2", "latest":
+		return pgproto3.ProtocolVersion32, nil
+	default:
+		return 0, fmt.Errorf("invalid protocol version: %q", s)
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/ctxwatch/context_watcher.go b/vendor/github.com/jackc/pgx/v5/pgconn/ctxwatch/context_watcher.go
new file mode 100644
index 000000000..b8892e68b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/ctxwatch/context_watcher.go
@@ -0,0 +1,72 @@
+package ctxwatch
+
+import (
+	"context"
+	"sync"
+)
+
+// ContextWatcher watches a context and performs an action when the context is canceled. It can watch one context at a
+// time.
+type ContextWatcher struct {
+	handler Handler
+
+	// Lock protects the members below.
+	lock sync.Mutex
+	// Stop is the handle for an "after func". See [context.AfterFunc].
+	stop func() bool
+	done chan struct{}
+}
+
+// NewContextWatcher returns a ContextWatcher. onCancel will be called when a watched context is canceled.
+// OnUnwatchAfterCancel will be called when Unwatch is called and the watched context had already been canceled and
+// onCancel called.
+func NewContextWatcher(handler Handler) *ContextWatcher {
+	cw := &ContextWatcher{
+		handler: handler,
+	}
+
+	return cw
+}
+
+// Watch starts watching ctx. If ctx is canceled then the onCancel function passed to NewContextWatcher will be called.
+func (cw *ContextWatcher) Watch(ctx context.Context) {
+	cw.lock.Lock()
+	defer cw.lock.Unlock()
+
+	if cw.stop != nil {
+		panic("watch already in progress")
+	}
+
+	if ctx.Done() != nil {
+		cw.done = make(chan struct{})
+		cw.stop = context.AfterFunc(ctx, func() {
+			cw.handler.HandleCancel(ctx)
+			close(cw.done)
+		})
+	}
+}
+
+// Unwatch stops watching the previously watched context. If the onCancel function passed to NewContextWatcher was
+// called then onUnwatchAfterCancel will also be called.
+func (cw *ContextWatcher) Unwatch() {
+	cw.lock.Lock()
+	defer cw.lock.Unlock()
+
+	if cw.stop != nil {
+		if !cw.stop() {
+			<-cw.done
+			cw.handler.HandleUnwatchAfterCancel()
+		}
+		cw.stop = nil
+		cw.done = nil
+	}
+}
+
+type Handler interface {
+	// HandleCancel is called when the context that a ContextWatcher is currently watching is canceled. canceledCtx is the
+	// context that was canceled.
+	HandleCancel(canceledCtx context.Context)
+
+	// HandleUnwatchAfterCancel is called when a ContextWatcher that called HandleCancel on this Handler is unwatched.
+	HandleUnwatchAfterCancel()
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/defaults.go b/vendor/github.com/jackc/pgx/v5/pgconn/defaults.go
new file mode 100644
index 000000000..1dd514ff4
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/defaults.go
@@ -0,0 +1,63 @@
+//go:build !windows
+// +build !windows
+
+package pgconn
+
+import (
+	"os"
+	"os/user"
+	"path/filepath"
+)
+
+func defaultSettings() map[string]string {
+	settings := make(map[string]string)
+
+	settings["host"] = defaultHost()
+	settings["port"] = "5432"
+
+	// Default to the OS user name. Purposely ignoring err getting user name from
+	// OS. The client application will simply have to specify the user in that
+	// case (which they typically will be doing anyway).
+	user, err := user.Current()
+	if err == nil {
+		settings["user"] = user.Username
+		settings["passfile"] = filepath.Join(user.HomeDir, ".pgpass")
+		settings["servicefile"] = filepath.Join(user.HomeDir, ".pg_service.conf")
+		sslcert := filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
+		sslkey := filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
+		if _, err := os.Stat(sslcert); err == nil {
+			if _, err := os.Stat(sslkey); err == nil {
+				// Both the cert and key must be present to use them, or do not use either
+				settings["sslcert"] = sslcert
+				settings["sslkey"] = sslkey
+			}
+		}
+		sslrootcert := filepath.Join(user.HomeDir, ".postgresql", "root.crt")
+		if _, err := os.Stat(sslrootcert); err == nil {
+			settings["sslrootcert"] = sslrootcert
+		}
+	}
+
+	settings["target_session_attrs"] = "any"
+
+	return settings
+}
+
+// defaultHost attempts to mimic libpq's default host. libpq uses the default unix socket location on *nix and localhost
+// on Windows. The default socket location is compiled into libpq. Since pgx does not have access to that default it
+// checks the existence of common locations.
+func defaultHost() string {
+	candidatePaths := []string{
+		"/var/run/postgresql", // Debian
+		"/private/tmp",        // OSX - homebrew
+		"/tmp",                // standard PostgreSQL
+	}
+
+	for _, path := range candidatePaths {
+		if _, err := os.Stat(path); err == nil {
+			return path
+		}
+	}
+
+	return "localhost"
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/defaults_windows.go b/vendor/github.com/jackc/pgx/v5/pgconn/defaults_windows.go
new file mode 100644
index 000000000..33b4a1ff8
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/defaults_windows.go
@@ -0,0 +1,57 @@
+package pgconn
+
+import (
+	"os"
+	"os/user"
+	"path/filepath"
+	"strings"
+)
+
+func defaultSettings() map[string]string {
+	settings := make(map[string]string)
+
+	settings["host"] = defaultHost()
+	settings["port"] = "5432"
+
+	// Default to the OS user name. Purposely ignoring err getting user name from
+	// OS. The client application will simply have to specify the user in that
+	// case (which they typically will be doing anyway).
+	user, err := user.Current()
+	appData := os.Getenv("APPDATA")
+	if err == nil {
+		// Windows gives us the username here as `DOMAIN\user` or `LOCALPCNAME\user`,
+		// but the libpq default is just the `user` portion, so we strip off the first part.
+		username := user.Username
+		if strings.Contains(username, "\\") {
+			username = username[strings.LastIndex(username, "\\")+1:]
+		}
+
+		settings["user"] = username
+		settings["passfile"] = filepath.Join(appData, "postgresql", "pgpass.conf")
+		settings["servicefile"] = filepath.Join(user.HomeDir, ".pg_service.conf")
+		sslcert := filepath.Join(appData, "postgresql", "postgresql.crt")
+		sslkey := filepath.Join(appData, "postgresql", "postgresql.key")
+		if _, err := os.Stat(sslcert); err == nil {
+			if _, err := os.Stat(sslkey); err == nil {
+				// Both the cert and key must be present to use them, or do not use either
+				settings["sslcert"] = sslcert
+				settings["sslkey"] = sslkey
+			}
+		}
+		sslrootcert := filepath.Join(appData, "postgresql", "root.crt")
+		if _, err := os.Stat(sslrootcert); err == nil {
+			settings["sslrootcert"] = sslrootcert
+		}
+	}
+
+	settings["target_session_attrs"] = "any"
+
+	return settings
+}
+
+// defaultHost attempts to mimic libpq's default host. libpq uses the default unix socket location on *nix and localhost
+// on Windows. The default socket location is compiled into libpq. Since pgx does not have access to that default it
+// checks the existence of common locations.
+func defaultHost() string {
+	return "localhost"
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/doc.go b/vendor/github.com/jackc/pgx/v5/pgconn/doc.go
new file mode 100644
index 000000000..f9707262e
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/doc.go
@@ -0,0 +1,64 @@
+// Package pgconn is a low-level PostgreSQL database driver.
+/*
+pgconn provides lower level access to a PostgreSQL connection than a database/sql or pgx connection. It operates at
+nearly the same level is the C library libpq.
+
+Establishing a Connection
+
+Use Connect to establish a connection. It accepts a connection string in URL or keyword/value format and will read the
+environment for libpq style environment variables.
+
+Connecting Securely
+
+By default ParseConfig matches libpq and uses sslmode=prefer, which silently falls back to an unencrypted connection
+if the server does not offer TLS. For connections that traverse an untrusted network, set the following parameters
+explicitly:
+
+	# URL form
+	postgres://user@db.example.com/mydb?sslmode=verify-full&sslrootcert=/path/to/root.crt&channel_binding=require&require_auth=scram-sha-256
+
+	# keyword/value form
+	host=db.example.com user=user dbname=mydb sslmode=verify-full sslrootcert=/path/to/root.crt channel_binding=require require_auth=scram-sha-256
+
+	sslmode=verify-full       Require TLS, verify the server certificate against sslrootcert, and verify that the
+	                          certificate's host name matches the host being connected to. Weaker modes (disable,
+	                          allow, prefer, require) either permit plaintext fallback or skip certificate
+	                          verification, allowing a network attacker to impersonate the server.
+	channel_binding=require   Require SCRAM-SHA-256-PLUS, which binds the authentication exchange to the TLS channel
+	                          so that a TLS-terminating intermediary cannot relay credentials to the real server.
+	require_auth=scram-sha-256
+	                          Refuse to respond to AuthenticationCleartextPassword or AuthenticationMD5Password
+	                          requests from the server. Without this, a server (or interceptor) can request the
+	                          password in cleartext and the client will send it.
+
+These parameters may also be set via the PGSSLMODE, PGSSLROOTCERT, PGCHANNELBINDING, and PGREQUIREAUTH environment
+variables.
+
+Executing a Query
+
+ExecParams and ExecPrepared execute a single query. They return readers that iterate over each row. The Read method
+reads all rows into memory.
+
+Executing Multiple Queries in a Single Round Trip
+
+Exec and ExecBatch can execute multiple queries in a single round trip. They return readers that iterate over each query
+result. The ReadAll method reads all query results into memory.
+
+Pipeline Mode
+
+Pipeline mode allows sending queries without having read the results of previously sent queries. It allows control of
+exactly how many and when network round trips occur.
+
+Context Support
+
+All potentially blocking operations take a context.Context. The default behavior when a context is canceled is for the
+method to immediately return. In most circumstances, this will also close the underlying connection. This behavior can
+be customized by using BuildContextWatcherHandler on the Config to create a ctxwatch.Handler with different behavior.
+This can be especially useful when queries that are frequently canceled and the overhead of creating new connections is
+a problem. DeadlineContextWatcherHandler and CancelRequestContextWatcherHandler can be used to introduce a delay before
+interrupting the query in such a way as to close the connection.
+
+The CancelRequest method may be used to request the PostgreSQL server cancel an in-progress query without forcing the
+client to abort.
+*/
+package pgconn
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/errors.go b/vendor/github.com/jackc/pgx/v5/pgconn/errors.go
new file mode 100644
index 000000000..9fbe68cb6
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/errors.go
@@ -0,0 +1,287 @@
+package pgconn
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net"
+	"net/url"
+	"regexp"
+	"strings"
+)
+
+// SafeToRetry checks if the err is guaranteed to have occurred before sending any data to the server.
+func SafeToRetry(err error) bool {
+	var retryableErr interface{ SafeToRetry() bool }
+	if errors.As(err, &retryableErr) {
+		return retryableErr.SafeToRetry()
+	}
+	return false
+}
+
+// Timeout checks if err was caused by a timeout. To be specific, it is true if err was caused within pgconn by a
+// context.DeadlineExceeded or an implementer of net.Error where Timeout() is true.
+func Timeout(err error) bool {
+	var timeoutErr *errTimeout
+	return errors.As(err, &timeoutErr)
+}
+
+// PgError represents an error reported by the PostgreSQL server. See
+// http://www.postgresql.org/docs/current/static/protocol-error-fields.html for
+// detailed field description.
+type PgError struct {
+	Severity            string
+	SeverityUnlocalized string
+	Code                string
+	Message             string
+	Detail              string
+	Hint                string
+	Position            int32
+	InternalPosition    int32
+	InternalQuery       string
+	Where               string
+	SchemaName          string
+	TableName           string
+	ColumnName          string
+	DataTypeName        string
+	ConstraintName      string
+	File                string
+	Line                int32
+	Routine             string
+}
+
+func (pe *PgError) Error() string {
+	return pe.Severity + ": " + pe.Message + " (SQLSTATE " + pe.Code + ")"
+}
+
+// SQLState returns the SQLState of the error.
+func (pe *PgError) SQLState() string {
+	return pe.Code
+}
+
+// ConnectError is the error returned when a connection attempt fails.
+type ConnectError struct {
+	Config *Config // The configuration that was used in the connection attempt.
+	err    error
+}
+
+func (e *ConnectError) Error() string {
+	prefix := fmt.Sprintf("failed to connect to `user=%s database=%s`:", e.Config.User, e.Config.Database)
+	details := e.err.Error()
+	if strings.Contains(details, "\n") {
+		return prefix + "\n\t" + strings.ReplaceAll(details, "\n", "\n\t")
+	} else {
+		return prefix + " " + details
+	}
+}
+
+func (e *ConnectError) Unwrap() error {
+	return e.err
+}
+
+type perDialConnectError struct {
+	address          string
+	originalHostname string
+	err              error
+}
+
+func (e *perDialConnectError) Error() string {
+	return fmt.Sprintf("%s (%s): %s", e.address, e.originalHostname, e.err.Error())
+}
+
+func (e *perDialConnectError) Unwrap() error {
+	return e.err
+}
+
+// ErrConnClosed is returned (possibly wrapped) when an operation is attempted
+// on a connection that the driver has already closed, e.g. because a prior
+// query was cancelled mid-flight or the underlying socket went away. Use
+// errors.Is to test for it, since it shows up wrapped inside connLockError.
+var ErrConnClosed = errors.New("conn closed")
+
+type connLockError struct {
+	status string
+}
+
+func (e *connLockError) SafeToRetry() bool {
+	return true // a lock failure by definition happens before the connection is used.
+}
+
+func (e *connLockError) Error() string {
+	return e.status
+}
+
+func (e *connLockError) Unwrap() error {
+	if e.status == "conn closed" {
+		return ErrConnClosed
+	}
+	return nil
+}
+
+// ParseConfigError is the error returned when a connection string cannot be parsed.
+type ParseConfigError struct {
+	ConnString string // The connection string that could not be parsed.
+	msg        string
+	err        error
+}
+
+func NewParseConfigError(conn, msg string, err error) error {
+	return &ParseConfigError{
+		ConnString: conn,
+		msg:        msg,
+		err:        err,
+	}
+}
+
+func (e *ParseConfigError) Error() string {
+	// Now that ParseConfigError is public and ConnString is available to the developer, perhaps it would be better only
+	// return a static string. That would ensure that the error message cannot leak a password. The ConnString field would
+	// allow access to the original string if desired and Unwrap would allow access to the underlying error.
+	connString := redactPW(e.ConnString)
+	if e.err == nil {
+		return fmt.Sprintf("cannot parse `%s`: %s", connString, e.msg)
+	}
+	return fmt.Sprintf("cannot parse `%s`: %s (%s)", connString, e.msg, e.err.Error())
+}
+
+func (e *ParseConfigError) Unwrap() error {
+	return e.err
+}
+
+func normalizeTimeoutError(ctx context.Context, err error) error {
+	var netErr net.Error
+	if errors.As(err, &netErr) && netErr.Timeout() {
+		switch ctx.Err() {
+		case context.Canceled:
+			// Since the timeout was caused by a context cancellation, the actual error is context.Canceled not the timeout error.
+			return context.Canceled
+		case context.DeadlineExceeded:
+			return &errTimeout{err: ctx.Err()}
+		default:
+			return &errTimeout{err: err}
+		}
+	}
+	return err
+}
+
+type pgconnError struct {
+	msg         string
+	err         error
+	safeToRetry bool
+}
+
+func (e *pgconnError) Error() string {
+	if e.msg == "" {
+		return e.err.Error()
+	}
+	if e.err == nil {
+		return e.msg
+	}
+	return fmt.Sprintf("%s: %s", e.msg, e.err.Error())
+}
+
+func (e *pgconnError) SafeToRetry() bool {
+	return e.safeToRetry
+}
+
+func (e *pgconnError) Unwrap() error {
+	return e.err
+}
+
+// errTimeout occurs when an error was caused by a timeout. Specifically, it wraps an error which is
+// context.Canceled, context.DeadlineExceeded, or an implementer of net.Error where Timeout() is true.
+type errTimeout struct {
+	err error
+}
+
+func (e *errTimeout) Error() string {
+	return fmt.Sprintf("timeout: %s", e.err.Error())
+}
+
+func (e *errTimeout) SafeToRetry() bool {
+	return SafeToRetry(e.err)
+}
+
+func (e *errTimeout) Unwrap() error {
+	return e.err
+}
+
+type contextAlreadyDoneError struct {
+	err error
+}
+
+func (e *contextAlreadyDoneError) Error() string {
+	return fmt.Sprintf("context already done: %s", e.err.Error())
+}
+
+func (e *contextAlreadyDoneError) SafeToRetry() bool {
+	return true
+}
+
+func (e *contextAlreadyDoneError) Unwrap() error {
+	return e.err
+}
+
+// newContextAlreadyDoneError double-wraps a context error in `contextAlreadyDoneError` and `errTimeout`.
+func newContextAlreadyDoneError(ctx context.Context) (err error) {
+	return &errTimeout{&contextAlreadyDoneError{err: ctx.Err()}}
+}
+
+func redactPW(connString string) string {
+	if strings.HasPrefix(connString, "postgres://") || strings.HasPrefix(connString, "postgresql://") {
+		if u, err := url.Parse(connString); err == nil {
+			return redactURL(u)
+		}
+	}
+	quotedKV := regexp.MustCompile(`password='[^']*'`)
+	connString = quotedKV.ReplaceAllLiteralString(connString, "password=xxxxx")
+	plainKV := regexp.MustCompile(`password=[^ ]*`)
+	connString = plainKV.ReplaceAllLiteralString(connString, "password=xxxxx")
+	brokenURL := regexp.MustCompile(`:[^:@]+?@`)
+	connString = brokenURL.ReplaceAllLiteralString(connString, ":xxxxxx@")
+	return connString
+}
+
+func redactURL(u *url.URL) string {
+	if u == nil {
+		return ""
+	}
+	if _, pwSet := u.User.Password(); pwSet {
+		u.User = url.UserPassword(u.User.Username(), "xxxxx")
+	}
+	return u.String()
+}
+
+type NotPreferredError struct {
+	err         error
+	safeToRetry bool
+}
+
+func (e *NotPreferredError) Error() string {
+	return fmt.Sprintf("standby server not found: %s", e.err.Error())
+}
+
+func (e *NotPreferredError) SafeToRetry() bool {
+	return e.safeToRetry
+}
+
+func (e *NotPreferredError) Unwrap() error {
+	return e.err
+}
+
+type PrepareError struct {
+	err error
+
+	ParseComplete bool // Indicates whether the error occurred after a ParseComplete message was received.
+}
+
+func (e *PrepareError) Error() string {
+	if e.ParseComplete {
+		return fmt.Sprintf("prepare failed after ParseComplete: %s", e.err.Error())
+	}
+	return e.err.Error()
+}
+
+func (e *PrepareError) Unwrap() error {
+	return e.err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/internal/bgreader/bgreader.go b/vendor/github.com/jackc/pgx/v5/pgconn/internal/bgreader/bgreader.go
new file mode 100644
index 000000000..e65c2c2bf
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/internal/bgreader/bgreader.go
@@ -0,0 +1,139 @@
+// Package bgreader provides a io.Reader that can optionally buffer reads in the background.
+package bgreader
+
+import (
+	"io"
+	"sync"
+
+	"github.com/jackc/pgx/v5/internal/iobufpool"
+)
+
+const (
+	StatusStopped = iota
+	StatusRunning
+	StatusStopping
+)
+
+// BGReader is an io.Reader that can optionally buffer reads in the background. It is safe for concurrent use.
+type BGReader struct {
+	r io.Reader
+
+	cond        *sync.Cond
+	status      int32
+	readResults []readResult
+}
+
+type readResult struct {
+	buf *[]byte
+	err error
+}
+
+// Start starts the backgrounder reader. If the background reader is already running this is a no-op. The background
+// reader will stop automatically when the underlying reader returns an error.
+func (r *BGReader) Start() {
+	r.cond.L.Lock()
+	defer r.cond.L.Unlock()
+
+	switch r.status {
+	case StatusStopped:
+		r.status = StatusRunning
+		go r.bgRead()
+	case StatusRunning:
+		// no-op
+	case StatusStopping:
+		r.status = StatusRunning
+	}
+}
+
+// Stop tells the background reader to stop after the in progress Read returns. It is safe to call Stop when the
+// background reader is not running.
+func (r *BGReader) Stop() {
+	r.cond.L.Lock()
+	defer r.cond.L.Unlock()
+
+	switch r.status {
+	case StatusStopped:
+		// no-op
+	case StatusRunning:
+		r.status = StatusStopping
+	case StatusStopping:
+		// no-op
+	}
+}
+
+// Status returns the current status of the background reader.
+func (r *BGReader) Status() int32 {
+	r.cond.L.Lock()
+	defer r.cond.L.Unlock()
+	return r.status
+}
+
+func (r *BGReader) bgRead() {
+	keepReading := true
+	for keepReading {
+		buf := iobufpool.Get(8192)
+		n, err := r.r.Read(*buf)
+		*buf = (*buf)[:n]
+
+		r.cond.L.Lock()
+		r.readResults = append(r.readResults, readResult{buf: buf, err: err})
+		if r.status == StatusStopping || err != nil {
+			r.status = StatusStopped
+			keepReading = false
+		}
+		r.cond.L.Unlock()
+		r.cond.Broadcast()
+	}
+}
+
+// Read implements the io.Reader interface.
+func (r *BGReader) Read(p []byte) (int, error) {
+	r.cond.L.Lock()
+	defer r.cond.L.Unlock()
+
+	if len(r.readResults) > 0 {
+		return r.readFromReadResults(p)
+	}
+
+	// There are no unread background read results and the background reader is stopped.
+	if r.status == StatusStopped {
+		return r.r.Read(p)
+	}
+
+	// Wait for results from the background reader
+	for len(r.readResults) == 0 {
+		r.cond.Wait()
+	}
+	return r.readFromReadResults(p)
+}
+
+// readBackgroundResults reads a result previously read by the background reader. r.cond.L must be held.
+func (r *BGReader) readFromReadResults(p []byte) (int, error) {
+	buf := r.readResults[0].buf
+	var err error
+
+	n := copy(p, *buf)
+	if n == len(*buf) {
+		err = r.readResults[0].err
+		iobufpool.Put(buf)
+		if len(r.readResults) == 1 {
+			r.readResults = nil
+		} else {
+			r.readResults = r.readResults[1:]
+		}
+	} else {
+		*buf = (*buf)[n:]
+		r.readResults[0].buf = buf
+	}
+
+	return n, err
+}
+
+func New(r io.Reader) *BGReader {
+	return &BGReader{
+		r: r,
+		cond: &sync.Cond{
+			L: &sync.Mutex{},
+		},
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/krb5.go b/vendor/github.com/jackc/pgx/v5/pgconn/krb5.go
new file mode 100644
index 000000000..efb0d61b8
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/krb5.go
@@ -0,0 +1,100 @@
+package pgconn
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/jackc/pgx/v5/pgproto3"
+)
+
+// NewGSSFunc creates a GSS authentication provider, for use with
+// RegisterGSSProvider.
+type NewGSSFunc func() (GSS, error)
+
+var newGSS NewGSSFunc
+
+// RegisterGSSProvider registers a GSS authentication provider. For example, if
+// you need to use Kerberos to authenticate with your server, add this to your
+// main package:
+//
+//	import "github.com/otan/gopgkrb5"
+//
+//	func init() {
+//		pgconn.RegisterGSSProvider(func() (pgconn.GSS, error) { return gopgkrb5.NewGSS() })
+//	}
+func RegisterGSSProvider(newGSSArg NewGSSFunc) {
+	newGSS = newGSSArg
+}
+
+// GSS provides GSSAPI authentication (e.g., Kerberos).
+type GSS interface {
+	GetInitToken(host, service string) ([]byte, error)
+	GetInitTokenFromSPN(spn string) ([]byte, error)
+	Continue(inToken []byte) (done bool, outToken []byte, err error)
+}
+
+func (c *PgConn) gssAuth() error {
+	if newGSS == nil {
+		return errors.New("kerberos error: no GSSAPI provider registered, see https://github.com/otan/gopgkrb5")
+	}
+	cli, err := newGSS()
+	if err != nil {
+		return err
+	}
+
+	var nextData []byte
+	if c.config.KerberosSpn != "" {
+		// Use the supplied SPN if provided.
+		nextData, err = cli.GetInitTokenFromSPN(c.config.KerberosSpn)
+	} else {
+		// Allow the kerberos service name to be overridden
+		service := "postgres"
+		if c.config.KerberosSrvName != "" {
+			service = c.config.KerberosSrvName
+		}
+		nextData, err = cli.GetInitToken(c.config.Host, service)
+	}
+	if err != nil {
+		return err
+	}
+
+	for {
+		gssResponse := &pgproto3.GSSResponse{
+			Data: nextData,
+		}
+		c.frontend.Send(gssResponse)
+		err = c.flushWithPotentialWriteReadDeadlock()
+		if err != nil {
+			return err
+		}
+		resp, err := c.rxGSSContinue()
+		if err != nil {
+			return err
+		}
+		var done bool
+		done, nextData, err = cli.Continue(resp.Data)
+		if err != nil {
+			return err
+		}
+		if done {
+			break
+		}
+	}
+	return nil
+}
+
+func (c *PgConn) rxGSSContinue() (*pgproto3.AuthenticationGSSContinue, error) {
+	msg, err := c.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+
+	switch m := msg.(type) {
+	case *pgproto3.AuthenticationGSSContinue:
+		return m, nil
+	case *pgproto3.ErrorResponse:
+		return nil, ErrorResponseToPgError(m)
+	}
+
+	return nil, fmt.Errorf("expected AuthenticationGSSContinue message but received unexpected message %T", msg)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/pgconn.go b/vendor/github.com/jackc/pgx/v5/pgconn/pgconn.go
new file mode 100644
index 000000000..d181f7f5f
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/pgconn.go
@@ -0,0 +1,3042 @@
+package pgconn
+
+import (
+	"container/list"
+	"context"
+	"crypto/md5"
+	"crypto/tls"
+	"encoding/binary"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"io"
+	"maps"
+	"math"
+	"net"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/jackc/pgx/v5/internal/iobufpool"
+	"github.com/jackc/pgx/v5/internal/pgio"
+	"github.com/jackc/pgx/v5/pgconn/ctxwatch"
+	"github.com/jackc/pgx/v5/pgconn/internal/bgreader"
+	"github.com/jackc/pgx/v5/pgproto3"
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+const (
+	connStatusUninitialized = iota
+	connStatusConnecting
+	connStatusClosed
+	connStatusIdle
+	connStatusBusy
+)
+
+// Notice represents a notice response message reported by the PostgreSQL server. Be aware that this is distinct from
+// LISTEN/NOTIFY notification.
+type Notice PgError
+
+// Notification is a message received from the PostgreSQL LISTEN/NOTIFY system
+type Notification struct {
+	PID     uint32 // backend pid that sent the notification
+	Channel string // channel from which notification was received
+	Payload string
+}
+
+// DialFunc is a function that can be used to connect to a PostgreSQL server.
+type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
+
+// LookupFunc is a function that can be used to lookup IPs addrs from host. Optionally an ip:port combination can be
+// returned in order to override the connection string's port.
+type LookupFunc func(ctx context.Context, host string) (addrs []string, err error)
+
+// BuildFrontendFunc is a function that can be used to create Frontend implementation for connection.
+type BuildFrontendFunc func(r io.Reader, w io.Writer) *pgproto3.Frontend
+
+// PgErrorHandler is a function that handles errors returned from Postgres. This function must return true to keep
+// the connection open. Returning false will cause the connection to be closed immediately. You should return
+// false on any FATAL-severity errors. This will not receive network errors. The *PgConn is provided so the handler is
+// aware of the origin of the error, but it must not invoke any query method.
+type PgErrorHandler func(*PgConn, *PgError) bool
+
+// NoticeHandler is a function that can handle notices received from the PostgreSQL server. Notices can be received at
+// any time, usually during handling of a query response. The *PgConn is provided so the handler is aware of the origin
+// of the notice, but it must not invoke any query method. Be aware that this is distinct from LISTEN/NOTIFY
+// notification.
+type NoticeHandler func(*PgConn, *Notice)
+
+// NotificationHandler is a function that can handle notifications received from the PostgreSQL server. Notifications
+// can be received at any time, usually during handling of a query response. The *PgConn is provided so the handler is
+// aware of the origin of the notice, but it must not invoke any query method. Be aware that this is distinct from a
+// notice event.
+type NotificationHandler func(*PgConn, *Notification)
+
+// PgConn is a low-level PostgreSQL connection handle. It is not safe for concurrent usage.
+type PgConn struct {
+	conn              net.Conn
+	tlsConfig         *tls.Config       // tls.Config that conn was negotiated with; nil if conn is not TLS
+	pid               uint32            // backend pid
+	secretKey         []byte            // key to use to send a cancel query message to the server
+	parameterStatuses map[string]string // parameters that have been reported by the server
+	txStatus          byte
+	frontend          *pgproto3.Frontend
+	bgReader          *bgreader.BGReader
+	slowWriteTimer    *time.Timer
+	bgReaderStarted   chan struct{}
+
+	customData map[string]any
+
+	config *Config
+
+	status byte // One of connStatus* constants
+
+	bufferingReceive    bool
+	bufferingReceiveMux sync.Mutex
+	bufferingReceiveMsg pgproto3.BackendMessage
+	bufferingReceiveErr error
+
+	peekedMsg pgproto3.BackendMessage
+
+	// Reusable / preallocated resources
+	resultReader      ResultReader
+	multiResultReader MultiResultReader
+	pipeline          Pipeline
+	contextWatcher    *ctxwatch.ContextWatcher
+	fieldDescriptions [16]FieldDescription
+
+	cleanupDone chan struct{}
+}
+
+// Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or keyword/value
+// format) to provide configuration. See documentation for [ParseConfig] for details. ctx can be used to cancel a
+// connect attempt.
+func Connect(ctx context.Context, connString string) (*PgConn, error) {
+	config, err := ParseConfig(connString)
+	if err != nil {
+		return nil, err
+	}
+
+	return ConnectConfig(ctx, config)
+}
+
+// Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or keyword/value
+// format) and ParseConfigOptions to provide additional configuration. See documentation for [ParseConfig] for details.
+// ctx can be used to cancel a connect attempt.
+func ConnectWithOptions(ctx context.Context, connString string, parseConfigOptions ParseConfigOptions) (*PgConn, error) {
+	config, err := ParseConfigWithOptions(connString, parseConfigOptions)
+	if err != nil {
+		return nil, err
+	}
+
+	return ConnectConfig(ctx, config)
+}
+
+// Connect establishes a connection to a PostgreSQL server using config. config must have been constructed with
+// [ParseConfig]. ctx can be used to cancel a connect attempt.
+//
+// If config.Fallbacks are present they will sequentially be tried in case of error establishing network connection. An
+// authentication error will terminate the chain of attempts (like libpq:
+// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS) and be returned as the error.
+func ConnectConfig(ctx context.Context, config *Config) (*PgConn, error) {
+	// Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from
+	// zero values.
+	if !config.createdByParseConfig {
+		panic("config must be created by ParseConfig")
+	}
+
+	var allErrors []error
+
+	connectConfigs, errs := buildConnectOneConfigs(ctx, config)
+	if len(errs) > 0 {
+		allErrors = append(allErrors, errs...)
+	}
+
+	if len(connectConfigs) == 0 {
+		return nil, &ConnectError{Config: config, err: fmt.Errorf("hostname resolving error: %w", errors.Join(allErrors...))}
+	}
+
+	pgConn, errs := connectPreferred(ctx, config, connectConfigs)
+	if len(errs) > 0 {
+		allErrors = append(allErrors, errs...)
+		return nil, &ConnectError{Config: config, err: errors.Join(allErrors...)}
+	}
+
+	if config.AfterConnect != nil {
+		err := config.AfterConnect(ctx, pgConn)
+		if err != nil {
+			pgConn.conn.Close()
+			return nil, &ConnectError{Config: config, err: fmt.Errorf("AfterConnect error: %w", err)}
+		}
+	}
+
+	return pgConn, nil
+}
+
+// buildConnectOneConfigs resolves hostnames and builds a list of connectOneConfigs to try connecting to. It returns a
+// slice of successfully resolved connectOneConfigs and a slice of errors. It is possible for both slices to contain
+// values if some hosts were successfully resolved and others were not.
+func buildConnectOneConfigs(ctx context.Context, config *Config) ([]*connectOneConfig, []error) {
+	// Simplify usage by treating primary config and fallbacks the same.
+	fallbackConfigs := []*FallbackConfig{
+		{
+			Host:      config.Host,
+			Port:      config.Port,
+			TLSConfig: config.TLSConfig,
+		},
+	}
+	fallbackConfigs = append(fallbackConfigs, config.Fallbacks...)
+
+	var configs []*connectOneConfig
+
+	var allErrors []error
+
+	for _, fb := range fallbackConfigs {
+		// skip resolve for unix sockets
+		if isAbsolutePath(fb.Host) {
+			network, address := NetworkAddress(fb.Host, fb.Port)
+			configs = append(configs, &connectOneConfig{
+				network:          network,
+				address:          address,
+				originalHostname: fb.Host,
+				tlsConfig:        fb.TLSConfig,
+			})
+
+			continue
+		}
+
+		ips, err := config.LookupFunc(ctx, fb.Host)
+		if err != nil {
+			allErrors = append(allErrors, err)
+			continue
+		}
+
+		for _, ip := range ips {
+			splitIP, splitPort, err := net.SplitHostPort(ip)
+			if err == nil {
+				port, err := strconv.ParseUint(splitPort, 10, 16)
+				if err != nil {
+					return nil, []error{fmt.Errorf("error parsing port (%s) from lookup: %w", splitPort, err)}
+				}
+				network, address := NetworkAddress(splitIP, uint16(port))
+				configs = append(configs, &connectOneConfig{
+					network:          network,
+					address:          address,
+					originalHostname: fb.Host,
+					tlsConfig:        fb.TLSConfig,
+				})
+			} else {
+				network, address := NetworkAddress(ip, fb.Port)
+				configs = append(configs, &connectOneConfig{
+					network:          network,
+					address:          address,
+					originalHostname: fb.Host,
+					tlsConfig:        fb.TLSConfig,
+				})
+			}
+		}
+	}
+
+	return configs, allErrors
+}
+
+// connectPreferred attempts to connect to the preferred host from connectOneConfigs. The connections are attempted in
+// order. If a connection is successful it is returned. If no connection is successful then all errors are returned. If
+// a connection attempt returns a [NotPreferredError], then that host will be used if no other hosts are successful.
+func connectPreferred(ctx context.Context, config *Config, connectOneConfigs []*connectOneConfig) (*PgConn, []error) {
+	octx := ctx
+	var allErrors []error
+
+	var fallbackConnectOneConfig *connectOneConfig
+	for i, c := range connectOneConfigs {
+		// ConnectTimeout restricts the whole connection process.
+		if config.ConnectTimeout != 0 {
+			// create new context first time or when previous host was different
+			if i == 0 || (connectOneConfigs[i].address != connectOneConfigs[i-1].address) {
+				var cancel context.CancelFunc
+				ctx, cancel = context.WithTimeout(octx, config.ConnectTimeout)
+				defer cancel()
+			}
+		} else {
+			ctx = octx
+		}
+
+		pgConn, err := connectOne(ctx, config, c, false)
+		if pgConn != nil {
+			return pgConn, nil
+		}
+
+		allErrors = append(allErrors, err)
+
+		var pgErr *PgError
+		if errors.As(err, &pgErr) {
+			// pgx will try next host even if libpq does not in certain cases (see #2246)
+			// consider change for the next major version
+
+			const ERRCODE_INVALID_PASSWORD = "28P01"
+			const ERRCODE_INVALID_CATALOG_NAME = "3D000"   // db does not exist
+			const ERRCODE_INSUFFICIENT_PRIVILEGE = "42501" // missing connect privilege
+
+			// auth failed due to invalid password, db does not exist or user has no permission
+			if pgErr.Code == ERRCODE_INVALID_PASSWORD ||
+				pgErr.Code == ERRCODE_INVALID_CATALOG_NAME ||
+				pgErr.Code == ERRCODE_INSUFFICIENT_PRIVILEGE {
+				return nil, allErrors
+			}
+		}
+
+		var npErr *NotPreferredError
+		if errors.As(err, &npErr) {
+			fallbackConnectOneConfig = c
+		}
+	}
+
+	if fallbackConnectOneConfig != nil {
+		fallbackCtx := octx
+		if config.ConnectTimeout != 0 {
+			var cancel context.CancelFunc
+			fallbackCtx, cancel = context.WithTimeout(octx, config.ConnectTimeout)
+			defer cancel()
+		}
+		pgConn, err := connectOne(fallbackCtx, config, fallbackConnectOneConfig, true)
+		if err == nil {
+			return pgConn, nil
+		}
+		allErrors = append(allErrors, err)
+	}
+
+	return nil, allErrors
+}
+
+// connectOne makes one connection attempt to a single host.
+func connectOne(ctx context.Context, config *Config, connectConfig *connectOneConfig,
+	ignoreNotPreferredErr bool,
+) (*PgConn, error) {
+	pgConn := new(PgConn)
+	pgConn.config = config
+	pgConn.cleanupDone = make(chan struct{})
+	pgConn.customData = make(map[string]any)
+
+	var err error
+
+	newPerDialConnectError := func(msg string, err error) *perDialConnectError {
+		err = normalizeTimeoutError(ctx, err)
+		e := &perDialConnectError{address: connectConfig.address, originalHostname: connectConfig.originalHostname, err: fmt.Errorf("%s: %w", msg, err)}
+		return e
+	}
+
+	maxProtocolVersion, err := parseProtocolVersion(config.MaxProtocolVersion)
+	if err != nil {
+		return nil, newPerDialConnectError("invalid max_protocol_version", err)
+	}
+	minProtocolVersion, err := parseProtocolVersion(config.MinProtocolVersion)
+	if err != nil {
+		return nil, newPerDialConnectError("invalid min_protocol_version", err)
+	}
+
+	pgConn.conn, err = config.DialFunc(ctx, connectConfig.network, connectConfig.address)
+	if err != nil {
+		return nil, newPerDialConnectError("dial error", err)
+	}
+
+	if connectConfig.tlsConfig != nil {
+		pgConn.contextWatcher = ctxwatch.NewContextWatcher(&DeadlineContextWatcherHandler{Conn: pgConn.conn})
+		pgConn.contextWatcher.Watch(ctx)
+		var (
+			tlsConn net.Conn
+			err     error
+		)
+		if config.SSLNegotiation == "direct" {
+			tlsConn = tls.Client(pgConn.conn, connectConfig.tlsConfig)
+		} else {
+			tlsConn, err = startTLS(pgConn.conn, connectConfig.tlsConfig)
+		}
+		pgConn.contextWatcher.Unwatch() // Always unwatch `netConn` after TLS.
+		if err != nil {
+			pgConn.conn.Close()
+			return nil, newPerDialConnectError("tls error", err)
+		}
+
+		pgConn.conn = tlsConn
+		pgConn.tlsConfig = connectConfig.tlsConfig
+	}
+
+	if config.AfterNetConnect != nil {
+		pgConn.conn, err = config.AfterNetConnect(ctx, config, pgConn.conn)
+		if err != nil {
+			pgConn.conn.Close()
+			return nil, newPerDialConnectError("AfterNetConnect failed", err)
+		}
+	}
+
+	// Use a deadline-only watcher during connect. The application-supplied
+	// BuildContextWatcherHandler may read *PgConn fields (e.g.
+	// CancelRequestContextWatcherHandler reads pgConn.pid and
+	// pgConn.secretKey), which would race with this function's writes to
+	// those fields when handling BackendKeyData. The application handler is
+	// installed below, after the connection reaches connStatusIdle.
+	pgConn.contextWatcher = ctxwatch.NewContextWatcher(&DeadlineContextWatcherHandler{Conn: pgConn.conn})
+	pgConn.contextWatcher.Watch(ctx)
+	defer pgConn.contextWatcher.Unwatch()
+
+	pgConn.parameterStatuses = make(map[string]string)
+	pgConn.status = connStatusConnecting
+	pgConn.bgReader = bgreader.New(pgConn.conn)
+	pgConn.slowWriteTimer = time.AfterFunc(time.Duration(math.MaxInt64),
+		func() {
+			pgConn.bgReader.Start()
+			pgConn.bgReaderStarted <- struct{}{}
+		},
+	)
+	pgConn.slowWriteTimer.Stop()
+	pgConn.bgReaderStarted = make(chan struct{})
+	pgConn.frontend = config.BuildFrontend(pgConn.bgReader, pgConn.conn)
+
+	startupMsg := pgproto3.StartupMessage{
+		ProtocolVersion: maxProtocolVersion,
+		Parameters:      make(map[string]string),
+	}
+
+	// Copy default run-time params
+	maps.Copy(startupMsg.Parameters, config.RuntimeParams)
+
+	startupMsg.Parameters["user"] = config.User
+	if config.Database != "" {
+		startupMsg.Parameters["database"] = config.Database
+	}
+
+	pgConn.frontend.Send(&startupMsg)
+	if err := pgConn.flushWithPotentialWriteReadDeadlock(); err != nil {
+		pgConn.conn.Close()
+		return nil, newPerDialConnectError("failed to write startup message", err)
+	}
+
+	// Parse require_auth on each connect so that callers who mutate
+	// Config.RequireAuth after ParseConfig see their change take effect.
+	// The parser is pure and cheap; ParseConfigWithOptions validates the
+	// value up front so any parse error here indicates post-parse mutation.
+	requireAuthPolicy, err := parseRequireAuth(config.RequireAuth)
+	if err != nil {
+		pgConn.conn.Close()
+		return nil, newPerDialConnectError("invalid require_auth", err)
+	}
+	requireAuthFail := func(err error) (*PgConn, error) {
+		pgConn.conn.Close()
+		return nil, newPerDialConnectError("require_auth check failed", err)
+	}
+	clientFinishedAuth := false
+
+	for {
+		msg, err := pgConn.receiveMessage()
+		if err != nil {
+			pgConn.conn.Close()
+			if err, ok := err.(*PgError); ok {
+				return nil, newPerDialConnectError("server error", err)
+			}
+			return nil, newPerDialConnectError("failed to receive message", err)
+		}
+
+		switch msg := msg.(type) {
+		case *pgproto3.BackendKeyData:
+			pgConn.pid = msg.ProcessID
+			pgConn.secretKey = msg.SecretKey
+
+		case *pgproto3.AuthenticationOk:
+			if requireAuthPolicy.authRequired && !clientFinishedAuth {
+				return requireAuthFail(requireAuthPolicy.check(authMethodNone))
+			}
+		case *pgproto3.AuthenticationCleartextPassword:
+			if err := requireAuthPolicy.check(authMethodPassword); err != nil {
+				return requireAuthFail(err)
+			}
+			err = pgConn.txPasswordMessage(pgConn.config.Password)
+			if err != nil {
+				pgConn.conn.Close()
+				return nil, newPerDialConnectError("failed to write password message", err)
+			}
+			clientFinishedAuth = true
+		case *pgproto3.AuthenticationMD5Password:
+			if err := requireAuthPolicy.check(authMethodMD5); err != nil {
+				return requireAuthFail(err)
+			}
+			digestedPassword := "md5" + hexMD5(hexMD5(pgConn.config.Password+pgConn.config.User)+string(msg.Salt[:]))
+			err = pgConn.txPasswordMessage(digestedPassword)
+			if err != nil {
+				pgConn.conn.Close()
+				return nil, newPerDialConnectError("failed to write password message", err)
+			}
+			clientFinishedAuth = true
+		case *pgproto3.AuthenticationSASL:
+			// Check if OAUTHBEARER is supported
+			serverSupportsOAuthBearer := false
+			for _, mech := range msg.AuthMechanisms {
+				if mech == "OAUTHBEARER" {
+					serverSupportsOAuthBearer = true
+					break
+				}
+			}
+
+			if serverSupportsOAuthBearer && pgConn.config.OAuthTokenProvider != nil {
+				if err := requireAuthPolicy.check(authMethodOAuth); err != nil {
+					return requireAuthFail(err)
+				}
+				err = pgConn.oauthAuth(ctx)
+			} else {
+				if err := requireAuthPolicy.check(authMethodSCRAMSHA256); err != nil {
+					return requireAuthFail(err)
+				}
+				err = pgConn.scramAuth(msg.AuthMechanisms)
+			}
+			if err != nil {
+				pgConn.conn.Close()
+				return nil, newPerDialConnectError("failed SASL auth", err)
+			}
+			clientFinishedAuth = true
+		case *pgproto3.AuthenticationGSS:
+			if err := requireAuthPolicy.check(authMethodGSS); err != nil {
+				return requireAuthFail(err)
+			}
+			err = pgConn.gssAuth()
+			if err != nil {
+				pgConn.conn.Close()
+				return nil, newPerDialConnectError("failed GSS auth", err)
+			}
+			clientFinishedAuth = true
+		case *pgproto3.ReadyForQuery:
+			pgConn.status = connStatusIdle
+			// The connect-phase deadline-only watcher is no longer needed; replace
+			// it with the application-supplied watcher so subsequent operations
+			// (including any queries run by ValidateConnect) use it.
+			pgConn.contextWatcher.Unwatch()
+			pgConn.contextWatcher = ctxwatch.NewContextWatcher(config.BuildContextWatcherHandler(pgConn))
+
+			if config.ValidateConnect != nil {
+				err := config.ValidateConnect(ctx, pgConn)
+				if err != nil {
+					if _, ok := err.(*NotPreferredError); ignoreNotPreferredErr && ok {
+						return pgConn, nil
+					}
+					pgConn.conn.Close()
+					return nil, newPerDialConnectError("ValidateConnect failed", err)
+				}
+			}
+			return pgConn, nil
+		case *pgproto3.ParameterStatus, *pgproto3.NoticeResponse:
+			// handled by ReceiveMessage
+		case *pgproto3.NegotiateProtocolVersion:
+			serverVersion := pgproto3.ProtocolVersion30&0xFFFF0000 | msg.NewestMinorProtocol
+			if serverVersion < minProtocolVersion {
+				pgConn.conn.Close()
+				return nil, newPerDialConnectError("server protocol version too low", nil)
+			}
+		case *pgproto3.ErrorResponse:
+			pgConn.conn.Close()
+			return nil, newPerDialConnectError("server error", ErrorResponseToPgError(msg))
+		default:
+			pgConn.conn.Close()
+			return nil, newPerDialConnectError("received unexpected message", err)
+		}
+	}
+}
+
+func startTLS(conn net.Conn, tlsConfig *tls.Config) (net.Conn, error) {
+	err := binary.Write(conn, binary.BigEndian, []int32{8, 80877103})
+	if err != nil {
+		return nil, err
+	}
+
+	response := make([]byte, 1)
+	if _, err = io.ReadFull(conn, response); err != nil {
+		return nil, err
+	}
+
+	if response[0] != 'S' {
+		return nil, errors.New("server refused TLS connection")
+	}
+
+	return tls.Client(conn, tlsConfig), nil
+}
+
+func (pgConn *PgConn) txPasswordMessage(password string) (err error) {
+	pgConn.frontend.Send(&pgproto3.PasswordMessage{Password: password})
+	return pgConn.flushWithPotentialWriteReadDeadlock()
+}
+
+func hexMD5(s string) string {
+	hash := md5.New()
+	io.WriteString(hash, s)
+	return hex.EncodeToString(hash.Sum(nil))
+}
+
+func (pgConn *PgConn) signalMessage() chan struct{} {
+	if pgConn.bufferingReceive {
+		panic("BUG: signalMessage when already in progress")
+	}
+
+	pgConn.bufferingReceive = true
+	pgConn.bufferingReceiveMux.Lock()
+
+	ch := make(chan struct{})
+	go func() {
+		pgConn.bufferingReceiveMsg, pgConn.bufferingReceiveErr = pgConn.frontend.Receive()
+		pgConn.bufferingReceiveMux.Unlock()
+		close(ch)
+	}()
+
+	return ch
+}
+
+// ReceiveMessage receives one wire protocol message from the PostgreSQL server. It must only be used when the
+// connection is not busy. e.g. It is an error to call [PgConn.ReceiveMessage] while reading the result of a query. The messages
+// are still handled by the core pgconn message handling system so receiving a NotificationResponse will still trigger
+// the OnNotification callback.
+//
+// This is a very low level method that requires deep understanding of the PostgreSQL wire protocol to use correctly.
+// See https://www.postgresql.org/docs/current/protocol.html.
+func (pgConn *PgConn) ReceiveMessage(ctx context.Context) (pgproto3.BackendMessage, error) {
+	if err := pgConn.lock(); err != nil {
+		return nil, err
+	}
+	defer pgConn.unlock()
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			return nil, newContextAlreadyDoneError(ctx)
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+		defer pgConn.contextWatcher.Unwatch()
+	}
+
+	msg, err := pgConn.receiveMessage()
+	if err != nil {
+		err = &pgconnError{
+			msg:         "receive message failed",
+			err:         normalizeTimeoutError(ctx, err),
+			safeToRetry: true,
+		}
+	}
+	return msg, err
+}
+
+// peekMessage peeks at the next message without setting up context cancellation.
+func (pgConn *PgConn) peekMessage() (pgproto3.BackendMessage, error) {
+	if pgConn.peekedMsg != nil {
+		return pgConn.peekedMsg, nil
+	}
+
+	var msg pgproto3.BackendMessage
+	var err error
+	if pgConn.bufferingReceive {
+		pgConn.bufferingReceiveMux.Lock()
+		msg = pgConn.bufferingReceiveMsg
+		err = pgConn.bufferingReceiveErr
+		pgConn.bufferingReceiveMux.Unlock()
+		pgConn.bufferingReceive = false
+
+		// If a timeout error happened in the background try the read again.
+		var netErr net.Error
+		if errors.As(err, &netErr) && netErr.Timeout() {
+			msg, err = pgConn.frontend.Receive()
+		}
+	} else {
+		msg, err = pgConn.frontend.Receive()
+	}
+
+	if err != nil {
+		// Close on anything other than timeout error - everything else is fatal
+		var netErr net.Error
+		isNetErr := errors.As(err, &netErr)
+		if !(isNetErr && netErr.Timeout()) {
+			pgConn.asyncClose()
+		}
+
+		return nil, err
+	}
+
+	pgConn.peekedMsg = msg
+	return msg, nil
+}
+
+// receiveMessage receives a message without setting up context cancellation
+func (pgConn *PgConn) receiveMessage() (pgproto3.BackendMessage, error) {
+	if pgConn.status == connStatusClosed {
+		return nil, &connLockError{status: "conn closed"}
+	}
+
+	msg, err := pgConn.peekMessage()
+	if err != nil {
+		return nil, err
+	}
+	pgConn.peekedMsg = nil
+
+	switch msg := msg.(type) {
+	case *pgproto3.ReadyForQuery:
+		pgConn.txStatus = msg.TxStatus
+	case *pgproto3.ParameterStatus:
+		pgConn.parameterStatuses[msg.Name] = msg.Value
+	case *pgproto3.ErrorResponse:
+		err := ErrorResponseToPgError(msg)
+		if pgConn.config.OnPgError != nil && !pgConn.config.OnPgError(pgConn, err) {
+			pgConn.status = connStatusClosed
+			pgConn.conn.Close() // Ignore error as the connection is already broken and there is already an error to return.
+			close(pgConn.cleanupDone)
+			return nil, err
+		}
+	case *pgproto3.NoticeResponse:
+		if pgConn.config.OnNotice != nil {
+			pgConn.config.OnNotice(pgConn, noticeResponseToNotice(msg))
+		}
+	case *pgproto3.NotificationResponse:
+		if pgConn.config.OnNotification != nil {
+			pgConn.config.OnNotification(pgConn, &Notification{PID: msg.PID, Channel: msg.Channel, Payload: msg.Payload})
+		}
+	}
+
+	return msg, nil
+}
+
+// Conn returns the underlying net.Conn. This rarely necessary. If the connection will be directly used for reading or
+// writing then SyncConn should usually be called before Conn.
+func (pgConn *PgConn) Conn() net.Conn {
+	return pgConn.conn
+}
+
+// PID returns the backend PID.
+func (pgConn *PgConn) PID() uint32 {
+	return pgConn.pid
+}
+
+// TxStatus returns the current TxStatus as reported by the server in the ReadyForQuery message.
+//
+// Possible return values:
+//
+//	'I' - idle / not in transaction
+//	'T' - in a transaction
+//	'E' - in a failed transaction
+//
+// See https://www.postgresql.org/docs/current/protocol-message-formats.html.
+func (pgConn *PgConn) TxStatus() byte {
+	return pgConn.txStatus
+}
+
+// SecretKey returns the backend secret key used to send a cancel query message to the server.
+func (pgConn *PgConn) SecretKey() []byte {
+	return pgConn.secretKey
+}
+
+// Frontend returns the underlying *pgproto3.Frontend. This rarely necessary.
+func (pgConn *PgConn) Frontend() *pgproto3.Frontend {
+	return pgConn.frontend
+}
+
+// Close closes a connection. It is safe to call Close on an already closed connection. Close attempts a clean close by
+// sending the exit message to PostgreSQL. However, this could block so ctx is available to limit the time to wait. The
+// underlying net.Conn.Close() will always be called regardless of any other errors.
+func (pgConn *PgConn) Close(ctx context.Context) error {
+	if pgConn.status == connStatusClosed {
+		return nil
+	}
+	pgConn.status = connStatusClosed
+
+	defer close(pgConn.cleanupDone)
+	defer pgConn.conn.Close()
+
+	if ctx != context.Background() {
+		// Close may be called while a cancellable query is in progress. This will most often be triggered by panic when
+		// a defer closes the connection (possibly indirectly via a transaction or a connection pool). Unwatch to end any
+		// previous watch. It is safe to Unwatch regardless of whether a watch is already is progress.
+		//
+		// See https://github.com/jackc/pgconn/issues/29
+		pgConn.contextWatcher.Unwatch()
+
+		pgConn.contextWatcher.Watch(ctx)
+		defer pgConn.contextWatcher.Unwatch()
+	}
+
+	// Ignore any errors sending Terminate message and waiting for server to close connection.
+	// This mimics the behavior of libpq PQfinish. It calls closePGconn which calls sendTerminateConn which purposefully
+	// ignores errors.
+	//
+	// See https://github.com/jackc/pgx/issues/637
+	pgConn.frontend.Send(&pgproto3.Terminate{})
+	pgConn.flushWithPotentialWriteReadDeadlock()
+
+	return pgConn.conn.Close()
+}
+
+// asyncClose marks the connection as closed and asynchronously sends a cancel query message and closes the underlying
+// connection.
+func (pgConn *PgConn) asyncClose() {
+	if pgConn.status == connStatusClosed {
+		return
+	}
+	pgConn.status = connStatusClosed
+
+	go func() {
+		defer close(pgConn.cleanupDone)
+		defer pgConn.conn.Close()
+
+		deadline := time.Now().Add(time.Second * 15)
+
+		ctx, cancel := context.WithDeadline(context.Background(), deadline)
+		defer cancel()
+
+		pgConn.CancelRequest(ctx)
+
+		pgConn.conn.SetDeadline(deadline)
+
+		pgConn.frontend.Send(&pgproto3.Terminate{})
+		pgConn.flushWithPotentialWriteReadDeadlock()
+	}()
+}
+
+// CleanupDone returns a channel that will be closed after all underlying resources have been cleaned up. A closed
+// connection is no longer usable, but underlying resources, in particular the net.Conn, may not have finished closing
+// yet. This is because certain errors such as a context cancellation require that the interrupted function call return
+// immediately, but the error may also cause the connection to be closed. In these cases the underlying resources are
+// closed asynchronously.
+//
+// This is only likely to be useful to connection pools. It gives them a way avoid establishing a new connection while
+// an old connection is still being cleaned up and thereby exceeding the maximum pool size.
+func (pgConn *PgConn) CleanupDone() chan (struct{}) {
+	return pgConn.cleanupDone
+}
+
+// IsClosed reports if the connection has been closed.
+//
+// CleanupDone() can be used to determine if all cleanup has been completed.
+func (pgConn *PgConn) IsClosed() bool {
+	return pgConn.status < connStatusIdle
+}
+
+// IsBusy reports if the connection is busy.
+func (pgConn *PgConn) IsBusy() bool {
+	return pgConn.status == connStatusBusy
+}
+
+// lock locks the connection.
+func (pgConn *PgConn) lock() error {
+	switch pgConn.status {
+	case connStatusBusy:
+		return &connLockError{status: "conn busy"} // This only should be possible in case of an application bug.
+	case connStatusClosed:
+		return &connLockError{status: "conn closed"}
+	case connStatusUninitialized:
+		return &connLockError{status: "conn uninitialized"}
+	}
+	pgConn.status = connStatusBusy
+	return nil
+}
+
+func (pgConn *PgConn) unlock() {
+	switch pgConn.status {
+	case connStatusBusy:
+		pgConn.status = connStatusIdle
+	case connStatusClosed:
+	default:
+		panic("BUG: cannot unlock unlocked connection") // This should only be possible if there is a bug in this package.
+	}
+}
+
+// ParameterStatus returns the value of a parameter reported by the server (e.g.
+// server_version). Returns an empty string for unknown parameters.
+func (pgConn *PgConn) ParameterStatus(key string) string {
+	return pgConn.parameterStatuses[key]
+}
+
+// CommandTag is the status text returned by PostgreSQL for a query.
+type CommandTag struct {
+	s string
+}
+
+// NewCommandTag makes a CommandTag from s.
+func NewCommandTag(s string) CommandTag {
+	return CommandTag{s: s}
+}
+
+// RowsAffected returns the number of rows affected. If the CommandTag was not
+// for a row affecting command (e.g. "CREATE TABLE") then it returns 0.
+func (ct CommandTag) RowsAffected() int64 {
+	// Parse the number from the end in a single pass.
+	var n int64
+	var mult int64 = 1
+
+	for i := len(ct.s) - 1; i >= 0; i-- {
+		c := ct.s[i]
+		if c >= '0' && c <= '9' {
+			n += int64(c-'0') * mult
+			mult *= 10
+		} else {
+			break
+		}
+	}
+
+	return n
+}
+
+func (ct CommandTag) String() string {
+	return ct.s
+}
+
+// Insert is true if the command tag starts with "INSERT".
+func (ct CommandTag) Insert() bool {
+	return strings.HasPrefix(ct.s, "INSERT")
+}
+
+// Update is true if the command tag starts with "UPDATE".
+func (ct CommandTag) Update() bool {
+	return strings.HasPrefix(ct.s, "UPDATE")
+}
+
+// Delete is true if the command tag starts with "DELETE".
+func (ct CommandTag) Delete() bool {
+	return strings.HasPrefix(ct.s, "DELETE")
+}
+
+// Select is true if the command tag starts with "SELECT".
+func (ct CommandTag) Select() bool {
+	return strings.HasPrefix(ct.s, "SELECT")
+}
+
+type FieldDescription struct {
+	Name                 string
+	TableOID             uint32
+	TableAttributeNumber uint16
+	DataTypeOID          uint32
+	DataTypeSize         int16
+	TypeModifier         int32
+	Format               int16
+}
+
+func (pgConn *PgConn) getFieldDescriptionSlice(n int) []FieldDescription {
+	if cap(pgConn.fieldDescriptions) >= n {
+		return pgConn.fieldDescriptions[:n:n]
+	} else {
+		return make([]FieldDescription, n)
+	}
+}
+
+func convertRowDescription(dst []FieldDescription, rd *pgproto3.RowDescription) {
+	for i := range rd.Fields {
+		dst[i].Name = string(rd.Fields[i].Name)
+		dst[i].TableOID = rd.Fields[i].TableOID
+		dst[i].TableAttributeNumber = rd.Fields[i].TableAttributeNumber
+		dst[i].DataTypeOID = rd.Fields[i].DataTypeOID
+		dst[i].DataTypeSize = rd.Fields[i].DataTypeSize
+		dst[i].TypeModifier = rd.Fields[i].TypeModifier
+		dst[i].Format = rd.Fields[i].Format
+	}
+}
+
+type StatementDescription struct {
+	Name      string
+	SQL       string
+	ParamOIDs []uint32
+	Fields    []FieldDescription
+}
+
+// Prepare creates a prepared statement. If the name is empty, the anonymous prepared statement will be used. This
+// allows Prepare to also to describe statements without creating a server-side prepared statement.
+//
+// Prepare does not send a PREPARE statement to the server. It uses the PostgreSQL Parse and Describe protocol messages
+// directly.
+//
+// In extremely rare cases, Prepare may fail after the Parse is successful, but before the Describe is complete. In this
+// case, the returned error will be an error where errors.As with a *PrepareError succeeds and the *PrepareError has
+// ParseComplete set to true.
+func (pgConn *PgConn) Prepare(ctx context.Context, name, sql string, paramOIDs []uint32) (*StatementDescription, error) {
+	if err := pgConn.lock(); err != nil {
+		return nil, err
+	}
+	defer pgConn.unlock()
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			return nil, newContextAlreadyDoneError(ctx)
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+		defer pgConn.contextWatcher.Unwatch()
+	}
+
+	pgConn.frontend.SendParse(&pgproto3.Parse{Name: name, Query: sql, ParameterOIDs: paramOIDs})
+	pgConn.frontend.SendDescribe(&pgproto3.Describe{ObjectType: 'S', Name: name})
+	pgConn.frontend.SendSync(&pgproto3.Sync{})
+	err := pgConn.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		pgConn.asyncClose()
+		return nil, err
+	}
+
+	psd := &StatementDescription{Name: name, SQL: sql}
+
+	var ParseComplete bool
+	var pgErr *PgError
+
+readloop:
+	for {
+		msg, err := pgConn.receiveMessage()
+		if err != nil {
+			pgConn.asyncClose()
+			return nil, normalizeTimeoutError(ctx, err)
+		}
+
+		switch msg := msg.(type) {
+		case *pgproto3.ParseComplete:
+			ParseComplete = true
+		case *pgproto3.ParameterDescription:
+			psd.ParamOIDs = make([]uint32, len(msg.ParameterOIDs))
+			copy(psd.ParamOIDs, msg.ParameterOIDs)
+		case *pgproto3.RowDescription:
+			psd.Fields = make([]FieldDescription, len(msg.Fields))
+			convertRowDescription(psd.Fields, msg)
+		case *pgproto3.ErrorResponse:
+			pgErr = ErrorResponseToPgError(msg)
+		case *pgproto3.ReadyForQuery:
+			break readloop
+		}
+	}
+
+	if pgErr != nil {
+		return nil, &PrepareError{err: pgErr, ParseComplete: ParseComplete}
+	}
+	return psd, nil
+}
+
+// Deallocate deallocates a prepared statement.
+//
+// Deallocate does not send a DEALLOCATE statement to the server. It uses the PostgreSQL Close protocol message
+// directly. This has slightly different behavior than executing DEALLOCATE statement.
+//   - Deallocate can succeed in an aborted transaction.
+//   - Deallocating a non-existent prepared statement is not an error.
+func (pgConn *PgConn) Deallocate(ctx context.Context, name string) error {
+	if err := pgConn.lock(); err != nil {
+		return err
+	}
+	defer pgConn.unlock()
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			return newContextAlreadyDoneError(ctx)
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+		defer pgConn.contextWatcher.Unwatch()
+	}
+
+	pgConn.frontend.SendClose(&pgproto3.Close{ObjectType: 'S', Name: name})
+	pgConn.frontend.SendSync(&pgproto3.Sync{})
+	err := pgConn.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		pgConn.asyncClose()
+		return err
+	}
+
+	for {
+		msg, err := pgConn.receiveMessage()
+		if err != nil {
+			pgConn.asyncClose()
+			return normalizeTimeoutError(ctx, err)
+		}
+
+		switch msg := msg.(type) {
+		case *pgproto3.ErrorResponse:
+			return ErrorResponseToPgError(msg)
+		case *pgproto3.ReadyForQuery:
+			return nil
+		}
+	}
+}
+
+// ErrorResponseToPgError converts a wire protocol error message to a *PgError.
+func ErrorResponseToPgError(msg *pgproto3.ErrorResponse) *PgError {
+	return &PgError{
+		Severity:            msg.Severity,
+		SeverityUnlocalized: msg.SeverityUnlocalized,
+		Code:                msg.Code,
+		Message:             msg.Message,
+		Detail:              msg.Detail,
+		Hint:                msg.Hint,
+		Position:            msg.Position,
+		InternalPosition:    msg.InternalPosition,
+		InternalQuery:       msg.InternalQuery,
+		Where:               msg.Where,
+		SchemaName:          msg.SchemaName,
+		TableName:           msg.TableName,
+		ColumnName:          msg.ColumnName,
+		DataTypeName:        msg.DataTypeName,
+		ConstraintName:      msg.ConstraintName,
+		File:                msg.File,
+		Line:                msg.Line,
+		Routine:             msg.Routine,
+	}
+}
+
+func noticeResponseToNotice(msg *pgproto3.NoticeResponse) *Notice {
+	pgerr := ErrorResponseToPgError((*pgproto3.ErrorResponse)(msg))
+	return (*Notice)(pgerr)
+}
+
+// CancelRequest sends a cancel request to the PostgreSQL server. It returns an error if unable to deliver the cancel
+// request, but lack of an error does not ensure that the query was canceled. As specified in the documentation, there
+// is no way to be sure a query was canceled.
+// See https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-CANCELING-REQUESTS
+func (pgConn *PgConn) CancelRequest(ctx context.Context) error {
+	// Open a cancellation request to the same server. The address is taken from the net.Conn directly instead of reusing
+	// the connection config. This is important in high availability configurations where fallback connections may be
+	// specified or DNS may be used to load balance.
+	serverAddr := pgConn.conn.RemoteAddr()
+	var serverNetwork string
+	var serverAddress string
+	if serverAddr.Network() == "unix" {
+		// for unix sockets, RemoteAddr() calls getpeername() which returns the name the
+		// server passed to bind(). For Postgres, this is always a relative path "./.s.PGSQL.5432"
+		// so connecting to it will fail. Fall back to the config's value
+		serverNetwork, serverAddress = NetworkAddress(pgConn.config.Host, pgConn.config.Port)
+	} else {
+		serverNetwork, serverAddress = serverAddr.Network(), serverAddr.String()
+	}
+	cancelConn, err := pgConn.config.DialFunc(ctx, serverNetwork, serverAddress)
+	if err != nil {
+		// In case of unix sockets, RemoteAddr() returns only the file part of the path. If the
+		// first connect failed, try the config.
+		if serverAddr.Network() != "unix" {
+			return err
+		}
+		serverNetwork, serverAddr := NetworkAddress(pgConn.config.Host, pgConn.config.Port)
+		cancelConn, err = pgConn.config.DialFunc(ctx, serverNetwork, serverAddr)
+		if err != nil {
+			return err
+		}
+	}
+	defer cancelConn.Close()
+
+	if ctx != context.Background() {
+		contextWatcher := ctxwatch.NewContextWatcher(&DeadlineContextWatcherHandler{Conn: cancelConn})
+		contextWatcher.Watch(ctx)
+		defer contextWatcher.Unwatch()
+	}
+
+	// If the primary connection is encrypted, encrypt the cancel connection the same way so the
+	// backend pid and secret key are not exposed to a passive network observer. This mirrors libpq's
+	// PQcancelCreate (PG17+), which reuses the original connection's sslmode/gssencmode for the
+	// cancel connection. The legacy unencrypted path is still used when the primary connection is
+	// plaintext (e.g. unix sockets or sslmode=disable).
+	if pgConn.tlsConfig != nil {
+		var tlsCancelConn net.Conn
+		if pgConn.config.SSLNegotiation == "direct" {
+			tlsCancelConn = tls.Client(cancelConn, pgConn.tlsConfig)
+		} else {
+			tlsCancelConn, err = startTLS(cancelConn, pgConn.tlsConfig)
+			if err != nil {
+				return fmt.Errorf("tls error on cancel connection: %w", err)
+			}
+		}
+		cancelConn = tlsCancelConn
+		defer cancelConn.Close()
+	}
+
+	buf := make([]byte, 12+len(pgConn.secretKey))
+	binary.BigEndian.PutUint32(buf[0:4], uint32(len(buf)))
+	binary.BigEndian.PutUint32(buf[4:8], 80877102)
+	binary.BigEndian.PutUint32(buf[8:12], pgConn.pid)
+	copy(buf[12:], pgConn.secretKey)
+
+	if _, err := cancelConn.Write(buf); err != nil {
+		return fmt.Errorf("write to connection for cancellation: %w", err)
+	}
+
+	// Wait for the cancel request to be acknowledged by the server.
+	// It copies the behavior of the libpq: https://github.com/postgres/postgres/blob/REL_16_0/src/interfaces/libpq/fe-connect.c#L4946-L4960
+	_, _ = cancelConn.Read(buf)
+
+	return nil
+}
+
+// WaitForNotification waits for a LISTEN/NOTIFY message to be received. It returns an error if a notification was not
+// received.
+func (pgConn *PgConn) WaitForNotification(ctx context.Context) error {
+	if err := pgConn.lock(); err != nil {
+		return err
+	}
+	defer pgConn.unlock()
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			return newContextAlreadyDoneError(ctx)
+		default:
+		}
+
+		pgConn.contextWatcher.Watch(ctx)
+		defer pgConn.contextWatcher.Unwatch()
+	}
+
+	for {
+		msg, err := pgConn.receiveMessage()
+		if err != nil {
+			return normalizeTimeoutError(ctx, err)
+		}
+
+		if _, ok := msg.(*pgproto3.NotificationResponse); ok {
+			return nil
+		}
+	}
+}
+
+// Exec executes SQL via the PostgreSQL simple query protocol. SQL may contain multiple queries. Execution is
+// implicitly wrapped in a transaction unless a transaction is already in progress or SQL contains transaction control
+// statements.
+//
+// Prefer [PgConn.ExecParams] unless executing arbitrary SQL that may contain multiple queries.
+func (pgConn *PgConn) Exec(ctx context.Context, sql string) *MultiResultReader {
+	if err := pgConn.lock(); err != nil {
+		return &MultiResultReader{
+			closed: true,
+			err:    err,
+		}
+	}
+
+	pgConn.multiResultReader = MultiResultReader{
+		pgConn: pgConn,
+		ctx:    ctx,
+	}
+	multiResult := &pgConn.multiResultReader
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			multiResult.closed = true
+			multiResult.err = newContextAlreadyDoneError(ctx)
+			pgConn.unlock()
+			return multiResult
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+	}
+
+	pgConn.frontend.SendQuery(&pgproto3.Query{String: sql})
+	err := pgConn.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		pgConn.asyncClose()
+		pgConn.contextWatcher.Unwatch()
+		multiResult.closed = true
+		multiResult.err = err
+		pgConn.unlock()
+		return multiResult
+	}
+
+	return multiResult
+}
+
+// ExecParams executes a command via the PostgreSQL extended query protocol.
+//
+// sql is a SQL command string. It may only contain one query. Parameter substitution is positional using $1, $2, $3,
+// etc.
+//
+// paramValues are the parameter values. It must be encoded in the format given by paramFormats.
+//
+// paramOIDs is a slice of data type OIDs for paramValues. If paramOIDs is nil, the server will infer the data type for
+// all parameters. Any paramOID element that is 0 that will cause the server to infer the data type for that parameter.
+// ExecParams will panic if len(paramOIDs) is not 0, 1, or len(paramValues).
+//
+// paramFormats is a slice of format codes determining for each paramValue column whether it is encoded in text or
+// binary format. If paramFormats is nil all params are text format. ExecParams will panic if
+// len(paramFormats) is not 0, 1, or len(paramValues).
+//
+// resultFormats is a slice of format codes determining for each result column whether it is encoded in text or
+// binary format. If resultFormats is nil all results will be in text format.
+//
+// [ResultReader] must be closed before [PgConn] can be used again.
+func (pgConn *PgConn) ExecParams(ctx context.Context, sql string, paramValues [][]byte, paramOIDs []uint32, paramFormats, resultFormats []int16) *ResultReader {
+	result := pgConn.execExtendedPrefix(ctx, paramValues)
+	if result.closed {
+		return result
+	}
+
+	pgConn.frontend.SendParse(&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs})
+	pgConn.frontend.SendBind(&pgproto3.Bind{ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats})
+
+	pgConn.execExtendedSuffix(result, nil, nil)
+
+	return result
+}
+
+// ExecPrepared enqueues the execution of a prepared statement via the PostgreSQL extended query protocol.
+//
+// paramValues are the parameter values. It must be encoded in the format given by paramFormats.
+//
+// paramFormats is a slice of format codes determining for each paramValue column whether it is encoded in text or
+// binary format. If paramFormats is nil all params are text format. ExecPrepared will panic if
+// len(paramFormats) is not 0, 1, or len(paramValues).
+//
+// resultFormats is a slice of format codes determining for each result column whether it is encoded in text or
+// binary format. If resultFormats is nil all results will be in text format.
+//
+// [ResultReader] must be closed before [PgConn] can be used again.
+func (pgConn *PgConn) ExecPrepared(ctx context.Context, stmtName string, paramValues [][]byte, paramFormats, resultFormats []int16) *ResultReader {
+	result := pgConn.execExtendedPrefix(ctx, paramValues)
+	if result.closed {
+		return result
+	}
+
+	pgConn.frontend.SendBind(&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats})
+
+	pgConn.execExtendedSuffix(result, nil, nil)
+
+	return result
+}
+
+// ExecStatement enqueues the execution of a prepared statement via the PostgreSQL extended query protocol.
+//
+// This differs from [PgConn.ExecPrepared] in that it takes a [*StatementDescription] instead of the prepared statement name.
+// Because it has the [*StatementDescription] it can avoid the Describe Portal message that [PgConn.ExecPrepared] must send to get
+// the result column descriptions.
+//
+// paramValues are the parameter values. It must be encoded in the format given by paramFormats.
+//
+// paramFormats is a slice of format codes determining for each paramValue column whether it is encoded in text or
+// binary format. If paramFormats is nil all params are text format. ExecStatement will panic if len(paramFormats) is not
+// 0, 1, or len(paramValues).
+//
+// resultFormats is a slice of format codes determining for each result column whether it is encoded in text or binary
+// format. If resultFormats is nil all results will be in text format.
+//
+// [ResultReader] must be closed before [PgConn] can be used again.
+func (pgConn *PgConn) ExecStatement(ctx context.Context, statementDescription *StatementDescription, paramValues [][]byte, paramFormats, resultFormats []int16) *ResultReader {
+	result := pgConn.execExtendedPrefix(ctx, paramValues)
+	if result.closed {
+		return result
+	}
+
+	pgConn.frontend.SendBind(&pgproto3.Bind{PreparedStatement: statementDescription.Name, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats})
+
+	pgConn.execExtendedSuffix(result, statementDescription, resultFormats)
+
+	return result
+}
+
+func (pgConn *PgConn) execExtendedPrefix(ctx context.Context, paramValues [][]byte) *ResultReader {
+	pgConn.resultReader = ResultReader{
+		pgConn: pgConn,
+		ctx:    ctx,
+	}
+	result := &pgConn.resultReader
+
+	if err := pgConn.lock(); err != nil {
+		result.concludeCommand(CommandTag{}, err)
+		result.closed = true
+		return result
+	}
+
+	if len(paramValues) > math.MaxUint16 {
+		result.concludeCommand(CommandTag{}, fmt.Errorf("extended protocol limited to %v parameters", math.MaxUint16))
+		result.closed = true
+		pgConn.unlock()
+		return result
+	}
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			result.concludeCommand(CommandTag{}, newContextAlreadyDoneError(ctx))
+			result.closed = true
+			pgConn.unlock()
+			return result
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+	}
+
+	return result
+}
+
+func (pgConn *PgConn) execExtendedSuffix(result *ResultReader, statementDescription *StatementDescription, resultFormats []int16) {
+	if statementDescription == nil {
+		pgConn.frontend.SendDescribe(&pgproto3.Describe{ObjectType: 'P'})
+	}
+	pgConn.frontend.SendExecute(&pgproto3.Execute{})
+	pgConn.frontend.SendSync(&pgproto3.Sync{})
+
+	err := pgConn.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		pgConn.asyncClose()
+		result.concludeCommand(CommandTag{}, err)
+		pgConn.contextWatcher.Unwatch()
+		result.closed = true
+		pgConn.unlock()
+		return
+	}
+
+	result.readUntilRowDescription(statementDescription, resultFormats)
+}
+
+// CopyTo executes the copy command sql and copies the results to w.
+func (pgConn *PgConn) CopyTo(ctx context.Context, w io.Writer, sql string) (CommandTag, error) {
+	if err := pgConn.lock(); err != nil {
+		return CommandTag{}, err
+	}
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			pgConn.unlock()
+			return CommandTag{}, newContextAlreadyDoneError(ctx)
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+		defer pgConn.contextWatcher.Unwatch()
+	}
+
+	// Send copy to command
+	pgConn.frontend.SendQuery(&pgproto3.Query{String: sql})
+
+	err := pgConn.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		pgConn.asyncClose()
+		pgConn.unlock()
+		return CommandTag{}, err
+	}
+
+	// Read results
+	var commandTag CommandTag
+	var pgErr error
+	for {
+		msg, err := pgConn.receiveMessage()
+		if err != nil {
+			pgConn.asyncClose()
+			return CommandTag{}, normalizeTimeoutError(ctx, err)
+		}
+
+		switch msg := msg.(type) {
+		case *pgproto3.CopyDone:
+		case *pgproto3.CopyData:
+			_, err := w.Write(msg.Data)
+			if err != nil {
+				pgConn.asyncClose()
+				return CommandTag{}, err
+			}
+		case *pgproto3.ReadyForQuery:
+			pgConn.unlock()
+			return commandTag, pgErr
+		case *pgproto3.CommandComplete:
+			commandTag = pgConn.makeCommandTag(msg.CommandTag)
+		case *pgproto3.ErrorResponse:
+			pgErr = ErrorResponseToPgError(msg)
+		}
+	}
+}
+
+// CopyFrom executes the copy command sql and copies all of r to the PostgreSQL server.
+//
+// Note: context cancellation will only interrupt operations on the underlying PostgreSQL network connection. Reads on r
+// could still block.
+func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (CommandTag, error) {
+	if err := pgConn.lock(); err != nil {
+		return CommandTag{}, err
+	}
+	defer pgConn.unlock()
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			return CommandTag{}, newContextAlreadyDoneError(ctx)
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+		defer pgConn.contextWatcher.Unwatch()
+	}
+
+	// Send copy from query
+	pgConn.frontend.SendQuery(&pgproto3.Query{String: sql})
+	err := pgConn.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		pgConn.asyncClose()
+		return CommandTag{}, err
+	}
+
+	// Send copy data
+	abortCopyChan := make(chan struct{})
+	copyErrChan := make(chan error, 1)
+	signalMessageChan := pgConn.signalMessage()
+	var wg sync.WaitGroup
+	wg.Go(func() {
+		buf := iobufpool.Get(65536)
+		defer iobufpool.Put(buf)
+		(*buf)[0] = 'd'
+
+		for {
+			n, readErr := r.Read((*buf)[5:cap(*buf)])
+			if n > 0 {
+				*buf = (*buf)[0 : n+5]
+				pgio.SetInt32((*buf)[1:], int32(n+4))
+
+				writeErr := pgConn.frontend.SendUnbufferedEncodedCopyData(*buf)
+				if writeErr != nil {
+					// Write errors are always fatal, but we can't use asyncClose because we are in a different goroutine. Not
+					// setting pgConn.status or closing pgConn.cleanupDone for the same reason.
+					pgConn.conn.Close()
+
+					copyErrChan <- writeErr
+					return
+				}
+			}
+			if readErr != nil {
+				copyErrChan <- readErr
+				return
+			}
+
+			select {
+			case <-abortCopyChan:
+				return
+			default:
+			}
+		}
+	})
+
+	var pgErr error
+	var copyErr error
+	for copyErr == nil && pgErr == nil {
+		select {
+		case copyErr = <-copyErrChan:
+		case <-signalMessageChan:
+			// If pgConn.receiveMessage encounters an error it will call pgConn.asyncClose. But that is a race condition with
+			// the goroutine. So instead check pgConn.bufferingReceiveErr which will have been set by the signalMessage. If an
+			// error is found then forcibly close the connection without sending the Terminate message.
+			if err := pgConn.bufferingReceiveErr; err != nil {
+				pgConn.status = connStatusClosed
+				pgConn.conn.Close()
+				close(pgConn.cleanupDone)
+				return CommandTag{}, normalizeTimeoutError(ctx, err)
+			}
+			// peekMessage never returns err in the bufferingReceive mode - it only forwards the bufferingReceive variables.
+			// Therefore, the only case for receiveMessage to return err is during handling of the ErrorResponse message type
+			// and using pgOnError handler to determine the connection is no longer valid (and thus closing the conn).
+			msg, serverError := pgConn.receiveMessage()
+			if serverError != nil {
+				close(abortCopyChan)
+				return CommandTag{}, serverError
+			}
+
+			switch msg := msg.(type) {
+			case *pgproto3.ErrorResponse:
+				pgErr = ErrorResponseToPgError(msg)
+			default:
+				signalMessageChan = pgConn.signalMessage()
+			}
+		}
+	}
+	close(abortCopyChan)
+	// Make sure io goroutine finishes before writing.
+	wg.Wait()
+
+	if copyErr == io.EOF || pgErr != nil {
+		pgConn.frontend.Send(&pgproto3.CopyDone{})
+	} else {
+		pgConn.frontend.Send(&pgproto3.CopyFail{Message: copyErr.Error()})
+	}
+	err = pgConn.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		pgConn.asyncClose()
+		return CommandTag{}, err
+	}
+
+	// Read results
+	var commandTag CommandTag
+	for {
+		msg, err := pgConn.receiveMessage()
+		if err != nil {
+			pgConn.asyncClose()
+			return CommandTag{}, normalizeTimeoutError(ctx, err)
+		}
+
+		switch msg := msg.(type) {
+		case *pgproto3.ReadyForQuery:
+			return commandTag, pgErr
+		case *pgproto3.CommandComplete:
+			commandTag = pgConn.makeCommandTag(msg.CommandTag)
+		case *pgproto3.ErrorResponse:
+			pgErr = ErrorResponseToPgError(msg)
+		}
+	}
+}
+
+// MultiResultReader is a reader for a command that could return multiple results such as Exec or ExecBatch.
+type MultiResultReader struct {
+	pgConn *PgConn
+	ctx    context.Context
+
+	rr *ResultReader
+
+	// Data from when the batch was queued.
+	statementDescriptions []*StatementDescription
+	resultFormats         [][]int16
+
+	closed bool
+	err    error
+}
+
+// ReadAll reads all available results. Calling ReadAll is mutually exclusive with all other MultiResultReader methods.
+func (mrr *MultiResultReader) ReadAll() ([]*Result, error) {
+	var results []*Result
+
+	for mrr.NextResult() {
+		results = append(results, mrr.ResultReader().Read())
+	}
+	err := mrr.Close()
+
+	return results, err
+}
+
+func (mrr *MultiResultReader) receiveMessage() (pgproto3.BackendMessage, error) {
+	msg, err := mrr.pgConn.receiveMessage()
+	if err != nil {
+		mrr.pgConn.contextWatcher.Unwatch()
+		mrr.err = normalizeTimeoutError(mrr.ctx, err)
+		mrr.closed = true
+		mrr.pgConn.asyncClose()
+		return nil, mrr.err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.ReadyForQuery:
+		mrr.closed = true
+		mrr.pgConn.contextWatcher.Unwatch()
+		mrr.pgConn.unlock()
+	case *pgproto3.ErrorResponse:
+		mrr.err = ErrorResponseToPgError(msg)
+	}
+
+	return msg, nil
+}
+
+// NextResult returns advances the MultiResultReader to the next result and returns true if a result is available.
+func (mrr *MultiResultReader) NextResult() bool {
+	for !mrr.closed && mrr.err == nil {
+		msg, _ := mrr.pgConn.peekMessage()
+		if _, ok := msg.(*pgproto3.DataRow); ok {
+			if len(mrr.statementDescriptions) > 0 {
+				rr := ResultReader{
+					pgConn:            mrr.pgConn,
+					multiResultReader: mrr,
+					ctx:               mrr.ctx,
+				}
+
+				// This result corresponds to a prepared statement description that was provided when queuing the batch.
+				sd := mrr.statementDescriptions[0]
+				mrr.statementDescriptions = mrr.statementDescriptions[1:]
+
+				resultFormats := mrr.resultFormats[0]
+				mrr.resultFormats = mrr.resultFormats[1:]
+
+				sdFields := sd.Fields
+				rr.fieldDescriptions = rr.pgConn.getFieldDescriptionSlice(len(sdFields))
+
+				err := combineFieldDescriptionsAndResultFormats(rr.fieldDescriptions, sdFields, resultFormats)
+				if err != nil {
+					rr.concludeCommand(CommandTag{}, err)
+				}
+
+				mrr.pgConn.resultReader = rr
+				mrr.rr = &mrr.pgConn.resultReader
+				return true
+			}
+
+			mrr.err = fmt.Errorf("unexpected DataRow message without preceding RowDescription")
+			return false
+		}
+
+		msg, err := mrr.receiveMessage()
+		if err != nil {
+			return false
+		}
+
+		switch msg := msg.(type) {
+		case *pgproto3.RowDescription:
+			mrr.pgConn.resultReader = ResultReader{
+				pgConn:            mrr.pgConn,
+				multiResultReader: mrr,
+				ctx:               mrr.ctx,
+				fieldDescriptions: mrr.pgConn.getFieldDescriptionSlice(len(msg.Fields)),
+			}
+			convertRowDescription(mrr.pgConn.resultReader.fieldDescriptions, msg)
+
+			mrr.rr = &mrr.pgConn.resultReader
+			return true
+		case *pgproto3.CommandComplete:
+			mrr.pgConn.resultReader = ResultReader{
+				commandTag:       mrr.pgConn.makeCommandTag(msg.CommandTag),
+				commandConcluded: true,
+				closed:           true,
+			}
+			mrr.rr = &mrr.pgConn.resultReader
+			return true
+		case *pgproto3.EmptyQueryResponse:
+			mrr.pgConn.resultReader = ResultReader{
+				commandConcluded: true,
+				closed:           true,
+			}
+			mrr.rr = &mrr.pgConn.resultReader
+			return true
+		}
+	}
+
+	return false
+}
+
+// ResultReader returns the current ResultReader.
+func (mrr *MultiResultReader) ResultReader() *ResultReader {
+	return mrr.rr
+}
+
+// Close closes the MultiResultReader and returns the first error that occurred during the MultiResultReader's use.
+func (mrr *MultiResultReader) Close() error {
+	for !mrr.closed {
+		_, err := mrr.receiveMessage()
+		if err != nil {
+			return mrr.err
+		}
+	}
+
+	return mrr.err
+}
+
+// ResultReader is a reader for the result of a single query.
+type ResultReader struct {
+	pgConn            *PgConn
+	multiResultReader *MultiResultReader
+	pipeline          *Pipeline
+	ctx               context.Context
+
+	fieldDescriptions []FieldDescription
+	rowValues         [][]byte
+	commandTag        CommandTag
+	preloaded         bool
+	commandConcluded  bool
+	closed            bool
+	err               error
+}
+
+// Result is the saved query response that is returned by calling Read on a ResultReader.
+type Result struct {
+	FieldDescriptions []FieldDescription
+	Rows              [][][]byte
+	CommandTag        CommandTag
+	Err               error
+}
+
+// Read saves the query response to a Result.
+func (rr *ResultReader) Read() *Result {
+	br := &Result{}
+
+	for rr.NextRow() {
+		if br.FieldDescriptions == nil {
+			br.FieldDescriptions = make([]FieldDescription, len(rr.FieldDescriptions()))
+			copy(br.FieldDescriptions, rr.FieldDescriptions())
+		}
+
+		values := rr.Values()
+		row := make([][]byte, len(values))
+		for i := range row {
+			if values[i] != nil {
+				row[i] = make([]byte, len(values[i]))
+				copy(row[i], values[i])
+			}
+		}
+		br.Rows = append(br.Rows, row)
+	}
+
+	br.CommandTag, br.Err = rr.Close()
+
+	return br
+}
+
+// NextRow advances the ResultReader to the next row and returns true if a row is available.
+func (rr *ResultReader) NextRow() bool {
+	if rr.preloaded {
+		rr.preloaded = false
+		return true
+	}
+
+	for !rr.commandConcluded {
+		msg, err := rr.receiveMessage()
+		if err != nil {
+			return false
+		}
+
+		if msg, ok := msg.(*pgproto3.DataRow); ok {
+			rr.rowValues = msg.Values
+			return true
+		}
+	}
+
+	return false
+}
+
+func (rr *ResultReader) preloadRowValues(values [][]byte) {
+	rr.rowValues = values
+	rr.preloaded = true
+}
+
+// FieldDescriptions returns the field descriptions for the current result set. The returned slice is only valid until
+// the ResultReader is closed. It may return nil (for example, if the query did not return a result set or an error was
+// encountered.)
+func (rr *ResultReader) FieldDescriptions() []FieldDescription {
+	return rr.fieldDescriptions
+}
+
+// Values returns the current row data. NextRow must have been previously been called. The returned [][]byte is only
+// valid until the next NextRow call or the ResultReader is closed.
+func (rr *ResultReader) Values() [][]byte {
+	return rr.rowValues
+}
+
+// Close consumes any remaining result data and returns the command tag or
+// error.
+func (rr *ResultReader) Close() (CommandTag, error) {
+	if rr.closed {
+		return rr.commandTag, rr.err
+	}
+	rr.closed = true
+
+	for !rr.commandConcluded {
+		_, err := rr.receiveMessage()
+		if err != nil {
+			return CommandTag{}, rr.err
+		}
+	}
+
+	if rr.multiResultReader == nil && rr.pipeline == nil {
+		for {
+			msg, err := rr.receiveMessage()
+			if err != nil {
+				return CommandTag{}, rr.err
+			}
+
+			switch msg := msg.(type) {
+			// Detect a deferred constraint violation where the ErrorResponse is sent after CommandComplete.
+			case *pgproto3.ErrorResponse:
+				rr.err = ErrorResponseToPgError(msg)
+			case *pgproto3.ReadyForQuery:
+				rr.pgConn.contextWatcher.Unwatch()
+				rr.pgConn.unlock()
+				return rr.commandTag, rr.err
+			}
+		}
+	}
+
+	return rr.commandTag, rr.err
+}
+
+// readUntilRowDescription ensures the ResultReader's fieldDescriptions are loaded. It does not return an error as any
+// error will be stored in the ResultReader.
+func (rr *ResultReader) readUntilRowDescription(statementDescription *StatementDescription, resultFormats []int16) {
+	for !rr.commandConcluded {
+		msg, _ := rr.receiveMessage()
+		switch msg := msg.(type) {
+		case *pgproto3.RowDescription:
+			return
+		case *pgproto3.DataRow:
+			rr.preloadRowValues(msg.Values)
+			if statementDescription != nil {
+				sdFields := statementDescription.Fields
+				rr.fieldDescriptions = rr.pgConn.getFieldDescriptionSlice(len(sdFields))
+
+				err := combineFieldDescriptionsAndResultFormats(rr.fieldDescriptions, sdFields, resultFormats)
+				if err != nil {
+					rr.concludeCommand(CommandTag{}, err)
+				}
+			}
+			return
+		case *pgproto3.CommandComplete:
+			if statementDescription != nil {
+				sdFields := statementDescription.Fields
+				rr.fieldDescriptions = rr.pgConn.getFieldDescriptionSlice(len(sdFields))
+
+				err := combineFieldDescriptionsAndResultFormats(rr.fieldDescriptions, sdFields, resultFormats)
+				if err != nil {
+					rr.concludeCommand(CommandTag{}, err)
+				}
+			}
+			return
+		}
+	}
+}
+
+func (rr *ResultReader) receiveMessage() (msg pgproto3.BackendMessage, err error) {
+	if rr.multiResultReader == nil {
+		msg, err = rr.pgConn.receiveMessage()
+	} else {
+		msg, err = rr.multiResultReader.receiveMessage()
+	}
+
+	if err != nil {
+		err = normalizeTimeoutError(rr.ctx, err)
+		rr.concludeCommand(CommandTag{}, err)
+		rr.pgConn.contextWatcher.Unwatch()
+		rr.closed = true
+		if rr.multiResultReader == nil {
+			rr.pgConn.asyncClose()
+		}
+
+		return nil, rr.err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.RowDescription:
+		rr.fieldDescriptions = rr.pgConn.getFieldDescriptionSlice(len(msg.Fields))
+		convertRowDescription(rr.fieldDescriptions, msg)
+	case *pgproto3.CommandComplete:
+		rr.concludeCommand(rr.pgConn.makeCommandTag(msg.CommandTag), nil)
+	case *pgproto3.EmptyQueryResponse:
+		rr.concludeCommand(CommandTag{}, nil)
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		if rr.pipeline != nil {
+			rr.pipeline.state.HandleError(pgErr)
+		}
+		rr.concludeCommand(CommandTag{}, pgErr)
+	}
+
+	return msg, nil
+}
+
+func (rr *ResultReader) concludeCommand(commandTag CommandTag, err error) {
+	// Keep the first error that is recorded. Store the error before checking if the command is already concluded to
+	// allow for receiving an error after CommandComplete but before ReadyForQuery.
+	if err != nil && rr.err == nil {
+		rr.err = err
+	}
+
+	if rr.commandConcluded {
+		return
+	}
+
+	rr.commandTag = commandTag
+	rr.rowValues = nil
+	rr.commandConcluded = true
+}
+
+// Batch is a collection of queries that can be sent to the PostgreSQL server in a single round-trip.
+type Batch struct {
+	buf                   []byte
+	statementDescriptions []*StatementDescription
+	resultFormats         [][]int16
+	err                   error
+}
+
+// ExecParams appends an ExecParams command to the batch. See PgConn.ExecParams for parameter descriptions.
+func (batch *Batch) ExecParams(sql string, paramValues [][]byte, paramOIDs []uint32, paramFormats, resultFormats []int16) {
+	if batch.err != nil {
+		return
+	}
+
+	batch.buf, batch.err = (&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs}).Encode(batch.buf)
+	if batch.err != nil {
+		return
+	}
+	batch.ExecPrepared("", paramValues, paramFormats, resultFormats)
+}
+
+// ExecPrepared appends an ExecPrepared e command to the batch. See PgConn.ExecPrepared for parameter descriptions.
+func (batch *Batch) ExecPrepared(stmtName string, paramValues [][]byte, paramFormats, resultFormats []int16) {
+	if batch.err != nil {
+		return
+	}
+
+	batch.buf, batch.err = (&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(batch.buf)
+	if batch.err != nil {
+		return
+	}
+
+	batch.buf, batch.err = (&pgproto3.Describe{ObjectType: 'P'}).Encode(batch.buf)
+	if batch.err != nil {
+		return
+	}
+
+	batch.buf, batch.err = (&pgproto3.Execute{}).Encode(batch.buf)
+	if batch.err != nil {
+		return
+	}
+}
+
+// ExecStatement appends an ExecStatement command to the batch. See PgConn.ExecPrepared for parameter descriptions.
+//
+// This differs from ExecPrepared in that it takes a *StatementDescription instead of just the prepared statement name.
+// Because it has the *StatementDescription it can avoid the Describe Portal message that ExecPrepared must send to get
+// the result column descriptions.
+func (batch *Batch) ExecStatement(statementDescription *StatementDescription, paramValues [][]byte, paramFormats, resultFormats []int16) {
+	if batch.err != nil {
+		return
+	}
+
+	batch.buf, batch.err = (&pgproto3.Bind{PreparedStatement: statementDescription.Name, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(batch.buf)
+	if batch.err != nil {
+		return
+	}
+
+	batch.statementDescriptions = append(batch.statementDescriptions, statementDescription)
+	batch.resultFormats = append(batch.resultFormats, resultFormats)
+
+	batch.buf, batch.err = (&pgproto3.Execute{}).Encode(batch.buf)
+	if batch.err != nil {
+		return
+	}
+}
+
+// ExecBatch executes all the queries in batch in a single round-trip. Execution is implicitly transactional unless a
+// transaction is already in progress or SQL contains transaction control statements. This is a simpler way of executing
+// multiple queries in a single round trip than using pipeline mode.
+func (pgConn *PgConn) ExecBatch(ctx context.Context, batch *Batch) *MultiResultReader {
+	if batch.err != nil {
+		return &MultiResultReader{
+			closed: true,
+			err:    batch.err,
+		}
+	}
+
+	if err := pgConn.lock(); err != nil {
+		return &MultiResultReader{
+			closed: true,
+			err:    err,
+		}
+	}
+
+	pgConn.multiResultReader = MultiResultReader{
+		pgConn:                pgConn,
+		ctx:                   ctx,
+		statementDescriptions: batch.statementDescriptions,
+		resultFormats:         batch.resultFormats,
+	}
+	multiResult := &pgConn.multiResultReader
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			multiResult.closed = true
+			multiResult.err = newContextAlreadyDoneError(ctx)
+			pgConn.unlock()
+			return multiResult
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+	}
+
+	batch.buf, batch.err = (&pgproto3.Sync{}).Encode(batch.buf)
+	if batch.err != nil {
+		pgConn.contextWatcher.Unwatch()
+		multiResult.err = normalizeTimeoutError(multiResult.ctx, batch.err)
+		multiResult.closed = true
+		pgConn.asyncClose()
+		return multiResult
+	}
+
+	_, err := func(buf []byte) (int, error) {
+		pgConn.enterPotentialWriteReadDeadlock()
+		defer pgConn.exitPotentialWriteReadDeadlock()
+		return pgConn.conn.Write(buf)
+	}(batch.buf)
+	if err != nil {
+		pgConn.contextWatcher.Unwatch()
+		multiResult.err = normalizeTimeoutError(multiResult.ctx, err)
+		multiResult.closed = true
+		pgConn.asyncClose()
+		return multiResult
+	}
+
+	return multiResult
+}
+
+// EscapeString escapes a string such that it can safely be interpolated into a SQL command string. It does not include
+// the surrounding single quotes.
+//
+// The current implementation requires that standard_conforming_strings=on and client_encoding="UTF8". If these
+// conditions are not met an error will be returned. It is possible these restrictions will be lifted in the future.
+func (pgConn *PgConn) EscapeString(s string) (string, error) {
+	if pgConn.ParameterStatus("standard_conforming_strings") != "on" {
+		return "", errors.New("EscapeString must be run with standard_conforming_strings=on")
+	}
+
+	if pgConn.ParameterStatus("client_encoding") != "UTF8" {
+		return "", errors.New("EscapeString must be run with client_encoding=UTF8")
+	}
+
+	return strings.ReplaceAll(s, "'", "''"), nil
+}
+
+// CheckConn checks the underlying connection without writing any bytes. This is currently implemented by doing a read
+// with a very short deadline. This can be useful because a TCP connection can be broken such that a write will appear
+// to succeed even though it will never actually reach the server. Reading immediately before a write will detect this
+// condition. If this is done immediately before sending a query it reduces the chances a query will be sent that fails
+// without the client knowing whether the server received it or not.
+//
+// Deprecated: CheckConn is deprecated in favor of Ping. CheckConn cannot detect all types of broken connections where
+// the write would still appear to succeed. Prefer Ping unless on a high latency connection.
+func (pgConn *PgConn) CheckConn() error {
+	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
+	defer cancel()
+
+	_, err := pgConn.ReceiveMessage(ctx)
+	if err != nil {
+		if !Timeout(err) {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// Ping pings the server. This can be useful because a TCP connection can be broken such that a write will appear to
+// succeed even though it will never actually reach the server. Pinging immediately before sending a query reduces the
+// chances a query will be sent that fails without the client knowing whether the server received it or not.
+func (pgConn *PgConn) Ping(ctx context.Context) error {
+	return pgConn.Exec(ctx, "-- ping").Close()
+}
+
+// makeCommandTag makes a CommandTag. It does not retain a reference to buf or buf's underlying memory.
+func (pgConn *PgConn) makeCommandTag(buf []byte) CommandTag {
+	return CommandTag{s: string(buf)}
+}
+
+// enterPotentialWriteReadDeadlock must be called before a write that could deadlock if the server is simultaneously
+// blocked writing to us.
+func (pgConn *PgConn) enterPotentialWriteReadDeadlock() {
+	// The time to wait is somewhat arbitrary. A Write should only take as long as the syscall and memcpy to the OS
+	// outbound network buffer unless the buffer is full (which potentially is a block). It needs to be long enough for
+	// the normal case, but short enough not to kill performance if a block occurs.
+	//
+	// In addition, on Windows the default timer resolution is 15.6ms. So setting the timer to less than that is
+	// ineffective.
+	if pgConn.slowWriteTimer.Reset(15 * time.Millisecond) {
+		panic("BUG: slow write timer already active")
+	}
+}
+
+// exitPotentialWriteReadDeadlock must be called after a call to enterPotentialWriteReadDeadlock.
+func (pgConn *PgConn) exitPotentialWriteReadDeadlock() {
+	if !pgConn.slowWriteTimer.Stop() {
+		// The timer starts its function in a separate goroutine. It is necessary to ensure the background reader has
+		// started before calling Stop. Otherwise, the background reader may not be stopped. That on its own is not a
+		// serious problem. But what is a serious problem is that the background reader may start at an inopportune time in
+		// a subsequent query. For example, if a subsequent query was canceled then a deadline may be set on the net.Conn to
+		// interrupt an in-progress read. After the read is interrupted, but before the deadline is cleared, the background
+		// reader could start and read a deadline error. Then the next query would receive the an unexpected deadline error.
+		<-pgConn.bgReaderStarted
+		pgConn.bgReader.Stop()
+	}
+}
+
+func (pgConn *PgConn) flushWithPotentialWriteReadDeadlock() error {
+	pgConn.enterPotentialWriteReadDeadlock()
+	defer pgConn.exitPotentialWriteReadDeadlock()
+	err := pgConn.frontend.Flush()
+	return err
+}
+
+// SyncConn prepares the underlying net.Conn for direct use. PgConn may internally buffer reads or use goroutines for
+// background IO. This means that any direct use of the underlying net.Conn may be corrupted if a read is already
+// buffered or a read is in progress. SyncConn drains read buffers and stops background IO. In some cases this may
+// require sending a ping to the server. ctx can be used to cancel this operation. This should be called before any
+// operation that will use the underlying net.Conn directly. e.g. Before Conn() or Hijack().
+//
+// This should not be confused with the PostgreSQL protocol Sync message.
+func (pgConn *PgConn) SyncConn(ctx context.Context) error {
+	for range 10 {
+		if pgConn.bgReader.Status() == bgreader.StatusStopped && pgConn.frontend.ReadBufferLen() == 0 {
+			return nil
+		}
+
+		err := pgConn.Ping(ctx)
+		if err != nil {
+			return fmt.Errorf("SyncConn: Ping failed while syncing conn: %w", err)
+		}
+	}
+
+	// This should never happen. Only way I can imagine this occurring is if the server is constantly sending data such as
+	// LISTEN/NOTIFY or log notifications such that we never can get an empty buffer.
+	return errors.New("SyncConn: conn never synchronized")
+}
+
+// CustomData returns a map that can be used to associate custom data with the connection.
+func (pgConn *PgConn) CustomData() map[string]any {
+	return pgConn.customData
+}
+
+// HijackedConn is the result of hijacking a connection.
+//
+// Due to the necessary exposure of internal implementation details, it is not covered by the semantic versioning
+// compatibility.
+type HijackedConn struct {
+	Conn              net.Conn
+	TLSConfig         *tls.Config       // tls.Config that Conn was negotiated with; nil if Conn is not TLS
+	PID               uint32            // backend pid
+	SecretKey         []byte            // key to use to send a cancel query message to the server
+	ParameterStatuses map[string]string // parameters that have been reported by the server
+	TxStatus          byte
+	Frontend          *pgproto3.Frontend
+	Config            *Config
+	CustomData        map[string]any
+}
+
+// Hijack extracts the internal connection data. pgConn must be in an idle state. SyncConn should be called immediately
+// before Hijack. pgConn is unusable after hijacking. Hijacking is typically only useful when using pgconn to establish
+// a connection, but taking complete control of the raw connection after that (e.g. a load balancer or proxy).
+//
+// Due to the necessary exposure of internal implementation details, it is not covered by the semantic versioning
+// compatibility.
+func (pgConn *PgConn) Hijack() (*HijackedConn, error) {
+	if err := pgConn.lock(); err != nil {
+		return nil, err
+	}
+	pgConn.status = connStatusClosed
+
+	return &HijackedConn{
+		Conn:              pgConn.conn,
+		TLSConfig:         pgConn.tlsConfig,
+		PID:               pgConn.pid,
+		SecretKey:         pgConn.secretKey,
+		ParameterStatuses: pgConn.parameterStatuses,
+		TxStatus:          pgConn.txStatus,
+		Frontend:          pgConn.frontend,
+		Config:            pgConn.config,
+		CustomData:        pgConn.customData,
+	}, nil
+}
+
+// Construct created a PgConn from an already established connection to a PostgreSQL server. This is the inverse of
+// PgConn.Hijack. The connection must be in an idle state.
+//
+// hc.Frontend is replaced by a new pgproto3.Frontend built by hc.Config.BuildFrontend.
+//
+// Due to the necessary exposure of internal implementation details, it is not covered by the semantic versioning
+// compatibility.
+func Construct(hc *HijackedConn) (*PgConn, error) {
+	pgConn := &PgConn{
+		conn:              hc.Conn,
+		tlsConfig:         hc.TLSConfig,
+		pid:               hc.PID,
+		secretKey:         hc.SecretKey,
+		parameterStatuses: hc.ParameterStatuses,
+		txStatus:          hc.TxStatus,
+		frontend:          hc.Frontend,
+		config:            hc.Config,
+		customData:        hc.CustomData,
+
+		status: connStatusIdle,
+
+		cleanupDone: make(chan struct{}),
+	}
+
+	pgConn.contextWatcher = ctxwatch.NewContextWatcher(hc.Config.BuildContextWatcherHandler(pgConn))
+	pgConn.bgReader = bgreader.New(pgConn.conn)
+	pgConn.slowWriteTimer = time.AfterFunc(time.Duration(math.MaxInt64),
+		func() {
+			pgConn.bgReader.Start()
+			pgConn.bgReaderStarted <- struct{}{}
+		},
+	)
+	pgConn.slowWriteTimer.Stop()
+	pgConn.bgReaderStarted = make(chan struct{})
+	pgConn.frontend = hc.Config.BuildFrontend(pgConn.bgReader, pgConn.conn)
+
+	return pgConn, nil
+}
+
+// Pipeline represents a connection in pipeline mode.
+//
+// SendPrepare, SendQueryParams, SendQueryPrepared, and SendQueryStatement queue requests to the server. These requests
+// are not written until pipeline is flushed by Flush or Sync. Sync must be called after the last request is queued.
+// Requests between synchronization points are implicitly transactional unless explicit transaction control statements
+// have been issued.
+//
+// The context the pipeline was started with is in effect for the entire life of the Pipeline.
+//
+// For a deeper understanding of pipeline mode see the PostgreSQL documentation for the extended query protocol
+// (https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY) and the libpq pipeline mode
+// (https://www.postgresql.org/docs/current/libpq-pipeline-mode.html).
+type Pipeline struct {
+	conn *PgConn
+	ctx  context.Context
+
+	state  pipelineState
+	err    error
+	closed bool
+}
+
+// PipelineSync is returned by GetResults when a ReadyForQuery message is received.
+type PipelineSync struct{}
+
+// CloseComplete is returned by GetResults when a CloseComplete message is received.
+type CloseComplete struct{}
+
+type pipelineRequestType int
+
+const (
+	pipelineNil pipelineRequestType = iota
+	pipelinePrepare
+	pipelineQueryParams
+	pipelineQueryPrepared
+	pipelineQueryStatement
+	pipelineDeallocate
+	pipelineSyncRequest
+	pipelineFlushRequest
+)
+
+type pipelineRequestEvent struct {
+	RequestType       pipelineRequestType
+	WasSentToServer   bool
+	BeforeFlushOrSync bool
+}
+
+type pipelineState struct {
+	requestEventQueue          list.List
+	statementDescriptionsQueue list.List
+	resultFormatsQueue         list.List
+	lastRequestType            pipelineRequestType
+	pgErr                      *PgError
+	expectedReadyForQueryCount int
+}
+
+func (s *pipelineState) Init() {
+	s.requestEventQueue.Init()
+	s.statementDescriptionsQueue.Init()
+	s.resultFormatsQueue.Init()
+	s.lastRequestType = pipelineNil
+}
+
+func (s *pipelineState) RegisterSendingToServer() {
+	for elem := s.requestEventQueue.Back(); elem != nil; elem = elem.Prev() {
+		val := elem.Value.(pipelineRequestEvent)
+		if val.WasSentToServer {
+			return
+		}
+		val.WasSentToServer = true
+		elem.Value = val
+	}
+}
+
+func (s *pipelineState) registerFlushingBufferOnServer() {
+	for elem := s.requestEventQueue.Back(); elem != nil; elem = elem.Prev() {
+		val := elem.Value.(pipelineRequestEvent)
+		if val.BeforeFlushOrSync {
+			return
+		}
+		val.BeforeFlushOrSync = true
+		elem.Value = val
+	}
+}
+
+func (s *pipelineState) PushBackRequestType(req pipelineRequestType) {
+	if req == pipelineNil {
+		return
+	}
+
+	if req != pipelineFlushRequest {
+		s.requestEventQueue.PushBack(pipelineRequestEvent{RequestType: req})
+	}
+	if req == pipelineFlushRequest || req == pipelineSyncRequest {
+		s.registerFlushingBufferOnServer()
+	}
+	s.lastRequestType = req
+
+	if req == pipelineSyncRequest {
+		s.expectedReadyForQueryCount++
+	}
+}
+
+func (s *pipelineState) ExtractFrontRequestType() pipelineRequestType {
+	for {
+		elem := s.requestEventQueue.Front()
+		if elem == nil {
+			return pipelineNil
+		}
+		val := elem.Value.(pipelineRequestEvent)
+		if !(val.WasSentToServer && val.BeforeFlushOrSync) {
+			return pipelineNil
+		}
+
+		s.requestEventQueue.Remove(elem)
+		if val.RequestType == pipelineSyncRequest {
+			s.pgErr = nil
+		}
+		if s.pgErr == nil {
+			return val.RequestType
+		}
+	}
+}
+
+func (s *pipelineState) PushBackStatementData(sd *StatementDescription, resultFormats []int16) {
+	s.statementDescriptionsQueue.PushBack(sd)
+	s.resultFormatsQueue.PushBack(resultFormats)
+}
+
+func (s *pipelineState) ExtractFrontStatementData() (*StatementDescription, []int16) {
+	sdElem := s.statementDescriptionsQueue.Front()
+	var sd *StatementDescription
+	if sdElem != nil {
+		s.statementDescriptionsQueue.Remove(sdElem)
+		sd = sdElem.Value.(*StatementDescription)
+	}
+
+	rfElem := s.resultFormatsQueue.Front()
+	var resultFormats []int16
+	if rfElem != nil {
+		s.resultFormatsQueue.Remove(rfElem)
+		resultFormats = rfElem.Value.([]int16)
+	}
+
+	return sd, resultFormats
+}
+
+func (s *pipelineState) HandleError(err *PgError) {
+	s.pgErr = err
+}
+
+func (s *pipelineState) HandleReadyForQuery() {
+	s.expectedReadyForQueryCount--
+}
+
+func (s *pipelineState) PendingSync() bool {
+	var notPendingSync bool
+
+	if elem := s.requestEventQueue.Back(); elem != nil {
+		val := elem.Value.(pipelineRequestEvent)
+		notPendingSync = (val.RequestType == pipelineSyncRequest) && val.WasSentToServer
+	} else {
+		notPendingSync = (s.lastRequestType == pipelineSyncRequest) || (s.lastRequestType == pipelineNil)
+	}
+
+	return !notPendingSync
+}
+
+func (s *pipelineState) ExpectedReadyForQuery() int {
+	return s.expectedReadyForQueryCount
+}
+
+// StartPipeline switches the connection to pipeline mode and returns a *Pipeline. In pipeline mode requests can be sent
+// to the server without waiting for a response. Close must be called on the returned *Pipeline to return the connection
+// to normal mode. While in pipeline mode, no methods that communicate with the server may be called except
+// CancelRequest and Close. ctx is in effect for entire life of the *Pipeline.
+//
+// Prefer ExecBatch when only sending one group of queries at once.
+func (pgConn *PgConn) StartPipeline(ctx context.Context) *Pipeline {
+	if err := pgConn.lock(); err != nil {
+		pipeline := &Pipeline{
+			closed: true,
+			err:    err,
+		}
+		pipeline.state.Init()
+
+		return pipeline
+	}
+
+	pgConn.resultReader = ResultReader{closed: true}
+
+	pgConn.pipeline = Pipeline{
+		conn: pgConn,
+		ctx:  ctx,
+	}
+	pgConn.pipeline.state.Init()
+
+	pipeline := &pgConn.pipeline
+
+	if ctx != context.Background() {
+		select {
+		case <-ctx.Done():
+			pipeline.closed = true
+			pipeline.err = newContextAlreadyDoneError(ctx)
+			pgConn.unlock()
+			return pipeline
+		default:
+		}
+		pgConn.contextWatcher.Watch(ctx)
+	}
+
+	return pipeline
+}
+
+// SendPrepare is the pipeline version of *PgConn.Prepare.
+func (p *Pipeline) SendPrepare(name, sql string, paramOIDs []uint32) {
+	if p.closed {
+		return
+	}
+
+	p.conn.frontend.SendParse(&pgproto3.Parse{Name: name, Query: sql, ParameterOIDs: paramOIDs})
+	p.conn.frontend.SendDescribe(&pgproto3.Describe{ObjectType: 'S', Name: name})
+	p.state.PushBackRequestType(pipelinePrepare)
+}
+
+// SendDeallocate deallocates a prepared statement.
+func (p *Pipeline) SendDeallocate(name string) {
+	if p.closed {
+		return
+	}
+
+	p.conn.frontend.SendClose(&pgproto3.Close{ObjectType: 'S', Name: name})
+	p.state.PushBackRequestType(pipelineDeallocate)
+}
+
+// SendQueryParams is the pipeline version of *PgConn.ExecParams.
+func (p *Pipeline) SendQueryParams(sql string, paramValues [][]byte, paramOIDs []uint32, paramFormats, resultFormats []int16) {
+	if p.closed {
+		return
+	}
+
+	p.conn.frontend.SendParse(&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs})
+	p.conn.frontend.SendBind(&pgproto3.Bind{ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats})
+	p.conn.frontend.SendDescribe(&pgproto3.Describe{ObjectType: 'P'})
+	p.conn.frontend.SendExecute(&pgproto3.Execute{})
+	p.state.PushBackRequestType(pipelineQueryParams)
+}
+
+// SendQueryPrepared is the pipeline version of *PgConn.ExecPrepared.
+func (p *Pipeline) SendQueryPrepared(stmtName string, paramValues [][]byte, paramFormats, resultFormats []int16) {
+	if p.closed {
+		return
+	}
+
+	p.conn.frontend.SendBind(&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats})
+	p.conn.frontend.SendDescribe(&pgproto3.Describe{ObjectType: 'P'})
+	p.conn.frontend.SendExecute(&pgproto3.Execute{})
+	p.state.PushBackRequestType(pipelineQueryPrepared)
+}
+
+// SendQueryStatement is the pipeline version of *PgConn.ExecStatement.
+func (p *Pipeline) SendQueryStatement(statementDescription *StatementDescription, paramValues [][]byte, paramFormats, resultFormats []int16) {
+	if p.closed {
+		return
+	}
+
+	p.conn.frontend.SendBind(&pgproto3.Bind{PreparedStatement: statementDescription.Name, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats})
+	p.conn.frontend.SendExecute(&pgproto3.Execute{})
+	p.state.PushBackRequestType(pipelineQueryStatement)
+	p.state.PushBackStatementData(statementDescription, resultFormats)
+}
+
+// SendFlushRequest sends a request for the server to flush its output buffer.
+//
+// The server flushes its output buffer automatically as a result of Sync being called,
+// or on any request when not in pipeline mode; this function is useful to cause the server
+// to flush its output buffer in pipeline mode without establishing a synchronization point.
+// Note that the request is not itself flushed to the server automatically; use Flush if
+// necessary. This copies the behavior of libpq PQsendFlushRequest.
+func (p *Pipeline) SendFlushRequest() {
+	if p.closed {
+		return
+	}
+
+	p.conn.frontend.Send(&pgproto3.Flush{})
+	p.state.PushBackRequestType(pipelineFlushRequest)
+}
+
+// SendPipelineSync marks a synchronization point in a pipeline by sending a sync message
+// without flushing the send buffer. This serves as the delimiter of an implicit
+// transaction and an error recovery point.
+//
+// Note that the request is not itself flushed to the server automatically; use Flush if
+// necessary. This copies the behavior of libpq PQsendPipelineSync.
+func (p *Pipeline) SendPipelineSync() {
+	if p.closed {
+		return
+	}
+
+	p.conn.frontend.SendSync(&pgproto3.Sync{})
+	p.state.PushBackRequestType(pipelineSyncRequest)
+}
+
+// Flush flushes the queued requests without establishing a synchronization point.
+func (p *Pipeline) Flush() error {
+	if p.closed {
+		if p.err != nil {
+			return p.err
+		}
+		return errors.New("pipeline closed")
+	}
+
+	err := p.conn.flushWithPotentialWriteReadDeadlock()
+	if err != nil {
+		err = normalizeTimeoutError(p.ctx, err)
+
+		p.conn.asyncClose()
+
+		p.conn.contextWatcher.Unwatch()
+		p.conn.unlock()
+		p.closed = true
+		p.err = err
+		return err
+	}
+
+	p.state.RegisterSendingToServer()
+	return nil
+}
+
+// Sync establishes a synchronization point and flushes the queued requests.
+func (p *Pipeline) Sync() error {
+	p.SendPipelineSync()
+	return p.Flush()
+}
+
+// GetResults gets the next results. If results are present, results may be a *ResultReader, *StatementDescription, or
+// *PipelineSync. If an ErrorResponse is received from the server, results will be nil and err will be a *PgError. If no
+// results are available, results and err will both be nil.
+func (p *Pipeline) GetResults() (results any, err error) {
+	if p.closed {
+		if p.err != nil {
+			return nil, p.err
+		}
+		return nil, errors.New("pipeline closed")
+	}
+
+	return p.getResults()
+}
+
+func (p *Pipeline) getResults() (results any, err error) {
+	if !p.conn.resultReader.closed {
+		_, err := p.conn.resultReader.Close()
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	currentRequestType := p.state.ExtractFrontRequestType()
+	switch currentRequestType {
+	case pipelineNil:
+		return nil, nil
+	case pipelinePrepare:
+		return p.getResultsPrepare()
+	case pipelineQueryParams:
+		return p.getResultsQueryParams()
+	case pipelineQueryPrepared:
+		return p.getResultsQueryPrepared()
+	case pipelineQueryStatement:
+		return p.getResultsQueryStatement()
+	case pipelineDeallocate:
+		return p.getResultsDeallocate()
+	case pipelineSyncRequest:
+		return p.getResultsSync()
+	case pipelineFlushRequest:
+		return nil, errors.New("BUG: pipelineFlushRequest should not be in request queue")
+	default:
+		return nil, errors.New("BUG: unknown pipeline request type")
+	}
+}
+
+func (p *Pipeline) getResultsPrepare() (*StatementDescription, error) {
+	err := p.receiveParseComplete("Prepare")
+	if err != nil {
+		return nil, err
+	}
+
+	psd := &StatementDescription{}
+
+	msg, err := p.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.ParameterDescription:
+		psd.ParamOIDs = make([]uint32, len(msg.ParameterOIDs))
+		copy(psd.ParamOIDs, msg.ParameterOIDs)
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		return nil, pgErr
+	default:
+		return nil, p.handleUnexpectedMessage("Prepare ParameterDescription", msg)
+	}
+
+	msg, err = p.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.RowDescription:
+		psd.Fields = make([]FieldDescription, len(msg.Fields))
+		convertRowDescription(psd.Fields, msg)
+		return psd, nil
+
+	// NoData is returned instead of RowDescription when there is no expected result. e.g. An INSERT without a RETURNING
+	// clause.
+	case *pgproto3.NoData:
+		return psd, nil
+
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		return nil, pgErr
+	default:
+		return nil, p.handleUnexpectedMessage("Prepare RowDescription", msg)
+	}
+}
+
+func (p *Pipeline) getResultsQueryParams() (*ResultReader, error) {
+	err := p.receiveParseComplete("QueryParams")
+	if err != nil {
+		return nil, err
+	}
+
+	err = p.receiveBindComplete("QueryParams")
+	if err != nil {
+		return nil, err
+	}
+
+	return p.receiveDescribedResultReader("QueryParams")
+}
+
+func (p *Pipeline) getResultsQueryPrepared() (*ResultReader, error) {
+	err := p.receiveBindComplete("QueryPrepared")
+	if err != nil {
+		return nil, err
+	}
+
+	return p.receiveDescribedResultReader("QueryPrepared")
+}
+
+func (p *Pipeline) getResultsQueryStatement() (*ResultReader, error) {
+	err := p.receiveBindComplete("QueryStatement")
+	if err != nil {
+		return nil, err
+	}
+
+	msg, err := p.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+
+	sd, resultFormats := p.state.ExtractFrontStatementData()
+	if sd == nil {
+		return nil, errors.New("BUG: missing statement description or result formats for QueryStatement")
+	}
+	sdFields := sd.Fields
+	fieldDescriptions := p.conn.getFieldDescriptionSlice(len(sdFields))
+	err = combineFieldDescriptionsAndResultFormats(fieldDescriptions, sdFields, resultFormats)
+	if err != nil {
+		return nil, err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.DataRow:
+		rr := ResultReader{
+			pgConn:            p.conn,
+			pipeline:          p,
+			ctx:               p.ctx,
+			fieldDescriptions: fieldDescriptions,
+		}
+		rr.preloadRowValues(msg.Values)
+		p.conn.resultReader = rr
+		return &p.conn.resultReader, nil
+	case *pgproto3.CommandComplete:
+		p.conn.resultReader = ResultReader{
+			commandTag:        p.conn.makeCommandTag(msg.CommandTag),
+			commandConcluded:  true,
+			closed:            true,
+			fieldDescriptions: fieldDescriptions,
+		}
+		return &p.conn.resultReader, nil
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		p.conn.resultReader.closed = true
+		return nil, pgErr
+	default:
+		return nil, p.handleUnexpectedMessage("QueryStatement", msg)
+	}
+}
+
+func (p *Pipeline) getResultsDeallocate() (*CloseComplete, error) {
+	msg, err := p.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.CloseComplete:
+		return &CloseComplete{}, nil
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		p.conn.resultReader.closed = true
+		return nil, pgErr
+	default:
+		return nil, p.handleUnexpectedMessage("Deallocate", msg)
+	}
+}
+
+func (p *Pipeline) getResultsSync() (*PipelineSync, error) {
+	msg, err := p.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.ReadyForQuery:
+		p.state.HandleReadyForQuery()
+		return &PipelineSync{}, nil
+	case *pgproto3.ErrorResponse:
+		// Error message that is received while expecting a Sync message still consumes the expected Sync. Put it back.
+		p.state.requestEventQueue.PushFront(pipelineRequestEvent{RequestType: pipelineSyncRequest, WasSentToServer: true, BeforeFlushOrSync: true})
+
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		p.conn.resultReader.closed = true
+		return nil, pgErr
+	default:
+		return nil, p.handleUnexpectedMessage("Sync", msg)
+	}
+}
+
+func (p *Pipeline) receiveParseComplete(errStr string) error {
+	msg, err := p.receiveMessage()
+	if err != nil {
+		return err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.ParseComplete:
+		return nil
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		return pgErr
+	default:
+		return p.handleUnexpectedMessage(fmt.Sprintf("%s Parse", errStr), msg)
+	}
+}
+
+func (p *Pipeline) receiveBindComplete(errStr string) error {
+	msg, err := p.receiveMessage()
+	if err != nil {
+		return err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.BindComplete:
+		return nil
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		return pgErr
+	default:
+		return p.handleUnexpectedMessage(fmt.Sprintf("%s Bind", errStr), msg)
+	}
+}
+
+func (p *Pipeline) receiveDescribedResultReader(errStr string) (*ResultReader, error) {
+	msg, err := p.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.RowDescription:
+		p.conn.resultReader = ResultReader{
+			pgConn:            p.conn,
+			pipeline:          p,
+			ctx:               p.ctx,
+			fieldDescriptions: p.conn.getFieldDescriptionSlice(len(msg.Fields)),
+		}
+		convertRowDescription(p.conn.resultReader.fieldDescriptions, msg)
+		return &p.conn.resultReader, nil
+	case *pgproto3.NoData:
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		p.conn.resultReader.closed = true
+		return nil, pgErr
+	default:
+		return nil, p.handleUnexpectedMessage(fmt.Sprintf("%s RowDescription or NoData", errStr), msg)
+	}
+
+	msg, err = p.receiveMessage()
+	if err != nil {
+		return nil, err
+	}
+
+	switch msg := msg.(type) {
+	case *pgproto3.CommandComplete:
+		p.conn.resultReader = ResultReader{
+			commandTag:       p.conn.makeCommandTag(msg.CommandTag),
+			commandConcluded: true,
+			closed:           true,
+		}
+		return &p.conn.resultReader, nil
+	case *pgproto3.ErrorResponse:
+		pgErr := ErrorResponseToPgError(msg)
+		p.state.HandleError(pgErr)
+		p.conn.resultReader.closed = true
+		return nil, pgErr
+	default:
+		return nil, p.handleUnexpectedMessage(fmt.Sprintf("%s CommandComplete", errStr), msg)
+	}
+}
+
+func (p *Pipeline) receiveMessage() (pgproto3.BackendMessage, error) {
+	for {
+		msg, err := p.conn.receiveMessage()
+		if err != nil {
+			p.err = err
+			p.conn.asyncClose()
+			return nil, normalizeTimeoutError(p.ctx, err)
+		}
+
+		switch msg := msg.(type) {
+		case *pgproto3.ParameterStatus, *pgproto3.NoticeResponse, *pgproto3.NotificationResponse:
+			// Filter these message types out in pipeline mode. The normal processing is handled by PgConn.receiveMessage.
+		default:
+			return msg, nil
+		}
+	}
+}
+
+func (p *Pipeline) handleUnexpectedMessage(errStr string, msg pgproto3.BackendMessage) error {
+	p.err = fmt.Errorf("pipeline: %s: received unexpected message type %T", errStr, msg)
+	p.conn.asyncClose()
+	return p.err
+}
+
+// Close closes the pipeline and returns the connection to normal mode.
+func (p *Pipeline) Close() error {
+	if p.closed {
+		return p.err
+	}
+
+	p.closed = true
+
+	if p.state.PendingSync() {
+		p.conn.asyncClose()
+		p.err = errors.New("pipeline has unsynced requests")
+		p.conn.contextWatcher.Unwatch()
+		p.conn.unlock()
+
+		return p.err
+	}
+
+	for p.state.ExpectedReadyForQuery() > 0 {
+		results, err := p.getResults()
+		if err != nil {
+			p.err = err
+			var pgErr *PgError
+			if !errors.As(err, &pgErr) {
+				p.conn.asyncClose()
+				break
+			}
+		} else if results == nil {
+			// getResults returns (nil, nil) when the request queue is exhausted but
+			// ExpectedReadyForQuery is still > 0. This can happen when FATAL errors consume
+			// queued request slots without the server ever sending ReadyForQuery.
+			p.conn.asyncClose()
+			if p.err == nil {
+				p.err = errors.New("pipeline: no more results but expected ReadyForQuery")
+			}
+			break
+		}
+	}
+
+	p.conn.contextWatcher.Unwatch()
+	p.conn.unlock()
+
+	return p.err
+}
+
+// DeadlineContextWatcherHandler handles canceled contexts by setting a deadline on a net.Conn.
+type DeadlineContextWatcherHandler struct {
+	Conn net.Conn
+
+	// DeadlineDelay is the delay to set on the deadline set on net.Conn when the context is canceled.
+	DeadlineDelay time.Duration
+}
+
+func (h *DeadlineContextWatcherHandler) HandleCancel(ctx context.Context) {
+	h.Conn.SetDeadline(time.Now().Add(h.DeadlineDelay))
+}
+
+func (h *DeadlineContextWatcherHandler) HandleUnwatchAfterCancel() {
+	h.Conn.SetDeadline(time.Time{})
+}
+
+// CancelRequestContextWatcherHandler handles canceled contexts by sending a cancel request to the server. It also sets
+// a deadline on a net.Conn as a fallback.
+type CancelRequestContextWatcherHandler struct {
+	Conn *PgConn
+
+	// CancelRequestDelay is the delay before sending the cancel request to the server.
+	CancelRequestDelay time.Duration
+
+	// DeadlineDelay is the delay to set on the deadline set on net.Conn when the context is canceled.
+	DeadlineDelay time.Duration
+
+	cancelFinishedChan             chan struct{}
+	handleUnwatchAfterCancelCalled func()
+}
+
+func (h *CancelRequestContextWatcherHandler) HandleCancel(context.Context) {
+	h.cancelFinishedChan = make(chan struct{})
+	var handleUnwatchedAfterCancelCalledCtx context.Context
+	handleUnwatchedAfterCancelCalledCtx, h.handleUnwatchAfterCancelCalled = context.WithCancel(context.Background())
+
+	deadline := time.Now().Add(h.DeadlineDelay)
+	h.Conn.conn.SetDeadline(deadline)
+
+	go func() {
+		defer close(h.cancelFinishedChan)
+
+		select {
+		case <-handleUnwatchedAfterCancelCalledCtx.Done():
+			return
+		case <-time.After(h.CancelRequestDelay):
+		}
+
+		cancelRequestCtx, cancel := context.WithDeadline(handleUnwatchedAfterCancelCalledCtx, deadline)
+		defer cancel()
+		h.Conn.CancelRequest(cancelRequestCtx)
+
+		// CancelRequest is inherently racy. Even though the cancel request has been received by the server at this point,
+		// it hasn't necessarily been delivered to the other connection. If we immediately return and the connection is
+		// immediately used then it is possible the CancelRequest will actually cancel our next query. The
+		// TestCancelRequestContextWatcherHandler Stress test can produce this error without the sleep below. The sleep time
+		// is arbitrary, but should be sufficient to prevent this error case.
+		time.Sleep(100 * time.Millisecond)
+	}()
+}
+
+func (h *CancelRequestContextWatcherHandler) HandleUnwatchAfterCancel() {
+	h.handleUnwatchAfterCancelCalled()
+	<-h.cancelFinishedChan
+
+	h.Conn.conn.SetDeadline(time.Time{})
+}
+
+func combineFieldDescriptionsAndResultFormats(outputFields, inputFields []FieldDescription, resultFormats []int16) error {
+	switch {
+	case len(resultFormats) == 0:
+		// No format codes provided means text format for all columns.
+		for i := range inputFields {
+			outputFields[i] = inputFields[i]
+			outputFields[i].Format = pgtype.TextFormatCode
+		}
+	case len(resultFormats) == 1:
+		// Single format code applies to all columns.
+		format := resultFormats[0]
+		for i := range inputFields {
+			outputFields[i] = inputFields[i]
+			outputFields[i].Format = format
+		}
+	case len(resultFormats) == len(inputFields):
+		// One format code per column.
+		for i := range inputFields {
+			outputFields[i] = inputFields[i]
+			outputFields[i].Format = resultFormats[i]
+		}
+	default:
+		// This should not occur if Bind validation is correct, but handle gracefully
+		return fmt.Errorf("result format codes length %d does not match field count %d", len(resultFormats), len(inputFields))
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgconn/require_auth.go b/vendor/github.com/jackc/pgx/v5/pgconn/require_auth.go
new file mode 100644
index 000000000..3449a2fcc
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgconn/require_auth.go
@@ -0,0 +1,146 @@
+package pgconn
+
+import (
+	"fmt"
+	"strings"
+)
+
+// authMethod is one of the method keywords accepted by libpq's require_auth.
+type authMethod uint8
+
+const (
+	authMethodPassword authMethod = iota
+	authMethodMD5
+	authMethodGSS
+	authMethodSSPI
+	authMethodSCRAMSHA256
+	authMethodOAuth
+	authMethodNone
+	authMethodCount
+)
+
+var authMethodNames = [authMethodCount]string{
+	authMethodPassword:    "password",
+	authMethodMD5:         "md5",
+	authMethodGSS:         "gss",
+	authMethodSSPI:        "sspi",
+	authMethodSCRAMSHA256: "scram-sha-256",
+	authMethodOAuth:       "oauth",
+	authMethodNone:        "none",
+}
+
+// requireAuth is the parsed form of the require_auth connection parameter. It mirrors libpq's
+// auth_required / allowed_auth_methods bookkeeping (see fe-connect.c, conn->allowed_auth_methods).
+type requireAuth struct {
+	// raw is the original parameter value, used in error messages.
+	raw string
+
+	// authRequired is true when the server must complete an authentication exchange before sending
+	// AuthenticationOk. It is false when the parameter is unset, fully negated, or "none" is in the
+	// allowed set.
+	authRequired bool
+
+	// allowed is a bitmask of permitted authMethod values.
+	allowed uint8
+}
+
+func (ra requireAuth) allows(m authMethod) bool {
+	return ra.allowed&(1<<m) != 0
+}
+
+// check returns an error if method m is not permitted by the policy. The reason is phrased to
+// follow libpq's "authentication method requirement \"%s\" failed: %s" form so users migrating
+// from libpq see familiar diagnostics.
+func (ra requireAuth) check(m authMethod) error {
+	if ra.allows(m) {
+		return nil
+	}
+	var reason string
+	if m == authMethodNone {
+		reason = "server did not complete authentication"
+	} else {
+		reason = fmt.Sprintf("server requested %s authentication", authMethodNames[m])
+	}
+	return fmt.Errorf("authentication method requirement %q failed: %s", ra.raw, reason)
+}
+
+// parseRequireAuth parses the require_auth connection parameter with libpq-compatible semantics:
+// a comma-separated list of method names, optionally each prefixed with "!" to negate. Negated and
+// non-negated entries cannot be mixed; duplicate entries are rejected. An empty string yields a
+// permissive policy (all methods allowed, no authentication required).
+func parseRequireAuth(s string) (requireAuth, error) {
+	ra := requireAuth{raw: s}
+
+	if s == "" {
+		ra.allowed = 1<<authMethodCount - 1
+		return ra, nil
+	}
+
+	first := true
+	negated := false
+	for part := range strings.SplitSeq(s, ",") {
+		method := strings.TrimSpace(part)
+
+		neg := strings.HasPrefix(method, "!")
+		if neg {
+			method = method[1:]
+		}
+		if first {
+			negated = neg
+			if negated {
+				// A negated list starts from "everything allowed, auth not required" and removes
+				// methods; "!none" below flips authRequired back on.
+				ra.allowed = 1<<authMethodCount - 1
+			} else {
+				ra.authRequired = true
+			}
+			first = false
+		} else if neg != negated {
+			if neg {
+				return requireAuth{}, fmt.Errorf("negative require_auth method %q cannot be mixed with non-negative methods", method)
+			}
+			return requireAuth{}, fmt.Errorf("require_auth method %q cannot be mixed with negative methods", method)
+		}
+
+		var m authMethod
+		switch method {
+		case "password":
+			m = authMethodPassword
+		case "md5":
+			m = authMethodMD5
+		case "gss":
+			m = authMethodGSS
+		case "sspi":
+			m = authMethodSSPI
+		case "scram-sha-256":
+			m = authMethodSCRAMSHA256
+		case "oauth":
+			m = authMethodOAuth
+		case "none":
+			m = authMethodNone
+		default:
+			return requireAuth{}, fmt.Errorf("invalid require_auth method: %q", method)
+		}
+
+		bit := uint8(1) << m
+		if negated {
+			if ra.allowed&bit == 0 {
+				return requireAuth{}, fmt.Errorf("require_auth method %q is specified more than once", part)
+			}
+			ra.allowed &^= bit
+			if m == authMethodNone {
+				ra.authRequired = true
+			}
+		} else {
+			if ra.allowed&bit != 0 {
+				return requireAuth{}, fmt.Errorf("require_auth method %q is specified more than once", part)
+			}
+			ra.allowed |= bit
+			if m == authMethodNone {
+				ra.authRequired = false
+			}
+		}
+	}
+
+	return ra, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/README.md b/vendor/github.com/jackc/pgx/v5/pgproto3/README.md
new file mode 100644
index 000000000..7a26f1cbd
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/README.md
@@ -0,0 +1,7 @@
+# pgproto3
+
+Package pgproto3 is an encoder and decoder of the PostgreSQL wire protocol version 3.
+
+pgproto3 can be used as a foundation for PostgreSQL drivers, proxies, mock servers, load balancers and more.
+
+See example/pgfortune for a playful example of a fake PostgreSQL server.
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_cleartext_password.go b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_cleartext_password.go
new file mode 100644
index 000000000..415e1a24a
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_cleartext_password.go
@@ -0,0 +1,50 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// AuthenticationCleartextPassword is a message sent from the backend indicating that a clear-text password is required.
+type AuthenticationCleartextPassword struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationCleartextPassword) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationCleartextPassword) AuthenticationResponse() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *AuthenticationCleartextPassword) Decode(src []byte) error {
+	if len(src) != 4 {
+		return errors.New("bad authentication message size")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeCleartextPassword {
+		return errors.New("bad auth type")
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *AuthenticationCleartextPassword) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'R')
+	dst = pgio.AppendUint32(dst, AuthTypeCleartextPassword)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationCleartextPassword) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "AuthenticationCleartextPassword",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_gss.go b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_gss.go
new file mode 100644
index 000000000..178ef31d8
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_gss.go
@@ -0,0 +1,58 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type AuthenticationGSS struct{}
+
+func (a *AuthenticationGSS) Backend() {}
+
+func (a *AuthenticationGSS) AuthenticationResponse() {}
+
+func (a *AuthenticationGSS) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("authentication message too short")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeGSS {
+		return errors.New("bad auth type")
+	}
+	return nil
+}
+
+func (a *AuthenticationGSS) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'R')
+	dst = pgio.AppendUint32(dst, AuthTypeGSS)
+	return finishMessage(dst, sp)
+}
+
+func (a *AuthenticationGSS) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data []byte
+	}{
+		Type: "AuthenticationGSS",
+	})
+}
+
+func (a *AuthenticationGSS) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Type string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_gss_continue.go b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_gss_continue.go
new file mode 100644
index 000000000..2ba3f3b3e
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_gss_continue.go
@@ -0,0 +1,67 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type AuthenticationGSSContinue struct {
+	Data []byte
+}
+
+func (a *AuthenticationGSSContinue) Backend() {}
+
+func (a *AuthenticationGSSContinue) AuthenticationResponse() {}
+
+func (a *AuthenticationGSSContinue) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("authentication message too short")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeGSSCont {
+		return errors.New("bad auth type")
+	}
+
+	a.Data = src[4:]
+	return nil
+}
+
+func (a *AuthenticationGSSContinue) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'R')
+	dst = pgio.AppendUint32(dst, AuthTypeGSSCont)
+	dst = append(dst, a.Data...)
+	return finishMessage(dst, sp)
+}
+
+func (a *AuthenticationGSSContinue) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data []byte
+	}{
+		Type: "AuthenticationGSSContinue",
+		Data: a.Data,
+	})
+}
+
+func (a *AuthenticationGSSContinue) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Type string
+		Data []byte
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	a.Data = msg.Data
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_md5_password.go b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_md5_password.go
new file mode 100644
index 000000000..854c6404e
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_md5_password.go
@@ -0,0 +1,76 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// AuthenticationMD5Password is a message sent from the backend indicating that an MD5 hashed password is required.
+type AuthenticationMD5Password struct {
+	Salt [4]byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationMD5Password) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationMD5Password) AuthenticationResponse() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *AuthenticationMD5Password) Decode(src []byte) error {
+	if len(src) != 8 {
+		return errors.New("bad authentication message size")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeMD5Password {
+		return errors.New("bad auth type")
+	}
+
+	copy(dst.Salt[:], src[4:8])
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *AuthenticationMD5Password) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'R')
+	dst = pgio.AppendUint32(dst, AuthTypeMD5Password)
+	dst = append(dst, src.Salt[:]...)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationMD5Password) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Salt [4]byte
+	}{
+		Type: "AuthenticationMD5Password",
+		Salt: src.Salt,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *AuthenticationMD5Password) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Type string
+		Salt [4]byte
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.Salt = msg.Salt
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_ok.go b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_ok.go
new file mode 100644
index 000000000..98c0b2d66
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_ok.go
@@ -0,0 +1,50 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// AuthenticationOk is a message sent from the backend indicating that authentication was successful.
+type AuthenticationOk struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationOk) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationOk) AuthenticationResponse() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *AuthenticationOk) Decode(src []byte) error {
+	if len(src) != 4 {
+		return errors.New("bad authentication message size")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeOk {
+		return errors.New("bad auth type")
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *AuthenticationOk) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'R')
+	dst = pgio.AppendUint32(dst, AuthTypeOk)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationOk) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "AuthenticationOK",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl.go b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl.go
new file mode 100644
index 000000000..69e228215
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl.go
@@ -0,0 +1,73 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// AuthenticationSASL is a message sent from the backend indicating that SASL authentication is required.
+type AuthenticationSASL struct {
+	AuthMechanisms []string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationSASL) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationSASL) AuthenticationResponse() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *AuthenticationSASL) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("authentication message too short")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeSASL {
+		return errors.New("bad auth type")
+	}
+
+	dst.AuthMechanisms = dst.AuthMechanisms[:0]
+	authMechanisms := src[4:]
+	for len(authMechanisms) > 1 {
+		idx := bytes.IndexByte(authMechanisms, 0)
+		if idx == -1 {
+			return &invalidMessageFormatErr{messageType: "AuthenticationSASL", details: "unterminated string"}
+		}
+		dst.AuthMechanisms = append(dst.AuthMechanisms, string(authMechanisms[:idx]))
+		authMechanisms = authMechanisms[idx+1:]
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *AuthenticationSASL) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'R')
+	dst = pgio.AppendUint32(dst, AuthTypeSASL)
+
+	for _, s := range src.AuthMechanisms {
+		dst = append(dst, []byte(s)...)
+		dst = append(dst, 0)
+	}
+	dst = append(dst, 0)
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationSASL) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type           string
+		AuthMechanisms []string
+	}{
+		Type:           "AuthenticationSASL",
+		AuthMechanisms: src.AuthMechanisms,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl_continue.go b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl_continue.go
new file mode 100644
index 000000000..70fba4a67
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl_continue.go
@@ -0,0 +1,75 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// AuthenticationSASLContinue is a message sent from the backend containing a SASL challenge.
+type AuthenticationSASLContinue struct {
+	Data []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationSASLContinue) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationSASLContinue) AuthenticationResponse() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *AuthenticationSASLContinue) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("authentication message too short")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeSASLContinue {
+		return errors.New("bad auth type")
+	}
+
+	dst.Data = src[4:]
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *AuthenticationSASLContinue) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'R')
+	dst = pgio.AppendUint32(dst, AuthTypeSASLContinue)
+	dst = append(dst, src.Data...)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationSASLContinue) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data string
+	}{
+		Type: "AuthenticationSASLContinue",
+		Data: string(src.Data),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *AuthenticationSASLContinue) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Data string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.Data = []byte(msg.Data)
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl_final.go b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl_final.go
new file mode 100644
index 000000000..84976c2a3
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/authentication_sasl_final.go
@@ -0,0 +1,75 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// AuthenticationSASLFinal is a message sent from the backend indicating a SASL authentication has completed.
+type AuthenticationSASLFinal struct {
+	Data []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationSASLFinal) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationSASLFinal) AuthenticationResponse() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *AuthenticationSASLFinal) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("authentication message too short")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeSASLFinal {
+		return errors.New("bad auth type")
+	}
+
+	dst.Data = src[4:]
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *AuthenticationSASLFinal) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'R')
+	dst = pgio.AppendUint32(dst, AuthTypeSASLFinal)
+	dst = append(dst, src.Data...)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Unmarshaler.
+func (src AuthenticationSASLFinal) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data string
+	}{
+		Type: "AuthenticationSASLFinal",
+		Data: string(src.Data),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *AuthenticationSASLFinal) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Data string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.Data = []byte(msg.Data)
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/backend.go b/vendor/github.com/jackc/pgx/v5/pgproto3/backend.go
new file mode 100644
index 000000000..65388ad49
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/backend.go
@@ -0,0 +1,299 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"io"
+)
+
+// Backend acts as a server for the PostgreSQL wire protocol version 3.
+type Backend struct {
+	cr *chunkReader
+	w  io.Writer
+
+	// tracer is used to trace messages when Send or Receive is called. This means an outbound message is traced
+	// before it is actually transmitted (i.e. before Flush).
+	tracer *tracer
+
+	wbuf        []byte
+	encodeError error
+
+	// Frontend message flyweights
+	bind           Bind
+	cancelRequest  CancelRequest
+	_close         Close
+	copyFail       CopyFail
+	copyData       CopyData
+	copyDone       CopyDone
+	describe       Describe
+	execute        Execute
+	flush          Flush
+	functionCall   FunctionCall
+	gssEncRequest  GSSEncRequest
+	parse          Parse
+	query          Query
+	sslRequest     SSLRequest
+	startupMessage StartupMessage
+	sync           Sync
+	terminate      Terminate
+
+	bodyLen    int
+	maxBodyLen int // maxBodyLen is the maximum length of a message body in octets. If a message body exceeds this length, Receive will return an error.
+	msgType    byte
+	partialMsg bool
+	authType   uint32
+}
+
+const (
+	minStartupPacketLen = 4      // minStartupPacketLen is a single 32-bit int version or code.
+	maxStartupPacketLen = 10_000 // maxStartupPacketLen is MAX_STARTUP_PACKET_LENGTH from PG source.
+)
+
+// NewBackend creates a new Backend.
+func NewBackend(r io.Reader, w io.Writer) *Backend {
+	cr := newChunkReader(r, 0)
+	return &Backend{cr: cr, w: w}
+}
+
+// Send sends a message to the frontend (i.e. the client). The message is buffered until Flush is called. Any error
+// encountered will be returned from Flush.
+func (b *Backend) Send(msg BackendMessage) {
+	if b.encodeError != nil {
+		return
+	}
+
+	prevLen := len(b.wbuf)
+	newBuf, err := msg.Encode(b.wbuf)
+	if err != nil {
+		b.encodeError = err
+		return
+	}
+	b.wbuf = newBuf
+
+	if b.tracer != nil {
+		b.tracer.traceMessage('B', int32(len(b.wbuf)-prevLen), msg)
+	}
+}
+
+// Flush writes any pending messages to the frontend (i.e. the client).
+func (b *Backend) Flush() error {
+	if err := b.encodeError; err != nil {
+		b.encodeError = nil
+		b.wbuf = b.wbuf[:0]
+		return &writeError{err: err, safeToRetry: true}
+	}
+
+	n, err := b.w.Write(b.wbuf)
+
+	const maxLen = 1024
+	if len(b.wbuf) > maxLen {
+		b.wbuf = make([]byte, 0, maxLen)
+	} else {
+		b.wbuf = b.wbuf[:0]
+	}
+
+	if err != nil {
+		return &writeError{err: err, safeToRetry: n == 0}
+	}
+
+	return nil
+}
+
+// Trace starts tracing the message traffic to w. It writes in a similar format to that produced by the libpq function
+// PQtrace.
+func (b *Backend) Trace(w io.Writer, options TracerOptions) {
+	b.tracer = &tracer{
+		w:             w,
+		buf:           &bytes.Buffer{},
+		TracerOptions: options,
+	}
+}
+
+// Untrace stops tracing.
+func (b *Backend) Untrace() {
+	b.tracer = nil
+}
+
+// ReceiveStartupMessage receives the initial connection message. This method is used of the normal Receive method
+// because the initial connection message is "special" and does not include the message type as the first byte. This
+// will return either a StartupMessage, SSLRequest, GSSEncRequest, or CancelRequest.
+func (b *Backend) ReceiveStartupMessage() (FrontendMessage, error) {
+	buf, err := b.cr.Next(4)
+	if err != nil {
+		return nil, err
+	}
+	msgSize := int(int32(binary.BigEndian.Uint32(buf)) - 4)
+
+	if msgSize < minStartupPacketLen || msgSize > maxStartupPacketLen {
+		return nil, fmt.Errorf("invalid length of startup packet: %d", msgSize)
+	}
+
+	buf, err = b.cr.Next(msgSize)
+	if err != nil {
+		return nil, translateEOFtoErrUnexpectedEOF(err)
+	}
+
+	code := binary.BigEndian.Uint32(buf)
+
+	switch code {
+	case ProtocolVersion30, ProtocolVersion32:
+		err = b.startupMessage.Decode(buf)
+		if err != nil {
+			return nil, err
+		}
+		return &b.startupMessage, nil
+	case sslRequestNumber:
+		err = b.sslRequest.Decode(buf)
+		if err != nil {
+			return nil, err
+		}
+		return &b.sslRequest, nil
+	case cancelRequestCode:
+		err = b.cancelRequest.Decode(buf)
+		if err != nil {
+			return nil, err
+		}
+		return &b.cancelRequest, nil
+	case gssEncReqNumber:
+		err = b.gssEncRequest.Decode(buf)
+		if err != nil {
+			return nil, err
+		}
+		return &b.gssEncRequest, nil
+	default:
+		return nil, fmt.Errorf("unknown startup message code: %d", code)
+	}
+}
+
+// Receive receives a message from the frontend. The returned message is only valid until the next call to Receive.
+func (b *Backend) Receive() (FrontendMessage, error) {
+	if !b.partialMsg {
+		header, err := b.cr.Next(5)
+		if err != nil {
+			return nil, translateEOFtoErrUnexpectedEOF(err)
+		}
+
+		b.msgType = header[0]
+
+		msgLength := int(int32(binary.BigEndian.Uint32(header[1:])))
+		if msgLength < 4 {
+			return nil, fmt.Errorf("invalid message length: %d", msgLength)
+		}
+
+		b.bodyLen = msgLength - 4
+		if b.maxBodyLen > 0 && b.bodyLen > b.maxBodyLen {
+			return nil, &ExceededMaxBodyLenErr{b.maxBodyLen, b.bodyLen}
+		}
+		b.partialMsg = true
+	}
+
+	var msg FrontendMessage
+	switch b.msgType {
+	case 'B':
+		msg = &b.bind
+	case 'C':
+		msg = &b._close
+	case 'D':
+		msg = &b.describe
+	case 'E':
+		msg = &b.execute
+	case 'F':
+		msg = &b.functionCall
+	case 'f':
+		msg = &b.copyFail
+	case 'd':
+		msg = &b.copyData
+	case 'c':
+		msg = &b.copyDone
+	case 'H':
+		msg = &b.flush
+	case 'P':
+		msg = &b.parse
+	case 'p':
+		switch b.authType {
+		case AuthTypeSASL:
+			msg = &SASLInitialResponse{}
+		case AuthTypeSASLContinue:
+			msg = &SASLResponse{}
+		case AuthTypeSASLFinal:
+			msg = &SASLResponse{}
+		case AuthTypeGSS, AuthTypeGSSCont:
+			msg = &GSSResponse{}
+		case AuthTypeCleartextPassword, AuthTypeMD5Password:
+			fallthrough
+		default:
+			// to maintain backwards compatibility
+			msg = &PasswordMessage{}
+		}
+	case 'Q':
+		msg = &b.query
+	case 'S':
+		msg = &b.sync
+	case 'X':
+		msg = &b.terminate
+	default:
+		return nil, fmt.Errorf("unknown message type: %c", b.msgType)
+	}
+
+	msgBody, err := b.cr.Next(b.bodyLen)
+	if err != nil {
+		return nil, translateEOFtoErrUnexpectedEOF(err)
+	}
+
+	b.partialMsg = false
+
+	err = msg.Decode(msgBody)
+	if err != nil {
+		return nil, err
+	}
+
+	if b.tracer != nil {
+		b.tracer.traceMessage('F', int32(5+len(msgBody)), msg)
+	}
+
+	return msg, nil
+}
+
+// SetAuthType sets the authentication type in the backend.
+// Since multiple message types can start with 'p', SetAuthType allows
+// contextual identification of FrontendMessages. For example, in the
+// PG message flow documentation for PasswordMessage:
+//
+//			Byte1('p')
+//
+//	     Identifies the message as a password response. Note that this is also used for
+//			GSSAPI, SSPI and SASL response messages. The exact message type can be deduced from
+//			the context.
+//
+// Since the Frontend does not know about the state of a backend, it is important
+// to call SetAuthType() after an authentication request is received by the Frontend.
+func (b *Backend) SetAuthType(authType uint32) error {
+	switch authType {
+	case AuthTypeOk,
+		AuthTypeCleartextPassword,
+		AuthTypeMD5Password,
+		AuthTypeSCMCreds,
+		AuthTypeGSS,
+		AuthTypeGSSCont,
+		AuthTypeSSPI,
+		AuthTypeSASL,
+		AuthTypeSASLContinue,
+		AuthTypeSASLFinal:
+		b.authType = authType
+	default:
+		return fmt.Errorf("authType not recognized: %d", authType)
+	}
+
+	return nil
+}
+
+// SetMaxBodyLen sets the maximum length of a message body in octets.
+// If a message body exceeds this length, Receive will return an error.
+// This is useful for protecting against malicious clients that send
+// large messages with the intent of causing memory exhaustion.
+// The default value is 0.
+// If maxBodyLen is 0, then no maximum is enforced.
+func (b *Backend) SetMaxBodyLen(maxBodyLen int) {
+	b.maxBodyLen = maxBodyLen
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/backend_key_data.go b/vendor/github.com/jackc/pgx/v5/pgproto3/backend_key_data.go
new file mode 100644
index 000000000..c73b2da0c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/backend_key_data.go
@@ -0,0 +1,71 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"encoding/json"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type BackendKeyData struct {
+	ProcessID uint32
+	SecretKey []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*BackendKeyData) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *BackendKeyData) Decode(src []byte) error {
+	if len(src) < 8 {
+		return &invalidMessageLenErr{messageType: "BackendKeyData", expectedLen: 8, actualLen: len(src)}
+	}
+
+	dst.ProcessID = binary.BigEndian.Uint32(src[:4])
+	dst.SecretKey = make([]byte, len(src)-4)
+	copy(dst.SecretKey, src[4:])
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *BackendKeyData) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'K')
+	dst = pgio.AppendUint32(dst, src.ProcessID)
+	dst = append(dst, src.SecretKey...)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src BackendKeyData) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type      string
+		ProcessID uint32
+		SecretKey string
+	}{
+		Type:      "BackendKeyData",
+		ProcessID: src.ProcessID,
+		SecretKey: hex.EncodeToString(src.SecretKey),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *BackendKeyData) UnmarshalJSON(data []byte) error {
+	var msg struct {
+		ProcessID uint32
+		SecretKey string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.ProcessID = msg.ProcessID
+	secretKey, err := hex.DecodeString(msg.SecretKey)
+	if err != nil {
+		return err
+	}
+	dst.SecretKey = secretKey
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/big_endian.go b/vendor/github.com/jackc/pgx/v5/pgproto3/big_endian.go
new file mode 100644
index 000000000..f7bdb97eb
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/big_endian.go
@@ -0,0 +1,37 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+)
+
+type BigEndianBuf [8]byte
+
+func (b BigEndianBuf) Int16(n int16) []byte {
+	buf := b[0:2]
+	binary.BigEndian.PutUint16(buf, uint16(n))
+	return buf
+}
+
+func (b BigEndianBuf) Uint16(n uint16) []byte {
+	buf := b[0:2]
+	binary.BigEndian.PutUint16(buf, n)
+	return buf
+}
+
+func (b BigEndianBuf) Int32(n int32) []byte {
+	buf := b[0:4]
+	binary.BigEndian.PutUint32(buf, uint32(n))
+	return buf
+}
+
+func (b BigEndianBuf) Uint32(n uint32) []byte {
+	buf := b[0:4]
+	binary.BigEndian.PutUint32(buf, n)
+	return buf
+}
+
+func (b BigEndianBuf) Int64(n int64) []byte {
+	buf := b[0:8]
+	binary.BigEndian.PutUint64(buf, uint64(n))
+	return buf
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/bind.go b/vendor/github.com/jackc/pgx/v5/pgproto3/bind.go
new file mode 100644
index 000000000..fb56e4dca
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/bind.go
@@ -0,0 +1,223 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Bind struct {
+	DestinationPortal    string
+	PreparedStatement    string
+	ParameterFormatCodes []int16
+	Parameters           [][]byte
+	ResultFormatCodes    []int16
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Bind) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Bind) Decode(src []byte) error {
+	*dst = Bind{}
+
+	idx := bytes.IndexByte(src, 0)
+	if idx < 0 {
+		return &invalidMessageFormatErr{messageType: "Bind"}
+	}
+	dst.DestinationPortal = string(src[:idx])
+	rp := idx + 1
+
+	idx = bytes.IndexByte(src[rp:], 0)
+	if idx < 0 {
+		return &invalidMessageFormatErr{messageType: "Bind"}
+	}
+	dst.PreparedStatement = string(src[rp : rp+idx])
+	rp += idx + 1
+
+	if len(src[rp:]) < 2 {
+		return &invalidMessageFormatErr{messageType: "Bind"}
+	}
+	parameterFormatCodeCount := int(binary.BigEndian.Uint16(src[rp:]))
+	rp += 2
+
+	if parameterFormatCodeCount > 0 {
+		dst.ParameterFormatCodes = make([]int16, parameterFormatCodeCount)
+
+		if len(src[rp:]) < len(dst.ParameterFormatCodes)*2 {
+			return &invalidMessageFormatErr{messageType: "Bind"}
+		}
+		for i := range parameterFormatCodeCount {
+			dst.ParameterFormatCodes[i] = int16(binary.BigEndian.Uint16(src[rp:]))
+			rp += 2
+		}
+	}
+
+	if len(src[rp:]) < 2 {
+		return &invalidMessageFormatErr{messageType: "Bind"}
+	}
+	parameterCount := int(binary.BigEndian.Uint16(src[rp:]))
+	rp += 2
+
+	if parameterCount > 0 {
+		dst.Parameters = make([][]byte, parameterCount)
+
+		for i := range parameterCount {
+			if len(src[rp:]) < 4 {
+				return &invalidMessageFormatErr{messageType: "Bind"}
+			}
+
+			msgSize := int(int32(binary.BigEndian.Uint32(src[rp:])))
+			rp += 4
+
+			// null
+			if msgSize == -1 {
+				continue
+			}
+
+			if msgSize < 0 || len(src[rp:]) < msgSize {
+				return &invalidMessageFormatErr{messageType: "Bind"}
+			}
+
+			dst.Parameters[i] = src[rp : rp+msgSize]
+			rp += msgSize
+		}
+	}
+
+	if len(src[rp:]) < 2 {
+		return &invalidMessageFormatErr{messageType: "Bind"}
+	}
+	resultFormatCodeCount := int(binary.BigEndian.Uint16(src[rp:]))
+	rp += 2
+
+	dst.ResultFormatCodes = make([]int16, resultFormatCodeCount)
+	if len(src[rp:]) < len(dst.ResultFormatCodes)*2 {
+		return &invalidMessageFormatErr{messageType: "Bind"}
+	}
+	for i := range resultFormatCodeCount {
+		dst.ResultFormatCodes[i] = int16(binary.BigEndian.Uint16(src[rp:]))
+		rp += 2
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Bind) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'B')
+
+	dst = append(dst, src.DestinationPortal...)
+	dst = append(dst, 0)
+	dst = append(dst, src.PreparedStatement...)
+	dst = append(dst, 0)
+
+	if len(src.ParameterFormatCodes) > math.MaxUint16 {
+		return nil, errors.New("too many parameter format codes")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.ParameterFormatCodes)))
+	for _, fc := range src.ParameterFormatCodes {
+		dst = pgio.AppendInt16(dst, fc)
+	}
+
+	if len(src.Parameters) > math.MaxUint16 {
+		return nil, errors.New("too many parameters")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.Parameters)))
+	for _, p := range src.Parameters {
+		if p == nil {
+			dst = pgio.AppendInt32(dst, -1)
+			continue
+		}
+
+		dst = pgio.AppendInt32(dst, int32(len(p)))
+		dst = append(dst, p...)
+	}
+
+	if len(src.ResultFormatCodes) > math.MaxUint16 {
+		return nil, errors.New("too many result format codes")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.ResultFormatCodes)))
+	for _, fc := range src.ResultFormatCodes {
+		dst = pgio.AppendInt16(dst, fc)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Bind) MarshalJSON() ([]byte, error) {
+	formattedParameters := make([]map[string]string, len(src.Parameters))
+	for i, p := range src.Parameters {
+		if p == nil {
+			continue
+		}
+
+		textFormat := true
+		if len(src.ParameterFormatCodes) == 1 {
+			textFormat = src.ParameterFormatCodes[0] == 0
+		} else if len(src.ParameterFormatCodes) > 1 {
+			textFormat = src.ParameterFormatCodes[i] == 0
+		}
+
+		if textFormat {
+			formattedParameters[i] = map[string]string{"text": string(p)}
+		} else {
+			formattedParameters[i] = map[string]string{"binary": hex.EncodeToString(p)}
+		}
+	}
+
+	return json.Marshal(struct {
+		Type                 string
+		DestinationPortal    string
+		PreparedStatement    string
+		ParameterFormatCodes []int16
+		Parameters           []map[string]string
+		ResultFormatCodes    []int16
+	}{
+		Type:                 "Bind",
+		DestinationPortal:    src.DestinationPortal,
+		PreparedStatement:    src.PreparedStatement,
+		ParameterFormatCodes: src.ParameterFormatCodes,
+		Parameters:           formattedParameters,
+		ResultFormatCodes:    src.ResultFormatCodes,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *Bind) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		DestinationPortal    string
+		PreparedStatement    string
+		ParameterFormatCodes []int16
+		Parameters           []map[string]string
+		ResultFormatCodes    []int16
+	}
+	err := json.Unmarshal(data, &msg)
+	if err != nil {
+		return err
+	}
+	dst.DestinationPortal = msg.DestinationPortal
+	dst.PreparedStatement = msg.PreparedStatement
+	dst.ParameterFormatCodes = msg.ParameterFormatCodes
+	dst.Parameters = make([][]byte, len(msg.Parameters))
+	dst.ResultFormatCodes = msg.ResultFormatCodes
+	for n, parameter := range msg.Parameters {
+		dst.Parameters[n], err = getValueFromJSON(parameter)
+		if err != nil {
+			return fmt.Errorf("cannot get param %d: %w", n, err)
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/bind_complete.go b/vendor/github.com/jackc/pgx/v5/pgproto3/bind_complete.go
new file mode 100644
index 000000000..bacf30d88
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/bind_complete.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type BindComplete struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*BindComplete) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *BindComplete) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "BindComplete", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *BindComplete) Encode(dst []byte) ([]byte, error) {
+	return append(dst, '2', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src BindComplete) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "BindComplete",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/cancel_request.go b/vendor/github.com/jackc/pgx/v5/pgproto3/cancel_request.go
new file mode 100644
index 000000000..63ebe5c47
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/cancel_request.go
@@ -0,0 +1,85 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+const cancelRequestCode = 80877102
+
+type CancelRequest struct {
+	ProcessID uint32
+	SecretKey []byte
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*CancelRequest) Frontend() {}
+
+func (dst *CancelRequest) Decode(src []byte) error {
+	if len(src) < 12 {
+		return errors.New("cancel request too short")
+	}
+	if len(src) > 264 {
+		return errors.New("cancel request too long")
+	}
+
+	requestCode := binary.BigEndian.Uint32(src)
+	if requestCode != cancelRequestCode {
+		return errors.New("bad cancel request code")
+	}
+
+	dst.ProcessID = binary.BigEndian.Uint32(src[4:])
+	dst.SecretKey = make([]byte, len(src)-8)
+	copy(dst.SecretKey, src[8:])
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 4 byte message length.
+func (src *CancelRequest) Encode(dst []byte) ([]byte, error) {
+	if len(src.SecretKey) > 256 {
+		return nil, errors.New("secret key too long")
+	}
+	msgLen := int32(12 + len(src.SecretKey))
+	dst = pgio.AppendInt32(dst, msgLen)
+	dst = pgio.AppendInt32(dst, cancelRequestCode)
+	dst = pgio.AppendUint32(dst, src.ProcessID)
+	dst = append(dst, src.SecretKey...)
+	return dst, nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CancelRequest) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type      string
+		ProcessID uint32
+		SecretKey string
+	}{
+		Type:      "CancelRequest",
+		ProcessID: src.ProcessID,
+		SecretKey: hex.EncodeToString(src.SecretKey),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CancelRequest) UnmarshalJSON(data []byte) error {
+	var msg struct {
+		ProcessID uint32
+		SecretKey string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.ProcessID = msg.ProcessID
+	secretKey, err := hex.DecodeString(msg.SecretKey)
+	if err != nil {
+		return err
+	}
+	dst.SecretKey = secretKey
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/chunkreader.go b/vendor/github.com/jackc/pgx/v5/pgproto3/chunkreader.go
new file mode 100644
index 000000000..fc0fa61e9
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/chunkreader.go
@@ -0,0 +1,90 @@
+package pgproto3
+
+import (
+	"io"
+
+	"github.com/jackc/pgx/v5/internal/iobufpool"
+)
+
+// chunkReader is a io.Reader wrapper that minimizes IO reads and memory allocations. It allocates memory in chunks and
+// will read as much as will fit in the current buffer in a single call regardless of how large a read is actually
+// requested. The memory returned via Next is only valid until the next call to Next.
+//
+// This is roughly equivalent to a bufio.Reader that only uses Peek and Discard to never copy bytes.
+type chunkReader struct {
+	r io.Reader
+
+	buf    *[]byte
+	rp, wp int // buf read position and write position
+
+	minBufSize int
+}
+
+// newChunkReader creates and returns a new chunkReader for r with default configuration. If minBufSize is <= 0 it uses
+// a default value.
+func newChunkReader(r io.Reader, minBufSize int) *chunkReader {
+	if minBufSize <= 0 {
+		// By historical reasons Postgres currently has 8KB send buffer inside,
+		// so here we want to have at least the same size buffer.
+		// @see https://github.com/postgres/postgres/blob/249d64999615802752940e017ee5166e726bc7cd/src/backend/libpq/pqcomm.c#L134
+		// @see https://www.postgresql.org/message-id/0cdc5485-cb3c-5e16-4a46-e3b2f7a41322%40ya.ru
+		//
+		// In addition, testing has found no benefit of any larger buffer.
+		minBufSize = 8192
+	}
+
+	return &chunkReader{
+		r:          r,
+		minBufSize: minBufSize,
+		buf:        iobufpool.Get(minBufSize),
+	}
+}
+
+// Next returns buf filled with the next n bytes. buf is only valid until next call of Next. If an error occurs, buf
+// will be nil.
+func (r *chunkReader) Next(n int) (buf []byte, err error) {
+	// Reset the buffer if it is empty
+	if r.rp == r.wp {
+		if len(*r.buf) != r.minBufSize {
+			iobufpool.Put(r.buf)
+			r.buf = iobufpool.Get(r.minBufSize)
+		}
+		r.rp = 0
+		r.wp = 0
+	}
+
+	// n bytes already in buf
+	if (r.wp - r.rp) >= n {
+		buf = (*r.buf)[r.rp : r.rp+n : r.rp+n]
+		r.rp += n
+		return buf, err
+	}
+
+	// buf is smaller than requested number of bytes
+	if len(*r.buf) < n {
+		bigBuf := iobufpool.Get(n)
+		r.wp = copy((*bigBuf), (*r.buf)[r.rp:r.wp])
+		r.rp = 0
+		iobufpool.Put(r.buf)
+		r.buf = bigBuf
+	}
+
+	// buf is large enough, but need to shift filled area to start to make enough contiguous space
+	minReadCount := n - (r.wp - r.rp)
+	if (len(*r.buf) - r.wp) < minReadCount {
+		r.wp = copy((*r.buf), (*r.buf)[r.rp:r.wp])
+		r.rp = 0
+	}
+
+	// Read at least the required number of bytes from the underlying io.Reader
+	readBytesCount, err := io.ReadAtLeast(r.r, (*r.buf)[r.wp:], minReadCount)
+	r.wp += readBytesCount
+	// fmt.Println("read", n)
+	if err != nil {
+		return nil, err
+	}
+
+	buf = (*r.buf)[r.rp : r.rp+n : r.rp+n]
+	r.rp += n
+	return buf, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/close.go b/vendor/github.com/jackc/pgx/v5/pgproto3/close.go
new file mode 100644
index 000000000..0e7e04952
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/close.go
@@ -0,0 +1,81 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+)
+
+type Close struct {
+	ObjectType byte // 'S' = prepared statement, 'P' = portal
+	Name       string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Close) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Close) Decode(src []byte) error {
+	if len(src) < 2 {
+		return &invalidMessageFormatErr{messageType: "Close"}
+	}
+
+	dst.ObjectType = src[0]
+	rp := 1
+
+	idx := bytes.IndexByte(src[rp:], 0)
+	if idx != len(src[rp:])-1 {
+		return &invalidMessageFormatErr{messageType: "Close"}
+	}
+
+	dst.Name = string(src[rp : len(src)-1])
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Close) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'C')
+	dst = append(dst, src.ObjectType)
+	dst = append(dst, src.Name...)
+	dst = append(dst, 0)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Close) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type       string
+		ObjectType string
+		Name       string
+	}{
+		Type:       "Close",
+		ObjectType: string(src.ObjectType),
+		Name:       src.Name,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *Close) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		ObjectType string
+		Name       string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	if len(msg.ObjectType) != 1 {
+		return errors.New("invalid length for Close.ObjectType")
+	}
+
+	dst.ObjectType = msg.ObjectType[0]
+	dst.Name = msg.Name
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/close_complete.go b/vendor/github.com/jackc/pgx/v5/pgproto3/close_complete.go
new file mode 100644
index 000000000..833f7a12c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/close_complete.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type CloseComplete struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CloseComplete) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *CloseComplete) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "CloseComplete", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *CloseComplete) Encode(dst []byte) ([]byte, error) {
+	return append(dst, '3', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CloseComplete) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "CloseComplete",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/command_complete.go b/vendor/github.com/jackc/pgx/v5/pgproto3/command_complete.go
new file mode 100644
index 000000000..eba70947d
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/command_complete.go
@@ -0,0 +1,66 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/json"
+)
+
+type CommandComplete struct {
+	CommandTag []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CommandComplete) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *CommandComplete) Decode(src []byte) error {
+	idx := bytes.IndexByte(src, 0)
+	if idx == -1 {
+		return &invalidMessageFormatErr{messageType: "CommandComplete", details: "unterminated string"}
+	}
+	if idx != len(src)-1 {
+		return &invalidMessageFormatErr{messageType: "CommandComplete", details: "string terminated too early"}
+	}
+
+	dst.CommandTag = src[:idx]
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *CommandComplete) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'C')
+	dst = append(dst, src.CommandTag...)
+	dst = append(dst, 0)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CommandComplete) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type       string
+		CommandTag string
+	}{
+		Type:       "CommandComplete",
+		CommandTag: string(src.CommandTag),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CommandComplete) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		CommandTag string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.CommandTag = []byte(msg.CommandTag)
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/copy_both_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_both_response.go
new file mode 100644
index 000000000..e2a402f9a
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_both_response.go
@@ -0,0 +1,95 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type CopyBothResponse struct {
+	OverallFormat     byte
+	ColumnFormatCodes []uint16
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CopyBothResponse) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *CopyBothResponse) Decode(src []byte) error {
+	buf := bytes.NewBuffer(src)
+
+	if buf.Len() < 3 {
+		return &invalidMessageFormatErr{messageType: "CopyBothResponse"}
+	}
+
+	overallFormat := buf.Next(1)[0]
+
+	columnCount := int(binary.BigEndian.Uint16(buf.Next(2)))
+	if buf.Len() != columnCount*2 {
+		return &invalidMessageFormatErr{messageType: "CopyBothResponse"}
+	}
+
+	columnFormatCodes := make([]uint16, columnCount)
+	for i := range columnCount {
+		columnFormatCodes[i] = binary.BigEndian.Uint16(buf.Next(2))
+	}
+
+	*dst = CopyBothResponse{OverallFormat: overallFormat, ColumnFormatCodes: columnFormatCodes}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *CopyBothResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'W')
+	dst = append(dst, src.OverallFormat)
+	if len(src.ColumnFormatCodes) > math.MaxUint16 {
+		return nil, errors.New("too many column format codes")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
+	for _, fc := range src.ColumnFormatCodes {
+		dst = pgio.AppendUint16(dst, fc)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyBothResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type              string
+		ColumnFormatCodes []uint16
+	}{
+		Type:              "CopyBothResponse",
+		ColumnFormatCodes: src.ColumnFormatCodes,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CopyBothResponse) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		OverallFormat     string
+		ColumnFormatCodes []uint16
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	if len(msg.OverallFormat) != 1 {
+		return errors.New("invalid length for CopyBothResponse.OverallFormat")
+	}
+
+	dst.OverallFormat = msg.OverallFormat[0]
+	dst.ColumnFormatCodes = msg.ColumnFormatCodes
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/copy_data.go b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_data.go
new file mode 100644
index 000000000..d72e1f353
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_data.go
@@ -0,0 +1,67 @@
+package pgproto3
+
+import (
+	"encoding/hex"
+	"encoding/json"
+)
+
+type CopyData struct {
+	Data []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CopyData) Backend() {}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*CopyData) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *CopyData) Decode(src []byte) error {
+	dst.Data = src
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *CopyData) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'd')
+	dst = append(dst, src.Data...)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyData) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data string
+	}{
+		Type: "CopyData",
+		Data: hex.EncodeToString(src.Data),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CopyData) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Data string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	if msg.Data == "" {
+		dst.Data = []byte{}
+		return nil
+	}
+	b, err := hex.DecodeString(msg.Data)
+	if err != nil {
+		return err
+	}
+	dst.Data = b
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/copy_done.go b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_done.go
new file mode 100644
index 000000000..c3421a9b5
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_done.go
@@ -0,0 +1,37 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type CopyDone struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CopyDone) Backend() {}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*CopyDone) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *CopyDone) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "CopyDone", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *CopyDone) Encode(dst []byte) ([]byte, error) {
+	return append(dst, 'c', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyDone) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "CopyDone",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/copy_fail.go b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_fail.go
new file mode 100644
index 000000000..f8a00b8b7
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_fail.go
@@ -0,0 +1,49 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/json"
+)
+
+type CopyFail struct {
+	Message string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*CopyFail) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *CopyFail) Decode(src []byte) error {
+	if len(src) == 0 {
+		return &invalidMessageFormatErr{messageType: "CopyFail"}
+	}
+
+	idx := bytes.IndexByte(src, 0)
+	if idx != len(src)-1 {
+		return &invalidMessageFormatErr{messageType: "CopyFail"}
+	}
+
+	dst.Message = string(src[:idx])
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *CopyFail) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'f')
+	dst = append(dst, src.Message...)
+	dst = append(dst, 0)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyFail) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type    string
+		Message string
+	}{
+		Type:    "CopyFail",
+		Message: src.Message,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/copy_in_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_in_response.go
new file mode 100644
index 000000000..0633935b9
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_in_response.go
@@ -0,0 +1,96 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type CopyInResponse struct {
+	OverallFormat     byte
+	ColumnFormatCodes []uint16
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CopyInResponse) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *CopyInResponse) Decode(src []byte) error {
+	buf := bytes.NewBuffer(src)
+
+	if buf.Len() < 3 {
+		return &invalidMessageFormatErr{messageType: "CopyInResponse"}
+	}
+
+	overallFormat := buf.Next(1)[0]
+
+	columnCount := int(binary.BigEndian.Uint16(buf.Next(2)))
+	if buf.Len() != columnCount*2 {
+		return &invalidMessageFormatErr{messageType: "CopyInResponse"}
+	}
+
+	columnFormatCodes := make([]uint16, columnCount)
+	for i := range columnCount {
+		columnFormatCodes[i] = binary.BigEndian.Uint16(buf.Next(2))
+	}
+
+	*dst = CopyInResponse{OverallFormat: overallFormat, ColumnFormatCodes: columnFormatCodes}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *CopyInResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'G')
+
+	dst = append(dst, src.OverallFormat)
+	if len(src.ColumnFormatCodes) > math.MaxUint16 {
+		return nil, errors.New("too many column format codes")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
+	for _, fc := range src.ColumnFormatCodes {
+		dst = pgio.AppendUint16(dst, fc)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyInResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type              string
+		ColumnFormatCodes []uint16
+	}{
+		Type:              "CopyInResponse",
+		ColumnFormatCodes: src.ColumnFormatCodes,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CopyInResponse) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		OverallFormat     string
+		ColumnFormatCodes []uint16
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	if len(msg.OverallFormat) != 1 {
+		return errors.New("invalid length for CopyInResponse.OverallFormat")
+	}
+
+	dst.OverallFormat = msg.OverallFormat[0]
+	dst.ColumnFormatCodes = msg.ColumnFormatCodes
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/copy_out_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_out_response.go
new file mode 100644
index 000000000..006864ac8
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/copy_out_response.go
@@ -0,0 +1,96 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type CopyOutResponse struct {
+	OverallFormat     byte
+	ColumnFormatCodes []uint16
+}
+
+func (*CopyOutResponse) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *CopyOutResponse) Decode(src []byte) error {
+	buf := bytes.NewBuffer(src)
+
+	if buf.Len() < 3 {
+		return &invalidMessageFormatErr{messageType: "CopyOutResponse"}
+	}
+
+	overallFormat := buf.Next(1)[0]
+
+	columnCount := int(binary.BigEndian.Uint16(buf.Next(2)))
+	if buf.Len() != columnCount*2 {
+		return &invalidMessageFormatErr{messageType: "CopyOutResponse"}
+	}
+
+	columnFormatCodes := make([]uint16, columnCount)
+	for i := range columnCount {
+		columnFormatCodes[i] = binary.BigEndian.Uint16(buf.Next(2))
+	}
+
+	*dst = CopyOutResponse{OverallFormat: overallFormat, ColumnFormatCodes: columnFormatCodes}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *CopyOutResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'H')
+
+	dst = append(dst, src.OverallFormat)
+
+	if len(src.ColumnFormatCodes) > math.MaxUint16 {
+		return nil, errors.New("too many column format codes")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
+	for _, fc := range src.ColumnFormatCodes {
+		dst = pgio.AppendUint16(dst, fc)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyOutResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type              string
+		ColumnFormatCodes []uint16
+	}{
+		Type:              "CopyOutResponse",
+		ColumnFormatCodes: src.ColumnFormatCodes,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CopyOutResponse) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		OverallFormat     string
+		ColumnFormatCodes []uint16
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	if len(msg.OverallFormat) != 1 {
+		return errors.New("invalid length for CopyOutResponse.OverallFormat")
+	}
+
+	dst.OverallFormat = msg.OverallFormat[0]
+	dst.ColumnFormatCodes = msg.ColumnFormatCodes
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/data_row.go b/vendor/github.com/jackc/pgx/v5/pgproto3/data_row.go
new file mode 100644
index 000000000..54418d58c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/data_row.go
@@ -0,0 +1,140 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type DataRow struct {
+	Values [][]byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*DataRow) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *DataRow) Decode(src []byte) error {
+	if len(src) < 2 {
+		return &invalidMessageFormatErr{messageType: "DataRow"}
+	}
+	rp := 0
+	fieldCount := int(binary.BigEndian.Uint16(src[rp:]))
+	rp += 2
+
+	// If the capacity of the values slice is too small OR substantially too
+	// large reallocate. This is too avoid one row with many columns from
+	// permanently allocating memory.
+	if cap(dst.Values) < fieldCount || cap(dst.Values)-fieldCount > 32 {
+		newCap := max(32, fieldCount)
+		dst.Values = make([][]byte, fieldCount, newCap)
+	} else {
+		dst.Values = dst.Values[:fieldCount]
+	}
+
+	for i := range fieldCount {
+		if len(src[rp:]) < 4 {
+			return &invalidMessageFormatErr{messageType: "DataRow"}
+		}
+
+		valueLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
+		rp += 4
+
+		// null
+		if valueLen == -1 {
+			dst.Values[i] = nil
+		} else {
+			if len(src[rp:]) < valueLen || valueLen < 0 {
+				return &invalidMessageFormatErr{messageType: "DataRow"}
+			}
+
+			dst.Values[i] = src[rp : rp+valueLen : rp+valueLen]
+			rp += valueLen
+		}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *DataRow) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'D')
+
+	if len(src.Values) > math.MaxUint16 {
+		return nil, errors.New("too many values")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.Values)))
+	for _, v := range src.Values {
+		if v == nil {
+			dst = pgio.AppendInt32(dst, -1)
+			continue
+		}
+
+		dst = pgio.AppendInt32(dst, int32(len(v)))
+		dst = append(dst, v...)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src DataRow) MarshalJSON() ([]byte, error) {
+	formattedValues := make([]map[string]string, len(src.Values))
+	for i, v := range src.Values {
+		if v == nil {
+			continue
+		}
+
+		var hasNonPrintable bool
+		for _, b := range v {
+			if b < 32 {
+				hasNonPrintable = true
+				break
+			}
+		}
+
+		if hasNonPrintable {
+			formattedValues[i] = map[string]string{"binary": hex.EncodeToString(v)}
+		} else {
+			formattedValues[i] = map[string]string{"text": string(v)}
+		}
+	}
+
+	return json.Marshal(struct {
+		Type   string
+		Values []map[string]string
+	}{
+		Type:   "DataRow",
+		Values: formattedValues,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *DataRow) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Values []map[string]string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.Values = make([][]byte, len(msg.Values))
+	for n, parameter := range msg.Values {
+		var err error
+		dst.Values[n], err = getValueFromJSON(parameter)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/describe.go b/vendor/github.com/jackc/pgx/v5/pgproto3/describe.go
new file mode 100644
index 000000000..0c396f1ba
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/describe.go
@@ -0,0 +1,80 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+)
+
+type Describe struct {
+	ObjectType byte // 'S' = prepared statement, 'P' = portal
+	Name       string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Describe) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Describe) Decode(src []byte) error {
+	if len(src) < 2 {
+		return &invalidMessageFormatErr{messageType: "Describe"}
+	}
+
+	dst.ObjectType = src[0]
+	rp := 1
+
+	idx := bytes.IndexByte(src[rp:], 0)
+	if idx != len(src[rp:])-1 {
+		return &invalidMessageFormatErr{messageType: "Describe"}
+	}
+
+	dst.Name = string(src[rp : len(src)-1])
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Describe) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'D')
+	dst = append(dst, src.ObjectType)
+	dst = append(dst, src.Name...)
+	dst = append(dst, 0)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Describe) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type       string
+		ObjectType string
+		Name       string
+	}{
+		Type:       "Describe",
+		ObjectType: string(src.ObjectType),
+		Name:       src.Name,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *Describe) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		ObjectType string
+		Name       string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	if len(msg.ObjectType) != 1 {
+		return errors.New("invalid length for Describe.ObjectType")
+	}
+
+	dst.ObjectType = msg.ObjectType[0]
+	dst.Name = msg.Name
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/doc.go b/vendor/github.com/jackc/pgx/v5/pgproto3/doc.go
new file mode 100644
index 000000000..0afd18e29
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/doc.go
@@ -0,0 +1,11 @@
+// Package pgproto3 is an encoder and decoder of the PostgreSQL wire protocol version 3.
+//
+// The primary interfaces are Frontend and Backend. They correspond to a client and server respectively. Messages are
+// sent with Send (or a specialized Send variant). Messages are automatically buffered to minimize small writes. Call
+// Flush to ensure a message has actually been sent.
+//
+// The Trace method of Frontend and Backend can be used to examine the wire-level message traffic. It outputs in a
+// similar format to the PQtrace function in libpq.
+//
+// See https://www.postgresql.org/docs/current/protocol-message-formats.html for meanings of the different messages.
+package pgproto3
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/empty_query_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/empty_query_response.go
new file mode 100644
index 000000000..cb6cca073
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/empty_query_response.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type EmptyQueryResponse struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*EmptyQueryResponse) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *EmptyQueryResponse) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "EmptyQueryResponse", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *EmptyQueryResponse) Encode(dst []byte) ([]byte, error) {
+	return append(dst, 'I', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src EmptyQueryResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "EmptyQueryResponse",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/error_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/error_response.go
new file mode 100644
index 000000000..6ef9bd061
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/error_response.go
@@ -0,0 +1,326 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/json"
+	"strconv"
+)
+
+type ErrorResponse struct {
+	Severity            string
+	SeverityUnlocalized string // only in 9.6 and greater
+	Code                string
+	Message             string
+	Detail              string
+	Hint                string
+	Position            int32
+	InternalPosition    int32
+	InternalQuery       string
+	Where               string
+	SchemaName          string
+	TableName           string
+	ColumnName          string
+	DataTypeName        string
+	ConstraintName      string
+	File                string
+	Line                int32
+	Routine             string
+
+	UnknownFields map[byte]string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ErrorResponse) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *ErrorResponse) Decode(src []byte) error {
+	*dst = ErrorResponse{}
+
+	buf := bytes.NewBuffer(src)
+
+	for {
+		k, err := buf.ReadByte()
+		if err != nil {
+			return err
+		}
+		if k == 0 {
+			break
+		}
+
+		vb, err := buf.ReadBytes(0)
+		if err != nil {
+			return err
+		}
+		v := string(vb[:len(vb)-1])
+
+		switch k {
+		case 'S':
+			dst.Severity = v
+		case 'V':
+			dst.SeverityUnlocalized = v
+		case 'C':
+			dst.Code = v
+		case 'M':
+			dst.Message = v
+		case 'D':
+			dst.Detail = v
+		case 'H':
+			dst.Hint = v
+		case 'P':
+			s := v
+			n, _ := strconv.ParseInt(s, 10, 32)
+			dst.Position = int32(n)
+		case 'p':
+			s := v
+			n, _ := strconv.ParseInt(s, 10, 32)
+			dst.InternalPosition = int32(n)
+		case 'q':
+			dst.InternalQuery = v
+		case 'W':
+			dst.Where = v
+		case 's':
+			dst.SchemaName = v
+		case 't':
+			dst.TableName = v
+		case 'c':
+			dst.ColumnName = v
+		case 'd':
+			dst.DataTypeName = v
+		case 'n':
+			dst.ConstraintName = v
+		case 'F':
+			dst.File = v
+		case 'L':
+			s := v
+			n, _ := strconv.ParseInt(s, 10, 32)
+			dst.Line = int32(n)
+		case 'R':
+			dst.Routine = v
+
+		default:
+			if dst.UnknownFields == nil {
+				dst.UnknownFields = make(map[byte]string)
+			}
+			dst.UnknownFields[k] = v
+		}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *ErrorResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'E')
+	dst = src.appendFields(dst)
+	return finishMessage(dst, sp)
+}
+
+func (src *ErrorResponse) appendFields(dst []byte) []byte {
+	if src.Severity != "" {
+		dst = append(dst, 'S')
+		dst = append(dst, src.Severity...)
+		dst = append(dst, 0)
+	}
+	if src.SeverityUnlocalized != "" {
+		dst = append(dst, 'V')
+		dst = append(dst, src.SeverityUnlocalized...)
+		dst = append(dst, 0)
+	}
+	if src.Code != "" {
+		dst = append(dst, 'C')
+		dst = append(dst, src.Code...)
+		dst = append(dst, 0)
+	}
+	if src.Message != "" {
+		dst = append(dst, 'M')
+		dst = append(dst, src.Message...)
+		dst = append(dst, 0)
+	}
+	if src.Detail != "" {
+		dst = append(dst, 'D')
+		dst = append(dst, src.Detail...)
+		dst = append(dst, 0)
+	}
+	if src.Hint != "" {
+		dst = append(dst, 'H')
+		dst = append(dst, src.Hint...)
+		dst = append(dst, 0)
+	}
+	if src.Position != 0 {
+		dst = append(dst, 'P')
+		dst = append(dst, strconv.Itoa(int(src.Position))...)
+		dst = append(dst, 0)
+	}
+	if src.InternalPosition != 0 {
+		dst = append(dst, 'p')
+		dst = append(dst, strconv.Itoa(int(src.InternalPosition))...)
+		dst = append(dst, 0)
+	}
+	if src.InternalQuery != "" {
+		dst = append(dst, 'q')
+		dst = append(dst, src.InternalQuery...)
+		dst = append(dst, 0)
+	}
+	if src.Where != "" {
+		dst = append(dst, 'W')
+		dst = append(dst, src.Where...)
+		dst = append(dst, 0)
+	}
+	if src.SchemaName != "" {
+		dst = append(dst, 's')
+		dst = append(dst, src.SchemaName...)
+		dst = append(dst, 0)
+	}
+	if src.TableName != "" {
+		dst = append(dst, 't')
+		dst = append(dst, src.TableName...)
+		dst = append(dst, 0)
+	}
+	if src.ColumnName != "" {
+		dst = append(dst, 'c')
+		dst = append(dst, src.ColumnName...)
+		dst = append(dst, 0)
+	}
+	if src.DataTypeName != "" {
+		dst = append(dst, 'd')
+		dst = append(dst, src.DataTypeName...)
+		dst = append(dst, 0)
+	}
+	if src.ConstraintName != "" {
+		dst = append(dst, 'n')
+		dst = append(dst, src.ConstraintName...)
+		dst = append(dst, 0)
+	}
+	if src.File != "" {
+		dst = append(dst, 'F')
+		dst = append(dst, src.File...)
+		dst = append(dst, 0)
+	}
+	if src.Line != 0 {
+		dst = append(dst, 'L')
+		dst = append(dst, strconv.Itoa(int(src.Line))...)
+		dst = append(dst, 0)
+	}
+	if src.Routine != "" {
+		dst = append(dst, 'R')
+		dst = append(dst, src.Routine...)
+		dst = append(dst, 0)
+	}
+
+	for k, v := range src.UnknownFields {
+		dst = append(dst, k)
+		dst = append(dst, v...)
+		dst = append(dst, 0)
+	}
+
+	dst = append(dst, 0)
+
+	return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src ErrorResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type                string
+		Severity            string
+		SeverityUnlocalized string // only in 9.6 and greater
+		Code                string
+		Message             string
+		Detail              string
+		Hint                string
+		Position            int32
+		InternalPosition    int32
+		InternalQuery       string
+		Where               string
+		SchemaName          string
+		TableName           string
+		ColumnName          string
+		DataTypeName        string
+		ConstraintName      string
+		File                string
+		Line                int32
+		Routine             string
+
+		UnknownFields map[byte]string
+	}{
+		Type:                "ErrorResponse",
+		Severity:            src.Severity,
+		SeverityUnlocalized: src.SeverityUnlocalized,
+		Code:                src.Code,
+		Message:             src.Message,
+		Detail:              src.Detail,
+		Hint:                src.Hint,
+		Position:            src.Position,
+		InternalPosition:    src.InternalPosition,
+		InternalQuery:       src.InternalQuery,
+		Where:               src.Where,
+		SchemaName:          src.SchemaName,
+		TableName:           src.TableName,
+		ColumnName:          src.ColumnName,
+		DataTypeName:        src.DataTypeName,
+		ConstraintName:      src.ConstraintName,
+		File:                src.File,
+		Line:                src.Line,
+		Routine:             src.Routine,
+		UnknownFields:       src.UnknownFields,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *ErrorResponse) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Type                string
+		Severity            string
+		SeverityUnlocalized string // only in 9.6 and greater
+		Code                string
+		Message             string
+		Detail              string
+		Hint                string
+		Position            int32
+		InternalPosition    int32
+		InternalQuery       string
+		Where               string
+		SchemaName          string
+		TableName           string
+		ColumnName          string
+		DataTypeName        string
+		ConstraintName      string
+		File                string
+		Line                int32
+		Routine             string
+
+		UnknownFields map[byte]string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.Severity = msg.Severity
+	dst.SeverityUnlocalized = msg.SeverityUnlocalized
+	dst.Code = msg.Code
+	dst.Message = msg.Message
+	dst.Detail = msg.Detail
+	dst.Hint = msg.Hint
+	dst.Position = msg.Position
+	dst.InternalPosition = msg.InternalPosition
+	dst.InternalQuery = msg.InternalQuery
+	dst.Where = msg.Where
+	dst.SchemaName = msg.SchemaName
+	dst.TableName = msg.TableName
+	dst.ColumnName = msg.ColumnName
+	dst.DataTypeName = msg.DataTypeName
+	dst.ConstraintName = msg.ConstraintName
+	dst.File = msg.File
+	dst.Line = msg.Line
+	dst.Routine = msg.Routine
+
+	dst.UnknownFields = msg.UnknownFields
+
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/execute.go b/vendor/github.com/jackc/pgx/v5/pgproto3/execute.go
new file mode 100644
index 000000000..31bc714d1
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/execute.go
@@ -0,0 +1,58 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Execute struct {
+	Portal  string
+	MaxRows uint32
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Execute) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Execute) Decode(src []byte) error {
+	buf := bytes.NewBuffer(src)
+
+	b, err := buf.ReadBytes(0)
+	if err != nil {
+		return err
+	}
+	dst.Portal = string(b[:len(b)-1])
+
+	if buf.Len() < 4 {
+		return &invalidMessageFormatErr{messageType: "Execute"}
+	}
+	dst.MaxRows = binary.BigEndian.Uint32(buf.Next(4))
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Execute) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'E')
+	dst = append(dst, src.Portal...)
+	dst = append(dst, 0)
+	dst = pgio.AppendUint32(dst, src.MaxRows)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Execute) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type    string
+		Portal  string
+		MaxRows uint32
+	}{
+		Type:    "Execute",
+		Portal:  src.Portal,
+		MaxRows: src.MaxRows,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/flush.go b/vendor/github.com/jackc/pgx/v5/pgproto3/flush.go
new file mode 100644
index 000000000..e5dc1fbbd
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/flush.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type Flush struct{}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Flush) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Flush) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "Flush", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Flush) Encode(dst []byte) ([]byte, error) {
+	return append(dst, 'H', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Flush) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "Flush",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go b/vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go
new file mode 100644
index 000000000..9fc85f2c7
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go
@@ -0,0 +1,475 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+)
+
+// Frontend acts as a client for the PostgreSQL wire protocol version 3.
+type Frontend struct {
+	cr *chunkReader
+	w  io.Writer
+
+	// tracer is used to trace messages when Send or Receive is called. This means an outbound message is traced
+	// before it is actually transmitted (i.e. before Flush). It is safe to change this variable when the Frontend is
+	// idle. Setting and unsetting tracer provides equivalent functionality to PQtrace and PQuntrace in libpq.
+	tracer *tracer
+
+	wbuf        []byte
+	encodeError error
+
+	// Backend message flyweights
+	authenticationOk                AuthenticationOk
+	authenticationCleartextPassword AuthenticationCleartextPassword
+	authenticationMD5Password       AuthenticationMD5Password
+	authenticationGSS               AuthenticationGSS
+	authenticationGSSContinue       AuthenticationGSSContinue
+	authenticationSASL              AuthenticationSASL
+	authenticationSASLContinue      AuthenticationSASLContinue
+	authenticationSASLFinal         AuthenticationSASLFinal
+	backendKeyData                  BackendKeyData
+	bindComplete                    BindComplete
+	closeComplete                   CloseComplete
+	commandComplete                 CommandComplete
+	copyBothResponse                CopyBothResponse
+	copyData                        CopyData
+	copyInResponse                  CopyInResponse
+	copyOutResponse                 CopyOutResponse
+	copyDone                        CopyDone
+	dataRow                         DataRow
+	emptyQueryResponse              EmptyQueryResponse
+	errorResponse                   ErrorResponse
+	functionCallResponse            FunctionCallResponse
+	noData                          NoData
+	noticeResponse                  NoticeResponse
+	notificationResponse            NotificationResponse
+	parameterDescription            ParameterDescription
+	parameterStatus                 ParameterStatus
+	parseComplete                   ParseComplete
+	readyForQuery                   ReadyForQuery
+	rowDescription                  RowDescription
+	portalSuspended                 PortalSuspended
+	negotiateProtocolVersion        NegotiateProtocolVersion
+
+	bodyLen    int
+	maxBodyLen int // maxBodyLen is the maximum length of a message body in octets. If a message body exceeds this length, Receive will return an error.
+	msgType    byte
+	partialMsg bool
+	authType   uint32
+}
+
+// NewFrontend creates a new Frontend.
+//
+// The maximum accepted message body length defaults to the same ~1 GiB limit the PostgreSQL
+// server enforces on inbound messages (PQ_LARGE_MESSAGE_LIMIT in src/include/libpq/libpq.h).
+// Use [Frontend.SetMaxBodyLen] to change or remove the limit.
+func NewFrontend(r io.Reader, w io.Writer) *Frontend {
+	cr := newChunkReader(r, 0)
+	return &Frontend{cr: cr, w: w, maxBodyLen: maxMessageBodyLen}
+}
+
+// Send sends a message to the backend (i.e. the server). The message is buffered until Flush is called. Any error
+// encountered will be returned from Flush.
+//
+// Send can work with any FrontendMessage. Some commonly used message types such as Bind have specialized send methods
+// such as SendBind. These methods should be preferred when the type of message is known up front (e.g. when building an
+// extended query protocol query) as they may be faster due to knowing the type of msg rather than it being hidden
+// behind an interface.
+func (f *Frontend) Send(msg FrontendMessage) {
+	if f.encodeError != nil {
+		return
+	}
+
+	prevLen := len(f.wbuf)
+	newBuf, err := msg.Encode(f.wbuf)
+	if err != nil {
+		f.encodeError = err
+		return
+	}
+	f.wbuf = newBuf
+
+	if f.tracer != nil {
+		f.tracer.traceMessage('F', int32(len(f.wbuf)-prevLen), msg)
+	}
+}
+
+// Flush writes any pending messages to the backend (i.e. the server).
+func (f *Frontend) Flush() error {
+	if err := f.encodeError; err != nil {
+		f.encodeError = nil
+		f.wbuf = f.wbuf[:0]
+		return &writeError{err: err, safeToRetry: true}
+	}
+
+	if len(f.wbuf) == 0 {
+		return nil
+	}
+
+	n, err := f.w.Write(f.wbuf)
+
+	const maxLen = 1024
+	if len(f.wbuf) > maxLen {
+		f.wbuf = make([]byte, 0, maxLen)
+	} else {
+		f.wbuf = f.wbuf[:0]
+	}
+
+	if err != nil {
+		return &writeError{err: err, safeToRetry: n == 0}
+	}
+
+	return nil
+}
+
+// Trace starts tracing the message traffic to w. It writes in a similar format to that produced by the libpq function
+// PQtrace.
+func (f *Frontend) Trace(w io.Writer, options TracerOptions) {
+	f.tracer = &tracer{
+		w:             w,
+		buf:           &bytes.Buffer{},
+		TracerOptions: options,
+	}
+}
+
+// Untrace stops tracing.
+func (f *Frontend) Untrace() {
+	f.tracer = nil
+}
+
+// SendBind sends a Bind message to the backend (i.e. the server). The message is buffered until Flush is called. Any
+// error encountered will be returned from Flush.
+func (f *Frontend) SendBind(msg *Bind) {
+	if f.encodeError != nil {
+		return
+	}
+
+	prevLen := len(f.wbuf)
+	newBuf, err := msg.Encode(f.wbuf)
+	if err != nil {
+		f.encodeError = err
+		return
+	}
+	f.wbuf = newBuf
+
+	if f.tracer != nil {
+		f.tracer.traceBind('F', int32(len(f.wbuf)-prevLen), msg)
+	}
+}
+
+// SendParse sends a Parse message to the backend (i.e. the server). The message is buffered until Flush is called. Any
+// error encountered will be returned from Flush.
+func (f *Frontend) SendParse(msg *Parse) {
+	if f.encodeError != nil {
+		return
+	}
+
+	prevLen := len(f.wbuf)
+	newBuf, err := msg.Encode(f.wbuf)
+	if err != nil {
+		f.encodeError = err
+		return
+	}
+	f.wbuf = newBuf
+
+	if f.tracer != nil {
+		f.tracer.traceParse('F', int32(len(f.wbuf)-prevLen), msg)
+	}
+}
+
+// SendClose sends a Close message to the backend (i.e. the server). The message is buffered until Flush is called. Any
+// error encountered will be returned from Flush.
+func (f *Frontend) SendClose(msg *Close) {
+	if f.encodeError != nil {
+		return
+	}
+
+	prevLen := len(f.wbuf)
+	newBuf, err := msg.Encode(f.wbuf)
+	if err != nil {
+		f.encodeError = err
+		return
+	}
+	f.wbuf = newBuf
+
+	if f.tracer != nil {
+		f.tracer.traceClose('F', int32(len(f.wbuf)-prevLen), msg)
+	}
+}
+
+// SendDescribe sends a Describe message to the backend (i.e. the server). The message is buffered until Flush is
+// called. Any error encountered will be returned from Flush.
+func (f *Frontend) SendDescribe(msg *Describe) {
+	if f.encodeError != nil {
+		return
+	}
+
+	prevLen := len(f.wbuf)
+	newBuf, err := msg.Encode(f.wbuf)
+	if err != nil {
+		f.encodeError = err
+		return
+	}
+	f.wbuf = newBuf
+
+	if f.tracer != nil {
+		f.tracer.traceDescribe('F', int32(len(f.wbuf)-prevLen), msg)
+	}
+}
+
+// SendExecute sends an Execute message to the backend (i.e. the server). The message is buffered until Flush is called.
+// Any error encountered will be returned from Flush.
+func (f *Frontend) SendExecute(msg *Execute) {
+	if f.encodeError != nil {
+		return
+	}
+
+	prevLen := len(f.wbuf)
+	newBuf, err := msg.Encode(f.wbuf)
+	if err != nil {
+		f.encodeError = err
+		return
+	}
+	f.wbuf = newBuf
+
+	if f.tracer != nil {
+		f.tracer.traceExecute('F', int32(len(f.wbuf)-prevLen), msg)
+	}
+}
+
+// SendSync sends a Sync message to the backend (i.e. the server). The message is buffered until Flush is called. Any
+// error encountered will be returned from Flush.
+func (f *Frontend) SendSync(msg *Sync) {
+	if f.encodeError != nil {
+		return
+	}
+
+	prevLen := len(f.wbuf)
+	newBuf, err := msg.Encode(f.wbuf)
+	if err != nil {
+		f.encodeError = err
+		return
+	}
+	f.wbuf = newBuf
+
+	if f.tracer != nil {
+		f.tracer.traceSync('F', int32(len(f.wbuf)-prevLen), msg)
+	}
+}
+
+// SendQuery sends a Query message to the backend (i.e. the server). The message is buffered until Flush is called. Any
+// error encountered will be returned from Flush.
+func (f *Frontend) SendQuery(msg *Query) {
+	if f.encodeError != nil {
+		return
+	}
+
+	prevLen := len(f.wbuf)
+	newBuf, err := msg.Encode(f.wbuf)
+	if err != nil {
+		f.encodeError = err
+		return
+	}
+	f.wbuf = newBuf
+
+	if f.tracer != nil {
+		f.tracer.traceQuery('F', int32(len(f.wbuf)-prevLen), msg)
+	}
+}
+
+// SendUnbufferedEncodedCopyData immediately sends an encoded CopyData message to the backend (i.e. the server). This method
+// is more efficient than sending a CopyData message with Send as the message data is not copied to the internal buffer
+// before being written out. The internal buffer is flushed before the message is sent.
+func (f *Frontend) SendUnbufferedEncodedCopyData(msg []byte) error {
+	err := f.Flush()
+	if err != nil {
+		return err
+	}
+
+	n, err := f.w.Write(msg)
+	if err != nil {
+		return &writeError{err: err, safeToRetry: n == 0}
+	}
+
+	if f.tracer != nil {
+		f.tracer.traceCopyData('F', int32(len(msg)-1), &CopyData{})
+	}
+
+	return nil
+}
+
+func translateEOFtoErrUnexpectedEOF(err error) error {
+	if err == io.EOF {
+		return io.ErrUnexpectedEOF
+	}
+	return err
+}
+
+// Receive receives a message from the backend. The returned message is only valid until the next call to Receive.
+func (f *Frontend) Receive() (BackendMessage, error) {
+	if !f.partialMsg {
+		header, err := f.cr.Next(5)
+		if err != nil {
+			return nil, translateEOFtoErrUnexpectedEOF(err)
+		}
+
+		f.msgType = header[0]
+
+		msgLength := int(int32(binary.BigEndian.Uint32(header[1:])))
+		if msgLength < 4 {
+			return nil, fmt.Errorf("invalid message length: %d", msgLength)
+		}
+
+		f.bodyLen = msgLength - 4
+		if f.maxBodyLen > 0 && f.bodyLen > f.maxBodyLen {
+			return nil, &ExceededMaxBodyLenErr{f.maxBodyLen, f.bodyLen}
+		}
+		f.partialMsg = true
+	}
+
+	msgBody, err := f.cr.Next(f.bodyLen)
+	if err != nil {
+		return nil, translateEOFtoErrUnexpectedEOF(err)
+	}
+
+	f.partialMsg = false
+
+	var msg BackendMessage
+	switch f.msgType {
+	case '1':
+		msg = &f.parseComplete
+	case '2':
+		msg = &f.bindComplete
+	case '3':
+		msg = &f.closeComplete
+	case 'A':
+		msg = &f.notificationResponse
+	case 'c':
+		msg = &f.copyDone
+	case 'C':
+		msg = &f.commandComplete
+	case 'd':
+		msg = &f.copyData
+	case 'D':
+		msg = &f.dataRow
+	case 'E':
+		msg = &f.errorResponse
+	case 'G':
+		msg = &f.copyInResponse
+	case 'H':
+		msg = &f.copyOutResponse
+	case 'I':
+		msg = &f.emptyQueryResponse
+	case 'K':
+		msg = &f.backendKeyData
+	case 'n':
+		msg = &f.noData
+	case 'N':
+		msg = &f.noticeResponse
+	case 'R':
+		var err error
+		msg, err = f.findAuthenticationMessageType(msgBody)
+		if err != nil {
+			return nil, err
+		}
+	case 's':
+		msg = &f.portalSuspended
+	case 'S':
+		msg = &f.parameterStatus
+	case 't':
+		msg = &f.parameterDescription
+	case 'T':
+		msg = &f.rowDescription
+	case 'V':
+		msg = &f.functionCallResponse
+	case 'W':
+		msg = &f.copyBothResponse
+	case 'Z':
+		msg = &f.readyForQuery
+	case 'v':
+		msg = &f.negotiateProtocolVersion
+	default:
+		return nil, fmt.Errorf("unknown message type: %c", f.msgType)
+	}
+
+	err = msg.Decode(msgBody)
+	if err != nil {
+		return nil, err
+	}
+
+	if f.tracer != nil {
+		f.tracer.traceMessage('B', int32(5+len(msgBody)), msg)
+	}
+
+	return msg, nil
+}
+
+// Authentication message type constants.
+// See src/include/libpq/pqcomm.h for all
+// constants.
+const (
+	AuthTypeOk                = 0
+	AuthTypeCleartextPassword = 3
+	AuthTypeMD5Password       = 5
+	AuthTypeSCMCreds          = 6
+	AuthTypeGSS               = 7
+	AuthTypeGSSCont           = 8
+	AuthTypeSSPI              = 9
+	AuthTypeSASL              = 10
+	AuthTypeSASLContinue      = 11
+	AuthTypeSASLFinal         = 12
+)
+
+func (f *Frontend) findAuthenticationMessageType(src []byte) (BackendMessage, error) {
+	if len(src) < 4 {
+		return nil, errors.New("authentication message too short")
+	}
+	f.authType = binary.BigEndian.Uint32(src[:4])
+
+	switch f.authType {
+	case AuthTypeOk:
+		return &f.authenticationOk, nil
+	case AuthTypeCleartextPassword:
+		return &f.authenticationCleartextPassword, nil
+	case AuthTypeMD5Password:
+		return &f.authenticationMD5Password, nil
+	case AuthTypeSCMCreds:
+		return nil, errors.New("AuthTypeSCMCreds is unimplemented")
+	case AuthTypeGSS:
+		return &f.authenticationGSS, nil
+	case AuthTypeGSSCont:
+		return &f.authenticationGSSContinue, nil
+	case AuthTypeSSPI:
+		return nil, errors.New("AuthTypeSSPI is unimplemented")
+	case AuthTypeSASL:
+		return &f.authenticationSASL, nil
+	case AuthTypeSASLContinue:
+		return &f.authenticationSASLContinue, nil
+	case AuthTypeSASLFinal:
+		return &f.authenticationSASLFinal, nil
+	default:
+		return nil, fmt.Errorf("unknown authentication type: %d", f.authType)
+	}
+}
+
+// GetAuthType returns the authType used in the current state of the frontend.
+// See SetAuthType for more information.
+func (f *Frontend) GetAuthType() uint32 {
+	return f.authType
+}
+
+func (f *Frontend) ReadBufferLen() int {
+	return f.cr.wp - f.cr.rp
+}
+
+// SetMaxBodyLen sets the maximum length of a message body in octets.
+// If a message body exceeds this length, Receive will return an error.
+// This is useful for protecting against a corrupted server that sends
+// messages with incorrect length, which can cause memory exhaustion.
+// The default value is 0.
+// If maxBodyLen is 0, then no maximum is enforced.
+func (f *Frontend) SetMaxBodyLen(maxBodyLen int) {
+	f.maxBodyLen = maxBodyLen
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/function_call.go b/vendor/github.com/jackc/pgx/v5/pgproto3/function_call.go
new file mode 100644
index 000000000..ef3cfd3b8
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/function_call.go
@@ -0,0 +1,124 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"errors"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type FunctionCall struct {
+	Function         uint32
+	ArgFormatCodes   []uint16
+	Arguments        [][]byte
+	ResultFormatCode uint16
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*FunctionCall) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *FunctionCall) Decode(src []byte) error {
+	*dst = FunctionCall{}
+	rp := 0
+
+	if len(src) < 8 {
+		return &invalidMessageFormatErr{messageType: "FunctionCall"}
+	}
+
+	// Specifies the object ID of the function to call.
+	dst.Function = binary.BigEndian.Uint32(src[rp:])
+	rp += 4
+	// The number of argument format codes that follow (denoted C below).
+	// This can be zero to indicate that there are no arguments or that the arguments all use the default format (text);
+	// or one, in which case the specified format code is applied to all arguments;
+	// or it can equal the actual number of arguments.
+	nArgumentCodes := int(binary.BigEndian.Uint16(src[rp:]))
+	rp += 2
+
+	if len(src[rp:]) < nArgumentCodes*2+2 {
+		return &invalidMessageFormatErr{messageType: "FunctionCall"}
+	}
+
+	argumentCodes := make([]uint16, nArgumentCodes)
+	for i := range nArgumentCodes {
+		// The argument format codes. Each must presently be zero (text) or one (binary).
+		ac := binary.BigEndian.Uint16(src[rp:])
+		if ac != 0 && ac != 1 {
+			return &invalidMessageFormatErr{messageType: "FunctionCall"}
+		}
+		argumentCodes[i] = ac
+		rp += 2
+	}
+	dst.ArgFormatCodes = argumentCodes
+
+	// Specifies the number of arguments being supplied to the function.
+	nArguments := int(binary.BigEndian.Uint16(src[rp:]))
+	rp += 2
+	arguments := make([][]byte, nArguments)
+	for i := range nArguments {
+		if len(src[rp:]) < 4 {
+			return &invalidMessageFormatErr{messageType: "FunctionCall"}
+		}
+		// The length of the argument value, in bytes (this count does not include itself). Can be zero.
+		// As a special case, -1 indicates a NULL argument value. No value bytes follow in the NULL case.
+		argumentLength := int(int32(binary.BigEndian.Uint32(src[rp:])))
+		rp += 4
+		switch {
+		case argumentLength == -1:
+			arguments[i] = nil
+		case argumentLength < 0:
+			return &invalidMessageFormatErr{messageType: "FunctionCall"}
+		default:
+			if len(src[rp:]) < argumentLength {
+				return &invalidMessageFormatErr{messageType: "FunctionCall"}
+			}
+			// The value of the argument, in the format indicated by the associated format code. n is the above length.
+			argumentValue := src[rp : rp+argumentLength]
+			rp += argumentLength
+			arguments[i] = argumentValue
+		}
+	}
+	dst.Arguments = arguments
+	// The format code for the function result. Must presently be zero (text) or one (binary).
+	if len(src[rp:]) < 2 {
+		return &invalidMessageFormatErr{messageType: "FunctionCall"}
+	}
+	resultFormatCode := binary.BigEndian.Uint16(src[rp:])
+	if resultFormatCode != 0 && resultFormatCode != 1 {
+		return &invalidMessageFormatErr{messageType: "FunctionCall"}
+	}
+	dst.ResultFormatCode = resultFormatCode
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *FunctionCall) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'F')
+	dst = pgio.AppendUint32(dst, src.Function)
+
+	if len(src.ArgFormatCodes) > math.MaxUint16 {
+		return nil, errors.New("too many arg format codes")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.ArgFormatCodes)))
+	for _, argFormatCode := range src.ArgFormatCodes {
+		dst = pgio.AppendUint16(dst, argFormatCode)
+	}
+
+	if len(src.Arguments) > math.MaxUint16 {
+		return nil, errors.New("too many arguments")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.Arguments)))
+	for _, argument := range src.Arguments {
+		if argument == nil {
+			dst = pgio.AppendInt32(dst, -1)
+		} else {
+			dst = pgio.AppendInt32(dst, int32(len(argument)))
+			dst = append(dst, argument...)
+		}
+	}
+	dst = pgio.AppendUint16(dst, src.ResultFormatCode)
+	return finishMessage(dst, sp)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/function_call_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/function_call_response.go
new file mode 100644
index 000000000..6b6ed8b92
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/function_call_response.go
@@ -0,0 +1,97 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/hex"
+	"encoding/json"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type FunctionCallResponse struct {
+	Result []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*FunctionCallResponse) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *FunctionCallResponse) Decode(src []byte) error {
+	if len(src) < 4 {
+		return &invalidMessageFormatErr{messageType: "FunctionCallResponse"}
+	}
+	rp := 0
+	resultSize := int(int32(binary.BigEndian.Uint32(src[rp:])))
+	rp += 4
+
+	if resultSize == -1 {
+		dst.Result = nil
+		return nil
+	}
+
+	if resultSize < 0 || len(src[rp:]) != resultSize {
+		return &invalidMessageFormatErr{messageType: "FunctionCallResponse"}
+	}
+
+	dst.Result = src[rp:]
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *FunctionCallResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'V')
+
+	if src.Result == nil {
+		dst = pgio.AppendInt32(dst, -1)
+	} else {
+		dst = pgio.AppendInt32(dst, int32(len(src.Result)))
+		dst = append(dst, src.Result...)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src FunctionCallResponse) MarshalJSON() ([]byte, error) {
+	var formattedValue map[string]string
+	var hasNonPrintable bool
+	for _, b := range src.Result {
+		if b < 32 {
+			hasNonPrintable = true
+			break
+		}
+	}
+
+	if hasNonPrintable {
+		formattedValue = map[string]string{"binary": hex.EncodeToString(src.Result)}
+	} else {
+		formattedValue = map[string]string{"text": string(src.Result)}
+	}
+
+	return json.Marshal(struct {
+		Type   string
+		Result map[string]string
+	}{
+		Type:   "FunctionCallResponse",
+		Result: formattedValue,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *FunctionCallResponse) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Result map[string]string
+	}
+	err := json.Unmarshal(data, &msg)
+	if err != nil {
+		return err
+	}
+	dst.Result, err = getValueFromJSON(msg.Result)
+	return err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/gss_enc_request.go b/vendor/github.com/jackc/pgx/v5/pgproto3/gss_enc_request.go
new file mode 100644
index 000000000..122d1341c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/gss_enc_request.go
@@ -0,0 +1,48 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+const gssEncReqNumber = 80877104
+
+type GSSEncRequest struct{}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*GSSEncRequest) Frontend() {}
+
+func (dst *GSSEncRequest) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("gss encoding request too short")
+	}
+
+	requestCode := binary.BigEndian.Uint32(src)
+
+	if requestCode != gssEncReqNumber {
+		return errors.New("bad gss encoding request code")
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 4 byte message length.
+func (src *GSSEncRequest) Encode(dst []byte) ([]byte, error) {
+	dst = pgio.AppendInt32(dst, 8)
+	dst = pgio.AppendInt32(dst, gssEncReqNumber)
+	return dst, nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src GSSEncRequest) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type            string
+		ProtocolVersion uint32
+		Parameters      map[string]string
+	}{
+		Type: "GSSEncRequest",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/gss_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/gss_response.go
new file mode 100644
index 000000000..10d937759
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/gss_response.go
@@ -0,0 +1,46 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type GSSResponse struct {
+	Data []byte
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (g *GSSResponse) Frontend() {}
+
+func (g *GSSResponse) Decode(data []byte) error {
+	g.Data = data
+	return nil
+}
+
+func (g *GSSResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'p')
+	dst = append(dst, g.Data...)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (g *GSSResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data []byte
+	}{
+		Type: "GSSResponse",
+		Data: g.Data,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (g *GSSResponse) UnmarshalJSON(data []byte) error {
+	var msg struct {
+		Data []byte
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	g.Data = msg.Data
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/negotiate_protocol_version.go b/vendor/github.com/jackc/pgx/v5/pgproto3/negotiate_protocol_version.go
new file mode 100644
index 000000000..43bd7ec63
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/negotiate_protocol_version.go
@@ -0,0 +1,93 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type NegotiateProtocolVersion struct {
+	NewestMinorProtocol uint32
+	UnrecognizedOptions []string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*NegotiateProtocolVersion) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *NegotiateProtocolVersion) Decode(src []byte) error {
+	if len(src) < 8 {
+		return &invalidMessageLenErr{messageType: "NegotiateProtocolVersion", expectedLen: 8, actualLen: len(src)}
+	}
+
+	dst.NewestMinorProtocol = binary.BigEndian.Uint32(src[:4])
+	optionCount := int(binary.BigEndian.Uint32(src[4:8]))
+
+	rp := 8
+
+	// Use the remaining message size as an upper bound for capacity to prevent
+	// malicious optionCount values from causing excessive memory allocation.
+	capHint := optionCount
+	if remaining := len(src) - rp; capHint > remaining {
+		capHint = remaining
+	}
+	dst.UnrecognizedOptions = make([]string, 0, capHint)
+	for i := 0; i < optionCount; i++ {
+		if rp >= len(src) {
+			return &invalidMessageFormatErr{messageType: "NegotiateProtocolVersion"}
+		}
+		end := rp
+		for end < len(src) && src[end] != 0 {
+			end++
+		}
+		if end >= len(src) {
+			return &invalidMessageFormatErr{messageType: "NegotiateProtocolVersion"}
+		}
+		dst.UnrecognizedOptions = append(dst.UnrecognizedOptions, string(src[rp:end]))
+		rp = end + 1
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *NegotiateProtocolVersion) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'v')
+	dst = pgio.AppendUint32(dst, src.NewestMinorProtocol)
+	dst = pgio.AppendUint32(dst, uint32(len(src.UnrecognizedOptions)))
+	for _, option := range src.UnrecognizedOptions {
+		dst = append(dst, option...)
+		dst = append(dst, 0)
+	}
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src NegotiateProtocolVersion) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type                string
+		NewestMinorProtocol uint32
+		UnrecognizedOptions []string
+	}{
+		Type:                "NegotiateProtocolVersion",
+		NewestMinorProtocol: src.NewestMinorProtocol,
+		UnrecognizedOptions: src.UnrecognizedOptions,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *NegotiateProtocolVersion) UnmarshalJSON(data []byte) error {
+	var msg struct {
+		NewestMinorProtocol uint32
+		UnrecognizedOptions []string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	dst.NewestMinorProtocol = msg.NewestMinorProtocol
+	dst.UnrecognizedOptions = msg.UnrecognizedOptions
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/no_data.go b/vendor/github.com/jackc/pgx/v5/pgproto3/no_data.go
new file mode 100644
index 000000000..cbcaad40c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/no_data.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type NoData struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*NoData) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *NoData) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "NoData", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *NoData) Encode(dst []byte) ([]byte, error) {
+	return append(dst, 'n', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src NoData) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "NoData",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/notice_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/notice_response.go
new file mode 100644
index 000000000..497aba6dd
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/notice_response.go
@@ -0,0 +1,19 @@
+package pgproto3
+
+type NoticeResponse ErrorResponse
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*NoticeResponse) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *NoticeResponse) Decode(src []byte) error {
+	return (*ErrorResponse)(dst).Decode(src)
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *NoticeResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'N')
+	dst = (*ErrorResponse)(src).appendFields(dst)
+	return finishMessage(dst, sp)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/notification_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/notification_response.go
new file mode 100644
index 000000000..243b6bf7c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/notification_response.go
@@ -0,0 +1,71 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type NotificationResponse struct {
+	PID     uint32
+	Channel string
+	Payload string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*NotificationResponse) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *NotificationResponse) Decode(src []byte) error {
+	buf := bytes.NewBuffer(src)
+
+	if buf.Len() < 4 {
+		return &invalidMessageFormatErr{messageType: "NotificationResponse", details: "too short"}
+	}
+
+	pid := binary.BigEndian.Uint32(buf.Next(4))
+
+	b, err := buf.ReadBytes(0)
+	if err != nil {
+		return err
+	}
+	channel := string(b[:len(b)-1])
+
+	b, err = buf.ReadBytes(0)
+	if err != nil {
+		return err
+	}
+	payload := string(b[:len(b)-1])
+
+	*dst = NotificationResponse{PID: pid, Channel: channel, Payload: payload}
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *NotificationResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'A')
+	dst = pgio.AppendUint32(dst, src.PID)
+	dst = append(dst, src.Channel...)
+	dst = append(dst, 0)
+	dst = append(dst, src.Payload...)
+	dst = append(dst, 0)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src NotificationResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type    string
+		PID     uint32
+		Channel string
+		Payload string
+	}{
+		Type:    "NotificationResponse",
+		PID:     src.PID,
+		Channel: src.Channel,
+		Payload: src.Payload,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/parameter_description.go b/vendor/github.com/jackc/pgx/v5/pgproto3/parameter_description.go
new file mode 100644
index 000000000..58eb26ef0
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/parameter_description.go
@@ -0,0 +1,67 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type ParameterDescription struct {
+	ParameterOIDs []uint32
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ParameterDescription) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *ParameterDescription) Decode(src []byte) error {
+	buf := bytes.NewBuffer(src)
+
+	if buf.Len() < 2 {
+		return &invalidMessageFormatErr{messageType: "ParameterDescription"}
+	}
+
+	// Reported parameter count will be incorrect when number of args is greater than uint16
+	buf.Next(2)
+	// Instead infer parameter count by remaining size of message
+	parameterCount := buf.Len() / 4
+
+	*dst = ParameterDescription{ParameterOIDs: make([]uint32, parameterCount)}
+
+	for i := range parameterCount {
+		dst.ParameterOIDs[i] = binary.BigEndian.Uint32(buf.Next(4))
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *ParameterDescription) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 't')
+
+	if len(src.ParameterOIDs) > math.MaxUint16 {
+		return nil, errors.New("too many parameter oids")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs)))
+	for _, oid := range src.ParameterOIDs {
+		dst = pgio.AppendUint32(dst, oid)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src ParameterDescription) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type          string
+		ParameterOIDs []uint32
+	}{
+		Type:          "ParameterDescription",
+		ParameterOIDs: src.ParameterOIDs,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/parameter_status.go b/vendor/github.com/jackc/pgx/v5/pgproto3/parameter_status.go
new file mode 100644
index 000000000..9ee0720b5
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/parameter_status.go
@@ -0,0 +1,58 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/json"
+)
+
+type ParameterStatus struct {
+	Name  string
+	Value string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ParameterStatus) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *ParameterStatus) Decode(src []byte) error {
+	buf := bytes.NewBuffer(src)
+
+	b, err := buf.ReadBytes(0)
+	if err != nil {
+		return err
+	}
+	name := string(b[:len(b)-1])
+
+	b, err = buf.ReadBytes(0)
+	if err != nil {
+		return err
+	}
+	value := string(b[:len(b)-1])
+
+	*dst = ParameterStatus{Name: name, Value: value}
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *ParameterStatus) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'S')
+	dst = append(dst, src.Name...)
+	dst = append(dst, 0)
+	dst = append(dst, src.Value...)
+	dst = append(dst, 0)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (ps ParameterStatus) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type  string
+		Name  string
+		Value string
+	}{
+		Type:  "ParameterStatus",
+		Name:  ps.Name,
+		Value: ps.Value,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/parse.go b/vendor/github.com/jackc/pgx/v5/pgproto3/parse.go
new file mode 100644
index 000000000..8fb8de5d4
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/parse.go
@@ -0,0 +1,89 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Parse struct {
+	Name          string
+	Query         string
+	ParameterOIDs []uint32
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Parse) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Parse) Decode(src []byte) error {
+	*dst = Parse{}
+
+	buf := bytes.NewBuffer(src)
+
+	b, err := buf.ReadBytes(0)
+	if err != nil {
+		return err
+	}
+	dst.Name = string(b[:len(b)-1])
+
+	b, err = buf.ReadBytes(0)
+	if err != nil {
+		return err
+	}
+	dst.Query = string(b[:len(b)-1])
+
+	if buf.Len() < 2 {
+		return &invalidMessageFormatErr{messageType: "Parse"}
+	}
+	parameterOIDCount := int(binary.BigEndian.Uint16(buf.Next(2)))
+
+	for range parameterOIDCount {
+		if buf.Len() < 4 {
+			return &invalidMessageFormatErr{messageType: "Parse"}
+		}
+		dst.ParameterOIDs = append(dst.ParameterOIDs, binary.BigEndian.Uint32(buf.Next(4)))
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Parse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'P')
+
+	dst = append(dst, src.Name...)
+	dst = append(dst, 0)
+	dst = append(dst, src.Query...)
+	dst = append(dst, 0)
+
+	if len(src.ParameterOIDs) > math.MaxUint16 {
+		return nil, errors.New("too many parameter oids")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs)))
+	for _, oid := range src.ParameterOIDs {
+		dst = pgio.AppendUint32(dst, oid)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Parse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type          string
+		Name          string
+		Query         string
+		ParameterOIDs []uint32
+	}{
+		Type:          "Parse",
+		Name:          src.Name,
+		Query:         src.Query,
+		ParameterOIDs: src.ParameterOIDs,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/parse_complete.go b/vendor/github.com/jackc/pgx/v5/pgproto3/parse_complete.go
new file mode 100644
index 000000000..cff9e27d0
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/parse_complete.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type ParseComplete struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ParseComplete) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *ParseComplete) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "ParseComplete", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *ParseComplete) Encode(dst []byte) ([]byte, error) {
+	return append(dst, '1', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src ParseComplete) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "ParseComplete",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/password_message.go b/vendor/github.com/jackc/pgx/v5/pgproto3/password_message.go
new file mode 100644
index 000000000..67b78515d
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/password_message.go
@@ -0,0 +1,49 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/json"
+)
+
+type PasswordMessage struct {
+	Password string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*PasswordMessage) Frontend() {}
+
+// InitialResponse identifies this message as an authentication response.
+func (*PasswordMessage) InitialResponse() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *PasswordMessage) Decode(src []byte) error {
+	buf := bytes.NewBuffer(src)
+
+	b, err := buf.ReadBytes(0)
+	if err != nil {
+		return err
+	}
+	dst.Password = string(b[:len(b)-1])
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *PasswordMessage) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'p')
+	dst = append(dst, src.Password...)
+	dst = append(dst, 0)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src PasswordMessage) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type     string
+		Password string
+	}{
+		Type:     "PasswordMessage",
+		Password: src.Password,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/pgproto3.go b/vendor/github.com/jackc/pgx/v5/pgproto3/pgproto3.go
new file mode 100644
index 000000000..128f97f87
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/pgproto3.go
@@ -0,0 +1,120 @@
+package pgproto3
+
+import (
+	"encoding/hex"
+	"errors"
+	"fmt"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// maxMessageBodyLen is the maximum length of a message body in bytes. See PG_LARGE_MESSAGE_LIMIT in the PostgreSQL
+// source. It is defined as (MaxAllocSize - 1). MaxAllocSize is defined as 0x3fffffff.
+const maxMessageBodyLen = (0x3fffffff - 1)
+
+// Message is the interface implemented by an object that can decode and encode
+// a particular PostgreSQL message.
+type Message interface {
+	// Decode is allowed and expected to retain a reference to data after
+	// returning (unlike encoding.BinaryUnmarshaler).
+	Decode(data []byte) error
+
+	// Encode appends itself to dst and returns the new buffer.
+	Encode(dst []byte) ([]byte, error)
+}
+
+// FrontendMessage is a message sent by the frontend (i.e. the client).
+type FrontendMessage interface {
+	Message
+	Frontend() // no-op method to distinguish frontend from backend methods
+}
+
+// BackendMessage is a message sent by the backend (i.e. the server).
+type BackendMessage interface {
+	Message
+	Backend() // no-op method to distinguish frontend from backend methods
+}
+
+type AuthenticationResponseMessage interface {
+	BackendMessage
+	AuthenticationResponse() // no-op method to distinguish authentication responses
+}
+
+type invalidMessageLenErr struct {
+	messageType string
+	expectedLen int
+	actualLen   int
+}
+
+func (e *invalidMessageLenErr) Error() string {
+	return fmt.Sprintf("%s body must have length of %d, but it is %d", e.messageType, e.expectedLen, e.actualLen)
+}
+
+type invalidMessageFormatErr struct {
+	messageType string
+	details     string
+}
+
+func (e *invalidMessageFormatErr) Error() string {
+	return fmt.Sprintf("%s body is invalid %s", e.messageType, e.details)
+}
+
+type writeError struct {
+	err         error
+	safeToRetry bool
+}
+
+func (e *writeError) Error() string {
+	return fmt.Sprintf("write failed: %s", e.err.Error())
+}
+
+func (e *writeError) SafeToRetry() bool {
+	return e.safeToRetry
+}
+
+func (e *writeError) Unwrap() error {
+	return e.err
+}
+
+type ExceededMaxBodyLenErr struct {
+	MaxExpectedBodyLen int
+	ActualBodyLen      int
+}
+
+func (e *ExceededMaxBodyLenErr) Error() string {
+	return fmt.Sprintf("invalid body length: expected at most %d, but got %d", e.MaxExpectedBodyLen, e.ActualBodyLen)
+}
+
+// getValueFromJSON gets the value from a protocol message representation in JSON.
+func getValueFromJSON(v map[string]string) ([]byte, error) {
+	if v == nil {
+		return nil, nil
+	}
+	if text, ok := v["text"]; ok {
+		return []byte(text), nil
+	}
+	if binary, ok := v["binary"]; ok {
+		return hex.DecodeString(binary)
+	}
+	return nil, errors.New("unknown protocol representation")
+}
+
+// beginMessage begins a new message of type t. It appends the message type and a placeholder for the message length to
+// dst. It returns the new buffer and the position of the message length placeholder.
+func beginMessage(dst []byte, t byte) ([]byte, int) {
+	dst = append(dst, t)
+	sp := len(dst)
+	dst = pgio.AppendInt32(dst, -1)
+	return dst, sp
+}
+
+// finishMessage finishes a message that was started with beginMessage. It computes the message length and writes it to
+// dst[sp]. If the message length is too large it returns an error. Otherwise it returns the final message buffer.
+func finishMessage(dst []byte, sp int) ([]byte, error) {
+	messageBodyLen := len(dst[sp:])
+	if messageBodyLen > maxMessageBodyLen {
+		return nil, errors.New("message body too large")
+	}
+	pgio.SetInt32(dst[sp:], int32(messageBodyLen))
+	return dst, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/portal_suspended.go b/vendor/github.com/jackc/pgx/v5/pgproto3/portal_suspended.go
new file mode 100644
index 000000000..9e2f8cbc4
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/portal_suspended.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type PortalSuspended struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*PortalSuspended) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *PortalSuspended) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "PortalSuspended", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *PortalSuspended) Encode(dst []byte) ([]byte, error) {
+	return append(dst, 's', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src PortalSuspended) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "PortalSuspended",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/query.go b/vendor/github.com/jackc/pgx/v5/pgproto3/query.go
new file mode 100644
index 000000000..9e16465c2
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/query.go
@@ -0,0 +1,49 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/json"
+)
+
+type Query struct {
+	String string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Query) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Query) Decode(src []byte) error {
+	if len(src) == 0 {
+		return &invalidMessageFormatErr{messageType: "Query"}
+	}
+
+	i := bytes.IndexByte(src, 0)
+	if i != len(src)-1 {
+		return &invalidMessageFormatErr{messageType: "Query"}
+	}
+
+	dst.String = string(src[:i])
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Query) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'Q')
+	dst = append(dst, src.String...)
+	dst = append(dst, 0)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Query) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type   string
+		String string
+	}{
+		Type:   "Query",
+		String: src.String,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/ready_for_query.go b/vendor/github.com/jackc/pgx/v5/pgproto3/ready_for_query.go
new file mode 100644
index 000000000..a56af9fb2
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/ready_for_query.go
@@ -0,0 +1,61 @@
+package pgproto3
+
+import (
+	"encoding/json"
+	"errors"
+)
+
+type ReadyForQuery struct {
+	TxStatus byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ReadyForQuery) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *ReadyForQuery) Decode(src []byte) error {
+	if len(src) != 1 {
+		return &invalidMessageLenErr{messageType: "ReadyForQuery", expectedLen: 1, actualLen: len(src)}
+	}
+
+	dst.TxStatus = src[0]
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *ReadyForQuery) Encode(dst []byte) ([]byte, error) {
+	return append(dst, 'Z', 0, 0, 0, 5, src.TxStatus), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src ReadyForQuery) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type     string
+		TxStatus string
+	}{
+		Type:     "ReadyForQuery",
+		TxStatus: string(src.TxStatus),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *ReadyForQuery) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		TxStatus string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	if len(msg.TxStatus) != 1 {
+		return errors.New("invalid length for ReadyForQuery.TxStatus")
+	}
+	dst.TxStatus = msg.TxStatus[0]
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/row_description.go b/vendor/github.com/jackc/pgx/v5/pgproto3/row_description.go
new file mode 100644
index 000000000..b46f510dc
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/row_description.go
@@ -0,0 +1,165 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"math"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+const (
+	TextFormat   = 0
+	BinaryFormat = 1
+)
+
+type FieldDescription struct {
+	Name                 []byte
+	TableOID             uint32
+	TableAttributeNumber uint16
+	DataTypeOID          uint32
+	DataTypeSize         int16
+	TypeModifier         int32
+	Format               int16
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (fd FieldDescription) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Name                 string
+		TableOID             uint32
+		TableAttributeNumber uint16
+		DataTypeOID          uint32
+		DataTypeSize         int16
+		TypeModifier         int32
+		Format               int16
+	}{
+		Name:                 string(fd.Name),
+		TableOID:             fd.TableOID,
+		TableAttributeNumber: fd.TableAttributeNumber,
+		DataTypeOID:          fd.DataTypeOID,
+		DataTypeSize:         fd.DataTypeSize,
+		TypeModifier:         fd.TypeModifier,
+		Format:               fd.Format,
+	})
+}
+
+type RowDescription struct {
+	Fields []FieldDescription
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*RowDescription) Backend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *RowDescription) Decode(src []byte) error {
+	if len(src) < 2 {
+		return &invalidMessageFormatErr{messageType: "RowDescription"}
+	}
+	fieldCount := int(binary.BigEndian.Uint16(src))
+	rp := 2
+
+	dst.Fields = dst.Fields[0:0]
+
+	for range fieldCount {
+		var fd FieldDescription
+
+		idx := bytes.IndexByte(src[rp:], 0)
+		if idx < 0 {
+			return &invalidMessageFormatErr{messageType: "RowDescription"}
+		}
+		fd.Name = src[rp : rp+idx]
+		rp += idx + 1
+
+		// Since buf.Next() doesn't return an error if we hit the end of the buffer
+		// check Len ahead of time
+		if len(src[rp:]) < 18 {
+			return &invalidMessageFormatErr{messageType: "RowDescription"}
+		}
+
+		fd.TableOID = binary.BigEndian.Uint32(src[rp:])
+		rp += 4
+		fd.TableAttributeNumber = binary.BigEndian.Uint16(src[rp:])
+		rp += 2
+		fd.DataTypeOID = binary.BigEndian.Uint32(src[rp:])
+		rp += 4
+		fd.DataTypeSize = int16(binary.BigEndian.Uint16(src[rp:]))
+		rp += 2
+		fd.TypeModifier = int32(binary.BigEndian.Uint32(src[rp:]))
+		rp += 4
+		fd.Format = int16(binary.BigEndian.Uint16(src[rp:]))
+		rp += 2
+
+		dst.Fields = append(dst.Fields, fd)
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *RowDescription) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'T')
+
+	if len(src.Fields) > math.MaxUint16 {
+		return nil, errors.New("too many fields")
+	}
+	dst = pgio.AppendUint16(dst, uint16(len(src.Fields)))
+	for _, fd := range src.Fields {
+		dst = append(dst, fd.Name...)
+		dst = append(dst, 0)
+
+		dst = pgio.AppendUint32(dst, fd.TableOID)
+		dst = pgio.AppendUint16(dst, fd.TableAttributeNumber)
+		dst = pgio.AppendUint32(dst, fd.DataTypeOID)
+		dst = pgio.AppendInt16(dst, fd.DataTypeSize)
+		dst = pgio.AppendInt32(dst, fd.TypeModifier)
+		dst = pgio.AppendInt16(dst, fd.Format)
+	}
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src RowDescription) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type   string
+		Fields []FieldDescription
+	}{
+		Type:   "RowDescription",
+		Fields: src.Fields,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *RowDescription) UnmarshalJSON(data []byte) error {
+	var msg struct {
+		Fields []struct {
+			Name                 string
+			TableOID             uint32
+			TableAttributeNumber uint16
+			DataTypeOID          uint32
+			DataTypeSize         int16
+			TypeModifier         int32
+			Format               int16
+		}
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	dst.Fields = make([]FieldDescription, len(msg.Fields))
+	for n, field := range msg.Fields {
+		dst.Fields[n] = FieldDescription{
+			Name:                 []byte(field.Name),
+			TableOID:             field.TableOID,
+			TableAttributeNumber: field.TableAttributeNumber,
+			DataTypeOID:          field.DataTypeOID,
+			DataTypeSize:         field.DataTypeSize,
+			TypeModifier:         field.TypeModifier,
+			Format:               field.Format,
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/sasl_initial_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/sasl_initial_response.go
new file mode 100644
index 000000000..123f3cd66
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/sasl_initial_response.go
@@ -0,0 +1,93 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type SASLInitialResponse struct {
+	AuthMechanism string
+	Data          []byte
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*SASLInitialResponse) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *SASLInitialResponse) Decode(src []byte) error {
+	*dst = SASLInitialResponse{}
+
+	rp := 0
+
+	idx := bytes.IndexByte(src, 0)
+	if idx < 0 {
+		return errors.New("invalid SASLInitialResponse")
+	}
+
+	dst.AuthMechanism = string(src[rp:idx])
+	rp = idx + 1
+
+	if len(src[rp:]) < 4 {
+		return errors.New("invalid SASLInitialResponse")
+	}
+	rp += 4 // The rest of the message is data so we can just skip the size
+	dst.Data = src[rp:]
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *SASLInitialResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'p')
+
+	dst = append(dst, []byte(src.AuthMechanism)...)
+	dst = append(dst, 0)
+
+	dst = pgio.AppendInt32(dst, int32(len(src.Data)))
+	dst = append(dst, src.Data...)
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src SASLInitialResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type          string
+		AuthMechanism string
+		Data          string
+	}{
+		Type:          "SASLInitialResponse",
+		AuthMechanism: src.AuthMechanism,
+		Data:          string(src.Data),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *SASLInitialResponse) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		AuthMechanism string
+		Data          string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	dst.AuthMechanism = msg.AuthMechanism
+	if msg.Data != "" {
+		decoded, err := hex.DecodeString(msg.Data)
+		if err != nil {
+			return err
+		}
+		dst.Data = decoded
+	}
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/sasl_response.go b/vendor/github.com/jackc/pgx/v5/pgproto3/sasl_response.go
new file mode 100644
index 000000000..1b604c254
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/sasl_response.go
@@ -0,0 +1,56 @@
+package pgproto3
+
+import (
+	"encoding/hex"
+	"encoding/json"
+)
+
+type SASLResponse struct {
+	Data []byte
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*SASLResponse) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *SASLResponse) Decode(src []byte) error {
+	*dst = SASLResponse{Data: src}
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *SASLResponse) Encode(dst []byte) ([]byte, error) {
+	dst, sp := beginMessage(dst, 'p')
+	dst = append(dst, src.Data...)
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src SASLResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data string
+	}{
+		Type: "SASLResponse",
+		Data: string(src.Data),
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *SASLResponse) UnmarshalJSON(data []byte) error {
+	var msg struct {
+		Data string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	if msg.Data != "" {
+		decoded, err := hex.DecodeString(msg.Data)
+		if err != nil {
+			return err
+		}
+		dst.Data = decoded
+	}
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/ssl_request.go b/vendor/github.com/jackc/pgx/v5/pgproto3/ssl_request.go
new file mode 100644
index 000000000..bdfc7c427
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/ssl_request.go
@@ -0,0 +1,48 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+const sslRequestNumber = 80877103
+
+type SSLRequest struct{}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*SSLRequest) Frontend() {}
+
+func (dst *SSLRequest) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("ssl request too short")
+	}
+
+	requestCode := binary.BigEndian.Uint32(src)
+
+	if requestCode != sslRequestNumber {
+		return errors.New("bad ssl request code")
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 4 byte message length.
+func (src *SSLRequest) Encode(dst []byte) ([]byte, error) {
+	dst = pgio.AppendInt32(dst, 8)
+	dst = pgio.AppendInt32(dst, sslRequestNumber)
+	return dst, nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src SSLRequest) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type            string
+		ProtocolVersion uint32
+		Parameters      map[string]string
+	}{
+		Type: "SSLRequest",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/startup_message.go b/vendor/github.com/jackc/pgx/v5/pgproto3/startup_message.go
new file mode 100644
index 000000000..eb48f72bf
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/startup_message.go
@@ -0,0 +1,99 @@
+package pgproto3
+
+import (
+	"bytes"
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"fmt"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+const (
+	ProtocolVersion30     = 196608            // 3.0
+	ProtocolVersion32     = 196610            // 3.2
+	ProtocolVersionLatest = ProtocolVersion32 // Latest is 3.2
+	ProtocolVersionNumber = ProtocolVersion30 // Default is still 3.0
+)
+
+type StartupMessage struct {
+	ProtocolVersion uint32
+	Parameters      map[string]string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*StartupMessage) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *StartupMessage) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("startup message too short")
+	}
+
+	dst.ProtocolVersion = binary.BigEndian.Uint32(src)
+	rp := 4
+
+	if dst.ProtocolVersion != ProtocolVersion30 && dst.ProtocolVersion != ProtocolVersion32 {
+		return fmt.Errorf("Bad startup message version number. Expected %d or %d, got %d", ProtocolVersion30, ProtocolVersion32, dst.ProtocolVersion)
+	}
+
+	dst.Parameters = make(map[string]string)
+	for {
+		idx := bytes.IndexByte(src[rp:], 0)
+		if idx < 0 {
+			return &invalidMessageFormatErr{messageType: "StartupMessage"}
+		}
+		key := string(src[rp : rp+idx])
+		rp += idx + 1
+
+		idx = bytes.IndexByte(src[rp:], 0)
+		if idx < 0 {
+			return &invalidMessageFormatErr{messageType: "StartupMessage"}
+		}
+		value := string(src[rp : rp+idx])
+		rp += idx + 1
+
+		dst.Parameters[key] = value
+
+		if len(src[rp:]) == 1 {
+			if src[rp] != 0 {
+				return fmt.Errorf("Bad startup message last byte. Expected 0, got %d", src[rp])
+			}
+			break
+		}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *StartupMessage) Encode(dst []byte) ([]byte, error) {
+	sp := len(dst)
+	dst = pgio.AppendInt32(dst, -1)
+
+	dst = pgio.AppendUint32(dst, src.ProtocolVersion)
+	for k, v := range src.Parameters {
+		dst = append(dst, k...)
+		dst = append(dst, 0)
+		dst = append(dst, v...)
+		dst = append(dst, 0)
+	}
+	dst = append(dst, 0)
+
+	return finishMessage(dst, sp)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src StartupMessage) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type            string
+		ProtocolVersion uint32
+		Parameters      map[string]string
+	}{
+		Type:            "StartupMessage",
+		ProtocolVersion: src.ProtocolVersion,
+		Parameters:      src.Parameters,
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/sync.go b/vendor/github.com/jackc/pgx/v5/pgproto3/sync.go
new file mode 100644
index 000000000..ea4fc9594
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/sync.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type Sync struct{}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Sync) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Sync) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "Sync", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Sync) Encode(dst []byte) ([]byte, error) {
+	return append(dst, 'S', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Sync) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "Sync",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/terminate.go b/vendor/github.com/jackc/pgx/v5/pgproto3/terminate.go
new file mode 100644
index 000000000..35a9dc837
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/terminate.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+	"encoding/json"
+)
+
+type Terminate struct{}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Terminate) Frontend() {}
+
+// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
+// type identifier and 4 byte message length.
+func (dst *Terminate) Decode(src []byte) error {
+	if len(src) != 0 {
+		return &invalidMessageLenErr{messageType: "Terminate", expectedLen: 0, actualLen: len(src)}
+	}
+
+	return nil
+}
+
+// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
+func (src *Terminate) Encode(dst []byte) ([]byte, error) {
+	return append(dst, 'X', 0, 0, 0, 4), nil
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Terminate) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+	}{
+		Type: "Terminate",
+	})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/trace.go b/vendor/github.com/jackc/pgx/v5/pgproto3/trace.go
new file mode 100644
index 000000000..2f9da6289
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgproto3/trace.go
@@ -0,0 +1,416 @@
+package pgproto3
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+// tracer traces the messages send to and from a Backend or Frontend. The format it produces roughly mimics the
+// format produced by the libpq C function PQtrace.
+type tracer struct {
+	TracerOptions
+
+	mux sync.Mutex
+	w   io.Writer
+	buf *bytes.Buffer
+}
+
+// TracerOptions controls tracing behavior. It is roughly equivalent to the libpq function PQsetTraceFlags.
+type TracerOptions struct {
+	// SuppressTimestamps prevents printing of timestamps.
+	SuppressTimestamps bool
+
+	// RegressMode redacts fields that may be vary between executions.
+	RegressMode bool
+}
+
+func (t *tracer) traceMessage(sender byte, encodedLen int32, msg Message) {
+	switch msg := msg.(type) {
+	case *AuthenticationCleartextPassword:
+		t.traceAuthenticationCleartextPassword(sender, encodedLen, msg)
+	case *AuthenticationGSS:
+		t.traceAuthenticationGSS(sender, encodedLen, msg)
+	case *AuthenticationGSSContinue:
+		t.traceAuthenticationGSSContinue(sender, encodedLen, msg)
+	case *AuthenticationMD5Password:
+		t.traceAuthenticationMD5Password(sender, encodedLen, msg)
+	case *AuthenticationOk:
+		t.traceAuthenticationOk(sender, encodedLen, msg)
+	case *AuthenticationSASL:
+		t.traceAuthenticationSASL(sender, encodedLen, msg)
+	case *AuthenticationSASLContinue:
+		t.traceAuthenticationSASLContinue(sender, encodedLen, msg)
+	case *AuthenticationSASLFinal:
+		t.traceAuthenticationSASLFinal(sender, encodedLen, msg)
+	case *BackendKeyData:
+		t.traceBackendKeyData(sender, encodedLen, msg)
+	case *Bind:
+		t.traceBind(sender, encodedLen, msg)
+	case *BindComplete:
+		t.traceBindComplete(sender, encodedLen, msg)
+	case *CancelRequest:
+		t.traceCancelRequest(sender, encodedLen, msg)
+	case *Close:
+		t.traceClose(sender, encodedLen, msg)
+	case *CloseComplete:
+		t.traceCloseComplete(sender, encodedLen, msg)
+	case *CommandComplete:
+		t.traceCommandComplete(sender, encodedLen, msg)
+	case *CopyBothResponse:
+		t.traceCopyBothResponse(sender, encodedLen, msg)
+	case *CopyData:
+		t.traceCopyData(sender, encodedLen, msg)
+	case *CopyDone:
+		t.traceCopyDone(sender, encodedLen, msg)
+	case *CopyFail:
+		t.traceCopyFail(sender, encodedLen, msg)
+	case *CopyInResponse:
+		t.traceCopyInResponse(sender, encodedLen, msg)
+	case *CopyOutResponse:
+		t.traceCopyOutResponse(sender, encodedLen, msg)
+	case *DataRow:
+		t.traceDataRow(sender, encodedLen, msg)
+	case *Describe:
+		t.traceDescribe(sender, encodedLen, msg)
+	case *EmptyQueryResponse:
+		t.traceEmptyQueryResponse(sender, encodedLen, msg)
+	case *ErrorResponse:
+		t.traceErrorResponse(sender, encodedLen, msg)
+	case *Execute:
+		t.traceExecute(sender, encodedLen, msg)
+	case *Flush:
+		t.traceFlush(sender, encodedLen, msg)
+	case *FunctionCall:
+		t.traceFunctionCall(sender, encodedLen, msg)
+	case *FunctionCallResponse:
+		t.traceFunctionCallResponse(sender, encodedLen, msg)
+	case *GSSEncRequest:
+		t.traceGSSEncRequest(sender, encodedLen, msg)
+	case *NoData:
+		t.traceNoData(sender, encodedLen, msg)
+	case *NoticeResponse:
+		t.traceNoticeResponse(sender, encodedLen, msg)
+	case *NotificationResponse:
+		t.traceNotificationResponse(sender, encodedLen, msg)
+	case *ParameterDescription:
+		t.traceParameterDescription(sender, encodedLen, msg)
+	case *ParameterStatus:
+		t.traceParameterStatus(sender, encodedLen, msg)
+	case *Parse:
+		t.traceParse(sender, encodedLen, msg)
+	case *ParseComplete:
+		t.traceParseComplete(sender, encodedLen, msg)
+	case *PortalSuspended:
+		t.tracePortalSuspended(sender, encodedLen, msg)
+	case *Query:
+		t.traceQuery(sender, encodedLen, msg)
+	case *ReadyForQuery:
+		t.traceReadyForQuery(sender, encodedLen, msg)
+	case *RowDescription:
+		t.traceRowDescription(sender, encodedLen, msg)
+	case *SSLRequest:
+		t.traceSSLRequest(sender, encodedLen, msg)
+	case *StartupMessage:
+		t.traceStartupMessage(sender, encodedLen, msg)
+	case *Sync:
+		t.traceSync(sender, encodedLen, msg)
+	case *Terminate:
+		t.traceTerminate(sender, encodedLen, msg)
+	default:
+		t.writeTrace(sender, encodedLen, "Unknown", nil)
+	}
+}
+
+func (t *tracer) traceAuthenticationCleartextPassword(sender byte, encodedLen int32, msg *AuthenticationCleartextPassword) {
+	t.writeTrace(sender, encodedLen, "AuthenticationCleartextPassword", nil)
+}
+
+func (t *tracer) traceAuthenticationGSS(sender byte, encodedLen int32, msg *AuthenticationGSS) {
+	t.writeTrace(sender, encodedLen, "AuthenticationGSS", nil)
+}
+
+func (t *tracer) traceAuthenticationGSSContinue(sender byte, encodedLen int32, msg *AuthenticationGSSContinue) {
+	t.writeTrace(sender, encodedLen, "AuthenticationGSSContinue", nil)
+}
+
+func (t *tracer) traceAuthenticationMD5Password(sender byte, encodedLen int32, msg *AuthenticationMD5Password) {
+	t.writeTrace(sender, encodedLen, "AuthenticationMD5Password", nil)
+}
+
+func (t *tracer) traceAuthenticationOk(sender byte, encodedLen int32, msg *AuthenticationOk) {
+	t.writeTrace(sender, encodedLen, "AuthenticationOk", nil)
+}
+
+func (t *tracer) traceAuthenticationSASL(sender byte, encodedLen int32, msg *AuthenticationSASL) {
+	t.writeTrace(sender, encodedLen, "AuthenticationSASL", nil)
+}
+
+func (t *tracer) traceAuthenticationSASLContinue(sender byte, encodedLen int32, msg *AuthenticationSASLContinue) {
+	t.writeTrace(sender, encodedLen, "AuthenticationSASLContinue", nil)
+}
+
+func (t *tracer) traceAuthenticationSASLFinal(sender byte, encodedLen int32, msg *AuthenticationSASLFinal) {
+	t.writeTrace(sender, encodedLen, "AuthenticationSASLFinal", nil)
+}
+
+func (t *tracer) traceBackendKeyData(sender byte, encodedLen int32, msg *BackendKeyData) {
+	t.writeTrace(sender, encodedLen, "BackendKeyData", func() {
+		if t.RegressMode {
+			t.buf.WriteString("\t NNNN NNNN")
+		} else {
+			fmt.Fprintf(t.buf, "\t %d %d", msg.ProcessID, msg.SecretKey)
+		}
+	})
+}
+
+func (t *tracer) traceBind(sender byte, encodedLen int32, msg *Bind) {
+	t.writeTrace(sender, encodedLen, "Bind", func() {
+		fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.DestinationPortal)), traceDoubleQuotedString([]byte(msg.PreparedStatement)), len(msg.ParameterFormatCodes))
+		for _, fc := range msg.ParameterFormatCodes {
+			fmt.Fprintf(t.buf, " %d", fc)
+		}
+		fmt.Fprintf(t.buf, " %d", len(msg.Parameters))
+		for _, p := range msg.Parameters {
+			fmt.Fprintf(t.buf, " %s", traceSingleQuotedString(p))
+		}
+		fmt.Fprintf(t.buf, " %d", len(msg.ResultFormatCodes))
+		for _, fc := range msg.ResultFormatCodes {
+			fmt.Fprintf(t.buf, " %d", fc)
+		}
+	})
+}
+
+func (t *tracer) traceBindComplete(sender byte, encodedLen int32, msg *BindComplete) {
+	t.writeTrace(sender, encodedLen, "BindComplete", nil)
+}
+
+func (t *tracer) traceCancelRequest(sender byte, encodedLen int32, msg *CancelRequest) {
+	t.writeTrace(sender, encodedLen, "CancelRequest", nil)
+}
+
+func (t *tracer) traceClose(sender byte, encodedLen int32, msg *Close) {
+	t.writeTrace(sender, encodedLen, "Close", nil)
+}
+
+func (t *tracer) traceCloseComplete(sender byte, encodedLen int32, msg *CloseComplete) {
+	t.writeTrace(sender, encodedLen, "CloseComplete", nil)
+}
+
+func (t *tracer) traceCommandComplete(sender byte, encodedLen int32, msg *CommandComplete) {
+	t.writeTrace(sender, encodedLen, "CommandComplete", func() {
+		fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString(msg.CommandTag))
+	})
+}
+
+func (t *tracer) traceCopyBothResponse(sender byte, encodedLen int32, msg *CopyBothResponse) {
+	t.writeTrace(sender, encodedLen, "CopyBothResponse", nil)
+}
+
+func (t *tracer) traceCopyData(sender byte, encodedLen int32, msg *CopyData) {
+	t.writeTrace(sender, encodedLen, "CopyData", nil)
+}
+
+func (t *tracer) traceCopyDone(sender byte, encodedLen int32, msg *CopyDone) {
+	t.writeTrace(sender, encodedLen, "CopyDone", nil)
+}
+
+func (t *tracer) traceCopyFail(sender byte, encodedLen int32, msg *CopyFail) {
+	t.writeTrace(sender, encodedLen, "CopyFail", func() {
+		fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.Message)))
+	})
+}
+
+func (t *tracer) traceCopyInResponse(sender byte, encodedLen int32, msg *CopyInResponse) {
+	t.writeTrace(sender, encodedLen, "CopyInResponse", nil)
+}
+
+func (t *tracer) traceCopyOutResponse(sender byte, encodedLen int32, msg *CopyOutResponse) {
+	t.writeTrace(sender, encodedLen, "CopyOutResponse", nil)
+}
+
+func (t *tracer) traceDataRow(sender byte, encodedLen int32, msg *DataRow) {
+	t.writeTrace(sender, encodedLen, "DataRow", func() {
+		fmt.Fprintf(t.buf, "\t %d", len(msg.Values))
+		for _, v := range msg.Values {
+			if v == nil {
+				t.buf.WriteString(" -1")
+			} else {
+				fmt.Fprintf(t.buf, " %d %s", len(v), traceSingleQuotedString(v))
+			}
+		}
+	})
+}
+
+func (t *tracer) traceDescribe(sender byte, encodedLen int32, msg *Describe) {
+	t.writeTrace(sender, encodedLen, "Describe", func() {
+		fmt.Fprintf(t.buf, "\t %c %s", msg.ObjectType, traceDoubleQuotedString([]byte(msg.Name)))
+	})
+}
+
+func (t *tracer) traceEmptyQueryResponse(sender byte, encodedLen int32, msg *EmptyQueryResponse) {
+	t.writeTrace(sender, encodedLen, "EmptyQueryResponse", nil)
+}
+
+func (t *tracer) traceErrorResponse(sender byte, encodedLen int32, msg *ErrorResponse) {
+	t.writeTrace(sender, encodedLen, "ErrorResponse", nil)
+}
+
+func (t *tracer) traceExecute(sender byte, encodedLen int32, msg *Execute) {
+	t.writeTrace(sender, encodedLen, "Execute", func() {
+		fmt.Fprintf(t.buf, "\t %s %d", traceDoubleQuotedString([]byte(msg.Portal)), msg.MaxRows)
+	})
+}
+
+func (t *tracer) traceFlush(sender byte, encodedLen int32, msg *Flush) {
+	t.writeTrace(sender, encodedLen, "Flush", nil)
+}
+
+func (t *tracer) traceFunctionCall(sender byte, encodedLen int32, msg *FunctionCall) {
+	t.writeTrace(sender, encodedLen, "FunctionCall", nil)
+}
+
+func (t *tracer) traceFunctionCallResponse(sender byte, encodedLen int32, msg *FunctionCallResponse) {
+	t.writeTrace(sender, encodedLen, "FunctionCallResponse", nil)
+}
+
+func (t *tracer) traceGSSEncRequest(sender byte, encodedLen int32, msg *GSSEncRequest) {
+	t.writeTrace(sender, encodedLen, "GSSEncRequest", nil)
+}
+
+func (t *tracer) traceNoData(sender byte, encodedLen int32, msg *NoData) {
+	t.writeTrace(sender, encodedLen, "NoData", nil)
+}
+
+func (t *tracer) traceNoticeResponse(sender byte, encodedLen int32, msg *NoticeResponse) {
+	t.writeTrace(sender, encodedLen, "NoticeResponse", nil)
+}
+
+func (t *tracer) traceNotificationResponse(sender byte, encodedLen int32, msg *NotificationResponse) {
+	t.writeTrace(sender, encodedLen, "NotificationResponse", func() {
+		fmt.Fprintf(t.buf, "\t %d %s %s", msg.PID, traceDoubleQuotedString([]byte(msg.Channel)), traceDoubleQuotedString([]byte(msg.Payload)))
+	})
+}
+
+func (t *tracer) traceParameterDescription(sender byte, encodedLen int32, msg *ParameterDescription) {
+	t.writeTrace(sender, encodedLen, "ParameterDescription", nil)
+}
+
+func (t *tracer) traceParameterStatus(sender byte, encodedLen int32, msg *ParameterStatus) {
+	t.writeTrace(sender, encodedLen, "ParameterStatus", func() {
+		fmt.Fprintf(t.buf, "\t %s %s", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Value)))
+	})
+}
+
+func (t *tracer) traceParse(sender byte, encodedLen int32, msg *Parse) {
+	t.writeTrace(sender, encodedLen, "Parse", func() {
+		fmt.Fprintf(t.buf, "\t %s %s %d", traceDoubleQuotedString([]byte(msg.Name)), traceDoubleQuotedString([]byte(msg.Query)), len(msg.ParameterOIDs))
+		for _, oid := range msg.ParameterOIDs {
+			fmt.Fprintf(t.buf, " %d", oid)
+		}
+	})
+}
+
+func (t *tracer) traceParseComplete(sender byte, encodedLen int32, msg *ParseComplete) {
+	t.writeTrace(sender, encodedLen, "ParseComplete", nil)
+}
+
+func (t *tracer) tracePortalSuspended(sender byte, encodedLen int32, msg *PortalSuspended) {
+	t.writeTrace(sender, encodedLen, "PortalSuspended", nil)
+}
+
+func (t *tracer) traceQuery(sender byte, encodedLen int32, msg *Query) {
+	t.writeTrace(sender, encodedLen, "Query", func() {
+		fmt.Fprintf(t.buf, "\t %s", traceDoubleQuotedString([]byte(msg.String)))
+	})
+}
+
+func (t *tracer) traceReadyForQuery(sender byte, encodedLen int32, msg *ReadyForQuery) {
+	t.writeTrace(sender, encodedLen, "ReadyForQuery", func() {
+		fmt.Fprintf(t.buf, "\t %c", msg.TxStatus)
+	})
+}
+
+func (t *tracer) traceRowDescription(sender byte, encodedLen int32, msg *RowDescription) {
+	t.writeTrace(sender, encodedLen, "RowDescription", func() {
+		fmt.Fprintf(t.buf, "\t %d", len(msg.Fields))
+		for _, fd := range msg.Fields {
+			fmt.Fprintf(t.buf, ` %s %d %d %d %d %d %d`, traceDoubleQuotedString(fd.Name), fd.TableOID, fd.TableAttributeNumber, fd.DataTypeOID, fd.DataTypeSize, fd.TypeModifier, fd.Format)
+		}
+	})
+}
+
+func (t *tracer) traceSSLRequest(sender byte, encodedLen int32, msg *SSLRequest) {
+	t.writeTrace(sender, encodedLen, "SSLRequest", nil)
+}
+
+func (t *tracer) traceStartupMessage(sender byte, encodedLen int32, msg *StartupMessage) {
+	t.writeTrace(sender, encodedLen, "StartupMessage", nil)
+}
+
+func (t *tracer) traceSync(sender byte, encodedLen int32, msg *Sync) {
+	t.writeTrace(sender, encodedLen, "Sync", nil)
+}
+
+func (t *tracer) traceTerminate(sender byte, encodedLen int32, msg *Terminate) {
+	t.writeTrace(sender, encodedLen, "Terminate", nil)
+}
+
+func (t *tracer) writeTrace(sender byte, encodedLen int32, msgType string, writeDetails func()) {
+	t.mux.Lock()
+	defer t.mux.Unlock()
+	defer func() {
+		if t.buf.Cap() > 1024 {
+			t.buf = &bytes.Buffer{}
+		} else {
+			t.buf.Reset()
+		}
+	}()
+
+	if !t.SuppressTimestamps {
+		now := time.Now()
+		t.buf.WriteString(now.Format("2006-01-02 15:04:05.000000"))
+		t.buf.WriteByte('\t')
+	}
+
+	t.buf.WriteByte(sender)
+	t.buf.WriteByte('\t')
+	t.buf.WriteString(msgType)
+	t.buf.WriteByte('\t')
+	t.buf.WriteString(strconv.FormatInt(int64(encodedLen), 10))
+
+	if writeDetails != nil {
+		writeDetails()
+	}
+
+	t.buf.WriteByte('\n')
+	t.buf.WriteTo(t.w)
+}
+
+// traceDoubleQuotedString returns t.buf as a double-quoted string without any escaping. It is roughly equivalent to
+// pqTraceOutputString in libpq.
+func traceDoubleQuotedString(buf []byte) string {
+	return `"` + string(buf) + `"`
+}
+
+// traceSingleQuotedString returns buf as a single-quoted string with non-printable characters hex-escaped. It is
+// roughly equivalent to pqTraceOutputNchar in libpq.
+func traceSingleQuotedString(buf []byte) string {
+	sb := &strings.Builder{}
+
+	sb.WriteByte('\'')
+	for _, b := range buf {
+		if b < 32 || b > 126 {
+			fmt.Fprintf(sb, `\x%x`, b)
+		} else {
+			sb.WriteByte(b)
+		}
+	}
+	sb.WriteByte('\'')
+
+	return sb.String()
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/array.go b/vendor/github.com/jackc/pgx/v5/pgtype/array.go
new file mode 100644
index 000000000..26505fb84
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/array.go
@@ -0,0 +1,469 @@
+package pgtype
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+	"unicode"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// Information on the internals of PostgreSQL arrays can be found in
+// src/include/utils/array.h and src/backend/utils/adt/arrayfuncs.c. Of
+// particular interest is the array_send function.
+
+type arrayHeader struct {
+	ContainsNull bool
+	ElementOID   uint32
+	Dimensions   []ArrayDimension
+}
+
+type ArrayDimension struct {
+	Length     int32
+	LowerBound int32
+}
+
+// cardinality returns the number of elements in an array of dimensions size.
+func cardinality(dimensions []ArrayDimension) int {
+	if len(dimensions) == 0 {
+		return 0
+	}
+
+	elementCount := int(dimensions[0].Length)
+	for _, d := range dimensions[1:] {
+		elementCount *= int(d.Length)
+	}
+
+	if elementCount < 0 {
+		return 0
+	}
+
+	return elementCount
+}
+
+func (dst *arrayHeader) DecodeBinary(m *Map, src []byte) (int, error) {
+	if len(src) < 12 {
+		return 0, fmt.Errorf("array header too short: %d", len(src))
+	}
+
+	rp := 0
+
+	numDims := int(binary.BigEndian.Uint32(src[rp:]))
+	rp += 4
+
+	if numDims > 6 {
+		return 0, fmt.Errorf("array has too many dimensions: %d", numDims)
+	}
+
+	dst.ContainsNull = binary.BigEndian.Uint32(src[rp:]) == 1
+	rp += 4
+
+	dst.ElementOID = binary.BigEndian.Uint32(src[rp:])
+	rp += 4
+
+	if len(src) < 12+numDims*8 {
+		return 0, fmt.Errorf("array header too short for %d dimensions: %d", numDims, len(src))
+	}
+	dst.Dimensions = make([]ArrayDimension, numDims)
+	for i := range dst.Dimensions {
+		dst.Dimensions[i].Length = int32(binary.BigEndian.Uint32(src[rp:]))
+		rp += 4
+
+		dst.Dimensions[i].LowerBound = int32(binary.BigEndian.Uint32(src[rp:]))
+		rp += 4
+	}
+
+	return rp, nil
+}
+
+func (src arrayHeader) EncodeBinary(buf []byte) []byte {
+	buf = pgio.AppendInt32(buf, int32(len(src.Dimensions)))
+
+	var containsNull int32
+	if src.ContainsNull {
+		containsNull = 1
+	}
+	buf = pgio.AppendInt32(buf, containsNull)
+
+	buf = pgio.AppendUint32(buf, src.ElementOID)
+
+	for i := range src.Dimensions {
+		buf = pgio.AppendInt32(buf, src.Dimensions[i].Length)
+		buf = pgio.AppendInt32(buf, src.Dimensions[i].LowerBound)
+	}
+
+	return buf
+}
+
+type untypedTextArray struct {
+	Elements   []string
+	Quoted     []bool
+	Dimensions []ArrayDimension
+}
+
+func parseUntypedTextArray(src string) (*untypedTextArray, error) {
+	dst := &untypedTextArray{
+		Elements:   []string{},
+		Quoted:     []bool{},
+		Dimensions: []ArrayDimension{},
+	}
+
+	buf := bytes.NewBufferString(src)
+
+	skipWhitespace(buf)
+
+	r, _, err := buf.ReadRune()
+	if err != nil {
+		return nil, fmt.Errorf("invalid array: %w", err)
+	}
+
+	var explicitDimensions []ArrayDimension
+
+	// Array has explicit dimensions
+	if r == '[' {
+		buf.UnreadRune()
+
+		for {
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %w", err)
+			}
+
+			if r == '=' {
+				break
+			} else if r != '[' {
+				return nil, fmt.Errorf("invalid array, expected '[' or '=' got %v", r)
+			}
+
+			lower, err := arrayParseInteger(buf)
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %w", err)
+			}
+
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %w", err)
+			}
+
+			if r != ':' {
+				return nil, fmt.Errorf("invalid array, expected ':' got %v", r)
+			}
+
+			upper, err := arrayParseInteger(buf)
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %w", err)
+			}
+
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return nil, fmt.Errorf("invalid array: %w", err)
+			}
+
+			if r != ']' {
+				return nil, fmt.Errorf("invalid array, expected ']' got %v", r)
+			}
+
+			explicitDimensions = append(explicitDimensions, ArrayDimension{LowerBound: lower, Length: upper - lower + 1})
+		}
+
+		r, _, err = buf.ReadRune()
+		if err != nil {
+			return nil, fmt.Errorf("invalid array: %w", err)
+		}
+	}
+
+	if r != '{' {
+		return nil, fmt.Errorf("invalid array, expected '{' got %v", r)
+	}
+
+	implicitDimensions := []ArrayDimension{{LowerBound: 1, Length: 0}}
+
+	// Consume all initial opening brackets. This provides number of dimensions.
+	for {
+		r, _, err = buf.ReadRune()
+		if err != nil {
+			return nil, fmt.Errorf("invalid array: %w", err)
+		}
+
+		if r == '{' {
+			implicitDimensions[len(implicitDimensions)-1].Length = 1
+			implicitDimensions = append(implicitDimensions, ArrayDimension{LowerBound: 1})
+		} else {
+			buf.UnreadRune()
+			break
+		}
+	}
+	currentDim := len(implicitDimensions) - 1
+	counterDim := currentDim
+
+	for {
+		r, _, err = buf.ReadRune()
+		if err != nil {
+			return nil, fmt.Errorf("invalid array: %w", err)
+		}
+
+		switch r {
+		case '{':
+			if currentDim == counterDim {
+				implicitDimensions[currentDim].Length++
+			}
+			currentDim++
+		case ',':
+		case '}':
+			currentDim--
+			if currentDim < counterDim {
+				counterDim = currentDim
+			}
+		default:
+			buf.UnreadRune()
+			value, quoted, err := arrayParseValue(buf)
+			if err != nil {
+				return nil, fmt.Errorf("invalid array value: %w", err)
+			}
+			if currentDim == counterDim {
+				implicitDimensions[currentDim].Length++
+			}
+			dst.Quoted = append(dst.Quoted, quoted)
+			dst.Elements = append(dst.Elements, value)
+		}
+
+		if currentDim < 0 {
+			break
+		}
+	}
+
+	skipWhitespace(buf)
+
+	if buf.Len() > 0 {
+		return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
+	}
+
+	switch {
+	case len(dst.Elements) == 0:
+	case len(explicitDimensions) > 0:
+		dst.Dimensions = explicitDimensions
+	default:
+		dst.Dimensions = implicitDimensions
+	}
+
+	return dst, nil
+}
+
+func skipWhitespace(buf *bytes.Buffer) {
+	var r rune
+	var err error
+	for r, _, _ = buf.ReadRune(); unicode.IsSpace(r); r, _, _ = buf.ReadRune() {
+	}
+
+	if err != io.EOF {
+		buf.UnreadRune()
+	}
+}
+
+func arrayParseValue(buf *bytes.Buffer) (string, bool, error) {
+	r, _, err := buf.ReadRune()
+	if err != nil {
+		return "", false, err
+	}
+	if r == '"' {
+		return arrayParseQuotedValue(buf)
+	}
+	buf.UnreadRune()
+
+	s := &bytes.Buffer{}
+
+	for {
+		r, _, err := buf.ReadRune()
+		if err != nil {
+			return "", false, err
+		}
+
+		switch r {
+		case ',', '}':
+			buf.UnreadRune()
+			return s.String(), false, nil
+		}
+
+		s.WriteRune(r)
+	}
+}
+
+func arrayParseQuotedValue(buf *bytes.Buffer) (string, bool, error) {
+	s := &bytes.Buffer{}
+
+	for {
+		r, _, err := buf.ReadRune()
+		if err != nil {
+			return "", false, err
+		}
+
+		switch r {
+		case '\\':
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return "", false, err
+			}
+		case '"':
+			_, _, err = buf.ReadRune()
+			if err != nil {
+				return "", false, err
+			}
+			buf.UnreadRune()
+			return s.String(), true, nil
+		}
+		s.WriteRune(r)
+	}
+}
+
+func arrayParseInteger(buf *bytes.Buffer) (int32, error) {
+	s := &bytes.Buffer{}
+
+	for {
+		r, _, err := buf.ReadRune()
+		if err != nil {
+			return 0, err
+		}
+
+		if ('0' <= r && r <= '9') || r == '-' {
+			s.WriteRune(r)
+		} else {
+			buf.UnreadRune()
+			n, err := strconv.ParseInt(s.String(), 10, 32)
+			if err != nil {
+				return 0, err
+			}
+			return int32(n), nil
+		}
+	}
+}
+
+func encodeTextArrayDimensions(buf []byte, dimensions []ArrayDimension) []byte {
+	var customDimensions bool
+	for _, dim := range dimensions {
+		if dim.LowerBound != 1 {
+			customDimensions = true
+		}
+	}
+
+	if !customDimensions {
+		return buf
+	}
+
+	for _, dim := range dimensions {
+		buf = append(buf, '[')
+		buf = append(buf, strconv.FormatInt(int64(dim.LowerBound), 10)...)
+		buf = append(buf, ':')
+		buf = append(buf, strconv.FormatInt(int64(dim.LowerBound+dim.Length-1), 10)...)
+		buf = append(buf, ']')
+	}
+
+	return append(buf, '=')
+}
+
+var quoteArrayReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
+
+func quoteArrayElement(src string) string {
+	return `"` + quoteArrayReplacer.Replace(src) + `"`
+}
+
+func isSpace(ch byte) bool {
+	// see array_isspace:
+	// https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/arrayfuncs.c
+	return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f'
+}
+
+func quoteArrayElementIfNeeded(src string) string {
+	if src == "" || (len(src) == 4 && strings.EqualFold(src, "null")) || isSpace(src[0]) || isSpace(src[len(src)-1]) || strings.ContainsAny(src, `{},"\`) {
+		return quoteArrayElement(src)
+	}
+	return src
+}
+
+// Array represents a PostgreSQL array for T. It implements the [ArrayGetter] and [ArraySetter] interfaces. It preserves
+// PostgreSQL dimensions and custom lower bounds. Use [FlatArray] if these are not needed.
+type Array[T any] struct {
+	Elements []T
+	Dims     []ArrayDimension
+	Valid    bool
+}
+
+func (a Array[T]) Dimensions() []ArrayDimension {
+	return a.Dims
+}
+
+func (a Array[T]) Index(i int) any {
+	return a.Elements[i]
+}
+
+func (a Array[T]) IndexType() any {
+	var el T
+	return el
+}
+
+func (a *Array[T]) SetDimensions(dimensions []ArrayDimension) error {
+	if dimensions == nil {
+		*a = Array[T]{}
+		return nil
+	}
+
+	elementCount := cardinality(dimensions)
+	*a = Array[T]{
+		Elements: make([]T, elementCount),
+		Dims:     dimensions,
+		Valid:    true,
+	}
+
+	return nil
+}
+
+func (a Array[T]) ScanIndex(i int) any {
+	return &a.Elements[i]
+}
+
+func (a Array[T]) ScanIndexType() any {
+	return new(T)
+}
+
+// FlatArray implements the [ArrayGetter] and [ArraySetter] interfaces for any slice of T. It ignores PostgreSQL dimensions
+// and custom lower bounds. Use [Array] to preserve these.
+type FlatArray[T any] []T
+
+func (a FlatArray[T]) Dimensions() []ArrayDimension {
+	if a == nil {
+		return nil
+	}
+
+	return []ArrayDimension{{Length: int32(len(a)), LowerBound: 1}}
+}
+
+func (a FlatArray[T]) Index(i int) any {
+	return a[i]
+}
+
+func (a FlatArray[T]) IndexType() any {
+	var el T
+	return el
+}
+
+func (a *FlatArray[T]) SetDimensions(dimensions []ArrayDimension) error {
+	if dimensions == nil {
+		*a = nil
+		return nil
+	}
+
+	elementCount := cardinality(dimensions)
+	*a = make(FlatArray[T], elementCount)
+	return nil
+}
+
+func (a FlatArray[T]) ScanIndex(i int) any {
+	return &a[i]
+}
+
+func (a FlatArray[T]) ScanIndexType() any {
+	return new(T)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/array_codec.go b/vendor/github.com/jackc/pgx/v5/pgtype/array_codec.go
new file mode 100644
index 000000000..ac01496ad
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/array_codec.go
@@ -0,0 +1,428 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"reflect"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// ArrayGetter is a type that can be converted into a PostgreSQL array.
+type ArrayGetter interface {
+	// Dimensions returns the array dimensions. If array is nil then nil is returned.
+	Dimensions() []ArrayDimension
+
+	// Index returns the element at i.
+	Index(i int) any
+
+	// IndexType returns a non-nil scan target of the type Index will return. This is used by ArrayCodec.PlanEncode.
+	IndexType() any
+}
+
+// ArraySetter is a type can be set from a PostgreSQL array.
+type ArraySetter interface {
+	// SetDimensions prepares the value such that ScanIndex can be called for each element. This will remove any existing
+	// elements. dimensions may be nil to indicate a NULL array. If unable to exactly preserve dimensions SetDimensions
+	// may return an error or silently flatten the array dimensions.
+	SetDimensions(dimensions []ArrayDimension) error
+
+	// ScanIndex returns a value usable as a scan target for i. SetDimensions must be called before ScanIndex.
+	ScanIndex(i int) any
+
+	// ScanIndexType returns a non-nil scan target of the type ScanIndex will return. This is used by
+	// ArrayCodec.PlanScan.
+	ScanIndexType() any
+}
+
+// ArrayCodec is a codec for any array type.
+type ArrayCodec struct {
+	ElementType *Type
+}
+
+func (c *ArrayCodec) FormatSupported(format int16) bool {
+	return c.ElementType.Codec.FormatSupported(format)
+}
+
+func (c *ArrayCodec) PreferredFormat() int16 {
+	// The binary format should always be preferred for arrays if it is supported. Usually, this will happen automatically
+	// because most types that support binary prefer it. However, text, json, and jsonb support binary but prefer the text
+	// format. This is because it is simpler for jsonb and PostgreSQL can be significantly faster using the text format
+	// for text-like data types than binary. However, arrays appear to always be faster in binary.
+	//
+	// https://www.postgresql.org/message-id/CAMovtNoHFod2jMAKQjjxv209PCTJx5Kc66anwWvX0mEiaXwgmA%40mail.gmail.com
+	if c.ElementType.Codec.FormatSupported(BinaryFormatCode) {
+		return BinaryFormatCode
+	}
+	return TextFormatCode
+}
+
+func (c *ArrayCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	arrayValuer, ok := value.(ArrayGetter)
+	if !ok {
+		return nil
+	}
+
+	elementType := arrayValuer.IndexType()
+
+	elementEncodePlan := m.PlanEncode(c.ElementType.OID, format, elementType)
+	if elementEncodePlan == nil {
+		if reflect.TypeOf(elementType) != nil {
+			return nil
+		}
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return &encodePlanArrayCodecBinary{ac: c, m: m, oid: oid}
+	case TextFormatCode:
+		return &encodePlanArrayCodecText{ac: c, m: m, oid: oid}
+	}
+
+	return nil
+}
+
+type encodePlanArrayCodecText struct {
+	ac  *ArrayCodec
+	m   *Map
+	oid uint32
+}
+
+func (p *encodePlanArrayCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	array := value.(ArrayGetter)
+
+	dimensions := array.Dimensions()
+	if dimensions == nil {
+		return nil, nil
+	}
+
+	elementCount := cardinality(dimensions)
+	if elementCount == 0 {
+		return append(buf, '{', '}'), nil
+	}
+
+	buf = encodeTextArrayDimensions(buf, dimensions)
+
+	// dimElemCounts is the multiples of elements that each array lies on. For
+	// example, a single dimension array of length 4 would have a dimElemCounts of
+	// [4]. A multi-dimensional array of lengths [3,5,2] would have a
+	// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
+	// or '}'.
+	dimElemCounts := make([]int, len(dimensions))
+	dimElemCounts[len(dimensions)-1] = int(dimensions[len(dimensions)-1].Length)
+	for i := len(dimensions) - 2; i > -1; i-- {
+		dimElemCounts[i] = int(dimensions[i].Length) * dimElemCounts[i+1]
+	}
+
+	var encodePlan EncodePlan
+	var lastElemType reflect.Type
+	inElemBuf := make([]byte, 0, 32)
+	for i := range elementCount {
+		if i > 0 {
+			buf = append(buf, ',')
+		}
+
+		for _, dec := range dimElemCounts {
+			if i%dec == 0 {
+				buf = append(buf, '{')
+			}
+		}
+
+		elem := array.Index(i)
+		var elemBuf []byte
+		isNil, callNilDriverValuer := isNilDriverValuer(elem)
+		if !isNil {
+			elemType := reflect.TypeOf(elem)
+			if lastElemType != elemType {
+				lastElemType = elemType
+				encodePlan = p.m.PlanEncode(p.ac.ElementType.OID, TextFormatCode, elem)
+				if encodePlan == nil {
+					return nil, fmt.Errorf("unable to encode %v", array.Index(i))
+				}
+			}
+			elemBuf, err = encodePlan.Encode(elem, inElemBuf)
+			if err != nil {
+				return nil, err
+			}
+		} else if callNilDriverValuer {
+			elemBuf, err = (&encodePlanDriverValuer{m: p.m, oid: p.ac.ElementType.OID, formatCode: TextFormatCode}).Encode(elem, inElemBuf)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if elemBuf == nil {
+			buf = append(buf, `NULL`...)
+		} else {
+			buf = append(buf, quoteArrayElementIfNeeded(string(elemBuf))...)
+		}
+
+		for _, dec := range dimElemCounts {
+			if (i+1)%dec == 0 {
+				buf = append(buf, '}')
+			}
+		}
+	}
+
+	return buf, nil
+}
+
+type encodePlanArrayCodecBinary struct {
+	ac  *ArrayCodec
+	m   *Map
+	oid uint32
+}
+
+func (p *encodePlanArrayCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	array := value.(ArrayGetter)
+
+	dimensions := array.Dimensions()
+	if dimensions == nil {
+		return nil, nil
+	}
+
+	arrayHeader := arrayHeader{
+		Dimensions: dimensions,
+		ElementOID: p.ac.ElementType.OID,
+	}
+
+	containsNullIndex := len(buf) + 4
+
+	buf = arrayHeader.EncodeBinary(buf)
+
+	elementCount := cardinality(dimensions)
+
+	var encodePlan EncodePlan
+	var lastElemType reflect.Type
+	for i := range elementCount {
+		sp := len(buf)
+		buf = pgio.AppendInt32(buf, -1)
+
+		elem := array.Index(i)
+		var elemBuf []byte
+		isNil, callNilDriverValuer := isNilDriverValuer(elem)
+		if !isNil {
+			elemType := reflect.TypeOf(elem)
+			if lastElemType != elemType {
+				lastElemType = elemType
+				encodePlan = p.m.PlanEncode(p.ac.ElementType.OID, BinaryFormatCode, elem)
+				if encodePlan == nil {
+					return nil, fmt.Errorf("unable to encode %v", array.Index(i))
+				}
+			}
+			elemBuf, err = encodePlan.Encode(elem, buf)
+			if err != nil {
+				return nil, err
+			}
+		} else if callNilDriverValuer {
+			elemBuf, err = (&encodePlanDriverValuer{m: p.m, oid: p.ac.ElementType.OID, formatCode: BinaryFormatCode}).Encode(elem, buf)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if elemBuf == nil {
+			pgio.SetInt32(buf[containsNullIndex:], 1)
+		} else {
+			buf = elemBuf
+			pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+		}
+	}
+
+	return buf, nil
+}
+
+func (c *ArrayCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	arrayScanner, ok := target.(ArraySetter)
+	if !ok {
+		return nil
+	}
+
+	// target / arrayScanner might be a pointer to a nil. If it is create one so we can call ScanIndexType to plan the
+	// scan of the elements.
+	if isNil, _ := isNilDriverValuer(target); isNil {
+		arrayScanner = reflect.New(reflect.TypeOf(target).Elem()).Interface().(ArraySetter)
+	}
+
+	elementType := arrayScanner.ScanIndexType()
+
+	elementScanPlan := m.PlanScan(c.ElementType.OID, format, elementType)
+	if _, ok := elementScanPlan.(*scanPlanFail); ok {
+		return nil
+	}
+
+	return &scanPlanArrayCodec{
+		arrayCodec: c,
+		m:          m,
+		oid:        oid,
+		formatCode: format,
+	}
+}
+
+func (c *ArrayCodec) decodeBinary(m *Map, arrayOID uint32, src []byte, array ArraySetter) error {
+	var arrayHeader arrayHeader
+	rp, err := arrayHeader.DecodeBinary(m, src)
+	if err != nil {
+		return err
+	}
+
+	elementCount := cardinality(arrayHeader.Dimensions)
+	// Each element carries at minimum a 4-byte length header, so elementCount cannot exceed the
+	// remaining bytes / 4. This bounds the allocation in SetDimensions and the loop below against a
+	// malicious server claiming huge dimensions in a small message.
+	if maxElements := len(src[rp:]) / 4; elementCount > maxElements {
+		return fmt.Errorf("array claims %d elements but only %d bytes remain", elementCount, len(src[rp:]))
+	}
+
+	err = array.SetDimensions(arrayHeader.Dimensions)
+	if err != nil {
+		return err
+	}
+
+	if elementCount == 0 {
+		return nil
+	}
+
+	elementScanPlan := c.ElementType.Codec.PlanScan(m, c.ElementType.OID, BinaryFormatCode, array.ScanIndex(0))
+	if elementScanPlan == nil {
+		elementScanPlan = m.PlanScan(c.ElementType.OID, BinaryFormatCode, array.ScanIndex(0))
+	}
+
+	for i := range elementCount {
+		if len(src[rp:]) < 4 {
+			return fmt.Errorf("array body truncated at element %d", i)
+		}
+		elem := array.ScanIndex(i)
+		elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
+		rp += 4
+		var elemSrc []byte
+		if elemLen >= 0 {
+			if len(src[rp:]) < elemLen {
+				return fmt.Errorf("array element %d length %d exceeds remaining %d bytes", i, elemLen, len(src[rp:]))
+			}
+			elemSrc = src[rp : rp+elemLen]
+			rp += elemLen
+		}
+		err = elementScanPlan.Scan(elemSrc, elem)
+		if err != nil {
+			return fmt.Errorf("failed to scan array element %d: %w", i, err)
+		}
+	}
+
+	return nil
+}
+
+func (c *ArrayCodec) decodeText(m *Map, arrayOID uint32, src []byte, array ArraySetter) error {
+	uta, err := parseUntypedTextArray(string(src))
+	if err != nil {
+		return err
+	}
+
+	err = array.SetDimensions(uta.Dimensions)
+	if err != nil {
+		return err
+	}
+
+	if len(uta.Elements) == 0 {
+		return nil
+	}
+
+	elementScanPlan := c.ElementType.Codec.PlanScan(m, c.ElementType.OID, TextFormatCode, array.ScanIndex(0))
+	if elementScanPlan == nil {
+		elementScanPlan = m.PlanScan(c.ElementType.OID, TextFormatCode, array.ScanIndex(0))
+	}
+
+	for i, s := range uta.Elements {
+		elem := array.ScanIndex(i)
+		var elemSrc []byte
+		if s != "NULL" || uta.Quoted[i] {
+			elemSrc = []byte(s)
+		}
+
+		err = elementScanPlan.Scan(elemSrc, elem)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+type scanPlanArrayCodec struct {
+	arrayCodec      *ArrayCodec
+	m               *Map
+	oid             uint32
+	formatCode      int16
+	elementScanPlan ScanPlan
+}
+
+func (spac *scanPlanArrayCodec) Scan(src []byte, dst any) error {
+	c := spac.arrayCodec
+	m := spac.m
+	oid := spac.oid
+	formatCode := spac.formatCode
+
+	array := dst.(ArraySetter)
+
+	if src == nil {
+		return array.SetDimensions(nil)
+	}
+
+	switch formatCode {
+	case BinaryFormatCode:
+		return c.decodeBinary(m, oid, src, array)
+	case TextFormatCode:
+		return c.decodeText(m, oid, src, array)
+	default:
+		return fmt.Errorf("unknown format code %d", formatCode)
+	}
+}
+
+func (c *ArrayCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case TextFormatCode:
+		return string(src), nil
+	case BinaryFormatCode:
+		buf := make([]byte, len(src))
+		copy(buf, src)
+		return buf, nil
+	default:
+		return nil, fmt.Errorf("unknown format code %d", format)
+	}
+}
+
+func (c *ArrayCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var slice []any
+	err := m.PlanScan(oid, format, &slice).Scan(src, &slice)
+	return slice, err
+}
+
+func isRagged(slice reflect.Value) bool {
+	if slice.Type().Elem().Kind() != reflect.Slice {
+		return false
+	}
+
+	sliceLen := slice.Len()
+	innerLen := 0
+	for i := range sliceLen {
+		if i == 0 {
+			innerLen = slice.Index(i).Len()
+		} else if slice.Index(i).Len() != innerLen {
+			return true
+		}
+		if isRagged(slice.Index(i)) {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/bits.go b/vendor/github.com/jackc/pgx/v5/pgtype/bits.go
new file mode 100644
index 000000000..986fe2311
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/bits.go
@@ -0,0 +1,208 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type BitsScanner interface {
+	ScanBits(v Bits) error
+}
+
+type BitsValuer interface {
+	BitsValue() (Bits, error)
+}
+
+// Bits represents the PostgreSQL bit and varbit types.
+type Bits struct {
+	Bytes []byte
+	Len   int32 // Number of bits
+	Valid bool
+}
+
+// ScanBits implements the [BitsScanner] interface.
+func (b *Bits) ScanBits(v Bits) error {
+	*b = v
+	return nil
+}
+
+// BitsValue implements the [BitsValuer] interface.
+func (b Bits) BitsValue() (Bits, error) {
+	return b, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Bits) Scan(src any) error {
+	if src == nil {
+		*dst = Bits{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToBitsScanner{}.Scan([]byte(src), dst)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Bits) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	buf, err := BitsCodec{}.PlanEncode(nil, 0, TextFormatCode, src).Encode(src, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type BitsCodec struct{}
+
+func (BitsCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (BitsCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (BitsCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(BitsValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanBitsCodecBinary{}
+	case TextFormatCode:
+		return encodePlanBitsCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanBitsCodecBinary struct{}
+
+func (encodePlanBitsCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	bits, err := value.(BitsValuer).BitsValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !bits.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendInt32(buf, bits.Len)
+	return append(buf, bits.Bytes...), nil
+}
+
+type encodePlanBitsCodecText struct{}
+
+func (encodePlanBitsCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	bits, err := value.(BitsValuer).BitsValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !bits.Valid {
+		return nil, nil
+	}
+
+	for i := int32(0); i < bits.Len; i++ {
+		byteIdx := i / 8
+		bitMask := byte(128 >> byte(i%8))
+		char := byte('0')
+		if bits.Bytes[byteIdx]&bitMask > 0 {
+			char = '1'
+		}
+		buf = append(buf, char)
+	}
+
+	return buf, nil
+}
+
+func (BitsCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(BitsScanner); ok {
+			return scanPlanBinaryBitsToBitsScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(BitsScanner); ok {
+			return scanPlanTextAnyToBitsScanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c BitsCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c BitsCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var box Bits
+	err := codecScan(c, m, oid, format, src, &box)
+	if err != nil {
+		return nil, err
+	}
+	return box, nil
+}
+
+type scanPlanBinaryBitsToBitsScanner struct{}
+
+func (scanPlanBinaryBitsToBitsScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(BitsScanner)
+
+	if src == nil {
+		return scanner.ScanBits(Bits{})
+	}
+
+	if len(src) < 4 {
+		return fmt.Errorf("invalid length for bit/varbit: %v", len(src))
+	}
+
+	bitLen := int32(binary.BigEndian.Uint32(src))
+	rp := 4
+	buf := make([]byte, len(src[rp:]))
+	copy(buf, src[rp:])
+
+	return scanner.ScanBits(Bits{Bytes: buf, Len: bitLen, Valid: true})
+}
+
+type scanPlanTextAnyToBitsScanner struct{}
+
+func (scanPlanTextAnyToBitsScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(BitsScanner)
+
+	if src == nil {
+		return scanner.ScanBits(Bits{})
+	}
+
+	bitLen := len(src)
+	byteLen := bitLen / 8
+	if bitLen%8 > 0 {
+		byteLen++
+	}
+	buf := make([]byte, byteLen)
+
+	for i, b := range src {
+		if b == '1' {
+			byteIdx := i / 8
+			bitIdx := uint(i % 8)
+			buf[byteIdx] |= 128 >> bitIdx
+		}
+	}
+
+	return scanner.ScanBits(Bits{Bytes: buf, Len: int32(bitLen), Valid: true})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/bool.go b/vendor/github.com/jackc/pgx/v5/pgtype/bool.go
new file mode 100644
index 000000000..077668e79
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/bool.go
@@ -0,0 +1,346 @@
+package pgtype
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"encoding/json"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+type BoolScanner interface {
+	ScanBool(v Bool) error
+}
+
+type BoolValuer interface {
+	BoolValue() (Bool, error)
+}
+
+type Bool struct {
+	Bool  bool
+	Valid bool
+}
+
+// ScanBool implements the [BoolScanner] interface.
+func (b *Bool) ScanBool(v Bool) error {
+	*b = v
+	return nil
+}
+
+// BoolValue implements the [BoolValuer] interface.
+func (b Bool) BoolValue() (Bool, error) {
+	return b, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Bool) Scan(src any) error {
+	if src == nil {
+		*dst = Bool{}
+		return nil
+	}
+
+	switch src := src.(type) {
+	case bool:
+		*dst = Bool{Bool: src, Valid: true}
+		return nil
+	case string:
+		b, err := strconv.ParseBool(src)
+		if err != nil {
+			return err
+		}
+		*dst = Bool{Bool: b, Valid: true}
+		return nil
+	case []byte:
+		b, err := strconv.ParseBool(string(src))
+		if err != nil {
+			return err
+		}
+		*dst = Bool{Bool: b, Valid: true}
+		return nil
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Bool) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	return src.Bool, nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Bool) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+
+	if src.Bool {
+		return []byte("true"), nil
+	} else {
+		return []byte("false"), nil
+	}
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Bool) UnmarshalJSON(b []byte) error {
+	var v *bool
+	err := json.Unmarshal(b, &v)
+	if err != nil {
+		return err
+	}
+
+	if v == nil {
+		*dst = Bool{}
+	} else {
+		*dst = Bool{Bool: *v, Valid: true}
+	}
+
+	return nil
+}
+
+type BoolCodec struct{}
+
+func (BoolCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (BoolCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (BoolCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case bool:
+			return encodePlanBoolCodecBinaryBool{}
+		case BoolValuer:
+			return encodePlanBoolCodecBinaryBoolValuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case bool:
+			return encodePlanBoolCodecTextBool{}
+		case BoolValuer:
+			return encodePlanBoolCodecTextBoolValuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanBoolCodecBinaryBool struct{}
+
+func (encodePlanBoolCodecBinaryBool) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v := value.(bool)
+
+	if v {
+		buf = append(buf, 1)
+	} else {
+		buf = append(buf, 0)
+	}
+
+	return buf, nil
+}
+
+type encodePlanBoolCodecTextBoolValuer struct{}
+
+func (encodePlanBoolCodecTextBoolValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	b, err := value.(BoolValuer).BoolValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !b.Valid {
+		return nil, nil
+	}
+
+	if b.Bool {
+		buf = append(buf, 't')
+	} else {
+		buf = append(buf, 'f')
+	}
+
+	return buf, nil
+}
+
+type encodePlanBoolCodecBinaryBoolValuer struct{}
+
+func (encodePlanBoolCodecBinaryBoolValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	b, err := value.(BoolValuer).BoolValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !b.Valid {
+		return nil, nil
+	}
+
+	if b.Bool {
+		buf = append(buf, 1)
+	} else {
+		buf = append(buf, 0)
+	}
+
+	return buf, nil
+}
+
+type encodePlanBoolCodecTextBool struct{}
+
+func (encodePlanBoolCodecTextBool) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v := value.(bool)
+
+	if v {
+		buf = append(buf, 't')
+	} else {
+		buf = append(buf, 'f')
+	}
+
+	return buf, nil
+}
+
+func (BoolCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *bool:
+			return scanPlanBinaryBoolToBool{}
+		case BoolScanner:
+			return scanPlanBinaryBoolToBoolScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *bool:
+			return scanPlanTextAnyToBool{}
+		case BoolScanner:
+			return scanPlanTextAnyToBoolScanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c BoolCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return c.DecodeValue(m, oid, format, src)
+}
+
+func (c BoolCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var b bool
+	err := codecScan(c, m, oid, format, src, &b)
+	if err != nil {
+		return nil, err
+	}
+	return b, nil
+}
+
+type scanPlanBinaryBoolToBool struct{}
+
+func (scanPlanBinaryBoolToBool) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 1 {
+		return fmt.Errorf("invalid length for bool: %v", len(src))
+	}
+
+	p, ok := (dst).(*bool)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = src[0] == 1
+
+	return nil
+}
+
+type scanPlanTextAnyToBool struct{}
+
+func (scanPlanTextAnyToBool) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) == 0 {
+		return fmt.Errorf("cannot scan empty string into %T", dst)
+	}
+
+	p, ok := (dst).(*bool)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	v, err := planTextToBool(src)
+	if err != nil {
+		return err
+	}
+
+	*p = v
+
+	return nil
+}
+
+type scanPlanBinaryBoolToBoolScanner struct{}
+
+func (scanPlanBinaryBoolToBoolScanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(BoolScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanBool(Bool{})
+	}
+
+	if len(src) != 1 {
+		return fmt.Errorf("invalid length for bool: %v", len(src))
+	}
+
+	return s.ScanBool(Bool{Bool: src[0] == 1, Valid: true})
+}
+
+type scanPlanTextAnyToBoolScanner struct{}
+
+func (scanPlanTextAnyToBoolScanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(BoolScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanBool(Bool{})
+	}
+
+	if len(src) == 0 {
+		return fmt.Errorf("cannot scan empty string into %T", dst)
+	}
+
+	v, err := planTextToBool(src)
+	if err != nil {
+		return err
+	}
+
+	return s.ScanBool(Bool{Bool: v, Valid: true})
+}
+
+// https://www.postgresql.org/docs/current/datatype-boolean.html
+func planTextToBool(src []byte) (bool, error) {
+	s := string(bytes.ToLower(bytes.TrimSpace(src)))
+
+	switch {
+	case strings.HasPrefix("true", s), strings.HasPrefix("yes", s), s == "on", s == "1": //nolint:gocritic // s is intentionally the prefix argument so partial inputs (t, tr, tru) also match.
+		return true, nil
+	case strings.HasPrefix("false", s), strings.HasPrefix("no", s), strings.HasPrefix("off", s), s == "0": //nolint:gocritic // s is intentionally the prefix argument so partial inputs (f, fa, fal) also match.
+		return false, nil
+	default:
+		return false, fmt.Errorf("unknown boolean string representation %q", src)
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/box.go b/vendor/github.com/jackc/pgx/v5/pgtype/box.go
new file mode 100644
index 000000000..8270aafd5
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/box.go
@@ -0,0 +1,235 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type BoxScanner interface {
+	ScanBox(v Box) error
+}
+
+type BoxValuer interface {
+	BoxValue() (Box, error)
+}
+
+type Box struct {
+	P     [2]Vec2
+	Valid bool
+}
+
+// ScanBox implements the [BoxScanner] interface.
+func (b *Box) ScanBox(v Box) error {
+	*b = v
+	return nil
+}
+
+// BoxValue implements the [BoxValuer] interface.
+func (b Box) BoxValue() (Box, error) {
+	return b, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Box) Scan(src any) error {
+	if src == nil {
+		*dst = Box{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToBoxScanner{}.Scan([]byte(src), dst)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Box) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	buf, err := BoxCodec{}.PlanEncode(nil, 0, TextFormatCode, src).Encode(src, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type BoxCodec struct{}
+
+func (BoxCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (BoxCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (BoxCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(BoxValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanBoxCodecBinary{}
+	case TextFormatCode:
+		return encodePlanBoxCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanBoxCodecBinary struct{}
+
+func (encodePlanBoxCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	box, err := value.(BoxValuer).BoxValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !box.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendUint64(buf, math.Float64bits(box.P[0].X))
+	buf = pgio.AppendUint64(buf, math.Float64bits(box.P[0].Y))
+	buf = pgio.AppendUint64(buf, math.Float64bits(box.P[1].X))
+	buf = pgio.AppendUint64(buf, math.Float64bits(box.P[1].Y))
+	return buf, nil
+}
+
+type encodePlanBoxCodecText struct{}
+
+func (encodePlanBoxCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	box, err := value.(BoxValuer).BoxValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !box.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, fmt.Sprintf(`(%s,%s),(%s,%s)`,
+		strconv.FormatFloat(box.P[0].X, 'f', -1, 64),
+		strconv.FormatFloat(box.P[0].Y, 'f', -1, 64),
+		strconv.FormatFloat(box.P[1].X, 'f', -1, 64),
+		strconv.FormatFloat(box.P[1].Y, 'f', -1, 64),
+	)...)
+	return buf, nil
+}
+
+func (BoxCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(BoxScanner); ok {
+			return scanPlanBinaryBoxToBoxScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(BoxScanner); ok {
+			return scanPlanTextAnyToBoxScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryBoxToBoxScanner struct{}
+
+func (scanPlanBinaryBoxToBoxScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(BoxScanner)
+
+	if src == nil {
+		return scanner.ScanBox(Box{})
+	}
+
+	if len(src) != 32 {
+		return fmt.Errorf("invalid length for Box: %v", len(src))
+	}
+
+	x1 := binary.BigEndian.Uint64(src)
+	y1 := binary.BigEndian.Uint64(src[8:])
+	x2 := binary.BigEndian.Uint64(src[16:])
+	y2 := binary.BigEndian.Uint64(src[24:])
+
+	return scanner.ScanBox(Box{
+		P: [2]Vec2{
+			{math.Float64frombits(x1), math.Float64frombits(y1)},
+			{math.Float64frombits(x2), math.Float64frombits(y2)},
+		},
+		Valid: true,
+	})
+}
+
+type scanPlanTextAnyToBoxScanner struct{}
+
+func (scanPlanTextAnyToBoxScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(BoxScanner)
+
+	if src == nil {
+		return scanner.ScanBox(Box{})
+	}
+
+	if len(src) < 11 {
+		return fmt.Errorf("invalid length for Box: %v", len(src))
+	}
+
+	// Expected format: (x1,y1),(x2,y2)
+	sp1, sp2, found := strings.Cut(string(src[1:len(src)-1]), "),(")
+	if !found {
+		return fmt.Errorf("invalid format for Box")
+	}
+
+	sx1, sy1, found := strings.Cut(sp1, ",")
+	if !found {
+		return fmt.Errorf("invalid format for Box")
+	}
+	sx2, sy2, found := strings.Cut(sp2, ",")
+	if !found {
+		return fmt.Errorf("invalid format for Box")
+	}
+
+	x1, err := strconv.ParseFloat(sx1, 64)
+	if err != nil {
+		return err
+	}
+	y1, err := strconv.ParseFloat(sy1, 64)
+	if err != nil {
+		return err
+	}
+	x2, err := strconv.ParseFloat(sx2, 64)
+	if err != nil {
+		return err
+	}
+	y2, err := strconv.ParseFloat(sy2, 64)
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanBox(Box{P: [2]Vec2{{x1, y1}, {x2, y2}}, Valid: true})
+}
+
+func (c BoxCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c BoxCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var box Box
+	err := codecScan(c, m, oid, format, src, &box)
+	if err != nil {
+		return nil, err
+	}
+	return box, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/builtin_wrappers.go b/vendor/github.com/jackc/pgx/v5/pgtype/builtin_wrappers.go
new file mode 100644
index 000000000..a412763a9
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/builtin_wrappers.go
@@ -0,0 +1,952 @@
+package pgtype
+
+import (
+	"errors"
+	"fmt"
+	"math"
+	"math/big"
+	"net"
+	"net/netip"
+	"reflect"
+	"time"
+)
+
+type int8Wrapper int8
+
+func (w int8Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *int8Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *int8")
+	}
+
+	if v.Int64 < math.MinInt8 {
+		return fmt.Errorf("%d is less than minimum value for int8", v.Int64)
+	}
+	if v.Int64 > math.MaxInt8 {
+		return fmt.Errorf("%d is greater than maximum value for int8", v.Int64)
+	}
+	*w = int8Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w int8Wrapper) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+type int16Wrapper int16
+
+func (w int16Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *int16Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *int16")
+	}
+
+	if v.Int64 < math.MinInt16 {
+		return fmt.Errorf("%d is less than minimum value for int16", v.Int64)
+	}
+	if v.Int64 > math.MaxInt16 {
+		return fmt.Errorf("%d is greater than maximum value for int16", v.Int64)
+	}
+	*w = int16Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w int16Wrapper) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+type int32Wrapper int32
+
+func (w int32Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *int32Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *int32")
+	}
+
+	if v.Int64 < math.MinInt32 {
+		return fmt.Errorf("%d is less than minimum value for int32", v.Int64)
+	}
+	if v.Int64 > math.MaxInt32 {
+		return fmt.Errorf("%d is greater than maximum value for int32", v.Int64)
+	}
+	*w = int32Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w int32Wrapper) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+type int64Wrapper int64
+
+func (w int64Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *int64Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *int64")
+	}
+
+	*w = int64Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w int64Wrapper) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+type intWrapper int
+
+func (w intWrapper) SkipUnderlyingTypePlan() {}
+
+func (w *intWrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *int")
+	}
+
+	if v.Int64 < math.MinInt {
+		return fmt.Errorf("%d is less than minimum value for int", v.Int64)
+	}
+	if v.Int64 > math.MaxInt {
+		return fmt.Errorf("%d is greater than maximum value for int", v.Int64)
+	}
+
+	*w = intWrapper(v.Int64)
+
+	return nil
+}
+
+func (w intWrapper) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+type uint8Wrapper uint8
+
+func (w uint8Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *uint8Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *uint8")
+	}
+
+	if v.Int64 < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint8", v.Int64)
+	}
+	if v.Int64 > math.MaxUint8 {
+		return fmt.Errorf("%d is greater than maximum value for uint8", v.Int64)
+	}
+	*w = uint8Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w uint8Wrapper) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+type uint16Wrapper uint16
+
+func (w uint16Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *uint16Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *uint16")
+	}
+
+	if v.Int64 < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint16", v.Int64)
+	}
+	if v.Int64 > math.MaxUint16 {
+		return fmt.Errorf("%d is greater than maximum value for uint16", v.Int64)
+	}
+	*w = uint16Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w uint16Wrapper) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+type uint32Wrapper uint32
+
+func (w uint32Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *uint32Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *uint32")
+	}
+
+	if v.Int64 < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint32", v.Int64)
+	}
+	if v.Int64 > math.MaxUint32 {
+		return fmt.Errorf("%d is greater than maximum value for uint32", v.Int64)
+	}
+	*w = uint32Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w uint32Wrapper) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+type uint64Wrapper uint64
+
+func (w uint64Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *uint64Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *uint64")
+	}
+
+	if v.Int64 < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint64", v.Int64)
+	}
+
+	*w = uint64Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w uint64Wrapper) Int64Value() (Int8, error) {
+	if uint64(w) > uint64(math.MaxInt64) {
+		return Int8{}, fmt.Errorf("%d is greater than maximum value for int64", w)
+	}
+
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+func (w *uint64Wrapper) ScanNumeric(v Numeric) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *uint64")
+	}
+
+	bi, err := v.toBigInt()
+	if err != nil {
+		return fmt.Errorf("cannot scan into *uint64: %w", err)
+	}
+
+	if !bi.IsUint64() {
+		return fmt.Errorf("cannot scan %v into *uint64", bi.String())
+	}
+
+	*w = uint64Wrapper(bi.Uint64())
+
+	return nil
+}
+
+func (w uint64Wrapper) NumericValue() (Numeric, error) {
+	return Numeric{Int: new(big.Int).SetUint64(uint64(w)), Valid: true}, nil
+}
+
+type uintWrapper uint
+
+func (w uintWrapper) SkipUnderlyingTypePlan() {}
+
+func (w *uintWrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *uint64")
+	}
+
+	if v.Int64 < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint64", v.Int64)
+	}
+
+	if uint64(v.Int64) > math.MaxUint {
+		return fmt.Errorf("%d is greater than maximum value for uint", v.Int64)
+	}
+
+	*w = uintWrapper(v.Int64)
+
+	return nil
+}
+
+func (w uintWrapper) Int64Value() (Int8, error) {
+	if uint64(w) > uint64(math.MaxInt64) {
+		return Int8{}, fmt.Errorf("%d is greater than maximum value for int64", w)
+	}
+
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+func (w *uintWrapper) ScanNumeric(v Numeric) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *uint")
+	}
+
+	bi, err := v.toBigInt()
+	if err != nil {
+		return fmt.Errorf("cannot scan into *uint: %w", err)
+	}
+
+	if !bi.IsUint64() {
+		return fmt.Errorf("cannot scan %v into *uint", bi.String())
+	}
+
+	ui := bi.Uint64()
+
+	if math.MaxUint < ui {
+		return fmt.Errorf("cannot scan %v into *uint", ui)
+	}
+
+	*w = uintWrapper(ui)
+
+	return nil
+}
+
+func (w uintWrapper) NumericValue() (Numeric, error) {
+	return Numeric{Int: new(big.Int).SetUint64(uint64(w)), Valid: true}, nil
+}
+
+type float32Wrapper float32
+
+func (w float32Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *float32Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *float32")
+	}
+
+	*w = float32Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w float32Wrapper) Int64Value() (Int8, error) {
+	if w > math.MaxInt64 {
+		return Int8{}, fmt.Errorf("%f is greater than maximum value for int64", w)
+	}
+
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+func (w *float32Wrapper) ScanFloat64(v Float8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *float32")
+	}
+
+	*w = float32Wrapper(v.Float64)
+
+	return nil
+}
+
+func (w float32Wrapper) Float64Value() (Float8, error) {
+	return Float8{Float64: float64(w), Valid: true}, nil
+}
+
+type float64Wrapper float64
+
+func (w float64Wrapper) SkipUnderlyingTypePlan() {}
+
+func (w *float64Wrapper) ScanInt64(v Int8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *float64")
+	}
+
+	*w = float64Wrapper(v.Int64)
+
+	return nil
+}
+
+func (w float64Wrapper) Int64Value() (Int8, error) {
+	if w > math.MaxInt64 {
+		return Int8{}, fmt.Errorf("%f is greater than maximum value for int64", w)
+	}
+
+	return Int8{Int64: int64(w), Valid: true}, nil
+}
+
+func (w *float64Wrapper) ScanFloat64(v Float8) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *float64")
+	}
+
+	*w = float64Wrapper(v.Float64)
+
+	return nil
+}
+
+func (w float64Wrapper) Float64Value() (Float8, error) {
+	return Float8{Float64: float64(w), Valid: true}, nil
+}
+
+type stringWrapper string
+
+func (w stringWrapper) SkipUnderlyingTypePlan() {}
+
+func (w *stringWrapper) ScanText(v Text) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *string")
+	}
+
+	*w = stringWrapper(v.String)
+	return nil
+}
+
+func (w stringWrapper) TextValue() (Text, error) {
+	return Text{String: string(w), Valid: true}, nil
+}
+
+type timeWrapper time.Time
+
+func (w *timeWrapper) ScanDate(v Date) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *time.Time")
+	}
+
+	switch v.InfinityModifier {
+	case Finite:
+		*w = timeWrapper(v.Time)
+		return nil
+	case Infinity:
+		return fmt.Errorf("cannot scan Infinity into *time.Time")
+	case NegativeInfinity:
+		return fmt.Errorf("cannot scan -Infinity into *time.Time")
+	default:
+		return fmt.Errorf("invalid InfinityModifier: %v", v.InfinityModifier)
+	}
+}
+
+func (w timeWrapper) DateValue() (Date, error) {
+	return Date{Time: time.Time(w), Valid: true}, nil
+}
+
+func (w *timeWrapper) ScanTimestamp(v Timestamp) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *time.Time")
+	}
+
+	switch v.InfinityModifier {
+	case Finite:
+		*w = timeWrapper(v.Time)
+		return nil
+	case Infinity:
+		return fmt.Errorf("cannot scan Infinity into *time.Time")
+	case NegativeInfinity:
+		return fmt.Errorf("cannot scan -Infinity into *time.Time")
+	default:
+		return fmt.Errorf("invalid InfinityModifier: %v", v.InfinityModifier)
+	}
+}
+
+func (w timeWrapper) TimestampValue() (Timestamp, error) {
+	return Timestamp{Time: time.Time(w), Valid: true}, nil
+}
+
+func (w *timeWrapper) ScanTimestamptz(v Timestamptz) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *time.Time")
+	}
+
+	switch v.InfinityModifier {
+	case Finite:
+		*w = timeWrapper(v.Time)
+		return nil
+	case Infinity:
+		return fmt.Errorf("cannot scan Infinity into *time.Time")
+	case NegativeInfinity:
+		return fmt.Errorf("cannot scan -Infinity into *time.Time")
+	default:
+		return fmt.Errorf("invalid InfinityModifier: %v", v.InfinityModifier)
+	}
+}
+
+func (w timeWrapper) TimestamptzValue() (Timestamptz, error) {
+	return Timestamptz{Time: time.Time(w), Valid: true}, nil
+}
+
+func (w *timeWrapper) ScanTime(v Time) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *time.Time")
+	}
+
+	// 24:00:00 is max allowed time in PostgreSQL, but time.Time will normalize that to 00:00:00 the next day.
+	var maxRepresentableByTime int64 = 24*60*60*1000000 - 1
+	if v.Microseconds > maxRepresentableByTime {
+		return fmt.Errorf("%d microseconds cannot be represented as time.Time", v.Microseconds)
+	}
+
+	usec := v.Microseconds
+	hours := usec / microsecondsPerHour
+	usec -= hours * microsecondsPerHour
+	minutes := usec / microsecondsPerMinute
+	usec -= minutes * microsecondsPerMinute
+	seconds := usec / microsecondsPerSecond
+	usec -= seconds * microsecondsPerSecond
+	ns := usec * 1000
+	*w = timeWrapper(time.Date(2000, 1, 1, int(hours), int(minutes), int(seconds), int(ns), time.UTC))
+	return nil
+}
+
+func (w timeWrapper) TimeValue() (Time, error) {
+	t := time.Time(w)
+	usec := int64(t.Hour())*microsecondsPerHour +
+		int64(t.Minute())*microsecondsPerMinute +
+		int64(t.Second())*microsecondsPerSecond +
+		int64(t.Nanosecond())/1000
+	return Time{Microseconds: usec, Valid: true}, nil
+}
+
+type durationWrapper time.Duration
+
+func (w durationWrapper) SkipUnderlyingTypePlan() {}
+
+func (w *durationWrapper) ScanInterval(v Interval) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *time.Interval")
+	}
+
+	us := int64(v.Months)*microsecondsPerMonth + int64(v.Days)*microsecondsPerDay + v.Microseconds
+	*w = durationWrapper(time.Duration(us) * time.Microsecond)
+	return nil
+}
+
+func (w durationWrapper) IntervalValue() (Interval, error) {
+	return Interval{Microseconds: int64(w) / 1000, Valid: true}, nil
+}
+
+type netIPNetWrapper net.IPNet
+
+func (w *netIPNetWrapper) ScanNetipPrefix(v netip.Prefix) error {
+	if !v.IsValid() {
+		return fmt.Errorf("cannot scan NULL into *net.IPNet")
+	}
+
+	*w = netIPNetWrapper{
+		IP:   v.Addr().AsSlice(),
+		Mask: net.CIDRMask(v.Bits(), v.Addr().BitLen()),
+	}
+
+	return nil
+}
+
+func (w netIPNetWrapper) NetipPrefixValue() (netip.Prefix, error) {
+	ip, ok := netip.AddrFromSlice(w.IP)
+	if !ok {
+		return netip.Prefix{}, errors.New("invalid net.IPNet")
+	}
+
+	ones, _ := w.Mask.Size()
+
+	return netip.PrefixFrom(ip, ones), nil
+}
+
+type netIPWrapper net.IP
+
+func (w netIPWrapper) SkipUnderlyingTypePlan() {}
+
+func (w *netIPWrapper) ScanNetipPrefix(v netip.Prefix) error {
+	if !v.IsValid() {
+		*w = nil
+		return nil
+	}
+
+	if v.Addr().BitLen() != v.Bits() {
+		return fmt.Errorf("cannot scan %v to *net.IP", v)
+	}
+
+	*w = netIPWrapper(v.Addr().AsSlice())
+	return nil
+}
+
+func (w netIPWrapper) NetipPrefixValue() (netip.Prefix, error) {
+	if w == nil {
+		return netip.Prefix{}, nil
+	}
+
+	addr, ok := netip.AddrFromSlice([]byte(w))
+	if !ok {
+		return netip.Prefix{}, errors.New("invalid net.IP")
+	}
+
+	return netip.PrefixFrom(addr, addr.BitLen()), nil
+}
+
+type netipPrefixWrapper netip.Prefix
+
+func (w *netipPrefixWrapper) ScanNetipPrefix(v netip.Prefix) error {
+	*w = netipPrefixWrapper(v)
+	return nil
+}
+
+func (w netipPrefixWrapper) NetipPrefixValue() (netip.Prefix, error) {
+	return netip.Prefix(w), nil
+}
+
+type netipAddrWrapper netip.Addr
+
+func (w *netipAddrWrapper) ScanNetipPrefix(v netip.Prefix) error {
+	if !v.IsValid() {
+		*w = netipAddrWrapper(netip.Addr{})
+		return nil
+	}
+
+	if v.Addr().BitLen() != v.Bits() {
+		return fmt.Errorf("cannot scan %v to netip.Addr", v)
+	}
+
+	*w = netipAddrWrapper(v.Addr())
+
+	return nil
+}
+
+func (w netipAddrWrapper) NetipPrefixValue() (netip.Prefix, error) {
+	addr := (netip.Addr)(w)
+	if !addr.IsValid() {
+		return netip.Prefix{}, nil
+	}
+
+	return netip.PrefixFrom(addr, addr.BitLen()), nil
+}
+
+type mapStringToPointerStringWrapper map[string]*string
+
+func (w *mapStringToPointerStringWrapper) ScanHstore(v Hstore) error {
+	*w = mapStringToPointerStringWrapper(v)
+	return nil
+}
+
+func (w mapStringToPointerStringWrapper) HstoreValue() (Hstore, error) {
+	return Hstore(w), nil
+}
+
+type mapStringToStringWrapper map[string]string
+
+func (w *mapStringToStringWrapper) ScanHstore(v Hstore) error {
+	*w = make(mapStringToStringWrapper, len(v))
+	for k, v := range v {
+		if v == nil {
+			return fmt.Errorf("cannot scan NULL to string")
+		}
+		(*w)[k] = *v
+	}
+	return nil
+}
+
+func (w mapStringToStringWrapper) HstoreValue() (Hstore, error) {
+	if w == nil {
+		return nil, nil
+	}
+
+	hstore := make(Hstore, len(w))
+	for k, v := range w {
+		s := v
+		hstore[k] = &s
+	}
+	return hstore, nil
+}
+
+type fmtStringerWrapper struct {
+	s fmt.Stringer
+}
+
+func (w fmtStringerWrapper) TextValue() (Text, error) {
+	return Text{String: w.s.String(), Valid: true}, nil
+}
+
+type byte16Wrapper [16]byte
+
+func (w *byte16Wrapper) ScanUUID(v UUID) error {
+	if !v.Valid {
+		return fmt.Errorf("cannot scan NULL into *[16]byte")
+	}
+	*w = byte16Wrapper(v.Bytes)
+	return nil
+}
+
+func (w byte16Wrapper) UUIDValue() (UUID, error) {
+	return UUID{Bytes: [16]byte(w), Valid: true}, nil
+}
+
+type byteSliceWrapper []byte
+
+func (w byteSliceWrapper) SkipUnderlyingTypePlan() {}
+
+func (w *byteSliceWrapper) ScanText(v Text) error {
+	if !v.Valid {
+		*w = nil
+		return nil
+	}
+
+	*w = byteSliceWrapper(v.String)
+	return nil
+}
+
+func (w byteSliceWrapper) TextValue() (Text, error) {
+	if w == nil {
+		return Text{}, nil
+	}
+
+	return Text{String: string(w), Valid: true}, nil
+}
+
+func (w *byteSliceWrapper) ScanUUID(v UUID) error {
+	if !v.Valid {
+		*w = nil
+		return nil
+	}
+	*w = make(byteSliceWrapper, 16)
+	copy(*w, v.Bytes[:])
+	return nil
+}
+
+func (w byteSliceWrapper) UUIDValue() (UUID, error) {
+	if w == nil {
+		return UUID{}, nil
+	}
+
+	uuid := UUID{Valid: true}
+	copy(uuid.Bytes[:], w)
+	return uuid, nil
+}
+
+// structWrapper implements CompositeIndexGetter for a struct.
+type structWrapper struct {
+	s              any
+	exportedFields []reflect.Value
+}
+
+func (w structWrapper) IsNull() bool {
+	return w.s == nil
+}
+
+func (w structWrapper) Index(i int) any {
+	if i >= len(w.exportedFields) {
+		return fmt.Errorf("%#v only has %d public fields - %d is out of bounds", w.s, len(w.exportedFields), i)
+	}
+
+	return w.exportedFields[i].Interface()
+}
+
+// ptrStructWrapper implements CompositeIndexScanner for a pointer to a struct.
+type ptrStructWrapper struct {
+	s              any
+	exportedFields []reflect.Value
+}
+
+func (w *ptrStructWrapper) ScanNull() error {
+	return fmt.Errorf("cannot scan NULL into %#v", w.s)
+}
+
+func (w *ptrStructWrapper) ScanIndex(i int) any {
+	if i >= len(w.exportedFields) {
+		return fmt.Errorf("%#v only has %d public fields - %d is out of bounds", w.s, len(w.exportedFields), i)
+	}
+
+	return w.exportedFields[i].Addr().Interface()
+}
+
+type anySliceArrayReflect struct {
+	slice reflect.Value
+}
+
+func (a anySliceArrayReflect) Dimensions() []ArrayDimension {
+	if a.slice.IsNil() {
+		return nil
+	}
+
+	return []ArrayDimension{{Length: int32(a.slice.Len()), LowerBound: 1}}
+}
+
+func (a anySliceArrayReflect) Index(i int) any {
+	return a.slice.Index(i).Interface()
+}
+
+func (a anySliceArrayReflect) IndexType() any {
+	return reflect.New(a.slice.Type().Elem()).Elem().Interface()
+}
+
+func (a *anySliceArrayReflect) SetDimensions(dimensions []ArrayDimension) error {
+	sliceType := a.slice.Type()
+
+	if dimensions == nil {
+		a.slice.Set(reflect.Zero(sliceType))
+		return nil
+	}
+
+	elementCount := cardinality(dimensions)
+	slice := reflect.MakeSlice(sliceType, elementCount, elementCount)
+	a.slice.Set(slice)
+	return nil
+}
+
+func (a *anySliceArrayReflect) ScanIndex(i int) any {
+	return a.slice.Index(i).Addr().Interface()
+}
+
+func (a *anySliceArrayReflect) ScanIndexType() any {
+	return reflect.New(a.slice.Type().Elem()).Interface()
+}
+
+type anyMultiDimSliceArray struct {
+	slice reflect.Value
+	dims  []ArrayDimension
+}
+
+func (a *anyMultiDimSliceArray) Dimensions() []ArrayDimension {
+	if a.slice.IsNil() {
+		return nil
+	}
+
+	s := a.slice
+	for {
+		a.dims = append(a.dims, ArrayDimension{Length: int32(s.Len()), LowerBound: 1})
+		if s.Len() > 0 {
+			s = s.Index(0)
+		} else {
+			break
+		}
+		if s.Type().Kind() == reflect.Slice {
+		} else {
+			break
+		}
+	}
+
+	return a.dims
+}
+
+func (a *anyMultiDimSliceArray) Index(i int) any {
+	if len(a.dims) == 1 {
+		return a.slice.Index(i).Interface()
+	}
+
+	indexes := make([]int, len(a.dims))
+	for j := len(a.dims) - 1; j >= 0; j-- {
+		dimLen := int(a.dims[j].Length)
+		indexes[j] = i % dimLen
+		i /= dimLen
+	}
+
+	v := a.slice
+	for _, si := range indexes {
+		v = v.Index(si)
+	}
+
+	return v.Interface()
+}
+
+func (a *anyMultiDimSliceArray) IndexType() any {
+	lowestSliceType := a.slice.Type()
+	for ; lowestSliceType.Elem().Kind() == reflect.Slice; lowestSliceType = lowestSliceType.Elem() {
+	}
+	return reflect.New(lowestSliceType.Elem()).Elem().Interface()
+}
+
+func (a *anyMultiDimSliceArray) SetDimensions(dimensions []ArrayDimension) error {
+	sliceType := a.slice.Type()
+
+	if dimensions == nil {
+		a.slice.Set(reflect.Zero(sliceType))
+		return nil
+	}
+
+	switch len(dimensions) {
+	case 0:
+		// Empty, but non-nil array
+		slice := reflect.MakeSlice(sliceType, 0, 0)
+		a.slice.Set(slice)
+		return nil
+	case 1:
+		elementCount := cardinality(dimensions)
+		slice := reflect.MakeSlice(sliceType, elementCount, elementCount)
+		a.slice.Set(slice)
+		return nil
+	default:
+		sliceDimensionCount := 1
+		lowestSliceType := sliceType
+		for ; lowestSliceType.Elem().Kind() == reflect.Slice; lowestSliceType = lowestSliceType.Elem() {
+			sliceDimensionCount++
+		}
+
+		if sliceDimensionCount != len(dimensions) {
+			return fmt.Errorf("PostgreSQL array has %d dimensions but slice has %d dimensions", len(dimensions), sliceDimensionCount)
+		}
+
+		elementCount := cardinality(dimensions)
+		flatSlice := reflect.MakeSlice(lowestSliceType, elementCount, elementCount)
+
+		multiDimSlice := a.makeMultidimensionalSlice(sliceType, dimensions, flatSlice, 0)
+		a.slice.Set(multiDimSlice)
+
+		// Now that a.slice is a multi-dimensional slice with the underlying data pointed at flatSlice change a.slice to
+		// flatSlice so ScanIndex only has to handle simple one dimensional slices.
+		a.slice = flatSlice
+
+		return nil
+	}
+}
+
+func (a *anyMultiDimSliceArray) makeMultidimensionalSlice(sliceType reflect.Type, dimensions []ArrayDimension, flatSlice reflect.Value, flatSliceIdx int) reflect.Value {
+	if len(dimensions) == 1 {
+		endIdx := flatSliceIdx + int(dimensions[0].Length)
+		return flatSlice.Slice3(flatSliceIdx, endIdx, endIdx)
+	}
+
+	sliceLen := int(dimensions[0].Length)
+	slice := reflect.MakeSlice(sliceType, sliceLen, sliceLen)
+	for i := range sliceLen {
+		subSlice := a.makeMultidimensionalSlice(sliceType.Elem(), dimensions[1:], flatSlice, flatSliceIdx+(i*int(dimensions[1].Length)))
+		slice.Index(i).Set(subSlice)
+	}
+
+	return slice
+}
+
+func (a *anyMultiDimSliceArray) ScanIndex(i int) any {
+	return a.slice.Index(i).Addr().Interface()
+}
+
+func (a *anyMultiDimSliceArray) ScanIndexType() any {
+	lowestSliceType := a.slice.Type()
+	for ; lowestSliceType.Elem().Kind() == reflect.Slice; lowestSliceType = lowestSliceType.Elem() {
+	}
+	return reflect.New(lowestSliceType.Elem()).Interface()
+}
+
+type anyArrayArrayReflect struct {
+	array reflect.Value
+}
+
+func (a anyArrayArrayReflect) Dimensions() []ArrayDimension {
+	return []ArrayDimension{{Length: int32(a.array.Len()), LowerBound: 1}}
+}
+
+func (a anyArrayArrayReflect) Index(i int) any {
+	return a.array.Index(i).Interface()
+}
+
+func (a anyArrayArrayReflect) IndexType() any {
+	return reflect.New(a.array.Type().Elem()).Elem().Interface()
+}
+
+func (a *anyArrayArrayReflect) SetDimensions(dimensions []ArrayDimension) error {
+	if dimensions == nil {
+		return fmt.Errorf("anyArrayArrayReflect: cannot scan NULL into %v", a.array.Type().String())
+	}
+
+	if len(dimensions) != 1 {
+		return fmt.Errorf("anyArrayArrayReflect: cannot scan multi-dimensional array into %v", a.array.Type().String())
+	}
+
+	if int(dimensions[0].Length) != a.array.Len() {
+		return fmt.Errorf("anyArrayArrayReflect: cannot scan array with length %v into %v", dimensions[0].Length, a.array.Type().String())
+	}
+
+	return nil
+}
+
+func (a *anyArrayArrayReflect) ScanIndex(i int) any {
+	return a.array.Index(i).Addr().Interface()
+}
+
+func (a *anyArrayArrayReflect) ScanIndexType() any {
+	return reflect.New(a.array.Type().Elem()).Interface()
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/bytea.go b/vendor/github.com/jackc/pgx/v5/pgtype/bytea.go
new file mode 100644
index 000000000..6c4f0c5ea
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/bytea.go
@@ -0,0 +1,254 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/hex"
+	"fmt"
+)
+
+type BytesScanner interface {
+	// ScanBytes receives a byte slice of driver memory that is only valid until the next database method call.
+	ScanBytes(v []byte) error
+}
+
+type BytesValuer interface {
+	// BytesValue returns a byte slice of the byte data. The caller must not change the returned slice.
+	BytesValue() ([]byte, error)
+}
+
+// DriverBytes is a byte slice that holds a reference to memory owned by the driver. It is only valid from the time it
+// is scanned until Rows.Next or Rows.Close is called. It is never safe to use DriverBytes with QueryRow as Row.Scan
+// internally calls Rows.Close before returning.
+type DriverBytes []byte
+
+func (b *DriverBytes) ScanBytes(v []byte) error {
+	*b = v
+	return nil
+}
+
+// PreallocBytes is a byte slice of preallocated memory that scanned bytes will be copied to. If it is too small a new
+// slice will be allocated.
+type PreallocBytes []byte
+
+func (b *PreallocBytes) ScanBytes(v []byte) error {
+	if v == nil {
+		*b = nil
+		return nil
+	}
+
+	if len(v) <= len(*b) {
+		*b = (*b)[:len(v)]
+	} else {
+		*b = make(PreallocBytes, len(v))
+	}
+	copy(*b, v)
+	return nil
+}
+
+// UndecodedBytes can be used as a scan target to get the raw bytes from PostgreSQL without any decoding.
+type UndecodedBytes []byte
+
+type scanPlanAnyToUndecodedBytes struct{}
+
+func (scanPlanAnyToUndecodedBytes) Scan(src []byte, dst any) error {
+	dstBuf := dst.(*UndecodedBytes)
+	if src == nil {
+		*dstBuf = nil
+		return nil
+	}
+
+	*dstBuf = make([]byte, len(src))
+	copy(*dstBuf, src)
+	return nil
+}
+
+type ByteaCodec struct{}
+
+func (ByteaCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (ByteaCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (ByteaCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case []byte:
+			return encodePlanBytesCodecBinaryBytes{}
+		case BytesValuer:
+			return encodePlanBytesCodecBinaryBytesValuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case []byte:
+			return encodePlanBytesCodecTextBytes{}
+		case BytesValuer:
+			return encodePlanBytesCodecTextBytesValuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanBytesCodecBinaryBytes struct{}
+
+func (encodePlanBytesCodecBinaryBytes) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	b := value.([]byte)
+	if b == nil {
+		return nil, nil
+	}
+
+	return append(buf, b...), nil
+}
+
+type encodePlanBytesCodecBinaryBytesValuer struct{}
+
+func (encodePlanBytesCodecBinaryBytesValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	b, err := value.(BytesValuer).BytesValue()
+	if err != nil {
+		return nil, err
+	}
+	if b == nil {
+		return nil, nil
+	}
+
+	return append(buf, b...), nil
+}
+
+type encodePlanBytesCodecTextBytes struct{}
+
+func (encodePlanBytesCodecTextBytes) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	b := value.([]byte)
+	if b == nil {
+		return nil, nil
+	}
+
+	buf = append(buf, `\x`...)
+	buf = append(buf, hex.EncodeToString(b)...)
+	return buf, nil
+}
+
+type encodePlanBytesCodecTextBytesValuer struct{}
+
+func (encodePlanBytesCodecTextBytesValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	b, err := value.(BytesValuer).BytesValue()
+	if err != nil {
+		return nil, err
+	}
+	if b == nil {
+		return nil, nil
+	}
+
+	buf = append(buf, `\x`...)
+	buf = append(buf, hex.EncodeToString(b)...)
+	return buf, nil
+}
+
+func (ByteaCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *[]byte:
+			return scanPlanBinaryBytesToBytes{}
+		case BytesScanner:
+			return scanPlanBinaryBytesToBytesScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *[]byte:
+			return scanPlanTextByteaToBytes{}
+		case BytesScanner:
+			return scanPlanTextByteaToBytesScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryBytesToBytes struct{}
+
+func (scanPlanBinaryBytesToBytes) Scan(src []byte, dst any) error {
+	dstBuf := dst.(*[]byte)
+	if src == nil {
+		*dstBuf = nil
+		return nil
+	}
+
+	*dstBuf = make([]byte, len(src))
+	copy(*dstBuf, src)
+	return nil
+}
+
+type scanPlanBinaryBytesToBytesScanner struct{}
+
+func (scanPlanBinaryBytesToBytesScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(BytesScanner)
+	return scanner.ScanBytes(src)
+}
+
+type scanPlanTextByteaToBytes struct{}
+
+func (scanPlanTextByteaToBytes) Scan(src []byte, dst any) error {
+	dstBuf := dst.(*[]byte)
+	if src == nil {
+		*dstBuf = nil
+		return nil
+	}
+
+	buf, err := decodeHexBytea(src)
+	if err != nil {
+		return err
+	}
+	*dstBuf = buf
+
+	return nil
+}
+
+type scanPlanTextByteaToBytesScanner struct{}
+
+func (scanPlanTextByteaToBytesScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(BytesScanner)
+	buf, err := decodeHexBytea(src)
+	if err != nil {
+		return err
+	}
+	return scanner.ScanBytes(buf)
+}
+
+func decodeHexBytea(src []byte) ([]byte, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	if len(src) < 2 || src[0] != '\\' || src[1] != 'x' {
+		return nil, fmt.Errorf("invalid hex format")
+	}
+
+	buf := make([]byte, (len(src)-2)/2)
+	_, err := hex.Decode(buf, src[2:])
+	if err != nil {
+		return nil, err
+	}
+
+	return buf, nil
+}
+
+func (c ByteaCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return c.DecodeValue(m, oid, format, src)
+}
+
+func (c ByteaCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var buf []byte
+	err := codecScan(c, m, oid, format, src, &buf)
+	if err != nil {
+		return nil, err
+	}
+	return buf, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/circle.go b/vendor/github.com/jackc/pgx/v5/pgtype/circle.go
new file mode 100644
index 000000000..ea1d62995
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/circle.go
@@ -0,0 +1,231 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type CircleScanner interface {
+	ScanCircle(v Circle) error
+}
+
+type CircleValuer interface {
+	CircleValue() (Circle, error)
+}
+
+type Circle struct {
+	P     Vec2
+	R     float64
+	Valid bool
+}
+
+// ScanCircle implements the [CircleScanner] interface.
+func (c *Circle) ScanCircle(v Circle) error {
+	*c = v
+	return nil
+}
+
+// CircleValue implements the [CircleValuer] interface.
+func (c Circle) CircleValue() (Circle, error) {
+	return c, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Circle) Scan(src any) error {
+	if src == nil {
+		*dst = Circle{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToCircleScanner{}.Scan([]byte(src), dst)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Circle) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	buf, err := CircleCodec{}.PlanEncode(nil, 0, TextFormatCode, src).Encode(src, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type CircleCodec struct{}
+
+func (CircleCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (CircleCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (CircleCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(CircleValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanCircleCodecBinary{}
+	case TextFormatCode:
+		return encodePlanCircleCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanCircleCodecBinary struct{}
+
+func (encodePlanCircleCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	circle, err := value.(CircleValuer).CircleValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !circle.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendUint64(buf, math.Float64bits(circle.P.X))
+	buf = pgio.AppendUint64(buf, math.Float64bits(circle.P.Y))
+	buf = pgio.AppendUint64(buf, math.Float64bits(circle.R))
+	return buf, nil
+}
+
+type encodePlanCircleCodecText struct{}
+
+func (encodePlanCircleCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	circle, err := value.(CircleValuer).CircleValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !circle.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, fmt.Sprintf(`<(%s,%s),%s>`,
+		strconv.FormatFloat(circle.P.X, 'f', -1, 64),
+		strconv.FormatFloat(circle.P.Y, 'f', -1, 64),
+		strconv.FormatFloat(circle.R, 'f', -1, 64),
+	)...)
+	return buf, nil
+}
+
+func (CircleCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(CircleScanner); ok {
+			return scanPlanBinaryCircleToCircleScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(CircleScanner); ok {
+			return scanPlanTextAnyToCircleScanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c CircleCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c CircleCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var circle Circle
+	err := codecScan(c, m, oid, format, src, &circle)
+	if err != nil {
+		return nil, err
+	}
+	return circle, nil
+}
+
+type scanPlanBinaryCircleToCircleScanner struct{}
+
+func (scanPlanBinaryCircleToCircleScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(CircleScanner)
+
+	if src == nil {
+		return scanner.ScanCircle(Circle{})
+	}
+
+	if len(src) != 24 {
+		return fmt.Errorf("invalid length for Circle: %v", len(src))
+	}
+
+	x := binary.BigEndian.Uint64(src)
+	y := binary.BigEndian.Uint64(src[8:])
+	r := binary.BigEndian.Uint64(src[16:])
+
+	return scanner.ScanCircle(Circle{
+		P:     Vec2{math.Float64frombits(x), math.Float64frombits(y)},
+		R:     math.Float64frombits(r),
+		Valid: true,
+	})
+}
+
+type scanPlanTextAnyToCircleScanner struct{}
+
+func (scanPlanTextAnyToCircleScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(CircleScanner)
+
+	if src == nil {
+		return scanner.ScanCircle(Circle{})
+	}
+
+	if len(src) < 9 {
+		return fmt.Errorf("invalid length for Circle: %v", len(src))
+	}
+
+	// Expected format: <(x,y),r>
+	str, ok := strings.CutPrefix(string(src), "<(")
+	if !ok {
+		return fmt.Errorf("invalid format for Circle")
+	}
+	str, ok = strings.CutSuffix(str, ">")
+	if !ok {
+		return fmt.Errorf("invalid format for Circle")
+	}
+
+	sx, str, found := strings.Cut(str, ",")
+	if !found {
+		return fmt.Errorf("invalid format for Circle")
+	}
+	sy, sr, found := strings.Cut(str, "),")
+	if !found {
+		return fmt.Errorf("invalid format for Circle")
+	}
+
+	x, err := strconv.ParseFloat(sx, 64)
+	if err != nil {
+		return err
+	}
+	y, err := strconv.ParseFloat(sy, 64)
+	if err != nil {
+		return err
+	}
+	r, err := strconv.ParseFloat(sr, 64)
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanCircle(Circle{P: Vec2{x, y}, R: r, Valid: true})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/composite.go b/vendor/github.com/jackc/pgx/v5/pgtype/composite.go
new file mode 100644
index 000000000..7f96ab490
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/composite.go
@@ -0,0 +1,613 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// CompositeIndexGetter is a type accessed by index that can be converted into a PostgreSQL composite.
+type CompositeIndexGetter interface {
+	// IsNull returns true if the value is SQL NULL.
+	IsNull() bool
+
+	// Index returns the element at i.
+	Index(i int) any
+}
+
+// CompositeIndexScanner is a type accessed by index that can be scanned from a PostgreSQL composite.
+type CompositeIndexScanner interface {
+	// ScanNull sets the value to SQL NULL.
+	ScanNull() error
+
+	// ScanIndex returns a value usable as a scan target for i.
+	ScanIndex(i int) any
+}
+
+type CompositeCodecField struct {
+	Name string
+	Type *Type
+}
+
+type CompositeCodec struct {
+	Fields []CompositeCodecField
+}
+
+func (c *CompositeCodec) FormatSupported(format int16) bool {
+	for _, f := range c.Fields {
+		if !f.Type.Codec.FormatSupported(format) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (c *CompositeCodec) PreferredFormat() int16 {
+	if c.FormatSupported(BinaryFormatCode) {
+		return BinaryFormatCode
+	}
+	return TextFormatCode
+}
+
+func (c *CompositeCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(CompositeIndexGetter); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return &encodePlanCompositeCodecCompositeIndexGetterToBinary{cc: c, m: m}
+	case TextFormatCode:
+		return &encodePlanCompositeCodecCompositeIndexGetterToText{cc: c, m: m}
+	}
+
+	return nil
+}
+
+type encodePlanCompositeCodecCompositeIndexGetterToBinary struct {
+	cc *CompositeCodec
+	m  *Map
+}
+
+func (plan *encodePlanCompositeCodecCompositeIndexGetterToBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	getter := value.(CompositeIndexGetter)
+
+	if getter.IsNull() {
+		return nil, nil
+	}
+
+	builder := NewCompositeBinaryBuilder(plan.m, buf)
+	for i, field := range plan.cc.Fields {
+		builder.AppendValue(field.Type.OID, getter.Index(i))
+	}
+
+	return builder.Finish()
+}
+
+type encodePlanCompositeCodecCompositeIndexGetterToText struct {
+	cc *CompositeCodec
+	m  *Map
+}
+
+func (plan *encodePlanCompositeCodecCompositeIndexGetterToText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	getter := value.(CompositeIndexGetter)
+
+	if getter.IsNull() {
+		return nil, nil
+	}
+
+	b := NewCompositeTextBuilder(plan.m, buf)
+	for i, field := range plan.cc.Fields {
+		b.AppendValue(field.Type.OID, getter.Index(i))
+	}
+
+	return b.Finish()
+}
+
+func (c *CompositeCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(CompositeIndexScanner); ok {
+			return &scanPlanBinaryCompositeToCompositeIndexScanner{cc: c, m: m}
+		}
+	case TextFormatCode:
+		if _, ok := target.(CompositeIndexScanner); ok {
+			return &scanPlanTextCompositeToCompositeIndexScanner{cc: c, m: m}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryCompositeToCompositeIndexScanner struct {
+	cc *CompositeCodec
+	m  *Map
+}
+
+func (plan *scanPlanBinaryCompositeToCompositeIndexScanner) Scan(src []byte, target any) error {
+	targetScanner := (target).(CompositeIndexScanner)
+
+	if src == nil {
+		return targetScanner.ScanNull()
+	}
+
+	scanner := NewCompositeBinaryScanner(plan.m, src)
+	for i, field := range plan.cc.Fields {
+		if scanner.Next() {
+			fieldTarget := targetScanner.ScanIndex(i)
+			if fieldTarget != nil {
+				fieldPlan := plan.m.PlanScan(field.Type.OID, BinaryFormatCode, fieldTarget)
+				if fieldPlan == nil {
+					return fmt.Errorf("unable to encode %v into OID %d in binary format", field, field.Type.OID)
+				}
+
+				err := fieldPlan.Scan(scanner.Bytes(), fieldTarget)
+				if err != nil {
+					return err
+				}
+			}
+		} else {
+			return errors.New("read past end of composite")
+		}
+	}
+
+	if err := scanner.Err(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+type scanPlanTextCompositeToCompositeIndexScanner struct {
+	cc *CompositeCodec
+	m  *Map
+}
+
+func (plan *scanPlanTextCompositeToCompositeIndexScanner) Scan(src []byte, target any) error {
+	targetScanner := (target).(CompositeIndexScanner)
+
+	if src == nil {
+		return targetScanner.ScanNull()
+	}
+
+	scanner := NewCompositeTextScanner(plan.m, src)
+	for i, field := range plan.cc.Fields {
+		if scanner.Next() {
+			fieldTarget := targetScanner.ScanIndex(i)
+			if fieldTarget != nil {
+				fieldPlan := plan.m.PlanScan(field.Type.OID, TextFormatCode, fieldTarget)
+				if fieldPlan == nil {
+					return fmt.Errorf("unable to encode %v into OID %d in text format", field, field.Type.OID)
+				}
+
+				err := fieldPlan.Scan(scanner.Bytes(), fieldTarget)
+				if err != nil {
+					return err
+				}
+			}
+		} else {
+			return errors.New("read past end of composite")
+		}
+	}
+
+	if err := scanner.Err(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *CompositeCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case TextFormatCode:
+		return string(src), nil
+	case BinaryFormatCode:
+		buf := make([]byte, len(src))
+		copy(buf, src)
+		return buf, nil
+	default:
+		return nil, fmt.Errorf("unknown format code %d", format)
+	}
+}
+
+func (c *CompositeCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case TextFormatCode:
+		scanner := NewCompositeTextScanner(m, src)
+		values := make(map[string]any, len(c.Fields))
+		for i := 0; scanner.Next() && i < len(c.Fields); i++ {
+			var v any
+			fieldPlan := m.PlanScan(c.Fields[i].Type.OID, TextFormatCode, &v)
+			if fieldPlan == nil {
+				return nil, fmt.Errorf("unable to scan OID %d in text format into %v", c.Fields[i].Type.OID, v)
+			}
+
+			err := fieldPlan.Scan(scanner.Bytes(), &v)
+			if err != nil {
+				return nil, err
+			}
+
+			values[c.Fields[i].Name] = v
+		}
+
+		if err := scanner.Err(); err != nil {
+			return nil, err
+		}
+
+		return values, nil
+	case BinaryFormatCode:
+		scanner := NewCompositeBinaryScanner(m, src)
+		values := make(map[string]any, len(c.Fields))
+		for i := 0; scanner.Next() && i < len(c.Fields); i++ {
+			var v any
+			fieldPlan := m.PlanScan(scanner.OID(), BinaryFormatCode, &v)
+			if fieldPlan == nil {
+				return nil, fmt.Errorf("unable to scan OID %d in binary format into %v", scanner.OID(), v)
+			}
+
+			err := fieldPlan.Scan(scanner.Bytes(), &v)
+			if err != nil {
+				return nil, err
+			}
+
+			values[c.Fields[i].Name] = v
+		}
+
+		if err := scanner.Err(); err != nil {
+			return nil, err
+		}
+
+		return values, nil
+	default:
+		return nil, fmt.Errorf("unknown format code %d", format)
+	}
+}
+
+type CompositeBinaryScanner struct {
+	m   *Map
+	rp  int
+	src []byte
+
+	fieldCount int32
+	fieldBytes []byte
+	fieldOID   uint32
+	err        error
+}
+
+// NewCompositeBinaryScanner a scanner over a binary encoded composite value.
+func NewCompositeBinaryScanner(m *Map, src []byte) *CompositeBinaryScanner {
+	rp := 0
+	if len(src[rp:]) < 4 {
+		return &CompositeBinaryScanner{err: fmt.Errorf("Record incomplete %v", src)}
+	}
+
+	fieldCount := int32(binary.BigEndian.Uint32(src[rp:]))
+	rp += 4
+
+	return &CompositeBinaryScanner{
+		m:          m,
+		rp:         rp,
+		src:        src,
+		fieldCount: fieldCount,
+	}
+}
+
+// Next advances the scanner to the next field. It returns false after the last field is read or an error occurs. After
+// Next returns false, the Err method can be called to check if any errors occurred.
+func (cfs *CompositeBinaryScanner) Next() bool {
+	if cfs.err != nil {
+		return false
+	}
+
+	if cfs.rp == len(cfs.src) {
+		return false
+	}
+
+	if len(cfs.src[cfs.rp:]) < 8 {
+		cfs.err = fmt.Errorf("Record incomplete %v", cfs.src)
+		return false
+	}
+	cfs.fieldOID = binary.BigEndian.Uint32(cfs.src[cfs.rp:])
+	cfs.rp += 4
+
+	fieldLen := int(int32(binary.BigEndian.Uint32(cfs.src[cfs.rp:])))
+	cfs.rp += 4
+
+	if fieldLen >= 0 {
+		if len(cfs.src[cfs.rp:]) < fieldLen {
+			cfs.err = fmt.Errorf("Record incomplete rp=%d src=%v", cfs.rp, cfs.src)
+			return false
+		}
+		cfs.fieldBytes = cfs.src[cfs.rp : cfs.rp+fieldLen]
+		cfs.rp += fieldLen
+	} else {
+		cfs.fieldBytes = nil
+	}
+
+	return true
+}
+
+func (cfs *CompositeBinaryScanner) FieldCount() int {
+	return int(cfs.fieldCount)
+}
+
+// Bytes returns the bytes of the field most recently read by Scan().
+func (cfs *CompositeBinaryScanner) Bytes() []byte {
+	return cfs.fieldBytes
+}
+
+// OID returns the OID of the field most recently read by Scan().
+func (cfs *CompositeBinaryScanner) OID() uint32 {
+	return cfs.fieldOID
+}
+
+// Err returns any error encountered by the scanner.
+func (cfs *CompositeBinaryScanner) Err() error {
+	return cfs.err
+}
+
+type CompositeTextScanner struct {
+	m   *Map
+	rp  int
+	src []byte
+
+	fieldBytes []byte
+	err        error
+}
+
+// NewCompositeTextScanner a scanner over a text encoded composite value.
+func NewCompositeTextScanner(m *Map, src []byte) *CompositeTextScanner {
+	if len(src) < 2 {
+		return &CompositeTextScanner{err: fmt.Errorf("Record incomplete %v", src)}
+	}
+
+	if src[0] != '(' {
+		return &CompositeTextScanner{err: fmt.Errorf("composite text format must start with '('")}
+	}
+
+	if src[len(src)-1] != ')' {
+		return &CompositeTextScanner{err: fmt.Errorf("composite text format must end with ')'")}
+	}
+
+	return &CompositeTextScanner{
+		m:   m,
+		rp:  1,
+		src: src,
+	}
+}
+
+// Next advances the scanner to the next field. It returns false after the last field is read or an error occurs. After
+// Next returns false, the Err method can be called to check if any errors occurred.
+func (cfs *CompositeTextScanner) Next() bool {
+	if cfs.err != nil {
+		return false
+	}
+
+	if cfs.rp == len(cfs.src) {
+		return false
+	}
+
+	switch cfs.src[cfs.rp] {
+	case ',', ')': // null
+		cfs.rp++
+		cfs.fieldBytes = nil
+		return true
+	case '"': // quoted value
+		cfs.rp++
+		cfs.fieldBytes = make([]byte, 0, 16)
+	quotedValue:
+		for {
+			ch := cfs.src[cfs.rp]
+
+			switch ch {
+			case '"':
+				cfs.rp++
+				if cfs.src[cfs.rp] == '"' {
+					cfs.fieldBytes = append(cfs.fieldBytes, '"')
+					cfs.rp++
+				} else {
+					break quotedValue
+				}
+			case '\\':
+				cfs.rp++
+				cfs.fieldBytes = append(cfs.fieldBytes, cfs.src[cfs.rp])
+				cfs.rp++
+			default:
+				cfs.fieldBytes = append(cfs.fieldBytes, ch)
+				cfs.rp++
+			}
+		}
+		cfs.rp++
+		return true
+	default: // unquoted value
+		start := cfs.rp
+		for {
+			ch := cfs.src[cfs.rp]
+			if ch == ',' || ch == ')' {
+				break
+			}
+			cfs.rp++
+		}
+		cfs.fieldBytes = cfs.src[start:cfs.rp]
+		cfs.rp++
+		return true
+	}
+}
+
+// Bytes returns the bytes of the field most recently read by Scan().
+func (cfs *CompositeTextScanner) Bytes() []byte {
+	return cfs.fieldBytes
+}
+
+// Err returns any error encountered by the scanner.
+func (cfs *CompositeTextScanner) Err() error {
+	return cfs.err
+}
+
+type CompositeBinaryBuilder struct {
+	m          *Map
+	buf        []byte
+	startIdx   int
+	fieldCount uint32
+	err        error
+}
+
+func NewCompositeBinaryBuilder(m *Map, buf []byte) *CompositeBinaryBuilder {
+	startIdx := len(buf)
+	buf = append(buf, 0, 0, 0, 0) // allocate room for number of fields
+	return &CompositeBinaryBuilder{m: m, buf: buf, startIdx: startIdx}
+}
+
+func (b *CompositeBinaryBuilder) AppendValue(oid uint32, field any) {
+	if b.err != nil {
+		return
+	}
+
+	isNil, callNilDriverValuer := isNilDriverValuer(field)
+	if isNil && !callNilDriverValuer {
+		b.buf = pgio.AppendUint32(b.buf, oid)
+		b.buf = pgio.AppendInt32(b.buf, -1)
+		b.fieldCount++
+		return
+	}
+
+	var plan EncodePlan
+	if isNil {
+		plan = &encodePlanDriverValuer{m: b.m, oid: oid, formatCode: BinaryFormatCode}
+	} else {
+		plan = b.m.PlanEncode(oid, BinaryFormatCode, field)
+		if plan == nil {
+			b.err = fmt.Errorf("unable to encode %v into OID %d in binary format", field, oid)
+			return
+		}
+	}
+
+	b.buf = pgio.AppendUint32(b.buf, oid)
+	lengthPos := len(b.buf)
+	b.buf = pgio.AppendInt32(b.buf, -1)
+	fieldBuf, err := plan.Encode(field, b.buf)
+	if err != nil {
+		b.err = err
+		return
+	}
+	if fieldBuf != nil {
+		binary.BigEndian.PutUint32(fieldBuf[lengthPos:], uint32(len(fieldBuf)-len(b.buf)))
+		b.buf = fieldBuf
+	}
+
+	b.fieldCount++
+}
+
+func (b *CompositeBinaryBuilder) Finish() ([]byte, error) {
+	if b.err != nil {
+		return nil, b.err
+	}
+
+	binary.BigEndian.PutUint32(b.buf[b.startIdx:], b.fieldCount)
+	return b.buf, nil
+}
+
+type CompositeTextBuilder struct {
+	m          *Map
+	buf        []byte
+	startIdx   int
+	fieldCount uint32
+	err        error
+	fieldBuf   [32]byte
+}
+
+func NewCompositeTextBuilder(m *Map, buf []byte) *CompositeTextBuilder {
+	buf = append(buf, '(') // allocate room for number of fields
+	return &CompositeTextBuilder{m: m, buf: buf}
+}
+
+func (b *CompositeTextBuilder) AppendValue(oid uint32, field any) {
+	if b.err != nil {
+		return
+	}
+
+	isNil, callNilDriverValuer := isNilDriverValuer(field)
+	if isNil && !callNilDriverValuer {
+		b.buf = append(b.buf, ',')
+		return
+	}
+
+	var plan EncodePlan
+	if isNil {
+		plan = &encodePlanDriverValuer{m: b.m, oid: oid, formatCode: TextFormatCode}
+	} else {
+		plan = b.m.PlanEncode(oid, TextFormatCode, field)
+		if plan == nil {
+			b.err = fmt.Errorf("unable to encode %v into OID %d in text format", field, oid)
+			return
+		}
+	}
+
+	fieldBuf, err := plan.Encode(field, b.fieldBuf[0:0])
+	if err != nil {
+		b.err = err
+		return
+	}
+	if fieldBuf != nil {
+		b.buf = append(b.buf, quoteCompositeFieldIfNeeded(string(fieldBuf))...)
+	}
+
+	b.buf = append(b.buf, ',')
+}
+
+func (b *CompositeTextBuilder) Finish() ([]byte, error) {
+	if b.err != nil {
+		return nil, b.err
+	}
+
+	b.buf[len(b.buf)-1] = ')'
+	return b.buf, nil
+}
+
+var quoteCompositeReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
+
+func quoteCompositeField(src string) string {
+	return `"` + quoteCompositeReplacer.Replace(src) + `"`
+}
+
+func quoteCompositeFieldIfNeeded(src string) string {
+	if src == "" || src[0] == ' ' || src[len(src)-1] == ' ' || strings.ContainsAny(src, `(),"\`) {
+		return quoteCompositeField(src)
+	}
+	return src
+}
+
+// CompositeFields represents the values of a composite value. It can be used as an encoding source or as a scan target.
+// It cannot scan a NULL, but the composite fields can be NULL.
+type CompositeFields []any
+
+func (cf CompositeFields) SkipUnderlyingTypePlan() {}
+
+func (cf CompositeFields) IsNull() bool {
+	return cf == nil
+}
+
+func (cf CompositeFields) Index(i int) any {
+	return cf[i]
+}
+
+func (cf CompositeFields) ScanNull() error {
+	return fmt.Errorf("cannot scan NULL into CompositeFields")
+}
+
+func (cf CompositeFields) ScanIndex(i int) any {
+	return cf[i]
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/convert.go b/vendor/github.com/jackc/pgx/v5/pgtype/convert.go
new file mode 100644
index 000000000..669333841
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/convert.go
@@ -0,0 +1,108 @@
+package pgtype
+
+import (
+	"reflect"
+)
+
+func NullAssignTo(dst any) error {
+	dstPtr := reflect.ValueOf(dst)
+
+	// AssignTo dst must always be a pointer
+	if dstPtr.Kind() != reflect.Pointer {
+		return &nullAssignmentError{dst: dst}
+	}
+
+	dstVal := dstPtr.Elem()
+
+	switch dstVal.Kind() {
+	case reflect.Pointer, reflect.Slice, reflect.Map:
+		dstVal.Set(reflect.Zero(dstVal.Type()))
+		return nil
+	}
+
+	return &nullAssignmentError{dst: dst}
+}
+
+var kindTypes map[reflect.Kind]reflect.Type
+
+func toInterface(dst reflect.Value, t reflect.Type) (any, bool) {
+	nextDst := dst.Convert(t)
+	return nextDst.Interface(), dst.Type() != nextDst.Type()
+}
+
+// GetAssignToDstType attempts to convert dst to something AssignTo can assign
+// to. If dst is a pointer to pointer it allocates a value and returns the
+// dereferences pointer. If dst is a named type such as *Foo where Foo is type
+// Foo int16, it converts dst to *int16.
+//
+// GetAssignToDstType returns the converted dst and a bool representing if any
+// change was made.
+func GetAssignToDstType(dst any) (any, bool) {
+	dstPtr := reflect.ValueOf(dst)
+
+	// AssignTo dst must always be a pointer
+	if dstPtr.Kind() != reflect.Pointer {
+		return nil, false
+	}
+
+	dstVal := dstPtr.Elem()
+
+	// if dst is a pointer to pointer, allocate space try again with the dereferenced pointer
+	if dstVal.Kind() == reflect.Pointer {
+		dstVal.Set(reflect.New(dstVal.Type().Elem()))
+		return dstVal.Interface(), true
+	}
+
+	// if dst is pointer to a base type that has been renamed
+	if baseValType, ok := kindTypes[dstVal.Kind()]; ok {
+		return toInterface(dstPtr, reflect.PointerTo(baseValType))
+	}
+
+	if dstVal.Kind() == reflect.Slice {
+		if baseElemType, ok := kindTypes[dstVal.Type().Elem().Kind()]; ok {
+			return toInterface(dstPtr, reflect.PointerTo(reflect.SliceOf(baseElemType)))
+		}
+	}
+
+	if dstVal.Kind() == reflect.Array {
+		if baseElemType, ok := kindTypes[dstVal.Type().Elem().Kind()]; ok {
+			return toInterface(dstPtr, reflect.PointerTo(reflect.ArrayOf(dstVal.Len(), baseElemType)))
+		}
+	}
+
+	if dstVal.Kind() == reflect.Struct {
+		if dstVal.Type().NumField() == 1 && dstVal.Type().Field(0).Anonymous {
+			dstPtr = dstVal.Field(0).Addr()
+			nested := dstVal.Type().Field(0).Type
+			if nested.Kind() == reflect.Array {
+				if baseElemType, ok := kindTypes[nested.Elem().Kind()]; ok {
+					return toInterface(dstPtr, reflect.PointerTo(reflect.ArrayOf(nested.Len(), baseElemType)))
+				}
+			}
+			if _, ok := kindTypes[nested.Kind()]; ok && dstPtr.CanInterface() {
+				return dstPtr.Interface(), true
+			}
+		}
+	}
+
+	return nil, false
+}
+
+func init() {
+	kindTypes = map[reflect.Kind]reflect.Type{
+		reflect.Bool:    reflect.TypeFor[bool](),
+		reflect.Float32: reflect.TypeFor[float32](),
+		reflect.Float64: reflect.TypeFor[float64](),
+		reflect.Int:     reflect.TypeFor[int](),
+		reflect.Int8:    reflect.TypeFor[int8](),
+		reflect.Int16:   reflect.TypeFor[int16](),
+		reflect.Int32:   reflect.TypeFor[int32](),
+		reflect.Int64:   reflect.TypeFor[int64](),
+		reflect.Uint:    reflect.TypeFor[uint](),
+		reflect.Uint8:   reflect.TypeFor[uint8](),
+		reflect.Uint16:  reflect.TypeFor[uint16](),
+		reflect.Uint32:  reflect.TypeFor[uint32](),
+		reflect.Uint64:  reflect.TypeFor[uint64](),
+		reflect.String:  reflect.TypeFor[string](),
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/date.go b/vendor/github.com/jackc/pgx/v5/pgtype/date.go
new file mode 100644
index 000000000..305d83c31
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/date.go
@@ -0,0 +1,412 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"encoding/json"
+	"fmt"
+	"strconv"
+	"time"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type DateScanner interface {
+	ScanDate(v Date) error
+}
+
+type DateValuer interface {
+	DateValue() (Date, error)
+}
+
+type Date struct {
+	Time             time.Time
+	InfinityModifier InfinityModifier
+	Valid            bool
+}
+
+// ScanDate implements the [DateScanner] interface.
+func (d *Date) ScanDate(v Date) error {
+	*d = v
+	return nil
+}
+
+// DateValue implements the [DateValuer] interface.
+func (d Date) DateValue() (Date, error) {
+	return d, nil
+}
+
+const (
+	negativeInfinityDayOffset = -2147483648
+	infinityDayOffset         = 2147483647
+)
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Date) Scan(src any) error {
+	if src == nil {
+		*dst = Date{}
+		return nil
+	}
+
+	switch src := src.(type) {
+	case string:
+		return scanPlanTextAnyToDateScanner{}.Scan([]byte(src), dst)
+	case time.Time:
+		*dst = Date{Time: src, Valid: true}
+		return nil
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Date) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	if src.InfinityModifier != Finite {
+		return src.InfinityModifier.String(), nil
+	}
+	return src.Time, nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Date) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+
+	var s string
+
+	switch src.InfinityModifier {
+	case Finite:
+		s = src.Time.Format("2006-01-02")
+	case Infinity:
+		s = "infinity"
+	case NegativeInfinity:
+		s = "-infinity"
+	}
+
+	return json.Marshal(s)
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Date) UnmarshalJSON(b []byte) error {
+	var s *string
+	err := json.Unmarshal(b, &s)
+	if err != nil {
+		return err
+	}
+
+	if s == nil {
+		*dst = Date{}
+		return nil
+	}
+
+	switch *s {
+	case "infinity":
+		*dst = Date{Valid: true, InfinityModifier: Infinity}
+	case "-infinity":
+		*dst = Date{Valid: true, InfinityModifier: -Infinity}
+	default:
+		t, err := time.ParseInLocation("2006-01-02", *s, time.UTC)
+		if err != nil {
+			return err
+		}
+
+		*dst = Date{Time: t, Valid: true}
+	}
+
+	return nil
+}
+
+type DateCodec struct{}
+
+func (DateCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (DateCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (DateCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(DateValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanDateCodecBinary{}
+	case TextFormatCode:
+		return encodePlanDateCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanDateCodecBinary struct{}
+
+func (encodePlanDateCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	date, err := value.(DateValuer).DateValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !date.Valid {
+		return nil, nil
+	}
+
+	var daysSinceDateEpoch int32
+	switch date.InfinityModifier {
+	case Finite:
+		tUnix := time.Date(date.Time.Year(), date.Time.Month(), date.Time.Day(), 0, 0, 0, 0, time.UTC).Unix()
+		dateEpoch := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).Unix()
+
+		secSinceDateEpoch := tUnix - dateEpoch
+		daysSinceDateEpoch = int32(secSinceDateEpoch / 86400)
+	case Infinity:
+		daysSinceDateEpoch = infinityDayOffset
+	case NegativeInfinity:
+		daysSinceDateEpoch = negativeInfinityDayOffset
+	}
+
+	return pgio.AppendInt32(buf, daysSinceDateEpoch), nil
+}
+
+type encodePlanDateCodecText struct{}
+
+func (encodePlanDateCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	date, err := value.(DateValuer).DateValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !date.Valid {
+		return nil, nil
+	}
+
+	switch date.InfinityModifier {
+	case Finite:
+		// Year 0000 is 1 BC
+		bc := false
+		year := date.Time.Year()
+		if year <= 0 {
+			year = -year + 1
+			bc = true
+		}
+
+		yearBytes := strconv.AppendInt(make([]byte, 0, 6), int64(year), 10)
+		for i := len(yearBytes); i < 4; i++ {
+			buf = append(buf, '0')
+		}
+		buf = append(buf, yearBytes...)
+		buf = append(buf, '-')
+		if date.Time.Month() < 10 {
+			buf = append(buf, '0')
+		}
+		buf = strconv.AppendInt(buf, int64(date.Time.Month()), 10)
+		buf = append(buf, '-')
+		if date.Time.Day() < 10 {
+			buf = append(buf, '0')
+		}
+		buf = strconv.AppendInt(buf, int64(date.Time.Day()), 10)
+
+		if bc {
+			buf = append(buf, " BC"...)
+		}
+	case Infinity:
+		buf = append(buf, "infinity"...)
+	case NegativeInfinity:
+		buf = append(buf, "-infinity"...)
+	}
+
+	return buf, nil
+}
+
+func (DateCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(DateScanner); ok {
+			return scanPlanBinaryDateToDateScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(DateScanner); ok {
+			return scanPlanTextAnyToDateScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryDateToDateScanner struct{}
+
+func (scanPlanBinaryDateToDateScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(DateScanner)
+
+	if src == nil {
+		return scanner.ScanDate(Date{})
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for date: %v", len(src))
+	}
+
+	dayOffset := int32(binary.BigEndian.Uint32(src))
+
+	switch dayOffset {
+	case infinityDayOffset:
+		return scanner.ScanDate(Date{InfinityModifier: Infinity, Valid: true})
+	case negativeInfinityDayOffset:
+		return scanner.ScanDate(Date{InfinityModifier: -Infinity, Valid: true})
+	default:
+		t := time.Date(2000, 1, int(1+dayOffset), 0, 0, 0, 0, time.UTC)
+		return scanner.ScanDate(Date{Time: t, Valid: true})
+	}
+}
+
+type scanPlanTextAnyToDateScanner struct{}
+
+func (scanPlanTextAnyToDateScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(DateScanner)
+
+	if src == nil {
+		return scanner.ScanDate(Date{})
+	}
+
+	// Check infinity cases first
+	if len(src) == 8 && string(src) == "infinity" {
+		return scanner.ScanDate(Date{InfinityModifier: Infinity, Valid: true})
+	}
+	if len(src) == 9 && string(src) == "-infinity" {
+		return scanner.ScanDate(Date{InfinityModifier: -Infinity, Valid: true})
+	}
+
+	// Format: YYYY-MM-DD or YYYY...-MM-DD BC
+	// Minimum: 10 chars (2000-01-01), with BC: 13 chars
+	if len(src) < 10 {
+		return fmt.Errorf("invalid date format")
+	}
+
+	// Check for BC suffix
+	bc := false
+	datePart := src
+	if len(src) >= 13 && string(src[len(src)-3:]) == " BC" {
+		bc = true
+		datePart = src[:len(src)-3]
+	}
+
+	// Find year-month separator (first dash after at least 4 digits)
+	yearEnd := -1
+	for i := 4; i < len(datePart); i++ {
+		if datePart[i] == '-' {
+			yearEnd = i
+			break
+		}
+		if datePart[i] < '0' || datePart[i] > '9' {
+			return fmt.Errorf("invalid date format")
+		}
+	}
+	if yearEnd == -1 || yearEnd+6 > len(datePart) {
+		return fmt.Errorf("invalid date format")
+	}
+
+	// Validate: -MM-DD structure after year
+	if datePart[yearEnd+3] != '-' {
+		return fmt.Errorf("invalid date format")
+	}
+
+	// Parse year
+	year, err := parseDigits(datePart[:yearEnd])
+	if err != nil {
+		return fmt.Errorf("invalid date format")
+	}
+
+	// Parse month (2 digits)
+	month, err := parse2Digits(datePart[yearEnd+1 : yearEnd+3])
+	if err != nil {
+		return fmt.Errorf("invalid date format")
+	}
+
+	// Parse day (2 digits)
+	day, err := parse2Digits(datePart[yearEnd+4 : yearEnd+6])
+	if err != nil {
+		return fmt.Errorf("invalid date format")
+	}
+
+	// Ensure nothing extra after day
+	if yearEnd+6 != len(datePart) {
+		return fmt.Errorf("invalid date format")
+	}
+
+	if bc {
+		year = -year + 1
+	}
+
+	t := time.Date(int(year), time.Month(month), int(day), 0, 0, 0, 0, time.UTC)
+	return scanner.ScanDate(Date{Time: t, Valid: true})
+}
+
+// parse2Digits parses exactly 2 ASCII digits.
+func parse2Digits(b []byte) (int64, error) {
+	if len(b) != 2 {
+		return 0, fmt.Errorf("expected 2 digits")
+	}
+	d1, d2 := b[0], b[1]
+	if d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9' {
+		return 0, fmt.Errorf("expected digits")
+	}
+	return int64(d1-'0')*10 + int64(d2-'0'), nil
+}
+
+// parseDigits parses a sequence of ASCII digits.
+func parseDigits(b []byte) (int64, error) {
+	if len(b) == 0 {
+		return 0, fmt.Errorf("empty")
+	}
+	var n int64
+	for _, c := range b {
+		if c < '0' || c > '9' {
+			return 0, fmt.Errorf("non-digit")
+		}
+		n = n*10 + int64(c-'0')
+	}
+	return n, nil
+}
+
+func (c DateCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var date Date
+	err := codecScan(c, m, oid, format, src, &date)
+	if err != nil {
+		return nil, err
+	}
+
+	if date.InfinityModifier != Finite {
+		return date.InfinityModifier.String(), nil
+	}
+
+	return date.Time, nil
+}
+
+func (c DateCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var date Date
+	err := codecScan(c, m, oid, format, src, &date)
+	if err != nil {
+		return nil, err
+	}
+
+	if date.InfinityModifier != Finite {
+		return date.InfinityModifier, nil
+	}
+
+	return date.Time, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/doc.go b/vendor/github.com/jackc/pgx/v5/pgtype/doc.go
new file mode 100644
index 000000000..dbcdf692f
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/doc.go
@@ -0,0 +1,196 @@
+// Package pgtype converts between Go and PostgreSQL values.
+/*
+The primary type is the [Map] type. It is a map of PostgreSQL types identified by OID (object ID) to a [Codec]. A [Codec] is
+responsible for converting between Go and PostgreSQL values. [NewMap] creates a [Map] with all supported standard PostgreSQL
+types already registered. Additional types can be registered with [Map.RegisterType].
+
+Use [Map.Scan] and [Map.Encode] to decode PostgreSQL values to Go and encode Go values to PostgreSQL respectively.
+
+Base Type Mapping
+
+pgtype maps between all common base types directly between Go and PostgreSQL. In particular:
+
+    Go           PostgreSQL
+    -----------------------
+    string        varchar
+                  text
+
+    // Integers are automatically be converted to any other integer type if
+    // it can be done without overflow or underflow.
+    int8
+    int16         smallint
+    int32         int
+    int64         bigint
+    int
+    uint8
+    uint16
+    uint32
+    uint64
+    uint
+
+    // Floats are strict and do not automatically convert like integers.
+    float32       float4
+    float64       float8
+
+    time.Time     date
+                  timestamp
+                  timestamptz
+
+    netip.Addr    inet
+    netip.Prefix  cidr
+
+    []byte        bytea
+
+Null Values
+
+pgtype can map NULLs in two ways. The first is types that can directly represent NULL such as Int4. They work in a
+similar fashion to database/sql. The second is to use a pointer to a pointer.
+
+    var foo pgtype.Text
+    var bar *string
+    err := conn.QueryRow("select foo, bar from widgets where id=$1", 42).Scan(&foo, &bar)
+    if err != nil {
+        return err
+    }
+
+When using nullable pgtype types as parameters for queries, one has to remember to explicitly set their Valid field to
+true, otherwise the parameter's value will be NULL.
+
+JSON Support
+
+pgtype automatically marshals and unmarshals data from json and jsonb PostgreSQL types.
+
+Extending Existing PostgreSQL Type Support
+
+Generally, all Codecs will support interfaces that can be implemented to enable scanning and encoding. For example,
+[PointCodec] can use any Go type that implements the [PointScanner] and [PointValuer] interfaces. So rather than use
+[Point] an application can directly use its own point type with pgtype as long as it implements those interfaces.
+
+See example_custom_type_test.go for an example of a custom type for the PostgreSQL point type.
+
+Sometimes pgx supports a PostgreSQL type such as numeric but the Go type is in an external package that does not have
+pgx support such as github.com/shopspring/decimal. These types can be registered with pgtype with custom conversion
+logic. See https://github.com/jackc/pgx-shopspring-decimal and https://github.com/jackc/pgx-gofrs-uuid for example
+integrations.
+
+New PostgreSQL Type Support
+
+pgtype uses the PostgreSQL OID to determine how to encode or decode a value. pgtype supports array, composite, domain,
+and enum types. However, any type created in PostgreSQL with CREATE TYPE will receive a new OID. This means that the OID
+of each new PostgreSQL type must be registered for pgtype to handle values of that type with the correct [Codec].
+
+The [github.com/jackc/pgx/v5.Conn.LoadType] method can return a [*Type] for array, composite, domain, and enum types by
+inspecting the database metadata. This [*Type] can then be registered with [Map.RegisterType].
+
+For example, the following function could be called after a connection is established:
+
+    func RegisterDataTypes(ctx context.Context, conn *pgx.Conn) error {
+      dataTypeNames := []string{
+        "foo",
+        "_foo",
+        "bar",
+        "_bar",
+      }
+
+      for _, typeName := range dataTypeNames {
+        dataType, err := conn.LoadType(ctx, typeName)
+        if err != nil {
+          return err
+        }
+        conn.TypeMap().RegisterType(dataType)
+      }
+
+      return nil
+    }
+
+A type cannot be registered unless all types it depends on are already registered. e.g. An array type cannot be
+registered until its element type is registered.
+
+[ArrayCodec] implements support for arrays. If pgtype supports type T then it can easily support []T by registering an
+[ArrayCodec] for the appropriate PostgreSQL OID. In addition, [Array] type can support multi-dimensional arrays.
+
+[CompositeCodec] implements support for PostgreSQL composite types. Go structs can be scanned into if the public fields of
+the struct are in the exact order and type of the PostgreSQL type or by implementing [CompositeIndexScanner] and
+[CompositeIndexGetter].
+
+Domain types are treated as their underlying type if the underlying type and the domain type are registered.
+
+PostgreSQL enums can usually be treated as text. However, [EnumCodec] implements support for interning strings which can
+reduce memory usage.
+
+While pgtype will often still work with unregistered types it is highly recommended that all types be registered due to
+an improvement in performance and the elimination of certain edge cases.
+
+If an entirely new PostgreSQL type (e.g. PostGIS types) is used then the application or a library can create a new
+[Codec]. Then the OID / [Codec] mapping can be registered with [Map.RegisterType]. There is no difference between a [Codec]
+defined and registered by the application and a [Codec] built in to pgtype. See any of the [Codec]s in pgtype for [Codec]
+examples and for examples of type registration.
+
+Encoding Unknown Types
+
+pgtype works best when the OID of the PostgreSQL type is known. But in some cases such as using the simple protocol the
+OID is unknown. In this case [Map.RegisterDefaultPgType] can be used to register an assumed OID for a particular Go type.
+
+Renamed Types
+
+If pgtype does not recognize a type and that type is a renamed simple type simple (e.g. type MyInt32 int32) pgtype acts
+as if it is the underlying type. It currently cannot automatically detect the underlying type of renamed structs (eg.g.
+type MyTime time.Time).
+
+Compatibility with [database/sql]
+
+pgtype also includes support for custom types implementing the [database/sql.Scanner] and [database/sql/driver.Valuer]
+interfaces.
+
+Encoding Typed Nils
+
+pgtype encodes untyped and typed nils (e.g. nil and []byte(nil)) to the SQL NULL value without going through the [Codec]
+system. This means that [Codec]s and other encoding logic do not have to handle nil or *T(nil).
+
+However, [database/sql] compatibility requires Value to be called on T(nil) when T implements [database/sql/driver.Valuer]. Therefore,
+[database/sql/driver.Valuer] values are only considered NULL when *T(nil) where [database/sql/driver.Valuer] is implemented on T not on *T. See
+https://github.com/golang/go/issues/8415 and
+https://github.com/golang/go/commit/0ce1d79a6a771f7449ec493b993ed2a720917870.
+
+Child Records
+
+pgtype's support for arrays and composite records can be used to load records and their children in a single query.  See
+example_child_records_test.go for an example.
+
+Overview of Scanning Implementation
+
+The first step is to use the OID to lookup the correct [Codec]. The [Map] will call the [Codec.PlanScan] method to get a
+plan for scanning into the Go value. A [Codec] will support scanning into one or more Go types. Oftentime these Go types
+are interfaces rather than explicit types. For example, [PointCodec] can use any Go type that implements the [PointScanner]
+and [PointValuer] interfaces.
+
+If a Go value is not supported directly by a [Codec] then [Map] will try see if it is a [database/sql.Scanner]. If is then that
+interface will be used to scan the value. Most [database/sql.Scanner]s require the input to be in the text format (e.g. UUIDs and
+numeric). However, pgx will typically have received the value in the binary format. In this case the binary value will be
+parsed, reencoded as text, and then passed to the [database/sql.Scanner]. This may incur additional overhead for query results with
+a large number of affected values.
+
+If a Go value is not supported directly by a [Codec] then [Map] will try wrapping it with additional logic and try again.
+For example, [Int8Codec] does not support scanning into a renamed type (e.g. type myInt64 int64). But [Map] will detect that
+myInt64 is a renamed type and create a plan that converts the value to the underlying int64 type and then passes that to
+the [Codec] (see [TryFindUnderlyingTypeScanPlan]).
+
+These plan wrappers are contained in [Map.TryWrapScanPlanFuncs]. By default these contain shared logic to handle renamed
+types, pointers to pointers, slices, composite types, etc. Additional plan wrappers can be added to seamlessly integrate
+types that do not support pgx directly. For example, the before mentioned
+https://github.com/jackc/pgx-shopspring-decimal package detects decimal.Decimal values, wraps them in something
+implementing [NumericScanner] and passes that to the [Codec].
+
+[Map.Scan] and [Map.Encode] are convenience methods that wrap [Map.PlanScan] and [Map.PlanEncode].  Determining how to scan or
+encode a particular type may be a time consuming operation. Hence the planning and execution steps of a conversion are
+internally separated.
+
+Reducing Compiled Binary Size
+
+[github.com/jackc/pgx/v5.QueryExecModeExec] and [github.com/jackc/pgx/v5.QueryExecModeSimpleProtocol] require the default
+PostgreSQL type to be registered for each Go type used as a query parameter. By default pgx does this for all supported
+types and their array variants. If an application does not use those query execution modes or manually registers the default
+PostgreSQL type for the types it uses as query parameters it can use the build tag nopgxregisterdefaulttypes. This omits
+the default type registration and reduces the compiled binary size by ~2MB.
+*/
+package pgtype
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/enum_codec.go b/vendor/github.com/jackc/pgx/v5/pgtype/enum_codec.go
new file mode 100644
index 000000000..5e787c1e2
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/enum_codec.go
@@ -0,0 +1,109 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"fmt"
+)
+
+// EnumCodec is a codec that caches the strings it decodes. If the same string is read multiple times only one copy is
+// allocated. These strings are only garbage collected when the EnumCodec is garbage collected. EnumCodec can be used
+// for any text type not only enums, but it should only be used when there are a small number of possible values.
+type EnumCodec struct {
+	membersMap map[string]string // map to quickly lookup member and reuse string instead of allocating
+}
+
+func (EnumCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (EnumCodec) PreferredFormat() int16 {
+	return TextFormatCode
+}
+
+func (EnumCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case TextFormatCode, BinaryFormatCode:
+		switch value.(type) {
+		case string:
+			return encodePlanTextCodecString{}
+		case []byte:
+			return encodePlanTextCodecByteSlice{}
+		case TextValuer:
+			return encodePlanTextCodecTextValuer{}
+		}
+	}
+
+	return nil
+}
+
+func (c *EnumCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case TextFormatCode, BinaryFormatCode:
+		switch target.(type) {
+		case *string:
+			return &scanPlanTextAnyToEnumString{codec: c}
+		case *[]byte:
+			return scanPlanAnyToNewByteSlice{}
+		case TextScanner:
+			return &scanPlanTextAnyToEnumTextScanner{codec: c}
+		}
+	}
+
+	return nil
+}
+
+func (c *EnumCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return c.DecodeValue(m, oid, format, src)
+}
+
+func (c *EnumCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	return c.lookupAndCacheString(src), nil
+}
+
+// lookupAndCacheString looks for src in the members map. If it is not found it is added to the map.
+func (c *EnumCodec) lookupAndCacheString(src []byte) string {
+	if c.membersMap == nil {
+		c.membersMap = make(map[string]string)
+	}
+
+	if s, found := c.membersMap[string(src)]; found {
+		return s
+	}
+
+	s := string(src)
+	c.membersMap[s] = s
+	return s
+}
+
+type scanPlanTextAnyToEnumString struct {
+	codec *EnumCodec
+}
+
+func (plan *scanPlanTextAnyToEnumString) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p := (dst).(*string)
+	*p = plan.codec.lookupAndCacheString(src)
+
+	return nil
+}
+
+type scanPlanTextAnyToEnumTextScanner struct {
+	codec *EnumCodec
+}
+
+func (plan *scanPlanTextAnyToEnumTextScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TextScanner)
+
+	if src == nil {
+		return scanner.ScanText(Text{})
+	}
+
+	return scanner.ScanText(Text{String: plan.codec.lookupAndCacheString(src), Valid: true})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/float4.go b/vendor/github.com/jackc/pgx/v5/pgtype/float4.go
new file mode 100644
index 000000000..a43553f67
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/float4.go
@@ -0,0 +1,323 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"encoding/json"
+	"fmt"
+	"math"
+	"strconv"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Float4 struct {
+	Float32 float32
+	Valid   bool
+}
+
+// ScanFloat64 implements the [Float64Scanner] interface.
+func (f *Float4) ScanFloat64(n Float8) error {
+	*f = Float4{Float32: float32(n.Float64), Valid: n.Valid}
+	return nil
+}
+
+// Float64Value implements the [Float64Valuer] interface.
+func (f Float4) Float64Value() (Float8, error) {
+	return Float8{Float64: float64(f.Float32), Valid: f.Valid}, nil
+}
+
+// ScanInt64 implements the [Int64Scanner] interface.
+func (f *Float4) ScanInt64(n Int8) error {
+	*f = Float4{Float32: float32(n.Int64), Valid: n.Valid}
+	return nil
+}
+
+// Int64Value implements the [Int64Valuer] interface.
+func (f Float4) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(f.Float32), Valid: f.Valid}, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (f *Float4) Scan(src any) error {
+	if src == nil {
+		*f = Float4{}
+		return nil
+	}
+
+	switch src := src.(type) {
+	case float64:
+		*f = Float4{Float32: float32(src), Valid: true}
+		return nil
+	case string:
+		n, err := strconv.ParseFloat(src, 32)
+		if err != nil {
+			return err
+		}
+		*f = Float4{Float32: float32(n), Valid: true}
+		return nil
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (f Float4) Value() (driver.Value, error) {
+	if !f.Valid {
+		return nil, nil
+	}
+	return float64(f.Float32), nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (f Float4) MarshalJSON() ([]byte, error) {
+	if !f.Valid {
+		return []byte("null"), nil
+	}
+	return json.Marshal(f.Float32)
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (f *Float4) UnmarshalJSON(b []byte) error {
+	var n *float32
+	err := json.Unmarshal(b, &n)
+	if err != nil {
+		return err
+	}
+
+	if n == nil {
+		*f = Float4{}
+	} else {
+		*f = Float4{Float32: *n, Valid: true}
+	}
+
+	return nil
+}
+
+type Float4Codec struct{}
+
+func (Float4Codec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (Float4Codec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (Float4Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case float32:
+			return encodePlanFloat4CodecBinaryFloat32{}
+		case Float64Valuer:
+			return encodePlanFloat4CodecBinaryFloat64Valuer{}
+		case Int64Valuer:
+			return encodePlanFloat4CodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case float32:
+			return encodePlanTextFloat32{}
+		case Float64Valuer:
+			return encodePlanTextFloat64Valuer{}
+		case Int64Valuer:
+			return encodePlanTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanFloat4CodecBinaryFloat32 struct{}
+
+func (encodePlanFloat4CodecBinaryFloat32) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(float32)
+	return pgio.AppendUint32(buf, math.Float32bits(n)), nil
+}
+
+type encodePlanTextFloat32 struct{}
+
+func (encodePlanTextFloat32) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(float32)
+	return append(buf, strconv.FormatFloat(float64(n), 'f', -1, 32)...), nil
+}
+
+type encodePlanFloat4CodecBinaryFloat64Valuer struct{}
+
+func (encodePlanFloat4CodecBinaryFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Float64Valuer).Float64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	return pgio.AppendUint32(buf, math.Float32bits(float32(n.Float64))), nil
+}
+
+type encodePlanFloat4CodecBinaryInt64Valuer struct{}
+
+func (encodePlanFloat4CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	f := float32(n.Int64)
+	return pgio.AppendUint32(buf, math.Float32bits(f)), nil
+}
+
+func (Float4Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *float32:
+			return scanPlanBinaryFloat4ToFloat32{}
+		case Float64Scanner:
+			return scanPlanBinaryFloat4ToFloat64Scanner{}
+		case Int64Scanner:
+			return scanPlanBinaryFloat4ToInt64Scanner{}
+		case TextScanner:
+			return scanPlanBinaryFloat4ToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *float32:
+			return scanPlanTextAnyToFloat32{}
+		case Float64Scanner:
+			return scanPlanTextAnyToFloat64Scanner{}
+		case Int64Scanner:
+			return scanPlanTextAnyToInt64Scanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryFloat4ToFloat32 struct{}
+
+func (scanPlanBinaryFloat4ToFloat32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for float4: %v", len(src))
+	}
+
+	n := int32(binary.BigEndian.Uint32(src))
+	f := (dst).(*float32)
+	*f = math.Float32frombits(uint32(n))
+
+	return nil
+}
+
+type scanPlanBinaryFloat4ToFloat64Scanner struct{}
+
+func (scanPlanBinaryFloat4ToFloat64Scanner) Scan(src []byte, dst any) error {
+	s := (dst).(Float64Scanner)
+
+	if src == nil {
+		return s.ScanFloat64(Float8{})
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for float4: %v", len(src))
+	}
+
+	n := int32(binary.BigEndian.Uint32(src))
+	return s.ScanFloat64(Float8{Float64: float64(math.Float32frombits(uint32(n))), Valid: true})
+}
+
+type scanPlanBinaryFloat4ToInt64Scanner struct{}
+
+func (scanPlanBinaryFloat4ToInt64Scanner) Scan(src []byte, dst any) error {
+	s := (dst).(Int64Scanner)
+
+	if src == nil {
+		return s.ScanInt64(Int8{})
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for float4: %v", len(src))
+	}
+
+	ui32 := int32(binary.BigEndian.Uint32(src))
+	f32 := math.Float32frombits(uint32(ui32))
+	i64 := int64(f32)
+	if f32 != float32(i64) {
+		return fmt.Errorf("cannot losslessly convert %v to int64", f32)
+	}
+
+	return s.ScanInt64(Int8{Int64: i64, Valid: true})
+}
+
+type scanPlanBinaryFloat4ToTextScanner struct{}
+
+func (scanPlanBinaryFloat4ToTextScanner) Scan(src []byte, dst any) error {
+	s := (dst).(TextScanner)
+
+	if src == nil {
+		return s.ScanText(Text{})
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for float4: %v", len(src))
+	}
+
+	ui32 := int32(binary.BigEndian.Uint32(src))
+	f32 := math.Float32frombits(uint32(ui32))
+
+	return s.ScanText(Text{String: strconv.FormatFloat(float64(f32), 'f', -1, 32), Valid: true})
+}
+
+type scanPlanTextAnyToFloat32 struct{}
+
+func (scanPlanTextAnyToFloat32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	n, err := strconv.ParseFloat(string(src), 32)
+	if err != nil {
+		return err
+	}
+
+	f := (dst).(*float32)
+	*f = float32(n)
+
+	return nil
+}
+
+func (c Float4Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n float32
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return float64(n), nil
+}
+
+func (c Float4Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n float32
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/float8.go b/vendor/github.com/jackc/pgx/v5/pgtype/float8.go
new file mode 100644
index 000000000..6234231d7
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/float8.go
@@ -0,0 +1,369 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"encoding/json"
+	"fmt"
+	"math"
+	"strconv"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Float64Scanner interface {
+	ScanFloat64(Float8) error
+}
+
+type Float64Valuer interface {
+	Float64Value() (Float8, error)
+}
+
+type Float8 struct {
+	Float64 float64
+	Valid   bool
+}
+
+// ScanFloat64 implements the [Float64Scanner] interface.
+func (f *Float8) ScanFloat64(n Float8) error {
+	*f = n
+	return nil
+}
+
+// Float64Value implements the [Float64Valuer] interface.
+func (f Float8) Float64Value() (Float8, error) {
+	return f, nil
+}
+
+// ScanInt64 implements the [Int64Scanner] interface.
+func (f *Float8) ScanInt64(n Int8) error {
+	*f = Float8{Float64: float64(n.Int64), Valid: n.Valid}
+	return nil
+}
+
+// Int64Value implements the [Int64Valuer] interface.
+func (f Float8) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(f.Float64), Valid: f.Valid}, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (f *Float8) Scan(src any) error {
+	if src == nil {
+		*f = Float8{}
+		return nil
+	}
+
+	switch src := src.(type) {
+	case float64:
+		*f = Float8{Float64: src, Valid: true}
+		return nil
+	case string:
+		n, err := strconv.ParseFloat(src, 64)
+		if err != nil {
+			return err
+		}
+		*f = Float8{Float64: n, Valid: true}
+		return nil
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (f Float8) Value() (driver.Value, error) {
+	if !f.Valid {
+		return nil, nil
+	}
+	return f.Float64, nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (f Float8) MarshalJSON() ([]byte, error) {
+	if !f.Valid {
+		return []byte("null"), nil
+	}
+	return json.Marshal(f.Float64)
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (f *Float8) UnmarshalJSON(b []byte) error {
+	var n *float64
+	err := json.Unmarshal(b, &n)
+	if err != nil {
+		return err
+	}
+
+	if n == nil {
+		*f = Float8{}
+	} else {
+		*f = Float8{Float64: *n, Valid: true}
+	}
+
+	return nil
+}
+
+type Float8Codec struct{}
+
+func (Float8Codec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (Float8Codec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (Float8Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case float64:
+			return encodePlanFloat8CodecBinaryFloat64{}
+		case Float64Valuer:
+			return encodePlanFloat8CodecBinaryFloat64Valuer{}
+		case Int64Valuer:
+			return encodePlanFloat8CodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case float64:
+			return encodePlanTextFloat64{}
+		case Float64Valuer:
+			return encodePlanTextFloat64Valuer{}
+		case Int64Valuer:
+			return encodePlanTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanFloat8CodecBinaryFloat64 struct{}
+
+func (encodePlanFloat8CodecBinaryFloat64) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(float64)
+	return pgio.AppendUint64(buf, math.Float64bits(n)), nil
+}
+
+type encodePlanTextFloat64 struct{}
+
+func (encodePlanTextFloat64) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(float64)
+	return append(buf, strconv.FormatFloat(n, 'f', -1, 64)...), nil
+}
+
+type encodePlanFloat8CodecBinaryFloat64Valuer struct{}
+
+func (encodePlanFloat8CodecBinaryFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Float64Valuer).Float64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	return pgio.AppendUint64(buf, math.Float64bits(n.Float64)), nil
+}
+
+type encodePlanTextFloat64Valuer struct{}
+
+func (encodePlanTextFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Float64Valuer).Float64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	return append(buf, strconv.FormatFloat(n.Float64, 'f', -1, 64)...), nil
+}
+
+type encodePlanFloat8CodecBinaryInt64Valuer struct{}
+
+func (encodePlanFloat8CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	f := float64(n.Int64)
+	return pgio.AppendUint64(buf, math.Float64bits(f)), nil
+}
+
+type encodePlanTextInt64Valuer struct{}
+
+func (encodePlanTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	return append(buf, strconv.FormatInt(n.Int64, 10)...), nil
+}
+
+func (Float8Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *float64:
+			return scanPlanBinaryFloat8ToFloat64{}
+		case Float64Scanner:
+			return scanPlanBinaryFloat8ToFloat64Scanner{}
+		case Int64Scanner:
+			return scanPlanBinaryFloat8ToInt64Scanner{}
+		case TextScanner:
+			return scanPlanBinaryFloat8ToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *float64:
+			return scanPlanTextAnyToFloat64{}
+		case Float64Scanner:
+			return scanPlanTextAnyToFloat64Scanner{}
+		case Int64Scanner:
+			return scanPlanTextAnyToInt64Scanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryFloat8ToFloat64 struct{}
+
+func (scanPlanBinaryFloat8ToFloat64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for float8: %v", len(src))
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	f := (dst).(*float64)
+	*f = math.Float64frombits(uint64(n))
+
+	return nil
+}
+
+type scanPlanBinaryFloat8ToFloat64Scanner struct{}
+
+func (scanPlanBinaryFloat8ToFloat64Scanner) Scan(src []byte, dst any) error {
+	s := (dst).(Float64Scanner)
+
+	if src == nil {
+		return s.ScanFloat64(Float8{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for float8: %v", len(src))
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	return s.ScanFloat64(Float8{Float64: math.Float64frombits(uint64(n)), Valid: true})
+}
+
+type scanPlanBinaryFloat8ToInt64Scanner struct{}
+
+func (scanPlanBinaryFloat8ToInt64Scanner) Scan(src []byte, dst any) error {
+	s := (dst).(Int64Scanner)
+
+	if src == nil {
+		return s.ScanInt64(Int8{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for float8: %v", len(src))
+	}
+
+	ui64 := int64(binary.BigEndian.Uint64(src))
+	f64 := math.Float64frombits(uint64(ui64))
+	i64 := int64(f64)
+	if f64 != float64(i64) {
+		return fmt.Errorf("cannot losslessly convert %v to int64", f64)
+	}
+
+	return s.ScanInt64(Int8{Int64: i64, Valid: true})
+}
+
+type scanPlanBinaryFloat8ToTextScanner struct{}
+
+func (scanPlanBinaryFloat8ToTextScanner) Scan(src []byte, dst any) error {
+	s := (dst).(TextScanner)
+
+	if src == nil {
+		return s.ScanText(Text{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for float8: %v", len(src))
+	}
+
+	ui64 := int64(binary.BigEndian.Uint64(src))
+	f64 := math.Float64frombits(uint64(ui64))
+
+	return s.ScanText(Text{String: strconv.FormatFloat(f64, 'f', -1, 64), Valid: true})
+}
+
+type scanPlanTextAnyToFloat64 struct{}
+
+func (scanPlanTextAnyToFloat64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	n, err := strconv.ParseFloat(string(src), 64)
+	if err != nil {
+		return err
+	}
+
+	f := (dst).(*float64)
+	*f = n
+
+	return nil
+}
+
+type scanPlanTextAnyToFloat64Scanner struct{}
+
+func (scanPlanTextAnyToFloat64Scanner) Scan(src []byte, dst any) error {
+	s := (dst).(Float64Scanner)
+
+	if src == nil {
+		return s.ScanFloat64(Float8{})
+	}
+
+	n, err := strconv.ParseFloat(string(src), 64)
+	if err != nil {
+		return err
+	}
+
+	return s.ScanFloat64(Float8{Float64: n, Valid: true})
+}
+
+func (c Float8Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return c.DecodeValue(m, oid, format, src)
+}
+
+func (c Float8Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n float64
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/hstore.go b/vendor/github.com/jackc/pgx/v5/pgtype/hstore.go
new file mode 100644
index 000000000..4a2bb0a5b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/hstore.go
@@ -0,0 +1,502 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type HstoreScanner interface {
+	ScanHstore(v Hstore) error
+}
+
+type HstoreValuer interface {
+	HstoreValue() (Hstore, error)
+}
+
+// Hstore represents an hstore column that can be null or have null values
+// associated with its keys.
+type Hstore map[string]*string
+
+// ScanHstore implements the [HstoreScanner] interface.
+func (h *Hstore) ScanHstore(v Hstore) error {
+	*h = v
+	return nil
+}
+
+// HstoreValue implements the [HstoreValuer] interface.
+func (h Hstore) HstoreValue() (Hstore, error) {
+	return h, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (h *Hstore) Scan(src any) error {
+	if src == nil {
+		*h = nil
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToHstoreScanner{}.scanString(src, h)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (h Hstore) Value() (driver.Value, error) {
+	if h == nil {
+		return nil, nil
+	}
+
+	buf, err := HstoreCodec{}.PlanEncode(nil, 0, TextFormatCode, h).Encode(h, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type HstoreCodec struct{}
+
+func (HstoreCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (HstoreCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (HstoreCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(HstoreValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanHstoreCodecBinary{}
+	case TextFormatCode:
+		return encodePlanHstoreCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanHstoreCodecBinary struct{}
+
+func (encodePlanHstoreCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	hstore, err := value.(HstoreValuer).HstoreValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if hstore == nil {
+		return nil, nil
+	}
+
+	buf = pgio.AppendInt32(buf, int32(len(hstore)))
+
+	for k, v := range hstore {
+		buf = pgio.AppendInt32(buf, int32(len(k)))
+		buf = append(buf, k...)
+
+		if v == nil {
+			buf = pgio.AppendInt32(buf, -1)
+		} else {
+			buf = pgio.AppendInt32(buf, int32(len(*v)))
+			buf = append(buf, (*v)...)
+		}
+	}
+
+	return buf, nil
+}
+
+type encodePlanHstoreCodecText struct{}
+
+func (encodePlanHstoreCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	hstore, err := value.(HstoreValuer).HstoreValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if len(hstore) == 0 {
+		// distinguish between empty and nil: Not strictly required by Postgres, since its protocol
+		// explicitly marks NULL column values separately. However, the Binary codec does this, and
+		// this means we can "round trip" Encode and Scan without data loss.
+		// nil: []byte(nil); empty: []byte{}
+		if hstore == nil {
+			return nil, nil
+		}
+		return []byte{}, nil
+	}
+
+	firstPair := true
+
+	for k, v := range hstore {
+		if firstPair {
+			firstPair = false
+		} else {
+			buf = append(buf, ',', ' ')
+		}
+
+		// unconditionally quote hstore keys/values like Postgres does
+		// this avoids a Mac OS X Postgres hstore parsing bug:
+		// https://www.postgresql.org/message-id/CA%2BHWA9awUW0%2BRV_gO9r1ABZwGoZxPztcJxPy8vMFSTbTfi4jig%40mail.gmail.com
+		buf = append(buf, '"')
+		buf = append(buf, quoteArrayReplacer.Replace(k)...)
+		buf = append(buf, '"')
+		buf = append(buf, "=>"...)
+
+		if v == nil {
+			buf = append(buf, "NULL"...)
+		} else {
+			buf = append(buf, '"')
+			buf = append(buf, quoteArrayReplacer.Replace(*v)...)
+			buf = append(buf, '"')
+		}
+	}
+
+	return buf, nil
+}
+
+func (HstoreCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(HstoreScanner); ok {
+			return scanPlanBinaryHstoreToHstoreScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(HstoreScanner); ok {
+			return scanPlanTextAnyToHstoreScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryHstoreToHstoreScanner struct{}
+
+func (scanPlanBinaryHstoreToHstoreScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(HstoreScanner)
+
+	if src == nil {
+		return scanner.ScanHstore(Hstore(nil))
+	}
+
+	rp := 0
+
+	const uint32Len = 4
+	if len(src[rp:]) < uint32Len {
+		return fmt.Errorf("hstore incomplete %v", src)
+	}
+	pairCount := int(int32(binary.BigEndian.Uint32(src[rp:])))
+	rp += uint32Len
+
+	if pairCount < 0 {
+		return fmt.Errorf("hstore invalid pair count: %d", pairCount)
+	}
+	// Each pair carries at minimum two int32 length headers (key, value), so pairCount cannot
+	// exceed the remaining bytes / 8. This bounds the up-front make() against a malicious server
+	// claiming a huge pair count in a small message.
+	if maxPairs := len(src[rp:]) / (2 * uint32Len); pairCount > maxPairs {
+		return fmt.Errorf("hstore invalid pair count %d for %d remaining bytes", pairCount, len(src[rp:]))
+	}
+
+	hstore := make(Hstore, pairCount)
+	// one allocation for all *string, rather than one per string, just like text parsing
+	valueStrings := make([]string, pairCount)
+
+	for i := range pairCount {
+		if len(src[rp:]) < uint32Len {
+			return fmt.Errorf("hstore incomplete %v", src)
+		}
+		keyLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
+		rp += uint32Len
+
+		if keyLen < 0 {
+			return fmt.Errorf("hstore invalid key length: %d", keyLen)
+		}
+		if len(src[rp:]) < keyLen {
+			return fmt.Errorf("hstore incomplete %v", src)
+		}
+		key := string(src[rp : rp+keyLen])
+		rp += keyLen
+
+		if len(src[rp:]) < uint32Len {
+			return fmt.Errorf("hstore incomplete %v", src)
+		}
+		valueLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
+		rp += 4
+
+		if valueLen >= 0 {
+			if len(src[rp:]) < valueLen {
+				return fmt.Errorf("hstore incomplete %v", src)
+			}
+			valueStrings[i] = string(src[rp : rp+valueLen])
+			rp += valueLen
+
+			hstore[key] = &valueStrings[i]
+		} else {
+			hstore[key] = nil
+		}
+	}
+
+	return scanner.ScanHstore(hstore)
+}
+
+type scanPlanTextAnyToHstoreScanner struct{}
+
+func (s scanPlanTextAnyToHstoreScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(HstoreScanner)
+
+	if src == nil {
+		return scanner.ScanHstore(Hstore(nil))
+	}
+	return s.scanString(string(src), scanner)
+}
+
+// scanString does not return nil hstore values because string cannot be nil.
+func (scanPlanTextAnyToHstoreScanner) scanString(src string, scanner HstoreScanner) error {
+	hstore, err := parseHstore(src)
+	if err != nil {
+		return err
+	}
+	return scanner.ScanHstore(hstore)
+}
+
+func (c HstoreCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c HstoreCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var hstore Hstore
+	err := codecScan(c, m, oid, format, src, &hstore)
+	if err != nil {
+		return nil, err
+	}
+	return hstore, nil
+}
+
+type hstoreParser struct {
+	str           string
+	pos           int
+	nextBackslash int
+}
+
+func newHSP(in string) *hstoreParser {
+	return &hstoreParser{
+		pos:           0,
+		str:           in,
+		nextBackslash: strings.IndexByte(in, '\\'),
+	}
+}
+
+func (p *hstoreParser) atEnd() bool {
+	return p.pos >= len(p.str)
+}
+
+// consume returns the next byte of the string, or end if the string is done.
+func (p *hstoreParser) consume() (b byte, end bool) {
+	if p.pos >= len(p.str) {
+		return 0, true
+	}
+	b = p.str[p.pos]
+	p.pos++
+	return b, false
+}
+
+func unexpectedByteErr(actualB, expectedB byte) error {
+	return fmt.Errorf("expected '%c' ('%#v'); found '%c' ('%#v')", expectedB, expectedB, actualB, actualB)
+}
+
+// consumeExpectedByte consumes expectedB from the string, or returns an error.
+func (p *hstoreParser) consumeExpectedByte(expectedB byte) error {
+	nextB, end := p.consume()
+	if end {
+		return fmt.Errorf("expected '%c' ('%#v'); found end", expectedB, expectedB)
+	}
+	if nextB != expectedB {
+		return unexpectedByteErr(nextB, expectedB)
+	}
+	return nil
+}
+
+// consumeExpected2 consumes two expected bytes or returns an error.
+// This was a bit faster than using a string argument (better inlining? Not sure).
+func (p *hstoreParser) consumeExpected2(one, two byte) error {
+	if p.pos+2 > len(p.str) {
+		return errors.New("unexpected end of string")
+	}
+	if p.str[p.pos] != one {
+		return unexpectedByteErr(p.str[p.pos], one)
+	}
+	if p.str[p.pos+1] != two {
+		return unexpectedByteErr(p.str[p.pos+1], two)
+	}
+	p.pos += 2
+	return nil
+}
+
+var errEOSInQuoted = errors.New(`found end before closing double-quote ('"')`)
+
+// consumeDoubleQuoted consumes a double-quoted string from p. The double quote must have been
+// parsed already. This copies the string from the backing string so it can be garbage collected.
+func (p *hstoreParser) consumeDoubleQuoted() (string, error) {
+	// fast path: assume most keys/values do not contain escapes
+	nextDoubleQuote := strings.IndexByte(p.str[p.pos:], '"')
+	if nextDoubleQuote == -1 {
+		return "", errEOSInQuoted
+	}
+	nextDoubleQuote += p.pos
+	if p.nextBackslash == -1 || p.nextBackslash > nextDoubleQuote {
+		// clone the string from the source string to ensure it can be garbage collected separately
+		// TODO: use strings.Clone on Go 1.20; this could get optimized away
+		s := strings.Clone(p.str[p.pos:nextDoubleQuote])
+		p.pos = nextDoubleQuote + 1
+		return s, nil
+	}
+
+	// slow path: string contains escapes
+	s, err := p.consumeDoubleQuotedWithEscapes(p.nextBackslash)
+	p.nextBackslash = strings.IndexByte(p.str[p.pos:], '\\')
+	if p.nextBackslash != -1 {
+		p.nextBackslash += p.pos
+	}
+	return s, err
+}
+
+// consumeDoubleQuotedWithEscapes consumes a double-quoted string containing escapes, starting
+// at p.pos, and with the first backslash at firstBackslash. This copies the string so it can be
+// garbage collected separately.
+func (p *hstoreParser) consumeDoubleQuotedWithEscapes(firstBackslash int) (string, error) {
+	// copy the prefix that does not contain backslashes
+	var builder strings.Builder
+	builder.WriteString(p.str[p.pos:firstBackslash])
+
+	// skip to the backslash
+	p.pos = firstBackslash
+
+	// copy bytes until the end, unescaping backslashes
+quotedString:
+	for {
+		nextB, end := p.consume()
+		switch {
+		case end:
+			return "", errEOSInQuoted
+		case nextB == '"':
+			break quotedString
+		case nextB == '\\':
+			// escape: skip the backslash and copy the char
+			nextB, end = p.consume()
+			if end {
+				return "", errEOSInQuoted
+			}
+			if !(nextB == '\\' || nextB == '"') {
+				return "", fmt.Errorf("unexpected escape in quoted string: found '%#v'", nextB)
+			}
+			builder.WriteByte(nextB)
+		default:
+			// normal byte: copy it
+			builder.WriteByte(nextB)
+		}
+	}
+	return builder.String(), nil
+}
+
+// consumePairSeparator consumes the Hstore pair separator ", " or returns an error.
+func (p *hstoreParser) consumePairSeparator() error {
+	return p.consumeExpected2(',', ' ')
+}
+
+// consumeKVSeparator consumes the Hstore key/value separator "=>" or returns an error.
+func (p *hstoreParser) consumeKVSeparator() error {
+	return p.consumeExpected2('=', '>')
+}
+
+// consumeDoubleQuotedOrNull consumes the Hstore key/value separator "=>" or returns an error.
+func (p *hstoreParser) consumeDoubleQuotedOrNull() (Text, error) {
+	// peek at the next byte
+	if p.atEnd() {
+		return Text{}, errors.New("found end instead of value")
+	}
+	next := p.str[p.pos]
+	if next == 'N' {
+		// must be the exact string NULL: use consumeExpected2 twice
+		err := p.consumeExpected2('N', 'U')
+		if err != nil {
+			return Text{}, err
+		}
+		err = p.consumeExpected2('L', 'L')
+		if err != nil {
+			return Text{}, err
+		}
+		return Text{String: "", Valid: false}, nil
+	} else if next != '"' {
+		return Text{}, unexpectedByteErr(next, '"')
+	}
+
+	// skip the double quote
+	p.pos += 1
+	s, err := p.consumeDoubleQuoted()
+	if err != nil {
+		return Text{}, err
+	}
+	return Text{String: s, Valid: true}, nil
+}
+
+func parseHstore(s string) (Hstore, error) {
+	p := newHSP(s)
+
+	// This is an over-estimate of the number of key/value pairs. Use '>' because I am guessing it
+	// is less likely to occur in keys/values than '=' or ','.
+	numPairsEstimate := strings.Count(s, ">")
+	// makes one allocation of strings for the entire Hstore, rather than one allocation per value.
+	valueStrings := make([]string, 0, numPairsEstimate)
+	result := make(Hstore, numPairsEstimate)
+	first := true
+	for !p.atEnd() {
+		if !first {
+			err := p.consumePairSeparator()
+			if err != nil {
+				return nil, err
+			}
+		} else {
+			first = false
+		}
+
+		err := p.consumeExpectedByte('"')
+		if err != nil {
+			return nil, err
+		}
+
+		key, err := p.consumeDoubleQuoted()
+		if err != nil {
+			return nil, err
+		}
+
+		err = p.consumeKVSeparator()
+		if err != nil {
+			return nil, err
+		}
+
+		value, err := p.consumeDoubleQuotedOrNull()
+		if err != nil {
+			return nil, err
+		}
+		if value.Valid {
+			valueStrings = append(valueStrings, value.String)
+			result[key] = &valueStrings[len(valueStrings)-1]
+		} else {
+			result[key] = nil
+		}
+	}
+
+	return result, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/inet.go b/vendor/github.com/jackc/pgx/v5/pgtype/inet.go
new file mode 100644
index 000000000..2592a5b5b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/inet.go
@@ -0,0 +1,197 @@
+package pgtype
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"errors"
+	"fmt"
+	"net/netip"
+)
+
+// Network address family is dependent on server socket.h value for AF_INET.
+// In practice, all platforms appear to have the same value. See
+// src/include/utils/inet.h for more information.
+const (
+	defaultAFInet  = 2
+	defaultAFInet6 = 3
+)
+
+type NetipPrefixScanner interface {
+	ScanNetipPrefix(v netip.Prefix) error
+}
+
+type NetipPrefixValuer interface {
+	NetipPrefixValue() (netip.Prefix, error)
+}
+
+// InetCodec handles both inet and cidr PostgreSQL types. The preferred Go types are [netip.Prefix] and [netip.Addr]. If
+// IsValid() is false then they are treated as SQL NULL.
+type InetCodec struct{}
+
+func (InetCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (InetCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (InetCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(NetipPrefixValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanInetCodecBinary{}
+	case TextFormatCode:
+		return encodePlanInetCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanInetCodecBinary struct{}
+
+func (encodePlanInetCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	prefix, err := value.(NetipPrefixValuer).NetipPrefixValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !prefix.IsValid() {
+		return nil, nil
+	}
+
+	var family byte
+	if prefix.Addr().Is4() {
+		family = defaultAFInet
+	} else {
+		family = defaultAFInet6
+	}
+
+	buf = append(buf, family)
+
+	ones := prefix.Bits()
+	buf = append(buf, byte(ones))
+
+	// is_cidr is ignored on server
+	buf = append(buf, 0)
+
+	if family == defaultAFInet {
+		buf = append(buf, byte(4))
+		b := prefix.Addr().As4()
+		buf = append(buf, b[:]...)
+	} else {
+		buf = append(buf, byte(16))
+		b := prefix.Addr().As16()
+		buf = append(buf, b[:]...)
+	}
+
+	return buf, nil
+}
+
+type encodePlanInetCodecText struct{}
+
+func (encodePlanInetCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	prefix, err := value.(NetipPrefixValuer).NetipPrefixValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !prefix.IsValid() {
+		return nil, nil
+	}
+
+	return append(buf, prefix.String()...), nil
+}
+
+func (InetCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(NetipPrefixScanner); ok {
+			return scanPlanBinaryInetToNetipPrefixScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(NetipPrefixScanner); ok {
+			return scanPlanTextAnyToNetipPrefixScanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c InetCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c InetCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var prefix netip.Prefix
+	err := codecScan(c, m, oid, format, src, (*netipPrefixWrapper)(&prefix))
+	if err != nil {
+		return nil, err
+	}
+
+	if !prefix.IsValid() {
+		return nil, nil
+	}
+
+	return prefix, nil
+}
+
+type scanPlanBinaryInetToNetipPrefixScanner struct{}
+
+func (scanPlanBinaryInetToNetipPrefixScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(NetipPrefixScanner)
+
+	if src == nil {
+		return scanner.ScanNetipPrefix(netip.Prefix{})
+	}
+
+	if len(src) != 8 && len(src) != 20 {
+		return fmt.Errorf("Received an invalid size for an inet: %d", len(src))
+	}
+
+	// ignore family
+	bits := src[1]
+	// ignore is_cidr
+	// ignore addressLength - implicit in length of message
+
+	addr, ok := netip.AddrFromSlice(src[4:])
+	if !ok {
+		return errors.New("netip.AddrFromSlice failed")
+	}
+
+	return scanner.ScanNetipPrefix(netip.PrefixFrom(addr, int(bits)))
+}
+
+type scanPlanTextAnyToNetipPrefixScanner struct{}
+
+func (scanPlanTextAnyToNetipPrefixScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(NetipPrefixScanner)
+
+	if src == nil {
+		return scanner.ScanNetipPrefix(netip.Prefix{})
+	}
+
+	var prefix netip.Prefix
+	if bytes.IndexByte(src, '/') == -1 {
+		addr, err := netip.ParseAddr(string(src))
+		if err != nil {
+			return err
+		}
+		prefix = netip.PrefixFrom(addr, addr.BitLen())
+	} else {
+		var err error
+		prefix, err = netip.ParsePrefix(string(src))
+		if err != nil {
+			return err
+		}
+	}
+
+	return scanner.ScanNetipPrefix(prefix)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/int.go b/vendor/github.com/jackc/pgx/v5/pgtype/int.go
new file mode 100644
index 000000000..95032e5a2
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/int.go
@@ -0,0 +1,1990 @@
+// Code generated from pgtype/int.go.erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"encoding/json"
+	"fmt"
+	"math"
+	"strconv"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Int64Scanner interface {
+	ScanInt64(Int8) error
+}
+
+type Int64Valuer interface {
+	Int64Value() (Int8, error)
+}
+
+type Int2 struct {
+	Int16 int16
+	Valid bool
+}
+
+// ScanInt64 implements the [Int64Scanner] interface.
+func (dst *Int2) ScanInt64(n Int8) error {
+	if !n.Valid {
+		*dst = Int2{}
+		return nil
+	}
+
+	if n.Int64 < math.MinInt16 {
+		return fmt.Errorf("%d is less than minimum value for Int2", n.Int64)
+	}
+	if n.Int64 > math.MaxInt16 {
+		return fmt.Errorf("%d is greater than maximum value for Int2", n.Int64)
+	}
+	*dst = Int2{Int16: int16(n.Int64), Valid: true}
+
+	return nil
+}
+
+// Int64Value implements the [Int64Valuer] interface.
+func (n Int2) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(n.Int16), Valid: n.Valid}, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Int2) Scan(src any) error {
+	if src == nil {
+		*dst = Int2{}
+		return nil
+	}
+
+	var n int64
+
+	switch src := src.(type) {
+	case int64:
+		n = src
+	case string:
+		var err error
+		n, err = strconv.ParseInt(src, 10, 16)
+		if err != nil {
+			return err
+		}
+	case []byte:
+		var err error
+		n, err = strconv.ParseInt(string(src), 10, 16)
+		if err != nil {
+			return err
+		}
+	default:
+		return fmt.Errorf("cannot scan %T", src)
+	}
+
+	if n < math.MinInt16 {
+		return fmt.Errorf("%d is less than minimum value for Int2", n)
+	}
+	if n > math.MaxInt16 {
+		return fmt.Errorf("%d is greater than maximum value for Int2", n)
+	}
+	*dst = Int2{Int16: int16(n), Valid: true}
+
+	return nil
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Int2) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+	return int64(src.Int16), nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Int2) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+	return []byte(strconv.FormatInt(int64(src.Int16), 10)), nil
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Int2) UnmarshalJSON(b []byte) error {
+	var n *int16
+	err := json.Unmarshal(b, &n)
+	if err != nil {
+		return err
+	}
+
+	if n == nil {
+		*dst = Int2{}
+	} else {
+		*dst = Int2{Int16: *n, Valid: true}
+	}
+
+	return nil
+}
+
+type Int2Codec struct{}
+
+func (Int2Codec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (Int2Codec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (Int2Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case int16:
+			return encodePlanInt2CodecBinaryInt16{}
+		case Int64Valuer:
+			return encodePlanInt2CodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case int16:
+			return encodePlanInt2CodecTextInt16{}
+		case Int64Valuer:
+			return encodePlanInt2CodecTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanInt2CodecBinaryInt16 struct{}
+
+func (encodePlanInt2CodecBinaryInt16) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(int16)
+	return pgio.AppendInt16(buf, int16(n)), nil
+}
+
+type encodePlanInt2CodecTextInt16 struct{}
+
+func (encodePlanInt2CodecTextInt16) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(int16)
+	return append(buf, strconv.FormatInt(int64(n), 10)...), nil
+}
+
+type encodePlanInt2CodecBinaryInt64Valuer struct{}
+
+func (encodePlanInt2CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	if n.Int64 > math.MaxInt16 {
+		return nil, fmt.Errorf("%d is greater than maximum value for int2", n.Int64)
+	}
+	if n.Int64 < math.MinInt16 {
+		return nil, fmt.Errorf("%d is less than minimum value for int2", n.Int64)
+	}
+
+	return pgio.AppendInt16(buf, int16(n.Int64)), nil
+}
+
+type encodePlanInt2CodecTextInt64Valuer struct{}
+
+func (encodePlanInt2CodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	if n.Int64 > math.MaxInt16 {
+		return nil, fmt.Errorf("%d is greater than maximum value for int2", n.Int64)
+	}
+	if n.Int64 < math.MinInt16 {
+		return nil, fmt.Errorf("%d is less than minimum value for int2", n.Int64)
+	}
+
+	return append(buf, strconv.FormatInt(n.Int64, 10)...), nil
+}
+
+func (Int2Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *int8:
+			return scanPlanBinaryInt2ToInt8{}
+		case *int16:
+			return scanPlanBinaryInt2ToInt16{}
+		case *int32:
+			return scanPlanBinaryInt2ToInt32{}
+		case *int64:
+			return scanPlanBinaryInt2ToInt64{}
+		case *int:
+			return scanPlanBinaryInt2ToInt{}
+		case *uint8:
+			return scanPlanBinaryInt2ToUint8{}
+		case *uint16:
+			return scanPlanBinaryInt2ToUint16{}
+		case *uint32:
+			return scanPlanBinaryInt2ToUint32{}
+		case *uint64:
+			return scanPlanBinaryInt2ToUint64{}
+		case *uint:
+			return scanPlanBinaryInt2ToUint{}
+		case Int64Scanner:
+			return scanPlanBinaryInt2ToInt64Scanner{}
+		case TextScanner:
+			return scanPlanBinaryInt2ToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *int8:
+			return scanPlanTextAnyToInt8{}
+		case *int16:
+			return scanPlanTextAnyToInt16{}
+		case *int32:
+			return scanPlanTextAnyToInt32{}
+		case *int64:
+			return scanPlanTextAnyToInt64{}
+		case *int:
+			return scanPlanTextAnyToInt{}
+		case *uint8:
+			return scanPlanTextAnyToUint8{}
+		case *uint16:
+			return scanPlanTextAnyToUint16{}
+		case *uint32:
+			return scanPlanTextAnyToUint32{}
+		case *uint64:
+			return scanPlanTextAnyToUint64{}
+		case *uint:
+			return scanPlanTextAnyToUint{}
+		case Int64Scanner:
+			return scanPlanTextAnyToInt64Scanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c Int2Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n int64
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+func (c Int2Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n int16
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+type scanPlanBinaryInt2ToInt8 struct{}
+
+func (scanPlanBinaryInt2ToInt8) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for int2: %v", len(src))
+	}
+
+	p, ok := (dst).(*int8)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int16(binary.BigEndian.Uint16(src))
+	if n < math.MinInt8 {
+		return fmt.Errorf("%d is less than minimum value for int8", n)
+	} else if n > math.MaxInt8 {
+		return fmt.Errorf("%d is greater than maximum value for int8", n)
+	}
+
+	*p = int8(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToUint8 struct{}
+
+func (scanPlanBinaryInt2ToUint8) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for uint2: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint8)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int16(binary.BigEndian.Uint16(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint8", n)
+	}
+
+	if n > math.MaxUint8 {
+		return fmt.Errorf("%d is greater than maximum value for uint8", n)
+	}
+
+	*p = uint8(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToInt16 struct{}
+
+func (scanPlanBinaryInt2ToInt16) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for int2: %v", len(src))
+	}
+
+	p, ok := (dst).(*int16)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = int16(binary.BigEndian.Uint16(src))
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToUint16 struct{}
+
+func (scanPlanBinaryInt2ToUint16) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for uint2: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint16)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int16(binary.BigEndian.Uint16(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint16", n)
+	}
+
+	*p = uint16(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToInt32 struct{}
+
+func (scanPlanBinaryInt2ToInt32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for int2: %v", len(src))
+	}
+
+	p, ok := (dst).(*int32)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = int32(int16(binary.BigEndian.Uint16(src)))
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToUint32 struct{}
+
+func (scanPlanBinaryInt2ToUint32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for uint2: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint32)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int16(binary.BigEndian.Uint16(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint32", n)
+	}
+
+	*p = uint32(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToInt64 struct{}
+
+func (scanPlanBinaryInt2ToInt64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for int2: %v", len(src))
+	}
+
+	p, ok := (dst).(*int64)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = int64(int16(binary.BigEndian.Uint16(src)))
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToUint64 struct{}
+
+func (scanPlanBinaryInt2ToUint64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for uint2: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint64)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int16(binary.BigEndian.Uint16(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint64", n)
+	}
+
+	*p = uint64(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToInt struct{}
+
+func (scanPlanBinaryInt2ToInt) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for int2: %v", len(src))
+	}
+
+	p, ok := (dst).(*int)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = int(int16(binary.BigEndian.Uint16(src)))
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToUint struct{}
+
+func (scanPlanBinaryInt2ToUint) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for uint2: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(int16(binary.BigEndian.Uint16(src)))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint", n)
+	}
+
+	*p = uint(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt2ToInt64Scanner struct{}
+
+func (scanPlanBinaryInt2ToInt64Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Int64Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanInt64(Int8{})
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for int2: %v", len(src))
+	}
+
+	n := int64(int16(binary.BigEndian.Uint16(src)))
+
+	return s.ScanInt64(Int8{Int64: n, Valid: true})
+}
+
+type scanPlanBinaryInt2ToTextScanner struct{}
+
+func (scanPlanBinaryInt2ToTextScanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(TextScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanText(Text{})
+	}
+
+	if len(src) != 2 {
+		return fmt.Errorf("invalid length for int2: %v", len(src))
+	}
+
+	n := int64(int16(binary.BigEndian.Uint16(src)))
+
+	return s.ScanText(Text{String: strconv.FormatInt(n, 10), Valid: true})
+}
+
+type Int4 struct {
+	Int32 int32
+	Valid bool
+}
+
+// ScanInt64 implements the [Int64Scanner] interface.
+func (dst *Int4) ScanInt64(n Int8) error {
+	if !n.Valid {
+		*dst = Int4{}
+		return nil
+	}
+
+	if n.Int64 < math.MinInt32 {
+		return fmt.Errorf("%d is less than minimum value for Int4", n.Int64)
+	}
+	if n.Int64 > math.MaxInt32 {
+		return fmt.Errorf("%d is greater than maximum value for Int4", n.Int64)
+	}
+	*dst = Int4{Int32: int32(n.Int64), Valid: true}
+
+	return nil
+}
+
+// Int64Value implements the [Int64Valuer] interface.
+func (n Int4) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(n.Int32), Valid: n.Valid}, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Int4) Scan(src any) error {
+	if src == nil {
+		*dst = Int4{}
+		return nil
+	}
+
+	var n int64
+
+	switch src := src.(type) {
+	case int64:
+		n = src
+	case string:
+		var err error
+		n, err = strconv.ParseInt(src, 10, 32)
+		if err != nil {
+			return err
+		}
+	case []byte:
+		var err error
+		n, err = strconv.ParseInt(string(src), 10, 32)
+		if err != nil {
+			return err
+		}
+	default:
+		return fmt.Errorf("cannot scan %T", src)
+	}
+
+	if n < math.MinInt32 {
+		return fmt.Errorf("%d is less than minimum value for Int4", n)
+	}
+	if n > math.MaxInt32 {
+		return fmt.Errorf("%d is greater than maximum value for Int4", n)
+	}
+	*dst = Int4{Int32: int32(n), Valid: true}
+
+	return nil
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Int4) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+	return int64(src.Int32), nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Int4) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+	return []byte(strconv.FormatInt(int64(src.Int32), 10)), nil
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Int4) UnmarshalJSON(b []byte) error {
+	var n *int32
+	err := json.Unmarshal(b, &n)
+	if err != nil {
+		return err
+	}
+
+	if n == nil {
+		*dst = Int4{}
+	} else {
+		*dst = Int4{Int32: *n, Valid: true}
+	}
+
+	return nil
+}
+
+type Int4Codec struct{}
+
+func (Int4Codec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (Int4Codec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (Int4Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case int32:
+			return encodePlanInt4CodecBinaryInt32{}
+		case Int64Valuer:
+			return encodePlanInt4CodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case int32:
+			return encodePlanInt4CodecTextInt32{}
+		case Int64Valuer:
+			return encodePlanInt4CodecTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanInt4CodecBinaryInt32 struct{}
+
+func (encodePlanInt4CodecBinaryInt32) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(int32)
+	return pgio.AppendInt32(buf, int32(n)), nil
+}
+
+type encodePlanInt4CodecTextInt32 struct{}
+
+func (encodePlanInt4CodecTextInt32) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(int32)
+	return append(buf, strconv.FormatInt(int64(n), 10)...), nil
+}
+
+type encodePlanInt4CodecBinaryInt64Valuer struct{}
+
+func (encodePlanInt4CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	if n.Int64 > math.MaxInt32 {
+		return nil, fmt.Errorf("%d is greater than maximum value for int4", n.Int64)
+	}
+	if n.Int64 < math.MinInt32 {
+		return nil, fmt.Errorf("%d is less than minimum value for int4", n.Int64)
+	}
+
+	return pgio.AppendInt32(buf, int32(n.Int64)), nil
+}
+
+type encodePlanInt4CodecTextInt64Valuer struct{}
+
+func (encodePlanInt4CodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	if n.Int64 > math.MaxInt32 {
+		return nil, fmt.Errorf("%d is greater than maximum value for int4", n.Int64)
+	}
+	if n.Int64 < math.MinInt32 {
+		return nil, fmt.Errorf("%d is less than minimum value for int4", n.Int64)
+	}
+
+	return append(buf, strconv.FormatInt(n.Int64, 10)...), nil
+}
+
+func (Int4Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *int8:
+			return scanPlanBinaryInt4ToInt8{}
+		case *int16:
+			return scanPlanBinaryInt4ToInt16{}
+		case *int32:
+			return scanPlanBinaryInt4ToInt32{}
+		case *int64:
+			return scanPlanBinaryInt4ToInt64{}
+		case *int:
+			return scanPlanBinaryInt4ToInt{}
+		case *uint8:
+			return scanPlanBinaryInt4ToUint8{}
+		case *uint16:
+			return scanPlanBinaryInt4ToUint16{}
+		case *uint32:
+			return scanPlanBinaryInt4ToUint32{}
+		case *uint64:
+			return scanPlanBinaryInt4ToUint64{}
+		case *uint:
+			return scanPlanBinaryInt4ToUint{}
+		case Int64Scanner:
+			return scanPlanBinaryInt4ToInt64Scanner{}
+		case TextScanner:
+			return scanPlanBinaryInt4ToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *int8:
+			return scanPlanTextAnyToInt8{}
+		case *int16:
+			return scanPlanTextAnyToInt16{}
+		case *int32:
+			return scanPlanTextAnyToInt32{}
+		case *int64:
+			return scanPlanTextAnyToInt64{}
+		case *int:
+			return scanPlanTextAnyToInt{}
+		case *uint8:
+			return scanPlanTextAnyToUint8{}
+		case *uint16:
+			return scanPlanTextAnyToUint16{}
+		case *uint32:
+			return scanPlanTextAnyToUint32{}
+		case *uint64:
+			return scanPlanTextAnyToUint64{}
+		case *uint:
+			return scanPlanTextAnyToUint{}
+		case Int64Scanner:
+			return scanPlanTextAnyToInt64Scanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c Int4Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n int64
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+func (c Int4Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n int32
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+type scanPlanBinaryInt4ToInt8 struct{}
+
+func (scanPlanBinaryInt4ToInt8) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for int4: %v", len(src))
+	}
+
+	p, ok := (dst).(*int8)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int32(binary.BigEndian.Uint32(src))
+	if n < math.MinInt8 {
+		return fmt.Errorf("%d is less than minimum value for int8", n)
+	} else if n > math.MaxInt8 {
+		return fmt.Errorf("%d is greater than maximum value for int8", n)
+	}
+
+	*p = int8(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToUint8 struct{}
+
+func (scanPlanBinaryInt4ToUint8) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for uint4: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint8)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int32(binary.BigEndian.Uint32(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint8", n)
+	}
+
+	if n > math.MaxUint8 {
+		return fmt.Errorf("%d is greater than maximum value for uint8", n)
+	}
+
+	*p = uint8(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToInt16 struct{}
+
+func (scanPlanBinaryInt4ToInt16) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for int4: %v", len(src))
+	}
+
+	p, ok := (dst).(*int16)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int32(binary.BigEndian.Uint32(src))
+	if n < math.MinInt16 {
+		return fmt.Errorf("%d is less than minimum value for int16", n)
+	} else if n > math.MaxInt16 {
+		return fmt.Errorf("%d is greater than maximum value for int16", n)
+	}
+
+	*p = int16(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToUint16 struct{}
+
+func (scanPlanBinaryInt4ToUint16) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for uint4: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint16)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int32(binary.BigEndian.Uint32(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint16", n)
+	}
+
+	if n > math.MaxUint16 {
+		return fmt.Errorf("%d is greater than maximum value for uint16", n)
+	}
+
+	*p = uint16(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToInt32 struct{}
+
+func (scanPlanBinaryInt4ToInt32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for int4: %v", len(src))
+	}
+
+	p, ok := (dst).(*int32)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = int32(binary.BigEndian.Uint32(src))
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToUint32 struct{}
+
+func (scanPlanBinaryInt4ToUint32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for uint4: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint32)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int32(binary.BigEndian.Uint32(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint32", n)
+	}
+
+	*p = uint32(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToInt64 struct{}
+
+func (scanPlanBinaryInt4ToInt64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for int4: %v", len(src))
+	}
+
+	p, ok := (dst).(*int64)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = int64(int32(binary.BigEndian.Uint32(src)))
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToUint64 struct{}
+
+func (scanPlanBinaryInt4ToUint64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for uint4: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint64)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int32(binary.BigEndian.Uint32(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint64", n)
+	}
+
+	*p = uint64(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToInt struct{}
+
+func (scanPlanBinaryInt4ToInt) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for int4: %v", len(src))
+	}
+
+	p, ok := (dst).(*int)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = int(int32(binary.BigEndian.Uint32(src)))
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToUint struct{}
+
+func (scanPlanBinaryInt4ToUint) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for uint4: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(int32(binary.BigEndian.Uint32(src)))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint", n)
+	}
+
+	*p = uint(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt4ToInt64Scanner struct{}
+
+func (scanPlanBinaryInt4ToInt64Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Int64Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanInt64(Int8{})
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for int4: %v", len(src))
+	}
+
+	n := int64(int32(binary.BigEndian.Uint32(src)))
+
+	return s.ScanInt64(Int8{Int64: n, Valid: true})
+}
+
+type scanPlanBinaryInt4ToTextScanner struct{}
+
+func (scanPlanBinaryInt4ToTextScanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(TextScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanText(Text{})
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for int4: %v", len(src))
+	}
+
+	n := int64(int32(binary.BigEndian.Uint32(src)))
+
+	return s.ScanText(Text{String: strconv.FormatInt(n, 10), Valid: true})
+}
+
+type Int8 struct {
+	Int64 int64
+	Valid bool
+}
+
+// ScanInt64 implements the [Int64Scanner] interface.
+func (dst *Int8) ScanInt64(n Int8) error {
+	if !n.Valid {
+		*dst = Int8{}
+		return nil
+	}
+
+	if n.Int64 < math.MinInt64 {
+		return fmt.Errorf("%d is less than minimum value for Int8", n.Int64)
+	}
+	if n.Int64 > math.MaxInt64 {
+		return fmt.Errorf("%d is greater than maximum value for Int8", n.Int64)
+	}
+	*dst = Int8{Int64: int64(n.Int64), Valid: true}
+
+	return nil
+}
+
+// Int64Value implements the [Int64Valuer] interface.
+func (n Int8) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(n.Int64), Valid: n.Valid}, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Int8) Scan(src any) error {
+	if src == nil {
+		*dst = Int8{}
+		return nil
+	}
+
+	var n int64
+
+	switch src := src.(type) {
+	case int64:
+		n = src
+	case string:
+		var err error
+		n, err = strconv.ParseInt(src, 10, 64)
+		if err != nil {
+			return err
+		}
+	case []byte:
+		var err error
+		n, err = strconv.ParseInt(string(src), 10, 64)
+		if err != nil {
+			return err
+		}
+	default:
+		return fmt.Errorf("cannot scan %T", src)
+	}
+
+	if n < math.MinInt64 {
+		return fmt.Errorf("%d is greater than maximum value for Int8", n)
+	}
+	if n > math.MaxInt64 {
+		return fmt.Errorf("%d is greater than maximum value for Int8", n)
+	}
+	*dst = Int8{Int64: int64(n), Valid: true}
+
+	return nil
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Int8) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+	return int64(src.Int64), nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Int8) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+	return []byte(strconv.FormatInt(int64(src.Int64), 10)), nil
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Int8) UnmarshalJSON(b []byte) error {
+	var n *int64
+	err := json.Unmarshal(b, &n)
+	if err != nil {
+		return err
+	}
+
+	if n == nil {
+		*dst = Int8{}
+	} else {
+		*dst = Int8{Int64: *n, Valid: true}
+	}
+
+	return nil
+}
+
+type Int8Codec struct{}
+
+func (Int8Codec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (Int8Codec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (Int8Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case int64:
+			return encodePlanInt8CodecBinaryInt64{}
+		case Int64Valuer:
+			return encodePlanInt8CodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case int64:
+			return encodePlanInt8CodecTextInt64{}
+		case Int64Valuer:
+			return encodePlanInt8CodecTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanInt8CodecBinaryInt64 struct{}
+
+func (encodePlanInt8CodecBinaryInt64) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(int64)
+	return pgio.AppendInt64(buf, int64(n)), nil
+}
+
+type encodePlanInt8CodecTextInt64 struct{}
+
+func (encodePlanInt8CodecTextInt64) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n := value.(int64)
+	return append(buf, strconv.FormatInt(int64(n), 10)...), nil
+}
+
+type encodePlanInt8CodecBinaryInt64Valuer struct{}
+
+func (encodePlanInt8CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	if n.Int64 > math.MaxInt64 {
+		return nil, fmt.Errorf("%d is greater than maximum value for int8", n.Int64)
+	}
+	if n.Int64 < math.MinInt64 {
+		return nil, fmt.Errorf("%d is less than minimum value for int8", n.Int64)
+	}
+
+	return pgio.AppendInt64(buf, int64(n.Int64)), nil
+}
+
+type encodePlanInt8CodecTextInt64Valuer struct{}
+
+func (encodePlanInt8CodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	if n.Int64 > math.MaxInt64 {
+		return nil, fmt.Errorf("%d is greater than maximum value for int8", n.Int64)
+	}
+	if n.Int64 < math.MinInt64 {
+		return nil, fmt.Errorf("%d is less than minimum value for int8", n.Int64)
+	}
+
+	return append(buf, strconv.FormatInt(n.Int64, 10)...), nil
+}
+
+func (Int8Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *int8:
+			return scanPlanBinaryInt8ToInt8{}
+		case *int16:
+			return scanPlanBinaryInt8ToInt16{}
+		case *int32:
+			return scanPlanBinaryInt8ToInt32{}
+		case *int64:
+			return scanPlanBinaryInt8ToInt64{}
+		case *int:
+			return scanPlanBinaryInt8ToInt{}
+		case *uint8:
+			return scanPlanBinaryInt8ToUint8{}
+		case *uint16:
+			return scanPlanBinaryInt8ToUint16{}
+		case *uint32:
+			return scanPlanBinaryInt8ToUint32{}
+		case *uint64:
+			return scanPlanBinaryInt8ToUint64{}
+		case *uint:
+			return scanPlanBinaryInt8ToUint{}
+		case Int64Scanner:
+			return scanPlanBinaryInt8ToInt64Scanner{}
+		case TextScanner:
+			return scanPlanBinaryInt8ToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *int8:
+			return scanPlanTextAnyToInt8{}
+		case *int16:
+			return scanPlanTextAnyToInt16{}
+		case *int32:
+			return scanPlanTextAnyToInt32{}
+		case *int64:
+			return scanPlanTextAnyToInt64{}
+		case *int:
+			return scanPlanTextAnyToInt{}
+		case *uint8:
+			return scanPlanTextAnyToUint8{}
+		case *uint16:
+			return scanPlanTextAnyToUint16{}
+		case *uint32:
+			return scanPlanTextAnyToUint32{}
+		case *uint64:
+			return scanPlanTextAnyToUint64{}
+		case *uint:
+			return scanPlanTextAnyToUint{}
+		case Int64Scanner:
+			return scanPlanTextAnyToInt64Scanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c Int8Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n int64
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+func (c Int8Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n int64
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+type scanPlanBinaryInt8ToInt8 struct{}
+
+func (scanPlanBinaryInt8ToInt8) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for int8: %v", len(src))
+	}
+
+	p, ok := (dst).(*int8)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	if n < math.MinInt8 {
+		return fmt.Errorf("%d is less than minimum value for int8", n)
+	} else if n > math.MaxInt8 {
+		return fmt.Errorf("%d is greater than maximum value for int8", n)
+	}
+
+	*p = int8(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToUint8 struct{}
+
+func (scanPlanBinaryInt8ToUint8) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for uint8: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint8)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint8", n)
+	}
+
+	if n > math.MaxUint8 {
+		return fmt.Errorf("%d is greater than maximum value for uint8", n)
+	}
+
+	*p = uint8(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToInt16 struct{}
+
+func (scanPlanBinaryInt8ToInt16) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for int8: %v", len(src))
+	}
+
+	p, ok := (dst).(*int16)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	if n < math.MinInt16 {
+		return fmt.Errorf("%d is less than minimum value for int16", n)
+	} else if n > math.MaxInt16 {
+		return fmt.Errorf("%d is greater than maximum value for int16", n)
+	}
+
+	*p = int16(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToUint16 struct{}
+
+func (scanPlanBinaryInt8ToUint16) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for uint8: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint16)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint16", n)
+	}
+
+	if n > math.MaxUint16 {
+		return fmt.Errorf("%d is greater than maximum value for uint16", n)
+	}
+
+	*p = uint16(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToInt32 struct{}
+
+func (scanPlanBinaryInt8ToInt32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for int8: %v", len(src))
+	}
+
+	p, ok := (dst).(*int32)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	if n < math.MinInt32 {
+		return fmt.Errorf("%d is less than minimum value for int32", n)
+	} else if n > math.MaxInt32 {
+		return fmt.Errorf("%d is greater than maximum value for int32", n)
+	}
+
+	*p = int32(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToUint32 struct{}
+
+func (scanPlanBinaryInt8ToUint32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for uint8: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint32)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint32", n)
+	}
+
+	if n > math.MaxUint32 {
+		return fmt.Errorf("%d is greater than maximum value for uint32", n)
+	}
+
+	*p = uint32(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToInt64 struct{}
+
+func (scanPlanBinaryInt8ToInt64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for int8: %v", len(src))
+	}
+
+	p, ok := (dst).(*int64)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	*p = int64(binary.BigEndian.Uint64(src))
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToUint64 struct{}
+
+func (scanPlanBinaryInt8ToUint64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for uint8: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint64)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint64", n)
+	}
+
+	*p = uint64(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToInt struct{}
+
+func (scanPlanBinaryInt8ToInt) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for int8: %v", len(src))
+	}
+
+	p, ok := (dst).(*int)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(binary.BigEndian.Uint64(src))
+	if n < math.MinInt {
+		return fmt.Errorf("%d is less than minimum value for int", n)
+	} else if n > math.MaxInt {
+		return fmt.Errorf("%d is greater than maximum value for int", n)
+	}
+
+	*p = int(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToUint struct{}
+
+func (scanPlanBinaryInt8ToUint) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for uint8: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(int64(binary.BigEndian.Uint64(src)))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint", n)
+	}
+
+	if uint64(n) > math.MaxUint {
+		return fmt.Errorf("%d is greater than maximum value for uint", n)
+	}
+
+	*p = uint(n)
+
+	return nil
+}
+
+type scanPlanBinaryInt8ToInt64Scanner struct{}
+
+func (scanPlanBinaryInt8ToInt64Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Int64Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanInt64(Int8{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for int8: %v", len(src))
+	}
+
+	n := int64(int64(binary.BigEndian.Uint64(src)))
+
+	return s.ScanInt64(Int8{Int64: n, Valid: true})
+}
+
+type scanPlanBinaryInt8ToTextScanner struct{}
+
+func (scanPlanBinaryInt8ToTextScanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(TextScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanText(Text{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for int8: %v", len(src))
+	}
+
+	n := int64(int64(binary.BigEndian.Uint64(src)))
+
+	return s.ScanText(Text{String: strconv.FormatInt(n, 10), Valid: true})
+}
+
+type scanPlanTextAnyToInt8 struct{}
+
+func (scanPlanTextAnyToInt8) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*int8)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseInt(string(src), 10, 8)
+	if err != nil {
+		return err
+	}
+
+	*p = int8(n)
+	return nil
+}
+
+type scanPlanTextAnyToUint8 struct{}
+
+func (scanPlanTextAnyToUint8) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*uint8)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseUint(string(src), 10, 8)
+	if err != nil {
+		return err
+	}
+
+	*p = uint8(n)
+	return nil
+}
+
+type scanPlanTextAnyToInt16 struct{}
+
+func (scanPlanTextAnyToInt16) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*int16)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseInt(string(src), 10, 16)
+	if err != nil {
+		return err
+	}
+
+	*p = int16(n)
+	return nil
+}
+
+type scanPlanTextAnyToUint16 struct{}
+
+func (scanPlanTextAnyToUint16) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*uint16)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseUint(string(src), 10, 16)
+	if err != nil {
+		return err
+	}
+
+	*p = uint16(n)
+	return nil
+}
+
+type scanPlanTextAnyToInt32 struct{}
+
+func (scanPlanTextAnyToInt32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*int32)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseInt(string(src), 10, 32)
+	if err != nil {
+		return err
+	}
+
+	*p = int32(n)
+	return nil
+}
+
+type scanPlanTextAnyToUint32 struct{}
+
+func (scanPlanTextAnyToUint32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*uint32)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseUint(string(src), 10, 32)
+	if err != nil {
+		return err
+	}
+
+	*p = uint32(n)
+	return nil
+}
+
+type scanPlanTextAnyToInt64 struct{}
+
+func (scanPlanTextAnyToInt64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*int64)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseInt(string(src), 10, 64)
+	if err != nil {
+		return err
+	}
+
+	*p = int64(n)
+	return nil
+}
+
+type scanPlanTextAnyToUint64 struct{}
+
+func (scanPlanTextAnyToUint64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*uint64)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseUint(string(src), 10, 64)
+	if err != nil {
+		return err
+	}
+
+	*p = uint64(n)
+	return nil
+}
+
+type scanPlanTextAnyToInt struct{}
+
+func (scanPlanTextAnyToInt) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*int)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseInt(string(src), 10, 0)
+	if err != nil {
+		return err
+	}
+
+	*p = int(n)
+	return nil
+}
+
+type scanPlanTextAnyToUint struct{}
+
+func (scanPlanTextAnyToUint) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*uint)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseUint(string(src), 10, 0)
+	if err != nil {
+		return err
+	}
+
+	*p = uint(n)
+	return nil
+}
+
+type scanPlanTextAnyToInt64Scanner struct{}
+
+func (scanPlanTextAnyToInt64Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Int64Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanInt64(Int8{})
+	}
+
+	n, err := strconv.ParseInt(string(src), 10, 64)
+	if err != nil {
+		return err
+	}
+
+	err = s.ScanInt64(Int8{Int64: n, Valid: true})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/int.go.erb b/vendor/github.com/jackc/pgx/v5/pgtype/int.go.erb
new file mode 100644
index 000000000..c2d40f60b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/int.go.erb
@@ -0,0 +1,551 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"encoding/json"
+	"fmt"
+	"math"
+	"strconv"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Int64Scanner interface {
+	ScanInt64(Int8) error
+}
+
+type Int64Valuer interface {
+	Int64Value() (Int8, error)
+}
+
+
+<% [2, 4, 8].each do |pg_byte_size| %>
+<% pg_bit_size = pg_byte_size * 8 %>
+type Int<%= pg_byte_size %> struct {
+	Int<%= pg_bit_size %>   int<%= pg_bit_size %>
+	Valid bool
+}
+
+// ScanInt64 implements the [Int64Scanner] interface.
+func (dst *Int<%= pg_byte_size %>) ScanInt64(n Int8) error {
+	if !n.Valid {
+		*dst = Int<%= pg_byte_size %>{}
+		return nil
+	}
+
+	if n.Int64 < math.MinInt<%= pg_bit_size %> {
+		return fmt.Errorf("%d is less than minimum value for Int<%= pg_byte_size %>", n.Int64)
+	}
+	if n.Int64 > math.MaxInt<%= pg_bit_size %> {
+		return fmt.Errorf("%d is greater than maximum value for Int<%= pg_byte_size %>", n.Int64)
+	}
+	*dst = Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: int<%= pg_bit_size %>(n.Int64), Valid: true}
+
+	return nil
+}
+
+// Int64Value implements the [Int64Valuer] interface.
+func (n Int<%= pg_byte_size %>) Int64Value() (Int8, error) {
+	return Int8{Int64: int64(n.Int<%= pg_bit_size %>), Valid: n.Valid}, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Int<%= pg_byte_size %>) Scan(src any) error {
+	if src == nil {
+		*dst = Int<%= pg_byte_size %>{}
+		return nil
+	}
+
+	var n int64
+
+	switch src := src.(type) {
+	case int64:
+		n = src
+	case string:
+		var err error
+		n, err = strconv.ParseInt(src, 10, <%= pg_bit_size %>)
+		if err != nil {
+			return err
+		}
+	case []byte:
+		var err error
+		n, err = strconv.ParseInt(string(src), 10, <%= pg_bit_size %>)
+		if err != nil {
+			return err
+		}
+	default:
+		return fmt.Errorf("cannot scan %T", src)
+	}
+
+	if n < math.MinInt<%= pg_bit_size %> {
+		return fmt.Errorf("%d is greater than maximum value for Int<%= pg_byte_size %>", n)
+	}
+	if n > math.MaxInt<%= pg_bit_size %> {
+		return fmt.Errorf("%d is greater than maximum value for Int<%= pg_byte_size %>", n)
+	}
+	*dst = Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: int<%= pg_bit_size %>(n), Valid: true}
+
+	return nil
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Int<%= pg_byte_size %>) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+	return int64(src.Int<%= pg_bit_size %>), nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Int<%= pg_byte_size %>) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+	return []byte(strconv.FormatInt(int64(src.Int<%= pg_bit_size %>), 10)), nil
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Int<%= pg_byte_size %>) UnmarshalJSON(b []byte) error {
+	var n *int<%= pg_bit_size %>
+	err := json.Unmarshal(b, &n)
+	if err != nil {
+		return err
+	}
+
+	if n == nil {
+		*dst = Int<%= pg_byte_size %>{}
+	} else {
+		*dst = Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: *n, Valid: true}
+	}
+
+	return nil
+}
+
+type Int<%= pg_byte_size %>Codec struct{}
+
+func (Int<%= pg_byte_size %>Codec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (Int<%= pg_byte_size %>Codec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (Int<%= pg_byte_size %>Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case int<%= pg_bit_size %>:
+			return encodePlanInt<%= pg_byte_size %>CodecBinaryInt<%= pg_bit_size %>{}
+		case Int64Valuer:
+			return encodePlanInt<%= pg_byte_size %>CodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case int<%= pg_bit_size %>:
+			return encodePlanInt<%= pg_byte_size %>CodecTextInt<%= pg_bit_size %>{}
+		case Int64Valuer:
+			return encodePlanInt<%= pg_byte_size %>CodecTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanInt<%= pg_byte_size %>CodecBinaryInt<%= pg_bit_size %> struct{}
+
+func (encodePlanInt<%= pg_byte_size %>CodecBinaryInt<%= pg_bit_size %>) Encode(value any, buf []byte) (newBuf []byte, err error) {
+  n := value.(int<%= pg_bit_size %>)
+  return pgio.AppendInt<%= pg_bit_size %>(buf, int<%= pg_bit_size %>(n)), nil
+}
+
+type encodePlanInt<%= pg_byte_size %>CodecTextInt<%= pg_bit_size %> struct{}
+
+func (encodePlanInt<%= pg_byte_size %>CodecTextInt<%= pg_bit_size %>) Encode(value any, buf []byte) (newBuf []byte, err error) {
+  n := value.(int<%= pg_bit_size %>)
+  return append(buf, strconv.FormatInt(int64(n), 10)...), nil
+}
+
+type encodePlanInt<%= pg_byte_size %>CodecBinaryInt64Valuer struct{}
+
+func (encodePlanInt<%= pg_byte_size %>CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+  n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	if n.Int64 > math.MaxInt<%= pg_bit_size %> {
+		return nil, fmt.Errorf("%d is greater than maximum value for int<%= pg_byte_size %>", n.Int64)
+	}
+	if n.Int64 < math.MinInt<%= pg_bit_size %> {
+		return nil, fmt.Errorf("%d is less than minimum value for int<%= pg_byte_size %>", n.Int64)
+	}
+
+  return pgio.AppendInt<%= pg_bit_size %>(buf, int<%= pg_bit_size %>(n.Int64)), nil
+}
+
+type encodePlanInt<%= pg_byte_size %>CodecTextInt64Valuer struct{}
+
+func (encodePlanInt<%= pg_byte_size %>CodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+  n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	if n.Int64 > math.MaxInt<%= pg_bit_size %> {
+		return nil, fmt.Errorf("%d is greater than maximum value for int<%= pg_byte_size %>", n.Int64)
+	}
+	if n.Int64 < math.MinInt<%= pg_bit_size %> {
+		return nil, fmt.Errorf("%d is less than minimum value for int<%= pg_byte_size %>", n.Int64)
+	}
+
+  return append(buf, strconv.FormatInt(n.Int64, 10)...), nil
+}
+
+func (Int<%= pg_byte_size %>Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *int8:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToInt8{}
+		case *int16:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToInt16{}
+		case *int32:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToInt32{}
+		case *int64:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToInt64{}
+		case *int:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToInt{}
+		case *uint8:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToUint8{}
+		case *uint16:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToUint16{}
+		case *uint32:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToUint32{}
+		case *uint64:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToUint64{}
+		case *uint:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToUint{}
+		case Int64Scanner:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToInt64Scanner{}
+		case TextScanner:
+			return scanPlanBinaryInt<%= pg_byte_size %>ToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *int8:
+			return scanPlanTextAnyToInt8{}
+		case *int16:
+			return scanPlanTextAnyToInt16{}
+		case *int32:
+			return scanPlanTextAnyToInt32{}
+		case *int64:
+			return scanPlanTextAnyToInt64{}
+		case *int:
+			return scanPlanTextAnyToInt{}
+		case *uint8:
+			return scanPlanTextAnyToUint8{}
+		case *uint16:
+			return scanPlanTextAnyToUint16{}
+		case *uint32:
+			return scanPlanTextAnyToUint32{}
+		case *uint64:
+			return scanPlanTextAnyToUint64{}
+		case *uint:
+			return scanPlanTextAnyToUint{}
+		case Int64Scanner:
+			return scanPlanTextAnyToInt64Scanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c Int<%= pg_byte_size %>Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n int64
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+func (c Int<%= pg_byte_size %>Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n int<%= pg_bit_size %>
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+<%# PostgreSQL binary format integer to fixed size Go integers %>
+<% [8, 16, 32, 64].each do |dst_bit_size| %>
+type scanPlanBinaryInt<%= pg_byte_size %>ToInt<%= dst_bit_size %> struct{}
+
+func (scanPlanBinaryInt<%= pg_byte_size %>ToInt<%= dst_bit_size %>) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != <%= pg_byte_size %> {
+		return fmt.Errorf("invalid length for int<%= pg_byte_size %>: %v", len(src))
+	}
+
+	p, ok := (dst).(*int<%= dst_bit_size %>)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+  <% if dst_bit_size < pg_bit_size %>
+	n := int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src))
+	if n < math.MinInt<%= dst_bit_size %> {
+		return fmt.Errorf("%d is less than minimum value for int<%= dst_bit_size %>", n)
+	} else if n > math.MaxInt<%= dst_bit_size %> {
+		return fmt.Errorf("%d is greater than maximum value for int<%= dst_bit_size %>", n)
+	}
+
+	*p = int<%= dst_bit_size %>(n)
+  <% elsif dst_bit_size == pg_bit_size %>
+	*p = int<%= dst_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src))
+  <% else %>
+	*p = int<%= dst_bit_size %>(int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src)))
+  <% end %>
+
+	return nil
+}
+
+type scanPlanBinaryInt<%= pg_byte_size %>ToUint<%= dst_bit_size %> struct{}
+
+func (scanPlanBinaryInt<%= pg_byte_size %>ToUint<%= dst_bit_size %>) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != <%= pg_byte_size %> {
+		return fmt.Errorf("invalid length for uint<%= pg_byte_size %>: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint<%= dst_bit_size %>)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint<%= dst_bit_size %>", n)
+	}
+  <% if dst_bit_size < pg_bit_size %>
+	if n > math.MaxUint<%= dst_bit_size %> {
+		return fmt.Errorf("%d is greater than maximum value for uint<%= dst_bit_size %>", n)
+	}
+  <% end %>
+	*p = uint<%= dst_bit_size %>(n)
+
+	return nil
+}
+<% end %>
+
+<%# PostgreSQL binary format integer to Go machine integers %>
+type scanPlanBinaryInt<%= pg_byte_size %>ToInt struct{}
+
+func (scanPlanBinaryInt<%= pg_byte_size %>ToInt) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != <%= pg_byte_size %> {
+		return fmt.Errorf("invalid length for int<%= pg_byte_size %>: %v", len(src))
+	}
+
+	p, ok := (dst).(*int)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+  <% if 32 < pg_bit_size %>
+	n := int64(binary.BigEndian.Uint<%= pg_bit_size %>(src))
+	if n < math.MinInt {
+		return fmt.Errorf("%d is less than minimum value for int", n)
+	} else if n > math.MaxInt {
+		return fmt.Errorf("%d is greater than maximum value for int", n)
+	}
+
+	*p = int(n)
+  <% else %>
+	*p = int(int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src)))
+  <% end %>
+
+	return nil
+}
+
+type scanPlanBinaryInt<%= pg_byte_size %>ToUint struct{}
+
+func (scanPlanBinaryInt<%= pg_byte_size %>ToUint) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != <%= pg_byte_size %> {
+		return fmt.Errorf("invalid length for uint<%= pg_byte_size %>: %v", len(src))
+	}
+
+	p, ok := (dst).(*uint)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n := int64(int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src)))
+	if n < 0 {
+		return fmt.Errorf("%d is less than minimum value for uint", n)
+	}
+  <% if 32 < pg_bit_size %>
+	if uint64(n) > math.MaxUint {
+		return fmt.Errorf("%d is greater than maximum value for uint", n)
+	}
+  <% end %>
+	*p = uint(n)
+
+	return nil
+}
+
+<%# PostgreSQL binary format integer to Go Int64Scanner %>
+type scanPlanBinaryInt<%= pg_byte_size %>ToInt64Scanner struct{}
+
+func (scanPlanBinaryInt<%= pg_byte_size %>ToInt64Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Int64Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+    return s.ScanInt64(Int8{})
+	}
+
+	if len(src) != <%= pg_byte_size %> {
+		return fmt.Errorf("invalid length for int<%= pg_byte_size %>: %v", len(src))
+	}
+
+
+	n := int64(int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src)))
+
+  return s.ScanInt64(Int8{Int64: n, Valid: true})
+}
+
+<%# PostgreSQL binary format integer to Go TextScanner %>
+type scanPlanBinaryInt<%= pg_byte_size %>ToTextScanner struct{}
+
+func (scanPlanBinaryInt<%= pg_byte_size %>ToTextScanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(TextScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+    return s.ScanText(Text{})
+	}
+
+	if len(src) != <%= pg_byte_size %> {
+		return fmt.Errorf("invalid length for int<%= pg_byte_size %>: %v", len(src))
+	}
+
+
+	n := int64(int<%= pg_bit_size %>(binary.BigEndian.Uint<%= pg_bit_size %>(src)))
+
+  return s.ScanText(Text{String: strconv.FormatInt(n, 10), Valid: true})
+}
+<% end %>
+
+<%# Any text to all integer types %>
+<% [
+  ["8", 8],
+  ["16", 16],
+  ["32", 32],
+  ["64", 64],
+  ["", 0]
+].each do |type_suffix, bit_size| %>
+type scanPlanTextAnyToInt<%= type_suffix %> struct{}
+
+func (scanPlanTextAnyToInt<%= type_suffix %>) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*int<%= type_suffix %>)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseInt(string(src), 10, <%= bit_size %>)
+	if err != nil {
+		return err
+	}
+
+	*p = int<%= type_suffix %>(n)
+	return nil
+}
+
+type scanPlanTextAnyToUint<%= type_suffix %> struct{}
+
+func (scanPlanTextAnyToUint<%= type_suffix %>) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p, ok := (dst).(*uint<%= type_suffix %>)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	n, err := strconv.ParseUint(string(src), 10, <%= bit_size %>)
+	if err != nil {
+		return err
+	}
+
+	*p = uint<%= type_suffix %>(n)
+	return nil
+}
+<% end %>
+
+type scanPlanTextAnyToInt64Scanner struct{}
+
+func (scanPlanTextAnyToInt64Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Int64Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+    return s.ScanInt64(Int8{})
+	}
+
+	n, err := strconv.ParseInt(string(src), 10, 64)
+	if err != nil {
+		return err
+	}
+
+  err = s.ScanInt64(Int8{Int64: n, Valid: true})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/int_test.go.erb b/vendor/github.com/jackc/pgx/v5/pgtype/int_test.go.erb
new file mode 100644
index 000000000..ac9a3f143
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/int_test.go.erb
@@ -0,0 +1,93 @@
+package pgtype_test
+
+import (
+	"math"
+	"testing"
+
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+<% [2, 4, 8].each do |pg_byte_size| %>
+<% pg_bit_size = pg_byte_size * 8 %>
+func TestInt<%= pg_byte_size %>Codec(t *testing.T) {
+	pgxtest.RunValueRoundTripTests(context.Background(), t, defaultConnTestRunner, nil, "int<%= pg_byte_size %>", []pgxtest.ValueRoundTripTest{
+		{int8(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{int16(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{int32(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{int64(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{uint8(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{uint16(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{uint32(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{uint64(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{int(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{uint(1), new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{pgtype.Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: 1, Valid: true}, new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{int32(-1), new(pgtype.Int<%= pg_byte_size %>), isExpectedEq(pgtype.Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: -1, Valid: true})},
+		{1, new(int8), isExpectedEq(int8(1))},
+		{1, new(int16), isExpectedEq(int16(1))},
+		{1, new(int32), isExpectedEq(int32(1))},
+		{1, new(int64), isExpectedEq(int64(1))},
+		{1, new(uint8), isExpectedEq(uint8(1))},
+		{1, new(uint16), isExpectedEq(uint16(1))},
+		{1, new(uint32), isExpectedEq(uint32(1))},
+		{1, new(uint64), isExpectedEq(uint64(1))},
+		{1, new(int), isExpectedEq(int(1))},
+		{1, new(uint), isExpectedEq(uint(1))},
+		{-1, new(int8), isExpectedEq(int8(-1))},
+		{-1, new(int16), isExpectedEq(int16(-1))},
+		{-1, new(int32), isExpectedEq(int32(-1))},
+		{-1, new(int64), isExpectedEq(int64(-1))},
+		{-1, new(int), isExpectedEq(int(-1))},
+		{math.MinInt<%= pg_bit_size %>, new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(math.MinInt<%= pg_bit_size %>))},
+		{-1, new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(-1))},
+		{0, new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(0))},
+		{1, new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(1))},
+		{math.MaxInt<%= pg_bit_size %>, new(int<%= pg_bit_size %>), isExpectedEq(int<%= pg_bit_size %>(math.MaxInt<%= pg_bit_size %>))},
+		{1, new(pgtype.Int<%= pg_byte_size %>), isExpectedEq(pgtype.Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: 1, Valid: true})},
+		{"1", new(string), isExpectedEq("1")},
+		{pgtype.Int<%= pg_byte_size %>{}, new(pgtype.Int<%= pg_byte_size %>), isExpectedEq(pgtype.Int<%= pg_byte_size %>{})},
+		{nil, new(*int<%= pg_bit_size %>), isExpectedEq((*int<%= pg_bit_size %>)(nil))},
+	})
+}
+
+func TestInt<%= pg_byte_size %>MarshalJSON(t *testing.T) {
+	successfulTests := []struct {
+		source pgtype.Int<%= pg_byte_size %>
+		result string
+	}{
+		{source: pgtype.Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: 0}, result: "null"},
+		{source: pgtype.Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: 1, Valid: true}, result: "1"},
+	}
+	for i, tt := range successfulTests {
+		r, err := tt.source.MarshalJSON()
+		if err != nil {
+			t.Errorf("%d: %v", i, err)
+		}
+
+		if string(r) != tt.result {
+			t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, string(r))
+		}
+	}
+}
+
+func TestInt<%= pg_byte_size %>UnmarshalJSON(t *testing.T) {
+	successfulTests := []struct {
+		source string
+		result pgtype.Int<%= pg_byte_size %>
+	}{
+		{source: "null", result: pgtype.Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: 0}},
+		{source: "1", result: pgtype.Int<%= pg_byte_size %>{Int<%= pg_bit_size %>: 1, Valid: true}},
+	}
+	for i, tt := range successfulTests {
+		var r pgtype.Int<%= pg_byte_size %>
+		err := r.UnmarshalJSON([]byte(tt.source))
+		if err != nil {
+			t.Errorf("%d: %v", i, err)
+		}
+
+		if r != tt.result {
+			t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
+		}
+	}
+}
+<% end %>
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/integration_benchmark_test.go.erb b/vendor/github.com/jackc/pgx/v5/pgtype/integration_benchmark_test.go.erb
new file mode 100644
index 000000000..6f4011534
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/integration_benchmark_test.go.erb
@@ -0,0 +1,62 @@
+package pgtype_test
+
+import (
+	"context"
+	"testing"
+
+	"github.com/jackc/pgx/v5/pgtype/testutil"
+	"github.com/jackc/pgx/v5"
+)
+
+<%
+  [
+    ["int4", ["int16", "int32", "int64", "uint64", "pgtype.Int4"], [[1, 1], [1, 10], [10, 1], [100, 10]]],
+    ["numeric", ["int64", "float64", "pgtype.Numeric"], [[1, 1], [1, 10], [10, 1], [100, 10]]],
+  ].each do |pg_type, go_types, rows_columns|
+%>
+<% go_types.each do |go_type| %>
+<% rows_columns.each do |rows, columns| %>
+<% [["Text", "pgx.TextFormatCode"], ["Binary", "pgx.BinaryFormatCode"]].each do |format_name, format_code| %>
+func BenchmarkQuery<%= format_name %>FormatDecode_PG_<%= pg_type %>_to_Go_<%= go_type.gsub(/\W/, "_") %>_<%= rows %>_rows_<%= columns %>_columns(b *testing.B) {
+  defaultConnTestRunner.RunTest(context.Background(), b, func(ctx context.Context, _ testing.TB, conn *pgx.Conn) {
+    b.ResetTimer()
+    var v [<%= columns %>]<%= go_type %>
+    for i := 0; i < b.N; i++ {
+      rows, _ := conn.Query(
+        ctx,
+        `select <% columns.times do |col_idx| %><% if col_idx != 0 %>, <% end %>n::<%= pg_type %> + <%= col_idx%><% end %> from generate_series(1, <%= rows %>) n`,
+        pgx.QueryResultFormats{<%= format_code %>},
+      )
+      _, err := pgx.ForEachRow(rows, []any{<% columns.times do |col_idx| %><% if col_idx != 0 %>, <% end %>&v[<%= col_idx%>]<% end %>},  func() error { return nil })
+      if err != nil {
+        b.Fatal(err)
+      }
+    }
+  })
+}
+<% end %>
+<% end %>
+<% end %>
+<% end %>
+
+<% [10, 100, 1000].each do |array_size| %>
+<% [["Text", "pgx.TextFormatCode"], ["Binary", "pgx.BinaryFormatCode"]].each do |format_name, format_code| %>
+func BenchmarkQuery<%= format_name %>FormatDecode_PG_Int4Array_With_Go_Int4Array_<%= array_size %>(b *testing.B) {
+  defaultConnTestRunner.RunTest(context.Background(), b, func(ctx context.Context, _ testing.TB, conn *pgx.Conn) {
+    b.ResetTimer()
+    var v []int32
+    for i := 0; i < b.N; i++ {
+      rows, _ := conn.Query(
+        ctx,
+        `select array_agg(n) from generate_series(1, <%= array_size %>) n`,
+        pgx.QueryResultFormats{<%= format_code %>},
+      )
+      _, err := pgx.ForEachRow(rows, []any{&v},  func() error { return nil })
+      if err != nil {
+        b.Fatal(err)
+      }
+    }
+  })
+}
+<% end %>
+<% end %>
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/integration_benchmark_test_gen.sh b/vendor/github.com/jackc/pgx/v5/pgtype/integration_benchmark_test_gen.sh
new file mode 100644
index 000000000..22ac01aaf
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/integration_benchmark_test_gen.sh
@@ -0,0 +1,2 @@
+erb integration_benchmark_test.go.erb > integration_benchmark_test.go
+goimports -w integration_benchmark_test.go
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/interval.go b/vendor/github.com/jackc/pgx/v5/pgtype/interval.go
new file mode 100644
index 000000000..be8decdd1
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/interval.go
@@ -0,0 +1,297 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+const (
+	microsecondsPerSecond = 1_000_000
+	microsecondsPerMinute = 60 * microsecondsPerSecond
+	microsecondsPerHour   = 60 * microsecondsPerMinute
+	microsecondsPerDay    = 24 * microsecondsPerHour
+	microsecondsPerMonth  = 30 * microsecondsPerDay
+)
+
+type IntervalScanner interface {
+	ScanInterval(v Interval) error
+}
+
+type IntervalValuer interface {
+	IntervalValue() (Interval, error)
+}
+
+type Interval struct {
+	Microseconds int64
+	Days         int32
+	Months       int32
+	Valid        bool
+}
+
+// ScanInterval implements the [IntervalScanner] interface.
+func (interval *Interval) ScanInterval(v Interval) error {
+	*interval = v
+	return nil
+}
+
+// IntervalValue implements the [IntervalValuer] interface.
+func (interval Interval) IntervalValue() (Interval, error) {
+	return interval, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (interval *Interval) Scan(src any) error {
+	if src == nil {
+		*interval = Interval{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToIntervalScanner{}.Scan([]byte(src), interval)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (interval Interval) Value() (driver.Value, error) {
+	if !interval.Valid {
+		return nil, nil
+	}
+
+	buf, err := IntervalCodec{}.PlanEncode(nil, 0, TextFormatCode, interval).Encode(interval, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type IntervalCodec struct{}
+
+func (IntervalCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (IntervalCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (IntervalCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(IntervalValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanIntervalCodecBinary{}
+	case TextFormatCode:
+		return encodePlanIntervalCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanIntervalCodecBinary struct{}
+
+func (encodePlanIntervalCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	interval, err := value.(IntervalValuer).IntervalValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !interval.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendInt64(buf, interval.Microseconds)
+	buf = pgio.AppendInt32(buf, interval.Days)
+	buf = pgio.AppendInt32(buf, interval.Months)
+	return buf, nil
+}
+
+type encodePlanIntervalCodecText struct{}
+
+func (encodePlanIntervalCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	interval, err := value.(IntervalValuer).IntervalValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !interval.Valid {
+		return nil, nil
+	}
+
+	if interval.Months != 0 {
+		buf = append(buf, strconv.FormatInt(int64(interval.Months), 10)...)
+		buf = append(buf, " mon "...)
+	}
+
+	if interval.Days != 0 {
+		buf = append(buf, strconv.FormatInt(int64(interval.Days), 10)...)
+		buf = append(buf, " day "...)
+	}
+
+	absMicroseconds := interval.Microseconds
+	if absMicroseconds < 0 {
+		absMicroseconds = -absMicroseconds
+		buf = append(buf, '-')
+	}
+
+	hours := absMicroseconds / microsecondsPerHour
+	minutes := (absMicroseconds % microsecondsPerHour) / microsecondsPerMinute
+	seconds := (absMicroseconds % microsecondsPerMinute) / microsecondsPerSecond
+
+	timeStr := fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
+	buf = append(buf, timeStr...)
+
+	microseconds := absMicroseconds % microsecondsPerSecond
+	if microseconds != 0 {
+		buf = append(buf, fmt.Sprintf(".%06d", microseconds)...)
+	}
+
+	return buf, nil
+}
+
+func (IntervalCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(IntervalScanner); ok {
+			return scanPlanBinaryIntervalToIntervalScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(IntervalScanner); ok {
+			return scanPlanTextAnyToIntervalScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryIntervalToIntervalScanner struct{}
+
+func (scanPlanBinaryIntervalToIntervalScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(IntervalScanner)
+
+	if src == nil {
+		return scanner.ScanInterval(Interval{})
+	}
+
+	if len(src) != 16 {
+		return fmt.Errorf("Received an invalid size for an interval: %d", len(src))
+	}
+
+	microseconds := int64(binary.BigEndian.Uint64(src))
+	days := int32(binary.BigEndian.Uint32(src[8:]))
+	months := int32(binary.BigEndian.Uint32(src[12:]))
+
+	return scanner.ScanInterval(Interval{Microseconds: microseconds, Days: days, Months: months, Valid: true})
+}
+
+type scanPlanTextAnyToIntervalScanner struct{}
+
+func (scanPlanTextAnyToIntervalScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(IntervalScanner)
+
+	if src == nil {
+		return scanner.ScanInterval(Interval{})
+	}
+
+	var microseconds int64
+	var days int32
+	var months int32
+
+	parts := strings.Split(string(src), " ")
+
+	for i := 0; i < len(parts)-1; i += 2 {
+		scalar, err := strconv.ParseInt(parts[i], 10, 64)
+		if err != nil {
+			return fmt.Errorf("bad interval format")
+		}
+
+		switch parts[i+1] {
+		case "year", "years":
+			months += int32(scalar * 12)
+		case "mon", "mons":
+			months += int32(scalar)
+		case "day", "days":
+			days = int32(scalar)
+		default:
+			return fmt.Errorf("bad interval format: %q", parts[i+1])
+		}
+	}
+
+	if len(parts)%2 == 1 {
+		timeParts := strings.SplitN(parts[len(parts)-1], ":", 3)
+		if len(timeParts) != 3 {
+			return fmt.Errorf("bad interval format")
+		}
+
+		var negative bool
+		if timeParts[0][0] == '-' {
+			negative = true
+			timeParts[0] = timeParts[0][1:]
+		}
+
+		hours, err := strconv.ParseInt(timeParts[0], 10, 64)
+		if err != nil {
+			return fmt.Errorf("bad interval hour format: %s", timeParts[0])
+		}
+
+		minutes, err := strconv.ParseInt(timeParts[1], 10, 64)
+		if err != nil {
+			return fmt.Errorf("bad interval minute format: %s", timeParts[1])
+		}
+
+		sec, secFrac, secFracFound := strings.Cut(timeParts[2], ".")
+
+		seconds, err := strconv.ParseInt(sec, 10, 64)
+		if err != nil {
+			return fmt.Errorf("bad interval second format: %s", sec)
+		}
+
+		var uSeconds int64
+		if secFracFound {
+			uSeconds, err = strconv.ParseInt(secFrac, 10, 64)
+			if err != nil {
+				return fmt.Errorf("bad interval decimal format: %s", secFrac)
+			}
+
+			for i := 0; i < 6-len(secFrac); i++ {
+				uSeconds *= 10
+			}
+		}
+
+		microseconds = hours * microsecondsPerHour
+		microseconds += minutes * microsecondsPerMinute
+		microseconds += seconds * microsecondsPerSecond
+		microseconds += uSeconds
+
+		if negative {
+			microseconds = -microseconds
+		}
+	}
+
+	return scanner.ScanInterval(Interval{Months: months, Days: days, Microseconds: microseconds, Valid: true})
+}
+
+func (c IntervalCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c IntervalCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var interval Interval
+	err := codecScan(c, m, oid, format, src, &interval)
+	if err != nil {
+		return nil, err
+	}
+	return interval, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/json.go b/vendor/github.com/jackc/pgx/v5/pgtype/json.go
new file mode 100644
index 000000000..a5f74eaed
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/json.go
@@ -0,0 +1,243 @@
+package pgtype
+
+import (
+	"database/sql"
+	"database/sql/driver"
+	"encoding/json"
+	"fmt"
+	"reflect"
+)
+
+type JSONCodec struct {
+	Marshal   func(v any) ([]byte, error)
+	Unmarshal func(data []byte, v any) error
+}
+
+func (*JSONCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (*JSONCodec) PreferredFormat() int16 {
+	return TextFormatCode
+}
+
+func (c *JSONCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch value.(type) {
+	case string:
+		return encodePlanJSONCodecEitherFormatString{}
+	case []byte:
+		return encodePlanJSONCodecEitherFormatByteSlice{}
+
+	// Handle json.RawMessage specifically because if it is run through json.Marshal it may be mutated.
+	// e.g. `{"foo": "bar"}` -> `{"foo":"bar"}`.
+	case json.RawMessage:
+		return encodePlanJSONCodecEitherFormatJSONRawMessage{}
+
+	// Cannot rely on driver.Valuer being handled later because anything can be marshalled.
+	//
+	// https://github.com/jackc/pgx/issues/1430
+	//
+	// Check for driver.Valuer must come before json.Marshaler so that it is guaranteed to be used
+	// when both are implemented https://github.com/jackc/pgx/issues/1805
+	case driver.Valuer:
+		return &encodePlanDriverValuer{m: m, oid: oid, formatCode: format}
+
+	// Must come before trying wrap encode plans because a pointer to a struct may be unwrapped to a struct that can be
+	// marshalled.
+	//
+	// https://github.com/jackc/pgx/issues/1681
+	case json.Marshaler:
+		return &encodePlanJSONCodecEitherFormatMarshal{
+			marshal: c.Marshal,
+		}
+	}
+
+	// Because anything can be marshalled the normal wrapping in Map.PlanScan doesn't get a chance to run. So try the
+	// appropriate wrappers here.
+	for _, f := range []TryWrapEncodePlanFunc{
+		TryWrapDerefPointerEncodePlan,
+		TryWrapFindUnderlyingTypeEncodePlan,
+	} {
+		if wrapperPlan, nextValue, ok := f(value); ok {
+			if nextPlan := c.PlanEncode(m, oid, format, nextValue); nextPlan != nil {
+				wrapperPlan.SetNext(nextPlan)
+				return wrapperPlan
+			}
+		}
+	}
+
+	return &encodePlanJSONCodecEitherFormatMarshal{
+		marshal: c.Marshal,
+	}
+}
+
+// JSON needs its on scan plan for pointers to handle 'null'::json(b).
+// Consider making pointerPointerScanPlan more flexible in the future.
+type jsonPointerScanPlan struct {
+	next ScanPlan
+}
+
+func (p jsonPointerScanPlan) Scan(src []byte, dst any) error {
+	el := reflect.ValueOf(dst).Elem()
+	if src == nil || string(src) == "null" {
+		el.SetZero()
+		return nil
+	}
+
+	el.Set(reflect.New(el.Type().Elem()))
+	if p.next != nil {
+		return p.next.Scan(src, el.Interface())
+	}
+
+	return nil
+}
+
+type encodePlanJSONCodecEitherFormatString struct{}
+
+func (encodePlanJSONCodecEitherFormatString) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	jsonString := value.(string)
+	buf = append(buf, jsonString...)
+	return buf, nil
+}
+
+type encodePlanJSONCodecEitherFormatByteSlice struct{}
+
+func (encodePlanJSONCodecEitherFormatByteSlice) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	jsonBytes := value.([]byte)
+	if jsonBytes == nil {
+		return nil, nil
+	}
+
+	buf = append(buf, jsonBytes...)
+	return buf, nil
+}
+
+type encodePlanJSONCodecEitherFormatJSONRawMessage struct{}
+
+func (encodePlanJSONCodecEitherFormatJSONRawMessage) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	jsonBytes := value.(json.RawMessage)
+	if jsonBytes == nil {
+		return nil, nil
+	}
+
+	buf = append(buf, jsonBytes...)
+	return buf, nil
+}
+
+type encodePlanJSONCodecEitherFormatMarshal struct {
+	marshal func(v any) ([]byte, error)
+}
+
+func (e *encodePlanJSONCodecEitherFormatMarshal) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	jsonBytes, err := e.marshal(value)
+	if err != nil {
+		return nil, err
+	}
+
+	buf = append(buf, jsonBytes...)
+	return buf, nil
+}
+
+func (c *JSONCodec) PlanScan(m *Map, oid uint32, formatCode int16, target any) ScanPlan {
+	return c.planScan(m, oid, formatCode, target, 0)
+}
+
+// JSON cannot fallback to pointerPointerScanPlan because of 'null'::json(b),
+// so we need to duplicate the logic here.
+func (c *JSONCodec) planScan(m *Map, oid uint32, formatCode int16, target any, depth int) ScanPlan {
+	if depth > 8 {
+		return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
+	}
+
+	switch target.(type) {
+	case *string:
+		return &scanPlanAnyToString{}
+	case *[]byte:
+		return &scanPlanJSONToByteSlice{}
+	case BytesScanner:
+		return &scanPlanBinaryBytesToBytesScanner{}
+	case sql.Scanner:
+		return &scanPlanCodecSQLScanner{c: c, m: m, oid: oid, formatCode: formatCode}
+	}
+
+	rv := reflect.ValueOf(target)
+	if rv.Kind() == reflect.Pointer && rv.Elem().Kind() == reflect.Pointer {
+		var plan jsonPointerScanPlan
+		plan.next = c.planScan(m, oid, formatCode, rv.Elem().Interface(), depth+1)
+		return plan
+	} else {
+		return &scanPlanJSONToJSONUnmarshal{unmarshal: c.Unmarshal}
+	}
+}
+
+type scanPlanAnyToString struct{}
+
+func (scanPlanAnyToString) Scan(src []byte, dst any) error {
+	p := dst.(*string)
+	*p = string(src)
+	return nil
+}
+
+type scanPlanJSONToByteSlice struct{}
+
+func (scanPlanJSONToByteSlice) Scan(src []byte, dst any) error {
+	dstBuf := dst.(*[]byte)
+	if src == nil {
+		*dstBuf = nil
+		return nil
+	}
+
+	*dstBuf = make([]byte, len(src))
+	copy(*dstBuf, src)
+	return nil
+}
+
+type scanPlanJSONToJSONUnmarshal struct {
+	unmarshal func(data []byte, v any) error
+}
+
+func (s *scanPlanJSONToJSONUnmarshal) Scan(src []byte, dst any) error {
+	if src == nil {
+		dstValue := reflect.ValueOf(dst)
+		if dstValue.Kind() == reflect.Pointer {
+			el := dstValue.Elem()
+			switch el.Kind() {
+			case reflect.Pointer, reflect.Slice, reflect.Map, reflect.Interface:
+				el.Set(reflect.Zero(el.Type()))
+				return nil
+			}
+		}
+
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	v := reflect.ValueOf(dst)
+	if v.Kind() != reflect.Pointer || v.IsNil() {
+		return fmt.Errorf("cannot scan into non-pointer or nil destinations %T", dst)
+	}
+
+	elem := v.Elem()
+	elem.Set(reflect.Zero(elem.Type()))
+
+	return s.unmarshal(src, dst)
+}
+
+func (c *JSONCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	dstBuf := make([]byte, len(src))
+	copy(dstBuf, src)
+	return dstBuf, nil
+}
+
+func (c *JSONCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var dst any
+	err := c.Unmarshal(src, &dst)
+	return dst, err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/jsonb.go b/vendor/github.com/jackc/pgx/v5/pgtype/jsonb.go
new file mode 100644
index 000000000..4d4eb58e5
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/jsonb.go
@@ -0,0 +1,129 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"fmt"
+)
+
+type JSONBCodec struct {
+	Marshal   func(v any) ([]byte, error)
+	Unmarshal func(data []byte, v any) error
+}
+
+func (*JSONBCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (*JSONBCodec) PreferredFormat() int16 {
+	return TextFormatCode
+}
+
+func (c *JSONBCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		plan := (&JSONCodec{Marshal: c.Marshal, Unmarshal: c.Unmarshal}).PlanEncode(m, oid, TextFormatCode, value)
+		if plan != nil {
+			return &encodePlanJSONBCodecBinaryWrapper{textPlan: plan}
+		}
+	case TextFormatCode:
+		return (&JSONCodec{Marshal: c.Marshal, Unmarshal: c.Unmarshal}).PlanEncode(m, oid, format, value)
+	}
+
+	return nil
+}
+
+type encodePlanJSONBCodecBinaryWrapper struct {
+	textPlan EncodePlan
+}
+
+func (plan *encodePlanJSONBCodecBinaryWrapper) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	buf = append(buf, 1)
+	return plan.textPlan.Encode(value, buf)
+}
+
+func (c *JSONBCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		plan := (&JSONCodec{Marshal: c.Marshal, Unmarshal: c.Unmarshal}).PlanScan(m, oid, TextFormatCode, target)
+		if plan != nil {
+			return &scanPlanJSONBCodecBinaryUnwrapper{textPlan: plan}
+		}
+	case TextFormatCode:
+		return (&JSONCodec{Marshal: c.Marshal, Unmarshal: c.Unmarshal}).PlanScan(m, oid, format, target)
+	}
+
+	return nil
+}
+
+type scanPlanJSONBCodecBinaryUnwrapper struct {
+	textPlan ScanPlan
+}
+
+func (plan *scanPlanJSONBCodecBinaryUnwrapper) Scan(src []byte, dst any) error {
+	if src == nil {
+		return plan.textPlan.Scan(src, dst)
+	}
+
+	if len(src) == 0 {
+		return fmt.Errorf("jsonb too short")
+	}
+
+	if src[0] != 1 {
+		return fmt.Errorf("unknown jsonb version number %d", src[0])
+	}
+
+	return plan.textPlan.Scan(src[1:], dst)
+}
+
+func (c *JSONBCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		if len(src) == 0 {
+			return nil, fmt.Errorf("jsonb too short")
+		}
+
+		if src[0] != 1 {
+			return nil, fmt.Errorf("unknown jsonb version number %d", src[0])
+		}
+
+		dstBuf := make([]byte, len(src)-1)
+		copy(dstBuf, src[1:])
+		return dstBuf, nil
+	case TextFormatCode:
+		dstBuf := make([]byte, len(src))
+		copy(dstBuf, src)
+		return dstBuf, nil
+	default:
+		return nil, fmt.Errorf("unknown format code: %v", format)
+	}
+}
+
+func (c *JSONBCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		if len(src) == 0 {
+			return nil, fmt.Errorf("jsonb too short")
+		}
+
+		if src[0] != 1 {
+			return nil, fmt.Errorf("unknown jsonb version number %d", src[0])
+		}
+
+		src = src[1:]
+	case TextFormatCode:
+	default:
+		return nil, fmt.Errorf("unknown format code: %v", format)
+	}
+
+	var dst any
+	err := c.Unmarshal(src, &dst)
+	return dst, err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/line.go b/vendor/github.com/jackc/pgx/v5/pgtype/line.go
new file mode 100644
index 000000000..73b063649
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/line.go
@@ -0,0 +1,223 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type LineScanner interface {
+	ScanLine(v Line) error
+}
+
+type LineValuer interface {
+	LineValue() (Line, error)
+}
+
+type Line struct {
+	A, B, C float64
+	Valid   bool
+}
+
+// ScanLine implements the [LineScanner] interface.
+func (line *Line) ScanLine(v Line) error {
+	*line = v
+	return nil
+}
+
+// LineValue implements the [LineValuer] interface.
+func (line Line) LineValue() (Line, error) {
+	return line, nil
+}
+
+func (line *Line) Set(src any) error {
+	return fmt.Errorf("cannot convert %v to Line", src)
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (line *Line) Scan(src any) error {
+	if src == nil {
+		*line = Line{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToLineScanner{}.Scan([]byte(src), line)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (line Line) Value() (driver.Value, error) {
+	if !line.Valid {
+		return nil, nil
+	}
+
+	buf, err := LineCodec{}.PlanEncode(nil, 0, TextFormatCode, line).Encode(line, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type LineCodec struct{}
+
+func (LineCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (LineCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (LineCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(LineValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanLineCodecBinary{}
+	case TextFormatCode:
+		return encodePlanLineCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanLineCodecBinary struct{}
+
+func (encodePlanLineCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	line, err := value.(LineValuer).LineValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !line.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendUint64(buf, math.Float64bits(line.A))
+	buf = pgio.AppendUint64(buf, math.Float64bits(line.B))
+	buf = pgio.AppendUint64(buf, math.Float64bits(line.C))
+	return buf, nil
+}
+
+type encodePlanLineCodecText struct{}
+
+func (encodePlanLineCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	line, err := value.(LineValuer).LineValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !line.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, fmt.Sprintf(`{%s,%s,%s}`,
+		strconv.FormatFloat(line.A, 'f', -1, 64),
+		strconv.FormatFloat(line.B, 'f', -1, 64),
+		strconv.FormatFloat(line.C, 'f', -1, 64),
+	)...)
+	return buf, nil
+}
+
+func (LineCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(LineScanner); ok {
+			return scanPlanBinaryLineToLineScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(LineScanner); ok {
+			return scanPlanTextAnyToLineScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryLineToLineScanner struct{}
+
+func (scanPlanBinaryLineToLineScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(LineScanner)
+
+	if src == nil {
+		return scanner.ScanLine(Line{})
+	}
+
+	if len(src) != 24 {
+		return fmt.Errorf("invalid length for line: %v", len(src))
+	}
+
+	a := binary.BigEndian.Uint64(src)
+	b := binary.BigEndian.Uint64(src[8:])
+	c := binary.BigEndian.Uint64(src[16:])
+
+	return scanner.ScanLine(Line{
+		A:     math.Float64frombits(a),
+		B:     math.Float64frombits(b),
+		C:     math.Float64frombits(c),
+		Valid: true,
+	})
+}
+
+type scanPlanTextAnyToLineScanner struct{}
+
+func (scanPlanTextAnyToLineScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(LineScanner)
+
+	if src == nil {
+		return scanner.ScanLine(Line{})
+	}
+
+	if len(src) < 7 {
+		return fmt.Errorf("invalid length for line: %v", len(src))
+	}
+
+	parts := strings.SplitN(string(src[1:len(src)-1]), ",", 3)
+	if len(parts) < 3 {
+		return fmt.Errorf("invalid format for line")
+	}
+
+	a, err := strconv.ParseFloat(parts[0], 64)
+	if err != nil {
+		return err
+	}
+
+	b, err := strconv.ParseFloat(parts[1], 64)
+	if err != nil {
+		return err
+	}
+
+	c, err := strconv.ParseFloat(parts[2], 64)
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanLine(Line{A: a, B: b, C: c, Valid: true})
+}
+
+func (c LineCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c LineCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var line Line
+	err := codecScan(c, m, oid, format, src, &line)
+	if err != nil {
+		return nil, err
+	}
+	return line, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/lseg.go b/vendor/github.com/jackc/pgx/v5/pgtype/lseg.go
new file mode 100644
index 000000000..438b45b62
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/lseg.go
@@ -0,0 +1,235 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type LsegScanner interface {
+	ScanLseg(v Lseg) error
+}
+
+type LsegValuer interface {
+	LsegValue() (Lseg, error)
+}
+
+type Lseg struct {
+	P     [2]Vec2
+	Valid bool
+}
+
+// ScanLseg implements the [LsegScanner] interface.
+func (lseg *Lseg) ScanLseg(v Lseg) error {
+	*lseg = v
+	return nil
+}
+
+// LsegValue implements the [LsegValuer] interface.
+func (lseg Lseg) LsegValue() (Lseg, error) {
+	return lseg, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (lseg *Lseg) Scan(src any) error {
+	if src == nil {
+		*lseg = Lseg{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToLsegScanner{}.Scan([]byte(src), lseg)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (lseg Lseg) Value() (driver.Value, error) {
+	if !lseg.Valid {
+		return nil, nil
+	}
+
+	buf, err := LsegCodec{}.PlanEncode(nil, 0, TextFormatCode, lseg).Encode(lseg, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type LsegCodec struct{}
+
+func (LsegCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (LsegCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (LsegCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(LsegValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanLsegCodecBinary{}
+	case TextFormatCode:
+		return encodePlanLsegCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanLsegCodecBinary struct{}
+
+func (encodePlanLsegCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	lseg, err := value.(LsegValuer).LsegValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !lseg.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendUint64(buf, math.Float64bits(lseg.P[0].X))
+	buf = pgio.AppendUint64(buf, math.Float64bits(lseg.P[0].Y))
+	buf = pgio.AppendUint64(buf, math.Float64bits(lseg.P[1].X))
+	buf = pgio.AppendUint64(buf, math.Float64bits(lseg.P[1].Y))
+	return buf, nil
+}
+
+type encodePlanLsegCodecText struct{}
+
+func (encodePlanLsegCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	lseg, err := value.(LsegValuer).LsegValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !lseg.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, fmt.Sprintf(`[(%s,%s),(%s,%s)]`,
+		strconv.FormatFloat(lseg.P[0].X, 'f', -1, 64),
+		strconv.FormatFloat(lseg.P[0].Y, 'f', -1, 64),
+		strconv.FormatFloat(lseg.P[1].X, 'f', -1, 64),
+		strconv.FormatFloat(lseg.P[1].Y, 'f', -1, 64),
+	)...)
+	return buf, nil
+}
+
+func (LsegCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(LsegScanner); ok {
+			return scanPlanBinaryLsegToLsegScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(LsegScanner); ok {
+			return scanPlanTextAnyToLsegScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryLsegToLsegScanner struct{}
+
+func (scanPlanBinaryLsegToLsegScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(LsegScanner)
+
+	if src == nil {
+		return scanner.ScanLseg(Lseg{})
+	}
+
+	if len(src) != 32 {
+		return fmt.Errorf("invalid length for lseg: %v", len(src))
+	}
+
+	x1 := binary.BigEndian.Uint64(src)
+	y1 := binary.BigEndian.Uint64(src[8:])
+	x2 := binary.BigEndian.Uint64(src[16:])
+	y2 := binary.BigEndian.Uint64(src[24:])
+
+	return scanner.ScanLseg(Lseg{
+		P: [2]Vec2{
+			{math.Float64frombits(x1), math.Float64frombits(y1)},
+			{math.Float64frombits(x2), math.Float64frombits(y2)},
+		},
+		Valid: true,
+	})
+}
+
+type scanPlanTextAnyToLsegScanner struct{}
+
+func (scanPlanTextAnyToLsegScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(LsegScanner)
+
+	if src == nil {
+		return scanner.ScanLseg(Lseg{})
+	}
+
+	if len(src) < 11 {
+		return fmt.Errorf("invalid length for lseg: %v", len(src))
+	}
+
+	// Expected format: [(x1,y1),(x2,y2)]
+	sp1, sp2, found := strings.Cut(string(src[2:len(src)-2]), "),(")
+	if !found {
+		return fmt.Errorf("invalid format for lseg")
+	}
+
+	sx1, sy1, found := strings.Cut(sp1, ",")
+	if !found {
+		return fmt.Errorf("invalid format for lseg")
+	}
+	sx2, sy2, found := strings.Cut(sp2, ",")
+	if !found {
+		return fmt.Errorf("invalid format for lseg")
+	}
+
+	x1, err := strconv.ParseFloat(sx1, 64)
+	if err != nil {
+		return err
+	}
+	y1, err := strconv.ParseFloat(sy1, 64)
+	if err != nil {
+		return err
+	}
+	x2, err := strconv.ParseFloat(sx2, 64)
+	if err != nil {
+		return err
+	}
+	y2, err := strconv.ParseFloat(sy2, 64)
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanLseg(Lseg{P: [2]Vec2{{x1, y1}, {x2, y2}}, Valid: true})
+}
+
+func (c LsegCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c LsegCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var lseg Lseg
+	err := codecScan(c, m, oid, format, src, &lseg)
+	if err != nil {
+		return nil, err
+	}
+	return lseg, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/ltree.go b/vendor/github.com/jackc/pgx/v5/pgtype/ltree.go
new file mode 100644
index 000000000..6af317794
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/ltree.go
@@ -0,0 +1,122 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"fmt"
+)
+
+type LtreeCodec struct{}
+
+func (l LtreeCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+// PreferredFormat returns the preferred format.
+func (l LtreeCodec) PreferredFormat() int16 {
+	return TextFormatCode
+}
+
+// PlanEncode returns an EncodePlan for encoding value into PostgreSQL format for oid and format. If no plan can be
+// found then nil is returned.
+func (l LtreeCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case TextFormatCode:
+		return (TextCodec)(l).PlanEncode(m, oid, format, value)
+	case BinaryFormatCode:
+		switch value.(type) {
+		case string:
+			return encodeLtreeCodecBinaryString{}
+		case []byte:
+			return encodeLtreeCodecBinaryByteSlice{}
+		case TextValuer:
+			return encodeLtreeCodecBinaryTextValuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodeLtreeCodecBinaryString struct{}
+
+func (encodeLtreeCodecBinaryString) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	ltree := value.(string)
+	buf = append(buf, 1)
+	return append(buf, ltree...), nil
+}
+
+type encodeLtreeCodecBinaryByteSlice struct{}
+
+func (encodeLtreeCodecBinaryByteSlice) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	ltree := value.([]byte)
+	buf = append(buf, 1)
+	return append(buf, ltree...), nil
+}
+
+type encodeLtreeCodecBinaryTextValuer struct{}
+
+func (encodeLtreeCodecBinaryTextValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	t, err := value.(TextValuer).TextValue()
+	if err != nil {
+		return nil, err
+	}
+	if !t.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, 1)
+	return append(buf, t.String...), nil
+}
+
+// PlanScan returns a ScanPlan for scanning a PostgreSQL value into a destination with the same type as target. If
+// no plan can be found then nil is returned.
+func (l LtreeCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case TextFormatCode:
+		return (TextCodec)(l).PlanScan(m, oid, format, target)
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *string:
+			return scanPlanBinaryLtreeToString{}
+		case TextScanner:
+			return scanPlanBinaryLtreeToTextScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryLtreeToString struct{}
+
+func (scanPlanBinaryLtreeToString) Scan(src []byte, target any) error {
+	version := src[0]
+	if version != 1 {
+		return fmt.Errorf("unsupported ltree version %d", version)
+	}
+
+	p := (target).(*string)
+	*p = string(src[1:])
+
+	return nil
+}
+
+type scanPlanBinaryLtreeToTextScanner struct{}
+
+func (scanPlanBinaryLtreeToTextScanner) Scan(src []byte, target any) error {
+	version := src[0]
+	if version != 1 {
+		return fmt.Errorf("unsupported ltree version %d", version)
+	}
+
+	scanner := (target).(TextScanner)
+	return scanner.ScanText(Text{String: string(src[1:]), Valid: true})
+}
+
+// DecodeDatabaseSQLValue returns src decoded into a value compatible with the sql.Scanner interface.
+func (l LtreeCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return (TextCodec)(l).DecodeDatabaseSQLValue(m, oid, format, src)
+}
+
+// DecodeValue returns src decoded into its default format.
+func (l LtreeCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	return (TextCodec)(l).DecodeValue(m, oid, format, src)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/macaddr.go b/vendor/github.com/jackc/pgx/v5/pgtype/macaddr.go
new file mode 100644
index 000000000..e913ec903
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/macaddr.go
@@ -0,0 +1,162 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"net"
+)
+
+type MacaddrCodec struct{}
+
+func (MacaddrCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (MacaddrCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (MacaddrCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case net.HardwareAddr:
+			return encodePlanMacaddrCodecBinaryHardwareAddr{}
+		case TextValuer:
+			return encodePlanMacAddrCodecTextValuer{}
+
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case net.HardwareAddr:
+			return encodePlanMacaddrCodecTextHardwareAddr{}
+		case TextValuer:
+			return encodePlanTextCodecTextValuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanMacaddrCodecBinaryHardwareAddr struct{}
+
+func (encodePlanMacaddrCodecBinaryHardwareAddr) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	addr := value.(net.HardwareAddr)
+	if addr == nil {
+		return nil, nil
+	}
+
+	return append(buf, addr...), nil
+}
+
+type encodePlanMacAddrCodecTextValuer struct{}
+
+func (encodePlanMacAddrCodecTextValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	t, err := value.(TextValuer).TextValue()
+	if err != nil {
+		return nil, err
+	}
+	if !t.Valid {
+		return nil, nil
+	}
+
+	addr, err := net.ParseMAC(t.String)
+	if err != nil {
+		return nil, err
+	}
+
+	return append(buf, addr...), nil
+}
+
+type encodePlanMacaddrCodecTextHardwareAddr struct{}
+
+func (encodePlanMacaddrCodecTextHardwareAddr) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	addr := value.(net.HardwareAddr)
+	if addr == nil {
+		return nil, nil
+	}
+
+	return append(buf, addr.String()...), nil
+}
+
+func (MacaddrCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *net.HardwareAddr:
+			return scanPlanBinaryMacaddrToHardwareAddr{}
+		case TextScanner:
+			return scanPlanBinaryMacaddrToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *net.HardwareAddr:
+			return scanPlanTextMacaddrToHardwareAddr{}
+		case TextScanner:
+			return scanPlanTextAnyToTextScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryMacaddrToHardwareAddr struct{}
+
+func (scanPlanBinaryMacaddrToHardwareAddr) Scan(src []byte, dst any) error {
+	dstBuf := dst.(*net.HardwareAddr)
+	if src == nil {
+		*dstBuf = nil
+		return nil
+	}
+
+	*dstBuf = make([]byte, len(src))
+	copy(*dstBuf, src)
+	return nil
+}
+
+type scanPlanBinaryMacaddrToTextScanner struct{}
+
+func (scanPlanBinaryMacaddrToTextScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TextScanner)
+	if src == nil {
+		return scanner.ScanText(Text{})
+	}
+
+	return scanner.ScanText(Text{String: net.HardwareAddr(src).String(), Valid: true})
+}
+
+type scanPlanTextMacaddrToHardwareAddr struct{}
+
+func (scanPlanTextMacaddrToHardwareAddr) Scan(src []byte, dst any) error {
+	p := dst.(*net.HardwareAddr)
+
+	if src == nil {
+		*p = nil
+		return nil
+	}
+
+	addr, err := net.ParseMAC(string(src))
+	if err != nil {
+		return err
+	}
+
+	*p = addr
+
+	return nil
+}
+
+func (c MacaddrCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c MacaddrCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var addr net.HardwareAddr
+	err := codecScan(c, m, oid, format, src, &addr)
+	if err != nil {
+		return nil, err
+	}
+	return addr, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/multirange.go b/vendor/github.com/jackc/pgx/v5/pgtype/multirange.go
new file mode 100644
index 000000000..11f30b448
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/multirange.go
@@ -0,0 +1,453 @@
+package pgtype
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"reflect"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// MultirangeGetter is a type that can be converted into a PostgreSQL multirange.
+type MultirangeGetter interface {
+	// IsNull returns true if the value is SQL NULL.
+	IsNull() bool
+
+	// Len returns the number of elements in the multirange.
+	Len() int
+
+	// Index returns the element at i.
+	Index(i int) any
+
+	// IndexType returns a non-nil scan target of the type Index will return. This is used by MultirangeCodec.PlanEncode.
+	IndexType() any
+}
+
+// MultirangeSetter is a type can be set from a PostgreSQL multirange.
+type MultirangeSetter interface {
+	// ScanNull sets the value to SQL NULL.
+	ScanNull() error
+
+	// SetLen prepares the value such that ScanIndex can be called for each element. This will remove any existing
+	// elements.
+	SetLen(n int) error
+
+	// ScanIndex returns a value usable as a scan target for i. SetLen must be called before ScanIndex.
+	ScanIndex(i int) any
+
+	// ScanIndexType returns a non-nil scan target of the type ScanIndex will return. This is used by
+	// MultirangeCodec.PlanScan.
+	ScanIndexType() any
+}
+
+// MultirangeCodec is a codec for any multirange type.
+type MultirangeCodec struct {
+	ElementType *Type
+}
+
+func (c *MultirangeCodec) FormatSupported(format int16) bool {
+	return c.ElementType.Codec.FormatSupported(format)
+}
+
+func (c *MultirangeCodec) PreferredFormat() int16 {
+	return c.ElementType.Codec.PreferredFormat()
+}
+
+func (c *MultirangeCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	multirangeValuer, ok := value.(MultirangeGetter)
+	if !ok {
+		return nil
+	}
+
+	elementType := multirangeValuer.IndexType()
+
+	elementEncodePlan := m.PlanEncode(c.ElementType.OID, format, elementType)
+	if elementEncodePlan == nil {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return &encodePlanMultirangeCodecBinary{ac: c, m: m, oid: oid}
+	case TextFormatCode:
+		return &encodePlanMultirangeCodecText{ac: c, m: m, oid: oid}
+	}
+
+	return nil
+}
+
+type encodePlanMultirangeCodecText struct {
+	ac  *MultirangeCodec
+	m   *Map
+	oid uint32
+}
+
+func (p *encodePlanMultirangeCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	multirange := value.(MultirangeGetter)
+
+	if multirange.IsNull() {
+		return nil, nil
+	}
+
+	elementCount := multirange.Len()
+
+	buf = append(buf, '{')
+
+	var encodePlan EncodePlan
+	var lastElemType reflect.Type
+	inElemBuf := make([]byte, 0, 32)
+	for i := range elementCount {
+		if i > 0 {
+			buf = append(buf, ',')
+		}
+
+		elem := multirange.Index(i)
+		var elemBuf []byte
+		if elem != nil {
+			elemType := reflect.TypeOf(elem)
+			if lastElemType != elemType {
+				lastElemType = elemType
+				encodePlan = p.m.PlanEncode(p.ac.ElementType.OID, TextFormatCode, elem)
+				if encodePlan == nil {
+					return nil, fmt.Errorf("unable to encode %v", multirange.Index(i))
+				}
+			}
+			elemBuf, err = encodePlan.Encode(elem, inElemBuf)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if elemBuf == nil {
+			return nil, fmt.Errorf("multirange cannot contain NULL element")
+		} else {
+			buf = append(buf, elemBuf...)
+		}
+	}
+
+	buf = append(buf, '}')
+
+	return buf, nil
+}
+
+type encodePlanMultirangeCodecBinary struct {
+	ac  *MultirangeCodec
+	m   *Map
+	oid uint32
+}
+
+func (p *encodePlanMultirangeCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	multirange := value.(MultirangeGetter)
+
+	if multirange.IsNull() {
+		return nil, nil
+	}
+
+	elementCount := multirange.Len()
+
+	buf = pgio.AppendInt32(buf, int32(elementCount))
+
+	var encodePlan EncodePlan
+	var lastElemType reflect.Type
+	for i := range elementCount {
+		sp := len(buf)
+		buf = pgio.AppendInt32(buf, -1)
+
+		elem := multirange.Index(i)
+		var elemBuf []byte
+		if elem != nil {
+			elemType := reflect.TypeOf(elem)
+			if lastElemType != elemType {
+				lastElemType = elemType
+				encodePlan = p.m.PlanEncode(p.ac.ElementType.OID, BinaryFormatCode, elem)
+				if encodePlan == nil {
+					return nil, fmt.Errorf("unable to encode %v", multirange.Index(i))
+				}
+			}
+			elemBuf, err = encodePlan.Encode(elem, buf)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if elemBuf == nil {
+			return nil, fmt.Errorf("multirange cannot contain NULL element")
+		} else {
+			buf = elemBuf
+			pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+		}
+	}
+
+	return buf, nil
+}
+
+func (c *MultirangeCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	multirangeScanner, ok := target.(MultirangeSetter)
+	if !ok {
+		return nil
+	}
+
+	elementType := multirangeScanner.ScanIndexType()
+
+	elementScanPlan := m.PlanScan(c.ElementType.OID, format, elementType)
+	if _, ok := elementScanPlan.(*scanPlanFail); ok {
+		return nil
+	}
+
+	return &scanPlanMultirangeCodec{
+		multirangeCodec: c,
+		m:               m,
+		oid:             oid,
+		formatCode:      format,
+	}
+}
+
+func (c *MultirangeCodec) decodeBinary(m *Map, multirangeOID uint32, src []byte, multirange MultirangeSetter) error {
+	rp := 0
+
+	elementCount := int(binary.BigEndian.Uint32(src[rp:]))
+	rp += 4
+
+	// Each element requires at least 4 bytes for its length prefix.
+	if elementCount > len(src)/4 {
+		return fmt.Errorf("multirange element count %d exceeds available data", elementCount)
+	}
+
+	err := multirange.SetLen(elementCount)
+	if err != nil {
+		return err
+	}
+
+	if elementCount == 0 {
+		return nil
+	}
+
+	elementScanPlan := c.ElementType.Codec.PlanScan(m, c.ElementType.OID, BinaryFormatCode, multirange.ScanIndex(0))
+	if elementScanPlan == nil {
+		elementScanPlan = m.PlanScan(c.ElementType.OID, BinaryFormatCode, multirange.ScanIndex(0))
+	}
+
+	for i := range elementCount {
+		elem := multirange.ScanIndex(i)
+		if len(src[rp:]) < 4 {
+			return fmt.Errorf("multirange body truncated at element %d", i)
+		}
+		elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
+		rp += 4
+		var elemSrc []byte
+		if elemLen >= 0 {
+			if len(src[rp:]) < elemLen {
+				return fmt.Errorf("multirange element %d length %d exceeds remaining %d bytes", i, elemLen, len(src[rp:]))
+			}
+			elemSrc = src[rp : rp+elemLen]
+			rp += elemLen
+		}
+		err = elementScanPlan.Scan(elemSrc, elem)
+		if err != nil {
+			return fmt.Errorf("failed to scan multirange element %d: %w", i, err)
+		}
+	}
+
+	return nil
+}
+
+func (c *MultirangeCodec) decodeText(m *Map, multirangeOID uint32, src []byte, multirange MultirangeSetter) error {
+	elements, err := parseUntypedTextMultirange(src)
+	if err != nil {
+		return err
+	}
+
+	err = multirange.SetLen(len(elements))
+	if err != nil {
+		return err
+	}
+
+	if len(elements) == 0 {
+		return nil
+	}
+
+	elementScanPlan := c.ElementType.Codec.PlanScan(m, c.ElementType.OID, TextFormatCode, multirange.ScanIndex(0))
+	if elementScanPlan == nil {
+		elementScanPlan = m.PlanScan(c.ElementType.OID, TextFormatCode, multirange.ScanIndex(0))
+	}
+
+	for i, s := range elements {
+		elem := multirange.ScanIndex(i)
+		err = elementScanPlan.Scan([]byte(s), elem)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+type scanPlanMultirangeCodec struct {
+	multirangeCodec *MultirangeCodec
+	m               *Map
+	oid             uint32
+	formatCode      int16
+	elementScanPlan ScanPlan
+}
+
+func (spac *scanPlanMultirangeCodec) Scan(src []byte, dst any) error {
+	c := spac.multirangeCodec
+	m := spac.m
+	oid := spac.oid
+	formatCode := spac.formatCode
+
+	multirange := dst.(MultirangeSetter)
+
+	if src == nil {
+		return multirange.ScanNull()
+	}
+
+	switch formatCode {
+	case BinaryFormatCode:
+		return c.decodeBinary(m, oid, src, multirange)
+	case TextFormatCode:
+		return c.decodeText(m, oid, src, multirange)
+	default:
+		return fmt.Errorf("unknown format code %d", formatCode)
+	}
+}
+
+func (c *MultirangeCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case TextFormatCode:
+		return string(src), nil
+	case BinaryFormatCode:
+		buf := make([]byte, len(src))
+		copy(buf, src)
+		return buf, nil
+	default:
+		return nil, fmt.Errorf("unknown format code %d", format)
+	}
+}
+
+func (c *MultirangeCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var multirange Multirange[Range[any]]
+	err := m.PlanScan(oid, format, &multirange).Scan(src, &multirange)
+	return multirange, err
+}
+
+func parseUntypedTextMultirange(src []byte) ([]string, error) {
+	elements := make([]string, 0)
+
+	buf := bytes.NewBuffer(src)
+
+	skipWhitespace(buf)
+
+	r, _, err := buf.ReadRune()
+	if err != nil {
+		return nil, fmt.Errorf("invalid array: %w", err)
+	}
+
+	if r != '{' {
+		return nil, fmt.Errorf("invalid multirange, expected '{' got %v", r)
+	}
+
+parseValueLoop:
+	for {
+		r, _, err = buf.ReadRune()
+		if err != nil {
+			return nil, fmt.Errorf("invalid multirange: %w", err)
+		}
+
+		switch r {
+		case ',': // skip range separator
+		case '}':
+			break parseValueLoop
+		default:
+			buf.UnreadRune()
+			value, err := parseRange(buf)
+			if err != nil {
+				return nil, fmt.Errorf("invalid multirange value: %w", err)
+			}
+			elements = append(elements, value)
+		}
+	}
+
+	skipWhitespace(buf)
+
+	if buf.Len() > 0 {
+		return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
+	}
+
+	return elements, nil
+}
+
+func parseRange(buf *bytes.Buffer) (string, error) {
+	s := &bytes.Buffer{}
+
+	boundSepRead := false
+	for {
+		r, _, err := buf.ReadRune()
+		if err != nil {
+			return "", err
+		}
+
+		switch r {
+		case ',', '}':
+			if r == ',' && !boundSepRead {
+				boundSepRead = true
+				break
+			}
+			buf.UnreadRune()
+			return s.String(), nil
+		}
+
+		s.WriteRune(r)
+	}
+}
+
+// Multirange is a generic multirange type.
+//
+// T should implement [RangeValuer] and *T should implement [RangeScanner]. However, there does not appear to be a way to
+// enforce the [RangeScanner] constraint.
+type Multirange[T RangeValuer] []T
+
+func (r Multirange[T]) IsNull() bool {
+	return r == nil
+}
+
+func (r Multirange[T]) Len() int {
+	return len(r)
+}
+
+func (r Multirange[T]) Index(i int) any {
+	return r[i]
+}
+
+func (r Multirange[T]) IndexType() any {
+	var zero T
+	return zero
+}
+
+func (r *Multirange[T]) ScanNull() error {
+	*r = nil
+	return nil
+}
+
+func (r *Multirange[T]) SetLen(n int) error {
+	*r = make([]T, n)
+	return nil
+}
+
+func (r Multirange[T]) ScanIndex(i int) any {
+	return &r[i]
+}
+
+func (r Multirange[T]) ScanIndexType() any {
+	return new(T)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/numeric.go b/vendor/github.com/jackc/pgx/v5/pgtype/numeric.go
new file mode 100644
index 000000000..caf5ff17b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/numeric.go
@@ -0,0 +1,843 @@
+package pgtype
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"math/big"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// PostgreSQL internal numeric storage uses 16-bit "digits" with base of 10,000
+const nbase = 10_000
+
+const (
+	pgNumericNaN     = 0x00000000c0000000
+	pgNumericNaNSign = 0xc000
+
+	pgNumericPosInf     = 0x00000000d0000000
+	pgNumericPosInfSign = 0xd000
+
+	pgNumericNegInf     = 0x00000000f0000000
+	pgNumericNegInfSign = 0xf000
+)
+
+var (
+	big1    *big.Int = big.NewInt(1)
+	big10   *big.Int = big.NewInt(10)
+	big100  *big.Int = big.NewInt(100)
+	big1000 *big.Int = big.NewInt(1000)
+)
+
+var (
+	bigNBase   *big.Int = big.NewInt(nbase)
+	bigNBaseX2 *big.Int = big.NewInt(nbase * nbase)
+	bigNBaseX3 *big.Int = big.NewInt(nbase * nbase * nbase)
+	bigNBaseX4 *big.Int = big.NewInt(nbase * nbase * nbase * nbase)
+)
+
+type NumericScanner interface {
+	ScanNumeric(v Numeric) error
+}
+
+type NumericValuer interface {
+	NumericValue() (Numeric, error)
+}
+
+type Numeric struct {
+	Int              *big.Int
+	Exp              int32
+	NaN              bool
+	InfinityModifier InfinityModifier
+	Valid            bool
+}
+
+// ScanNumeric implements the [NumericScanner] interface.
+func (n *Numeric) ScanNumeric(v Numeric) error {
+	*n = v
+	return nil
+}
+
+// NumericValue implements the [NumericValuer] interface.
+func (n Numeric) NumericValue() (Numeric, error) {
+	return n, nil
+}
+
+// Float64Value implements the [Float64Valuer] interface.
+func (n Numeric) Float64Value() (Float8, error) {
+	switch {
+	case !n.Valid:
+		return Float8{}, nil
+	case n.NaN:
+		return Float8{Float64: math.NaN(), Valid: true}, nil
+	case n.InfinityModifier == Infinity:
+		return Float8{Float64: math.Inf(1), Valid: true}, nil
+	case n.InfinityModifier == NegativeInfinity:
+		return Float8{Float64: math.Inf(-1), Valid: true}, nil
+	}
+
+	buf := make([]byte, 0, 32)
+
+	if n.Int == nil {
+		buf = append(buf, '0')
+	} else {
+		buf = append(buf, n.Int.String()...)
+	}
+	buf = append(buf, 'e')
+	buf = append(buf, strconv.FormatInt(int64(n.Exp), 10)...)
+
+	f, err := strconv.ParseFloat(string(buf), 64)
+	if err != nil {
+		return Float8{}, err
+	}
+
+	return Float8{Float64: f, Valid: true}, nil
+}
+
+// ScanInt64 implements the [Int64Scanner] interface.
+func (n *Numeric) ScanInt64(v Int8) error {
+	if !v.Valid {
+		*n = Numeric{}
+		return nil
+	}
+
+	*n = Numeric{Int: big.NewInt(v.Int64), Valid: true}
+	return nil
+}
+
+// Int64Value implements the [Int64Valuer] interface.
+func (n Numeric) Int64Value() (Int8, error) {
+	if !n.Valid {
+		return Int8{}, nil
+	}
+
+	bi, err := n.toBigInt()
+	if err != nil {
+		return Int8{}, err
+	}
+
+	if !bi.IsInt64() {
+		return Int8{}, fmt.Errorf("cannot convert %v to int64", n)
+	}
+
+	return Int8{Int64: bi.Int64(), Valid: true}, nil
+}
+
+func (n *Numeric) ScanScientific(src string) error {
+	if !strings.ContainsAny(src, "eE") {
+		return scanPlanTextAnyToNumericScanner{}.Scan([]byte(src), n)
+	}
+
+	if bigF, ok := new(big.Float).SetString(src); ok {
+		smallF, _ := bigF.Float64()
+		src = strconv.FormatFloat(smallF, 'f', -1, 64)
+	}
+
+	num, exp, err := parseNumericString(src)
+	if err != nil {
+		return err
+	}
+
+	*n = Numeric{Int: num, Exp: exp, Valid: true}
+
+	return nil
+}
+
+func (n *Numeric) toBigInt() (*big.Int, error) {
+	if n.Exp == 0 {
+		return n.Int, nil
+	}
+
+	num := &big.Int{}
+	num.Set(n.Int)
+	if n.Exp > 0 {
+		mul := &big.Int{}
+		mul.Exp(big10, big.NewInt(int64(n.Exp)), nil)
+		num.Mul(num, mul)
+		return num, nil
+	}
+
+	div := &big.Int{}
+	div.Exp(big10, big.NewInt(int64(-n.Exp)), nil)
+	remainder := &big.Int{}
+	num.DivMod(num, div, remainder)
+	if remainder.Sign() != 0 {
+		return nil, fmt.Errorf("cannot convert %v to integer", n)
+	}
+	return num, nil
+}
+
+func parseNumericString(str string) (n *big.Int, exp int32, err error) {
+	idx := strings.IndexByte(str, '.')
+
+	if idx == -1 {
+		for len(str) > 1 && str[len(str)-1] == '0' && str[len(str)-2] != '-' {
+			str = str[:len(str)-1]
+			exp++
+		}
+	} else {
+		exp = int32(-(len(str) - idx - 1))
+		str = str[:idx] + str[idx+1:]
+	}
+
+	accum := &big.Int{}
+	if _, ok := accum.SetString(str, 10); !ok {
+		return nil, 0, fmt.Errorf("%s is not a number", str)
+	}
+
+	return accum, exp, nil
+}
+
+func nbaseDigitsToInt64(src []byte) (accum int64, bytesRead, digitsRead int) {
+	digits := min(len(src)/2, 4)
+
+	rp := 0
+
+	for i := range digits {
+		if i > 0 {
+			accum *= nbase
+		}
+		accum += int64(binary.BigEndian.Uint16(src[rp:]))
+		rp += 2
+	}
+
+	return accum, rp, digits
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (n *Numeric) Scan(src any) error {
+	if src == nil {
+		*n = Numeric{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToNumericScanner{}.Scan([]byte(src), n)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (n Numeric) Value() (driver.Value, error) {
+	if !n.Valid {
+		return nil, nil
+	}
+
+	buf, err := NumericCodec{}.PlanEncode(nil, 0, TextFormatCode, n).Encode(n, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (n Numeric) MarshalJSON() ([]byte, error) {
+	if !n.Valid {
+		return []byte("null"), nil
+	}
+
+	if n.NaN {
+		return []byte(`"NaN"`), nil
+	}
+
+	return n.numberTextBytes(), nil
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (n *Numeric) UnmarshalJSON(src []byte) error {
+	if bytes.Equal(src, []byte(`null`)) {
+		*n = Numeric{}
+		return nil
+	}
+	if bytes.Equal(src, []byte(`"NaN"`)) {
+		*n = Numeric{NaN: true, Valid: true}
+		return nil
+	}
+	return scanPlanTextAnyToNumericScanner{}.Scan(src, n)
+}
+
+// numberString returns a string of the number. undefined if NaN, infinite, or NULL
+func (n Numeric) numberTextBytes() []byte {
+	if n.Int == nil {
+		return []byte("0")
+	}
+
+	intStr := n.Int.String()
+
+	buf := &bytes.Buffer{}
+
+	if len(intStr) > 0 && intStr[:1] == "-" {
+		intStr = intStr[1:]
+		buf.WriteByte('-')
+	}
+
+	exp := int(n.Exp)
+	switch {
+	case exp > 0:
+		buf.WriteString(intStr)
+		for range exp {
+			buf.WriteByte('0')
+		}
+	case exp < 0:
+		if len(intStr) <= -exp {
+			buf.WriteString("0.")
+			leadingZeros := -exp - len(intStr)
+			for range leadingZeros {
+				buf.WriteByte('0')
+			}
+			buf.WriteString(intStr)
+		} else if len(intStr) > -exp {
+			dpPos := len(intStr) + exp
+			buf.WriteString(intStr[:dpPos])
+			buf.WriteByte('.')
+			buf.WriteString(intStr[dpPos:])
+		}
+	default:
+		buf.WriteString(intStr)
+	}
+
+	return buf.Bytes()
+}
+
+type NumericCodec struct{}
+
+func (NumericCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (NumericCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (NumericCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case NumericValuer:
+			return encodePlanNumericCodecBinaryNumericValuer{}
+		case Float64Valuer:
+			return encodePlanNumericCodecBinaryFloat64Valuer{}
+		case Int64Valuer:
+			return encodePlanNumericCodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case NumericValuer:
+			return encodePlanNumericCodecTextNumericValuer{}
+		case Float64Valuer:
+			return encodePlanNumericCodecTextFloat64Valuer{}
+		case Int64Valuer:
+			return encodePlanNumericCodecTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanNumericCodecBinaryNumericValuer struct{}
+
+func (encodePlanNumericCodecBinaryNumericValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(NumericValuer).NumericValue()
+	if err != nil {
+		return nil, err
+	}
+
+	return encodeNumericBinary(n, buf)
+}
+
+type encodePlanNumericCodecBinaryFloat64Valuer struct{}
+
+func (encodePlanNumericCodecBinaryFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Float64Valuer).Float64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	switch {
+	case math.IsNaN(n.Float64):
+		return encodeNumericBinary(Numeric{NaN: true, Valid: true}, buf)
+	case math.IsInf(n.Float64, 1):
+		return encodeNumericBinary(Numeric{InfinityModifier: Infinity, Valid: true}, buf)
+	case math.IsInf(n.Float64, -1):
+		return encodeNumericBinary(Numeric{InfinityModifier: NegativeInfinity, Valid: true}, buf)
+	}
+	num, exp, err := parseNumericString(strconv.FormatFloat(n.Float64, 'f', -1, 64))
+	if err != nil {
+		return nil, err
+	}
+
+	return encodeNumericBinary(Numeric{Int: num, Exp: exp, Valid: true}, buf)
+}
+
+type encodePlanNumericCodecBinaryInt64Valuer struct{}
+
+func (encodePlanNumericCodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	return encodeNumericBinary(Numeric{Int: big.NewInt(n.Int64), Valid: true}, buf)
+}
+
+func encodeNumericBinary(n Numeric, buf []byte) (newBuf []byte, err error) {
+	if !n.Valid {
+		return nil, nil
+	}
+
+	switch {
+	case n.NaN:
+		buf = pgio.AppendUint64(buf, pgNumericNaN)
+		return buf, nil
+	case n.InfinityModifier == Infinity:
+		buf = pgio.AppendUint64(buf, pgNumericPosInf)
+		return buf, nil
+	case n.InfinityModifier == NegativeInfinity:
+		buf = pgio.AppendUint64(buf, pgNumericNegInf)
+		return buf, nil
+	}
+
+	var sign int16
+	if n.Int != nil && n.Int.Sign() < 0 {
+		sign = 16384
+	}
+
+	absInt := &big.Int{}
+	wholePart := &big.Int{}
+	fracPart := &big.Int{}
+	remainder := &big.Int{}
+	if n.Int != nil {
+		absInt.Abs(n.Int)
+	}
+
+	// Normalize absInt and exp to where exp is always a multiple of 4. This makes
+	// converting to 16-bit base 10,000 digits easier.
+	var exp int32
+	switch n.Exp % 4 {
+	case 1, -3:
+		exp = n.Exp - 1
+		absInt.Mul(absInt, big10)
+	case 2, -2:
+		exp = n.Exp - 2
+		absInt.Mul(absInt, big100)
+	case 3, -1:
+		exp = n.Exp - 3
+		absInt.Mul(absInt, big1000)
+	default:
+		exp = n.Exp
+	}
+
+	if exp < 0 {
+		divisor := &big.Int{}
+		divisor.Exp(big10, big.NewInt(int64(-exp)), nil)
+		wholePart.DivMod(absInt, divisor, fracPart)
+		fracPart.Add(fracPart, divisor)
+	} else {
+		wholePart = absInt
+	}
+
+	var wholeDigits, fracDigits []int16
+
+	for wholePart.Sign() != 0 {
+		wholePart.DivMod(wholePart, bigNBase, remainder)
+		wholeDigits = append(wholeDigits, int16(remainder.Int64()))
+	}
+
+	if fracPart.Sign() != 0 {
+		for fracPart.Cmp(big1) != 0 {
+			fracPart.DivMod(fracPart, bigNBase, remainder)
+			fracDigits = append(fracDigits, int16(remainder.Int64()))
+		}
+	}
+
+	buf = pgio.AppendInt16(buf, int16(len(wholeDigits)+len(fracDigits)))
+
+	var weight int16
+	if len(wholeDigits) > 0 {
+		weight = int16(len(wholeDigits) - 1)
+		if exp > 0 {
+			weight += int16(exp / 4)
+		}
+	} else {
+		weight = int16(exp/4) - 1 + int16(len(fracDigits))
+	}
+	buf = pgio.AppendInt16(buf, weight)
+
+	buf = pgio.AppendInt16(buf, sign)
+
+	var dscale int16
+	if n.Exp < 0 {
+		dscale = int16(-n.Exp)
+	}
+	buf = pgio.AppendInt16(buf, dscale)
+
+	for i := len(wholeDigits) - 1; i >= 0; i-- {
+		buf = pgio.AppendInt16(buf, wholeDigits[i])
+	}
+
+	for i := len(fracDigits) - 1; i >= 0; i-- {
+		buf = pgio.AppendInt16(buf, fracDigits[i])
+	}
+
+	return buf, nil
+}
+
+type encodePlanNumericCodecTextNumericValuer struct{}
+
+func (encodePlanNumericCodecTextNumericValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(NumericValuer).NumericValue()
+	if err != nil {
+		return nil, err
+	}
+
+	return encodeNumericText(n, buf)
+}
+
+type encodePlanNumericCodecTextFloat64Valuer struct{}
+
+func (encodePlanNumericCodecTextFloat64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Float64Valuer).Float64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	switch {
+	case math.IsNaN(n.Float64):
+		buf = append(buf, "NaN"...)
+	case math.IsInf(n.Float64, 1):
+		buf = append(buf, "Infinity"...)
+	case math.IsInf(n.Float64, -1):
+		buf = append(buf, "-Infinity"...)
+	default:
+		buf = append(buf, strconv.FormatFloat(n.Float64, 'f', -1, 64)...)
+	}
+	return buf, nil
+}
+
+type encodePlanNumericCodecTextInt64Valuer struct{}
+
+func (encodePlanNumericCodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	n, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !n.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, strconv.FormatInt(n.Int64, 10)...)
+	return buf, nil
+}
+
+func encodeNumericText(n Numeric, buf []byte) (newBuf []byte, err error) {
+	if !n.Valid {
+		return nil, nil
+	}
+
+	switch {
+	case n.NaN:
+		buf = append(buf, "NaN"...)
+		return buf, nil
+	case n.InfinityModifier == Infinity:
+		buf = append(buf, "Infinity"...)
+		return buf, nil
+	case n.InfinityModifier == NegativeInfinity:
+		buf = append(buf, "-Infinity"...)
+		return buf, nil
+	}
+
+	buf = append(buf, n.numberTextBytes()...)
+
+	return buf, nil
+}
+
+func (NumericCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case NumericScanner:
+			return scanPlanBinaryNumericToNumericScanner{}
+		case Float64Scanner:
+			return scanPlanBinaryNumericToFloat64Scanner{}
+		case Int64Scanner:
+			return scanPlanBinaryNumericToInt64Scanner{}
+		case TextScanner:
+			return scanPlanBinaryNumericToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case NumericScanner:
+			return scanPlanTextAnyToNumericScanner{}
+		case Float64Scanner:
+			return scanPlanTextAnyToFloat64Scanner{}
+		case Int64Scanner:
+			return scanPlanTextAnyToInt64Scanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryNumericToNumericScanner struct{}
+
+func (scanPlanBinaryNumericToNumericScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(NumericScanner)
+
+	if src == nil {
+		return scanner.ScanNumeric(Numeric{})
+	}
+
+	if len(src) < 8 {
+		return fmt.Errorf("numeric incomplete %v", src)
+	}
+
+	rp := 0
+	ndigits := binary.BigEndian.Uint16(src[rp:])
+	rp += 2
+	weight := int16(binary.BigEndian.Uint16(src[rp:]))
+	rp += 2
+	sign := binary.BigEndian.Uint16(src[rp:])
+	rp += 2
+	dscale := int16(binary.BigEndian.Uint16(src[rp:]))
+	rp += 2
+
+	switch sign {
+	case pgNumericNaNSign:
+		return scanner.ScanNumeric(Numeric{NaN: true, Valid: true})
+	case pgNumericPosInfSign:
+		return scanner.ScanNumeric(Numeric{InfinityModifier: Infinity, Valid: true})
+	case pgNumericNegInfSign:
+		return scanner.ScanNumeric(Numeric{InfinityModifier: NegativeInfinity, Valid: true})
+	}
+
+	if ndigits == 0 {
+		return scanner.ScanNumeric(Numeric{Int: big.NewInt(0), Valid: true})
+	}
+
+	if len(src[rp:]) < int(ndigits)*2 {
+		return fmt.Errorf("numeric incomplete %v", src)
+	}
+
+	accum := &big.Int{}
+
+	for i := 0; i < int(ndigits+3)/4; i++ {
+		int64accum, bytesRead, digitsRead := nbaseDigitsToInt64(src[rp:])
+		rp += bytesRead
+
+		if i > 0 {
+			var mul *big.Int
+			switch digitsRead {
+			case 1:
+				mul = bigNBase
+			case 2:
+				mul = bigNBaseX2
+			case 3:
+				mul = bigNBaseX3
+			case 4:
+				mul = bigNBaseX4
+			default:
+				return fmt.Errorf("invalid digitsRead: %d (this can't happen)", digitsRead)
+			}
+			accum.Mul(accum, mul)
+		}
+
+		accum.Add(accum, big.NewInt(int64accum))
+	}
+
+	exp := (int32(weight) - int32(ndigits) + 1) * 4
+
+	if dscale > 0 {
+		fracNBaseDigits := int(ndigits) - int(weight) - 1
+		fracDecimalDigits := fracNBaseDigits * 4
+		dscaleInt := int(dscale)
+
+		if dscaleInt > fracDecimalDigits {
+			multCount := dscaleInt - fracDecimalDigits
+			for range multCount {
+				accum.Mul(accum, big10)
+				exp--
+			}
+		} else if dscaleInt < fracDecimalDigits {
+			divCount := fracDecimalDigits - dscaleInt
+			for range divCount {
+				accum.Div(accum, big10)
+				exp++
+			}
+		}
+	}
+
+	reduced := &big.Int{}
+	remainder := &big.Int{}
+	if exp >= 0 {
+		for {
+			reduced.DivMod(accum, big10, remainder)
+			if remainder.Sign() != 0 {
+				break
+			}
+			accum.Set(reduced)
+			exp++
+		}
+	}
+
+	if sign != 0 {
+		accum.Neg(accum)
+	}
+
+	return scanner.ScanNumeric(Numeric{Int: accum, Exp: exp, Valid: true})
+}
+
+type scanPlanBinaryNumericToFloat64Scanner struct{}
+
+func (scanPlanBinaryNumericToFloat64Scanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(Float64Scanner)
+
+	if src == nil {
+		return scanner.ScanFloat64(Float8{})
+	}
+
+	var n Numeric
+
+	err := scanPlanBinaryNumericToNumericScanner{}.Scan(src, &n)
+	if err != nil {
+		return err
+	}
+
+	f8, err := n.Float64Value()
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanFloat64(f8)
+}
+
+type scanPlanBinaryNumericToInt64Scanner struct{}
+
+func (scanPlanBinaryNumericToInt64Scanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(Int64Scanner)
+
+	if src == nil {
+		return scanner.ScanInt64(Int8{})
+	}
+
+	var n Numeric
+
+	err := scanPlanBinaryNumericToNumericScanner{}.Scan(src, &n)
+	if err != nil {
+		return err
+	}
+
+	bigInt, err := n.toBigInt()
+	if err != nil {
+		return err
+	}
+
+	if !bigInt.IsInt64() {
+		return fmt.Errorf("%v is out of range for int64", bigInt)
+	}
+
+	return scanner.ScanInt64(Int8{Int64: bigInt.Int64(), Valid: true})
+}
+
+type scanPlanBinaryNumericToTextScanner struct{}
+
+func (scanPlanBinaryNumericToTextScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TextScanner)
+
+	if src == nil {
+		return scanner.ScanText(Text{})
+	}
+
+	var n Numeric
+
+	err := scanPlanBinaryNumericToNumericScanner{}.Scan(src, &n)
+	if err != nil {
+		return err
+	}
+
+	sbuf, err := encodeNumericText(n, nil)
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanText(Text{String: string(sbuf), Valid: true})
+}
+
+type scanPlanTextAnyToNumericScanner struct{}
+
+func (scanPlanTextAnyToNumericScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(NumericScanner)
+
+	if src == nil {
+		return scanner.ScanNumeric(Numeric{})
+	}
+
+	switch string(src) {
+	case "NaN":
+		return scanner.ScanNumeric(Numeric{NaN: true, Valid: true})
+	case "Infinity":
+		return scanner.ScanNumeric(Numeric{InfinityModifier: Infinity, Valid: true})
+	case "-Infinity":
+		return scanner.ScanNumeric(Numeric{InfinityModifier: NegativeInfinity, Valid: true})
+	}
+
+	num, exp, err := parseNumericString(string(src))
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanNumeric(Numeric{Int: num, Exp: exp, Valid: true})
+}
+
+func (c NumericCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	if format == TextFormatCode {
+		return string(src), nil
+	}
+
+	var n Numeric
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+
+	buf, err := m.Encode(oid, TextFormatCode, n, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), nil
+}
+
+func (c NumericCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n Numeric
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/path.go b/vendor/github.com/jackc/pgx/v5/pgtype/path.go
new file mode 100644
index 000000000..6398b5815
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/path.go
@@ -0,0 +1,280 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type PathScanner interface {
+	ScanPath(v Path) error
+}
+
+type PathValuer interface {
+	PathValue() (Path, error)
+}
+
+type Path struct {
+	P      []Vec2
+	Closed bool
+	Valid  bool
+}
+
+// ScanPath implements the [PathScanner] interface.
+func (path *Path) ScanPath(v Path) error {
+	*path = v
+	return nil
+}
+
+// PathValue implements the [PathValuer] interface.
+func (path Path) PathValue() (Path, error) {
+	return path, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (path *Path) Scan(src any) error {
+	if src == nil {
+		*path = Path{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToPathScanner{}.Scan([]byte(src), path)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (path Path) Value() (driver.Value, error) {
+	if !path.Valid {
+		return nil, nil
+	}
+
+	buf, err := PathCodec{}.PlanEncode(nil, 0, TextFormatCode, path).Encode(path, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return string(buf), err
+}
+
+type PathCodec struct{}
+
+func (PathCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (PathCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (PathCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(PathValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanPathCodecBinary{}
+	case TextFormatCode:
+		return encodePlanPathCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanPathCodecBinary struct{}
+
+func (encodePlanPathCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	path, err := value.(PathValuer).PathValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !path.Valid {
+		return nil, nil
+	}
+
+	var closeByte byte
+	if path.Closed {
+		closeByte = 1
+	}
+	buf = append(buf, closeByte)
+
+	buf = pgio.AppendInt32(buf, int32(len(path.P)))
+
+	for _, p := range path.P {
+		buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
+		buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
+	}
+
+	return buf, nil
+}
+
+type encodePlanPathCodecText struct{}
+
+func (encodePlanPathCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	path, err := value.(PathValuer).PathValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !path.Valid {
+		return nil, nil
+	}
+
+	var startByte, endByte byte
+	if path.Closed {
+		startByte = '('
+		endByte = ')'
+	} else {
+		startByte = '['
+		endByte = ']'
+	}
+	buf = append(buf, startByte)
+
+	for i, p := range path.P {
+		if i > 0 {
+			buf = append(buf, ',')
+		}
+		buf = append(buf, fmt.Sprintf(`(%s,%s)`,
+			strconv.FormatFloat(p.X, 'f', -1, 64),
+			strconv.FormatFloat(p.Y, 'f', -1, 64),
+		)...)
+	}
+
+	buf = append(buf, endByte)
+
+	return buf, nil
+}
+
+func (PathCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(PathScanner); ok {
+			return scanPlanBinaryPathToPathScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(PathScanner); ok {
+			return scanPlanTextAnyToPathScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryPathToPathScanner struct{}
+
+func (scanPlanBinaryPathToPathScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(PathScanner)
+
+	if src == nil {
+		return scanner.ScanPath(Path{})
+	}
+
+	if len(src) < 5 {
+		return fmt.Errorf("invalid length for Path: %v", len(src))
+	}
+
+	closed := src[0] == 1
+	pointCount := int(binary.BigEndian.Uint32(src[1:]))
+
+	rp := 5
+
+	if 5+pointCount*16 != len(src) {
+		return fmt.Errorf("invalid length for Path with %d points: %v", pointCount, len(src))
+	}
+
+	points := make([]Vec2, pointCount)
+	for i := range points {
+		x := binary.BigEndian.Uint64(src[rp:])
+		rp += 8
+		y := binary.BigEndian.Uint64(src[rp:])
+		rp += 8
+		points[i] = Vec2{math.Float64frombits(x), math.Float64frombits(y)}
+	}
+
+	return scanner.ScanPath(Path{
+		P:      points,
+		Closed: closed,
+		Valid:  true,
+	})
+}
+
+type scanPlanTextAnyToPathScanner struct{}
+
+func (scanPlanTextAnyToPathScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(PathScanner)
+
+	if src == nil {
+		return scanner.ScanPath(Path{})
+	}
+
+	if len(src) < 7 {
+		return fmt.Errorf("invalid length for Path: %v", len(src))
+	}
+
+	closed := src[0] == '('
+	points := make([]Vec2, 0)
+
+	// Expected format: ((x1,y1),...,(xn,yn)) or [(x1,y1),...,(xn,yn)]
+	str := string(src[1 : len(src)-1])
+
+	for {
+		if len(str) == 0 || str[0] != '(' {
+			return fmt.Errorf("invalid format for Path")
+		}
+		body, rest, found := strings.Cut(str[1:], ")")
+		if !found {
+			return fmt.Errorf("invalid format for Path")
+		}
+
+		sx, sy, found := strings.Cut(body, ",")
+		if !found {
+			return fmt.Errorf("invalid format for Path")
+		}
+		x, err := strconv.ParseFloat(sx, 64)
+		if err != nil {
+			return err
+		}
+		y, err := strconv.ParseFloat(sy, 64)
+		if err != nil {
+			return err
+		}
+
+		points = append(points, Vec2{x, y})
+
+		if rest == "" {
+			break
+		}
+		str, found = strings.CutPrefix(rest, ",")
+		if !found {
+			return fmt.Errorf("invalid format for Path")
+		}
+	}
+
+	return scanner.ScanPath(Path{P: points, Closed: closed, Valid: true})
+}
+
+func (c PathCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c PathCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var path Path
+	err := codecScan(c, m, oid, format, src, &path)
+	if err != nil {
+		return nil, err
+	}
+	return path, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go b/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go
new file mode 100644
index 000000000..46b892bfb
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/pgtype.go
@@ -0,0 +1,2067 @@
+package pgtype
+
+import (
+	"database/sql"
+	"database/sql/driver"
+	"errors"
+	"fmt"
+	"net"
+	"net/netip"
+	"reflect"
+	"time"
+)
+
+// PostgreSQL oids for common types
+const (
+	BoolOID                = 16
+	ByteaOID               = 17
+	QCharOID               = 18
+	NameOID                = 19
+	Int8OID                = 20
+	Int2OID                = 21
+	Int4OID                = 23
+	TextOID                = 25
+	OIDOID                 = 26
+	TIDOID                 = 27
+	XIDOID                 = 28
+	CIDOID                 = 29
+	JSONOID                = 114
+	XMLOID                 = 142
+	XMLArrayOID            = 143
+	JSONArrayOID           = 199
+	XID8ArrayOID           = 271
+	PointOID               = 600
+	LsegOID                = 601
+	PathOID                = 602
+	BoxOID                 = 603
+	PolygonOID             = 604
+	LineOID                = 628
+	LineArrayOID           = 629
+	CIDROID                = 650
+	CIDRArrayOID           = 651
+	Float4OID              = 700
+	Float8OID              = 701
+	CircleOID              = 718
+	CircleArrayOID         = 719
+	UnknownOID             = 705
+	Macaddr8OID            = 774
+	MacaddrOID             = 829
+	InetOID                = 869
+	BoolArrayOID           = 1000
+	QCharArrayOID          = 1002
+	NameArrayOID           = 1003
+	Int2ArrayOID           = 1005
+	Int4ArrayOID           = 1007
+	TextArrayOID           = 1009
+	TIDArrayOID            = 1010
+	ByteaArrayOID          = 1001
+	XIDArrayOID            = 1011
+	CIDArrayOID            = 1012
+	BPCharArrayOID         = 1014
+	VarcharArrayOID        = 1015
+	Int8ArrayOID           = 1016
+	PointArrayOID          = 1017
+	LsegArrayOID           = 1018
+	PathArrayOID           = 1019
+	BoxArrayOID            = 1020
+	Float4ArrayOID         = 1021
+	Float8ArrayOID         = 1022
+	PolygonArrayOID        = 1027
+	OIDArrayOID            = 1028
+	ACLItemOID             = 1033
+	ACLItemArrayOID        = 1034
+	MacaddrArrayOID        = 1040
+	InetArrayOID           = 1041
+	BPCharOID              = 1042
+	VarcharOID             = 1043
+	DateOID                = 1082
+	TimeOID                = 1083
+	TimestampOID           = 1114
+	TimestampArrayOID      = 1115
+	DateArrayOID           = 1182
+	TimeArrayOID           = 1183
+	TimestamptzOID         = 1184
+	TimestamptzArrayOID    = 1185
+	IntervalOID            = 1186
+	IntervalArrayOID       = 1187
+	NumericArrayOID        = 1231
+	TimetzOID              = 1266
+	TimetzArrayOID         = 1270
+	BitOID                 = 1560
+	BitArrayOID            = 1561
+	VarbitOID              = 1562
+	VarbitArrayOID         = 1563
+	NumericOID             = 1700
+	RecordOID              = 2249
+	RecordArrayOID         = 2287
+	UUIDOID                = 2950
+	UUIDArrayOID           = 2951
+	TSVectorOID            = 3614
+	TSVectorArrayOID       = 3643
+	JSONBOID               = 3802
+	JSONBArrayOID          = 3807
+	DaterangeOID           = 3912
+	DaterangeArrayOID      = 3913
+	Int4rangeOID           = 3904
+	Int4rangeArrayOID      = 3905
+	NumrangeOID            = 3906
+	NumrangeArrayOID       = 3907
+	TsrangeOID             = 3908
+	TsrangeArrayOID        = 3909
+	TstzrangeOID           = 3910
+	TstzrangeArrayOID      = 3911
+	Int8rangeOID           = 3926
+	Int8rangeArrayOID      = 3927
+	JSONPathOID            = 4072
+	JSONPathArrayOID       = 4073
+	Int4multirangeOID      = 4451
+	NummultirangeOID       = 4532
+	TsmultirangeOID        = 4533
+	TstzmultirangeOID      = 4534
+	DatemultirangeOID      = 4535
+	Int8multirangeOID      = 4536
+	XID8OID                = 5069
+	Int4multirangeArrayOID = 6150
+	NummultirangeArrayOID  = 6151
+	TsmultirangeArrayOID   = 6152
+	TstzmultirangeArrayOID = 6153
+	DatemultirangeArrayOID = 6155
+	Int8multirangeArrayOID = 6157
+)
+
+type InfinityModifier int8
+
+const (
+	Infinity         InfinityModifier = 1
+	Finite           InfinityModifier = 0
+	NegativeInfinity InfinityModifier = -Infinity
+)
+
+func (im InfinityModifier) String() string {
+	switch im {
+	case Finite:
+		return "finite"
+	case Infinity:
+		return "infinity"
+	case NegativeInfinity:
+		return "-infinity"
+	default:
+		return "invalid"
+	}
+}
+
+// PostgreSQL format codes
+const (
+	TextFormatCode   = 0
+	BinaryFormatCode = 1
+)
+
+// A Codec converts between Go and PostgreSQL values. A Codec must not be mutated after it is registered with a [Map].
+type Codec interface {
+	// FormatSupported returns true if the format is supported.
+	FormatSupported(int16) bool
+
+	// PreferredFormat returns the preferred format.
+	PreferredFormat() int16
+
+	// PlanEncode returns an EncodePlan for encoding value into PostgreSQL format for oid and format. If no plan can be
+	// found then nil is returned.
+	PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan
+
+	// PlanScan returns a ScanPlan for scanning a PostgreSQL value into a destination with the same type as target. If
+	// no plan can be found then nil is returned.
+	PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan
+
+	// DecodeDatabaseSQLValue returns src decoded into a value compatible with the sql.Scanner interface.
+	DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error)
+
+	// DecodeValue returns src decoded into its default format.
+	DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error)
+}
+
+type nullAssignmentError struct {
+	dst any
+}
+
+func (e *nullAssignmentError) Error() string {
+	return fmt.Sprintf("cannot assign NULL to %T", e.dst)
+}
+
+// Type represents a PostgreSQL data type. It must not be mutated after it is registered with a [Map].
+type Type struct {
+	Codec Codec
+	Name  string
+	OID   uint32
+}
+
+// Map is the mapping between PostgreSQL server types and Go type handling logic. It can encode values for
+// transmission to a PostgreSQL server and scan received values.
+type Map struct {
+	oidToType         map[uint32]*Type
+	nameToType        map[string]*Type
+	reflectTypeToName map[reflect.Type]string
+	oidToFormatCode   map[uint32]int16
+
+	reflectTypeToType map[reflect.Type]*Type
+
+	memoizedEncodePlans map[uint32]map[reflect.Type][2]EncodePlan
+
+	// TryWrapEncodePlanFuncs is a slice of functions that will wrap a value that cannot be encoded by the Codec. Every
+	// time a wrapper is found the PlanEncode method will be recursively called with the new value. This allows several layers of wrappers
+	// to be built up. There are default functions placed in this slice by NewMap(). In most cases these functions
+	// should run last. i.e. Additional functions should typically be prepended not appended.
+	TryWrapEncodePlanFuncs []TryWrapEncodePlanFunc
+
+	// TryWrapScanPlanFuncs is a slice of functions that will wrap a target that cannot be scanned into by the Codec. Every
+	// time a wrapper is found the PlanScan method will be recursively called with the new target. This allows several layers of wrappers
+	// to be built up. There are default functions placed in this slice by NewMap(). In most cases these functions
+	// should run last. i.e. Additional functions should typically be prepended not appended.
+	TryWrapScanPlanFuncs []TryWrapScanPlanFunc
+}
+
+// Copy returns a new Map containing the same registered types.
+func (m *Map) Copy() *Map {
+	newMap := NewMap()
+	for _, type_ := range m.oidToType {
+		newMap.RegisterType(type_)
+	}
+	return newMap
+}
+
+func NewMap() *Map {
+	defaultMapInitOnce.Do(initDefaultMap)
+
+	return &Map{
+		oidToType:         make(map[uint32]*Type),
+		nameToType:        make(map[string]*Type),
+		reflectTypeToName: make(map[reflect.Type]string),
+		oidToFormatCode:   make(map[uint32]int16),
+
+		memoizedEncodePlans: make(map[uint32]map[reflect.Type][2]EncodePlan),
+
+		TryWrapEncodePlanFuncs: []TryWrapEncodePlanFunc{
+			TryWrapDerefPointerEncodePlan,
+			TryWrapBuiltinTypeEncodePlan,
+			TryWrapFindUnderlyingTypeEncodePlan,
+			TryWrapStringerEncodePlan,
+			TryWrapStructEncodePlan,
+			TryWrapSliceEncodePlan,
+			TryWrapMultiDimSliceEncodePlan,
+			TryWrapArrayEncodePlan,
+		},
+
+		TryWrapScanPlanFuncs: []TryWrapScanPlanFunc{
+			TryPointerPointerScanPlan,
+			TryWrapBuiltinTypeScanPlan,
+			TryFindUnderlyingTypeScanPlan,
+			TryWrapStructScanPlan,
+			TryWrapPtrSliceScanPlan,
+			TryWrapPtrMultiDimSliceScanPlan,
+			TryWrapPtrArrayScanPlan,
+		},
+	}
+}
+
+// RegisterTypes registers multiple data types in the sequence they are provided.
+func (m *Map) RegisterTypes(types []*Type) {
+	for _, t := range types {
+		m.RegisterType(t)
+	}
+}
+
+// RegisterType registers a data type with the [Map]. t must not be mutated after it is registered.
+func (m *Map) RegisterType(t *Type) {
+	m.oidToType[t.OID] = t
+	m.nameToType[t.Name] = t
+	m.oidToFormatCode[t.OID] = t.Codec.PreferredFormat()
+
+	// Invalidated by type registration
+	m.reflectTypeToType = nil
+	for k := range m.memoizedEncodePlans {
+		delete(m.memoizedEncodePlans, k)
+	}
+}
+
+// RegisterDefaultPgType registers a mapping of a Go type to a PostgreSQL type name. Typically the data type to be
+// encoded or decoded is determined by the PostgreSQL OID. But if the OID of a value to be encoded or decoded is
+// unknown, this additional mapping will be used by TypeForValue to determine a suitable data type.
+func (m *Map) RegisterDefaultPgType(value any, name string) {
+	m.reflectTypeToName[reflect.TypeOf(value)] = name
+
+	// Invalidated by type registration
+	m.reflectTypeToType = nil
+	for k := range m.memoizedEncodePlans {
+		delete(m.memoizedEncodePlans, k)
+	}
+}
+
+// TypeForOID returns the [Type] registered for the given OID. The returned [Type] must not be mutated.
+func (m *Map) TypeForOID(oid uint32) (*Type, bool) {
+	if dt, ok := m.oidToType[oid]; ok {
+		return dt, true
+	}
+
+	dt, ok := defaultMap.oidToType[oid]
+	return dt, ok
+}
+
+// TypeForName returns the [Type] registered for the given name. The returned [Type] must not be mutated.
+func (m *Map) TypeForName(name string) (*Type, bool) {
+	if dt, ok := m.nameToType[name]; ok {
+		return dt, true
+	}
+	dt, ok := defaultMap.nameToType[name]
+	return dt, ok
+}
+
+func (m *Map) buildReflectTypeToType() {
+	m.reflectTypeToType = make(map[reflect.Type]*Type)
+
+	for reflectType, name := range m.reflectTypeToName {
+		if dt, ok := m.TypeForName(name); ok {
+			m.reflectTypeToType[reflectType] = dt
+		}
+	}
+}
+
+// TypeForValue finds a data type suitable for v. Use [Map.RegisterType] to register types that can encode and decode
+// themselves. Use [Map.RegisterDefaultPgType] to register that can be handled by a registered data type.  The returned [Type]
+// must not be mutated.
+func (m *Map) TypeForValue(v any) (*Type, bool) {
+	if m.reflectTypeToType == nil {
+		m.buildReflectTypeToType()
+	}
+
+	if dt, ok := m.reflectTypeToType[reflect.TypeOf(v)]; ok {
+		return dt, true
+	}
+
+	dt, ok := defaultMap.reflectTypeToType[reflect.TypeOf(v)]
+	return dt, ok
+}
+
+// FormatCodeForOID returns the preferred format code for type oid. If the type is not registered it returns the text
+// format code.
+func (m *Map) FormatCodeForOID(oid uint32) int16 {
+	if fc, ok := m.oidToFormatCode[oid]; ok {
+		return fc
+	}
+
+	if fc, ok := defaultMap.oidToFormatCode[oid]; ok {
+		return fc
+	}
+
+	return TextFormatCode
+}
+
+// EncodePlan is a precompiled plan to encode a particular type into a particular OID and format.
+type EncodePlan interface {
+	// Encode appends the encoded bytes of value to buf. If value is the SQL value NULL then append nothing and return
+	// (nil, nil). The caller of Encode is responsible for writing the correct NULL value or the length of the data
+	// written.
+	Encode(value any, buf []byte) (newBuf []byte, err error)
+}
+
+// ScanPlan is a precompiled plan to scan into a type of destination.
+type ScanPlan interface {
+	// Scan scans src into target. src is only valid during the call to Scan. The ScanPlan must not retain a reference to
+	// src.
+	Scan(src []byte, target any) error
+}
+
+type scanPlanCodecSQLScanner struct {
+	c          Codec
+	m          *Map
+	oid        uint32
+	formatCode int16
+}
+
+func (plan *scanPlanCodecSQLScanner) Scan(src []byte, dst any) error {
+	value, err := plan.c.DecodeDatabaseSQLValue(plan.m, plan.oid, plan.formatCode, src)
+	if err != nil {
+		return err
+	}
+
+	scanner := dst.(sql.Scanner)
+	return scanner.Scan(value)
+}
+
+type scanPlanSQLScanner struct {
+	formatCode int16
+}
+
+func (plan *scanPlanSQLScanner) Scan(src []byte, dst any) error {
+	scanner := dst.(sql.Scanner)
+
+	switch {
+	case src == nil:
+		// This is necessary because interface value []byte:nil does not equal nil:nil for the binary format path and the
+		// text format path would be converted to empty string.
+		return scanner.Scan(nil)
+	case plan.formatCode == BinaryFormatCode:
+		return scanner.Scan(src)
+	default:
+		return scanner.Scan(string(src))
+	}
+}
+
+type scanPlanString struct{}
+
+func (scanPlanString) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p := (dst).(*string)
+	*p = string(src)
+	return nil
+}
+
+type scanPlanAnyTextToBytes struct{}
+
+func (scanPlanAnyTextToBytes) Scan(src []byte, dst any) error {
+	dstBuf := dst.(*[]byte)
+	if src == nil {
+		*dstBuf = nil
+		return nil
+	}
+
+	*dstBuf = make([]byte, len(src))
+	copy(*dstBuf, src)
+	return nil
+}
+
+type scanPlanFail struct {
+	m          *Map
+	oid        uint32
+	formatCode int16
+}
+
+func (plan *scanPlanFail) Scan(src []byte, dst any) error {
+	// If src is NULL it might be possible to scan into dst even though it is the types are not compatible. While this
+	// may seem to be a contrived case it can occur when selecting NULL directly. PostgreSQL assigns it the type of text.
+	// It would be surprising to the caller to have to cast the NULL (e.g. `select null::int`). So try to figure out a
+	// compatible data type for dst and scan with that.
+	//
+	// See https://github.com/jackc/pgx/issues/1326
+	if src == nil {
+		// As a horrible hack try all types to find anything that can scan into dst.
+		for oid := range plan.m.oidToType {
+			// using planScan instead of Scan or PlanScan to avoid polluting the planned scan cache.
+			plan := plan.m.planScan(oid, plan.formatCode, dst, 0)
+			if _, ok := plan.(*scanPlanFail); !ok {
+				return plan.Scan(src, dst)
+			}
+		}
+		for oid := range defaultMap.oidToType {
+			if _, ok := plan.m.oidToType[oid]; !ok {
+				plan := plan.m.planScan(oid, plan.formatCode, dst, 0)
+				if _, ok := plan.(*scanPlanFail); !ok {
+					return plan.Scan(src, dst)
+				}
+			}
+		}
+	}
+
+	var format string
+	switch plan.formatCode {
+	case TextFormatCode:
+		format = "text"
+	case BinaryFormatCode:
+		format = "binary"
+	default:
+		format = fmt.Sprintf("unknown %d", plan.formatCode)
+	}
+
+	var dataTypeName string
+	if t, ok := plan.m.TypeForOID(plan.oid); ok {
+		dataTypeName = t.Name
+	} else {
+		dataTypeName = "unknown type"
+	}
+
+	return fmt.Errorf("cannot scan %s (OID %d) in %v format into %T", dataTypeName, plan.oid, format, dst)
+}
+
+// TryWrapScanPlanFunc is a function that tries to create a wrapper plan for target. If successful it returns a plan
+// that will convert the target passed to Scan and then call the next plan. nextTarget is target as it will be converted
+// by plan. It must be used to find another suitable ScanPlan. When it is found SetNext must be called on plan for it
+// to be usabled. ok indicates if a suitable wrapper was found.
+type TryWrapScanPlanFunc func(target any) (plan WrappedScanPlanNextSetter, nextTarget any, ok bool)
+
+type pointerPointerScanPlan struct {
+	dstType reflect.Type
+	next    ScanPlan
+}
+
+func (plan *pointerPointerScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *pointerPointerScanPlan) Scan(src []byte, dst any) error {
+	el := reflect.ValueOf(dst).Elem()
+	if src == nil {
+		el.Set(reflect.Zero(el.Type()))
+		return nil
+	}
+
+	el.Set(reflect.New(el.Type().Elem()))
+	return plan.next.Scan(src, el.Interface())
+}
+
+// TryPointerPointerScanPlan handles a pointer to a pointer by setting the target to nil for SQL NULL and allocating and
+// scanning for non-NULL.
+func TryPointerPointerScanPlan(target any) (plan WrappedScanPlanNextSetter, nextTarget any, ok bool) {
+	if dstValue := reflect.ValueOf(target); dstValue.Kind() == reflect.Pointer {
+		elemValue := dstValue.Elem()
+		if elemValue.Kind() == reflect.Pointer {
+			plan = &pointerPointerScanPlan{dstType: dstValue.Type()}
+			return plan, reflect.Zero(elemValue.Type()).Interface(), true
+		}
+	}
+
+	return nil, nil, false
+}
+
+// SkipUnderlyingTypePlanner prevents PlanScan and PlanDecode from trying to use the underlying type.
+type SkipUnderlyingTypePlanner interface {
+	SkipUnderlyingTypePlan()
+}
+
+var elemKindToPointerTypes map[reflect.Kind]reflect.Type = map[reflect.Kind]reflect.Type{
+	reflect.Int:     reflect.TypeFor[*int](),
+	reflect.Int8:    reflect.TypeFor[*int8](),
+	reflect.Int16:   reflect.TypeFor[*int16](),
+	reflect.Int32:   reflect.TypeFor[*int32](),
+	reflect.Int64:   reflect.TypeFor[*int64](),
+	reflect.Uint:    reflect.TypeFor[*uint](),
+	reflect.Uint8:   reflect.TypeFor[*uint8](),
+	reflect.Uint16:  reflect.TypeFor[*uint16](),
+	reflect.Uint32:  reflect.TypeFor[*uint32](),
+	reflect.Uint64:  reflect.TypeFor[*uint64](),
+	reflect.Float32: reflect.TypeFor[*float32](),
+	reflect.Float64: reflect.TypeFor[*float64](),
+	reflect.String:  reflect.TypeFor[*string](),
+	reflect.Bool:    reflect.TypeFor[*bool](),
+}
+
+type underlyingTypeScanPlan struct {
+	dstType     reflect.Type
+	nextDstType reflect.Type
+	next        ScanPlan
+}
+
+func (plan *underlyingTypeScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *underlyingTypeScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, reflect.ValueOf(dst).Convert(plan.nextDstType).Interface())
+}
+
+// TryFindUnderlyingTypeScanPlan tries to convert to a Go builtin type. e.g. If value was of type MyString and
+// MyString was defined as a string then a wrapper plan would be returned that converts MyString to string.
+func TryFindUnderlyingTypeScanPlan(dst any) (plan WrappedScanPlanNextSetter, nextDst any, ok bool) {
+	if _, ok := dst.(SkipUnderlyingTypePlanner); ok {
+		return nil, nil, false
+	}
+
+	dstValue := reflect.ValueOf(dst)
+
+	if dstValue.Kind() == reflect.Pointer {
+		var elemValue reflect.Value
+		if dstValue.IsNil() {
+			elemValue = reflect.New(dstValue.Type().Elem()).Elem()
+		} else {
+			elemValue = dstValue.Elem()
+		}
+		nextDstType := elemKindToPointerTypes[elemValue.Kind()]
+		if nextDstType == nil {
+			if elemValue.Kind() == reflect.Slice {
+				if elemValue.Type().Elem().Kind() == reflect.Uint8 {
+					var v *[]byte
+					nextDstType = reflect.TypeOf(v)
+				}
+			}
+
+			// Get underlying type of any array.
+			// https://github.com/jackc/pgx/issues/2107
+			if elemValue.Kind() == reflect.Array {
+				nextDstType = reflect.PointerTo(reflect.ArrayOf(elemValue.Len(), elemValue.Type().Elem()))
+			}
+		}
+
+		if nextDstType != nil && dstValue.Type() != nextDstType && dstValue.CanConvert(nextDstType) {
+			return &underlyingTypeScanPlan{dstType: dstValue.Type(), nextDstType: nextDstType}, dstValue.Convert(nextDstType).Interface(), true
+		}
+	}
+
+	return nil, nil, false
+}
+
+type WrappedScanPlanNextSetter interface {
+	SetNext(ScanPlan)
+	ScanPlan
+}
+
+// TryWrapBuiltinTypeScanPlan tries to wrap a builtin type with a wrapper that provides additional methods. e.g. If
+// value was of type int32 then a wrapper plan would be returned that converts target to a value that implements
+// Int64Scanner.
+func TryWrapBuiltinTypeScanPlan(target any) (plan WrappedScanPlanNextSetter, nextDst any, ok bool) {
+	switch target := target.(type) {
+	case *int8:
+		return &wrapInt8ScanPlan{}, (*int8Wrapper)(target), true
+	case *int16:
+		return &wrapInt16ScanPlan{}, (*int16Wrapper)(target), true
+	case *int32:
+		return &wrapInt32ScanPlan{}, (*int32Wrapper)(target), true
+	case *int64:
+		return &wrapInt64ScanPlan{}, (*int64Wrapper)(target), true
+	case *int:
+		return &wrapIntScanPlan{}, (*intWrapper)(target), true
+	case *uint8:
+		return &wrapUint8ScanPlan{}, (*uint8Wrapper)(target), true
+	case *uint16:
+		return &wrapUint16ScanPlan{}, (*uint16Wrapper)(target), true
+	case *uint32:
+		return &wrapUint32ScanPlan{}, (*uint32Wrapper)(target), true
+	case *uint64:
+		return &wrapUint64ScanPlan{}, (*uint64Wrapper)(target), true
+	case *uint:
+		return &wrapUintScanPlan{}, (*uintWrapper)(target), true
+	case *float32:
+		return &wrapFloat32ScanPlan{}, (*float32Wrapper)(target), true
+	case *float64:
+		return &wrapFloat64ScanPlan{}, (*float64Wrapper)(target), true
+	case *string:
+		return &wrapStringScanPlan{}, (*stringWrapper)(target), true
+	case *time.Time:
+		return &wrapTimeScanPlan{}, (*timeWrapper)(target), true
+	case *time.Duration:
+		return &wrapDurationScanPlan{}, (*durationWrapper)(target), true
+	case *net.IPNet:
+		return &wrapNetIPNetScanPlan{}, (*netIPNetWrapper)(target), true
+	case *net.IP:
+		return &wrapNetIPScanPlan{}, (*netIPWrapper)(target), true
+	case *netip.Prefix:
+		return &wrapNetipPrefixScanPlan{}, (*netipPrefixWrapper)(target), true
+	case *netip.Addr:
+		return &wrapNetipAddrScanPlan{}, (*netipAddrWrapper)(target), true
+	case *map[string]*string:
+		return &wrapMapStringToPointerStringScanPlan{}, (*mapStringToPointerStringWrapper)(target), true
+	case *map[string]string:
+		return &wrapMapStringToStringScanPlan{}, (*mapStringToStringWrapper)(target), true
+	case *[16]byte:
+		return &wrapByte16ScanPlan{}, (*byte16Wrapper)(target), true
+	case *[]byte:
+		return &wrapByteSliceScanPlan{}, (*byteSliceWrapper)(target), true
+	}
+
+	return nil, nil, false
+}
+
+type wrapInt8ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapInt8ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapInt8ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*int8Wrapper)(dst.(*int8)))
+}
+
+type wrapInt16ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapInt16ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapInt16ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*int16Wrapper)(dst.(*int16)))
+}
+
+type wrapInt32ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapInt32ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapInt32ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*int32Wrapper)(dst.(*int32)))
+}
+
+type wrapInt64ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapInt64ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapInt64ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*int64Wrapper)(dst.(*int64)))
+}
+
+type wrapIntScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapIntScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapIntScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*intWrapper)(dst.(*int)))
+}
+
+type wrapUint8ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapUint8ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapUint8ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*uint8Wrapper)(dst.(*uint8)))
+}
+
+type wrapUint16ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapUint16ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapUint16ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*uint16Wrapper)(dst.(*uint16)))
+}
+
+type wrapUint32ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapUint32ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapUint32ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*uint32Wrapper)(dst.(*uint32)))
+}
+
+type wrapUint64ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapUint64ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapUint64ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*uint64Wrapper)(dst.(*uint64)))
+}
+
+type wrapUintScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapUintScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapUintScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*uintWrapper)(dst.(*uint)))
+}
+
+type wrapFloat32ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapFloat32ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapFloat32ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*float32Wrapper)(dst.(*float32)))
+}
+
+type wrapFloat64ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapFloat64ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapFloat64ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*float64Wrapper)(dst.(*float64)))
+}
+
+type wrapStringScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapStringScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapStringScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*stringWrapper)(dst.(*string)))
+}
+
+type wrapTimeScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapTimeScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapTimeScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*timeWrapper)(dst.(*time.Time)))
+}
+
+type wrapDurationScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapDurationScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapDurationScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*durationWrapper)(dst.(*time.Duration)))
+}
+
+type wrapNetIPNetScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapNetIPNetScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapNetIPNetScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*netIPNetWrapper)(dst.(*net.IPNet)))
+}
+
+type wrapNetIPScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapNetIPScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapNetIPScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*netIPWrapper)(dst.(*net.IP)))
+}
+
+type wrapNetipPrefixScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapNetipPrefixScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapNetipPrefixScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*netipPrefixWrapper)(dst.(*netip.Prefix)))
+}
+
+type wrapNetipAddrScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapNetipAddrScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapNetipAddrScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*netipAddrWrapper)(dst.(*netip.Addr)))
+}
+
+type wrapMapStringToPointerStringScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapMapStringToPointerStringScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapMapStringToPointerStringScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*mapStringToPointerStringWrapper)(dst.(*map[string]*string)))
+}
+
+type wrapMapStringToStringScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapMapStringToStringScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapMapStringToStringScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*mapStringToStringWrapper)(dst.(*map[string]string)))
+}
+
+type wrapByte16ScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapByte16ScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapByte16ScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*byte16Wrapper)(dst.(*[16]byte)))
+}
+
+type wrapByteSliceScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapByteSliceScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapByteSliceScanPlan) Scan(src []byte, dst any) error {
+	return plan.next.Scan(src, (*byteSliceWrapper)(dst.(*[]byte)))
+}
+
+type pointerEmptyInterfaceScanPlan struct {
+	codec      Codec
+	m          *Map
+	oid        uint32
+	formatCode int16
+}
+
+func (plan *pointerEmptyInterfaceScanPlan) Scan(src []byte, dst any) error {
+	value, err := plan.codec.DecodeValue(plan.m, plan.oid, plan.formatCode, src)
+	if err != nil {
+		return err
+	}
+
+	ptrAny := dst.(*any)
+	*ptrAny = value
+
+	return nil
+}
+
+// TryWrapStructScanPlan tries to wrap a struct with a wrapper that implements CompositeIndexGetter.
+func TryWrapStructScanPlan(target any) (plan WrappedScanPlanNextSetter, nextValue any, ok bool) {
+	targetValue := reflect.ValueOf(target)
+	if targetValue.Kind() != reflect.Pointer {
+		return nil, nil, false
+	}
+
+	var targetElemValue reflect.Value
+	if targetValue.IsNil() {
+		targetElemValue = reflect.Zero(targetValue.Type().Elem())
+	} else {
+		targetElemValue = targetValue.Elem()
+	}
+	targetElemType := targetElemValue.Type()
+
+	if targetElemType.Kind() == reflect.Struct {
+		exportedFields := getExportedFieldValues(targetElemValue)
+		if len(exportedFields) == 0 {
+			return nil, nil, false
+		}
+
+		w := ptrStructWrapper{
+			s:              target,
+			exportedFields: exportedFields,
+		}
+		return &wrapAnyPtrStructScanPlan{}, &w, true
+	}
+
+	return nil, nil, false
+}
+
+type wrapAnyPtrStructScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapAnyPtrStructScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapAnyPtrStructScanPlan) Scan(src []byte, target any) error {
+	w := ptrStructWrapper{
+		s:              target,
+		exportedFields: getExportedFieldValues(reflect.ValueOf(target).Elem()),
+	}
+
+	return plan.next.Scan(src, &w)
+}
+
+// TryWrapPtrSliceScanPlan tries to wrap a pointer to a single dimension slice.
+func TryWrapPtrSliceScanPlan(target any) (plan WrappedScanPlanNextSetter, nextValue any, ok bool) {
+	// Avoid using reflect path for common types.
+	switch target := target.(type) {
+	case *[]int16:
+		return &wrapPtrSliceScanPlan[int16]{}, (*FlatArray[int16])(target), true
+	case *[]int32:
+		return &wrapPtrSliceScanPlan[int32]{}, (*FlatArray[int32])(target), true
+	case *[]int64:
+		return &wrapPtrSliceScanPlan[int64]{}, (*FlatArray[int64])(target), true
+	case *[]float32:
+		return &wrapPtrSliceScanPlan[float32]{}, (*FlatArray[float32])(target), true
+	case *[]float64:
+		return &wrapPtrSliceScanPlan[float64]{}, (*FlatArray[float64])(target), true
+	case *[]string:
+		return &wrapPtrSliceScanPlan[string]{}, (*FlatArray[string])(target), true
+	case *[]time.Time:
+		return &wrapPtrSliceScanPlan[time.Time]{}, (*FlatArray[time.Time])(target), true
+	}
+
+	targetType := reflect.TypeOf(target)
+	if targetType.Kind() != reflect.Pointer {
+		return nil, nil, false
+	}
+
+	targetElemType := targetType.Elem()
+
+	if targetElemType.Kind() == reflect.Slice {
+		slice := reflect.New(targetElemType).Elem()
+		return &wrapPtrSliceReflectScanPlan{}, &anySliceArrayReflect{slice: slice}, true
+	}
+	return nil, nil, false
+}
+
+type wrapPtrSliceScanPlan[T any] struct {
+	next ScanPlan
+}
+
+func (plan *wrapPtrSliceScanPlan[T]) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapPtrSliceScanPlan[T]) Scan(src []byte, target any) error {
+	return plan.next.Scan(src, (*FlatArray[T])(target.(*[]T)))
+}
+
+type wrapPtrSliceReflectScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapPtrSliceReflectScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapPtrSliceReflectScanPlan) Scan(src []byte, target any) error {
+	return plan.next.Scan(src, &anySliceArrayReflect{slice: reflect.ValueOf(target).Elem()})
+}
+
+// TryWrapPtrMultiDimSliceScanPlan tries to wrap a pointer to a multi-dimension slice.
+func TryWrapPtrMultiDimSliceScanPlan(target any) (plan WrappedScanPlanNextSetter, nextValue any, ok bool) {
+	targetValue := reflect.ValueOf(target)
+	if targetValue.Kind() != reflect.Pointer {
+		return nil, nil, false
+	}
+
+	targetElemValue := targetValue.Elem()
+
+	if targetElemValue.Kind() == reflect.Slice {
+		elemElemKind := targetElemValue.Type().Elem().Kind()
+		if elemElemKind == reflect.Slice {
+			if !isRagged(targetElemValue) {
+				return &wrapPtrMultiDimSliceScanPlan{}, &anyMultiDimSliceArray{slice: targetValue.Elem()}, true
+			}
+		}
+	}
+
+	return nil, nil, false
+}
+
+type wrapPtrMultiDimSliceScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapPtrMultiDimSliceScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapPtrMultiDimSliceScanPlan) Scan(src []byte, target any) error {
+	return plan.next.Scan(src, &anyMultiDimSliceArray{slice: reflect.ValueOf(target).Elem()})
+}
+
+// TryWrapPtrArrayScanPlan tries to wrap a pointer to a single dimension array.
+func TryWrapPtrArrayScanPlan(target any) (plan WrappedScanPlanNextSetter, nextValue any, ok bool) {
+	targetValue := reflect.ValueOf(target)
+	if targetValue.Kind() != reflect.Pointer {
+		return nil, nil, false
+	}
+
+	targetElemValue := targetValue.Elem()
+
+	if targetElemValue.Kind() == reflect.Array {
+		return &wrapPtrArrayReflectScanPlan{}, &anyArrayArrayReflect{array: targetElemValue}, true
+	}
+	return nil, nil, false
+}
+
+type wrapPtrArrayReflectScanPlan struct {
+	next ScanPlan
+}
+
+func (plan *wrapPtrArrayReflectScanPlan) SetNext(next ScanPlan) { plan.next = next }
+
+func (plan *wrapPtrArrayReflectScanPlan) Scan(src []byte, target any) error {
+	return plan.next.Scan(src, &anyArrayArrayReflect{array: reflect.ValueOf(target).Elem()})
+}
+
+// PlanScan prepares a plan to scan a value into target.
+func (m *Map) PlanScan(oid uint32, formatCode int16, target any) ScanPlan {
+	return m.planScan(oid, formatCode, target, 0)
+}
+
+func (m *Map) planScan(oid uint32, formatCode int16, target any, depth int) ScanPlan {
+	if depth > 8 {
+		return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
+	}
+
+	if target == nil {
+		return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
+	}
+
+	if _, ok := target.(*UndecodedBytes); ok {
+		return scanPlanAnyToUndecodedBytes{}
+	}
+
+	switch formatCode {
+	case BinaryFormatCode:
+		if _, ok := target.(*string); ok {
+			switch oid {
+			case TextOID, VarcharOID:
+				return scanPlanString{}
+			}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *string:
+			return scanPlanString{}
+		case *[]byte:
+			if oid != ByteaOID {
+				return scanPlanAnyTextToBytes{}
+			}
+		case TextScanner:
+			return scanPlanTextAnyToTextScanner{}
+		}
+	}
+
+	var dt *Type
+
+	if dataType, ok := m.TypeForOID(oid); ok {
+		dt = dataType
+	} else if dataType, ok := m.TypeForValue(target); ok {
+		dt = dataType
+		oid = dt.OID // Preserve assumed OID in case we are recursively called below.
+	}
+
+	if dt != nil {
+		if plan := dt.Codec.PlanScan(m, oid, formatCode, target); plan != nil {
+			return plan
+		}
+	}
+
+	// This needs to happen before trying m.TryWrapScanPlanFuncs. Otherwise, a sql.Scanner would not get called if it was
+	// defined on a type that could be unwrapped such as `type myString string`.
+	//
+	//  https://github.com/jackc/pgtype/issues/197
+	if _, ok := target.(sql.Scanner); ok {
+		if dt == nil {
+			return &scanPlanSQLScanner{formatCode: formatCode}
+		} else {
+			return &scanPlanCodecSQLScanner{c: dt.Codec, m: m, oid: oid, formatCode: formatCode}
+		}
+	}
+
+	for _, f := range m.TryWrapScanPlanFuncs {
+		if wrapperPlan, nextDst, ok := f(target); ok {
+			if nextPlan := m.planScan(oid, formatCode, nextDst, depth+1); nextPlan != nil {
+				if _, failed := nextPlan.(*scanPlanFail); !failed {
+					wrapperPlan.SetNext(nextPlan)
+					return wrapperPlan
+				}
+			}
+		}
+	}
+
+	if _, ok := target.(*any); ok {
+		var codec Codec
+		if dt != nil {
+			codec = dt.Codec
+		} else {
+			if formatCode == TextFormatCode {
+				codec = TextCodec{}
+			} else {
+				codec = ByteaCodec{}
+			}
+		}
+		return &pointerEmptyInterfaceScanPlan{codec: codec, m: m, oid: oid, formatCode: formatCode}
+	}
+
+	return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
+}
+
+func (m *Map) Scan(oid uint32, formatCode int16, src []byte, dst any) error {
+	if dst == nil {
+		return nil
+	}
+
+	plan := m.PlanScan(oid, formatCode, dst)
+	return plan.Scan(src, dst)
+}
+
+var ErrScanTargetTypeChanged = errors.New("scan target type changed")
+
+func codecScan(codec Codec, m *Map, oid uint32, format int16, src []byte, dst any) error {
+	scanPlan := codec.PlanScan(m, oid, format, dst)
+	if scanPlan == nil {
+		return fmt.Errorf("PlanScan did not find a plan")
+	}
+	return scanPlan.Scan(src, dst)
+}
+
+func codecDecodeToTextFormat(codec Codec, m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	if format == TextFormatCode {
+		return string(src), nil
+	} else {
+		value, err := codec.DecodeValue(m, oid, format, src)
+		if err != nil {
+			return nil, err
+		}
+		buf, err := m.Encode(oid, TextFormatCode, value, nil)
+		if err != nil {
+			return nil, err
+		}
+		return string(buf), nil
+	}
+}
+
+// PlanEncode returns an EncodePlan for encoding value into PostgreSQL format for oid and format. If no plan can be
+// found then nil is returned.
+func (m *Map) PlanEncode(oid uint32, format int16, value any) EncodePlan {
+	return m.planEncodeDepth(oid, format, value, 0)
+}
+
+func (m *Map) planEncodeDepth(oid uint32, format int16, value any, depth int) EncodePlan {
+	// Guard against infinite recursion.
+	if depth > 8 {
+		return nil
+	}
+
+	oidMemo := m.memoizedEncodePlans[oid]
+	if oidMemo == nil {
+		oidMemo = make(map[reflect.Type][2]EncodePlan)
+		m.memoizedEncodePlans[oid] = oidMemo
+	}
+	targetReflectType := reflect.TypeOf(value)
+	typeMemo := oidMemo[targetReflectType]
+	plan := typeMemo[format]
+	if plan == nil {
+		plan = m.planEncode(oid, format, value, depth)
+		typeMemo[format] = plan
+		oidMemo[targetReflectType] = typeMemo
+	}
+
+	return plan
+}
+
+func (m *Map) planEncode(oid uint32, format int16, value any, depth int) EncodePlan {
+	if format == TextFormatCode {
+		switch value.(type) {
+		case string:
+			return encodePlanStringToAnyTextFormat{}
+		case TextValuer:
+			return encodePlanTextValuerToAnyTextFormat{}
+		}
+	}
+
+	var dt *Type
+	if dataType, ok := m.TypeForOID(oid); ok {
+		dt = dataType
+	} else {
+		// If no type for the OID was found, then either it is unknowable (e.g. the simple protocol) or it is an
+		// unregistered type. In either case try to find the type and OID that matches the value (e.g. a []byte would be
+		// registered to PostgreSQL bytea).
+		if dataType, ok := m.TypeForValue(value); ok {
+			dt = dataType
+			oid = dt.OID // Preserve assumed OID in case we are recursively called below.
+		}
+	}
+
+	if dt != nil {
+		if plan := dt.Codec.PlanEncode(m, oid, format, value); plan != nil {
+			return plan
+		}
+	}
+
+	for _, f := range m.TryWrapEncodePlanFuncs {
+		if wrapperPlan, nextValue, ok := f(value); ok {
+			if nextPlan := m.planEncodeDepth(oid, format, nextValue, depth+1); nextPlan != nil {
+				wrapperPlan.SetNext(nextPlan)
+				return wrapperPlan
+			}
+		}
+	}
+
+	if _, ok := value.(driver.Valuer); ok {
+		return &encodePlanDriverValuer{m: m, oid: oid, formatCode: format}
+	}
+
+	return nil
+}
+
+type encodePlanStringToAnyTextFormat struct{}
+
+func (encodePlanStringToAnyTextFormat) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	s := value.(string)
+	return append(buf, s...), nil
+}
+
+type encodePlanTextValuerToAnyTextFormat struct{}
+
+func (encodePlanTextValuerToAnyTextFormat) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	t, err := value.(TextValuer).TextValue()
+	if err != nil {
+		return nil, err
+	}
+	if !t.Valid {
+		return nil, nil
+	}
+
+	return append(buf, t.String...), nil
+}
+
+type encodePlanDriverValuer struct {
+	m          *Map
+	oid        uint32
+	formatCode int16
+}
+
+func (plan *encodePlanDriverValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	dv := value.(driver.Valuer)
+	if dv == nil {
+		return nil, nil
+	}
+	v, err := dv.Value()
+	if err != nil {
+		return nil, err
+	}
+	if v == nil {
+		return nil, nil
+	}
+
+	newBuf, err = plan.m.Encode(plan.oid, plan.formatCode, v, buf)
+	if err == nil {
+		return newBuf, nil
+	}
+
+	s, ok := v.(string)
+	if !ok {
+		return nil, err
+	}
+
+	var scannedValue any
+	scanErr := plan.m.Scan(plan.oid, TextFormatCode, []byte(s), &scannedValue)
+	if scanErr != nil {
+		return nil, err
+	}
+
+	// Prevent infinite loop. We can't encode this. See https://github.com/jackc/pgx/issues/1331.
+	if reflect.TypeOf(value) == reflect.TypeOf(scannedValue) {
+		return nil, fmt.Errorf("tried to encode %v via encoding to text and scanning but failed due to receiving same type back", value)
+	}
+
+	var err2 error
+	newBuf, err2 = plan.m.Encode(plan.oid, BinaryFormatCode, scannedValue, buf)
+	if err2 != nil {
+		return nil, err
+	}
+
+	return newBuf, nil
+}
+
+// TryWrapEncodePlanFunc is a function that tries to create a wrapper plan for value. If successful it returns a plan
+// that will convert the value passed to Encode and then call the next plan. nextValue is value as it will be converted
+// by plan. It must be used to find another suitable EncodePlan. When it is found SetNext must be called on plan for it
+// to be usabled. ok indicates if a suitable wrapper was found.
+type TryWrapEncodePlanFunc func(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool)
+
+type derefPointerEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *derefPointerEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *derefPointerEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	ptr := reflect.ValueOf(value)
+
+	if ptr.IsNil() {
+		return nil, nil
+	}
+
+	return plan.next.Encode(ptr.Elem().Interface(), buf)
+}
+
+// TryWrapDerefPointerEncodePlan tries to dereference a pointer. e.g. If value was of type *string then a wrapper plan
+// would be returned that dereferences the value.
+func TryWrapDerefPointerEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
+	if _, ok := value.(driver.Valuer); ok {
+		return nil, nil, false
+	}
+
+	if valueType := reflect.TypeOf(value); valueType != nil && valueType.Kind() == reflect.Pointer {
+		return &derefPointerEncodePlan{}, reflect.New(valueType.Elem()).Elem().Interface(), true
+	}
+
+	return nil, nil, false
+}
+
+var kindToTypes map[reflect.Kind]reflect.Type = map[reflect.Kind]reflect.Type{
+	reflect.Int:     reflect.TypeFor[int](),
+	reflect.Int8:    reflect.TypeFor[int8](),
+	reflect.Int16:   reflect.TypeFor[int16](),
+	reflect.Int32:   reflect.TypeFor[int32](),
+	reflect.Int64:   reflect.TypeFor[int64](),
+	reflect.Uint:    reflect.TypeFor[uint](),
+	reflect.Uint8:   reflect.TypeFor[uint8](),
+	reflect.Uint16:  reflect.TypeFor[uint16](),
+	reflect.Uint32:  reflect.TypeFor[uint32](),
+	reflect.Uint64:  reflect.TypeFor[uint64](),
+	reflect.Float32: reflect.TypeFor[float32](),
+	reflect.Float64: reflect.TypeFor[float64](),
+	reflect.String:  reflect.TypeFor[string](),
+	reflect.Bool:    reflect.TypeFor[bool](),
+}
+
+var byteSliceType = reflect.TypeFor[[]byte]()
+
+type underlyingTypeEncodePlan struct {
+	nextValueType reflect.Type
+	next          EncodePlan
+}
+
+func (plan *underlyingTypeEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *underlyingTypeEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(reflect.ValueOf(value).Convert(plan.nextValueType).Interface(), buf)
+}
+
+// TryWrapFindUnderlyingTypeEncodePlan tries to convert to a Go builtin type. e.g. If value was of type MyString and
+// MyString was defined as a string then a wrapper plan would be returned that converts MyString to string.
+func TryWrapFindUnderlyingTypeEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
+	if value == nil {
+		return nil, nil, false
+	}
+
+	if _, ok := value.(driver.Valuer); ok {
+		return nil, nil, false
+	}
+
+	if _, ok := value.(SkipUnderlyingTypePlanner); ok {
+		return nil, nil, false
+	}
+
+	refValue := reflect.ValueOf(value)
+
+	nextValueType := kindToTypes[refValue.Kind()]
+	if nextValueType != nil && refValue.Type() != nextValueType {
+		return &underlyingTypeEncodePlan{nextValueType: nextValueType}, refValue.Convert(nextValueType).Interface(), true
+	}
+
+	// []byte is a special case. It is a slice but we treat it as a scalar type. In the case of a named type like
+	// json.RawMessage which is defined as []byte the underlying type should be considered as []byte. But any other slice
+	// does not have a special underlying type.
+	//
+	// https://github.com/jackc/pgx/issues/1763
+	if refValue.Type() != byteSliceType && refValue.Type().AssignableTo(byteSliceType) {
+		return &underlyingTypeEncodePlan{nextValueType: byteSliceType}, refValue.Convert(byteSliceType).Interface(), true
+	}
+
+	// Get underlying type of any array.
+	// https://github.com/jackc/pgx/issues/2107
+	if refValue.Kind() == reflect.Array {
+		underlyingArrayType := reflect.ArrayOf(refValue.Len(), refValue.Type().Elem())
+		if refValue.Type() != underlyingArrayType {
+			return &underlyingTypeEncodePlan{nextValueType: underlyingArrayType}, refValue.Convert(underlyingArrayType).Interface(), true
+		}
+	}
+
+	return nil, nil, false
+}
+
+// TryWrapStringerEncodePlan tries to wrap a fmt.Stringer type with a wrapper that provides TextValuer. This is
+// intentionally a separate function from TryWrapBuiltinTypeEncodePlan so it can be ordered after
+// TryWrapFindUnderlyingTypeEncodePlan. This ensures that named types with an underlying builtin type (e.g. type MyEnum
+// int32 with a String() method) prefer encoding via the underlying type's codec (e.g. as an integer) rather than via
+// Stringer. Stringer is only used as a fallback when no type-specific encoding plan succeeds.
+// (https://github.com/jackc/pgx/discussions/2527)
+func TryWrapStringerEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
+	if _, ok := value.(driver.Valuer); ok {
+		return nil, nil, false
+	}
+
+	if s, ok := value.(fmt.Stringer); ok {
+		return &wrapFmtStringerEncodePlan{}, fmtStringerWrapper{s}, true
+	}
+
+	return nil, nil, false
+}
+
+type WrappedEncodePlanNextSetter interface {
+	SetNext(EncodePlan)
+	EncodePlan
+}
+
+// TryWrapBuiltinTypeEncodePlan tries to wrap a builtin type with a wrapper that provides additional methods. e.g. If
+// value was of type int32 then a wrapper plan would be returned that converts value to a type that implements
+// Int64Valuer.
+func TryWrapBuiltinTypeEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
+	if _, ok := value.(driver.Valuer); ok {
+		return nil, nil, false
+	}
+
+	switch value := value.(type) {
+	case int8:
+		return &wrapInt8EncodePlan{}, int8Wrapper(value), true
+	case int16:
+		return &wrapInt16EncodePlan{}, int16Wrapper(value), true
+	case int32:
+		return &wrapInt32EncodePlan{}, int32Wrapper(value), true
+	case int64:
+		return &wrapInt64EncodePlan{}, int64Wrapper(value), true
+	case int:
+		return &wrapIntEncodePlan{}, intWrapper(value), true
+	case uint8:
+		return &wrapUint8EncodePlan{}, uint8Wrapper(value), true
+	case uint16:
+		return &wrapUint16EncodePlan{}, uint16Wrapper(value), true
+	case uint32:
+		return &wrapUint32EncodePlan{}, uint32Wrapper(value), true
+	case uint64:
+		return &wrapUint64EncodePlan{}, uint64Wrapper(value), true
+	case uint:
+		return &wrapUintEncodePlan{}, uintWrapper(value), true
+	case float32:
+		return &wrapFloat32EncodePlan{}, float32Wrapper(value), true
+	case float64:
+		return &wrapFloat64EncodePlan{}, float64Wrapper(value), true
+	case string:
+		return &wrapStringEncodePlan{}, stringWrapper(value), true
+	case time.Time:
+		return &wrapTimeEncodePlan{}, timeWrapper(value), true
+	case time.Duration:
+		return &wrapDurationEncodePlan{}, durationWrapper(value), true
+	case net.IPNet:
+		return &wrapNetIPNetEncodePlan{}, netIPNetWrapper(value), true
+	case net.IP:
+		return &wrapNetIPEncodePlan{}, netIPWrapper(value), true
+	case netip.Prefix:
+		return &wrapNetipPrefixEncodePlan{}, netipPrefixWrapper(value), true
+	case netip.Addr:
+		return &wrapNetipAddrEncodePlan{}, netipAddrWrapper(value), true
+	case map[string]*string:
+		return &wrapMapStringToPointerStringEncodePlan{}, mapStringToPointerStringWrapper(value), true
+	case map[string]string:
+		return &wrapMapStringToStringEncodePlan{}, mapStringToStringWrapper(value), true
+	case [16]byte:
+		return &wrapByte16EncodePlan{}, byte16Wrapper(value), true
+	case []byte:
+		return &wrapByteSliceEncodePlan{}, byteSliceWrapper(value), true
+	}
+
+	return nil, nil, false
+}
+
+type wrapInt8EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapInt8EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapInt8EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(int8Wrapper(value.(int8)), buf)
+}
+
+type wrapInt16EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapInt16EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapInt16EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(int16Wrapper(value.(int16)), buf)
+}
+
+type wrapInt32EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapInt32EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapInt32EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(int32Wrapper(value.(int32)), buf)
+}
+
+type wrapInt64EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapInt64EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapInt64EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(int64Wrapper(value.(int64)), buf)
+}
+
+type wrapIntEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapIntEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapIntEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(intWrapper(value.(int)), buf)
+}
+
+type wrapUint8EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapUint8EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapUint8EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(uint8Wrapper(value.(uint8)), buf)
+}
+
+type wrapUint16EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapUint16EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapUint16EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(uint16Wrapper(value.(uint16)), buf)
+}
+
+type wrapUint32EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapUint32EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapUint32EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(uint32Wrapper(value.(uint32)), buf)
+}
+
+type wrapUint64EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapUint64EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapUint64EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(uint64Wrapper(value.(uint64)), buf)
+}
+
+type wrapUintEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapUintEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapUintEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(uintWrapper(value.(uint)), buf)
+}
+
+type wrapFloat32EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapFloat32EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapFloat32EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(float32Wrapper(value.(float32)), buf)
+}
+
+type wrapFloat64EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapFloat64EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapFloat64EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(float64Wrapper(value.(float64)), buf)
+}
+
+type wrapStringEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapStringEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapStringEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(stringWrapper(value.(string)), buf)
+}
+
+type wrapTimeEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapTimeEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapTimeEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(timeWrapper(value.(time.Time)), buf)
+}
+
+type wrapDurationEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapDurationEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapDurationEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(durationWrapper(value.(time.Duration)), buf)
+}
+
+type wrapNetIPNetEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapNetIPNetEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapNetIPNetEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(netIPNetWrapper(value.(net.IPNet)), buf)
+}
+
+type wrapNetIPEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapNetIPEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapNetIPEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(netIPWrapper(value.(net.IP)), buf)
+}
+
+type wrapNetipPrefixEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapNetipPrefixEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapNetipPrefixEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(netipPrefixWrapper(value.(netip.Prefix)), buf)
+}
+
+type wrapNetipAddrEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapNetipAddrEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapNetipAddrEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(netipAddrWrapper(value.(netip.Addr)), buf)
+}
+
+type wrapMapStringToPointerStringEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapMapStringToPointerStringEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapMapStringToPointerStringEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(mapStringToPointerStringWrapper(value.(map[string]*string)), buf)
+}
+
+type wrapMapStringToStringEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapMapStringToStringEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapMapStringToStringEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(mapStringToStringWrapper(value.(map[string]string)), buf)
+}
+
+type wrapByte16EncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapByte16EncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapByte16EncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(byte16Wrapper(value.([16]byte)), buf)
+}
+
+type wrapByteSliceEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapByteSliceEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapByteSliceEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(byteSliceWrapper(value.([]byte)), buf)
+}
+
+type wrapFmtStringerEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapFmtStringerEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapFmtStringerEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode(fmtStringerWrapper{value.(fmt.Stringer)}, buf)
+}
+
+// TryWrapStructEncodePlan tries to wrap a struct with a wrapper that implements CompositeIndexGetter.
+func TryWrapStructEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
+	if _, ok := value.(driver.Valuer); ok {
+		return nil, nil, false
+	}
+
+	if valueType := reflect.TypeOf(value); valueType != nil && valueType.Kind() == reflect.Struct {
+		exportedFields := getExportedFieldValues(reflect.ValueOf(value))
+		if len(exportedFields) == 0 {
+			return nil, nil, false
+		}
+
+		w := structWrapper{
+			s:              value,
+			exportedFields: exportedFields,
+		}
+		return &wrapAnyStructEncodePlan{}, w, true
+	}
+
+	return nil, nil, false
+}
+
+type wrapAnyStructEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapAnyStructEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapAnyStructEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	w := structWrapper{
+		s:              value,
+		exportedFields: getExportedFieldValues(reflect.ValueOf(value)),
+	}
+
+	return plan.next.Encode(w, buf)
+}
+
+func getExportedFieldValues(structValue reflect.Value) []reflect.Value {
+	structType := structValue.Type()
+	exportedFields := make([]reflect.Value, 0, structValue.NumField())
+	for i := 0; i < structType.NumField(); i++ {
+		sf := structType.Field(i)
+		if sf.IsExported() {
+			exportedFields = append(exportedFields, structValue.Field(i))
+		}
+	}
+
+	return exportedFields
+}
+
+func TryWrapSliceEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
+	if _, ok := value.(driver.Valuer); ok {
+		return nil, nil, false
+	}
+
+	// Avoid using reflect path for common types.
+	switch value := value.(type) {
+	case []int16:
+		return &wrapSliceEncodePlan[int16]{}, (FlatArray[int16])(value), true
+	case []int32:
+		return &wrapSliceEncodePlan[int32]{}, (FlatArray[int32])(value), true
+	case []int64:
+		return &wrapSliceEncodePlan[int64]{}, (FlatArray[int64])(value), true
+	case []float32:
+		return &wrapSliceEncodePlan[float32]{}, (FlatArray[float32])(value), true
+	case []float64:
+		return &wrapSliceEncodePlan[float64]{}, (FlatArray[float64])(value), true
+	case []string:
+		return &wrapSliceEncodePlan[string]{}, (FlatArray[string])(value), true
+	case []time.Time:
+		return &wrapSliceEncodePlan[time.Time]{}, (FlatArray[time.Time])(value), true
+	}
+
+	if valueType := reflect.TypeOf(value); valueType != nil && valueType.Kind() == reflect.Slice {
+		w := anySliceArrayReflect{
+			slice: reflect.ValueOf(value),
+		}
+		return &wrapSliceEncodeReflectPlan{}, w, true
+	}
+
+	return nil, nil, false
+}
+
+type wrapSliceEncodePlan[T any] struct {
+	next EncodePlan
+}
+
+func (plan *wrapSliceEncodePlan[T]) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapSliceEncodePlan[T]) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	return plan.next.Encode((FlatArray[T])(value.([]T)), buf)
+}
+
+type wrapSliceEncodeReflectPlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapSliceEncodeReflectPlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapSliceEncodeReflectPlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	w := anySliceArrayReflect{
+		slice: reflect.ValueOf(value),
+	}
+
+	return plan.next.Encode(w, buf)
+}
+
+func TryWrapMultiDimSliceEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
+	if _, ok := value.(driver.Valuer); ok {
+		return nil, nil, false
+	}
+
+	sliceValue := reflect.ValueOf(value)
+	if sliceValue.Kind() == reflect.Slice {
+		valueElemType := sliceValue.Type().Elem()
+
+		if valueElemType.Kind() == reflect.Slice {
+			if !isRagged(sliceValue) {
+				w := anyMultiDimSliceArray{
+					slice: reflect.ValueOf(value),
+				}
+				return &wrapMultiDimSliceEncodePlan{}, &w, true
+			}
+		}
+	}
+
+	return nil, nil, false
+}
+
+type wrapMultiDimSliceEncodePlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapMultiDimSliceEncodePlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapMultiDimSliceEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	w := anyMultiDimSliceArray{
+		slice: reflect.ValueOf(value),
+	}
+
+	return plan.next.Encode(&w, buf)
+}
+
+func TryWrapArrayEncodePlan(value any) (plan WrappedEncodePlanNextSetter, nextValue any, ok bool) {
+	if _, ok := value.(driver.Valuer); ok {
+		return nil, nil, false
+	}
+
+	if valueType := reflect.TypeOf(value); valueType != nil && valueType.Kind() == reflect.Array {
+		w := anyArrayArrayReflect{
+			array: reflect.ValueOf(value),
+		}
+		return &wrapArrayEncodeReflectPlan{}, w, true
+	}
+
+	return nil, nil, false
+}
+
+type wrapArrayEncodeReflectPlan struct {
+	next EncodePlan
+}
+
+func (plan *wrapArrayEncodeReflectPlan) SetNext(next EncodePlan) { plan.next = next }
+
+func (plan *wrapArrayEncodeReflectPlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	w := anyArrayArrayReflect{
+		array: reflect.ValueOf(value),
+	}
+
+	return plan.next.Encode(w, buf)
+}
+
+func newEncodeError(value any, m *Map, oid uint32, formatCode int16, err error) error {
+	var format string
+	switch formatCode {
+	case TextFormatCode:
+		format = "text"
+	case BinaryFormatCode:
+		format = "binary"
+	default:
+		format = fmt.Sprintf("unknown (%d)", formatCode)
+	}
+
+	var dataTypeName string
+	if t, ok := m.TypeForOID(oid); ok {
+		dataTypeName = t.Name
+	} else {
+		dataTypeName = "unknown type"
+	}
+
+	return fmt.Errorf("unable to encode %#v into %s format for %s (OID %d): %w", value, format, dataTypeName, oid, err)
+}
+
+// Encode appends the encoded bytes of value to buf. If value is the SQL value NULL then append nothing and return
+// (nil, nil). The caller of Encode is responsible for writing the correct NULL value or the length of the data
+// written.
+func (m *Map) Encode(oid uint32, formatCode int16, value any, buf []byte) (newBuf []byte, err error) {
+	if isNil, callNilDriverValuer := isNilDriverValuer(value); isNil {
+		if callNilDriverValuer {
+			newBuf, err = (&encodePlanDriverValuer{m: m, oid: oid, formatCode: formatCode}).Encode(value, buf)
+			if err != nil {
+				return nil, newEncodeError(value, m, oid, formatCode, err)
+			}
+
+			return newBuf, nil
+		} else {
+			return nil, nil
+		}
+	}
+
+	plan := m.PlanEncode(oid, formatCode, value)
+	if plan == nil {
+		return nil, newEncodeError(value, m, oid, formatCode, errors.New("cannot find encode plan"))
+	}
+
+	newBuf, err = plan.Encode(value, buf)
+	if err != nil {
+		return nil, newEncodeError(value, m, oid, formatCode, err)
+	}
+
+	return newBuf, nil
+}
+
+// SQLScanner returns a database/sql.Scanner for v. This is necessary for types like Array[T] and Range[T] where the
+// type needs assistance from Map to implement the sql.Scanner interface. It is not necessary for types like Box that
+// implement sql.Scanner directly.
+//
+// This uses the type of v to look up the PostgreSQL OID that v presumably came from. This means v must be registered
+// with m by calling RegisterDefaultPgType.
+func (m *Map) SQLScanner(v any) sql.Scanner {
+	if s, ok := v.(sql.Scanner); ok {
+		return s
+	}
+
+	return &sqlScannerWrapper{m: m, v: v}
+}
+
+type sqlScannerWrapper struct {
+	m *Map
+	v any
+}
+
+func (w *sqlScannerWrapper) Scan(src any) error {
+	t, ok := w.m.TypeForValue(w.v)
+	if !ok {
+		return fmt.Errorf("cannot convert to sql.Scanner: cannot find registered type for %T", w.v)
+	}
+
+	var bufSrc []byte
+	if src != nil {
+		switch src := src.(type) {
+		case string:
+			bufSrc = []byte(src)
+		case []byte:
+			bufSrc = src
+		default:
+			bufSrc = fmt.Append(nil, bufSrc)
+		}
+	}
+
+	return w.m.Scan(t.OID, TextFormatCode, bufSrc, w.v)
+}
+
+var valuerReflectType = reflect.TypeFor[driver.Valuer]()
+
+// isNilDriverValuer returns true if value is any type of nil unless it implements driver.Valuer. *T is not considered to implement
+// driver.Valuer if it is only implemented by T.
+func isNilDriverValuer(value any) (isNil, callNilDriverValuer bool) {
+	if value == nil {
+		return true, false
+	}
+
+	refVal := reflect.ValueOf(value)
+	kind := refVal.Kind()
+	switch kind {
+	case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.UnsafePointer, reflect.Interface, reflect.Slice:
+		if !refVal.IsNil() {
+			return false, false
+		}
+
+		if _, ok := value.(driver.Valuer); ok {
+			if kind == reflect.Pointer {
+				// The type assertion will succeed if driver.Valuer is implemented on T or *T. Check if it is implemented on *T
+				// by checking if it is not implemented on *T.
+				return true, !refVal.Type().Elem().Implements(valuerReflectType)
+			} else {
+				return true, true
+			}
+		}
+
+		return true, false
+	default:
+		return false, false
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/pgtype_default.go b/vendor/github.com/jackc/pgx/v5/pgtype/pgtype_default.go
new file mode 100644
index 000000000..42b39d827
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/pgtype_default.go
@@ -0,0 +1,251 @@
+package pgtype
+
+import (
+	"encoding/json"
+	"encoding/xml"
+	"net"
+	"net/netip"
+	"reflect"
+	"sync"
+	"time"
+)
+
+var (
+	// defaultMap contains default mappings between PostgreSQL server types and Go type handling logic.
+	defaultMap         *Map
+	defaultMapInitOnce = sync.Once{}
+)
+
+func initDefaultMap() {
+	defaultMap = &Map{
+		oidToType:         make(map[uint32]*Type),
+		nameToType:        make(map[string]*Type),
+		reflectTypeToName: make(map[reflect.Type]string),
+		oidToFormatCode:   make(map[uint32]int16),
+
+		memoizedEncodePlans: make(map[uint32]map[reflect.Type][2]EncodePlan),
+
+		TryWrapEncodePlanFuncs: []TryWrapEncodePlanFunc{
+			TryWrapDerefPointerEncodePlan,
+			TryWrapBuiltinTypeEncodePlan,
+			TryWrapFindUnderlyingTypeEncodePlan,
+			TryWrapStructEncodePlan,
+			TryWrapSliceEncodePlan,
+			TryWrapMultiDimSliceEncodePlan,
+			TryWrapArrayEncodePlan,
+		},
+
+		TryWrapScanPlanFuncs: []TryWrapScanPlanFunc{
+			TryPointerPointerScanPlan,
+			TryWrapBuiltinTypeScanPlan,
+			TryFindUnderlyingTypeScanPlan,
+			TryWrapStructScanPlan,
+			TryWrapPtrSliceScanPlan,
+			TryWrapPtrMultiDimSliceScanPlan,
+			TryWrapPtrArrayScanPlan,
+		},
+	}
+
+	// Base types
+	defaultMap.RegisterType(&Type{Name: "aclitem", OID: ACLItemOID, Codec: &TextFormatOnlyCodec{TextCodec{}}})
+	defaultMap.RegisterType(&Type{Name: "bit", OID: BitOID, Codec: BitsCodec{}})
+	defaultMap.RegisterType(&Type{Name: "bool", OID: BoolOID, Codec: BoolCodec{}})
+	defaultMap.RegisterType(&Type{Name: "box", OID: BoxOID, Codec: BoxCodec{}})
+	defaultMap.RegisterType(&Type{Name: "bpchar", OID: BPCharOID, Codec: TextCodec{}})
+	defaultMap.RegisterType(&Type{Name: "bytea", OID: ByteaOID, Codec: ByteaCodec{}})
+	defaultMap.RegisterType(&Type{Name: "char", OID: QCharOID, Codec: QCharCodec{}})
+	defaultMap.RegisterType(&Type{Name: "cid", OID: CIDOID, Codec: Uint32Codec{}})
+	defaultMap.RegisterType(&Type{Name: "cidr", OID: CIDROID, Codec: InetCodec{}})
+	defaultMap.RegisterType(&Type{Name: "circle", OID: CircleOID, Codec: CircleCodec{}})
+	defaultMap.RegisterType(&Type{Name: "date", OID: DateOID, Codec: DateCodec{}})
+	defaultMap.RegisterType(&Type{Name: "float4", OID: Float4OID, Codec: Float4Codec{}})
+	defaultMap.RegisterType(&Type{Name: "float8", OID: Float8OID, Codec: Float8Codec{}})
+	defaultMap.RegisterType(&Type{Name: "inet", OID: InetOID, Codec: InetCodec{}})
+	defaultMap.RegisterType(&Type{Name: "int2", OID: Int2OID, Codec: Int2Codec{}})
+	defaultMap.RegisterType(&Type{Name: "int4", OID: Int4OID, Codec: Int4Codec{}})
+	defaultMap.RegisterType(&Type{Name: "int8", OID: Int8OID, Codec: Int8Codec{}})
+	defaultMap.RegisterType(&Type{Name: "interval", OID: IntervalOID, Codec: IntervalCodec{}})
+	defaultMap.RegisterType(&Type{Name: "json", OID: JSONOID, Codec: &JSONCodec{Marshal: json.Marshal, Unmarshal: json.Unmarshal}})
+	defaultMap.RegisterType(&Type{Name: "jsonb", OID: JSONBOID, Codec: &JSONBCodec{Marshal: json.Marshal, Unmarshal: json.Unmarshal}})
+	defaultMap.RegisterType(&Type{Name: "jsonpath", OID: JSONPathOID, Codec: &TextFormatOnlyCodec{TextCodec{}}})
+	defaultMap.RegisterType(&Type{Name: "line", OID: LineOID, Codec: LineCodec{}})
+	defaultMap.RegisterType(&Type{Name: "lseg", OID: LsegOID, Codec: LsegCodec{}})
+	defaultMap.RegisterType(&Type{Name: "macaddr8", OID: Macaddr8OID, Codec: MacaddrCodec{}})
+	defaultMap.RegisterType(&Type{Name: "macaddr", OID: MacaddrOID, Codec: MacaddrCodec{}})
+	defaultMap.RegisterType(&Type{Name: "name", OID: NameOID, Codec: TextCodec{}})
+	defaultMap.RegisterType(&Type{Name: "numeric", OID: NumericOID, Codec: NumericCodec{}})
+	defaultMap.RegisterType(&Type{Name: "oid", OID: OIDOID, Codec: Uint32Codec{}})
+	defaultMap.RegisterType(&Type{Name: "path", OID: PathOID, Codec: PathCodec{}})
+	defaultMap.RegisterType(&Type{Name: "point", OID: PointOID, Codec: PointCodec{}})
+	defaultMap.RegisterType(&Type{Name: "polygon", OID: PolygonOID, Codec: PolygonCodec{}})
+	defaultMap.RegisterType(&Type{Name: "record", OID: RecordOID, Codec: RecordCodec{}})
+	defaultMap.RegisterType(&Type{Name: "text", OID: TextOID, Codec: TextCodec{}})
+	defaultMap.RegisterType(&Type{Name: "tid", OID: TIDOID, Codec: TIDCodec{}})
+	defaultMap.RegisterType(&Type{Name: "tsvector", OID: TSVectorOID, Codec: TSVectorCodec{}})
+	defaultMap.RegisterType(&Type{Name: "time", OID: TimeOID, Codec: TimeCodec{}})
+	defaultMap.RegisterType(&Type{Name: "timestamp", OID: TimestampOID, Codec: &TimestampCodec{}})
+	defaultMap.RegisterType(&Type{Name: "timestamptz", OID: TimestamptzOID, Codec: &TimestamptzCodec{}})
+	defaultMap.RegisterType(&Type{Name: "unknown", OID: UnknownOID, Codec: TextCodec{}})
+	defaultMap.RegisterType(&Type{Name: "uuid", OID: UUIDOID, Codec: UUIDCodec{}})
+	defaultMap.RegisterType(&Type{Name: "varbit", OID: VarbitOID, Codec: BitsCodec{}})
+	defaultMap.RegisterType(&Type{Name: "varchar", OID: VarcharOID, Codec: TextCodec{}})
+	defaultMap.RegisterType(&Type{Name: "xid", OID: XIDOID, Codec: Uint32Codec{}})
+	defaultMap.RegisterType(&Type{Name: "xid8", OID: XID8OID, Codec: Uint64Codec{}})
+	defaultMap.RegisterType(&Type{Name: "xml", OID: XMLOID, Codec: &XMLCodec{
+		Marshal: xml.Marshal,
+		// xml.Unmarshal does not support unmarshalling into *any. However, XMLCodec.DecodeValue calls Unmarshal with a
+		// *any. Wrap xml.Marshal with a function that copies the data into a new byte slice in this case. Not implementing
+		// directly in XMLCodec.DecodeValue to allow for the unlikely possibility that someone uses an alternative XML
+		// unmarshaler that does support unmarshalling into *any.
+		//
+		// https://github.com/jackc/pgx/issues/2227
+		// https://github.com/jackc/pgx/pull/2228
+		Unmarshal: func(data []byte, v any) error {
+			if v, ok := v.(*any); ok {
+				dstBuf := make([]byte, len(data))
+				copy(dstBuf, data)
+				*v = dstBuf
+				return nil
+			}
+			return xml.Unmarshal(data, v)
+		},
+	}})
+
+	// Range types
+	defaultMap.RegisterType(&Type{Name: "daterange", OID: DaterangeOID, Codec: &RangeCodec{ElementType: defaultMap.oidToType[DateOID]}})
+	defaultMap.RegisterType(&Type{Name: "int4range", OID: Int4rangeOID, Codec: &RangeCodec{ElementType: defaultMap.oidToType[Int4OID]}})
+	defaultMap.RegisterType(&Type{Name: "int8range", OID: Int8rangeOID, Codec: &RangeCodec{ElementType: defaultMap.oidToType[Int8OID]}})
+	defaultMap.RegisterType(&Type{Name: "numrange", OID: NumrangeOID, Codec: &RangeCodec{ElementType: defaultMap.oidToType[NumericOID]}})
+	defaultMap.RegisterType(&Type{Name: "tsrange", OID: TsrangeOID, Codec: &RangeCodec{ElementType: defaultMap.oidToType[TimestampOID]}})
+	defaultMap.RegisterType(&Type{Name: "tstzrange", OID: TstzrangeOID, Codec: &RangeCodec{ElementType: defaultMap.oidToType[TimestamptzOID]}})
+
+	// Multirange types
+	defaultMap.RegisterType(&Type{Name: "datemultirange", OID: DatemultirangeOID, Codec: &MultirangeCodec{ElementType: defaultMap.oidToType[DaterangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "int4multirange", OID: Int4multirangeOID, Codec: &MultirangeCodec{ElementType: defaultMap.oidToType[Int4rangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "int8multirange", OID: Int8multirangeOID, Codec: &MultirangeCodec{ElementType: defaultMap.oidToType[Int8rangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "nummultirange", OID: NummultirangeOID, Codec: &MultirangeCodec{ElementType: defaultMap.oidToType[NumrangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "tsmultirange", OID: TsmultirangeOID, Codec: &MultirangeCodec{ElementType: defaultMap.oidToType[TsrangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "tstzmultirange", OID: TstzmultirangeOID, Codec: &MultirangeCodec{ElementType: defaultMap.oidToType[TstzrangeOID]}})
+
+	// Array types
+	defaultMap.RegisterType(&Type{Name: "_aclitem", OID: ACLItemArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[ACLItemOID]}})
+	defaultMap.RegisterType(&Type{Name: "_bit", OID: BitArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[BitOID]}})
+	defaultMap.RegisterType(&Type{Name: "_bool", OID: BoolArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[BoolOID]}})
+	defaultMap.RegisterType(&Type{Name: "_box", OID: BoxArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[BoxOID]}})
+	defaultMap.RegisterType(&Type{Name: "_bpchar", OID: BPCharArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[BPCharOID]}})
+	defaultMap.RegisterType(&Type{Name: "_bytea", OID: ByteaArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[ByteaOID]}})
+	defaultMap.RegisterType(&Type{Name: "_char", OID: QCharArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[QCharOID]}})
+	defaultMap.RegisterType(&Type{Name: "_cid", OID: CIDArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[CIDOID]}})
+	defaultMap.RegisterType(&Type{Name: "_cidr", OID: CIDRArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[CIDROID]}})
+	defaultMap.RegisterType(&Type{Name: "_circle", OID: CircleArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[CircleOID]}})
+	defaultMap.RegisterType(&Type{Name: "_date", OID: DateArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[DateOID]}})
+	defaultMap.RegisterType(&Type{Name: "_daterange", OID: DaterangeArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[DaterangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "_float4", OID: Float4ArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[Float4OID]}})
+	defaultMap.RegisterType(&Type{Name: "_float8", OID: Float8ArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[Float8OID]}})
+	defaultMap.RegisterType(&Type{Name: "_inet", OID: InetArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[InetOID]}})
+	defaultMap.RegisterType(&Type{Name: "_int2", OID: Int2ArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[Int2OID]}})
+	defaultMap.RegisterType(&Type{Name: "_int4", OID: Int4ArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[Int4OID]}})
+	defaultMap.RegisterType(&Type{Name: "_int4range", OID: Int4rangeArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[Int4rangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "_int8", OID: Int8ArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[Int8OID]}})
+	defaultMap.RegisterType(&Type{Name: "_int8range", OID: Int8rangeArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[Int8rangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "_interval", OID: IntervalArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[IntervalOID]}})
+	defaultMap.RegisterType(&Type{Name: "_json", OID: JSONArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[JSONOID]}})
+	defaultMap.RegisterType(&Type{Name: "_jsonb", OID: JSONBArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[JSONBOID]}})
+	defaultMap.RegisterType(&Type{Name: "_jsonpath", OID: JSONPathArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[JSONPathOID]}})
+	defaultMap.RegisterType(&Type{Name: "_line", OID: LineArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[LineOID]}})
+	defaultMap.RegisterType(&Type{Name: "_lseg", OID: LsegArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[LsegOID]}})
+	defaultMap.RegisterType(&Type{Name: "_macaddr", OID: MacaddrArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[MacaddrOID]}})
+	defaultMap.RegisterType(&Type{Name: "_name", OID: NameArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[NameOID]}})
+	defaultMap.RegisterType(&Type{Name: "_numeric", OID: NumericArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[NumericOID]}})
+	defaultMap.RegisterType(&Type{Name: "_numrange", OID: NumrangeArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[NumrangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "_oid", OID: OIDArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[OIDOID]}})
+	defaultMap.RegisterType(&Type{Name: "_path", OID: PathArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[PathOID]}})
+	defaultMap.RegisterType(&Type{Name: "_point", OID: PointArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[PointOID]}})
+	defaultMap.RegisterType(&Type{Name: "_polygon", OID: PolygonArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[PolygonOID]}})
+	defaultMap.RegisterType(&Type{Name: "_record", OID: RecordArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[RecordOID]}})
+	defaultMap.RegisterType(&Type{Name: "_text", OID: TextArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[TextOID]}})
+	defaultMap.RegisterType(&Type{Name: "_tid", OID: TIDArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[TIDOID]}})
+	defaultMap.RegisterType(&Type{Name: "_tsvector", OID: TSVectorArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[TSVectorOID]}})
+	defaultMap.RegisterType(&Type{Name: "_time", OID: TimeArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[TimeOID]}})
+	defaultMap.RegisterType(&Type{Name: "_timestamp", OID: TimestampArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[TimestampOID]}})
+	defaultMap.RegisterType(&Type{Name: "_timestamptz", OID: TimestamptzArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[TimestamptzOID]}})
+	defaultMap.RegisterType(&Type{Name: "_tsrange", OID: TsrangeArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[TsrangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "_tstzrange", OID: TstzrangeArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[TstzrangeOID]}})
+	defaultMap.RegisterType(&Type{Name: "_uuid", OID: UUIDArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[UUIDOID]}})
+	defaultMap.RegisterType(&Type{Name: "_varbit", OID: VarbitArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[VarbitOID]}})
+	defaultMap.RegisterType(&Type{Name: "_varchar", OID: VarcharArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[VarcharOID]}})
+	defaultMap.RegisterType(&Type{Name: "_xid", OID: XIDArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[XIDOID]}})
+	defaultMap.RegisterType(&Type{Name: "_xid8", OID: XID8ArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[XID8OID]}})
+	defaultMap.RegisterType(&Type{Name: "_xml", OID: XMLArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[XMLOID]}})
+
+	// Integer types that directly map to a PostgreSQL type
+	registerDefaultPgTypeVariants[int16](defaultMap, "int2")
+	registerDefaultPgTypeVariants[int32](defaultMap, "int4")
+	registerDefaultPgTypeVariants[int64](defaultMap, "int8")
+
+	// Integer types that do not have a direct match to a PostgreSQL type
+	registerDefaultPgTypeVariants[int8](defaultMap, "int8")
+	registerDefaultPgTypeVariants[int](defaultMap, "int8")
+	registerDefaultPgTypeVariants[uint8](defaultMap, "int8")
+	registerDefaultPgTypeVariants[uint16](defaultMap, "int8")
+	registerDefaultPgTypeVariants[uint32](defaultMap, "int8")
+	registerDefaultPgTypeVariants[uint64](defaultMap, "numeric")
+	registerDefaultPgTypeVariants[uint](defaultMap, "numeric")
+
+	registerDefaultPgTypeVariants[float32](defaultMap, "float4")
+	registerDefaultPgTypeVariants[float64](defaultMap, "float8")
+
+	registerDefaultPgTypeVariants[bool](defaultMap, "bool")
+	registerDefaultPgTypeVariants[time.Time](defaultMap, "timestamptz")
+	registerDefaultPgTypeVariants[time.Duration](defaultMap, "interval")
+	registerDefaultPgTypeVariants[string](defaultMap, "text")
+	registerDefaultPgTypeVariants[json.RawMessage](defaultMap, "json")
+	registerDefaultPgTypeVariants[[]byte](defaultMap, "bytea")
+
+	registerDefaultPgTypeVariants[net.IP](defaultMap, "inet")
+	registerDefaultPgTypeVariants[net.IPNet](defaultMap, "cidr")
+	registerDefaultPgTypeVariants[netip.Addr](defaultMap, "inet")
+	registerDefaultPgTypeVariants[netip.Prefix](defaultMap, "cidr")
+
+	// pgtype provided structs
+	registerDefaultPgTypeVariants[Bits](defaultMap, "varbit")
+	registerDefaultPgTypeVariants[Bool](defaultMap, "bool")
+	registerDefaultPgTypeVariants[Box](defaultMap, "box")
+	registerDefaultPgTypeVariants[Circle](defaultMap, "circle")
+	registerDefaultPgTypeVariants[Date](defaultMap, "date")
+	registerDefaultPgTypeVariants[Range[Date]](defaultMap, "daterange")
+	registerDefaultPgTypeVariants[Multirange[Range[Date]]](defaultMap, "datemultirange")
+	registerDefaultPgTypeVariants[Float4](defaultMap, "float4")
+	registerDefaultPgTypeVariants[Float8](defaultMap, "float8")
+	registerDefaultPgTypeVariants[Range[Float8]](defaultMap, "numrange")                  // There is no PostgreSQL builtin float8range so map it to numrange.
+	registerDefaultPgTypeVariants[Multirange[Range[Float8]]](defaultMap, "nummultirange") // There is no PostgreSQL builtin float8multirange so map it to nummultirange.
+	registerDefaultPgTypeVariants[Int2](defaultMap, "int2")
+	registerDefaultPgTypeVariants[Int4](defaultMap, "int4")
+	registerDefaultPgTypeVariants[Range[Int4]](defaultMap, "int4range")
+	registerDefaultPgTypeVariants[Multirange[Range[Int4]]](defaultMap, "int4multirange")
+	registerDefaultPgTypeVariants[Int8](defaultMap, "int8")
+	registerDefaultPgTypeVariants[Range[Int8]](defaultMap, "int8range")
+	registerDefaultPgTypeVariants[Multirange[Range[Int8]]](defaultMap, "int8multirange")
+	registerDefaultPgTypeVariants[Interval](defaultMap, "interval")
+	registerDefaultPgTypeVariants[Line](defaultMap, "line")
+	registerDefaultPgTypeVariants[Lseg](defaultMap, "lseg")
+	registerDefaultPgTypeVariants[Numeric](defaultMap, "numeric")
+	registerDefaultPgTypeVariants[Range[Numeric]](defaultMap, "numrange")
+	registerDefaultPgTypeVariants[Multirange[Range[Numeric]]](defaultMap, "nummultirange")
+	registerDefaultPgTypeVariants[Path](defaultMap, "path")
+	registerDefaultPgTypeVariants[Point](defaultMap, "point")
+	registerDefaultPgTypeVariants[Polygon](defaultMap, "polygon")
+	registerDefaultPgTypeVariants[TID](defaultMap, "tid")
+	registerDefaultPgTypeVariants[Text](defaultMap, "text")
+	registerDefaultPgTypeVariants[Time](defaultMap, "time")
+	registerDefaultPgTypeVariants[Timestamp](defaultMap, "timestamp")
+	registerDefaultPgTypeVariants[Timestamptz](defaultMap, "timestamptz")
+	registerDefaultPgTypeVariants[Range[Timestamp]](defaultMap, "tsrange")
+	registerDefaultPgTypeVariants[Multirange[Range[Timestamp]]](defaultMap, "tsmultirange")
+	registerDefaultPgTypeVariants[Range[Timestamptz]](defaultMap, "tstzrange")
+	registerDefaultPgTypeVariants[Multirange[Range[Timestamptz]]](defaultMap, "tstzmultirange")
+	registerDefaultPgTypeVariants[TSVector](defaultMap, "tsvector")
+	registerDefaultPgTypeVariants[UUID](defaultMap, "uuid")
+
+	defaultMap.buildReflectTypeToType()
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/point.go b/vendor/github.com/jackc/pgx/v5/pgtype/point.go
new file mode 100644
index 000000000..d90cb7033
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/point.go
@@ -0,0 +1,266 @@
+package pgtype
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Vec2 struct {
+	X float64
+	Y float64
+}
+
+type PointScanner interface {
+	ScanPoint(v Point) error
+}
+
+type PointValuer interface {
+	PointValue() (Point, error)
+}
+
+type Point struct {
+	P     Vec2
+	Valid bool
+}
+
+// ScanPoint implements the [PointScanner] interface.
+func (p *Point) ScanPoint(v Point) error {
+	*p = v
+	return nil
+}
+
+// PointValue implements the [PointValuer] interface.
+func (p Point) PointValue() (Point, error) {
+	return p, nil
+}
+
+func parsePoint(src []byte) (*Point, error) {
+	if src == nil || bytes.Equal(src, []byte("null")) {
+		return &Point{}, nil
+	}
+
+	if len(src) < 5 {
+		return nil, fmt.Errorf("invalid length for point: %v", len(src))
+	}
+	if src[0] == '"' && src[len(src)-1] == '"' {
+		src = src[1 : len(src)-1]
+	}
+	sx, sy, found := strings.Cut(string(src[1:len(src)-1]), ",")
+	if !found {
+		return nil, fmt.Errorf("invalid format for point")
+	}
+
+	x, err := strconv.ParseFloat(sx, 64)
+	if err != nil {
+		return nil, err
+	}
+
+	y, err := strconv.ParseFloat(sy, 64)
+	if err != nil {
+		return nil, err
+	}
+
+	return &Point{P: Vec2{x, y}, Valid: true}, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Point) Scan(src any) error {
+	if src == nil {
+		*dst = Point{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToPointScanner{}.Scan([]byte(src), dst)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Point) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	buf, err := PointCodec{}.PlanEncode(nil, 0, TextFormatCode, src).Encode(src, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Point) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+
+	var buff bytes.Buffer
+	buff.WriteByte('"')
+	buff.WriteString(fmt.Sprintf("(%g,%g)", src.P.X, src.P.Y))
+	buff.WriteByte('"')
+	return buff.Bytes(), nil
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Point) UnmarshalJSON(point []byte) error {
+	p, err := parsePoint(point)
+	if err != nil {
+		return err
+	}
+	*dst = *p
+	return nil
+}
+
+type PointCodec struct{}
+
+func (PointCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (PointCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (PointCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(PointValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanPointCodecBinary{}
+	case TextFormatCode:
+		return encodePlanPointCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanPointCodecBinary struct{}
+
+func (encodePlanPointCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	point, err := value.(PointValuer).PointValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !point.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendUint64(buf, math.Float64bits(point.P.X))
+	buf = pgio.AppendUint64(buf, math.Float64bits(point.P.Y))
+	return buf, nil
+}
+
+type encodePlanPointCodecText struct{}
+
+func (encodePlanPointCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	point, err := value.(PointValuer).PointValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !point.Valid {
+		return nil, nil
+	}
+
+	return append(buf, fmt.Sprintf(`(%s,%s)`,
+		strconv.FormatFloat(point.P.X, 'f', -1, 64),
+		strconv.FormatFloat(point.P.Y, 'f', -1, 64),
+	)...), nil
+}
+
+func (PointCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(PointScanner); ok {
+			return scanPlanBinaryPointToPointScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(PointScanner); ok {
+			return scanPlanTextAnyToPointScanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c PointCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c PointCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var point Point
+	err := codecScan(c, m, oid, format, src, &point)
+	if err != nil {
+		return nil, err
+	}
+	return point, nil
+}
+
+type scanPlanBinaryPointToPointScanner struct{}
+
+func (scanPlanBinaryPointToPointScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(PointScanner)
+
+	if src == nil {
+		return scanner.ScanPoint(Point{})
+	}
+
+	if len(src) != 16 {
+		return fmt.Errorf("invalid length for point: %v", len(src))
+	}
+
+	x := binary.BigEndian.Uint64(src)
+	y := binary.BigEndian.Uint64(src[8:])
+
+	return scanner.ScanPoint(Point{
+		P:     Vec2{math.Float64frombits(x), math.Float64frombits(y)},
+		Valid: true,
+	})
+}
+
+type scanPlanTextAnyToPointScanner struct{}
+
+func (scanPlanTextAnyToPointScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(PointScanner)
+
+	if src == nil {
+		return scanner.ScanPoint(Point{})
+	}
+
+	if len(src) < 5 {
+		return fmt.Errorf("invalid length for point: %v", len(src))
+	}
+
+	sx, sy, found := strings.Cut(string(src[1:len(src)-1]), ",")
+	if !found {
+		return fmt.Errorf("invalid format for point")
+	}
+
+	x, err := strconv.ParseFloat(sx, 64)
+	if err != nil {
+		return err
+	}
+
+	y, err := strconv.ParseFloat(sy, 64)
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanPoint(Point{P: Vec2{x, y}, Valid: true})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/polygon.go b/vendor/github.com/jackc/pgx/v5/pgtype/polygon.go
new file mode 100644
index 000000000..34aa0a6a5
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/polygon.go
@@ -0,0 +1,261 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type PolygonScanner interface {
+	ScanPolygon(v Polygon) error
+}
+
+type PolygonValuer interface {
+	PolygonValue() (Polygon, error)
+}
+
+type Polygon struct {
+	P     []Vec2
+	Valid bool
+}
+
+// ScanPolygon implements the [PolygonScanner] interface.
+func (p *Polygon) ScanPolygon(v Polygon) error {
+	*p = v
+	return nil
+}
+
+// PolygonValue implements the [PolygonValuer] interface.
+func (p Polygon) PolygonValue() (Polygon, error) {
+	return p, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (p *Polygon) Scan(src any) error {
+	if src == nil {
+		*p = Polygon{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToPolygonScanner{}.Scan([]byte(src), p)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (p Polygon) Value() (driver.Value, error) {
+	if !p.Valid {
+		return nil, nil
+	}
+
+	buf, err := PolygonCodec{}.PlanEncode(nil, 0, TextFormatCode, p).Encode(p, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return string(buf), err
+}
+
+type PolygonCodec struct{}
+
+func (PolygonCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (PolygonCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (PolygonCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(PolygonValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanPolygonCodecBinary{}
+	case TextFormatCode:
+		return encodePlanPolygonCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanPolygonCodecBinary struct{}
+
+func (encodePlanPolygonCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	polygon, err := value.(PolygonValuer).PolygonValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !polygon.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendInt32(buf, int32(len(polygon.P)))
+
+	for _, p := range polygon.P {
+		buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
+		buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
+	}
+
+	return buf, nil
+}
+
+type encodePlanPolygonCodecText struct{}
+
+func (encodePlanPolygonCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	polygon, err := value.(PolygonValuer).PolygonValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !polygon.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, '(')
+
+	for i, p := range polygon.P {
+		if i > 0 {
+			buf = append(buf, ',')
+		}
+		buf = append(buf, fmt.Sprintf(`(%s,%s)`,
+			strconv.FormatFloat(p.X, 'f', -1, 64),
+			strconv.FormatFloat(p.Y, 'f', -1, 64),
+		)...)
+	}
+
+	buf = append(buf, ')')
+
+	return buf, nil
+}
+
+func (PolygonCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(PolygonScanner); ok {
+			return scanPlanBinaryPolygonToPolygonScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(PolygonScanner); ok {
+			return scanPlanTextAnyToPolygonScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryPolygonToPolygonScanner struct{}
+
+func (scanPlanBinaryPolygonToPolygonScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(PolygonScanner)
+
+	if src == nil {
+		return scanner.ScanPolygon(Polygon{})
+	}
+
+	if len(src) < 5 {
+		return fmt.Errorf("invalid length for polygon: %v", len(src))
+	}
+
+	pointCount := int(binary.BigEndian.Uint32(src))
+	rp := 4
+
+	if 4+pointCount*16 != len(src) {
+		return fmt.Errorf("invalid length for Polygon with %d points: %v", pointCount, len(src))
+	}
+
+	points := make([]Vec2, pointCount)
+	for i := range points {
+		x := binary.BigEndian.Uint64(src[rp:])
+		rp += 8
+		y := binary.BigEndian.Uint64(src[rp:])
+		rp += 8
+		points[i] = Vec2{math.Float64frombits(x), math.Float64frombits(y)}
+	}
+
+	return scanner.ScanPolygon(Polygon{
+		P:     points,
+		Valid: true,
+	})
+}
+
+type scanPlanTextAnyToPolygonScanner struct{}
+
+func (scanPlanTextAnyToPolygonScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(PolygonScanner)
+
+	if src == nil {
+		return scanner.ScanPolygon(Polygon{})
+	}
+
+	if len(src) < 7 {
+		return fmt.Errorf("invalid length for Polygon: %v", len(src))
+	}
+
+	points := make([]Vec2, 0)
+
+	// Expected format: ((x1,y1),...,(xn,yn))
+	str := string(src[1 : len(src)-1])
+
+	for {
+		if len(str) == 0 || str[0] != '(' {
+			return fmt.Errorf("invalid format for Polygon")
+		}
+		body, rest, found := strings.Cut(str[1:], ")")
+		if !found {
+			return fmt.Errorf("invalid format for Polygon")
+		}
+
+		sx, sy, found := strings.Cut(body, ",")
+		if !found {
+			return fmt.Errorf("invalid format for Polygon")
+		}
+		x, err := strconv.ParseFloat(sx, 64)
+		if err != nil {
+			return err
+		}
+		y, err := strconv.ParseFloat(sy, 64)
+		if err != nil {
+			return err
+		}
+
+		points = append(points, Vec2{x, y})
+
+		if rest == "" {
+			break
+		}
+		str, found = strings.CutPrefix(rest, ",")
+		if !found {
+			return fmt.Errorf("invalid format for Polygon")
+		}
+	}
+
+	return scanner.ScanPolygon(Polygon{P: points, Valid: true})
+}
+
+func (c PolygonCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c PolygonCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var polygon Polygon
+	err := codecScan(c, m, oid, format, src, &polygon)
+	if err != nil {
+		return nil, err
+	}
+	return polygon, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/qchar.go b/vendor/github.com/jackc/pgx/v5/pgtype/qchar.go
new file mode 100644
index 000000000..3de0b01fc
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/qchar.go
@@ -0,0 +1,163 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"fmt"
+	"math"
+)
+
+// QCharCodec is for PostgreSQL's special 8-bit-only "char" type more akin to the C
+// language's char type, or Go's byte type. (Note that the name in PostgreSQL
+// itself is "char", in double-quotes, and not char.) It gets used a lot in
+// PostgreSQL's system tables to hold a single ASCII character value (eg
+// pg_class.relkind). It is named Qchar for quoted char to disambiguate from SQL
+// standard type char.
+type QCharCodec struct{}
+
+func (QCharCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (QCharCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (QCharCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case TextFormatCode, BinaryFormatCode:
+		switch value.(type) {
+		case byte:
+			return encodePlanQcharCodecByte{}
+		case rune:
+			return encodePlanQcharCodecRune{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanQcharCodecByte struct{}
+
+func (encodePlanQcharCodecByte) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	b := value.(byte)
+	buf = append(buf, b)
+	return buf, nil
+}
+
+type encodePlanQcharCodecRune struct{}
+
+func (encodePlanQcharCodecRune) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	r := value.(rune)
+	if r > math.MaxUint8 {
+		return nil, fmt.Errorf(`%v cannot be encoded to "char"`, r)
+	}
+	b := byte(r)
+	buf = append(buf, b)
+	return buf, nil
+}
+
+func (QCharCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case TextFormatCode, BinaryFormatCode:
+		switch target.(type) {
+		case *byte:
+			return scanPlanQcharCodecByte{}
+		case *rune:
+			return scanPlanQcharCodecRune{}
+		case *string:
+			return scanPlanQcharCodecString{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanQcharCodecByte struct{}
+
+func (scanPlanQcharCodecByte) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) > 1 {
+		return fmt.Errorf(`invalid length for "char": %v`, len(src))
+	}
+
+	b := dst.(*byte)
+	// In the text format the zero value is returned as a zero byte value instead of 0
+	if len(src) == 0 {
+		*b = 0
+	} else {
+		*b = src[0]
+	}
+
+	return nil
+}
+
+type scanPlanQcharCodecRune struct{}
+
+func (scanPlanQcharCodecRune) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) > 1 {
+		return fmt.Errorf(`invalid length for "char": %v`, len(src))
+	}
+
+	r := dst.(*rune)
+	// In the text format the zero value is returned as a zero byte value instead of 0
+	if len(src) == 0 {
+		*r = 0
+	} else {
+		*r = rune(src[0])
+	}
+
+	return nil
+}
+
+type scanPlanQcharCodecString struct{}
+
+func (scanPlanQcharCodecString) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) > 1 {
+		return fmt.Errorf(`invalid length for "char": %v`, len(src))
+	}
+
+	p := dst.(*string)
+	// Copy the raw byte so the result matches the text-format *string scan path
+	// (string(src)) byte-for-byte. string(src[0]) would instead UTF-8-encode the
+	// byte as a code point, diverging for byte values >= 128.
+	*p = string(src)
+
+	return nil
+}
+
+func (c QCharCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var r rune
+	err := codecScan(c, m, oid, format, src, &r)
+	if err != nil {
+		return nil, err
+	}
+	return string(r), nil
+}
+
+func (c QCharCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var r rune
+	err := codecScan(c, m, oid, format, src, &r)
+	if err != nil {
+		return nil, err
+	}
+	return r, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/range.go b/vendor/github.com/jackc/pgx/v5/pgtype/range.go
new file mode 100644
index 000000000..dec153e50
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/range.go
@@ -0,0 +1,331 @@
+package pgtype
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+)
+
+type BoundType byte
+
+const (
+	Inclusive = BoundType('i')
+	Exclusive = BoundType('e')
+	Unbounded = BoundType('U')
+	Empty     = BoundType('E')
+)
+
+func (bt BoundType) String() string {
+	return string(bt)
+}
+
+type untypedTextRange struct {
+	Lower     string
+	Upper     string
+	LowerType BoundType
+	UpperType BoundType
+}
+
+func parseUntypedTextRange(src string) (*untypedTextRange, error) {
+	utr := &untypedTextRange{}
+	if src == "empty" {
+		utr.LowerType = Empty
+		utr.UpperType = Empty
+		return utr, nil
+	}
+
+	buf := bytes.NewBufferString(src)
+
+	skipWhitespace(buf)
+
+	r, _, err := buf.ReadRune()
+	if err != nil {
+		return nil, fmt.Errorf("invalid lower bound: %w", err)
+	}
+	switch r {
+	case '(':
+		utr.LowerType = Exclusive
+	case '[':
+		utr.LowerType = Inclusive
+	default:
+		return nil, fmt.Errorf("missing lower bound, instead got: %v", string(r))
+	}
+
+	r, _, err = buf.ReadRune()
+	if err != nil {
+		return nil, fmt.Errorf("invalid lower value: %w", err)
+	}
+	buf.UnreadRune()
+
+	if r == ',' {
+		utr.LowerType = Unbounded
+	} else {
+		utr.Lower, err = rangeParseValue(buf)
+		if err != nil {
+			return nil, fmt.Errorf("invalid lower value: %w", err)
+		}
+	}
+
+	r, _, err = buf.ReadRune()
+	if err != nil {
+		return nil, fmt.Errorf("missing range separator: %w", err)
+	}
+	if r != ',' {
+		return nil, fmt.Errorf("missing range separator: %v", r)
+	}
+
+	r, _, err = buf.ReadRune()
+	if err != nil {
+		return nil, fmt.Errorf("invalid upper value: %w", err)
+	}
+
+	if r == ')' || r == ']' {
+		utr.UpperType = Unbounded
+	} else {
+		buf.UnreadRune()
+		utr.Upper, err = rangeParseValue(buf)
+		if err != nil {
+			return nil, fmt.Errorf("invalid upper value: %w", err)
+		}
+
+		r, _, err = buf.ReadRune()
+		if err != nil {
+			return nil, fmt.Errorf("missing upper bound: %w", err)
+		}
+		switch r {
+		case ')':
+			utr.UpperType = Exclusive
+		case ']':
+			utr.UpperType = Inclusive
+		default:
+			return nil, fmt.Errorf("missing upper bound, instead got: %v", string(r))
+		}
+	}
+
+	skipWhitespace(buf)
+
+	if buf.Len() > 0 {
+		return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
+	}
+
+	return utr, nil
+}
+
+func rangeParseValue(buf *bytes.Buffer) (string, error) {
+	r, _, err := buf.ReadRune()
+	if err != nil {
+		return "", err
+	}
+	if r == '"' {
+		return rangeParseQuotedValue(buf)
+	}
+	buf.UnreadRune()
+
+	s := &bytes.Buffer{}
+
+	for {
+		r, _, err := buf.ReadRune()
+		if err != nil {
+			return "", err
+		}
+
+		switch r {
+		case '\\':
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return "", err
+			}
+		case ',', '[', ']', '(', ')':
+			buf.UnreadRune()
+			return s.String(), nil
+		}
+
+		s.WriteRune(r)
+	}
+}
+
+func rangeParseQuotedValue(buf *bytes.Buffer) (string, error) {
+	s := &bytes.Buffer{}
+
+	for {
+		r, _, err := buf.ReadRune()
+		if err != nil {
+			return "", err
+		}
+
+		switch r {
+		case '\\':
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return "", err
+			}
+		case '"':
+			r, _, err = buf.ReadRune()
+			if err != nil {
+				return "", err
+			}
+			if r != '"' {
+				buf.UnreadRune()
+				return s.String(), nil
+			}
+		}
+		s.WriteRune(r)
+	}
+}
+
+type untypedBinaryRange struct {
+	Lower     []byte
+	Upper     []byte
+	LowerType BoundType
+	UpperType BoundType
+}
+
+// 0 = ()      = 00000
+// 1 = empty   = 00001
+// 2 = [)      = 00010
+// 4 = (]      = 00100
+// 6 = []      = 00110
+// 8 = )       = 01000
+// 12 = ]      = 01100
+// 16 = (      = 10000
+// 18 = [      = 10010
+// 24 =        = 11000
+
+const (
+	emptyMask          = 1
+	lowerInclusiveMask = 2
+	upperInclusiveMask = 4
+	lowerUnboundedMask = 8
+	upperUnboundedMask = 16
+)
+
+func parseUntypedBinaryRange(src []byte) (*untypedBinaryRange, error) {
+	ubr := &untypedBinaryRange{}
+
+	if len(src) == 0 {
+		return nil, fmt.Errorf("range too short: %v", len(src))
+	}
+
+	rangeType := src[0]
+	rp := 1
+
+	if rangeType&emptyMask > 0 {
+		if len(src[rp:]) > 0 {
+			return nil, fmt.Errorf("unexpected trailing bytes parsing empty range: %v", len(src[rp:]))
+		}
+		ubr.LowerType = Empty
+		ubr.UpperType = Empty
+		return ubr, nil
+	}
+
+	switch {
+	case rangeType&lowerInclusiveMask > 0:
+		ubr.LowerType = Inclusive
+	case rangeType&lowerUnboundedMask > 0:
+		ubr.LowerType = Unbounded
+	default:
+		ubr.LowerType = Exclusive
+	}
+
+	switch {
+	case rangeType&upperInclusiveMask > 0:
+		ubr.UpperType = Inclusive
+	case rangeType&upperUnboundedMask > 0:
+		ubr.UpperType = Unbounded
+	default:
+		ubr.UpperType = Exclusive
+	}
+
+	if ubr.LowerType == Unbounded && ubr.UpperType == Unbounded {
+		if len(src[rp:]) > 0 {
+			return nil, fmt.Errorf("unexpected trailing bytes parsing unbounded range: %v", len(src[rp:]))
+		}
+		return ubr, nil
+	}
+
+	if len(src[rp:]) < 4 {
+		return nil, fmt.Errorf("too few bytes for size: %v", src[rp:])
+	}
+	valueLen := int(binary.BigEndian.Uint32(src[rp:]))
+	rp += 4
+
+	if valueLen < 0 || len(src[rp:]) < valueLen {
+		return nil, fmt.Errorf("range lower bound length %d exceeds remaining %d bytes", valueLen, len(src[rp:]))
+	}
+	val := src[rp : rp+valueLen]
+	rp += valueLen
+
+	if ubr.LowerType != Unbounded {
+		ubr.Lower = val
+	} else {
+		ubr.Upper = val
+		if len(src[rp:]) > 0 {
+			return nil, fmt.Errorf("unexpected trailing bytes parsing range: %v", len(src[rp:]))
+		}
+		return ubr, nil
+	}
+
+	if ubr.UpperType != Unbounded {
+		if len(src[rp:]) < 4 {
+			return nil, fmt.Errorf("too few bytes for size: %v", src[rp:])
+		}
+		valueLen := int(binary.BigEndian.Uint32(src[rp:]))
+		rp += 4
+		if valueLen < 0 || len(src[rp:]) < valueLen {
+			return nil, fmt.Errorf("range upper bound length %d exceeds remaining %d bytes", valueLen, len(src[rp:]))
+		}
+		ubr.Upper = src[rp : rp+valueLen]
+		rp += valueLen
+	}
+
+	if len(src[rp:]) > 0 {
+		return nil, fmt.Errorf("unexpected trailing bytes parsing range: %v", len(src[rp:]))
+	}
+
+	return ubr, nil
+}
+
+// Range is a generic range type.
+type Range[T any] struct {
+	Lower     T
+	Upper     T
+	LowerType BoundType
+	UpperType BoundType
+	Valid     bool
+}
+
+func (r Range[T]) IsNull() bool {
+	return !r.Valid
+}
+
+func (r Range[T]) BoundTypes() (lower, upper BoundType) {
+	return r.LowerType, r.UpperType
+}
+
+func (r Range[T]) Bounds() (lower, upper any) {
+	return &r.Lower, &r.Upper
+}
+
+func (r *Range[T]) ScanNull() error {
+	*r = Range[T]{}
+	return nil
+}
+
+func (r *Range[T]) ScanBounds() (lowerTarget, upperTarget any) {
+	return &r.Lower, &r.Upper
+}
+
+func (r *Range[T]) SetBoundTypes(lower, upper BoundType) error {
+	if lower == Unbounded || lower == Empty {
+		var zero T
+		r.Lower = zero
+	}
+	if upper == Unbounded || upper == Empty {
+		var zero T
+		r.Upper = zero
+	}
+	r.LowerType = lower
+	r.UpperType = upper
+	r.Valid = true
+	return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/range_codec.go b/vendor/github.com/jackc/pgx/v5/pgtype/range_codec.go
new file mode 100644
index 000000000..dc1ac8b06
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/range_codec.go
@@ -0,0 +1,377 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"fmt"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+// RangeValuer is a type that can be converted into a PostgreSQL range.
+type RangeValuer interface {
+	// IsNull returns true if the value is SQL NULL.
+	IsNull() bool
+
+	// BoundTypes returns the lower and upper bound types.
+	BoundTypes() (lower, upper BoundType)
+
+	// Bounds returns the lower and upper range values.
+	Bounds() (lower, upper any)
+}
+
+// RangeScanner is a type can be scanned from a PostgreSQL range.
+type RangeScanner interface {
+	// ScanNull sets the value to SQL NULL.
+	ScanNull() error
+
+	// ScanBounds returns values usable as a scan target. The returned values may not be scanned if the range is empty or
+	// the bound type is unbounded.
+	ScanBounds() (lowerTarget, upperTarget any)
+
+	// SetBoundTypes sets the lower and upper bound types. ScanBounds will be called and the returned values scanned
+	// (if appropriate) before SetBoundTypes is called. If the bound types are unbounded or empty this method must
+	// also set the bound values.
+	SetBoundTypes(lower, upper BoundType) error
+}
+
+// RangeCodec is a codec for any range type.
+type RangeCodec struct {
+	ElementType *Type
+}
+
+func (c *RangeCodec) FormatSupported(format int16) bool {
+	return c.ElementType.Codec.FormatSupported(format)
+}
+
+func (c *RangeCodec) PreferredFormat() int16 {
+	if c.FormatSupported(BinaryFormatCode) {
+		return BinaryFormatCode
+	}
+	return TextFormatCode
+}
+
+func (c *RangeCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(RangeValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return &encodePlanRangeCodecRangeValuerToBinary{rc: c, m: m}
+	case TextFormatCode:
+		return &encodePlanRangeCodecRangeValuerToText{rc: c, m: m}
+	}
+
+	return nil
+}
+
+type encodePlanRangeCodecRangeValuerToBinary struct {
+	rc *RangeCodec
+	m  *Map
+}
+
+func (plan *encodePlanRangeCodecRangeValuerToBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	getter := value.(RangeValuer)
+
+	if getter.IsNull() {
+		return nil, nil
+	}
+
+	lowerType, upperType := getter.BoundTypes()
+	lower, upper := getter.Bounds()
+
+	var rangeType byte
+	switch lowerType {
+	case Inclusive:
+		rangeType |= lowerInclusiveMask
+	case Unbounded:
+		rangeType |= lowerUnboundedMask
+	case Exclusive:
+	case Empty:
+		return append(buf, emptyMask), nil
+	default:
+		return nil, fmt.Errorf("unknown LowerType: %v", lowerType)
+	}
+
+	switch upperType {
+	case Inclusive:
+		rangeType |= upperInclusiveMask
+	case Unbounded:
+		rangeType |= upperUnboundedMask
+	case Exclusive:
+	default:
+		return nil, fmt.Errorf("unknown UpperType: %v", upperType)
+	}
+
+	buf = append(buf, rangeType)
+
+	if lowerType != Unbounded {
+		if lower == nil {
+			return nil, fmt.Errorf("Lower cannot be NULL unless LowerType is Unbounded")
+		}
+
+		sp := len(buf)
+		buf = pgio.AppendInt32(buf, -1)
+
+		lowerPlan := plan.m.PlanEncode(plan.rc.ElementType.OID, BinaryFormatCode, lower)
+		if lowerPlan == nil {
+			return nil, fmt.Errorf("cannot encode %v as element of range", lower)
+		}
+
+		buf, err = lowerPlan.Encode(lower, buf)
+		if err != nil {
+			return nil, fmt.Errorf("failed to encode %v as element of range: %w", lower, err)
+		}
+		if buf == nil {
+			return nil, fmt.Errorf("Lower cannot be NULL unless LowerType is Unbounded")
+		}
+
+		pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+	}
+
+	if upperType != Unbounded {
+		if upper == nil {
+			return nil, fmt.Errorf("Upper cannot be NULL unless UpperType is Unbounded")
+		}
+
+		sp := len(buf)
+		buf = pgio.AppendInt32(buf, -1)
+
+		upperPlan := plan.m.PlanEncode(plan.rc.ElementType.OID, BinaryFormatCode, upper)
+		if upperPlan == nil {
+			return nil, fmt.Errorf("cannot encode %v as element of range", upper)
+		}
+
+		buf, err = upperPlan.Encode(upper, buf)
+		if err != nil {
+			return nil, fmt.Errorf("failed to encode %v as element of range: %w", upper, err)
+		}
+		if buf == nil {
+			return nil, fmt.Errorf("Upper cannot be NULL unless UpperType is Unbounded")
+		}
+
+		pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+	}
+
+	return buf, nil
+}
+
+type encodePlanRangeCodecRangeValuerToText struct {
+	rc *RangeCodec
+	m  *Map
+}
+
+func (plan *encodePlanRangeCodecRangeValuerToText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	getter := value.(RangeValuer)
+
+	if getter.IsNull() {
+		return nil, nil
+	}
+
+	lowerType, upperType := getter.BoundTypes()
+	lower, upper := getter.Bounds()
+
+	switch lowerType {
+	case Exclusive, Unbounded:
+		buf = append(buf, '(')
+	case Inclusive:
+		buf = append(buf, '[')
+	case Empty:
+		return append(buf, "empty"...), nil
+	default:
+		return nil, fmt.Errorf("unknown lower bound type %v", lowerType)
+	}
+
+	if lowerType != Unbounded {
+		if lower == nil {
+			return nil, fmt.Errorf("Lower cannot be NULL unless LowerType is Unbounded")
+		}
+
+		lowerPlan := plan.m.PlanEncode(plan.rc.ElementType.OID, TextFormatCode, lower)
+		if lowerPlan == nil {
+			return nil, fmt.Errorf("cannot encode %v as element of range", lower)
+		}
+
+		buf, err = lowerPlan.Encode(lower, buf)
+		if err != nil {
+			return nil, fmt.Errorf("failed to encode %v as element of range: %w", lower, err)
+		}
+		if buf == nil {
+			return nil, fmt.Errorf("Lower cannot be NULL unless LowerType is Unbounded")
+		}
+	}
+
+	buf = append(buf, ',')
+
+	if upperType != Unbounded {
+		if upper == nil {
+			return nil, fmt.Errorf("Upper cannot be NULL unless UpperType is Unbounded")
+		}
+
+		upperPlan := plan.m.PlanEncode(plan.rc.ElementType.OID, TextFormatCode, upper)
+		if upperPlan == nil {
+			return nil, fmt.Errorf("cannot encode %v as element of range", upper)
+		}
+
+		buf, err = upperPlan.Encode(upper, buf)
+		if err != nil {
+			return nil, fmt.Errorf("failed to encode %v as element of range: %w", upper, err)
+		}
+		if buf == nil {
+			return nil, fmt.Errorf("Upper cannot be NULL unless UpperType is Unbounded")
+		}
+	}
+
+	switch upperType {
+	case Exclusive, Unbounded:
+		buf = append(buf, ')')
+	case Inclusive:
+		buf = append(buf, ']')
+	default:
+		return nil, fmt.Errorf("unknown upper bound type %v", upperType)
+	}
+
+	return buf, nil
+}
+
+func (c *RangeCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(RangeScanner); ok {
+			return &scanPlanBinaryRangeToRangeScanner{rc: c, m: m}
+		}
+	case TextFormatCode:
+		if _, ok := target.(RangeScanner); ok {
+			return &scanPlanTextRangeToRangeScanner{rc: c, m: m}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryRangeToRangeScanner struct {
+	rc *RangeCodec
+	m  *Map
+}
+
+func (plan *scanPlanBinaryRangeToRangeScanner) Scan(src []byte, target any) error {
+	rangeScanner := (target).(RangeScanner)
+
+	if src == nil {
+		return rangeScanner.ScanNull()
+	}
+
+	ubr, err := parseUntypedBinaryRange(src)
+	if err != nil {
+		return err
+	}
+
+	if ubr.LowerType == Empty {
+		return rangeScanner.SetBoundTypes(ubr.LowerType, ubr.UpperType)
+	}
+
+	lowerTarget, upperTarget := rangeScanner.ScanBounds()
+
+	if ubr.LowerType == Inclusive || ubr.LowerType == Exclusive {
+		lowerPlan := plan.m.PlanScan(plan.rc.ElementType.OID, BinaryFormatCode, lowerTarget)
+		if lowerPlan == nil {
+			return fmt.Errorf("cannot scan into %v from range element", lowerTarget)
+		}
+
+		err = lowerPlan.Scan(ubr.Lower, lowerTarget)
+		if err != nil {
+			return fmt.Errorf("cannot scan into %v from range element: %w", lowerTarget, err)
+		}
+	}
+
+	if ubr.UpperType == Inclusive || ubr.UpperType == Exclusive {
+		upperPlan := plan.m.PlanScan(plan.rc.ElementType.OID, BinaryFormatCode, upperTarget)
+		if upperPlan == nil {
+			return fmt.Errorf("cannot scan into %v from range element", upperTarget)
+		}
+
+		err = upperPlan.Scan(ubr.Upper, upperTarget)
+		if err != nil {
+			return fmt.Errorf("cannot scan into %v from range element: %w", upperTarget, err)
+		}
+	}
+
+	return rangeScanner.SetBoundTypes(ubr.LowerType, ubr.UpperType)
+}
+
+type scanPlanTextRangeToRangeScanner struct {
+	rc *RangeCodec
+	m  *Map
+}
+
+func (plan *scanPlanTextRangeToRangeScanner) Scan(src []byte, target any) error {
+	rangeScanner := (target).(RangeScanner)
+
+	if src == nil {
+		return rangeScanner.ScanNull()
+	}
+
+	utr, err := parseUntypedTextRange(string(src))
+	if err != nil {
+		return err
+	}
+
+	if utr.LowerType == Empty {
+		return rangeScanner.SetBoundTypes(utr.LowerType, utr.UpperType)
+	}
+
+	lowerTarget, upperTarget := rangeScanner.ScanBounds()
+
+	if utr.LowerType == Inclusive || utr.LowerType == Exclusive {
+		lowerPlan := plan.m.PlanScan(plan.rc.ElementType.OID, TextFormatCode, lowerTarget)
+		if lowerPlan == nil {
+			return fmt.Errorf("cannot scan into %v from range element", lowerTarget)
+		}
+
+		err = lowerPlan.Scan([]byte(utr.Lower), lowerTarget)
+		if err != nil {
+			return fmt.Errorf("cannot scan into %v from range element: %w", lowerTarget, err)
+		}
+	}
+
+	if utr.UpperType == Inclusive || utr.UpperType == Exclusive {
+		upperPlan := plan.m.PlanScan(plan.rc.ElementType.OID, TextFormatCode, upperTarget)
+		if upperPlan == nil {
+			return fmt.Errorf("cannot scan into %v from range element", upperTarget)
+		}
+
+		err = upperPlan.Scan([]byte(utr.Upper), upperTarget)
+		if err != nil {
+			return fmt.Errorf("cannot scan into %v from range element: %w", upperTarget, err)
+		}
+	}
+
+	return rangeScanner.SetBoundTypes(utr.LowerType, utr.UpperType)
+}
+
+func (c *RangeCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case TextFormatCode:
+		return string(src), nil
+	case BinaryFormatCode:
+		buf := make([]byte, len(src))
+		copy(buf, src)
+		return buf, nil
+	default:
+		return nil, fmt.Errorf("unknown format code %d", format)
+	}
+}
+
+func (c *RangeCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var r Range[any]
+	err := c.PlanScan(m, oid, format, &r).Scan(src, &r)
+	return r, err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/record_codec.go b/vendor/github.com/jackc/pgx/v5/pgtype/record_codec.go
new file mode 100644
index 000000000..a663e4dc2
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/record_codec.go
@@ -0,0 +1,123 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"fmt"
+)
+
+// ArrayGetter is a type that can be converted into a PostgreSQL array.
+
+// RecordCodec is a codec for the generic PostgreSQL record type such as is created with the "row" function. Record can
+// only decode the binary format. The text format output format from PostgreSQL does not include type information and
+// is therefore impossible to decode. Encoding is impossible because PostgreSQL does not support input of generic
+// records.
+type RecordCodec struct{}
+
+func (RecordCodec) FormatSupported(format int16) bool {
+	return format == BinaryFormatCode
+}
+
+func (RecordCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (RecordCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	return nil
+}
+
+func (RecordCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	if format == BinaryFormatCode {
+		if _, ok := target.(CompositeIndexScanner); ok {
+			return &scanPlanBinaryRecordToCompositeIndexScanner{m: m}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryRecordToCompositeIndexScanner struct {
+	m *Map
+}
+
+func (plan *scanPlanBinaryRecordToCompositeIndexScanner) Scan(src []byte, target any) error {
+	targetScanner := (target).(CompositeIndexScanner)
+
+	if src == nil {
+		return targetScanner.ScanNull()
+	}
+
+	scanner := NewCompositeBinaryScanner(plan.m, src)
+	for i := 0; scanner.Next(); i++ {
+		fieldTarget := targetScanner.ScanIndex(i)
+		if fieldTarget != nil {
+			fieldPlan := plan.m.PlanScan(scanner.OID(), BinaryFormatCode, fieldTarget)
+			if fieldPlan == nil {
+				return fmt.Errorf("unable to scan OID %d in binary format into %v", scanner.OID(), fieldTarget)
+			}
+
+			err := fieldPlan.Scan(scanner.Bytes(), fieldTarget)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	if err := scanner.Err(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (RecordCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case TextFormatCode:
+		return string(src), nil
+	case BinaryFormatCode:
+		buf := make([]byte, len(src))
+		copy(buf, src)
+		return buf, nil
+	default:
+		return nil, fmt.Errorf("unknown format code %d", format)
+	}
+}
+
+func (RecordCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	switch format {
+	case TextFormatCode:
+		return string(src), nil
+	case BinaryFormatCode:
+		scanner := NewCompositeBinaryScanner(m, src)
+		values := make([]any, scanner.FieldCount())
+		for i := 0; scanner.Next(); i++ {
+			var v any
+			fieldPlan := m.PlanScan(scanner.OID(), BinaryFormatCode, &v)
+			if fieldPlan == nil {
+				return nil, fmt.Errorf("unable to scan OID %d in binary format into %v", scanner.OID(), v)
+			}
+
+			err := fieldPlan.Scan(scanner.Bytes(), &v)
+			if err != nil {
+				return nil, err
+			}
+
+			values[i] = v
+		}
+
+		if err := scanner.Err(); err != nil {
+			return nil, err
+		}
+
+		return values, nil
+	default:
+		return nil, fmt.Errorf("unknown format code %d", format)
+	}
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/register_default_pg_types.go b/vendor/github.com/jackc/pgx/v5/pgtype/register_default_pg_types.go
new file mode 100644
index 000000000..be1ca4a18
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/register_default_pg_types.go
@@ -0,0 +1,35 @@
+//go:build !nopgxregisterdefaulttypes
+
+package pgtype
+
+func registerDefaultPgTypeVariants[T any](m *Map, name string) {
+	arrayName := "_" + name
+
+	var value T
+	m.RegisterDefaultPgType(value, name)  // T
+	m.RegisterDefaultPgType(&value, name) // *T
+
+	var sliceT []T
+	m.RegisterDefaultPgType(sliceT, arrayName)  // []T
+	m.RegisterDefaultPgType(&sliceT, arrayName) // *[]T
+
+	var slicePtrT []*T
+	m.RegisterDefaultPgType(slicePtrT, arrayName)  // []*T
+	m.RegisterDefaultPgType(&slicePtrT, arrayName) // *[]*T
+
+	var arrayOfT Array[T]
+	m.RegisterDefaultPgType(arrayOfT, arrayName)  // Array[T]
+	m.RegisterDefaultPgType(&arrayOfT, arrayName) // *Array[T]
+
+	var arrayOfPtrT Array[*T]
+	m.RegisterDefaultPgType(arrayOfPtrT, arrayName)  // Array[*T]
+	m.RegisterDefaultPgType(&arrayOfPtrT, arrayName) // *Array[*T]
+
+	var flatArrayOfT FlatArray[T]
+	m.RegisterDefaultPgType(flatArrayOfT, arrayName)  // FlatArray[T]
+	m.RegisterDefaultPgType(&flatArrayOfT, arrayName) // *FlatArray[T]
+
+	var flatArrayOfPtrT FlatArray[*T]
+	m.RegisterDefaultPgType(flatArrayOfPtrT, arrayName)  // FlatArray[*T]
+	m.RegisterDefaultPgType(&flatArrayOfPtrT, arrayName) // *FlatArray[*T]
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/register_default_pg_types_disabled.go b/vendor/github.com/jackc/pgx/v5/pgtype/register_default_pg_types_disabled.go
new file mode 100644
index 000000000..56fe7c226
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/register_default_pg_types_disabled.go
@@ -0,0 +1,6 @@
+//go:build nopgxregisterdefaulttypes
+
+package pgtype
+
+func registerDefaultPgTypeVariants[T any](m *Map, name string) {
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/text.go b/vendor/github.com/jackc/pgx/v5/pgtype/text.go
new file mode 100644
index 000000000..e08b12549
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/text.go
@@ -0,0 +1,226 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/json"
+	"fmt"
+)
+
+type TextScanner interface {
+	ScanText(v Text) error
+}
+
+type TextValuer interface {
+	TextValue() (Text, error)
+}
+
+type Text struct {
+	String string
+	Valid  bool
+}
+
+// ScanText implements the [TextScanner] interface.
+func (t *Text) ScanText(v Text) error {
+	*t = v
+	return nil
+}
+
+// TextValue implements the [TextValuer] interface.
+func (t Text) TextValue() (Text, error) {
+	return t, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Text) Scan(src any) error {
+	if src == nil {
+		*dst = Text{}
+		return nil
+	}
+
+	switch src := src.(type) {
+	case string:
+		*dst = Text{String: src, Valid: true}
+		return nil
+	case []byte:
+		*dst = Text{String: string(src), Valid: true}
+		return nil
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Text) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+	return src.String, nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Text) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+
+	return json.Marshal(src.String)
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Text) UnmarshalJSON(b []byte) error {
+	var s *string
+	err := json.Unmarshal(b, &s)
+	if err != nil {
+		return err
+	}
+
+	if s == nil {
+		*dst = Text{}
+	} else {
+		*dst = Text{String: *s, Valid: true}
+	}
+
+	return nil
+}
+
+type TextCodec struct{}
+
+func (TextCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (TextCodec) PreferredFormat() int16 {
+	return TextFormatCode
+}
+
+func (TextCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case TextFormatCode, BinaryFormatCode:
+		switch value.(type) {
+		case string:
+			return encodePlanTextCodecString{}
+		case []byte:
+			return encodePlanTextCodecByteSlice{}
+		case TextValuer:
+			return encodePlanTextCodecTextValuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanTextCodecString struct{}
+
+func (encodePlanTextCodecString) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	s := value.(string)
+	buf = append(buf, s...)
+	return buf, nil
+}
+
+type encodePlanTextCodecByteSlice struct{}
+
+func (encodePlanTextCodecByteSlice) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	s := value.([]byte)
+	buf = append(buf, s...)
+	return buf, nil
+}
+
+type encodePlanTextCodecStringer struct{}
+
+func (encodePlanTextCodecStringer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	s := value.(fmt.Stringer)
+	buf = append(buf, s.String()...)
+	return buf, nil
+}
+
+type encodePlanTextCodecTextValuer struct{}
+
+func (encodePlanTextCodecTextValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	text, err := value.(TextValuer).TextValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !text.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, text.String...)
+	return buf, nil
+}
+
+func (TextCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case TextFormatCode, BinaryFormatCode:
+		switch target.(type) {
+		case *string:
+			return scanPlanTextAnyToString{}
+		case *[]byte:
+			return scanPlanAnyToNewByteSlice{}
+		case BytesScanner:
+			return scanPlanAnyToByteScanner{}
+		case TextScanner:
+			return scanPlanTextAnyToTextScanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c TextCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return c.DecodeValue(m, oid, format, src)
+}
+
+func (c TextCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	return string(src), nil
+}
+
+type scanPlanTextAnyToString struct{}
+
+func (scanPlanTextAnyToString) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	p := (dst).(*string)
+	*p = string(src)
+
+	return nil
+}
+
+type scanPlanAnyToNewByteSlice struct{}
+
+func (scanPlanAnyToNewByteSlice) Scan(src []byte, dst any) error {
+	p := (dst).(*[]byte)
+	if src == nil {
+		*p = nil
+	} else {
+		*p = make([]byte, len(src))
+		copy(*p, src)
+	}
+
+	return nil
+}
+
+type scanPlanAnyToByteScanner struct{}
+
+func (scanPlanAnyToByteScanner) Scan(src []byte, dst any) error {
+	p := (dst).(BytesScanner)
+	return p.ScanBytes(src)
+}
+
+type scanPlanTextAnyToTextScanner struct{}
+
+func (scanPlanTextAnyToTextScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TextScanner)
+
+	if src == nil {
+		return scanner.ScanText(Text{})
+	}
+
+	return scanner.ScanText(Text{String: string(src), Valid: true})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/text_format_only_codec.go b/vendor/github.com/jackc/pgx/v5/pgtype/text_format_only_codec.go
new file mode 100644
index 000000000..d5e4cdb38
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/text_format_only_codec.go
@@ -0,0 +1,13 @@
+package pgtype
+
+type TextFormatOnlyCodec struct {
+	Codec
+}
+
+func (c *TextFormatOnlyCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode && c.Codec.FormatSupported(format)
+}
+
+func (TextFormatOnlyCodec) PreferredFormat() int16 {
+	return TextFormatCode
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/tid.go b/vendor/github.com/jackc/pgx/v5/pgtype/tid.go
new file mode 100644
index 000000000..98d067a65
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/tid.go
@@ -0,0 +1,240 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type TIDScanner interface {
+	ScanTID(v TID) error
+}
+
+type TIDValuer interface {
+	TIDValue() (TID, error)
+}
+
+// TID is PostgreSQL's Tuple Identifier type.
+//
+// When one does
+//
+//	select ctid, * from some_table;
+//
+// it is the data type of the ctid hidden system column.
+//
+// It is currently implemented as a pair unsigned two byte integers.
+// Its conversion functions can be found in src/backend/utils/adt/tid.c
+// in the PostgreSQL sources.
+type TID struct {
+	BlockNumber  uint32
+	OffsetNumber uint16
+	Valid        bool
+}
+
+// ScanTID implements the [TIDScanner] interface.
+func (b *TID) ScanTID(v TID) error {
+	*b = v
+	return nil
+}
+
+// TIDValue implements the [TIDValuer] interface.
+func (b TID) TIDValue() (TID, error) {
+	return b, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *TID) Scan(src any) error {
+	if src == nil {
+		*dst = TID{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToTIDScanner{}.Scan([]byte(src), dst)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src TID) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	buf, err := TIDCodec{}.PlanEncode(nil, 0, TextFormatCode, src).Encode(src, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type TIDCodec struct{}
+
+func (TIDCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (TIDCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (TIDCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(TIDValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanTIDCodecBinary{}
+	case TextFormatCode:
+		return encodePlanTIDCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanTIDCodecBinary struct{}
+
+func (encodePlanTIDCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	tid, err := value.(TIDValuer).TIDValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !tid.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendUint32(buf, tid.BlockNumber)
+	buf = pgio.AppendUint16(buf, tid.OffsetNumber)
+	return buf, nil
+}
+
+type encodePlanTIDCodecText struct{}
+
+func (encodePlanTIDCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	tid, err := value.(TIDValuer).TIDValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !tid.Valid {
+		return nil, nil
+	}
+
+	buf = append(buf, fmt.Sprintf(`(%d,%d)`, tid.BlockNumber, tid.OffsetNumber)...)
+	return buf, nil
+}
+
+func (TIDCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case TIDScanner:
+			return scanPlanBinaryTIDToTIDScanner{}
+		case TextScanner:
+			return scanPlanBinaryTIDToTextScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(TIDScanner); ok {
+			return scanPlanTextAnyToTIDScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryTIDToTIDScanner struct{}
+
+func (scanPlanBinaryTIDToTIDScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TIDScanner)
+
+	if src == nil {
+		return scanner.ScanTID(TID{})
+	}
+
+	if len(src) != 6 {
+		return fmt.Errorf("invalid length for tid: %v", len(src))
+	}
+
+	return scanner.ScanTID(TID{
+		BlockNumber:  binary.BigEndian.Uint32(src),
+		OffsetNumber: binary.BigEndian.Uint16(src[4:]),
+		Valid:        true,
+	})
+}
+
+type scanPlanBinaryTIDToTextScanner struct{}
+
+func (scanPlanBinaryTIDToTextScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TextScanner)
+
+	if src == nil {
+		return scanner.ScanText(Text{})
+	}
+
+	if len(src) != 6 {
+		return fmt.Errorf("invalid length for tid: %v", len(src))
+	}
+
+	blockNumber := binary.BigEndian.Uint32(src)
+	offsetNumber := binary.BigEndian.Uint16(src[4:])
+
+	return scanner.ScanText(Text{
+		String: fmt.Sprintf(`(%d,%d)`, blockNumber, offsetNumber),
+		Valid:  true,
+	})
+}
+
+type scanPlanTextAnyToTIDScanner struct{}
+
+func (scanPlanTextAnyToTIDScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TIDScanner)
+
+	if src == nil {
+		return scanner.ScanTID(TID{})
+	}
+
+	if len(src) < 5 {
+		return fmt.Errorf("invalid length for tid: %v", len(src))
+	}
+
+	block, offset, found := strings.Cut(string(src[1:len(src)-1]), ",")
+	if !found {
+		return fmt.Errorf("invalid format for tid")
+	}
+
+	blockNumber, err := strconv.ParseUint(block, 10, 32)
+	if err != nil {
+		return err
+	}
+
+	offsetNumber, err := strconv.ParseUint(offset, 10, 16)
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanTID(TID{BlockNumber: uint32(blockNumber), OffsetNumber: uint16(offsetNumber), Valid: true})
+}
+
+func (c TIDCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c TIDCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var tid TID
+	err := codecScan(c, m, oid, format, src, &tid)
+	if err != nil {
+		return nil, err
+	}
+	return tid, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/time.go b/vendor/github.com/jackc/pgx/v5/pgtype/time.go
new file mode 100644
index 000000000..72cdb5003
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/time.go
@@ -0,0 +1,273 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"strconv"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type TimeScanner interface {
+	ScanTime(v Time) error
+}
+
+type TimeValuer interface {
+	TimeValue() (Time, error)
+}
+
+// Time represents the PostgreSQL time type. The PostgreSQL time is a time of day without time zone.
+//
+// Time is represented as the number of microseconds since midnight in the same way that PostgreSQL does. Other time and
+// date types in pgtype can use time.Time as the underlying representation. However, pgtype.Time type cannot due to
+// needing to handle 24:00:00. time.Time converts that to 00:00:00 on the following day.
+//
+// The time with time zone type is not supported. Use of time with time zone is discouraged by the PostgreSQL documentation.
+type Time struct {
+	Microseconds int64 // Number of microseconds since midnight
+	Valid        bool
+}
+
+// ScanTime implements the [TimeScanner] interface.
+func (t *Time) ScanTime(v Time) error {
+	*t = v
+	return nil
+}
+
+// TimeValue implements the [TimeValuer] interface.
+func (t Time) TimeValue() (Time, error) {
+	return t, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (t *Time) Scan(src any) error {
+	if src == nil {
+		*t = Time{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		err := scanPlanTextAnyToTimeScanner{}.Scan([]byte(src), t)
+		if err != nil {
+			t.Microseconds = 0
+			t.Valid = false
+		}
+		return err
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (t Time) Value() (driver.Value, error) {
+	if !t.Valid {
+		return nil, nil
+	}
+
+	buf, err := TimeCodec{}.PlanEncode(nil, 0, TextFormatCode, t).Encode(t, nil)
+	if err != nil {
+		return nil, err
+	}
+	return string(buf), err
+}
+
+type TimeCodec struct{}
+
+func (TimeCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (TimeCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (TimeCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(TimeValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanTimeCodecBinary{}
+	case TextFormatCode:
+		return encodePlanTimeCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanTimeCodecBinary struct{}
+
+func (encodePlanTimeCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	t, err := value.(TimeValuer).TimeValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !t.Valid {
+		return nil, nil
+	}
+
+	return pgio.AppendInt64(buf, t.Microseconds), nil
+}
+
+type encodePlanTimeCodecText struct{}
+
+func (encodePlanTimeCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	t, err := value.(TimeValuer).TimeValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !t.Valid {
+		return nil, nil
+	}
+
+	usec := t.Microseconds
+	hours := usec / microsecondsPerHour
+	usec -= hours * microsecondsPerHour
+	minutes := usec / microsecondsPerMinute
+	usec -= minutes * microsecondsPerMinute
+	seconds := usec / microsecondsPerSecond
+	usec -= seconds * microsecondsPerSecond
+
+	s := fmt.Sprintf("%02d:%02d:%02d.%06d", hours, minutes, seconds, usec)
+
+	return append(buf, s...), nil
+}
+
+func (TimeCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case TimeScanner:
+			return scanPlanBinaryTimeToTimeScanner{}
+		case TextScanner:
+			return scanPlanBinaryTimeToTextScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(TimeScanner); ok {
+			return scanPlanTextAnyToTimeScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryTimeToTimeScanner struct{}
+
+func (scanPlanBinaryTimeToTimeScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TimeScanner)
+
+	if src == nil {
+		return scanner.ScanTime(Time{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for time: %v", len(src))
+	}
+
+	usec := int64(binary.BigEndian.Uint64(src))
+
+	return scanner.ScanTime(Time{Microseconds: usec, Valid: true})
+}
+
+type scanPlanBinaryTimeToTextScanner struct{}
+
+func (scanPlanBinaryTimeToTextScanner) Scan(src []byte, dst any) error {
+	ts, ok := (dst).(TextScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return ts.ScanText(Text{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for time: %v", len(src))
+	}
+
+	usec := int64(binary.BigEndian.Uint64(src))
+
+	tim := Time{Microseconds: usec, Valid: true}
+
+	buf, err := TimeCodec{}.PlanEncode(nil, 0, TextFormatCode, tim).Encode(tim, nil)
+	if err != nil {
+		return err
+	}
+
+	return ts.ScanText(Text{String: string(buf), Valid: true})
+}
+
+type scanPlanTextAnyToTimeScanner struct{}
+
+func (scanPlanTextAnyToTimeScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TimeScanner)
+
+	if src == nil {
+		return scanner.ScanTime(Time{})
+	}
+
+	s := string(src)
+
+	if len(s) < 8 || s[2] != ':' || s[5] != ':' {
+		return fmt.Errorf("cannot decode %v into Time", s)
+	}
+
+	hours, err := strconv.ParseInt(s[0:2], 10, 64)
+	if err != nil {
+		return fmt.Errorf("cannot decode %v into Time", s)
+	}
+	usec := hours * microsecondsPerHour
+
+	minutes, err := strconv.ParseInt(s[3:5], 10, 64)
+	if err != nil {
+		return fmt.Errorf("cannot decode %v into Time", s)
+	}
+	usec += minutes * microsecondsPerMinute
+
+	seconds, err := strconv.ParseInt(s[6:8], 10, 64)
+	if err != nil {
+		return fmt.Errorf("cannot decode %v into Time", s)
+	}
+	usec += seconds * microsecondsPerSecond
+
+	if len(s) > 9 {
+		if s[8] != '.' || len(s) > 15 {
+			return fmt.Errorf("cannot decode %v into Time", s)
+		}
+
+		fraction := s[9:]
+		n, err := strconv.ParseInt(fraction, 10, 64)
+		if err != nil {
+			return fmt.Errorf("cannot decode %v into Time", s)
+		}
+
+		for i := len(fraction); i < 6; i++ {
+			n *= 10
+		}
+
+		usec += n
+	}
+
+	return scanner.ScanTime(Time{Microseconds: usec, Valid: true})
+}
+
+func (c TimeCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c TimeCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var t Time
+	err := codecScan(c, m, oid, format, src, &t)
+	if err != nil {
+		return nil, err
+	}
+	return t, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/timestamp.go b/vendor/github.com/jackc/pgx/v5/pgtype/timestamp.go
new file mode 100644
index 000000000..405c77e96
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/timestamp.go
@@ -0,0 +1,368 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"encoding/json"
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+const (
+	pgTimestampFormat = "2006-01-02 15:04:05.999999999"
+	jsonISO8601       = "2006-01-02T15:04:05.999999999"
+)
+
+type TimestampScanner interface {
+	ScanTimestamp(v Timestamp) error
+}
+
+type TimestampValuer interface {
+	TimestampValue() (Timestamp, error)
+}
+
+// Timestamp represents the PostgreSQL timestamp type.
+type Timestamp struct {
+	Time             time.Time // Time zone will be ignored when encoding to PostgreSQL.
+	InfinityModifier InfinityModifier
+	Valid            bool
+}
+
+// ScanTimestamp implements the [TimestampScanner] interface.
+func (ts *Timestamp) ScanTimestamp(v Timestamp) error {
+	*ts = v
+	return nil
+}
+
+// TimestampValue implements the [TimestampValuer] interface.
+func (ts Timestamp) TimestampValue() (Timestamp, error) {
+	return ts, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (ts *Timestamp) Scan(src any) error {
+	if src == nil {
+		*ts = Timestamp{}
+		return nil
+	}
+
+	switch src := src.(type) {
+	case string:
+		return (&scanPlanTextTimestampToTimestampScanner{}).Scan([]byte(src), ts)
+	case time.Time:
+		*ts = Timestamp{Time: src, Valid: true}
+		return nil
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (ts Timestamp) Value() (driver.Value, error) {
+	if !ts.Valid {
+		return nil, nil
+	}
+
+	if ts.InfinityModifier != Finite {
+		return ts.InfinityModifier.String(), nil
+	}
+	return ts.Time, nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (ts Timestamp) MarshalJSON() ([]byte, error) {
+	if !ts.Valid {
+		return []byte("null"), nil
+	}
+
+	var s string
+
+	switch ts.InfinityModifier {
+	case Finite:
+		s = ts.Time.Format(jsonISO8601)
+	case Infinity:
+		s = "infinity"
+	case NegativeInfinity:
+		s = "-infinity"
+	}
+
+	return json.Marshal(s)
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (ts *Timestamp) UnmarshalJSON(b []byte) error {
+	var s *string
+	err := json.Unmarshal(b, &s)
+	if err != nil {
+		return err
+	}
+
+	if s == nil {
+		*ts = Timestamp{}
+		return nil
+	}
+
+	switch *s {
+	case "infinity":
+		*ts = Timestamp{Valid: true, InfinityModifier: Infinity}
+	case "-infinity":
+		*ts = Timestamp{Valid: true, InfinityModifier: -Infinity}
+	default:
+		// Parse time with or without timezone
+		tss := *s
+		// PostgreSQL uses ISO 8601 without timezone for to_json function and casting from a string to timestamp
+		tim, err := time.Parse(time.RFC3339Nano, tss)
+		if err == nil {
+			*ts = Timestamp{Time: tim, Valid: true}
+			return nil
+		}
+		tim, err = time.ParseInLocation(jsonISO8601, tss, time.UTC)
+		if err == nil {
+			*ts = Timestamp{Time: tim, Valid: true}
+			return nil
+		}
+		ts.Valid = false
+		return fmt.Errorf("cannot unmarshal %s to timestamp with layout %s or %s (%w)",
+			*s, time.RFC3339Nano, jsonISO8601, err)
+	}
+	return nil
+}
+
+type TimestampCodec struct {
+	// ScanLocation is the location that the time is assumed to be in for scanning. This is different from
+	// TimestamptzCodec.ScanLocation in that this setting does change the instant in time that the timestamp represents.
+	ScanLocation *time.Location
+}
+
+func (*TimestampCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (*TimestampCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (*TimestampCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(TimestampValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanTimestampCodecBinary{}
+	case TextFormatCode:
+		return encodePlanTimestampCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanTimestampCodecBinary struct{}
+
+func (encodePlanTimestampCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	ts, err := value.(TimestampValuer).TimestampValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !ts.Valid {
+		return nil, nil
+	}
+
+	var microsecSinceY2K int64
+	switch ts.InfinityModifier {
+	case Finite:
+		t := discardTimeZone(ts.Time)
+		microsecSinceUnixEpoch := t.Unix()*1_000_000 + int64(t.Nanosecond())/1000
+		microsecSinceY2K = microsecSinceUnixEpoch - microsecFromUnixEpochToY2K
+	case Infinity:
+		microsecSinceY2K = infinityMicrosecondOffset
+	case NegativeInfinity:
+		microsecSinceY2K = negativeInfinityMicrosecondOffset
+	}
+
+	buf = pgio.AppendInt64(buf, microsecSinceY2K)
+
+	return buf, nil
+}
+
+type encodePlanTimestampCodecText struct{}
+
+func (encodePlanTimestampCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	ts, err := value.(TimestampValuer).TimestampValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !ts.Valid {
+		return nil, nil
+	}
+
+	var s string
+
+	switch ts.InfinityModifier {
+	case Finite:
+		t := discardTimeZone(ts.Time)
+
+		// Year 0000 is 1 BC
+		bc := false
+		if year := t.Year(); year <= 0 {
+			year = -year + 1
+			t = time.Date(year, t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), time.UTC)
+			bc = true
+		}
+
+		s = t.Truncate(time.Microsecond).Format(pgTimestampFormat)
+
+		if bc {
+			s += " BC"
+		}
+	case Infinity:
+		s = "infinity"
+	case NegativeInfinity:
+		s = "-infinity"
+	}
+
+	buf = append(buf, s...)
+
+	return buf, nil
+}
+
+func discardTimeZone(t time.Time) time.Time {
+	if t.Location() != time.UTC {
+		return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), time.UTC)
+	}
+
+	return t
+}
+
+func (c *TimestampCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(TimestampScanner); ok {
+			return &scanPlanBinaryTimestampToTimestampScanner{location: c.ScanLocation}
+		}
+	case TextFormatCode:
+		if _, ok := target.(TimestampScanner); ok {
+			return &scanPlanTextTimestampToTimestampScanner{location: c.ScanLocation}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryTimestampToTimestampScanner struct{ location *time.Location }
+
+func (plan *scanPlanBinaryTimestampToTimestampScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TimestampScanner)
+
+	if src == nil {
+		return scanner.ScanTimestamp(Timestamp{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for timestamp: %v", len(src))
+	}
+
+	var ts Timestamp
+	microsecSinceY2K := int64(binary.BigEndian.Uint64(src))
+
+	switch microsecSinceY2K {
+	case infinityMicrosecondOffset:
+		ts = Timestamp{Valid: true, InfinityModifier: Infinity}
+	case negativeInfinityMicrosecondOffset:
+		ts = Timestamp{Valid: true, InfinityModifier: -Infinity}
+	default:
+		tim := time.Unix(
+			microsecFromUnixEpochToY2K/1_000_000+microsecSinceY2K/1_000_000,
+			(microsecFromUnixEpochToY2K%1_000_000*1_000)+(microsecSinceY2K%1_000_000*1000),
+		).UTC()
+		if plan.location != nil {
+			tim = time.Date(tim.Year(), tim.Month(), tim.Day(), tim.Hour(), tim.Minute(), tim.Second(), tim.Nanosecond(), plan.location)
+		}
+		ts = Timestamp{Time: tim, Valid: true}
+	}
+
+	return scanner.ScanTimestamp(ts)
+}
+
+type scanPlanTextTimestampToTimestampScanner struct{ location *time.Location }
+
+func (plan *scanPlanTextTimestampToTimestampScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TimestampScanner)
+
+	if src == nil {
+		return scanner.ScanTimestamp(Timestamp{})
+	}
+
+	var ts Timestamp
+	sbuf := string(src)
+	switch sbuf {
+	case "infinity":
+		ts = Timestamp{Valid: true, InfinityModifier: Infinity}
+	case "-infinity":
+		ts = Timestamp{Valid: true, InfinityModifier: -Infinity}
+	default:
+		bc := false
+		if strings.HasSuffix(sbuf, " BC") {
+			sbuf = sbuf[:len(sbuf)-3]
+			bc = true
+		}
+		tim, err := time.Parse(pgTimestampFormat, sbuf)
+		if err != nil {
+			return err
+		}
+
+		if bc {
+			year := -tim.Year() + 1
+			tim = time.Date(year, tim.Month(), tim.Day(), tim.Hour(), tim.Minute(), tim.Second(), tim.Nanosecond(), tim.Location())
+		}
+
+		if plan.location != nil {
+			tim = time.Date(tim.Year(), tim.Month(), tim.Day(), tim.Hour(), tim.Minute(), tim.Second(), tim.Nanosecond(), plan.location)
+		}
+
+		ts = Timestamp{Time: tim, Valid: true}
+	}
+
+	return scanner.ScanTimestamp(ts)
+}
+
+func (c *TimestampCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var ts Timestamp
+	err := codecScan(c, m, oid, format, src, &ts)
+	if err != nil {
+		return nil, err
+	}
+
+	if ts.InfinityModifier != Finite {
+		return ts.InfinityModifier.String(), nil
+	}
+
+	return ts.Time, nil
+}
+
+func (c *TimestampCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var ts Timestamp
+	err := codecScan(c, m, oid, format, src, &ts)
+	if err != nil {
+		return nil, err
+	}
+
+	if ts.InfinityModifier != Finite {
+		return ts.InfinityModifier, nil
+	}
+
+	return ts.Time, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/timestamptz.go b/vendor/github.com/jackc/pgx/v5/pgtype/timestamptz.go
new file mode 100644
index 000000000..139312a59
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/timestamptz.go
@@ -0,0 +1,370 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"encoding/json"
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+const (
+	pgTimestamptzHourFormat    = "2006-01-02 15:04:05.999999999Z07"
+	pgTimestamptzMinuteFormat  = "2006-01-02 15:04:05.999999999Z07:00"
+	pgTimestamptzSecondFormat  = "2006-01-02 15:04:05.999999999Z07:00:00"
+	microsecFromUnixEpochToY2K = 946_684_800 * 1_000_000
+)
+
+const (
+	negativeInfinityMicrosecondOffset = -9223372036854775808
+	infinityMicrosecondOffset         = 9223372036854775807
+)
+
+type TimestamptzScanner interface {
+	ScanTimestamptz(v Timestamptz) error
+}
+
+type TimestamptzValuer interface {
+	TimestamptzValue() (Timestamptz, error)
+}
+
+// Timestamptz represents the PostgreSQL timestamptz type.
+type Timestamptz struct {
+	Time             time.Time
+	InfinityModifier InfinityModifier
+	Valid            bool
+}
+
+// ScanTimestamptz implements the [TimestamptzScanner] interface.
+func (tstz *Timestamptz) ScanTimestamptz(v Timestamptz) error {
+	*tstz = v
+	return nil
+}
+
+// TimestamptzValue implements the [TimestamptzValuer] interface.
+func (tstz Timestamptz) TimestamptzValue() (Timestamptz, error) {
+	return tstz, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (tstz *Timestamptz) Scan(src any) error {
+	if src == nil {
+		*tstz = Timestamptz{}
+		return nil
+	}
+
+	switch src := src.(type) {
+	case string:
+		return (&scanPlanTextTimestamptzToTimestamptzScanner{}).Scan([]byte(src), tstz)
+	case time.Time:
+		*tstz = Timestamptz{Time: src, Valid: true}
+		return nil
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (tstz Timestamptz) Value() (driver.Value, error) {
+	if !tstz.Valid {
+		return nil, nil
+	}
+
+	if tstz.InfinityModifier != Finite {
+		return tstz.InfinityModifier.String(), nil
+	}
+	return tstz.Time, nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (tstz Timestamptz) MarshalJSON() ([]byte, error) {
+	if !tstz.Valid {
+		return []byte("null"), nil
+	}
+
+	var s string
+
+	switch tstz.InfinityModifier {
+	case Finite:
+		s = tstz.Time.Format(time.RFC3339Nano)
+	case Infinity:
+		s = "infinity"
+	case NegativeInfinity:
+		s = "-infinity"
+	}
+
+	return json.Marshal(s)
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (tstz *Timestamptz) UnmarshalJSON(b []byte) error {
+	var s *string
+	err := json.Unmarshal(b, &s)
+	if err != nil {
+		return err
+	}
+
+	if s == nil {
+		*tstz = Timestamptz{}
+		return nil
+	}
+
+	switch *s {
+	case "infinity":
+		*tstz = Timestamptz{Valid: true, InfinityModifier: Infinity}
+	case "-infinity":
+		*tstz = Timestamptz{Valid: true, InfinityModifier: -Infinity}
+	default:
+		// PostgreSQL uses ISO 8601 for to_json function and casting from a string to timestamptz
+		tim, err := time.Parse(time.RFC3339Nano, *s)
+		if err != nil {
+			return err
+		}
+
+		*tstz = Timestamptz{Time: tim, Valid: true}
+	}
+
+	return nil
+}
+
+type TimestamptzCodec struct {
+	// ScanLocation is the location to return scanned timestamptz values in. This does not change the instant in time that
+	// the timestamptz represents.
+	ScanLocation *time.Location
+}
+
+func (*TimestamptzCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (*TimestamptzCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (*TimestamptzCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(TimestamptzValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanTimestamptzCodecBinary{}
+	case TextFormatCode:
+		return encodePlanTimestamptzCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanTimestamptzCodecBinary struct{}
+
+func (encodePlanTimestamptzCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	ts, err := value.(TimestamptzValuer).TimestamptzValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !ts.Valid {
+		return nil, nil
+	}
+
+	var microsecSinceY2K int64
+	switch ts.InfinityModifier {
+	case Finite:
+		microsecSinceUnixEpoch := ts.Time.Unix()*1000000 + int64(ts.Time.Nanosecond())/1000
+		microsecSinceY2K = microsecSinceUnixEpoch - microsecFromUnixEpochToY2K
+	case Infinity:
+		microsecSinceY2K = infinityMicrosecondOffset
+	case NegativeInfinity:
+		microsecSinceY2K = negativeInfinityMicrosecondOffset
+	}
+
+	buf = pgio.AppendInt64(buf, microsecSinceY2K)
+
+	return buf, nil
+}
+
+type encodePlanTimestamptzCodecText struct{}
+
+func (encodePlanTimestamptzCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	ts, err := value.(TimestamptzValuer).TimestamptzValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !ts.Valid {
+		return nil, nil
+	}
+
+	var s string
+
+	switch ts.InfinityModifier {
+	case Finite:
+
+		t := ts.Time.UTC().Truncate(time.Microsecond)
+
+		// Year 0000 is 1 BC
+		bc := false
+		if year := t.Year(); year <= 0 {
+			year = -year + 1
+			t = time.Date(year, t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), time.UTC)
+			bc = true
+		}
+
+		s = t.Format(pgTimestamptzSecondFormat)
+
+		if bc {
+			s += " BC"
+		}
+	case Infinity:
+		s = "infinity"
+	case NegativeInfinity:
+		s = "-infinity"
+	}
+
+	buf = append(buf, s...)
+
+	return buf, nil
+}
+
+func (c *TimestamptzCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(TimestamptzScanner); ok {
+			return &scanPlanBinaryTimestamptzToTimestamptzScanner{location: c.ScanLocation}
+		}
+	case TextFormatCode:
+		if _, ok := target.(TimestamptzScanner); ok {
+			return &scanPlanTextTimestamptzToTimestamptzScanner{location: c.ScanLocation}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryTimestamptzToTimestamptzScanner struct{ location *time.Location }
+
+func (plan *scanPlanBinaryTimestamptzToTimestamptzScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TimestamptzScanner)
+
+	if src == nil {
+		return scanner.ScanTimestamptz(Timestamptz{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for timestamptz: %v", len(src))
+	}
+
+	var tstz Timestamptz
+	microsecSinceY2K := int64(binary.BigEndian.Uint64(src))
+
+	switch microsecSinceY2K {
+	case infinityMicrosecondOffset:
+		tstz = Timestamptz{Valid: true, InfinityModifier: Infinity}
+	case negativeInfinityMicrosecondOffset:
+		tstz = Timestamptz{Valid: true, InfinityModifier: -Infinity}
+	default:
+		tim := time.Unix(
+			microsecFromUnixEpochToY2K/1_000_000+microsecSinceY2K/1_000_000,
+			(microsecFromUnixEpochToY2K%1_000_000*1_000)+(microsecSinceY2K%1_000_000*1_000),
+		)
+		if plan.location != nil {
+			tim = tim.In(plan.location)
+		}
+		tstz = Timestamptz{Time: tim, Valid: true}
+	}
+
+	return scanner.ScanTimestamptz(tstz)
+}
+
+type scanPlanTextTimestamptzToTimestamptzScanner struct{ location *time.Location }
+
+func (plan *scanPlanTextTimestamptzToTimestamptzScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TimestamptzScanner)
+
+	if src == nil {
+		return scanner.ScanTimestamptz(Timestamptz{})
+	}
+
+	var tstz Timestamptz
+	sbuf := string(src)
+	switch sbuf {
+	case "infinity":
+		tstz = Timestamptz{Valid: true, InfinityModifier: Infinity}
+	case "-infinity":
+		tstz = Timestamptz{Valid: true, InfinityModifier: -Infinity}
+	default:
+		bc := false
+		if strings.HasSuffix(sbuf, " BC") {
+			sbuf = sbuf[:len(sbuf)-3]
+			bc = true
+		}
+
+		var format string
+		switch {
+		case len(sbuf) >= 9 && (sbuf[len(sbuf)-9] == '-' || sbuf[len(sbuf)-9] == '+'):
+			format = pgTimestamptzSecondFormat
+		case len(sbuf) >= 6 && (sbuf[len(sbuf)-6] == '-' || sbuf[len(sbuf)-6] == '+'):
+			format = pgTimestamptzMinuteFormat
+		default:
+			format = pgTimestamptzHourFormat
+		}
+
+		tim, err := time.Parse(format, sbuf)
+		if err != nil {
+			return err
+		}
+
+		if bc {
+			year := -tim.Year() + 1
+			tim = time.Date(year, tim.Month(), tim.Day(), tim.Hour(), tim.Minute(), tim.Second(), tim.Nanosecond(), tim.Location())
+		}
+
+		if plan.location != nil {
+			tim = tim.In(plan.location)
+		}
+
+		tstz = Timestamptz{Time: tim, Valid: true}
+	}
+
+	return scanner.ScanTimestamptz(tstz)
+}
+
+func (c *TimestamptzCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var tstz Timestamptz
+	err := codecScan(c, m, oid, format, src, &tstz)
+	if err != nil {
+		return nil, err
+	}
+
+	if tstz.InfinityModifier != Finite {
+		return tstz.InfinityModifier.String(), nil
+	}
+
+	return tstz.Time, nil
+}
+
+func (c *TimestamptzCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var tstz Timestamptz
+	err := codecScan(c, m, oid, format, src, &tstz)
+	if err != nil {
+		return nil, err
+	}
+
+	if tstz.InfinityModifier != Finite {
+		return tstz.InfinityModifier, nil
+	}
+
+	return tstz.Time, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/tsvector.go b/vendor/github.com/jackc/pgx/v5/pgtype/tsvector.go
new file mode 100644
index 000000000..cc7b83167
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/tsvector.go
@@ -0,0 +1,514 @@
+package pgtype
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type TSVectorScanner interface {
+	ScanTSVector(TSVector) error
+}
+
+type TSVectorValuer interface {
+	TSVectorValue() (TSVector, error)
+}
+
+// TSVector represents a PostgreSQL tsvector value.
+type TSVector struct {
+	Lexemes []TSVectorLexeme
+	Valid   bool
+}
+
+// TSVectorLexeme represents a lexeme within a tsvector, consisting of a word and its positions.
+type TSVectorLexeme struct {
+	Word      string
+	Positions []TSVectorPosition
+}
+
+// ScanTSVector implements the [TSVectorScanner] interface.
+func (t *TSVector) ScanTSVector(v TSVector) error {
+	*t = v
+	return nil
+}
+
+// TSVectorValue implements the [TSVectorValuer] interface.
+func (t TSVector) TSVectorValue() (TSVector, error) {
+	return t, nil
+}
+
+func (t TSVector) String() string {
+	buf, _ := encodePlanTSVectorCodecText{}.Encode(t, nil)
+	return string(buf)
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (t *TSVector) Scan(src any) error {
+	if src == nil {
+		*t = TSVector{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		return scanPlanTextAnyToTSVectorScanner{}.scanString(src, t)
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (t TSVector) Value() (driver.Value, error) {
+	if !t.Valid {
+		return nil, nil
+	}
+
+	buf, err := TSVectorCodec{}.PlanEncode(nil, 0, TextFormatCode, t).Encode(t, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return string(buf), nil
+}
+
+// TSVectorWeight represents the weight label of a lexeme position in a tsvector.
+type TSVectorWeight byte
+
+const (
+	TSVectorWeightA = TSVectorWeight('A')
+	TSVectorWeightB = TSVectorWeight('B')
+	TSVectorWeightC = TSVectorWeight('C')
+	TSVectorWeightD = TSVectorWeight('D')
+)
+
+// tsvectorWeightToBinary converts a TSVectorWeight to the 2-bit binary encoding used by PostgreSQL.
+func tsvectorWeightToBinary(w TSVectorWeight) uint16 {
+	switch w {
+	case TSVectorWeightA:
+		return 3
+	case TSVectorWeightB:
+		return 2
+	case TSVectorWeightC:
+		return 1
+	default:
+		return 0 // D or unset
+	}
+}
+
+// tsvectorWeightFromBinary converts a 2-bit binary weight value to a TSVectorWeight.
+func tsvectorWeightFromBinary(b uint16) TSVectorWeight {
+	switch b {
+	case 3:
+		return TSVectorWeightA
+	case 2:
+		return TSVectorWeightB
+	case 1:
+		return TSVectorWeightC
+	default:
+		return TSVectorWeightD
+	}
+}
+
+// TSVectorPosition represents a lexeme position and its optional weight within a tsvector.
+type TSVectorPosition struct {
+	Position uint16
+	Weight   TSVectorWeight
+}
+
+func (p TSVectorPosition) String() string {
+	s := strconv.FormatUint(uint64(p.Position), 10)
+	if p.Weight != 0 && p.Weight != TSVectorWeightD {
+		s += string(p.Weight)
+	}
+	return s
+}
+
+type TSVectorCodec struct{}
+
+func (TSVectorCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (TSVectorCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (TSVectorCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(TSVectorValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanTSVectorCodecBinary{}
+	case TextFormatCode:
+		return encodePlanTSVectorCodecText{}
+	}
+
+	return nil
+}
+
+type encodePlanTSVectorCodecBinary struct{}
+
+func (encodePlanTSVectorCodecBinary) Encode(value any, buf []byte) ([]byte, error) {
+	tsv, err := value.(TSVectorValuer).TSVectorValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !tsv.Valid {
+		return nil, nil
+	}
+
+	buf = pgio.AppendInt32(buf, int32(len(tsv.Lexemes)))
+
+	for _, entry := range tsv.Lexemes {
+		buf = append(buf, entry.Word...)
+		buf = append(buf, 0x00)
+		buf = pgio.AppendUint16(buf, uint16(len(entry.Positions)))
+
+		// Each position is a uint16: weight (2 bits) | position (14 bits)
+		for _, pos := range entry.Positions {
+			packed := tsvectorWeightToBinary(pos.Weight)<<14 | pos.Position&0x3FFF
+			buf = pgio.AppendUint16(buf, packed)
+		}
+	}
+
+	return buf, nil
+}
+
+type scanPlanBinaryTSVectorToTSVectorScanner struct{}
+
+func (scanPlanBinaryTSVectorToTSVectorScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TSVectorScanner)
+
+	if src == nil {
+		return scanner.ScanTSVector(TSVector{})
+	}
+
+	rp := 0
+
+	const (
+		uint16Len = 2
+		uint32Len = 4
+	)
+
+	if len(src[rp:]) < uint32Len {
+		return fmt.Errorf("tsvector incomplete %v", src)
+	}
+	entryCount := int(int32(binary.BigEndian.Uint32(src[rp:])))
+	rp += uint32Len
+
+	if entryCount < 0 {
+		return fmt.Errorf("tsvector invalid lexeme count: %d", entryCount)
+	}
+	// Each lexeme carries at minimum a 1-byte NUL terminator and a 2-byte position count, so
+	// entryCount cannot exceed remaining/3. This bounds the up-front make() against a malicious
+	// server claiming a huge lexeme count in a small message.
+	if maxEntries := len(src[rp:]) / 3; entryCount > maxEntries {
+		return fmt.Errorf("tsvector invalid lexeme count %d for %d remaining bytes", entryCount, len(src[rp:]))
+	}
+
+	var tsv TSVector
+	if entryCount > 0 {
+		tsv.Lexemes = make([]TSVectorLexeme, entryCount)
+	}
+
+	for i := range entryCount {
+		nullIndex := bytes.IndexByte(src[rp:], 0x00)
+		if nullIndex == -1 {
+			return fmt.Errorf("invalid tsvector binary format: missing null terminator")
+		}
+
+		lexeme := TSVectorLexeme{Word: string(src[rp : rp+nullIndex])}
+		rp += nullIndex + 1 // skip past null terminator
+
+		// Read position count.
+		if len(src[rp:]) < uint16Len {
+			return fmt.Errorf("invalid tsvector binary format: incomplete position count")
+		}
+
+		numPositions := int(binary.BigEndian.Uint16(src[rp:]))
+		rp += uint16Len
+
+		// Read each packed position: weight (2 bits) | position (14 bits)
+		if len(src[rp:]) < numPositions*uint16Len {
+			return fmt.Errorf("invalid tsvector binary format: incomplete positions")
+		}
+
+		if numPositions > 0 {
+			lexeme.Positions = make([]TSVectorPosition, numPositions)
+			for pos := range numPositions {
+				packed := binary.BigEndian.Uint16(src[rp:])
+				rp += uint16Len
+				lexeme.Positions[pos] = TSVectorPosition{
+					Position: packed & 0x3FFF,
+					Weight:   tsvectorWeightFromBinary(packed >> 14),
+				}
+			}
+		}
+
+		tsv.Lexemes[i] = lexeme
+	}
+	tsv.Valid = true
+
+	return scanner.ScanTSVector(tsv)
+}
+
+var tsvectorLexemeReplacer = strings.NewReplacer(
+	`\`, `\\`,
+	`'`, `\'`,
+)
+
+type encodePlanTSVectorCodecText struct{}
+
+func (encodePlanTSVectorCodecText) Encode(value any, buf []byte) ([]byte, error) {
+	tsv, err := value.(TSVectorValuer).TSVectorValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !tsv.Valid {
+		return nil, nil
+	}
+
+	if buf == nil {
+		buf = []byte{}
+	}
+
+	for i, lex := range tsv.Lexemes {
+		if i > 0 {
+			buf = append(buf, ' ')
+		}
+
+		buf = append(buf, '\'')
+		buf = append(buf, tsvectorLexemeReplacer.Replace(lex.Word)...)
+		buf = append(buf, '\'')
+
+		sep := byte(':')
+		for _, p := range lex.Positions {
+			buf = append(buf, sep)
+			buf = append(buf, p.String()...)
+			sep = ','
+		}
+	}
+
+	return buf, nil
+}
+
+func (TSVectorCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		if _, ok := target.(TSVectorScanner); ok {
+			return scanPlanBinaryTSVectorToTSVectorScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(TSVectorScanner); ok {
+			return scanPlanTextAnyToTSVectorScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanTextAnyToTSVectorScanner struct{}
+
+func (s scanPlanTextAnyToTSVectorScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TSVectorScanner)
+
+	if src == nil {
+		return scanner.ScanTSVector(TSVector{})
+	}
+
+	return s.scanString(string(src), scanner)
+}
+
+func (scanPlanTextAnyToTSVectorScanner) scanString(src string, scanner TSVectorScanner) error {
+	tsv, err := parseTSVector(src)
+	if err != nil {
+		return err
+	}
+	return scanner.ScanTSVector(tsv)
+}
+
+func (c TSVectorCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	return codecDecodeToTextFormat(c, m, oid, format, src)
+}
+
+func (c TSVectorCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var tsv TSVector
+	err := codecScan(c, m, oid, format, src, &tsv)
+	if err != nil {
+		return nil, err
+	}
+	return tsv, nil
+}
+
+type tsvectorParser struct {
+	str string
+	pos int
+}
+
+func (p *tsvectorParser) atEnd() bool {
+	return p.pos >= len(p.str)
+}
+
+func (p *tsvectorParser) peek() byte {
+	return p.str[p.pos]
+}
+
+func (p *tsvectorParser) consume() (byte, bool) {
+	if p.pos >= len(p.str) {
+		return 0, true
+	}
+	b := p.str[p.pos]
+	p.pos++
+	return b, false
+}
+
+func (p *tsvectorParser) consumeSpaces() {
+	for !p.atEnd() && p.peek() == ' ' {
+		p.consume()
+	}
+}
+
+// consumeLexeme consumes a single-quoted lexeme, handling single quotes and backslash escapes.
+func (p *tsvectorParser) consumeLexeme() (string, error) {
+	ch, end := p.consume()
+	if end || ch != '\'' {
+		return "", fmt.Errorf("invalid tsvector format: lexeme must start with a single quote")
+	}
+
+	var buf strings.Builder
+	for {
+		ch, end := p.consume()
+		if end {
+			return "", fmt.Errorf("invalid tsvector format: unterminated quoted lexeme")
+		}
+
+		switch ch {
+		case '\'':
+			// Escaped quote ('') — write a literal single quote
+			if !p.atEnd() && p.peek() == '\'' {
+				p.consume()
+				buf.WriteByte('\'')
+			} else {
+				// Closing quote — lexeme is complete
+				return buf.String(), nil
+			}
+		case '\\':
+			next, end := p.consume()
+			if end {
+				return "", fmt.Errorf("invalid tsvector format: unexpected end after backslash")
+			}
+			buf.WriteByte(next)
+		default:
+			buf.WriteByte(ch)
+		}
+	}
+}
+
+// consumePositions consumes a comma-separated list of position[weight] values.
+func (p *tsvectorParser) consumePositions() ([]TSVectorPosition, error) {
+	var positions []TSVectorPosition
+
+	for {
+		pos, err := p.consumePosition()
+		if err != nil {
+			return nil, err
+		}
+		positions = append(positions, pos)
+
+		if p.atEnd() || p.peek() != ',' {
+			break
+		}
+
+		p.consume() // skip ','
+	}
+
+	return positions, nil
+}
+
+// consumePosition consumes a single position number with optional weight letter.
+func (p *tsvectorParser) consumePosition() (TSVectorPosition, error) {
+	start := p.pos
+
+	for !p.atEnd() && p.peek() >= '0' && p.peek() <= '9' {
+		p.consume()
+	}
+
+	if p.pos == start {
+		return TSVectorPosition{}, fmt.Errorf("invalid tsvector format: expected position number")
+	}
+
+	num, err := strconv.ParseUint(p.str[start:p.pos], 10, 16)
+	if err != nil {
+		return TSVectorPosition{}, fmt.Errorf("invalid tsvector format: invalid position number %q", p.str[start:p.pos])
+	}
+
+	pos := TSVectorPosition{Position: uint16(num), Weight: TSVectorWeightD}
+
+	// Check for optional weight letter
+	if !p.atEnd() {
+		switch p.peek() {
+		case 'A', 'a':
+			pos.Weight = TSVectorWeightA
+		case 'B', 'b':
+			pos.Weight = TSVectorWeightB
+		case 'C', 'c':
+			pos.Weight = TSVectorWeightC
+		case 'D', 'd':
+			pos.Weight = TSVectorWeightD
+		default:
+			return pos, nil
+		}
+		p.consume()
+	}
+
+	return pos, nil
+}
+
+// parseTSVector parses a PostgreSQL tsvector text representation.
+func parseTSVector(s string) (TSVector, error) {
+	result := TSVector{}
+	p := &tsvectorParser{str: strings.TrimSpace(s), pos: 0}
+
+	for !p.atEnd() {
+		p.consumeSpaces()
+		if p.atEnd() {
+			break
+		}
+
+		word, err := p.consumeLexeme()
+		if err != nil {
+			return TSVector{}, err
+		}
+
+		entry := TSVectorLexeme{Word: word}
+
+		// Check for optional positions after ':'
+		if !p.atEnd() && p.peek() == ':' {
+			p.consume() // skip ':'
+
+			positions, err := p.consumePositions()
+			if err != nil {
+				return TSVector{}, err
+			}
+			entry.Positions = positions
+		}
+
+		result.Lexemes = append(result.Lexemes, entry)
+	}
+
+	result.Valid = true
+
+	return result, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/uint32.go b/vendor/github.com/jackc/pgx/v5/pgtype/uint32.go
new file mode 100644
index 000000000..e6d4b1cf6
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/uint32.go
@@ -0,0 +1,352 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"encoding/json"
+	"fmt"
+	"math"
+	"strconv"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Uint32Scanner interface {
+	ScanUint32(v Uint32) error
+}
+
+type Uint32Valuer interface {
+	Uint32Value() (Uint32, error)
+}
+
+// Uint32 is the core type that is used to represent PostgreSQL types such as OID, CID, and XID.
+type Uint32 struct {
+	Uint32 uint32
+	Valid  bool
+}
+
+// ScanUint32 implements the [Uint32Scanner] interface.
+func (n *Uint32) ScanUint32(v Uint32) error {
+	*n = v
+	return nil
+}
+
+// Uint32Value implements the [Uint32Valuer] interface.
+func (n Uint32) Uint32Value() (Uint32, error) {
+	return n, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Uint32) Scan(src any) error {
+	if src == nil {
+		*dst = Uint32{}
+		return nil
+	}
+
+	var n int64
+
+	switch src := src.(type) {
+	case int64:
+		n = src
+	case string:
+		un, err := strconv.ParseUint(src, 10, 32)
+		if err != nil {
+			return err
+		}
+		n = int64(un)
+	default:
+		return fmt.Errorf("cannot scan %T", src)
+	}
+
+	if n < 0 {
+		return fmt.Errorf("%d is less than the minimum value for Uint32", n)
+	}
+	if n > math.MaxUint32 {
+		return fmt.Errorf("%d is greater than maximum value for Uint32", n)
+	}
+
+	*dst = Uint32{Uint32: uint32(n), Valid: true}
+
+	return nil
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Uint32) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+	return int64(src.Uint32), nil
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src Uint32) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+	return json.Marshal(src.Uint32)
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *Uint32) UnmarshalJSON(b []byte) error {
+	var n *uint32
+	err := json.Unmarshal(b, &n)
+	if err != nil {
+		return err
+	}
+
+	if n == nil {
+		*dst = Uint32{}
+	} else {
+		*dst = Uint32{Uint32: *n, Valid: true}
+	}
+
+	return nil
+}
+
+type Uint32Codec struct{}
+
+func (Uint32Codec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (Uint32Codec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (Uint32Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case uint32:
+			return encodePlanUint32CodecBinaryUint32{}
+		case Uint32Valuer:
+			return encodePlanUint32CodecBinaryUint32Valuer{}
+		case Int64Valuer:
+			return encodePlanUint32CodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case uint32:
+			return encodePlanUint32CodecTextUint32{}
+		case Int64Valuer:
+			return encodePlanUint32CodecTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanUint32CodecBinaryUint32 struct{}
+
+func (encodePlanUint32CodecBinaryUint32) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v := value.(uint32)
+	return pgio.AppendUint32(buf, v), nil
+}
+
+type encodePlanUint32CodecBinaryUint32Valuer struct{}
+
+func (encodePlanUint32CodecBinaryUint32Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v, err := value.(Uint32Valuer).Uint32Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !v.Valid {
+		return nil, nil
+	}
+
+	return pgio.AppendUint32(buf, v.Uint32), nil
+}
+
+type encodePlanUint32CodecBinaryInt64Valuer struct{}
+
+func (encodePlanUint32CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !v.Valid {
+		return nil, nil
+	}
+
+	if v.Int64 < 0 {
+		return nil, fmt.Errorf("%d is less than minimum value for uint32", v.Int64)
+	}
+	if v.Int64 > math.MaxUint32 {
+		return nil, fmt.Errorf("%d is greater than maximum value for uint32", v.Int64)
+	}
+
+	return pgio.AppendUint32(buf, uint32(v.Int64)), nil
+}
+
+type encodePlanUint32CodecTextUint32 struct{}
+
+func (encodePlanUint32CodecTextUint32) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v := value.(uint32)
+	return append(buf, strconv.FormatUint(uint64(v), 10)...), nil
+}
+
+type encodePlanUint32CodecTextUint32Valuer struct{}
+
+func (encodePlanUint32CodecTextUint32Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v, err := value.(Uint32Valuer).Uint32Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !v.Valid {
+		return nil, nil
+	}
+
+	return append(buf, strconv.FormatUint(uint64(v.Uint32), 10)...), nil
+}
+
+type encodePlanUint32CodecTextInt64Valuer struct{}
+
+func (encodePlanUint32CodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !v.Valid {
+		return nil, nil
+	}
+
+	if v.Int64 < 0 {
+		return nil, fmt.Errorf("%d is less than minimum value for uint32", v.Int64)
+	}
+	if v.Int64 > math.MaxUint32 {
+		return nil, fmt.Errorf("%d is greater than maximum value for uint32", v.Int64)
+	}
+
+	return append(buf, strconv.FormatInt(v.Int64, 10)...), nil
+}
+
+func (Uint32Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *uint32:
+			return scanPlanBinaryUint32ToUint32{}
+		case Uint32Scanner:
+			return scanPlanBinaryUint32ToUint32Scanner{}
+		case TextScanner:
+			return scanPlanBinaryUint32ToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *uint32:
+			return scanPlanTextAnyToUint32{}
+		case Uint32Scanner:
+			return scanPlanTextAnyToUint32Scanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c Uint32Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n uint32
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return int64(n), nil
+}
+
+func (c Uint32Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n uint32
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+type scanPlanBinaryUint32ToUint32 struct{}
+
+func (scanPlanBinaryUint32ToUint32) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for uint32: %v", len(src))
+	}
+
+	p := (dst).(*uint32)
+	*p = binary.BigEndian.Uint32(src)
+
+	return nil
+}
+
+type scanPlanBinaryUint32ToUint32Scanner struct{}
+
+func (scanPlanBinaryUint32ToUint32Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Uint32Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanUint32(Uint32{})
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for uint32: %v", len(src))
+	}
+
+	n := binary.BigEndian.Uint32(src)
+
+	return s.ScanUint32(Uint32{Uint32: n, Valid: true})
+}
+
+type scanPlanBinaryUint32ToTextScanner struct{}
+
+func (scanPlanBinaryUint32ToTextScanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(TextScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanText(Text{})
+	}
+
+	if len(src) != 4 {
+		return fmt.Errorf("invalid length for uint32: %v", len(src))
+	}
+
+	n := uint64(binary.BigEndian.Uint32(src))
+	return s.ScanText(Text{String: strconv.FormatUint(n, 10), Valid: true})
+}
+
+type scanPlanTextAnyToUint32Scanner struct{}
+
+func (scanPlanTextAnyToUint32Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Uint32Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanUint32(Uint32{})
+	}
+
+	n, err := strconv.ParseUint(string(src), 10, 32)
+	if err != nil {
+		return err
+	}
+
+	return s.ScanUint32(Uint32{Uint32: uint32(n), Valid: true})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/uint64.go b/vendor/github.com/jackc/pgx/v5/pgtype/uint64.go
new file mode 100644
index 000000000..fc407bdb6
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/uint64.go
@@ -0,0 +1,323 @@
+package pgtype
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"strconv"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+)
+
+type Uint64Scanner interface {
+	ScanUint64(v Uint64) error
+}
+
+type Uint64Valuer interface {
+	Uint64Value() (Uint64, error)
+}
+
+// Uint64 is the core type that is used to represent PostgreSQL types such as XID8.
+type Uint64 struct {
+	Uint64 uint64
+	Valid  bool
+}
+
+// ScanUint64 implements the [Uint64Scanner] interface.
+func (n *Uint64) ScanUint64(v Uint64) error {
+	*n = v
+	return nil
+}
+
+// Uint64Value implements the [Uint64Valuer] interface.
+func (n Uint64) Uint64Value() (Uint64, error) {
+	return n, nil
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *Uint64) Scan(src any) error {
+	if src == nil {
+		*dst = Uint64{}
+		return nil
+	}
+
+	var n uint64
+
+	switch src := src.(type) {
+	case int64:
+		if src < 0 {
+			return fmt.Errorf("%d is less than the minimum value for Uint64", src)
+		}
+		n = uint64(src)
+	case string:
+		un, err := strconv.ParseUint(src, 10, 64)
+		if err != nil {
+			return err
+		}
+		n = un
+	default:
+		return fmt.Errorf("cannot scan %T", src)
+	}
+
+	*dst = Uint64{Uint64: n, Valid: true}
+
+	return nil
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src Uint64) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	// If the value is greater than the maximum value for int64, return it as a string instead of losing data or returning
+	// an error.
+	if src.Uint64 > math.MaxInt64 {
+		return strconv.FormatUint(src.Uint64, 10), nil
+	}
+
+	return int64(src.Uint64), nil
+}
+
+type Uint64Codec struct{}
+
+func (Uint64Codec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (Uint64Codec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (Uint64Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch format {
+	case BinaryFormatCode:
+		switch value.(type) {
+		case uint64:
+			return encodePlanUint64CodecBinaryUint64{}
+		case Uint64Valuer:
+			return encodePlanUint64CodecBinaryUint64Valuer{}
+		case Int64Valuer:
+			return encodePlanUint64CodecBinaryInt64Valuer{}
+		}
+	case TextFormatCode:
+		switch value.(type) {
+		case uint64:
+			return encodePlanUint64CodecTextUint64{}
+		case Int64Valuer:
+			return encodePlanUint64CodecTextInt64Valuer{}
+		}
+	}
+
+	return nil
+}
+
+type encodePlanUint64CodecBinaryUint64 struct{}
+
+func (encodePlanUint64CodecBinaryUint64) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v := value.(uint64)
+	return pgio.AppendUint64(buf, v), nil
+}
+
+type encodePlanUint64CodecBinaryUint64Valuer struct{}
+
+func (encodePlanUint64CodecBinaryUint64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v, err := value.(Uint64Valuer).Uint64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !v.Valid {
+		return nil, nil
+	}
+
+	return pgio.AppendUint64(buf, v.Uint64), nil
+}
+
+type encodePlanUint64CodecBinaryInt64Valuer struct{}
+
+func (encodePlanUint64CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !v.Valid {
+		return nil, nil
+	}
+
+	if v.Int64 < 0 {
+		return nil, fmt.Errorf("%d is less than minimum value for uint64", v.Int64)
+	}
+
+	return pgio.AppendUint64(buf, uint64(v.Int64)), nil
+}
+
+type encodePlanUint64CodecTextUint64 struct{}
+
+func (encodePlanUint64CodecTextUint64) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v := value.(uint64)
+	return append(buf, strconv.FormatUint(v, 10)...), nil
+}
+
+type encodePlanUint64CodecTextUint64Valuer struct{}
+
+func (encodePlanUint64CodecTextUint64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v, err := value.(Uint64Valuer).Uint64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !v.Valid {
+		return nil, nil
+	}
+
+	return append(buf, strconv.FormatUint(v.Uint64, 10)...), nil
+}
+
+type encodePlanUint64CodecTextInt64Valuer struct{}
+
+func (encodePlanUint64CodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	v, err := value.(Int64Valuer).Int64Value()
+	if err != nil {
+		return nil, err
+	}
+
+	if !v.Valid {
+		return nil, nil
+	}
+
+	if v.Int64 < 0 {
+		return nil, fmt.Errorf("%d is less than minimum value for uint64", v.Int64)
+	}
+
+	return append(buf, strconv.FormatInt(v.Int64, 10)...), nil
+}
+
+func (Uint64Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case *uint64:
+			return scanPlanBinaryUint64ToUint64{}
+		case Uint64Scanner:
+			return scanPlanBinaryUint64ToUint64Scanner{}
+		case TextScanner:
+			return scanPlanBinaryUint64ToTextScanner{}
+		}
+	case TextFormatCode:
+		switch target.(type) {
+		case *uint64:
+			return scanPlanTextAnyToUint64{}
+		case Uint64Scanner:
+			return scanPlanTextAnyToUint64Scanner{}
+		}
+	}
+
+	return nil
+}
+
+func (c Uint64Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n uint64
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return int64(n), nil
+}
+
+func (c Uint64Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var n uint64
+	err := codecScan(c, m, oid, format, src, &n)
+	if err != nil {
+		return nil, err
+	}
+	return n, nil
+}
+
+type scanPlanBinaryUint64ToUint64 struct{}
+
+func (scanPlanBinaryUint64ToUint64) Scan(src []byte, dst any) error {
+	if src == nil {
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for uint64: %v", len(src))
+	}
+
+	p := (dst).(*uint64)
+	*p = binary.BigEndian.Uint64(src)
+
+	return nil
+}
+
+type scanPlanBinaryUint64ToUint64Scanner struct{}
+
+func (scanPlanBinaryUint64ToUint64Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Uint64Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanUint64(Uint64{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for uint64: %v", len(src))
+	}
+
+	n := binary.BigEndian.Uint64(src)
+
+	return s.ScanUint64(Uint64{Uint64: n, Valid: true})
+}
+
+type scanPlanBinaryUint64ToTextScanner struct{}
+
+func (scanPlanBinaryUint64ToTextScanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(TextScanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanText(Text{})
+	}
+
+	if len(src) != 8 {
+		return fmt.Errorf("invalid length for uint64: %v", len(src))
+	}
+
+	n := binary.BigEndian.Uint64(src)
+	return s.ScanText(Text{String: strconv.FormatUint(n, 10), Valid: true})
+}
+
+type scanPlanTextAnyToUint64Scanner struct{}
+
+func (scanPlanTextAnyToUint64Scanner) Scan(src []byte, dst any) error {
+	s, ok := (dst).(Uint64Scanner)
+	if !ok {
+		return ErrScanTargetTypeChanged
+	}
+
+	if src == nil {
+		return s.ScanUint64(Uint64{})
+	}
+
+	n, err := strconv.ParseUint(string(src), 10, 64)
+	if err != nil {
+		return err
+	}
+
+	return s.ScanUint64(Uint64{Uint64: n, Valid: true})
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/uuid.go b/vendor/github.com/jackc/pgx/v5/pgtype/uuid.go
new file mode 100644
index 000000000..476889a8d
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/uuid.go
@@ -0,0 +1,291 @@
+package pgtype
+
+import (
+	"bytes"
+	"database/sql/driver"
+	"encoding/hex"
+	"fmt"
+)
+
+type UUIDScanner interface {
+	ScanUUID(v UUID) error
+}
+
+type UUIDValuer interface {
+	UUIDValue() (UUID, error)
+}
+
+type UUID struct {
+	Bytes [16]byte
+	Valid bool
+}
+
+// ScanUUID implements the [UUIDScanner] interface.
+func (b *UUID) ScanUUID(v UUID) error {
+	*b = v
+	return nil
+}
+
+// UUIDValue implements the [UUIDValuer] interface.
+func (b UUID) UUIDValue() (UUID, error) {
+	return b, nil
+}
+
+// parseUUID converts a string UUID in standard form to a byte array.
+func parseUUID(src string) (dst [16]byte, err error) {
+	switch len(src) {
+	case 36:
+		src = src[0:8] + src[9:13] + src[14:18] + src[19:23] + src[24:]
+	case 32:
+		// dashes already stripped, assume valid
+	default:
+		// assume invalid.
+		return dst, fmt.Errorf("cannot parse UUID %v", src)
+	}
+
+	buf, err := hex.DecodeString(src)
+	if err != nil {
+		return dst, err
+	}
+
+	copy(dst[:], buf)
+	return dst, err
+}
+
+// encodeUUID converts a uuid byte array to UUID standard string form.
+func encodeUUID(src [16]byte) string {
+	var buf [36]byte
+
+	hex.Encode(buf[0:8], src[:4])
+	buf[8] = '-'
+	hex.Encode(buf[9:13], src[4:6])
+	buf[13] = '-'
+	hex.Encode(buf[14:18], src[6:8])
+	buf[18] = '-'
+	hex.Encode(buf[19:23], src[8:10])
+	buf[23] = '-'
+	hex.Encode(buf[24:], src[10:])
+
+	return string(buf[:])
+}
+
+// Scan implements the [database/sql.Scanner] interface.
+func (dst *UUID) Scan(src any) error {
+	if src == nil {
+		*dst = UUID{}
+		return nil
+	}
+
+	if src, ok := src.(string); ok {
+		buf, err := parseUUID(src)
+		if err != nil {
+			return err
+		}
+		*dst = UUID{Bytes: buf, Valid: true}
+		return nil
+	}
+
+	return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the [database/sql/driver.Valuer] interface.
+func (src UUID) Value() (driver.Value, error) {
+	if !src.Valid {
+		return nil, nil
+	}
+
+	return encodeUUID(src.Bytes), nil
+}
+
+func (src UUID) String() string {
+	if !src.Valid {
+		return ""
+	}
+
+	return encodeUUID(src.Bytes)
+}
+
+// MarshalJSON implements the [encoding/json.Marshaler] interface.
+func (src UUID) MarshalJSON() ([]byte, error) {
+	if !src.Valid {
+		return []byte("null"), nil
+	}
+
+	var buff bytes.Buffer
+	buff.WriteByte('"')
+	buff.WriteString(encodeUUID(src.Bytes))
+	buff.WriteByte('"')
+	return buff.Bytes(), nil
+}
+
+// UnmarshalJSON implements the [encoding/json.Unmarshaler] interface.
+func (dst *UUID) UnmarshalJSON(src []byte) error {
+	if bytes.Equal(src, []byte("null")) {
+		*dst = UUID{}
+		return nil
+	}
+	if len(src) != 38 {
+		return fmt.Errorf("invalid length for UUID: %v", len(src))
+	}
+	buf, err := parseUUID(string(src[1 : len(src)-1]))
+	if err != nil {
+		return err
+	}
+	*dst = UUID{Bytes: buf, Valid: true}
+	return nil
+}
+
+type UUIDCodec struct{}
+
+func (UUIDCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (UUIDCodec) PreferredFormat() int16 {
+	return BinaryFormatCode
+}
+
+func (UUIDCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	if _, ok := value.(UUIDValuer); !ok {
+		return nil
+	}
+
+	switch format {
+	case BinaryFormatCode:
+		return encodePlanUUIDCodecBinaryUUIDValuer{}
+	case TextFormatCode:
+		return encodePlanUUIDCodecTextUUIDValuer{}
+	}
+
+	return nil
+}
+
+type encodePlanUUIDCodecBinaryUUIDValuer struct{}
+
+func (encodePlanUUIDCodecBinaryUUIDValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	uuid, err := value.(UUIDValuer).UUIDValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !uuid.Valid {
+		return nil, nil
+	}
+
+	return append(buf, uuid.Bytes[:]...), nil
+}
+
+type encodePlanUUIDCodecTextUUIDValuer struct{}
+
+func (encodePlanUUIDCodecTextUUIDValuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	uuid, err := value.(UUIDValuer).UUIDValue()
+	if err != nil {
+		return nil, err
+	}
+
+	if !uuid.Valid {
+		return nil, nil
+	}
+
+	return append(buf, encodeUUID(uuid.Bytes)...), nil
+}
+
+func (UUIDCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch format {
+	case BinaryFormatCode:
+		switch target.(type) {
+		case UUIDScanner:
+			return scanPlanBinaryUUIDToUUIDScanner{}
+		case TextScanner:
+			return scanPlanBinaryUUIDToTextScanner{}
+		}
+	case TextFormatCode:
+		if _, ok := target.(UUIDScanner); ok {
+			return scanPlanTextAnyToUUIDScanner{}
+		}
+	}
+
+	return nil
+}
+
+type scanPlanBinaryUUIDToUUIDScanner struct{}
+
+func (scanPlanBinaryUUIDToUUIDScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(UUIDScanner)
+
+	if src == nil {
+		return scanner.ScanUUID(UUID{})
+	}
+
+	if len(src) != 16 {
+		return fmt.Errorf("invalid length for UUID: %v", len(src))
+	}
+
+	uuid := UUID{Valid: true}
+	copy(uuid.Bytes[:], src)
+
+	return scanner.ScanUUID(uuid)
+}
+
+type scanPlanBinaryUUIDToTextScanner struct{}
+
+func (scanPlanBinaryUUIDToTextScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(TextScanner)
+
+	if src == nil {
+		return scanner.ScanText(Text{})
+	}
+
+	if len(src) != 16 {
+		return fmt.Errorf("invalid length for UUID: %v", len(src))
+	}
+
+	var buf [16]byte
+	copy(buf[:], src)
+
+	return scanner.ScanText(Text{String: encodeUUID(buf), Valid: true})
+}
+
+type scanPlanTextAnyToUUIDScanner struct{}
+
+func (scanPlanTextAnyToUUIDScanner) Scan(src []byte, dst any) error {
+	scanner := (dst).(UUIDScanner)
+
+	if src == nil {
+		return scanner.ScanUUID(UUID{})
+	}
+
+	buf, err := parseUUID(string(src))
+	if err != nil {
+		return err
+	}
+
+	return scanner.ScanUUID(UUID{Bytes: buf, Valid: true})
+}
+
+func (c UUIDCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var uuid UUID
+	err := codecScan(c, m, oid, format, src, &uuid)
+	if err != nil {
+		return nil, err
+	}
+
+	return encodeUUID(uuid.Bytes), nil
+}
+
+func (c UUIDCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var uuid UUID
+	err := codecScan(c, m, oid, format, src, &uuid)
+	if err != nil {
+		return nil, err
+	}
+	return uuid.Bytes, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgtype/xml.go b/vendor/github.com/jackc/pgx/v5/pgtype/xml.go
new file mode 100644
index 000000000..66e6dffda
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgtype/xml.go
@@ -0,0 +1,198 @@
+package pgtype
+
+import (
+	"database/sql"
+	"database/sql/driver"
+	"encoding/xml"
+	"fmt"
+	"reflect"
+)
+
+type XMLCodec struct {
+	Marshal   func(v any) ([]byte, error)
+	Unmarshal func(data []byte, v any) error
+}
+
+func (*XMLCodec) FormatSupported(format int16) bool {
+	return format == TextFormatCode || format == BinaryFormatCode
+}
+
+func (*XMLCodec) PreferredFormat() int16 {
+	return TextFormatCode
+}
+
+func (c *XMLCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
+	switch value.(type) {
+	case string:
+		return encodePlanXMLCodecEitherFormatString{}
+	case []byte:
+		return encodePlanXMLCodecEitherFormatByteSlice{}
+
+	// Cannot rely on driver.Valuer being handled later because anything can be marshalled.
+	//
+	// https://github.com/jackc/pgx/issues/1430
+	//
+	// Check for driver.Valuer must come before xml.Marshaler so that it is guaranteed to be used
+	// when both are implemented https://github.com/jackc/pgx/issues/1805
+	case driver.Valuer:
+		return &encodePlanDriverValuer{m: m, oid: oid, formatCode: format}
+
+	// Must come before trying wrap encode plans because a pointer to a struct may be unwrapped to a struct that can be
+	// marshalled.
+	//
+	// https://github.com/jackc/pgx/issues/1681
+	case xml.Marshaler:
+		return &encodePlanXMLCodecEitherFormatMarshal{
+			marshal: c.Marshal,
+		}
+	}
+
+	// Because anything can be marshalled the normal wrapping in Map.PlanScan doesn't get a chance to run. So try the
+	// appropriate wrappers here.
+	for _, f := range []TryWrapEncodePlanFunc{
+		TryWrapDerefPointerEncodePlan,
+		TryWrapFindUnderlyingTypeEncodePlan,
+	} {
+		if wrapperPlan, nextValue, ok := f(value); ok {
+			if nextPlan := c.PlanEncode(m, oid, format, nextValue); nextPlan != nil {
+				wrapperPlan.SetNext(nextPlan)
+				return wrapperPlan
+			}
+		}
+	}
+
+	return &encodePlanXMLCodecEitherFormatMarshal{
+		marshal: c.Marshal,
+	}
+}
+
+type encodePlanXMLCodecEitherFormatString struct{}
+
+func (encodePlanXMLCodecEitherFormatString) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	xmlString := value.(string)
+	buf = append(buf, xmlString...)
+	return buf, nil
+}
+
+type encodePlanXMLCodecEitherFormatByteSlice struct{}
+
+func (encodePlanXMLCodecEitherFormatByteSlice) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	xmlBytes := value.([]byte)
+	if xmlBytes == nil {
+		return nil, nil
+	}
+
+	buf = append(buf, xmlBytes...)
+	return buf, nil
+}
+
+type encodePlanXMLCodecEitherFormatMarshal struct {
+	marshal func(v any) ([]byte, error)
+}
+
+func (e *encodePlanXMLCodecEitherFormatMarshal) Encode(value any, buf []byte) (newBuf []byte, err error) {
+	xmlBytes, err := e.marshal(value)
+	if err != nil {
+		return nil, err
+	}
+
+	buf = append(buf, xmlBytes...)
+	return buf, nil
+}
+
+func (c *XMLCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
+	switch target.(type) {
+	case *string:
+		return scanPlanAnyToString{}
+
+	case **string:
+		// This is to fix **string scanning. It seems wrong to special case **string, but it's not clear what a better
+		// solution would be.
+		//
+		// https://github.com/jackc/pgx/issues/1470 -- **string
+		// https://github.com/jackc/pgx/issues/1691 -- ** anything else
+
+		if wrapperPlan, nextDst, ok := TryPointerPointerScanPlan(target); ok {
+			if nextPlan := m.planScan(oid, format, nextDst, 0); nextPlan != nil {
+				if _, failed := nextPlan.(*scanPlanFail); !failed {
+					wrapperPlan.SetNext(nextPlan)
+					return wrapperPlan
+				}
+			}
+		}
+
+	case *[]byte:
+		return scanPlanXMLToByteSlice{}
+	case BytesScanner:
+		return scanPlanBinaryBytesToBytesScanner{}
+
+	// Cannot rely on sql.Scanner being handled later because scanPlanXMLToXMLUnmarshal will take precedence.
+	//
+	// https://github.com/jackc/pgx/issues/1418
+	case sql.Scanner:
+		return &scanPlanSQLScanner{formatCode: format}
+	}
+
+	return &scanPlanXMLToXMLUnmarshal{
+		unmarshal: c.Unmarshal,
+	}
+}
+
+type scanPlanXMLToByteSlice struct{}
+
+func (scanPlanXMLToByteSlice) Scan(src []byte, dst any) error {
+	dstBuf := dst.(*[]byte)
+	if src == nil {
+		*dstBuf = nil
+		return nil
+	}
+
+	*dstBuf = make([]byte, len(src))
+	copy(*dstBuf, src)
+	return nil
+}
+
+type scanPlanXMLToXMLUnmarshal struct {
+	unmarshal func(data []byte, v any) error
+}
+
+func (s *scanPlanXMLToXMLUnmarshal) Scan(src []byte, dst any) error {
+	if src == nil {
+		dstValue := reflect.ValueOf(dst)
+		if dstValue.Kind() == reflect.Pointer {
+			el := dstValue.Elem()
+			switch el.Kind() {
+			case reflect.Pointer, reflect.Slice, reflect.Map, reflect.Interface, reflect.Struct:
+				el.Set(reflect.Zero(el.Type()))
+				return nil
+			}
+		}
+
+		return fmt.Errorf("cannot scan NULL into %T", dst)
+	}
+
+	elem := reflect.ValueOf(dst).Elem()
+	elem.Set(reflect.Zero(elem.Type()))
+
+	return s.unmarshal(src, dst)
+}
+
+func (c *XMLCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	dstBuf := make([]byte, len(src))
+	copy(dstBuf, src)
+	return dstBuf, nil
+}
+
+func (c *XMLCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
+	if src == nil {
+		return nil, nil
+	}
+
+	var dst any
+	err := c.Unmarshal(src, &dst)
+	return dst, err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/batch_results.go b/vendor/github.com/jackc/pgx/v5/pgxpool/batch_results.go
new file mode 100644
index 000000000..5d5c681d5
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/batch_results.go
@@ -0,0 +1,52 @@
+package pgxpool
+
+import (
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+type errBatchResults struct {
+	err error
+}
+
+func (br errBatchResults) Exec() (pgconn.CommandTag, error) {
+	return pgconn.CommandTag{}, br.err
+}
+
+func (br errBatchResults) Query() (pgx.Rows, error) {
+	return errRows{err: br.err}, br.err
+}
+
+func (br errBatchResults) QueryRow() pgx.Row {
+	return errRow{err: br.err}
+}
+
+func (br errBatchResults) Close() error {
+	return br.err
+}
+
+type poolBatchResults struct {
+	br pgx.BatchResults
+	c  *Conn
+}
+
+func (br *poolBatchResults) Exec() (pgconn.CommandTag, error) {
+	return br.br.Exec()
+}
+
+func (br *poolBatchResults) Query() (pgx.Rows, error) {
+	return br.br.Query()
+}
+
+func (br *poolBatchResults) QueryRow() pgx.Row {
+	return br.br.QueryRow()
+}
+
+func (br *poolBatchResults) Close() error {
+	err := br.br.Close()
+	if br.c != nil {
+		br.c.Release()
+		br.c = nil
+	}
+	return err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/conn.go b/vendor/github.com/jackc/pgx/v5/pgxpool/conn.go
new file mode 100644
index 000000000..b4f90605b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/conn.go
@@ -0,0 +1,133 @@
+package pgxpool
+
+import (
+	"context"
+
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+	"github.com/jackc/puddle/v2"
+)
+
+// Conn is an acquired *pgx.Conn from a Pool.
+type Conn struct {
+	res *puddle.Resource[*connResource]
+	p   *Pool
+}
+
+// Release returns c to the pool it was acquired from. Once Release has been called, other methods must not be called.
+// However, it is safe to call Release multiple times. Subsequent calls after the first will be ignored.
+func (c *Conn) Release() {
+	if c.res == nil {
+		return
+	}
+
+	conn := c.Conn()
+	res := c.res
+	c.res = nil
+
+	if c.p.releaseTracer != nil {
+		c.p.releaseTracer.TraceRelease(c.p, TraceReleaseData{Conn: conn})
+	}
+
+	if conn.IsClosed() || conn.PgConn().IsBusy() || conn.PgConn().TxStatus() != 'I' {
+		res.Destroy()
+		// Signal to the health check to run since we just destroyed a connections
+		// and we might be below minConns now
+		c.p.triggerHealthCheck()
+		return
+	}
+
+	// If the pool is consistently being used, we might never get to check the
+	// lifetime of a connection since we only check idle connections in checkConnsHealth
+	// so we also check the lifetime here and force a health check
+	if c.p.isExpired(res) {
+		c.p.lifetimeDestroyCount.Add(1)
+		res.Destroy()
+		// Signal to the health check to run since we just destroyed a connections
+		// and we might be below minConns now
+		c.p.triggerHealthCheck()
+		return
+	}
+
+	if c.p.afterRelease == nil {
+		res.Release()
+		return
+	}
+
+	go func() {
+		if c.p.afterRelease(conn) {
+			res.Release()
+		} else {
+			res.Destroy()
+			// Signal to the health check to run since we just destroyed a connections
+			// and we might be below minConns now
+			c.p.triggerHealthCheck()
+		}
+	}()
+}
+
+// Hijack assumes ownership of the connection from the pool. Caller is responsible for closing the connection. Hijack
+// will panic if called on an already released or hijacked connection.
+func (c *Conn) Hijack() *pgx.Conn {
+	if c.res == nil {
+		panic("cannot hijack already released or hijacked connection")
+	}
+
+	conn := c.Conn()
+	res := c.res
+	c.res = nil
+
+	res.Hijack()
+
+	return conn
+}
+
+func (c *Conn) Exec(ctx context.Context, sql string, arguments ...any) (pgconn.CommandTag, error) {
+	return c.Conn().Exec(ctx, sql, arguments...)
+}
+
+func (c *Conn) Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) {
+	return c.Conn().Query(ctx, sql, args...)
+}
+
+func (c *Conn) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row {
+	return c.Conn().QueryRow(ctx, sql, args...)
+}
+
+func (c *Conn) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults {
+	return c.Conn().SendBatch(ctx, b)
+}
+
+func (c *Conn) CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) {
+	return c.Conn().CopyFrom(ctx, tableName, columnNames, rowSrc)
+}
+
+// Begin starts a transaction block from the *Conn without explicitly setting a transaction mode (see BeginTx with TxOptions if transaction mode is required).
+func (c *Conn) Begin(ctx context.Context) (pgx.Tx, error) {
+	return c.Conn().Begin(ctx)
+}
+
+// BeginTx starts a transaction block from the *Conn with txOptions determining the transaction mode.
+func (c *Conn) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error) {
+	return c.Conn().BeginTx(ctx, txOptions)
+}
+
+func (c *Conn) Ping(ctx context.Context) error {
+	return c.Conn().Ping(ctx)
+}
+
+func (c *Conn) Conn() *pgx.Conn {
+	return c.connResource().conn
+}
+
+func (c *Conn) connResource() *connResource {
+	return c.res.Value()
+}
+
+func (c *Conn) getPoolRow(r pgx.Row) *poolRow {
+	return c.connResource().getPoolRow(c, r)
+}
+
+func (c *Conn) getPoolRows(r pgx.Rows) *poolRows {
+	return c.connResource().getPoolRows(c, r)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/doc.go b/vendor/github.com/jackc/pgx/v5/pgxpool/doc.go
new file mode 100644
index 000000000..099443bca
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/doc.go
@@ -0,0 +1,27 @@
+// Package pgxpool is a concurrency-safe connection pool for pgx.
+/*
+pgxpool implements a nearly identical interface to pgx connections.
+
+Creating a Pool
+
+The primary way of creating a pool is with [pgxpool.New]:
+
+    pool, err := pgxpool.New(context.Background(), os.Getenv("DATABASE_URL"))
+
+The database connection string can be in URL or keyword/value format. PostgreSQL settings, pgx settings, and pool settings can be
+specified here. In addition, a config struct can be created by [ParseConfig].
+
+    config, err := pgxpool.ParseConfig(os.Getenv("DATABASE_URL"))
+    if err != nil {
+        // ...
+    }
+    config.AfterConnect = func(ctx context.Context, conn *pgx.Conn) error {
+        // do something with every new connection
+    }
+
+    pool, err := pgxpool.NewWithConfig(context.Background(), config)
+
+A pool returns without waiting for any connections to be established. Acquire a connection immediately after creating
+the pool to check if a connection can successfully be established.
+*/
+package pgxpool
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/pool.go b/vendor/github.com/jackc/pgx/v5/pgxpool/pool.go
new file mode 100644
index 000000000..5c740b1f2
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/pool.go
@@ -0,0 +1,840 @@
+package pgxpool
+
+import (
+	"context"
+	"errors"
+	"math/rand/v2"
+	"runtime"
+	"strconv"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+	"github.com/jackc/puddle/v2"
+)
+
+var (
+	defaultMaxConns          = int32(4)
+	defaultMinConns          = int32(0)
+	defaultMinIdleConns      = int32(0)
+	defaultMaxConnLifetime   = time.Hour
+	defaultMaxConnIdleTime   = time.Minute * 30
+	defaultHealthCheckPeriod = time.Minute
+)
+
+type connResource struct {
+	conn       *pgx.Conn
+	conns      []Conn
+	poolRows   []poolRow
+	poolRowss  []poolRows
+	maxAgeTime time.Time
+}
+
+func (cr *connResource) getConn(p *Pool, res *puddle.Resource[*connResource]) *Conn {
+	if len(cr.conns) == 0 {
+		cr.conns = make([]Conn, 128)
+	}
+
+	c := &cr.conns[len(cr.conns)-1]
+	cr.conns = cr.conns[0 : len(cr.conns)-1]
+
+	c.res = res
+	c.p = p
+
+	return c
+}
+
+func (cr *connResource) getPoolRow(c *Conn, r pgx.Row) *poolRow {
+	if len(cr.poolRows) == 0 {
+		cr.poolRows = make([]poolRow, 128)
+	}
+
+	pr := &cr.poolRows[len(cr.poolRows)-1]
+	cr.poolRows = cr.poolRows[0 : len(cr.poolRows)-1]
+
+	pr.c = c
+	pr.r = r
+
+	return pr
+}
+
+func (cr *connResource) getPoolRows(c *Conn, r pgx.Rows) *poolRows {
+	if len(cr.poolRowss) == 0 {
+		cr.poolRowss = make([]poolRows, 128)
+	}
+
+	pr := &cr.poolRowss[len(cr.poolRowss)-1]
+	cr.poolRowss = cr.poolRowss[0 : len(cr.poolRowss)-1]
+
+	pr.c = c
+	pr.r = r
+
+	return pr
+}
+
+// Pool allows for connection reuse.
+type Pool struct {
+	newConnsCount        atomic.Int64
+	lifetimeDestroyCount atomic.Int64
+	idleDestroyCount     atomic.Int64
+
+	p                     *puddle.Pool[*connResource]
+	config                *Config
+	beforeConnect         func(context.Context, *pgx.ConnConfig) error
+	afterConnect          func(context.Context, *pgx.Conn) error
+	prepareConn           func(context.Context, *pgx.Conn) (bool, error)
+	afterRelease          func(*pgx.Conn) bool
+	beforeClose           func(*pgx.Conn)
+	shouldPing            func(context.Context, ShouldPingParams) bool
+	minConns              int32
+	minIdleConns          int32
+	maxConns              int32
+	maxConnLifetime       time.Duration
+	maxConnLifetimeJitter time.Duration
+	maxConnIdleTime       time.Duration
+	healthCheckPeriod     time.Duration
+	pingTimeout           time.Duration
+
+	healthCheckMu    sync.Mutex
+	healthCheckTimer *time.Timer
+
+	healthCheckChan chan struct{}
+
+	acquireTracer AcquireTracer
+	releaseTracer ReleaseTracer
+
+	closeOnce sync.Once
+	closeChan chan struct{}
+}
+
+// ShouldPingParams are the parameters passed to ShouldPing.
+type ShouldPingParams struct {
+	Conn         *pgx.Conn
+	IdleDuration time.Duration
+}
+
+// Config is the configuration struct for creating a pool. It must be created by [ParseConfig] and then it can be
+// modified.
+type Config struct {
+	ConnConfig *pgx.ConnConfig
+
+	// BeforeConnect is called before a new connection is made. It is passed a copy of the underlying [pgx.ConnConfig] and
+	// will not impact any existing open connections.
+	BeforeConnect func(context.Context, *pgx.ConnConfig) error
+
+	// AfterConnect is called after a connection is established, but before it is added to the pool.
+	AfterConnect func(context.Context, *pgx.Conn) error
+
+	// BeforeAcquire is called before a connection is acquired from the pool. It must return true to allow the
+	// acquisition or false to indicate that the connection should be destroyed and a different connection should be
+	// acquired.
+	//
+	// Deprecated: Use PrepareConn instead. If both PrepareConn and BeforeAcquire are set, PrepareConn will take
+	// precedence, ignoring BeforeAcquire.
+	BeforeAcquire func(context.Context, *pgx.Conn) bool
+
+	// PrepareConn is called before a connection is acquired from the pool. If this function returns true, the connection
+	// is considered valid, otherwise the connection is destroyed. If the function returns a non-nil error, the instigating
+	// query will fail with the returned error.
+	//
+	// Specifically, this means that:
+	//
+	// 	- If it returns true and a nil error, the query proceeds as normal.
+	// 	- If it returns true and an error, the connection will be returned to the pool, and the instigating query will fail with the returned error.
+	// 	- If it returns false, and an error, the connection will be destroyed, and the query will fail with the returned error.
+	// 	- If it returns false and a nil error, the connection will be destroyed, and the instigating query will be retried on a new connection.
+	PrepareConn func(context.Context, *pgx.Conn) (bool, error)
+
+	// AfterRelease is called after a connection is released, but before it is returned to the pool. It must return true to
+	// return the connection to the pool or false to destroy the connection.
+	AfterRelease func(*pgx.Conn) bool
+
+	// BeforeClose is called right before a connection is closed and removed from the pool.
+	BeforeClose func(*pgx.Conn)
+
+	// ShouldPing is called after a connection is acquired from the pool. If it returns true, the connection is pinged to check for liveness.
+	// If this func is not set, the default behavior is to ping connections that have been idle for at least 1 second.
+	ShouldPing func(context.Context, ShouldPingParams) bool
+
+	// MaxConnLifetime is the duration since creation after which a connection will be automatically closed.
+	MaxConnLifetime time.Duration
+
+	// MaxConnLifetimeJitter is the duration after MaxConnLifetime to randomly decide to close a connection.
+	// This helps prevent all connections from being closed at the exact same time, starving the pool.
+	MaxConnLifetimeJitter time.Duration
+
+	// MaxConnIdleTime is the duration after which an idle connection will be automatically closed by the health check.
+	MaxConnIdleTime time.Duration
+
+	// PingTimeout is the maximum amount of time to wait for a connection to pong before considering it as unhealthy and
+	// destroying it. If zero, the default is no timeout.
+	PingTimeout time.Duration
+
+	// MaxConns is the maximum size of the pool. The default is the greater of 4 or runtime.NumCPU().
+	MaxConns int32
+
+	// MinConns is the minimum size of the pool. After connection closes, the pool might dip below MinConns. A low
+	// number of MinConns might mean the pool is empty after MaxConnLifetime until the health check has a chance
+	// to create new connections.
+	MinConns int32
+
+	// MinIdleConns is the minimum number of idle connections in the pool. You can increase this to ensure that
+	// there are always idle connections available. This can help reduce tail latencies during request processing,
+	// as you can avoid the latency of establishing a new connection while handling requests. It is superior
+	// to MinConns for this purpose.
+	// Similar to MinConns, the pool might temporarily dip below MinIdleConns after connection closes.
+	MinIdleConns int32
+
+	// HealthCheckPeriod is the duration between checks of the health of idle connections.
+	HealthCheckPeriod time.Duration
+
+	createdByParseConfig bool // Used to enforce created by ParseConfig rule.
+}
+
+// Copy returns a deep copy of the config that is safe to use and modify.
+// The only exception is the tls.Config:
+// according to the tls.Config docs it must not be modified after creation.
+func (c *Config) Copy() *Config {
+	newConfig := new(Config)
+	*newConfig = *c
+	newConfig.ConnConfig = c.ConnConfig.Copy()
+	return newConfig
+}
+
+// ConnString returns the connection string as parsed by pgxpool.ParseConfig into pgxpool.Config.
+func (c *Config) ConnString() string { return c.ConnConfig.ConnString() }
+
+// New creates a new Pool. See [ParseConfig] for information on connString format.
+func New(ctx context.Context, connString string) (*Pool, error) {
+	config, err := ParseConfig(connString)
+	if err != nil {
+		return nil, err
+	}
+
+	return NewWithConfig(ctx, config)
+}
+
+// NewWithConfig creates a new [Pool]. config must have been created by [ParseConfig].
+func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
+	// Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from
+	// zero values.
+	if !config.createdByParseConfig {
+		panic("config must be created by ParseConfig")
+	}
+
+	prepareConn := config.PrepareConn
+	if prepareConn == nil && config.BeforeAcquire != nil {
+		prepareConn = func(ctx context.Context, conn *pgx.Conn) (bool, error) {
+			return config.BeforeAcquire(ctx, conn), nil
+		}
+	}
+
+	p := &Pool{
+		config:                config,
+		beforeConnect:         config.BeforeConnect,
+		afterConnect:          config.AfterConnect,
+		prepareConn:           prepareConn,
+		afterRelease:          config.AfterRelease,
+		beforeClose:           config.BeforeClose,
+		minConns:              config.MinConns,
+		minIdleConns:          config.MinIdleConns,
+		maxConns:              config.MaxConns,
+		maxConnLifetime:       config.MaxConnLifetime,
+		maxConnLifetimeJitter: config.MaxConnLifetimeJitter,
+		maxConnIdleTime:       config.MaxConnIdleTime,
+		pingTimeout:           config.PingTimeout,
+		healthCheckPeriod:     config.HealthCheckPeriod,
+		healthCheckChan:       make(chan struct{}, 1),
+		closeChan:             make(chan struct{}),
+	}
+
+	if t, ok := config.ConnConfig.Tracer.(AcquireTracer); ok {
+		p.acquireTracer = t
+	}
+
+	if t, ok := config.ConnConfig.Tracer.(ReleaseTracer); ok {
+		p.releaseTracer = t
+	}
+
+	if config.ShouldPing != nil {
+		p.shouldPing = config.ShouldPing
+	} else {
+		p.shouldPing = func(ctx context.Context, params ShouldPingParams) bool {
+			return params.IdleDuration > time.Second
+		}
+	}
+
+	var err error
+	p.p, err = puddle.NewPool(
+		&puddle.Config[*connResource]{
+			Constructor: func(ctx context.Context) (*connResource, error) {
+				p.newConnsCount.Add(1)
+				connConfig := p.config.ConnConfig.Copy()
+
+				// Connection will continue in background even if Acquire is canceled. Ensure that a connect won't hang forever.
+				if connConfig.ConnectTimeout <= 0 {
+					connConfig.ConnectTimeout = 2 * time.Minute
+				}
+
+				if p.beforeConnect != nil {
+					if err := p.beforeConnect(ctx, connConfig); err != nil {
+						return nil, err
+					}
+				}
+
+				conn, err := pgx.ConnectConfig(ctx, connConfig)
+				if err != nil {
+					return nil, err
+				}
+
+				if p.afterConnect != nil {
+					err = p.afterConnect(ctx, conn)
+					if err != nil {
+						conn.Close(ctx)
+						return nil, err
+					}
+				}
+
+				jitterSecs := rand.Float64() * config.MaxConnLifetimeJitter.Seconds()
+				maxAgeTime := time.Now().Add(config.MaxConnLifetime).Add(time.Duration(jitterSecs) * time.Second)
+
+				cr := &connResource{
+					conn:       conn,
+					conns:      make([]Conn, 64),
+					poolRows:   make([]poolRow, 64),
+					poolRowss:  make([]poolRows, 64),
+					maxAgeTime: maxAgeTime,
+				}
+
+				return cr, nil
+			},
+			Destructor: func(value *connResource) {
+				ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
+				conn := value.conn
+				if p.beforeClose != nil {
+					p.beforeClose(conn)
+				}
+				conn.Close(ctx)
+				select {
+				case <-conn.PgConn().CleanupDone():
+				case <-ctx.Done():
+				}
+				cancel()
+			},
+			MaxSize: config.MaxConns,
+		},
+	)
+	if err != nil {
+		return nil, err
+	}
+
+	go func() {
+		targetIdleResources := max(int(p.minConns), int(p.minIdleConns))
+		p.createIdleResources(ctx, targetIdleResources)
+		p.backgroundHealthCheck()
+	}()
+
+	return p, nil
+}
+
+// ParseConfig builds a Config from connString. It parses connString with the same behavior as [pgx.ParseConfig] with the
+// addition of the following variables:
+//
+//   - pool_max_conns: integer greater than 0 (default 4)
+//   - pool_min_conns: integer 0 or greater (default 0)
+//   - pool_max_conn_lifetime: duration string (default 1 hour)
+//   - pool_max_conn_idle_time: duration string (default 30 minutes)
+//   - pool_health_check_period: duration string (default 1 minute)
+//   - pool_max_conn_lifetime_jitter: duration string (default 0)
+//
+// See Config for definitions of these arguments.
+//
+//	# Example Keyword/Value
+//	user=jack password=secret host=pg.example.com port=5432 dbname=mydb sslmode=verify-ca pool_max_conns=10 pool_max_conn_lifetime=1h30m
+//
+//	# Example URL
+//	postgres://jack:secret@pg.example.com:5432/mydb?sslmode=verify-ca&pool_max_conns=10&pool_max_conn_lifetime=1h30m
+func ParseConfig(connString string) (*Config, error) {
+	connConfig, err := pgx.ParseConfig(connString)
+	if err != nil {
+		return nil, err
+	}
+
+	config := &Config{
+		ConnConfig:           connConfig,
+		createdByParseConfig: true,
+	}
+
+	if s, ok := config.ConnConfig.Config.RuntimeParams["pool_max_conns"]; ok {
+		delete(connConfig.Config.RuntimeParams, "pool_max_conns")
+		n, err := strconv.ParseInt(s, 10, 32)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_max_conns", err)
+		}
+		if n < 1 {
+			return nil, pgconn.NewParseConfigError(connString, "pool_max_conns too small", err)
+		}
+		config.MaxConns = int32(n)
+	} else {
+		config.MaxConns = defaultMaxConns
+		if numCPU := int32(runtime.NumCPU()); numCPU > config.MaxConns {
+			config.MaxConns = numCPU
+		}
+	}
+
+	if s, ok := config.ConnConfig.Config.RuntimeParams["pool_min_conns"]; ok {
+		delete(connConfig.Config.RuntimeParams, "pool_min_conns")
+		n, err := strconv.ParseInt(s, 10, 32)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_min_conns", err)
+		}
+		config.MinConns = int32(n)
+	} else {
+		config.MinConns = defaultMinConns
+	}
+
+	if s, ok := config.ConnConfig.Config.RuntimeParams["pool_min_idle_conns"]; ok {
+		delete(connConfig.Config.RuntimeParams, "pool_min_idle_conns")
+		n, err := strconv.ParseInt(s, 10, 32)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_min_idle_conns", err)
+		}
+		config.MinIdleConns = int32(n)
+	} else {
+		config.MinIdleConns = defaultMinIdleConns
+	}
+
+	if s, ok := config.ConnConfig.Config.RuntimeParams["pool_max_conn_lifetime"]; ok {
+		delete(connConfig.Config.RuntimeParams, "pool_max_conn_lifetime")
+		d, err := time.ParseDuration(s)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_max_conn_lifetime", err)
+		}
+		config.MaxConnLifetime = d
+	} else {
+		config.MaxConnLifetime = defaultMaxConnLifetime
+	}
+
+	if s, ok := config.ConnConfig.Config.RuntimeParams["pool_max_conn_idle_time"]; ok {
+		delete(connConfig.Config.RuntimeParams, "pool_max_conn_idle_time")
+		d, err := time.ParseDuration(s)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_max_conn_idle_time", err)
+		}
+		config.MaxConnIdleTime = d
+	} else {
+		config.MaxConnIdleTime = defaultMaxConnIdleTime
+	}
+
+	if s, ok := config.ConnConfig.Config.RuntimeParams["pool_health_check_period"]; ok {
+		delete(connConfig.Config.RuntimeParams, "pool_health_check_period")
+		d, err := time.ParseDuration(s)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_health_check_period", err)
+		}
+		config.HealthCheckPeriod = d
+	} else {
+		config.HealthCheckPeriod = defaultHealthCheckPeriod
+	}
+
+	if s, ok := config.ConnConfig.Config.RuntimeParams["pool_max_conn_lifetime_jitter"]; ok {
+		delete(connConfig.Config.RuntimeParams, "pool_max_conn_lifetime_jitter")
+		d, err := time.ParseDuration(s)
+		if err != nil {
+			return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_max_conn_lifetime_jitter", err)
+		}
+		config.MaxConnLifetimeJitter = d
+	}
+
+	return config, nil
+}
+
+// Close closes all connections in the pool and rejects future [Pool.Acquire] calls. Blocks until all connections are returned
+// to pool and closed.
+func (p *Pool) Close() {
+	p.closeOnce.Do(func() {
+		close(p.closeChan)
+		p.p.Close()
+	})
+}
+
+func (p *Pool) isExpired(res *puddle.Resource[*connResource]) bool {
+	return time.Now().After(res.Value().maxAgeTime)
+}
+
+func (p *Pool) triggerHealthCheck() {
+	const healthCheckDelay = 500 * time.Millisecond
+
+	p.healthCheckMu.Lock()
+	defer p.healthCheckMu.Unlock()
+
+	if p.healthCheckTimer == nil {
+		// Destroy is asynchronous so we give it time to actually remove itself from
+		// the pool otherwise we might try to check the pool size too soon
+		p.healthCheckTimer = time.AfterFunc(healthCheckDelay, func() {
+			select {
+			case <-p.closeChan:
+			case p.healthCheckChan <- struct{}{}:
+			default:
+			}
+		})
+		return
+	}
+
+	p.healthCheckTimer.Reset(healthCheckDelay)
+}
+
+func (p *Pool) backgroundHealthCheck() {
+	ticker := time.NewTicker(p.healthCheckPeriod)
+	defer ticker.Stop()
+	for {
+		select {
+		case <-p.closeChan:
+			return
+		case <-p.healthCheckChan:
+			p.checkHealth()
+		case <-ticker.C:
+			p.checkHealth()
+		}
+	}
+}
+
+func (p *Pool) checkHealth() {
+	for {
+		// If checkMinConns failed we don't destroy any connections since we couldn't
+		// even get to minConns
+		if err := p.checkMinConns(); err != nil {
+			// Should we log this error somewhere?
+			break
+		}
+		if !p.checkConnsHealth() {
+			// Since we didn't destroy any connections we can stop looping
+			break
+		}
+		// Technically Destroy is asynchronous but 500ms should be enough for it to
+		// remove it from the underlying pool
+		select {
+		case <-p.closeChan:
+			return
+		case <-time.After(500 * time.Millisecond):
+		}
+	}
+}
+
+// checkConnsHealth will check all idle connections, destroy a connection if
+// it's idle or too old, and returns true if any were destroyed
+func (p *Pool) checkConnsHealth() bool {
+	var destroyed bool
+	totalConns := p.Stat().TotalConns()
+	resources := p.p.AcquireAllIdle()
+	for _, res := range resources {
+		switch {
+		// We're okay going under minConns if the lifetime is up
+		case p.isExpired(res) && totalConns >= p.minConns:
+			p.lifetimeDestroyCount.Add(1)
+			res.Destroy()
+			destroyed = true
+			// Since Destroy is async we manually decrement totalConns.
+			totalConns--
+		case res.IdleDuration() > p.maxConnIdleTime && totalConns > p.minConns:
+			p.idleDestroyCount.Add(1)
+			res.Destroy()
+			destroyed = true
+			// Since Destroy is async we manually decrement totalConns.
+			totalConns--
+		default:
+			res.ReleaseUnused()
+		}
+	}
+	return destroyed
+}
+
+func (p *Pool) checkMinConns() error {
+	// TotalConns can include ones that are being destroyed but we should have
+	// sleep(500ms) around all of the destroys to help prevent that from throwing
+	// off this check
+
+	// Create the number of connections needed to get to both minConns and minIdleConns
+	stat := p.Stat()
+	toCreate := max(p.minConns-stat.TotalConns(), p.minIdleConns-stat.IdleConns())
+	if toCreate > 0 {
+		return p.createIdleResources(context.Background(), int(toCreate))
+	}
+	return nil
+}
+
+func (p *Pool) createIdleResources(parentCtx context.Context, targetResources int) error {
+	ctx, cancel := context.WithCancel(parentCtx)
+	defer cancel()
+
+	errs := make(chan error, targetResources)
+
+	for range targetResources {
+		go func() {
+			err := p.p.CreateResource(ctx)
+			// Ignore ErrNotAvailable since it means that the pool has become full since we started creating resource.
+			if err == puddle.ErrNotAvailable {
+				err = nil
+			}
+			errs <- err
+		}()
+	}
+
+	var firstError error
+	for range targetResources {
+		err := <-errs
+		if err != nil && firstError == nil {
+			cancel()
+			firstError = err
+		}
+	}
+
+	return firstError
+}
+
+// Acquire returns a connection ([Conn]) from the [Pool].
+func (p *Pool) Acquire(ctx context.Context) (c *Conn, err error) {
+	if p.acquireTracer != nil {
+		ctx = p.acquireTracer.TraceAcquireStart(ctx, p, TraceAcquireStartData{})
+		defer func() {
+			var conn *pgx.Conn
+			if c != nil {
+				conn = c.Conn()
+			}
+			p.acquireTracer.TraceAcquireEnd(ctx, p, TraceAcquireEndData{Conn: conn, Err: err})
+		}()
+	}
+
+	// Try to acquire from the connection pool up to maxConns + 1 times, so that
+	// any that fatal errors would empty the pool and still at least try 1 fresh
+	// connection.
+	for range int(p.maxConns) + 1 {
+		res, err := p.p.Acquire(ctx)
+		if err != nil {
+			return nil, err
+		}
+
+		cr := res.Value()
+
+		// Destroy expired connections before doing any further work (such as
+		// pinging) on them. This enforces MaxConnLifetime at acquire time so that
+		// a connection that expired while idle on a busy pool is not handed out.
+		if p.isExpired(res) {
+			p.lifetimeDestroyCount.Add(1)
+			res.Destroy()
+			continue
+		}
+
+		shouldPingParams := ShouldPingParams{Conn: cr.conn, IdleDuration: res.IdleDuration()}
+		if p.shouldPing(ctx, shouldPingParams) {
+			err := func() error {
+				pingCtx := ctx
+				if p.pingTimeout > 0 {
+					var cancel context.CancelFunc
+					pingCtx, cancel = context.WithTimeout(ctx, p.pingTimeout)
+					defer cancel()
+				}
+				return cr.conn.Ping(pingCtx)
+			}()
+			if err != nil {
+				res.Destroy()
+				continue
+			}
+		}
+
+		if p.prepareConn != nil {
+			ok, err := p.prepareConn(ctx, cr.conn)
+			if !ok {
+				res.Destroy()
+			}
+			if err != nil {
+				if ok {
+					res.Release()
+				}
+				return nil, err
+			}
+			if !ok {
+				continue
+			}
+		}
+
+		return cr.getConn(p, res), nil
+	}
+	return nil, errors.New("pgxpool: too many failed attempts acquiring connection; likely bug in PrepareConn, BeforeAcquire, or ShouldPing hook")
+}
+
+// AcquireFunc acquires a [Conn] and calls f with that [Conn]. ctx will only affect the [Pool.Acquire]. It has no effect on the
+// call of f. The return value is either an error acquiring the [Conn] or the return value of f. The [Conn] is
+// automatically released after the call of f.
+func (p *Pool) AcquireFunc(ctx context.Context, f func(*Conn) error) error {
+	conn, err := p.Acquire(ctx)
+	if err != nil {
+		return err
+	}
+	defer conn.Release()
+
+	return f(conn)
+}
+
+// AcquireAllIdle atomically acquires all currently idle connections. Its intended use is for health check and
+// keep-alive functionality. It does not update pool statistics.
+func (p *Pool) AcquireAllIdle(ctx context.Context) []*Conn {
+	resources := p.p.AcquireAllIdle()
+	conns := make([]*Conn, 0, len(resources))
+	for _, res := range resources {
+		cr := res.Value()
+		if p.prepareConn != nil {
+			ok, err := p.prepareConn(ctx, cr.conn)
+			if !ok || err != nil {
+				res.Destroy()
+				continue
+			}
+		}
+		conns = append(conns, cr.getConn(p, res))
+	}
+
+	return conns
+}
+
+// Reset closes all connections, but leaves the pool open. It is intended for use when an error is detected that would
+// disrupt all connections (such as a network interruption or a server state change).
+//
+// It is safe to reset a pool while connections are checked out. Those connections will be closed when they are returned
+// to the pool.
+func (p *Pool) Reset() {
+	p.p.Reset()
+}
+
+// Config returns a copy of config that was used to initialize this [Pool].
+func (p *Pool) Config() *Config { return p.config.Copy() }
+
+// Stat returns a pgxpool.Stat struct with a snapshot of Pool statistics.
+func (p *Pool) Stat() *Stat {
+	return &Stat{
+		s:                    p.p.Stat(),
+		newConnsCount:        p.newConnsCount.Load(),
+		lifetimeDestroyCount: p.lifetimeDestroyCount.Load(),
+		idleDestroyCount:     p.idleDestroyCount.Load(),
+	}
+}
+
+// Exec acquires a connection from the [Pool] and executes the given SQL.
+// SQL can be either a prepared statement name or an SQL string.
+// Arguments should be referenced positionally from the SQL string as $1, $2, etc.
+// The acquired connection is returned to the pool when the [Pool.Exec] function returns.
+func (p *Pool) Exec(ctx context.Context, sql string, arguments ...any) (pgconn.CommandTag, error) {
+	c, err := p.Acquire(ctx)
+	if err != nil {
+		return pgconn.CommandTag{}, err
+	}
+	defer c.Release()
+
+	return c.Exec(ctx, sql, arguments...)
+}
+
+// Query acquires a connection and executes a query that returns [pgx.Rows].
+// Arguments should be referenced positionally from the SQL string as $1, $2, etc.
+// See [pgx.Rows] documentation to close the returned [pgx.Rows] and return the acquired connection to the [Pool].
+//
+// If there is an error, the returned [pgx.Rows] will be returned in an error state.
+// If preferred, ignore the error returned from [Pool.Query] and handle errors using the returned [pgx.Rows].
+//
+// For extra control over how the query is executed, the types [pgx.QueryExecMode], [pgx.QueryResultFormats], and
+// [pgx.QueryResultFormatsByOID] may be used as the first args to control exactly how the query is executed. This is rarely
+// needed. See the documentation for those types for details.
+func (p *Pool) Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) {
+	c, err := p.Acquire(ctx)
+	if err != nil {
+		return errRows{err: err}, err
+	}
+
+	rows, err := c.Query(ctx, sql, args...)
+	if err != nil {
+		c.Release()
+		return errRows{err: err}, err
+	}
+
+	return c.getPoolRows(rows), nil
+}
+
+// QueryRow acquires a connection and executes a query that is expected
+// to return at most one row ([pgx.Row]). Errors are deferred until [pgx.Row]'s
+// Scan method is called. If the query selects no rows, [pgx.Row]'s Scan will
+// return [pgx.ErrNoRows]. Otherwise, [pgx.Row]'s Scan scans the first selected row
+// and discards the rest. The acquired connection is returned to the [Pool] when
+// [pgx.Row]'s Scan method is called.
+//
+// Arguments should be referenced positionally from the SQL string as $1, $2, etc.
+//
+// For extra control over how the query is executed, the types [pgx.QueryExecMode], [pgx.QueryResultFormats], and
+// [pgx.QueryResultFormatsByOID] may be used as the first args to control exactly how the query is executed. This is rarely
+// needed. See the documentation for those types for details.
+func (p *Pool) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row {
+	c, err := p.Acquire(ctx)
+	if err != nil {
+		return errRow{err: err}
+	}
+
+	row := c.QueryRow(ctx, sql, args...)
+	return c.getPoolRow(row)
+}
+
+func (p *Pool) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults {
+	c, err := p.Acquire(ctx)
+	if err != nil {
+		return errBatchResults{err: err}
+	}
+
+	br := c.SendBatch(ctx, b)
+	return &poolBatchResults{br: br, c: c}
+}
+
+// Begin acquires a connection from the [Pool] and starts a transaction. Unlike [database/sql], the context only affects the begin command. i.e. there is no
+// auto-rollback on context cancellation. Begin initiates a transaction block without explicitly setting a transaction mode for the block (see [Pool.BeginTx] with [pgx.TxOptions] if transaction mode is required).
+// [*Tx] is returned, which implements the [pgx.Tx] interface.
+// [Tx.Commit] or [Tx.Rollback] must be called on the returned transaction to finalize the transaction block.
+func (p *Pool) Begin(ctx context.Context) (pgx.Tx, error) {
+	return p.BeginTx(ctx, pgx.TxOptions{})
+}
+
+// BeginTx acquires a connection from the [Pool] and starts a transaction with [pgx.TxOptions] determining the transaction mode.
+// Unlike [database/sql], the context only affects the begin command. i.e. there is no auto-rollback on context cancellation.
+// [*Tx] is returned, which implements the [pgx.Tx] interface.
+// [Tx.Commit] or [Tx.Rollback] must be called on the returned transaction to finalize the transaction block.
+func (p *Pool) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error) {
+	c, err := p.Acquire(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	t, err := c.BeginTx(ctx, txOptions)
+	if err != nil {
+		c.Release()
+		return nil, err
+	}
+
+	return &Tx{t: t, c: c}, nil
+}
+
+func (p *Pool) CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) {
+	c, err := p.Acquire(ctx)
+	if err != nil {
+		return 0, err
+	}
+	defer c.Release()
+
+	return c.Conn().CopyFrom(ctx, tableName, columnNames, rowSrc)
+}
+
+// Ping acquires a connection from the [Pool] and executes an empty sql statement against it.
+// If the sql returns without error, the database [Pool.Ping] is considered successful, otherwise, the error is returned.
+func (p *Pool) Ping(ctx context.Context) error {
+	c, err := p.Acquire(ctx)
+	if err != nil {
+		return err
+	}
+	defer c.Release()
+	return c.Ping(ctx)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/rows.go b/vendor/github.com/jackc/pgx/v5/pgxpool/rows.go
new file mode 100644
index 000000000..f834b7ec3
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/rows.go
@@ -0,0 +1,116 @@
+package pgxpool
+
+import (
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+type errRows struct {
+	err error
+}
+
+func (errRows) Close()                                       {}
+func (e errRows) Err() error                                 { return e.err }
+func (errRows) CommandTag() pgconn.CommandTag                { return pgconn.CommandTag{} }
+func (errRows) FieldDescriptions() []pgconn.FieldDescription { return nil }
+func (errRows) Next() bool                                   { return false }
+func (e errRows) Scan(dest ...any) error                     { return e.err }
+func (e errRows) Values() ([]any, error)                     { return nil, e.err }
+func (e errRows) RawValues() [][]byte                        { return nil }
+func (e errRows) Conn() *pgx.Conn                            { return nil }
+
+type errRow struct {
+	err error
+}
+
+func (e errRow) Scan(dest ...any) error { return e.err }
+
+type poolRows struct {
+	r   pgx.Rows
+	c   *Conn
+	err error
+}
+
+func (rows *poolRows) Close() {
+	rows.r.Close()
+	if rows.c != nil {
+		rows.c.Release()
+		rows.c = nil
+	}
+}
+
+func (rows *poolRows) Err() error {
+	if rows.err != nil {
+		return rows.err
+	}
+	return rows.r.Err()
+}
+
+func (rows *poolRows) CommandTag() pgconn.CommandTag {
+	return rows.r.CommandTag()
+}
+
+func (rows *poolRows) FieldDescriptions() []pgconn.FieldDescription {
+	return rows.r.FieldDescriptions()
+}
+
+func (rows *poolRows) Next() bool {
+	if rows.err != nil {
+		return false
+	}
+
+	n := rows.r.Next()
+	if !n {
+		rows.Close()
+	}
+	return n
+}
+
+func (rows *poolRows) Scan(dest ...any) error {
+	err := rows.r.Scan(dest...)
+	if err != nil {
+		rows.Close()
+	}
+	return err
+}
+
+func (rows *poolRows) Values() ([]any, error) {
+	values, err := rows.r.Values()
+	if err != nil {
+		rows.Close()
+	}
+	return values, err
+}
+
+func (rows *poolRows) RawValues() [][]byte {
+	return rows.r.RawValues()
+}
+
+func (rows *poolRows) Conn() *pgx.Conn {
+	return rows.r.Conn()
+}
+
+type poolRow struct {
+	r   pgx.Row
+	c   *Conn
+	err error
+}
+
+func (row *poolRow) Scan(dest ...any) error {
+	if row.err != nil {
+		return row.err
+	}
+
+	panicked := true
+	defer func() {
+		if panicked && row.c != nil {
+			row.c.Release()
+		}
+	}()
+	err := row.r.Scan(dest...)
+	panicked = false
+	if row.c != nil {
+		row.c.Release()
+	}
+	return err
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/stat.go b/vendor/github.com/jackc/pgx/v5/pgxpool/stat.go
new file mode 100644
index 000000000..e02b6ac39
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/stat.go
@@ -0,0 +1,91 @@
+package pgxpool
+
+import (
+	"time"
+
+	"github.com/jackc/puddle/v2"
+)
+
+// Stat is a snapshot of Pool statistics.
+type Stat struct {
+	s                    *puddle.Stat
+	newConnsCount        int64
+	lifetimeDestroyCount int64
+	idleDestroyCount     int64
+}
+
+// AcquireCount returns the cumulative count of successful acquires from the pool.
+func (s *Stat) AcquireCount() int64 {
+	return s.s.AcquireCount()
+}
+
+// AcquireDuration returns the total duration of all successful acquires from
+// the pool.
+func (s *Stat) AcquireDuration() time.Duration {
+	return s.s.AcquireDuration()
+}
+
+// AcquiredConns returns the number of currently acquired connections in the pool.
+func (s *Stat) AcquiredConns() int32 {
+	return s.s.AcquiredResources()
+}
+
+// CanceledAcquireCount returns the cumulative count of acquires from the pool
+// that were canceled by a context.
+func (s *Stat) CanceledAcquireCount() int64 {
+	return s.s.CanceledAcquireCount()
+}
+
+// ConstructingConns returns the number of conns with construction in progress in
+// the pool.
+func (s *Stat) ConstructingConns() int32 {
+	return s.s.ConstructingResources()
+}
+
+// EmptyAcquireCount returns the cumulative count of successful acquires from the pool
+// that waited for a resource to be released or constructed because the pool was
+// empty.
+func (s *Stat) EmptyAcquireCount() int64 {
+	return s.s.EmptyAcquireCount()
+}
+
+// IdleConns returns the number of currently idle conns in the pool.
+func (s *Stat) IdleConns() int32 {
+	return s.s.IdleResources()
+}
+
+// MaxConns returns the maximum size of the pool.
+func (s *Stat) MaxConns() int32 {
+	return s.s.MaxResources()
+}
+
+// TotalConns returns the total number of resources currently in the pool.
+// The value is the sum of ConstructingConns, AcquiredConns, and
+// IdleConns.
+func (s *Stat) TotalConns() int32 {
+	return s.s.TotalResources()
+}
+
+// NewConnsCount returns the cumulative count of new connections opened.
+func (s *Stat) NewConnsCount() int64 {
+	return s.newConnsCount
+}
+
+// MaxLifetimeDestroyCount returns the cumulative count of connections destroyed
+// because they exceeded MaxConnLifetime.
+func (s *Stat) MaxLifetimeDestroyCount() int64 {
+	return s.lifetimeDestroyCount
+}
+
+// MaxIdleDestroyCount returns the cumulative count of connections destroyed because
+// they exceeded MaxConnIdleTime.
+func (s *Stat) MaxIdleDestroyCount() int64 {
+	return s.idleDestroyCount
+}
+
+// EmptyAcquireWaitTime returns the cumulative time waited for successful acquires
+// from the pool for a resource to be released or constructed because the pool was
+// empty.
+func (s *Stat) EmptyAcquireWaitTime() time.Duration {
+	return s.s.EmptyAcquireWaitTime()
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/tracer.go b/vendor/github.com/jackc/pgx/v5/pgxpool/tracer.go
new file mode 100644
index 000000000..78b9d15a2
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/tracer.go
@@ -0,0 +1,33 @@
+package pgxpool
+
+import (
+	"context"
+
+	"github.com/jackc/pgx/v5"
+)
+
+// AcquireTracer traces Acquire.
+type AcquireTracer interface {
+	// TraceAcquireStart is called at the beginning of Acquire.
+	// The returned context is used for the rest of the call and will be passed to the TraceAcquireEnd.
+	TraceAcquireStart(ctx context.Context, pool *Pool, data TraceAcquireStartData) context.Context
+	// TraceAcquireEnd is called when a connection has been acquired.
+	TraceAcquireEnd(ctx context.Context, pool *Pool, data TraceAcquireEndData)
+}
+
+type TraceAcquireStartData struct{}
+
+type TraceAcquireEndData struct {
+	Conn *pgx.Conn
+	Err  error
+}
+
+// ReleaseTracer traces Release.
+type ReleaseTracer interface {
+	// TraceRelease is called at the beginning of Release.
+	TraceRelease(pool *Pool, data TraceReleaseData)
+}
+
+type TraceReleaseData struct {
+	Conn *pgx.Conn
+}
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/tx.go b/vendor/github.com/jackc/pgx/v5/pgxpool/tx.go
new file mode 100644
index 000000000..b49e7f4d9
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/tx.go
@@ -0,0 +1,83 @@
+package pgxpool
+
+import (
+	"context"
+
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+// Tx represents a database transaction acquired from a Pool.
+type Tx struct {
+	t pgx.Tx
+	c *Conn
+}
+
+// Begin starts a pseudo nested transaction implemented with a savepoint.
+func (tx *Tx) Begin(ctx context.Context) (pgx.Tx, error) {
+	return tx.t.Begin(ctx)
+}
+
+// Commit commits the transaction and returns the associated connection back to the Pool. Commit will return an error
+// where errors.Is(ErrTxClosed) is true if the Tx is already closed, but is otherwise safe to call multiple times. If
+// the commit fails with a rollback status (e.g. the transaction was already in a broken state) then ErrTxCommitRollback
+// will be returned.
+func (tx *Tx) Commit(ctx context.Context) error {
+	err := tx.t.Commit(ctx)
+	if tx.c != nil {
+		tx.c.Release()
+		tx.c = nil
+	}
+	return err
+}
+
+// Rollback rolls back the transaction and returns the associated connection back to the Pool. Rollback will return
+// where an error where errors.Is(ErrTxClosed) is true if the Tx is already closed, but is otherwise safe to call
+// multiple times. Hence, defer tx.Rollback() is safe even if tx.Commit() will be called first in a non-error condition.
+func (tx *Tx) Rollback(ctx context.Context) error {
+	err := tx.t.Rollback(ctx)
+	if tx.c != nil {
+		tx.c.Release()
+		tx.c = nil
+	}
+	return err
+}
+
+func (tx *Tx) CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) {
+	return tx.t.CopyFrom(ctx, tableName, columnNames, rowSrc)
+}
+
+func (tx *Tx) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults {
+	return tx.t.SendBatch(ctx, b)
+}
+
+func (tx *Tx) LargeObjects() pgx.LargeObjects {
+	return tx.t.LargeObjects()
+}
+
+// Prepare creates a prepared statement with name and sql. If the name is empty,
+// an anonymous prepared statement will be used. sql can contain placeholders
+// for bound parameters. These placeholders are referenced positionally as $1, $2, etc.
+//
+// Prepare is idempotent; i.e. it is safe to call Prepare multiple times with the same
+// name and sql arguments. This allows a code path to Prepare and Query/Exec without
+// needing to first check whether the statement has already been prepared.
+func (tx *Tx) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error) {
+	return tx.t.Prepare(ctx, name, sql)
+}
+
+func (tx *Tx) Exec(ctx context.Context, sql string, arguments ...any) (pgconn.CommandTag, error) {
+	return tx.t.Exec(ctx, sql, arguments...)
+}
+
+func (tx *Tx) Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) {
+	return tx.t.Query(ctx, sql, args...)
+}
+
+func (tx *Tx) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row {
+	return tx.t.QueryRow(ctx, sql, args...)
+}
+
+func (tx *Tx) Conn() *pgx.Conn {
+	return tx.t.Conn()
+}
diff --git a/vendor/github.com/jackc/pgx/v5/rows.go b/vendor/github.com/jackc/pgx/v5/rows.go
new file mode 100644
index 000000000..4e5cf95d0
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/rows.go
@@ -0,0 +1,871 @@
+package pgx
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/jackc/pgx/v5/pgconn"
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+// Rows is the result set returned from [Conn.Query]. Rows must be closed before
+// the [Conn] can be used again. Rows are closed by explicitly calling [Rows.Close],
+// calling [Rows.Next] until it returns false, or when a fatal error occurs.
+//
+// Once a Rows is closed the only methods that may be called are [Rows.Close], [Rows.Err],
+// and [Rows.CommandTag].
+//
+// Rows is an interface instead of a struct to allow tests to mock Query. However,
+// adding a method to an interface is technically a breaking change. Because of this
+// the Rows interface is partially excluded from semantic version requirements.
+// Methods will not be removed or changed, but new methods may be added.
+type Rows interface {
+	// Close closes the rows, making the connection ready for use again. It is safe
+	// to call Close after rows is already closed.
+	Close()
+
+	// Err returns any error that occurred while executing a query or reading its results. Err must be called after the
+	// Rows is closed (either by calling Close or by Next returning false) to check if the query was successful. If it is
+	// called before the Rows is closed it may return nil even if the query failed on the server.
+	Err() error
+
+	// CommandTag returns the command tag from this query. It is only available after Rows is closed.
+	CommandTag() pgconn.CommandTag
+
+	// FieldDescriptions returns the field descriptions of the columns. It may return nil. In particular this can occur
+	// when there was an error executing the query.
+	FieldDescriptions() []pgconn.FieldDescription
+
+	// Next prepares the next row for reading. It returns true if there is another row and false if no more rows are
+	// available or a fatal error has occurred. It automatically closes rows upon returning false (whether due to all rows
+	// having been read or due to an error).
+	//
+	// Callers should check rows.Err() after rows.Next() returns false to detect whether result-set reading ended
+	// prematurely due to an error. See [Conn.Query] for details.
+	//
+	// For simpler error handling, consider using the higher-level pgx v5 [CollectRows()] and [ForEachRow()] helpers instead.
+	Next() bool
+
+	// Scan reads the values from the current row into dest values positionally. dest can include pointers to core types,
+	// values implementing the Scanner interface, and nil. nil will skip the value entirely. It is an error to call Scan
+	// without first calling Next() and checking that it returned true. Rows is automatically closed upon error.
+	Scan(dest ...any) error
+
+	// Values returns the decoded row values. As with Scan(), it is an error to
+	// call Values without first calling Next() and checking that it returned
+	// true.
+	Values() ([]any, error)
+
+	// RawValues returns the unparsed bytes of the row values. The returned data is only valid until the next Next
+	// call or the Rows is closed.
+	RawValues() [][]byte
+
+	// Conn returns the underlying *Conn on which the query was executed. This may return nil if Rows did not come from a
+	// *Conn (e.g. if it was created by RowsFromResultReader)
+	Conn() *Conn
+}
+
+// Row is a convenience wrapper over [Rows] that is returned by [Conn.QueryRow].
+//
+// Row is an interface instead of a struct to allow tests to mock QueryRow. However,
+// adding a method to an interface is technically a breaking change. Because of this
+// the Row interface is partially excluded from semantic version requirements.
+// Methods will not be removed or changed, but new methods may be added.
+type Row interface {
+	// Scan works the same as Rows. with the following exceptions. If no
+	// rows were found it returns ErrNoRows. If multiple rows are returned it
+	// ignores all but the first.
+	Scan(dest ...any) error
+}
+
+// RowScanner scans an entire row at a time into the RowScanner.
+type RowScanner interface {
+	// ScanRows scans the row.
+	ScanRow(rows Rows) error
+}
+
+// connRow implements the Row interface for Conn.QueryRow.
+type connRow baseRows
+
+func (r *connRow) Scan(dest ...any) (err error) {
+	rows := (*baseRows)(r)
+
+	if rows.Err() != nil {
+		return rows.Err()
+	}
+
+	for _, d := range dest {
+		if _, ok := d.(*pgtype.DriverBytes); ok {
+			rows.Close()
+			return fmt.Errorf("cannot scan into *pgtype.DriverBytes from QueryRow")
+		}
+	}
+
+	if !rows.Next() {
+		if rows.Err() == nil {
+			return ErrNoRows
+		}
+		return rows.Err()
+	}
+
+	rows.Scan(dest...)
+	rows.Close()
+	return rows.Err()
+}
+
+// baseRows implements the Rows interface for Conn.Query.
+type baseRows struct {
+	typeMap      *pgtype.Map
+	resultReader *pgconn.ResultReader
+
+	values [][]byte
+
+	commandTag pgconn.CommandTag
+	err        error
+	closed     bool
+
+	scanPlans []pgtype.ScanPlan
+	scanTypes []reflect.Type
+
+	conn              *Conn
+	multiResultReader *pgconn.MultiResultReader
+
+	queryTracer QueryTracer
+	batchTracer BatchTracer
+	ctx         context.Context
+	startTime   time.Time
+	sql         string
+	args        []any
+	rowCount    int
+}
+
+func (rows *baseRows) FieldDescriptions() []pgconn.FieldDescription {
+	return rows.resultReader.FieldDescriptions()
+}
+
+func (rows *baseRows) Close() {
+	if rows.closed {
+		return
+	}
+
+	rows.closed = true
+
+	if rows.resultReader != nil {
+		var closeErr error
+		rows.commandTag, closeErr = rows.resultReader.Close()
+		if rows.err == nil {
+			rows.err = closeErr
+		}
+	}
+
+	if rows.multiResultReader != nil {
+		closeErr := rows.multiResultReader.Close()
+		if rows.err == nil {
+			rows.err = closeErr
+		}
+	}
+
+	if rows.err != nil && rows.conn != nil && rows.sql != "" {
+		if sc := rows.conn.statementCache; sc != nil {
+			sc.Invalidate(rows.sql)
+		}
+
+		if sc := rows.conn.descriptionCache; sc != nil {
+			sc.Invalidate(rows.sql)
+		}
+	}
+
+	if rows.batchTracer != nil {
+		rows.batchTracer.TraceBatchQuery(rows.ctx, rows.conn, TraceBatchQueryData{SQL: rows.sql, Args: rows.args, CommandTag: rows.commandTag, Err: rows.err})
+	} else if rows.queryTracer != nil {
+		rows.queryTracer.TraceQueryEnd(rows.ctx, rows.conn, TraceQueryEndData{rows.commandTag, rows.err})
+	}
+
+	// Zero references to other memory allocations. This allows them to be GC'd even when the Rows still referenced. In
+	// particular, when using pgxpool GC could be delayed as pgxpool.poolRows are allocated in large slices.
+	//
+	// https://github.com/jackc/pgx/pull/2269
+	rows.values = nil
+	rows.scanPlans = nil
+	rows.scanTypes = nil
+	rows.ctx = nil
+	rows.sql = ""
+	rows.args = nil
+}
+
+func (rows *baseRows) CommandTag() pgconn.CommandTag {
+	return rows.commandTag
+}
+
+func (rows *baseRows) Err() error {
+	return rows.err
+}
+
+// fatal signals an error occurred after the query was sent to the server. It
+// closes the rows automatically.
+func (rows *baseRows) fatal(err error) {
+	if rows.err != nil {
+		return
+	}
+
+	rows.err = err
+	rows.Close()
+}
+
+func (rows *baseRows) Next() bool {
+	if rows.closed {
+		return false
+	}
+
+	if rows.resultReader.NextRow() {
+		rows.rowCount++
+		rows.values = rows.resultReader.Values()
+		return true
+	} else {
+		rows.Close()
+		return false
+	}
+}
+
+func (rows *baseRows) Scan(dest ...any) error {
+	m := rows.typeMap
+	fieldDescriptions := rows.FieldDescriptions()
+	values := rows.values
+
+	if len(fieldDescriptions) != len(values) {
+		err := fmt.Errorf("number of field descriptions must equal number of values, got %d and %d", len(fieldDescriptions), len(values))
+		rows.fatal(err)
+		return err
+	}
+
+	if len(dest) == 1 {
+		if rc, ok := dest[0].(RowScanner); ok {
+			err := rc.ScanRow(rows)
+			if err != nil {
+				rows.fatal(err)
+			}
+			return err
+		}
+	}
+
+	if len(fieldDescriptions) != len(dest) {
+		err := fmt.Errorf("number of field descriptions must equal number of destinations, got %d and %d", len(fieldDescriptions), len(dest))
+		rows.fatal(err)
+		return err
+	}
+
+	if rows.scanPlans == nil {
+		rows.scanPlans = make([]pgtype.ScanPlan, len(values))
+		rows.scanTypes = make([]reflect.Type, len(values))
+		for i := range dest {
+			rows.scanPlans[i] = m.PlanScan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, dest[i])
+			rows.scanTypes[i] = reflect.TypeOf(dest[i])
+		}
+	}
+
+	for i, dst := range dest {
+		if dst == nil {
+			continue
+		}
+
+		if rows.scanTypes[i] != reflect.TypeOf(dst) {
+			rows.scanPlans[i] = m.PlanScan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, dest[i])
+			rows.scanTypes[i] = reflect.TypeOf(dest[i])
+		}
+
+		err := rows.scanPlans[i].Scan(values[i], dst)
+		if err != nil {
+			err = ScanArgError{ColumnIndex: i, FieldName: fieldDescriptions[i].Name, Err: err}
+			rows.fatal(err)
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (rows *baseRows) Values() ([]any, error) {
+	if rows.closed {
+		return nil, errors.New("rows is closed")
+	}
+
+	values := make([]any, 0, len(rows.FieldDescriptions()))
+
+	for i := range rows.FieldDescriptions() {
+		buf := rows.values[i]
+		fd := &rows.FieldDescriptions()[i]
+
+		if buf == nil {
+			values = append(values, nil)
+			continue
+		}
+
+		if dt, ok := rows.typeMap.TypeForOID(fd.DataTypeOID); ok {
+			value, err := dt.Codec.DecodeValue(rows.typeMap, fd.DataTypeOID, fd.Format, buf)
+			if err != nil {
+				rows.fatal(err)
+			}
+			values = append(values, value)
+		} else {
+			switch fd.Format {
+			case TextFormatCode:
+				values = append(values, string(buf))
+			case BinaryFormatCode:
+				newBuf := make([]byte, len(buf))
+				copy(newBuf, buf)
+				values = append(values, newBuf)
+			default:
+				rows.fatal(errors.New("unknown format code"))
+			}
+		}
+
+		if rows.Err() != nil {
+			return nil, rows.Err()
+		}
+	}
+
+	return values, rows.Err()
+}
+
+func (rows *baseRows) RawValues() [][]byte {
+	return rows.values
+}
+
+func (rows *baseRows) Conn() *Conn {
+	return rows.conn
+}
+
+type ScanArgError struct {
+	ColumnIndex int
+	FieldName   string
+	Err         error
+}
+
+func (e ScanArgError) Error() string {
+	if e.FieldName == "?column?" { // Don't include the fieldname if it's unknown
+		return fmt.Sprintf("can't scan into dest[%d]: %v", e.ColumnIndex, e.Err)
+	}
+
+	return fmt.Sprintf("can't scan into dest[%d] (col: %s): %v", e.ColumnIndex, e.FieldName, e.Err)
+}
+
+func (e ScanArgError) Unwrap() error {
+	return e.Err
+}
+
+// ScanRow decodes raw row data into dest. It can be used to scan rows read from the lower level [pgconn] interface.
+//
+// typeMap - OID to Go type mapping.
+// fieldDescriptions - OID and format of values
+// values - the raw data as returned from the PostgreSQL server
+// dest - the destination that values will be decoded into
+func ScanRow(typeMap *pgtype.Map, fieldDescriptions []pgconn.FieldDescription, values [][]byte, dest ...any) error {
+	if len(fieldDescriptions) != len(values) {
+		return fmt.Errorf("number of field descriptions must equal number of values, got %d and %d", len(fieldDescriptions), len(values))
+	}
+	if len(fieldDescriptions) != len(dest) {
+		return fmt.Errorf("number of field descriptions must equal number of destinations, got %d and %d", len(fieldDescriptions), len(dest))
+	}
+
+	for i, d := range dest {
+		if d == nil {
+			continue
+		}
+
+		err := typeMap.Scan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, values[i], d)
+		if err != nil {
+			return ScanArgError{ColumnIndex: i, FieldName: fieldDescriptions[i].Name, Err: err}
+		}
+	}
+
+	return nil
+}
+
+// RowsFromResultReader returns a [Rows] that will read from values resultReader and decode with typeMap. It can be used
+// to read from the lower level [pgconn] interface.
+func RowsFromResultReader(typeMap *pgtype.Map, resultReader *pgconn.ResultReader) Rows {
+	return &baseRows{
+		typeMap:      typeMap,
+		resultReader: resultReader,
+	}
+}
+
+// ForEachRow iterates through rows. For each row it scans into the elements of scans and calls fn. If any row
+// fails to scan or fn returns an error the query will be aborted and the error will be returned. Rows will be closed
+// when ForEachRow returns.
+func ForEachRow(rows Rows, scans []any, fn func() error) (pgconn.CommandTag, error) {
+	defer rows.Close()
+
+	for rows.Next() {
+		err := rows.Scan(scans...)
+		if err != nil {
+			return pgconn.CommandTag{}, err
+		}
+
+		err = fn()
+		if err != nil {
+			return pgconn.CommandTag{}, err
+		}
+	}
+
+	if err := rows.Err(); err != nil {
+		return pgconn.CommandTag{}, err
+	}
+
+	return rows.CommandTag(), nil
+}
+
+// CollectableRow is the subset of Rows methods that a RowToFunc is allowed to call.
+type CollectableRow interface {
+	FieldDescriptions() []pgconn.FieldDescription
+	Scan(dest ...any) error
+	Values() ([]any, error)
+	RawValues() [][]byte
+}
+
+// RowToFunc is a function that scans or otherwise converts row to a T.
+type RowToFunc[T any] func(row CollectableRow) (T, error)
+
+// AppendRows iterates through rows, calling fn for each row, and appending the results into a slice of T.
+//
+// This function closes the rows automatically on return.
+func AppendRows[T any, S ~[]T](slice S, rows Rows, fn RowToFunc[T]) (S, error) {
+	defer rows.Close()
+
+	for rows.Next() {
+		value, err := fn(rows)
+		if err != nil {
+			return nil, err
+		}
+		slice = append(slice, value)
+	}
+
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+
+	return slice, nil
+}
+
+// CollectRows iterates through rows, calling fn for each row, and collecting the results into a slice of T.
+//
+// This function closes the rows automatically on return.
+func CollectRows[T any](rows Rows, fn RowToFunc[T]) ([]T, error) {
+	return AppendRows([]T{}, rows, fn)
+}
+
+// CollectOneRow calls fn for the first row in rows and returns the result. If no rows are found returns an error where errors.Is(ErrNoRows) is true.
+// CollectOneRow is to [CollectRows] as [Conn.QueryRow] is to [Conn.Query].
+//
+// This function closes the rows automatically on return.
+func CollectOneRow[T any](rows Rows, fn RowToFunc[T]) (T, error) {
+	defer rows.Close()
+
+	var value T
+	var err error
+
+	if !rows.Next() {
+		if err = rows.Err(); err != nil {
+			return value, err
+		}
+		return value, ErrNoRows
+	}
+
+	value, err = fn(rows)
+	if err != nil {
+		return value, err
+	}
+
+	// The defer rows.Close() won't have executed yet. If the query returned more than one row, rows would still be open.
+	// rows.Close() must be called before rows.Err() so we explicitly call it here.
+	rows.Close()
+	return value, rows.Err()
+}
+
+// CollectExactlyOneRow calls fn for the first row in rows and returns the result.
+//   - If no rows are found returns an error where errors.Is(ErrNoRows) is true.
+//   - If more than 1 row is found returns an error where errors.Is(ErrTooManyRows) is true.
+//
+// This function closes the rows automatically on return.
+func CollectExactlyOneRow[T any](rows Rows, fn RowToFunc[T]) (T, error) {
+	defer rows.Close()
+
+	var (
+		err   error
+		value T
+	)
+
+	if !rows.Next() {
+		if err = rows.Err(); err != nil {
+			return value, err
+		}
+
+		return value, ErrNoRows
+	}
+
+	value, err = fn(rows)
+	if err != nil {
+		return value, err
+	}
+
+	if rows.Next() {
+		var zero T
+
+		return zero, ErrTooManyRows
+	}
+
+	return value, rows.Err()
+}
+
+// RowTo returns a T scanned from row.
+func RowTo[T any](row CollectableRow) (T, error) {
+	var value T
+	err := row.Scan(&value)
+	return value, err
+}
+
+// RowToAddrOf returns the address of a T scanned from row.
+func RowToAddrOf[T any](row CollectableRow) (*T, error) {
+	var value T
+	err := row.Scan(&value)
+	return &value, err
+}
+
+// RowToMap returns a map scanned from row.
+func RowToMap(row CollectableRow) (map[string]any, error) {
+	var value map[string]any
+	err := row.Scan((*mapRowScanner)(&value))
+	return value, err
+}
+
+type mapRowScanner map[string]any
+
+func (rs *mapRowScanner) ScanRow(rows Rows) error {
+	values, err := rows.Values()
+	if err != nil {
+		return err
+	}
+
+	*rs = make(mapRowScanner, len(values))
+
+	for i := range values {
+		(*rs)[rows.FieldDescriptions()[i].Name] = values[i]
+	}
+
+	return nil
+}
+
+// RowToStructByPos returns a T scanned from row. T must be a struct. T must have the same number of public fields as row
+// has fields. The row and T fields will be matched by position. If the "db" struct tag is "-" then the field will be
+// ignored.
+func RowToStructByPos[T any](row CollectableRow) (T, error) {
+	var value T
+	err := (&positionalStructRowScanner{ptrToStruct: &value}).ScanRow(row)
+	return value, err
+}
+
+// RowToAddrOfStructByPos returns the address of a T scanned from row. T must be a struct. T must have the same number a
+// public fields as row has fields. The row and T fields will be matched by position. If the "db" struct tag is "-" then
+// the field will be ignored.
+func RowToAddrOfStructByPos[T any](row CollectableRow) (*T, error) {
+	var value T
+	err := (&positionalStructRowScanner{ptrToStruct: &value}).ScanRow(row)
+	return &value, err
+}
+
+type positionalStructRowScanner struct {
+	ptrToStruct any
+}
+
+func (rs *positionalStructRowScanner) ScanRow(rows CollectableRow) error {
+	typ := reflect.TypeOf(rs.ptrToStruct).Elem()
+	fields := lookupStructFields(typ)
+	if len(rows.RawValues()) > len(fields) {
+		return fmt.Errorf(
+			"got %d values, but dst struct has only %d fields",
+			len(rows.RawValues()),
+			len(fields),
+		)
+	}
+	scanTargets := setupStructScanTargets(rs.ptrToStruct, fields)
+	return rows.Scan(scanTargets...)
+}
+
+// Map from reflect.Type -> []structRowField
+var positionalStructFieldMap sync.Map
+
+func lookupStructFields(t reflect.Type) []structRowField {
+	if cached, ok := positionalStructFieldMap.Load(t); ok {
+		return cached.([]structRowField)
+	}
+
+	fieldStack := make([]int, 0, 1)
+	fields := computeStructFields(t, make([]structRowField, 0, t.NumField()), &fieldStack)
+	fieldsIface, _ := positionalStructFieldMap.LoadOrStore(t, fields)
+	return fieldsIface.([]structRowField)
+}
+
+func computeStructFields(
+	t reflect.Type,
+	fields []structRowField,
+	fieldStack *[]int,
+) []structRowField {
+	tail := len(*fieldStack)
+	*fieldStack = append(*fieldStack, 0)
+	for i := 0; i < t.NumField(); i++ {
+		sf := t.Field(i)
+		(*fieldStack)[tail] = i
+		// Handle anonymous struct embedding, but do not try to handle embedded pointers.
+		if sf.Anonymous && sf.Type.Kind() == reflect.Struct {
+			fields = computeStructFields(sf.Type, fields, fieldStack)
+		} else if sf.PkgPath == "" {
+			dbTag, _ := sf.Tag.Lookup(structTagKey)
+			if dbTag == "-" {
+				// Field is ignored, skip it.
+				continue
+			}
+			fields = append(fields, structRowField{
+				path: append([]int(nil), *fieldStack...),
+			})
+		}
+	}
+	*fieldStack = (*fieldStack)[:tail]
+	return fields
+}
+
+// RowToStructByName returns a T scanned from row. T must be a struct. T must have the same number of named public
+// fields as row has fields. The row and T fields will be matched by name. The match is case-insensitive. The database
+// column name can be overridden with a "db" struct tag. If the "db" struct tag is "-" then the field will be ignored.
+func RowToStructByName[T any](row CollectableRow) (T, error) {
+	var value T
+	err := (&namedStructRowScanner{ptrToStruct: &value}).ScanRow(row)
+	return value, err
+}
+
+// RowToAddrOfStructByName returns the address of a T scanned from row. T must be a struct. T must have the same number
+// of named public fields as row has fields. The row and T fields will be matched by name. The match is
+// case-insensitive. The database column name can be overridden with a "db" struct tag. If the "db" struct tag is "-"
+// then the field will be ignored.
+func RowToAddrOfStructByName[T any](row CollectableRow) (*T, error) {
+	var value T
+	err := (&namedStructRowScanner{ptrToStruct: &value}).ScanRow(row)
+	return &value, err
+}
+
+// RowToStructByNameLax returns a T scanned from row. T must be a struct. T must have greater than or equal number of named public
+// fields as row has fields. The row and T fields will be matched by name. The match is case-insensitive. The database
+// column name can be overridden with a "db" struct tag. If the "db" struct tag is "-" then the field will be ignored.
+func RowToStructByNameLax[T any](row CollectableRow) (T, error) {
+	var value T
+	err := (&namedStructRowScanner{ptrToStruct: &value, lax: true}).ScanRow(row)
+	return value, err
+}
+
+// RowToAddrOfStructByNameLax returns the address of a T scanned from row. T must be a struct. T must have greater than or
+// equal number of named public fields as row has fields. The row and T fields will be matched by name. The match is
+// case-insensitive. The database column name can be overridden with a "db" struct tag. If the "db" struct tag is "-"
+// then the field will be ignored.
+func RowToAddrOfStructByNameLax[T any](row CollectableRow) (*T, error) {
+	var value T
+	err := (&namedStructRowScanner{ptrToStruct: &value, lax: true}).ScanRow(row)
+	return &value, err
+}
+
+type namedStructRowScanner struct {
+	ptrToStruct any
+	lax         bool
+}
+
+func (rs *namedStructRowScanner) ScanRow(rows CollectableRow) error {
+	typ := reflect.TypeOf(rs.ptrToStruct).Elem()
+	fldDescs := rows.FieldDescriptions()
+	namedStructFields, err := lookupNamedStructFields(typ, fldDescs)
+	if err != nil {
+		return err
+	}
+	if !rs.lax && namedStructFields.missingField != "" {
+		return fmt.Errorf("cannot find field %s in returned row", namedStructFields.missingField)
+	}
+	fields := namedStructFields.fields
+	scanTargets := setupStructScanTargets(rs.ptrToStruct, fields)
+	return rows.Scan(scanTargets...)
+}
+
+// Map from namedStructFieldMap -> *namedStructFields
+var namedStructFieldMap sync.Map
+
+type namedStructFieldsKey struct {
+	t        reflect.Type
+	colNames string
+}
+
+type namedStructFields struct {
+	fields []structRowField
+	// missingField is the first field from the struct without a corresponding row field.
+	// This is used to construct the correct error message for non-lax queries.
+	missingField string
+}
+
+func lookupNamedStructFields(
+	t reflect.Type,
+	fldDescs []pgconn.FieldDescription,
+) (*namedStructFields, error) {
+	key := namedStructFieldsKey{
+		t:        t,
+		colNames: joinFieldNames(fldDescs),
+	}
+	if cached, ok := namedStructFieldMap.Load(key); ok {
+		return cached.(*namedStructFields), nil
+	}
+
+	// We could probably do two-levels of caching, where we compute the key -> fields mapping
+	// for a type only once, cache it by type, then use that to compute the column -> fields
+	// mapping for a given set of columns.
+	fieldStack := make([]int, 0, 1)
+	fields, missingField := computeNamedStructFields(
+		fldDescs,
+		t,
+		make([]structRowField, len(fldDescs)),
+		&fieldStack,
+	)
+	for i, f := range fields {
+		if f.path == nil {
+			return nil, fmt.Errorf(
+				"struct doesn't have corresponding row field %s",
+				fldDescs[i].Name,
+			)
+		}
+	}
+
+	fieldsIface, _ := namedStructFieldMap.LoadOrStore(
+		key,
+		&namedStructFields{fields: fields, missingField: missingField},
+	)
+	return fieldsIface.(*namedStructFields), nil
+}
+
+func joinFieldNames(fldDescs []pgconn.FieldDescription) string {
+	switch len(fldDescs) {
+	case 0:
+		return ""
+	case 1:
+		return fldDescs[0].Name
+	}
+
+	totalSize := len(fldDescs) - 1 // Space for separator bytes.
+	for _, d := range fldDescs {
+		totalSize += len(d.Name)
+	}
+	var b strings.Builder
+	b.Grow(totalSize)
+	b.WriteString(fldDescs[0].Name)
+	for _, d := range fldDescs[1:] {
+		b.WriteByte(0) // Join with NUL byte as it's (presumably) not a valid column character.
+		b.WriteString(d.Name)
+	}
+	return b.String()
+}
+
+func computeNamedStructFields(
+	fldDescs []pgconn.FieldDescription,
+	t reflect.Type,
+	fields []structRowField,
+	fieldStack *[]int,
+) ([]structRowField, string) {
+	var missingField string
+	tail := len(*fieldStack)
+	*fieldStack = append(*fieldStack, 0)
+	for i := 0; i < t.NumField(); i++ {
+		sf := t.Field(i)
+		(*fieldStack)[tail] = i
+		if sf.PkgPath != "" && !sf.Anonymous {
+			// Field is unexported, skip it.
+			continue
+		}
+		// Handle anonymous struct embedding, but do not try to handle embedded pointers.
+		if sf.Anonymous && sf.Type.Kind() == reflect.Struct {
+			var missingSubField string
+			fields, missingSubField = computeNamedStructFields(
+				fldDescs,
+				sf.Type,
+				fields,
+				fieldStack,
+			)
+			if missingField == "" {
+				missingField = missingSubField
+			}
+		} else {
+			dbTag, dbTagPresent := sf.Tag.Lookup(structTagKey)
+			if dbTagPresent {
+				dbTag, _, _ = strings.Cut(dbTag, ",")
+			}
+			if dbTag == "-" {
+				// Field is ignored, skip it.
+				continue
+			}
+			colName := dbTag
+			if !dbTagPresent {
+				colName = sf.Name
+			}
+			fpos := fieldPosByName(fldDescs, colName, !dbTagPresent)
+			if fpos == -1 {
+				if missingField == "" {
+					missingField = colName
+				}
+				continue
+			}
+			fields[fpos] = structRowField{
+				path: append([]int(nil), *fieldStack...),
+			}
+		}
+	}
+	*fieldStack = (*fieldStack)[:tail]
+
+	return fields, missingField
+}
+
+const structTagKey = "db"
+
+func fieldPosByName(fldDescs []pgconn.FieldDescription, field string, normalize bool) (i int) {
+	i = -1
+
+	if normalize {
+		field = strings.ReplaceAll(field, "_", "")
+	}
+	for i, desc := range fldDescs {
+		if normalize {
+			if strings.EqualFold(strings.ReplaceAll(desc.Name, "_", ""), field) {
+				return i
+			}
+		} else {
+			if desc.Name == field {
+				return i
+			}
+		}
+	}
+	return i
+}
+
+// structRowField describes a field of a struct.
+//
+// TODO: It would be a bit more efficient to track the path using the pointer
+// offset within the (outermost) struct and use unsafe.Pointer arithmetic to
+// construct references when scanning rows. However, it's not clear it's worth
+// using unsafe for this.
+type structRowField struct {
+	path []int
+}
+
+func setupStructScanTargets(receiver any, fields []structRowField) []any {
+	scanTargets := make([]any, len(fields))
+	v := reflect.ValueOf(receiver).Elem()
+	for i, f := range fields {
+		scanTargets[i] = v.FieldByIndex(f.path).Addr().Interface()
+	}
+	return scanTargets
+}
diff --git a/vendor/github.com/jackc/pgx/v5/test.sh b/vendor/github.com/jackc/pgx/v5/test.sh
new file mode 100644
index 000000000..8bab2d280
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/test.sh
@@ -0,0 +1,170 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# test.sh - Run pgx tests against specific database targets
+#
+# Usage:
+#   ./test.sh [target] [go test flags...]
+#
+# Targets:
+#   pg14    - PostgreSQL 14 (port 5414)
+#   pg15    - PostgreSQL 15 (port 5415)
+#   pg16    - PostgreSQL 16 (port 5416)
+#   pg17    - PostgreSQL 17 (port 5417)
+#   pg18    - PostgreSQL 18 (port 5432) [default]
+#   crdb    - CockroachDB (port 26257)
+#   all     - Run against all targets sequentially
+#
+# Examples:
+#   ./test.sh                          # Test against PG18
+#   ./test.sh pg14                     # Test against PG14
+#   ./test.sh crdb                     # Test against CockroachDB
+#   ./test.sh all                      # Test against all targets
+#   ./test.sh pg16 -run TestConnect    # Test specific test against PG16
+#   ./test.sh pg18 -count=1 -v         # Verbose, no cache, PG18
+
+# Color output (disabled if not a terminal)
+if [ -t 1 ]; then
+    GREEN='\033[0;32m'
+    RED='\033[0;31m'
+    BLUE='\033[0;34m'
+    NC='\033[0m'
+else
+    GREEN=''
+    RED=''
+    BLUE=''
+    NC=''
+fi
+
+log_info()  { echo -e "${BLUE}==> $*${NC}"; }
+log_ok()    { echo -e "${GREEN}==> $*${NC}"; }
+log_err()   { echo -e "${RED}==> $*${NC}" >&2; }
+
+# Wait for a database to accept connections
+wait_for_ready() {
+    local connstr="$1"
+    local label="$2"
+    local max_attempts=30
+    local attempt=0
+
+    log_info "Waiting for $label to be ready..."
+    while ! psql "$connstr" -c "SELECT 1" > /dev/null 2>&1; do
+        attempt=$((attempt + 1))
+        if [ "$attempt" -ge "$max_attempts" ]; then
+            log_err "$label did not become ready after $max_attempts attempts"
+            return 1
+        fi
+        sleep 1
+    done
+    log_ok "$label is ready"
+}
+
+# Directory containing this script (used to locate testsetup/)
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+CERTS_DIR="$SCRIPT_DIR/testsetup/certs"
+
+# Copy client certificates to /tmp for TLS tests
+setup_client_certs() {
+    if [ -d "$CERTS_DIR" ]; then
+        base64 -d "$CERTS_DIR/ca.pem.b64" > /tmp/ca.pem
+        base64 -d "$CERTS_DIR/pgx_sslcert.crt.b64" > /tmp/pgx_sslcert.crt
+        base64 -d "$CERTS_DIR/pgx_sslcert.key.b64" > /tmp/pgx_sslcert.key
+    fi
+}
+
+# Initialize CockroachDB (create database if not exists)
+init_crdb() {
+    local connstr="postgresql://root@localhost:26257/?sslmode=disable"
+    wait_for_ready "$connstr" "CockroachDB"
+    log_info "Ensuring pgx_test database exists on CockroachDB..."
+    psql "$connstr" -c "CREATE DATABASE IF NOT EXISTS pgx_test" 2>/dev/null || true
+}
+
+# Run tests against a single target
+run_tests() {
+    local target="$1"
+    shift
+    local extra_args=("$@")
+
+    local label=""
+    local port=""
+
+    case "$target" in
+        pg14) label="PostgreSQL 14"; port=5414 ;;
+        pg15) label="PostgreSQL 15"; port=5415 ;;
+        pg16) label="PostgreSQL 16"; port=5416 ;;
+        pg17) label="PostgreSQL 17"; port=5417 ;;
+        pg18) label="PostgreSQL 18"; port=5432 ;;
+        crdb)
+            label="CockroachDB (port 26257)"
+            init_crdb
+            log_info "Testing against $label"
+            if ! PGX_TEST_DATABASE="postgresql://root@localhost:26257/pgx_test?sslmode=disable&experimental_enable_temp_tables=on" \
+                go test -count=1 "${extra_args[@]}" ./...; then
+                log_err "Tests FAILED against $label"
+                return 1
+            fi
+            log_ok "Tests passed against $label"
+            return 0
+            ;;
+        *)
+            log_err "Unknown target: $target"
+            log_err "Valid targets: pg14, pg15, pg16, pg17, pg18, crdb, all"
+            return 1
+            ;;
+    esac
+
+    setup_client_certs
+
+    log_info "Testing against $label (port $port)"
+    if ! PGX_TEST_DATABASE="host=localhost port=$port user=postgres password=postgres dbname=pgx_test" \
+         PGX_TEST_UNIX_SOCKET_CONN_STRING="host=/var/run/postgresql port=$port user=postgres dbname=pgx_test" \
+         PGX_TEST_TCP_CONN_STRING="host=127.0.0.1 port=$port user=pgx_md5 password=secret dbname=pgx_test" \
+         PGX_TEST_MD5_PASSWORD_CONN_STRING="host=127.0.0.1 port=$port user=pgx_md5 password=secret dbname=pgx_test" \
+         PGX_TEST_SCRAM_PASSWORD_CONN_STRING="host=127.0.0.1 port=$port user=pgx_scram password=secret dbname=pgx_test channel_binding=disable" \
+         PGX_TEST_SCRAM_PLUS_CONN_STRING="host=localhost port=$port user=pgx_ssl password=secret sslmode=verify-full sslrootcert=/tmp/ca.pem dbname=pgx_test channel_binding=require" \
+         PGX_TEST_PLAIN_PASSWORD_CONN_STRING="host=127.0.0.1 port=$port user=pgx_pw password=secret dbname=pgx_test" \
+         PGX_TEST_TLS_CONN_STRING="host=localhost port=$port user=pgx_ssl password=secret sslmode=verify-full sslrootcert=/tmp/ca.pem dbname=pgx_test channel_binding=disable" \
+         PGX_TEST_TLS_CLIENT_CONN_STRING="host=localhost port=$port user=pgx_sslcert sslmode=verify-full sslrootcert=/tmp/ca.pem sslcert=/tmp/pgx_sslcert.crt sslkey=/tmp/pgx_sslcert.key dbname=pgx_test" \
+         PGX_SSL_PASSWORD=certpw \
+         go test -count=1 "${extra_args[@]}" ./...; then
+        log_err "Tests FAILED against $label"
+        return 1
+    fi
+    log_ok "Tests passed against $label"
+}
+
+# Main
+main() {
+    local target="${1:-pg18}"
+
+    if [ "$target" = "all" ]; then
+        shift || true
+        local targets=(pg14 pg15 pg16 pg17 pg18 crdb)
+        local failed=()
+
+        for t in "${targets[@]}"; do
+            echo ""
+            log_info "=========================================="
+            log_info "Target: $t"
+            log_info "=========================================="
+            if ! run_tests "$t" "$@"; then
+                failed+=("$t")
+                log_err "FAILED: $t"
+            fi
+        done
+
+        echo ""
+        if [ ${#failed[@]} -gt 0 ]; then
+            log_err "Failed targets: ${failed[*]}"
+            return 1
+        else
+            log_ok "All targets passed"
+        fi
+    else
+        shift || true
+        run_tests "$target" "$@"
+    fi
+}
+
+main "$@"
diff --git a/vendor/github.com/jackc/pgx/v5/tracer.go b/vendor/github.com/jackc/pgx/v5/tracer.go
new file mode 100644
index 000000000..58ca99f7e
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/tracer.go
@@ -0,0 +1,107 @@
+package pgx
+
+import (
+	"context"
+
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+// QueryTracer traces Query, QueryRow, and Exec.
+type QueryTracer interface {
+	// TraceQueryStart is called at the beginning of Query, QueryRow, and Exec calls. The returned context is used for the
+	// rest of the call and will be passed to TraceQueryEnd.
+	TraceQueryStart(ctx context.Context, conn *Conn, data TraceQueryStartData) context.Context
+
+	TraceQueryEnd(ctx context.Context, conn *Conn, data TraceQueryEndData)
+}
+
+type TraceQueryStartData struct {
+	SQL  string
+	Args []any
+}
+
+type TraceQueryEndData struct {
+	CommandTag pgconn.CommandTag
+	Err        error
+}
+
+// BatchTracer traces SendBatch.
+type BatchTracer interface {
+	// TraceBatchStart is called at the beginning of SendBatch calls. The returned context is used for the
+	// rest of the call and will be passed to TraceBatchQuery and TraceBatchEnd.
+	TraceBatchStart(ctx context.Context, conn *Conn, data TraceBatchStartData) context.Context
+
+	TraceBatchQuery(ctx context.Context, conn *Conn, data TraceBatchQueryData)
+	TraceBatchEnd(ctx context.Context, conn *Conn, data TraceBatchEndData)
+}
+
+type TraceBatchStartData struct {
+	Batch *Batch
+}
+
+type TraceBatchQueryData struct {
+	SQL        string
+	Args       []any
+	CommandTag pgconn.CommandTag
+	Err        error
+}
+
+type TraceBatchEndData struct {
+	Err error
+}
+
+// CopyFromTracer traces CopyFrom.
+type CopyFromTracer interface {
+	// TraceCopyFromStart is called at the beginning of CopyFrom calls. The returned context is used for the
+	// rest of the call and will be passed to TraceCopyFromEnd.
+	TraceCopyFromStart(ctx context.Context, conn *Conn, data TraceCopyFromStartData) context.Context
+
+	TraceCopyFromEnd(ctx context.Context, conn *Conn, data TraceCopyFromEndData)
+}
+
+type TraceCopyFromStartData struct {
+	TableName   Identifier
+	ColumnNames []string
+}
+
+type TraceCopyFromEndData struct {
+	CommandTag pgconn.CommandTag
+	Err        error
+}
+
+// PrepareTracer traces Prepare.
+type PrepareTracer interface {
+	// TracePrepareStart is called at the beginning of Prepare calls. The returned context is used for the
+	// rest of the call and will be passed to TracePrepareEnd.
+	TracePrepareStart(ctx context.Context, conn *Conn, data TracePrepareStartData) context.Context
+
+	TracePrepareEnd(ctx context.Context, conn *Conn, data TracePrepareEndData)
+}
+
+type TracePrepareStartData struct {
+	Name string
+	SQL  string
+}
+
+type TracePrepareEndData struct {
+	AlreadyPrepared bool
+	Err             error
+}
+
+// ConnectTracer traces Connect and ConnectConfig.
+type ConnectTracer interface {
+	// TraceConnectStart is called at the beginning of Connect and ConnectConfig calls. The returned context is used for
+	// the rest of the call and will be passed to TraceConnectEnd.
+	TraceConnectStart(ctx context.Context, data TraceConnectStartData) context.Context
+
+	TraceConnectEnd(ctx context.Context, data TraceConnectEndData)
+}
+
+type TraceConnectStartData struct {
+	ConnConfig *ConnConfig
+}
+
+type TraceConnectEndData struct {
+	Conn *Conn
+	Err  error
+}
diff --git a/vendor/github.com/jackc/pgx/v5/tx.go b/vendor/github.com/jackc/pgx/v5/tx.go
new file mode 100644
index 000000000..3f93a6f24
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/tx.go
@@ -0,0 +1,442 @@
+package pgx
+
+import (
+	"context"
+	"errors"
+	"strconv"
+	"strings"
+
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+// TxIsoLevel is the transaction isolation level (serializable, repeatable read, read committed or read uncommitted)
+type TxIsoLevel string
+
+// Transaction isolation levels
+const (
+	Serializable    TxIsoLevel = "serializable"
+	RepeatableRead  TxIsoLevel = "repeatable read"
+	ReadCommitted   TxIsoLevel = "read committed"
+	ReadUncommitted TxIsoLevel = "read uncommitted"
+)
+
+// TxAccessMode is the transaction access mode (read write or read only)
+type TxAccessMode string
+
+// Transaction access modes
+const (
+	ReadWrite TxAccessMode = "read write"
+	ReadOnly  TxAccessMode = "read only"
+)
+
+// TxDeferrableMode is the transaction deferrable mode (deferrable or not deferrable)
+type TxDeferrableMode string
+
+// Transaction deferrable modes
+const (
+	Deferrable    TxDeferrableMode = "deferrable"
+	NotDeferrable TxDeferrableMode = "not deferrable"
+)
+
+// TxOptions are transaction modes within a transaction block
+type TxOptions struct {
+	IsoLevel       TxIsoLevel
+	AccessMode     TxAccessMode
+	DeferrableMode TxDeferrableMode
+
+	// BeginQuery is the SQL query that will be executed to begin the transaction. This allows using non-standard syntax
+	// such as BEGIN PRIORITY HIGH with CockroachDB. If set this will override the other settings.
+	BeginQuery string
+	// CommitQuery is the SQL query that will be executed to commit the transaction.
+	CommitQuery string
+}
+
+var emptyTxOptions TxOptions
+
+func (txOptions TxOptions) beginSQL() string {
+	if txOptions == emptyTxOptions {
+		return "begin"
+	}
+
+	if txOptions.BeginQuery != "" {
+		return txOptions.BeginQuery
+	}
+
+	var buf strings.Builder
+	buf.Grow(64) // 64 - maximum length of string with available options
+	buf.WriteString("begin")
+
+	if txOptions.IsoLevel != "" {
+		buf.WriteString(" isolation level ")
+		buf.WriteString(string(txOptions.IsoLevel))
+	}
+	if txOptions.AccessMode != "" {
+		buf.WriteByte(' ')
+		buf.WriteString(string(txOptions.AccessMode))
+	}
+	if txOptions.DeferrableMode != "" {
+		buf.WriteByte(' ')
+		buf.WriteString(string(txOptions.DeferrableMode))
+	}
+
+	return buf.String()
+}
+
+var ErrTxClosed = errors.New("tx is closed")
+
+// ErrTxCommitRollback occurs when an error has occurred in a transaction and
+// Commit() is called. PostgreSQL accepts COMMIT on aborted transactions, but
+// it is treated as ROLLBACK.
+var ErrTxCommitRollback = errors.New("commit unexpectedly resulted in rollback")
+
+// Begin starts a transaction. Unlike [database/sql], the context only affects the begin command. i.e. there is no
+// auto-rollback on context cancellation.
+func (c *Conn) Begin(ctx context.Context) (Tx, error) {
+	return c.BeginTx(ctx, TxOptions{})
+}
+
+// BeginTx starts a transaction with txOptions determining the transaction mode. Unlike [database/sql], the context only
+// affects the begin command. i.e. there is no auto-rollback on context cancellation.
+func (c *Conn) BeginTx(ctx context.Context, txOptions TxOptions) (Tx, error) {
+	_, err := c.Exec(ctx, txOptions.beginSQL())
+	if err != nil {
+		// begin should never fail unless there is an underlying connection issue or
+		// a context timeout. In either case, the connection is possibly broken.
+		c.die()
+		return nil, err
+	}
+
+	return &dbTx{
+		conn:        c,
+		commitQuery: txOptions.CommitQuery,
+	}, nil
+}
+
+// Tx represents a database transaction.
+//
+// Tx is an interface instead of a struct to enable connection pools to be implemented without relying on internal pgx
+// state, to support pseudo-nested transactions with savepoints, and to allow tests to mock transactions. However,
+// adding a method to an interface is technically a breaking change. If new methods are added to Conn it may be
+// desirable to add them to Tx as well. Because of this the Tx interface is partially excluded from semantic version
+// requirements. Methods will not be removed or changed, but new methods may be added.
+type Tx interface {
+	// Begin starts a pseudo nested transaction.
+	Begin(ctx context.Context) (Tx, error)
+
+	// Commit commits the transaction if this is a real transaction or releases the savepoint if this is a pseudo nested
+	// transaction. Commit will return an error where errors.Is(ErrTxClosed) is true if the Tx is already closed, but is
+	// otherwise safe to call multiple times. If the commit fails with a rollback status (e.g. the transaction was already
+	// in a broken state) then an error where errors.Is(ErrTxCommitRollback) is true will be returned.
+	Commit(ctx context.Context) error
+
+	// Rollback rolls back the transaction if this is a real transaction or rolls back to the savepoint if this is a
+	// pseudo nested transaction. Rollback will return an error where errors.Is(ErrTxClosed) is true if the Tx is already
+	// closed, but is otherwise safe to call multiple times. Hence, a defer tx.Rollback() is safe even if tx.Commit() will
+	// be called first in a non-error condition. Any other failure of a real transaction will result in the connection
+	// being closed.
+	Rollback(ctx context.Context) error
+
+	CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error)
+	SendBatch(ctx context.Context, b *Batch) BatchResults
+	LargeObjects() LargeObjects
+
+	Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error)
+
+	Exec(ctx context.Context, sql string, arguments ...any) (commandTag pgconn.CommandTag, err error)
+	Query(ctx context.Context, sql string, args ...any) (Rows, error)
+	QueryRow(ctx context.Context, sql string, args ...any) Row
+
+	// Conn returns the underlying *Conn that on which this transaction is executing.
+	Conn() *Conn
+}
+
+// dbTx represents a database transaction.
+//
+// All dbTx methods return ErrTxClosed if Commit or Rollback has already been
+// called on the dbTx.
+type dbTx struct {
+	conn         *Conn
+	savepointNum int64
+	closed       bool
+	commitQuery  string
+}
+
+// Begin starts a pseudo nested transaction implemented with a savepoint.
+func (tx *dbTx) Begin(ctx context.Context) (Tx, error) {
+	if tx.closed {
+		return nil, ErrTxClosed
+	}
+
+	tx.savepointNum++
+	_, err := tx.conn.Exec(ctx, "savepoint sp_"+strconv.FormatInt(tx.savepointNum, 10))
+	if err != nil {
+		return nil, err
+	}
+
+	return &dbSimulatedNestedTx{tx: tx, savepointNum: tx.savepointNum}, nil
+}
+
+// Commit commits the transaction.
+func (tx *dbTx) Commit(ctx context.Context) error {
+	if tx.closed {
+		return ErrTxClosed
+	}
+
+	commandSQL := "commit"
+	if tx.commitQuery != "" {
+		commandSQL = tx.commitQuery
+	}
+
+	commandTag, err := tx.conn.Exec(ctx, commandSQL)
+	tx.closed = true
+	if err != nil {
+		if tx.conn.PgConn().TxStatus() != 'I' {
+			_ = tx.conn.Close(ctx) // already have error to return
+		}
+		return err
+	}
+	if commandTag.String() == "ROLLBACK" {
+		return ErrTxCommitRollback
+	}
+
+	return nil
+}
+
+// Rollback rolls back the transaction. Rollback will return ErrTxClosed if the
+// Tx is already closed, but is otherwise safe to call multiple times. Hence, a
+// defer tx.Rollback() is safe even if tx.Commit() will be called first in a
+// non-error condition.
+func (tx *dbTx) Rollback(ctx context.Context) error {
+	if tx.closed {
+		return ErrTxClosed
+	}
+
+	_, err := tx.conn.Exec(ctx, "rollback")
+	tx.closed = true
+	if err != nil {
+		// A rollback failure leaves the connection in an undefined state
+		tx.conn.die()
+		return err
+	}
+
+	return nil
+}
+
+// Exec delegates to the underlying *Conn
+func (tx *dbTx) Exec(ctx context.Context, sql string, arguments ...any) (commandTag pgconn.CommandTag, err error) {
+	if tx.closed {
+		return pgconn.CommandTag{}, ErrTxClosed
+	}
+
+	return tx.conn.Exec(ctx, sql, arguments...)
+}
+
+// Prepare delegates to the underlying *Conn
+func (tx *dbTx) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error) {
+	if tx.closed {
+		return nil, ErrTxClosed
+	}
+
+	return tx.conn.Prepare(ctx, name, sql)
+}
+
+// Query delegates to the underlying *Conn
+func (tx *dbTx) Query(ctx context.Context, sql string, args ...any) (Rows, error) {
+	if tx.closed {
+		// Because checking for errors can be deferred to the *Rows, build one with the error
+		err := ErrTxClosed
+		return &baseRows{closed: true, err: err}, err
+	}
+
+	return tx.conn.Query(ctx, sql, args...)
+}
+
+// QueryRow delegates to the underlying *Conn
+func (tx *dbTx) QueryRow(ctx context.Context, sql string, args ...any) Row {
+	rows, _ := tx.Query(ctx, sql, args...)
+	return (*connRow)(rows.(*baseRows))
+}
+
+// CopyFrom delegates to the underlying *Conn
+func (tx *dbTx) CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error) {
+	if tx.closed {
+		return 0, ErrTxClosed
+	}
+
+	return tx.conn.CopyFrom(ctx, tableName, columnNames, rowSrc)
+}
+
+// SendBatch delegates to the underlying *Conn
+func (tx *dbTx) SendBatch(ctx context.Context, b *Batch) BatchResults {
+	if tx.closed {
+		return &batchResults{err: ErrTxClosed}
+	}
+
+	return tx.conn.SendBatch(ctx, b)
+}
+
+// LargeObjects returns a LargeObjects instance for the transaction.
+func (tx *dbTx) LargeObjects() LargeObjects {
+	return LargeObjects{tx: tx}
+}
+
+func (tx *dbTx) Conn() *Conn {
+	return tx.conn
+}
+
+// dbSimulatedNestedTx represents a simulated nested transaction implemented by a savepoint.
+type dbSimulatedNestedTx struct {
+	tx           Tx
+	savepointNum int64
+	closed       bool
+}
+
+// Begin starts a pseudo nested transaction implemented with a savepoint.
+func (sp *dbSimulatedNestedTx) Begin(ctx context.Context) (Tx, error) {
+	if sp.closed {
+		return nil, ErrTxClosed
+	}
+
+	return sp.tx.Begin(ctx)
+}
+
+// Commit releases the savepoint essentially committing the pseudo nested transaction.
+func (sp *dbSimulatedNestedTx) Commit(ctx context.Context) error {
+	if sp.closed {
+		return ErrTxClosed
+	}
+
+	_, err := sp.Exec(ctx, "release savepoint sp_"+strconv.FormatInt(sp.savepointNum, 10))
+	sp.closed = true
+	return err
+}
+
+// Rollback rolls back to the savepoint essentially rolling back the pseudo nested transaction. Rollback will return
+// ErrTxClosed if the dbSavepoint is already closed, but is otherwise safe to call multiple times. Hence, a defer sp.Rollback()
+// is safe even if sp.Commit() will be called first in a non-error condition.
+func (sp *dbSimulatedNestedTx) Rollback(ctx context.Context) error {
+	if sp.closed {
+		return ErrTxClosed
+	}
+
+	_, err := sp.Exec(ctx, "rollback to savepoint sp_"+strconv.FormatInt(sp.savepointNum, 10))
+	sp.closed = true
+	return err
+}
+
+// Exec delegates to the underlying Tx
+func (sp *dbSimulatedNestedTx) Exec(ctx context.Context, sql string, arguments ...any) (commandTag pgconn.CommandTag, err error) {
+	if sp.closed {
+		return pgconn.CommandTag{}, ErrTxClosed
+	}
+
+	return sp.tx.Exec(ctx, sql, arguments...)
+}
+
+// Prepare delegates to the underlying Tx
+func (sp *dbSimulatedNestedTx) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error) {
+	if sp.closed {
+		return nil, ErrTxClosed
+	}
+
+	return sp.tx.Prepare(ctx, name, sql)
+}
+
+// Query delegates to the underlying Tx
+func (sp *dbSimulatedNestedTx) Query(ctx context.Context, sql string, args ...any) (Rows, error) {
+	if sp.closed {
+		// Because checking for errors can be deferred to the *Rows, build one with the error
+		err := ErrTxClosed
+		return &baseRows{closed: true, err: err}, err
+	}
+
+	return sp.tx.Query(ctx, sql, args...)
+}
+
+// QueryRow delegates to the underlying Tx
+func (sp *dbSimulatedNestedTx) QueryRow(ctx context.Context, sql string, args ...any) Row {
+	rows, _ := sp.Query(ctx, sql, args...)
+	return (*connRow)(rows.(*baseRows))
+}
+
+// CopyFrom delegates to the underlying *Conn
+func (sp *dbSimulatedNestedTx) CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error) {
+	if sp.closed {
+		return 0, ErrTxClosed
+	}
+
+	return sp.tx.CopyFrom(ctx, tableName, columnNames, rowSrc)
+}
+
+// SendBatch delegates to the underlying *Conn
+func (sp *dbSimulatedNestedTx) SendBatch(ctx context.Context, b *Batch) BatchResults {
+	if sp.closed {
+		return &batchResults{err: ErrTxClosed}
+	}
+
+	return sp.tx.SendBatch(ctx, b)
+}
+
+func (sp *dbSimulatedNestedTx) LargeObjects() LargeObjects {
+	return LargeObjects{tx: sp}
+}
+
+func (sp *dbSimulatedNestedTx) Conn() *Conn {
+	return sp.tx.Conn()
+}
+
+// BeginFunc calls Begin on db and then calls fn. If fn does not return an error then it calls [Tx.Commit] on db. If fn
+// returns an error it calls [Tx.Rollback] on db. The context will be used when executing the transaction control statements
+// (BEGIN, ROLLBACK, and COMMIT) but does not otherwise affect the execution of fn.
+func BeginFunc(
+	ctx context.Context,
+	db interface {
+		Begin(ctx context.Context) (Tx, error)
+	},
+	fn func(Tx) error,
+) (err error) {
+	var tx Tx
+	tx, err = db.Begin(ctx)
+	if err != nil {
+		return err
+	}
+
+	return beginFuncExec(ctx, tx, fn)
+}
+
+// BeginTxFunc calls BeginTx on db and then calls fn. If fn does not return an error then it calls [Tx.Commit] on db. If fn
+// returns an error it calls [Tx.Rollback] on db. The context will be used when executing the transaction control statements
+// (BEGIN, ROLLBACK, and COMMIT) but does not otherwise affect the execution of fn.
+func BeginTxFunc(
+	ctx context.Context,
+	db interface {
+		BeginTx(ctx context.Context, txOptions TxOptions) (Tx, error)
+	},
+	txOptions TxOptions,
+	fn func(Tx) error,
+) (err error) {
+	var tx Tx
+	tx, err = db.BeginTx(ctx, txOptions)
+	if err != nil {
+		return err
+	}
+
+	return beginFuncExec(ctx, tx, fn)
+}
+
+func beginFuncExec(ctx context.Context, tx Tx, fn func(Tx) error) (err error) {
+	defer func() {
+		rollbackErr := tx.Rollback(ctx)
+		if rollbackErr != nil && !errors.Is(rollbackErr, ErrTxClosed) {
+			err = rollbackErr
+		}
+	}()
+
+	fErr := fn(tx)
+	if fErr != nil {
+		_ = tx.Rollback(ctx) // ignore rollback error as there is already an error to return
+		return fErr
+	}
+
+	return tx.Commit(ctx)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/values.go b/vendor/github.com/jackc/pgx/v5/values.go
new file mode 100644
index 000000000..6e2ff3003
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/values.go
@@ -0,0 +1,63 @@
+package pgx
+
+import (
+	"errors"
+
+	"github.com/jackc/pgx/v5/internal/pgio"
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+// PostgreSQL format codes
+const (
+	TextFormatCode   = 0
+	BinaryFormatCode = 1
+)
+
+func convertSimpleArgument(m *pgtype.Map, arg any) (any, error) {
+	buf, err := m.Encode(0, TextFormatCode, arg, []byte{})
+	if err != nil {
+		return nil, err
+	}
+	if buf == nil {
+		return nil, nil
+	}
+	return string(buf), nil
+}
+
+func encodeCopyValue(m *pgtype.Map, buf []byte, oid uint32, arg any) ([]byte, error) {
+	sp := len(buf)
+	buf = pgio.AppendInt32(buf, -1)
+	argBuf, err := m.Encode(oid, BinaryFormatCode, arg, buf)
+	if err != nil {
+		if argBuf2, err2 := tryScanStringCopyValueThenEncode(m, buf, oid, arg); err2 == nil {
+			argBuf = argBuf2
+		} else {
+			return nil, err
+		}
+	}
+
+	if argBuf != nil {
+		buf = argBuf
+		pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+	}
+	return buf, nil
+}
+
+func tryScanStringCopyValueThenEncode(m *pgtype.Map, buf []byte, oid uint32, arg any) ([]byte, error) {
+	s, ok := arg.(string)
+	if !ok {
+		textBuf, err := m.Encode(oid, TextFormatCode, arg, nil)
+		if err != nil {
+			return nil, errors.New("not a string and cannot be encoded as text")
+		}
+		s = string(textBuf)
+	}
+
+	var v any
+	err := m.Scan(oid, TextFormatCode, []byte(s), &v)
+	if err != nil {
+		return nil, err
+	}
+
+	return m.Encode(oid, BinaryFormatCode, v, buf)
+}
diff --git a/vendor/github.com/jackc/puddle/v2/CHANGELOG.md b/vendor/github.com/jackc/puddle/v2/CHANGELOG.md
new file mode 100644
index 000000000..d0d202c74
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/CHANGELOG.md
@@ -0,0 +1,79 @@
+# 2.2.2 (September 10, 2024)
+
+* Add empty acquire time to stats (Maxim Ivanov)
+* Stop importing nanotime from runtime via linkname (maypok86)
+
+# 2.2.1 (July 15, 2023)
+
+* Fix: CreateResource cannot overflow pool. This changes documented behavior of CreateResource. Previously,
+  CreateResource could create a resource even if the pool was full. This could cause the pool to overflow. While this
+  was documented, it was documenting incorrect behavior. CreateResource now returns an error if the pool is full.
+
+# 2.2.0 (February 11, 2023)
+
+* Use Go 1.19 atomics and drop go.uber.org/atomic dependency
+
+# 2.1.2 (November 12, 2022)
+
+* Restore support to Go 1.18 via go.uber.org/atomic
+
+# 2.1.1 (November 11, 2022)
+
+* Fix create resource concurrently with Stat call race
+
+# 2.1.0 (October 28, 2022)
+
+* Concurrency control is now implemented with a semaphore. This simplifies some internal logic, resolves a few error conditions (including a deadlock), and improves performance. (Jan Dubsky)
+* Go 1.19 is now required for the improved atomic support.
+
+# 2.0.1 (October 28, 2022)
+
+* Fix race condition when Close is called concurrently with multiple constructors
+
+# 2.0.0 (September 17, 2022)
+
+* Use generics instead of interface{} (Столяров Владимир Алексеевич)
+* Add Reset
+* Do not cancel resource construction when Acquire is canceled
+* NewPool takes Config
+
+# 1.3.0 (August 27, 2022)
+
+* Acquire creates resources in background to allow creation to continue after Acquire is canceled (James Hartig)
+
+# 1.2.1 (December 2, 2021)
+
+* TryAcquire now does not block when background constructing resource
+
+# 1.2.0 (November 20, 2021)
+
+* Add TryAcquire (A. Jensen)
+* Fix: remove memory leak / unintentionally pinned memory when shrinking slices (Alexander Staubo)
+* Fix: Do not leave pool locked after panic from nil context
+
+# 1.1.4 (September 11, 2021)
+
+* Fix: Deadlock in CreateResource if pool was closed during resource acquisition (Dmitriy Matrenichev)
+
+# 1.1.3 (December 3, 2020)
+
+* Fix: Failed resource creation could cause concurrent Acquire to hang. (Evgeny Vanslov)
+
+# 1.1.2 (September 26, 2020)
+
+* Fix: Resource.Destroy no longer removes itself from the pool before its destructor has completed.
+* Fix: Prevent crash when pool is closed while resource is being created.
+
+# 1.1.1 (April 2, 2020)
+
+* Pool.Close can be safely called multiple times
+* AcquireAllIDle immediately returns nil if pool is closed
+* CreateResource checks if pool is closed before taking any action
+* Fix potential race condition when CreateResource and Close are called concurrently. CreateResource now checks if pool is closed before adding newly created resource to pool.
+
+# 1.1.0 (February 5, 2020)
+
+* Use runtime.nanotime for faster tracking of acquire time and last usage time.
+* Track resource idle time to enable client health check logic. (Patrick Ellul)
+* Add CreateResource to construct a new resource without acquiring it. (Patrick Ellul)
+* Fix deadlock race when acquire is cancelled. (Michael Tharp)
diff --git a/vendor/github.com/jackc/puddle/v2/LICENSE b/vendor/github.com/jackc/puddle/v2/LICENSE
new file mode 100644
index 000000000..bcc286c54
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2018 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/puddle/v2/README.md b/vendor/github.com/jackc/puddle/v2/README.md
new file mode 100644
index 000000000..fa82a9d46
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/README.md
@@ -0,0 +1,80 @@
+[![Go Reference](https://pkg.go.dev/badge/github.com/jackc/puddle/v2.svg)](https://pkg.go.dev/github.com/jackc/puddle/v2)
+![Build Status](https://github.com/jackc/puddle/actions/workflows/ci.yml/badge.svg)
+
+# Puddle
+
+Puddle is a tiny generic resource pool library for Go that uses the standard
+context library to signal cancellation of acquires. It is designed to contain
+the minimum functionality required for a resource pool. It can be used directly
+or it can be used as the base for a domain specific resource pool. For example,
+a database connection pool may use puddle internally and implement health checks
+and keep-alive behavior without needing to implement any concurrent code of its
+own.
+
+## Features
+
+* Acquire cancellation via context standard library
+* Statistics API for monitoring pool pressure
+* No dependencies outside of standard library and golang.org/x/sync
+* High performance
+* 100% test coverage of reachable code
+
+## Example Usage
+
+```go
+package main
+
+import (
+	"context"
+	"log"
+	"net"
+
+	"github.com/jackc/puddle/v2"
+)
+
+func main() {
+	constructor := func(context.Context) (net.Conn, error) {
+		return net.Dial("tcp", "127.0.0.1:8080")
+	}
+	destructor := func(value net.Conn) {
+		value.Close()
+	}
+	maxPoolSize := int32(10)
+
+	pool, err := puddle.NewPool(&puddle.Config[net.Conn]{Constructor: constructor, Destructor: destructor, MaxSize: maxPoolSize})
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Acquire resource from the pool.
+	res, err := pool.Acquire(context.Background())
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Use resource.
+	_, err = res.Value().Write([]byte{1})
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Release when done.
+	res.Release()
+}
+```
+
+## Status
+
+Puddle is stable and feature complete.
+
+* Bug reports and fixes are welcome.
+* New features will usually not be accepted if they can be feasibly implemented in a wrapper.
+* Performance optimizations will usually not be accepted unless the performance issue rises to the level of a bug.
+
+## Supported Go Versions
+
+puddle supports the same versions of Go that are supported by the Go project. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases. This means puddle supports Go 1.19 and higher.
+
+## License
+
+MIT
diff --git a/vendor/github.com/jackc/puddle/v2/context.go b/vendor/github.com/jackc/puddle/v2/context.go
new file mode 100644
index 000000000..e19d2a609
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/context.go
@@ -0,0 +1,24 @@
+package puddle
+
+import (
+	"context"
+	"time"
+)
+
+// valueCancelCtx combines two contexts into one. One context is used for values and the other is used for cancellation.
+type valueCancelCtx struct {
+	valueCtx  context.Context
+	cancelCtx context.Context
+}
+
+func (ctx *valueCancelCtx) Deadline() (time.Time, bool) { return ctx.cancelCtx.Deadline() }
+func (ctx *valueCancelCtx) Done() <-chan struct{}       { return ctx.cancelCtx.Done() }
+func (ctx *valueCancelCtx) Err() error                  { return ctx.cancelCtx.Err() }
+func (ctx *valueCancelCtx) Value(key any) any           { return ctx.valueCtx.Value(key) }
+
+func newValueCancelCtx(valueCtx, cancelContext context.Context) context.Context {
+	return &valueCancelCtx{
+		valueCtx:  valueCtx,
+		cancelCtx: cancelContext,
+	}
+}
diff --git a/vendor/github.com/jackc/puddle/v2/doc.go b/vendor/github.com/jackc/puddle/v2/doc.go
new file mode 100644
index 000000000..818e4a698
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/doc.go
@@ -0,0 +1,11 @@
+// Package puddle is a generic resource pool with type-parametrized api.
+/*
+
+Puddle is a tiny generic resource pool library for Go that uses the standard
+context library to signal cancellation of acquires. It is designed to contain
+the minimum functionality a resource pool needs that cannot be implemented
+without concurrency concerns. For example, a database connection pool may use
+puddle internally and implement health checks and keep-alive behavior without
+needing to implement any concurrent code of its own.
+*/
+package puddle
diff --git a/vendor/github.com/jackc/puddle/v2/internal/genstack/gen_stack.go b/vendor/github.com/jackc/puddle/v2/internal/genstack/gen_stack.go
new file mode 100644
index 000000000..7e4660c8c
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/internal/genstack/gen_stack.go
@@ -0,0 +1,85 @@
+package genstack
+
+// GenStack implements a generational stack.
+//
+// GenStack works as common stack except for the fact that all elements in the
+// older generation are guaranteed to be popped before any element in the newer
+// generation. New elements are always pushed to the current (newest)
+// generation.
+//
+// We could also say that GenStack behaves as a stack in case of a single
+// generation, but it behaves as a queue of individual generation stacks.
+type GenStack[T any] struct {
+	// We can represent arbitrary number of generations using 2 stacks. The
+	// new stack stores all new pushes and the old stack serves all reads.
+	// Old stack can represent multiple generations. If old == new, then all
+	// elements pushed in previous (not current) generations have already
+	// been popped.
+
+	old *stack[T]
+	new *stack[T]
+}
+
+// NewGenStack creates a new empty GenStack.
+func NewGenStack[T any]() *GenStack[T] {
+	s := &stack[T]{}
+	return &GenStack[T]{
+		old: s,
+		new: s,
+	}
+}
+
+func (s *GenStack[T]) Pop() (T, bool) {
+	// Pushes always append to the new stack, so if the old once becomes
+	// empty, it will remail empty forever.
+	if s.old.len() == 0 && s.old != s.new {
+		s.old = s.new
+	}
+
+	if s.old.len() == 0 {
+		var zero T
+		return zero, false
+	}
+
+	return s.old.pop(), true
+}
+
+// Push pushes a new element at the top of the stack.
+func (s *GenStack[T]) Push(v T) { s.new.push(v) }
+
+// NextGen starts a new stack generation.
+func (s *GenStack[T]) NextGen() {
+	if s.old == s.new {
+		s.new = &stack[T]{}
+		return
+	}
+
+	// We need to pop from the old stack to the top of the new stack. Let's
+	// have an example:
+	//
+	//   Old: <bottom> 4 3 2 1
+	//   New: <bottom> 8 7 6 5
+	//   PopOrder: 1 2 3 4 5 6 7 8
+	//
+	//
+	// To preserve pop order, we have to take all elements from the old
+	// stack and push them to the top of new stack:
+	//
+	//   New: 8 7 6 5 4 3 2 1
+	//
+	s.new.push(s.old.takeAll()...)
+
+	// We have the old stack allocated and empty, so why not to reuse it as
+	// new new stack.
+	s.old, s.new = s.new, s.old
+}
+
+// Len returns number of elements in the stack.
+func (s *GenStack[T]) Len() int {
+	l := s.old.len()
+	if s.old != s.new {
+		l += s.new.len()
+	}
+
+	return l
+}
diff --git a/vendor/github.com/jackc/puddle/v2/internal/genstack/stack.go b/vendor/github.com/jackc/puddle/v2/internal/genstack/stack.go
new file mode 100644
index 000000000..dbced0c72
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/internal/genstack/stack.go
@@ -0,0 +1,39 @@
+package genstack
+
+// stack is a wrapper around an array implementing a stack.
+//
+// We cannot use slice to represent the stack because append might change the
+// pointer value of the slice. That would be an issue in GenStack
+// implementation.
+type stack[T any] struct {
+	arr []T
+}
+
+// push pushes a new element at the top of a stack.
+func (s *stack[T]) push(vs ...T) { s.arr = append(s.arr, vs...) }
+
+// pop pops the stack top-most element.
+//
+// If stack length is zero, this method panics.
+func (s *stack[T]) pop() T {
+	idx := s.len() - 1
+	val := s.arr[idx]
+
+	// Avoid memory leak
+	var zero T
+	s.arr[idx] = zero
+
+	s.arr = s.arr[:idx]
+	return val
+}
+
+// takeAll returns all elements in the stack in order as they are stored - i.e.
+// the top-most stack element is the last one.
+func (s *stack[T]) takeAll() []T {
+	arr := s.arr
+	s.arr = nil
+	return arr
+}
+
+// len returns number of elements in the stack.
+func (s *stack[T]) len() int { return len(s.arr) }
diff --git a/vendor/github.com/jackc/puddle/v2/log.go b/vendor/github.com/jackc/puddle/v2/log.go
new file mode 100644
index 000000000..b21b94630
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/log.go
@@ -0,0 +1,32 @@
+package puddle
+
+import "unsafe"
+
+type ints interface {
+	int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
+}
+
+// log2Int returns log2 of an integer. This function panics if val < 0. For val
+// == 0, returns 0.
+func log2Int[T ints](val T) uint8 {
+	if val <= 0 {
+		panic("log2 of non-positive number does not exist")
+	}
+
+	return log2IntRange(val, 0, uint8(8*unsafe.Sizeof(val)))
+}
+
+func log2IntRange[T ints](val T, begin, end uint8) uint8 {
+	length := end - begin
+	if length == 1 {
+		return begin
+	}
+
+	delim := begin + length/2
+	mask := T(1) << delim
+	if mask > val {
+		return log2IntRange(val, begin, delim)
+	} else {
+		return log2IntRange(val, delim, end)
+	}
+}
diff --git a/vendor/github.com/jackc/puddle/v2/nanotime.go b/vendor/github.com/jackc/puddle/v2/nanotime.go
new file mode 100644
index 000000000..8a5351a0d
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/nanotime.go
@@ -0,0 +1,16 @@
+package puddle
+
+import "time"
+
+// nanotime returns the time in nanoseconds since process start.
+//
+// This approach, described at
+// https://github.com/golang/go/issues/61765#issuecomment-1672090302,
+// is fast, monotonic, and portable, and avoids the previous
+// dependence on runtime.nanotime using the (unsafe) linkname hack.
+// In particular, time.Since does less work than time.Now.
+func nanotime() int64 {
+	return time.Since(globalStart).Nanoseconds()
+}
+
+var globalStart = time.Now()
diff --git a/vendor/github.com/jackc/puddle/v2/pool.go b/vendor/github.com/jackc/puddle/v2/pool.go
new file mode 100644
index 000000000..c411d2f6e
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/pool.go
@@ -0,0 +1,710 @@
+package puddle
+
+import (
+	"context"
+	"errors"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/jackc/puddle/v2/internal/genstack"
+	"golang.org/x/sync/semaphore"
+)
+
+const (
+	resourceStatusConstructing = 0
+	resourceStatusIdle         = iota
+	resourceStatusAcquired     = iota
+	resourceStatusHijacked     = iota
+)
+
+// ErrClosedPool occurs on an attempt to acquire a connection from a closed pool
+// or a pool that is closed while the acquire is waiting.
+var ErrClosedPool = errors.New("closed pool")
+
+// ErrNotAvailable occurs on an attempt to acquire a resource from a pool
+// that is at maximum capacity and has no available resources.
+var ErrNotAvailable = errors.New("resource not available")
+
+// Constructor is a function called by the pool to construct a resource.
+type Constructor[T any] func(ctx context.Context) (res T, err error)
+
+// Destructor is a function called by the pool to destroy a resource.
+type Destructor[T any] func(res T)
+
+// Resource is the resource handle returned by acquiring from the pool.
+type Resource[T any] struct {
+	value          T
+	pool           *Pool[T]
+	creationTime   time.Time
+	lastUsedNano   int64
+	poolResetCount int
+	status         byte
+}
+
+// Value returns the resource value.
+func (res *Resource[T]) Value() T {
+	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
+		panic("tried to access resource that is not acquired or hijacked")
+	}
+	return res.value
+}
+
+// Release returns the resource to the pool. res must not be subsequently used.
+func (res *Resource[T]) Release() {
+	if res.status != resourceStatusAcquired {
+		panic("tried to release resource that is not acquired")
+	}
+	res.pool.releaseAcquiredResource(res, nanotime())
+}
+
+// ReleaseUnused returns the resource to the pool without updating when it was last used used. i.e. LastUsedNanotime
+// will not change. res must not be subsequently used.
+func (res *Resource[T]) ReleaseUnused() {
+	if res.status != resourceStatusAcquired {
+		panic("tried to release resource that is not acquired")
+	}
+	res.pool.releaseAcquiredResource(res, res.lastUsedNano)
+}
+
+// Destroy returns the resource to the pool for destruction. res must not be
+// subsequently used.
+func (res *Resource[T]) Destroy() {
+	if res.status != resourceStatusAcquired {
+		panic("tried to destroy resource that is not acquired")
+	}
+	go res.pool.destroyAcquiredResource(res)
+}
+
+// Hijack assumes ownership of the resource from the pool. Caller is responsible
+// for cleanup of resource value.
+func (res *Resource[T]) Hijack() {
+	if res.status != resourceStatusAcquired {
+		panic("tried to hijack resource that is not acquired")
+	}
+	res.pool.hijackAcquiredResource(res)
+}
+
+// CreationTime returns when the resource was created by the pool.
+func (res *Resource[T]) CreationTime() time.Time {
+	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
+		panic("tried to access resource that is not acquired or hijacked")
+	}
+	return res.creationTime
+}
+
+// LastUsedNanotime returns when Release was last called on the resource measured in nanoseconds from an arbitrary time
+// (a monotonic time). Returns creation time if Release has never been called. This is only useful to compare with
+// other calls to LastUsedNanotime. In almost all cases, IdleDuration should be used instead.
+func (res *Resource[T]) LastUsedNanotime() int64 {
+	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
+		panic("tried to access resource that is not acquired or hijacked")
+	}
+
+	return res.lastUsedNano
+}
+
+// IdleDuration returns the duration since Release was last called on the resource. This is equivalent to subtracting
+// LastUsedNanotime to the current nanotime.
+func (res *Resource[T]) IdleDuration() time.Duration {
+	if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
+		panic("tried to access resource that is not acquired or hijacked")
+	}
+
+	return time.Duration(nanotime() - res.lastUsedNano)
+}
+
+// Pool is a concurrency-safe resource pool.
+type Pool[T any] struct {
+	// mux is the pool internal lock. Any modification of shared state of
+	// the pool (but Acquires of acquireSem) must be performed only by
+	// holder of the lock. Long running operations are not allowed when mux
+	// is held.
+	mux sync.Mutex
+	// acquireSem provides an allowance to acquire a resource.
+	//
+	// Releases are allowed only when caller holds mux. Acquires have to
+	// happen before mux is locked (doesn't apply to semaphore.TryAcquire in
+	// AcquireAllIdle).
+	acquireSem *semaphore.Weighted
+	destructWG sync.WaitGroup
+
+	allResources  resList[T]
+	idleResources *genstack.GenStack[*Resource[T]]
+
+	constructor Constructor[T]
+	destructor  Destructor[T]
+	maxSize     int32
+
+	acquireCount         int64
+	acquireDuration      time.Duration
+	emptyAcquireCount    int64
+	emptyAcquireWaitTime time.Duration
+	canceledAcquireCount atomic.Int64
+
+	resetCount int
+
+	baseAcquireCtx       context.Context
+	cancelBaseAcquireCtx context.CancelFunc
+	closed               bool
+}
+
+type Config[T any] struct {
+	Constructor Constructor[T]
+	Destructor  Destructor[T]
+	MaxSize     int32
+}
+
+// NewPool creates a new pool. Returns an error iff MaxSize is less than 1.
+func NewPool[T any](config *Config[T]) (*Pool[T], error) {
+	if config.MaxSize < 1 {
+		return nil, errors.New("MaxSize must be >= 1")
+	}
+
+	baseAcquireCtx, cancelBaseAcquireCtx := context.WithCancel(context.Background())
+
+	return &Pool[T]{
+		acquireSem:           semaphore.NewWeighted(int64(config.MaxSize)),
+		idleResources:        genstack.NewGenStack[*Resource[T]](),
+		maxSize:              config.MaxSize,
+		constructor:          config.Constructor,
+		destructor:           config.Destructor,
+		baseAcquireCtx:       baseAcquireCtx,
+		cancelBaseAcquireCtx: cancelBaseAcquireCtx,
+	}, nil
+}
+
+// Close destroys all resources in the pool and rejects future Acquire calls.
+// Blocks until all resources are returned to pool and destroyed.
+func (p *Pool[T]) Close() {
+	defer p.destructWG.Wait()
+
+	p.mux.Lock()
+	defer p.mux.Unlock()
+
+	if p.closed {
+		return
+	}
+	p.closed = true
+	p.cancelBaseAcquireCtx()
+
+	for res, ok := p.idleResources.Pop(); ok; res, ok = p.idleResources.Pop() {
+		p.allResources.remove(res)
+		go p.destructResourceValue(res.value)
+	}
+}
+
+// Stat is a snapshot of Pool statistics.
+type Stat struct {
+	constructingResources int32
+	acquiredResources     int32
+	idleResources         int32
+	maxResources          int32
+	acquireCount          int64
+	acquireDuration       time.Duration
+	emptyAcquireCount     int64
+	emptyAcquireWaitTime  time.Duration
+	canceledAcquireCount  int64
+}
+
+// TotalResources returns the total number of resources currently in the pool.
+// The value is the sum of ConstructingResources, AcquiredResources, and
+// IdleResources.
+func (s *Stat) TotalResources() int32 {
+	return s.constructingResources + s.acquiredResources + s.idleResources
+}
+
+// ConstructingResources returns the number of resources with construction in progress in
+// the pool.
+func (s *Stat) ConstructingResources() int32 {
+	return s.constructingResources
+}
+
+// AcquiredResources returns the number of currently acquired resources in the pool.
+func (s *Stat) AcquiredResources() int32 {
+	return s.acquiredResources
+}
+
+// IdleResources returns the number of currently idle resources in the pool.
+func (s *Stat) IdleResources() int32 {
+	return s.idleResources
+}
+
+// MaxResources returns the maximum size of the pool.
+func (s *Stat) MaxResources() int32 {
+	return s.maxResources
+}
+
+// AcquireCount returns the cumulative count of successful acquires from the pool.
+func (s *Stat) AcquireCount() int64 {
+	return s.acquireCount
+}
+
+// AcquireDuration returns the total duration of all successful acquires from
+// the pool.
+func (s *Stat) AcquireDuration() time.Duration {
+	return s.acquireDuration
+}
+
+// EmptyAcquireCount returns the cumulative count of successful acquires from the pool
+// that waited for a resource to be released or constructed because the pool was
+// empty.
+func (s *Stat) EmptyAcquireCount() int64 {
+	return s.emptyAcquireCount
+}
+
+// EmptyAcquireWaitTime returns the cumulative time waited for successful acquires
+// from the pool for a resource to be released or constructed because the pool was
+// empty.
+func (s *Stat) EmptyAcquireWaitTime() time.Duration {
+	return s.emptyAcquireWaitTime
+}
+
+// CanceledAcquireCount returns the cumulative count of acquires from the pool
+// that were canceled by a context.
+func (s *Stat) CanceledAcquireCount() int64 {
+	return s.canceledAcquireCount
+}
+
+// Stat returns the current pool statistics.
+func (p *Pool[T]) Stat() *Stat {
+	p.mux.Lock()
+	defer p.mux.Unlock()
+
+	s := &Stat{
+		maxResources:         p.maxSize,
+		acquireCount:         p.acquireCount,
+		emptyAcquireCount:    p.emptyAcquireCount,
+		emptyAcquireWaitTime: p.emptyAcquireWaitTime,
+		canceledAcquireCount: p.canceledAcquireCount.Load(),
+		acquireDuration:      p.acquireDuration,
+	}
+
+	for _, res := range p.allResources {
+		switch res.status {
+		case resourceStatusConstructing:
+			s.constructingResources += 1
+		case resourceStatusIdle:
+			s.idleResources += 1
+		case resourceStatusAcquired:
+			s.acquiredResources += 1
+		}
+	}
+
+	return s
+}
+
+// tryAcquireIdleResource checks if there is any idle resource. If there is
+// some, this method removes it from idle list and returns it. If the idle pool
+// is empty, this method returns nil and doesn't modify the idleResources slice.
+//
+// WARNING: Caller of this method must hold the pool mutex!
+func (p *Pool[T]) tryAcquireIdleResource() *Resource[T] {
+	res, ok := p.idleResources.Pop()
+	if !ok {
+		return nil
+	}
+
+	res.status = resourceStatusAcquired
+	return res
+}
+
+// createNewResource creates a new resource and inserts it into list of pool
+// resources.
+//
+// WARNING: Caller of this method must hold the pool mutex!
+func (p *Pool[T]) createNewResource() *Resource[T] {
+	res := &Resource[T]{
+		pool:           p,
+		creationTime:   time.Now(),
+		lastUsedNano:   nanotime(),
+		poolResetCount: p.resetCount,
+		status:         resourceStatusConstructing,
+	}
+
+	p.allResources.append(res)
+	p.destructWG.Add(1)
+
+	return res
+}
+
+// Acquire gets a resource from the pool. If no resources are available and the pool is not at maximum capacity it will
+// create a new resource. If the pool is at maximum capacity it will block until a resource is available. ctx can be
+// used to cancel the Acquire.
+//
+// If Acquire creates a new resource the resource constructor function will receive a context that delegates Value() to
+// ctx. Canceling ctx will cause Acquire to return immediately but it will not cancel the resource creation. This avoids
+// the problem of it being impossible to create resources when the time to create a resource is greater than any one
+// caller of Acquire is willing to wait.
+func (p *Pool[T]) Acquire(ctx context.Context) (_ *Resource[T], err error) {
+	select {
+	case <-ctx.Done():
+		p.canceledAcquireCount.Add(1)
+		return nil, ctx.Err()
+	default:
+	}
+
+	return p.acquire(ctx)
+}
+
+// acquire is a continuation of Acquire function that doesn't check context
+// validity.
+//
+// This function exists solely only for benchmarking purposes.
+func (p *Pool[T]) acquire(ctx context.Context) (*Resource[T], error) {
+	startNano := nanotime()
+
+	var waitedForLock bool
+	if !p.acquireSem.TryAcquire(1) {
+		waitedForLock = true
+		err := p.acquireSem.Acquire(ctx, 1)
+		if err != nil {
+			p.canceledAcquireCount.Add(1)
+			return nil, err
+		}
+	}
+
+	p.mux.Lock()
+	if p.closed {
+		p.acquireSem.Release(1)
+		p.mux.Unlock()
+		return nil, ErrClosedPool
+	}
+
+	// If a resource is available in the pool.
+	if res := p.tryAcquireIdleResource(); res != nil {
+		waitTime := time.Duration(nanotime() - startNano)
+		if waitedForLock {
+			p.emptyAcquireCount += 1
+			p.emptyAcquireWaitTime += waitTime
+		}
+		p.acquireCount += 1
+		p.acquireDuration += waitTime
+		p.mux.Unlock()
+		return res, nil
+	}
+
+	if len(p.allResources) >= int(p.maxSize) {
+		// Unreachable code.
+		panic("bug: semaphore allowed more acquires than pool allows")
+	}
+
+	// The resource is not idle, but there is enough space to create one.
+	res := p.createNewResource()
+	p.mux.Unlock()
+
+	res, err := p.initResourceValue(ctx, res)
+	if err != nil {
+		return nil, err
+	}
+
+	p.mux.Lock()
+	defer p.mux.Unlock()
+
+	p.emptyAcquireCount += 1
+	p.acquireCount += 1
+	waitTime := time.Duration(nanotime() - startNano)
+	p.acquireDuration += waitTime
+	p.emptyAcquireWaitTime += waitTime
+
+	return res, nil
+}
+
+func (p *Pool[T]) initResourceValue(ctx context.Context, res *Resource[T]) (*Resource[T], error) {
+	// Create the resource in a goroutine to immediately return from Acquire
+	// if ctx is canceled without also canceling the constructor.
+	//
+	// See:
+	// - https://github.com/jackc/pgx/issues/1287
+	// - https://github.com/jackc/pgx/issues/1259
+	constructErrChan := make(chan error)
+	go func() {
+		constructorCtx := newValueCancelCtx(ctx, p.baseAcquireCtx)
+		value, err := p.constructor(constructorCtx)
+		if err != nil {
+			p.mux.Lock()
+			p.allResources.remove(res)
+			p.destructWG.Done()
+
+			// The resource won't be acquired because its
+			// construction failed. We have to allow someone else to
+			// take that resouce.
+			p.acquireSem.Release(1)
+			p.mux.Unlock()
+
+			select {
+			case constructErrChan <- err:
+			case <-ctx.Done():
+				// The caller is cancelled, so no-one awaits the
+				// error. This branch avoid goroutine leak.
+			}
+			return
+		}
+
+		// The resource is already in p.allResources where it might be read. So we need to acquire the lock to update its
+		// status.
+		p.mux.Lock()
+		res.value = value
+		res.status = resourceStatusAcquired
+		p.mux.Unlock()
+
+		// This select works because the channel is unbuffered.
+		select {
+		case constructErrChan <- nil:
+		case <-ctx.Done():
+			p.releaseAcquiredResource(res, res.lastUsedNano)
+		}
+	}()
+
+	select {
+	case <-ctx.Done():
+		p.canceledAcquireCount.Add(1)
+		return nil, ctx.Err()
+	case err := <-constructErrChan:
+		if err != nil {
+			return nil, err
+		}
+		return res, nil
+	}
+}
+
+// TryAcquire gets a resource from the pool if one is immediately available. If not, it returns ErrNotAvailable. If no
+// resources are available but the pool has room to grow, a resource will be created in the background. ctx is only
+// used to cancel the background creation.
+func (p *Pool[T]) TryAcquire(ctx context.Context) (*Resource[T], error) {
+	if !p.acquireSem.TryAcquire(1) {
+		return nil, ErrNotAvailable
+	}
+
+	p.mux.Lock()
+	defer p.mux.Unlock()
+
+	if p.closed {
+		p.acquireSem.Release(1)
+		return nil, ErrClosedPool
+	}
+
+	// If a resource is available now
+	if res := p.tryAcquireIdleResource(); res != nil {
+		p.acquireCount += 1
+		return res, nil
+	}
+
+	if len(p.allResources) >= int(p.maxSize) {
+		// Unreachable code.
+		panic("bug: semaphore allowed more acquires than pool allows")
+	}
+
+	res := p.createNewResource()
+	go func() {
+		value, err := p.constructor(ctx)
+
+		p.mux.Lock()
+		defer p.mux.Unlock()
+		// We have to create the resource and only then release the
+		// semaphore - For the time being there is no resource that
+		// someone could acquire.
+		defer p.acquireSem.Release(1)
+
+		if err != nil {
+			p.allResources.remove(res)
+			p.destructWG.Done()
+			return
+		}
+
+		res.value = value
+		res.status = resourceStatusIdle
+		p.idleResources.Push(res)
+	}()
+
+	return nil, ErrNotAvailable
+}
+
+// acquireSemAll tries to acquire num free tokens from sem. This function is
+// guaranteed to acquire at least the lowest number of tokens that has been
+// available in the semaphore during runtime of this function.
+//
+// For the time being, semaphore doesn't allow to acquire all tokens atomically
+// (see https://github.com/golang/sync/pull/19). We simulate this by trying all
+// powers of 2 that are less or equal to num.
+//
+// For example, let's immagine we have 19 free tokens in the semaphore which in
+// total has 24 tokens (i.e. the maxSize of the pool is 24 resources). Then if
+// num is 24, the log2Uint(24) is 4 and we try to acquire 16, 8, 4, 2 and 1
+// tokens. Out of those, the acquire of 16, 2 and 1 tokens will succeed.
+//
+// Naturally, Acquires and Releases of the semaphore might take place
+// concurrently. For this reason, it's not guaranteed that absolutely all free
+// tokens in the semaphore will be acquired. But it's guaranteed that at least
+// the minimal number of tokens that has been present over the whole process
+// will be acquired. This is sufficient for the use-case we have in this
+// package.
+//
+// TODO: Replace this with acquireSem.TryAcquireAll() if it gets to
+// upstream. https://github.com/golang/sync/pull/19
+func acquireSemAll(sem *semaphore.Weighted, num int) int {
+	if sem.TryAcquire(int64(num)) {
+		return num
+	}
+
+	var acquired int
+	for i := int(log2Int(num)); i >= 0; i-- {
+		val := 1 << i
+		if sem.TryAcquire(int64(val)) {
+			acquired += val
+		}
+	}
+
+	return acquired
+}
+
+// AcquireAllIdle acquires all currently idle resources. Its intended use is for
+// health check and keep-alive functionality. It does not update pool
+// statistics.
+func (p *Pool[T]) AcquireAllIdle() []*Resource[T] {
+	p.mux.Lock()
+	defer p.mux.Unlock()
+
+	if p.closed {
+		return nil
+	}
+
+	numIdle := p.idleResources.Len()
+	if numIdle == 0 {
+		return nil
+	}
+
+	// In acquireSemAll we use only TryAcquire and not Acquire. Because
+	// TryAcquire cannot block, the fact that we hold mutex locked and try
+	// to acquire semaphore cannot result in dead-lock.
+	//
+	// Because the mutex is locked, no parallel Release can run. This
+	// implies that the number of tokens can only decrease because some
+	// Acquire/TryAcquire call can consume the semaphore token. Consequently
+	// acquired is always less or equal to numIdle. Moreover if acquired <
+	// numIdle, then there are some parallel Acquire/TryAcquire calls that
+	// will take the remaining idle connections.
+	acquired := acquireSemAll(p.acquireSem, numIdle)
+
+	idle := make([]*Resource[T], acquired)
+	for i := range idle {
+		res, _ := p.idleResources.Pop()
+		res.status = resourceStatusAcquired
+		idle[i] = res
+	}
+
+	// We have to bump the generation to ensure that Acquire/TryAcquire
+	// calls running in parallel (those which caused acquired < numIdle)
+	// will consume old connections and not freshly released connections
+	// instead.
+	p.idleResources.NextGen()
+
+	return idle
+}
+
+// CreateResource constructs a new resource without acquiring it. It goes straight in the IdlePool. If the pool is full
+// it returns an error. It can be useful to maintain warm resources under little load.
+func (p *Pool[T]) CreateResource(ctx context.Context) error {
+	if !p.acquireSem.TryAcquire(1) {
+		return ErrNotAvailable
+	}
+
+	p.mux.Lock()
+	if p.closed {
+		p.acquireSem.Release(1)
+		p.mux.Unlock()
+		return ErrClosedPool
+	}
+
+	if len(p.allResources) >= int(p.maxSize) {
+		p.acquireSem.Release(1)
+		p.mux.Unlock()
+		return ErrNotAvailable
+	}
+
+	res := p.createNewResource()
+	p.mux.Unlock()
+
+	value, err := p.constructor(ctx)
+	p.mux.Lock()
+	defer p.mux.Unlock()
+	defer p.acquireSem.Release(1)
+	if err != nil {
+		p.allResources.remove(res)
+		p.destructWG.Done()
+		return err
+	}
+
+	res.value = value
+	res.status = resourceStatusIdle
+
+	// If closed while constructing resource then destroy it and return an error
+	if p.closed {
+		go p.destructResourceValue(res.value)
+		return ErrClosedPool
+	}
+
+	p.idleResources.Push(res)
+
+	return nil
+}
+
+// Reset destroys all resources, but leaves the pool open. It is intended for use when an error is detected that would
+// disrupt all resources (such as a network interruption or a server state change).
+//
+// It is safe to reset a pool while resources are checked out. Those resources will be destroyed when they are returned
+// to the pool.
+func (p *Pool[T]) Reset() {
+	p.mux.Lock()
+	defer p.mux.Unlock()
+
+	p.resetCount++
+
+	for res, ok := p.idleResources.Pop(); ok; res, ok = p.idleResources.Pop() {
+		p.allResources.remove(res)
+		go p.destructResourceValue(res.value)
+	}
+}
+
+// releaseAcquiredResource returns res to the the pool.
+func (p *Pool[T]) releaseAcquiredResource(res *Resource[T], lastUsedNano int64) {
+	p.mux.Lock()
+	defer p.mux.Unlock()
+	defer p.acquireSem.Release(1)
+
+	if p.closed || res.poolResetCount != p.resetCount {
+		p.allResources.remove(res)
+		go p.destructResourceValue(res.value)
+	} else {
+		res.lastUsedNano = lastUsedNano
+		res.status = resourceStatusIdle
+		p.idleResources.Push(res)
+	}
+}
+
+// Remove removes res from the pool and closes it. If res is not part of the
+// pool Remove will panic.
+func (p *Pool[T]) destroyAcquiredResource(res *Resource[T]) {
+	p.destructResourceValue(res.value)
+
+	p.mux.Lock()
+	defer p.mux.Unlock()
+	defer p.acquireSem.Release(1)
+
+	p.allResources.remove(res)
+}
+
+func (p *Pool[T]) hijackAcquiredResource(res *Resource[T]) {
+	p.mux.Lock()
+	defer p.mux.Unlock()
+	defer p.acquireSem.Release(1)
+
+	p.allResources.remove(res)
+	res.status = resourceStatusHijacked
+	p.destructWG.Done() // not responsible for destructing hijacked resources
+}
+
+func (p *Pool[T]) destructResourceValue(value T) {
+	p.destructor(value)
+	p.destructWG.Done()
+}
diff --git a/vendor/github.com/jackc/puddle/v2/resource_list.go b/vendor/github.com/jackc/puddle/v2/resource_list.go
new file mode 100644
index 000000000..b2430959b
--- /dev/null
+++ b/vendor/github.com/jackc/puddle/v2/resource_list.go
@@ -0,0 +1,28 @@
+package puddle
+
+type resList[T any] []*Resource[T]
+
+func (l *resList[T]) append(val *Resource[T]) { *l = append(*l, val) }
+
+func (l *resList[T]) popBack() *Resource[T] {
+	idx := len(*l) - 1
+	val := (*l)[idx]
+	(*l)[idx] = nil // Avoid memory leak
+	*l = (*l)[:idx]
+
+	return val
+}
+
+func (l *resList[T]) remove(val *Resource[T]) {
+	for i, elem := range *l {
+		if elem == val {
+			lastIdx := len(*l) - 1
+			(*l)[i] = (*l)[lastIdx]
+			(*l)[lastIdx] = nil // Avoid memory leak
+			(*l) = (*l)[:lastIdx]
+			return
+		}
+	}
+
+	panic("BUG: removeResource could not find res in slice")
+}
diff --git a/vendor/github.com/lufia/plan9stats/.gitignore b/vendor/github.com/lufia/plan9stats/.gitignore
new file mode 100644
index 000000000..f1c181ec9
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/.gitignore
@@ -0,0 +1,12 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
diff --git a/vendor/github.com/lufia/plan9stats/LICENSE b/vendor/github.com/lufia/plan9stats/LICENSE
new file mode 100644
index 000000000..a6d47e807
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2019, KADOTA, Kyohei
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/lufia/plan9stats/README.md b/vendor/github.com/lufia/plan9stats/README.md
new file mode 100644
index 000000000..a21700c0c
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/README.md
@@ -0,0 +1,2 @@
+# plan9stats
+A module for retrieving statistics of Plan 9
diff --git a/vendor/github.com/lufia/plan9stats/cpu.go b/vendor/github.com/lufia/plan9stats/cpu.go
new file mode 100644
index 000000000..a101b9119
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/cpu.go
@@ -0,0 +1,288 @@
+package stats
+
+import (
+	"bufio"
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// CPUType represents /dev/cputype.
+type CPUType struct {
+	Name  string
+	Clock int // clock rate in MHz
+}
+
+func ReadCPUType(ctx context.Context, opts ...Option) (*CPUType, error) {
+	cfg := newConfig(opts...)
+	var c CPUType
+	if err := readCPUType(cfg.rootdir, &c); err != nil {
+		return nil, err
+	}
+	return &c, nil
+}
+
+type SysStats struct {
+	ID           int
+	NumCtxSwitch int64
+	NumInterrupt int64
+	NumSyscall   int64
+	NumFault     int64
+	NumTLBFault  int64
+	NumTLBPurge  int64
+	LoadAvg      int64 // in units of milli-CPUs and is decayed over time
+	Idle         int   // percentage
+	Interrupt    int   // percentage
+}
+
+// ReadSysStats reads system statistics from /dev/sysstat.
+func ReadSysStats(ctx context.Context, opts ...Option) ([]*SysStats, error) {
+	cfg := newConfig(opts...)
+	file := filepath.Join(cfg.rootdir, "/dev/sysstat")
+	f, err := os.Open(file)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	scanner := bufio.NewScanner(f)
+	var stats []*SysStats
+	for scanner.Scan() {
+		a := strings.Fields(scanner.Text())
+		if len(a) != 10 {
+			continue
+		}
+		var (
+			p    intParser
+			stat SysStats
+		)
+		stat.ID = p.ParseInt(a[0], 10)
+		stat.NumCtxSwitch = p.ParseInt64(a[1], 10)
+		stat.NumInterrupt = p.ParseInt64(a[2], 10)
+		stat.NumSyscall = p.ParseInt64(a[3], 10)
+		stat.NumFault = p.ParseInt64(a[4], 10)
+		stat.NumTLBFault = p.ParseInt64(a[5], 10)
+		stat.NumTLBPurge = p.ParseInt64(a[6], 10)
+		stat.LoadAvg = p.ParseInt64(a[7], 10)
+		stat.Idle = p.ParseInt(a[8], 10)
+		stat.Interrupt = p.ParseInt(a[9], 10)
+		if err := p.Err(); err != nil {
+			return nil, err
+		}
+		stats = append(stats, &stat)
+	}
+	if err := scanner.Err(); err != nil {
+		return nil, err
+	}
+	return stats, nil
+}
+
+func readCPUType(rootdir string, c *CPUType) error {
+	file := filepath.Join(rootdir, "/dev/cputype")
+	b, err := ioutil.ReadFile(file)
+	if err != nil {
+		return err
+	}
+	b = bytes.TrimSpace(b)
+	i := bytes.LastIndexByte(b, ' ')
+	if i < 0 {
+		return fmt.Errorf("%s: invalid format", file)
+	}
+	clock, err := strconv.Atoi(string(b[i+1:]))
+	if err != nil {
+		return err
+	}
+	c.Name = string(b[:i])
+	c.Clock = clock
+	return nil
+}
+
+// Time represents /dev/time.
+type Time struct {
+	Unix     time.Duration
+	UnixNano time.Duration
+	Ticks    int64 // clock ticks
+	Freq     int64 //cloc frequency
+}
+
+// Uptime returns uptime.
+func (t *Time) Uptime() time.Duration {
+	v := float64(t.Ticks) / float64(t.Freq)
+	return time.Duration(v*1000_000_000) * time.Nanosecond
+}
+
+func ReadTime(ctx context.Context, opts ...Option) (*Time, error) {
+	cfg := newConfig(opts...)
+	file := filepath.Join(cfg.rootdir, "/dev/time")
+	var t Time
+	if err := readTime(file, &t); err != nil {
+		return nil, err
+	}
+	return &t, nil
+}
+
+// ProcStatus represents a /proc/n/status.
+type ProcStatus struct {
+	Name         string
+	User         string
+	State        string
+	Times        CPUTime
+	MemUsed      int64  // in units of 1024 bytes
+	BasePriority uint32 // 0(low) to 19(high)
+	Priority     uint32 // 0(low) to 19(high)
+}
+
+// CPUTime represents /dev/cputime or a part of /proc/n/status.
+type CPUTime struct {
+	User      time.Duration // the time in user mode (millisecconds)
+	Sys       time.Duration
+	Real      time.Duration
+	ChildUser time.Duration // exited children and descendants time in user mode
+	ChildSys  time.Duration
+	ChildReal time.Duration
+}
+
+// CPUStats emulates Linux's /proc/stat.
+type CPUStats struct {
+	User time.Duration
+	Sys  time.Duration
+	Idle time.Duration
+}
+
+func ReadCPUStats(ctx context.Context, opts ...Option) (*CPUStats, error) {
+	cfg := newConfig(opts...)
+	a, err := ReadSysStats(ctx, opts...)
+	if err != nil {
+		return nil, err
+	}
+
+	dir := filepath.Join(cfg.rootdir, "/proc")
+	d, err := os.Open(dir)
+	if err != nil {
+		return nil, err
+	}
+	defer d.Close()
+
+	names, err := d.Readdirnames(0)
+	if err != nil {
+		return nil, err
+	}
+	var up uint32parser
+	pids := make([]uint32, len(names))
+	for i, s := range names {
+		pids[i] = up.Parse(s)
+	}
+	if up.err != nil {
+		return nil, err
+	}
+	sort.Slice(pids, func(i, j int) bool {
+		return pids[i] < pids[j]
+	})
+
+	var stat CPUStats
+	for _, pid := range pids {
+		s := strconv.FormatUint(uint64(pid), 10)
+		file := filepath.Join(dir, s, "status")
+		var p ProcStatus
+		if err := readProcStatus(file, &p); err != nil {
+			return nil, err
+		}
+		stat.User += p.Times.User
+		stat.Sys += p.Times.Sys
+	}
+
+	var t Time
+	file := filepath.Join(cfg.rootdir, "/dev/time")
+	if err := readTime(file, &t); err != nil {
+		return nil, err
+	}
+	// In multi-processor host, Idle should multiple by number of cores.
+	u := t.Uptime() * time.Duration(len(a))
+	stat.Idle = u - stat.User - stat.Sys
+	return &stat, nil
+}
+
+func readProcStatus(file string, p *ProcStatus) error {
+	b, err := ioutil.ReadFile(file)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
+		return err
+	}
+	fields := strings.Fields(string(b))
+	if len(fields) != 12 {
+		return errors.New("invalid format")
+	}
+	p.Name = string(fields[0])
+	p.User = string(fields[1])
+	p.State = string(fields[2])
+	var up uint32parser
+	p.Times.User = time.Duration(up.Parse(fields[3])) * time.Millisecond
+	p.Times.Sys = time.Duration(up.Parse(fields[4])) * time.Millisecond
+	p.Times.Real = time.Duration(up.Parse(fields[5])) * time.Millisecond
+	p.Times.ChildUser = time.Duration(up.Parse(fields[6])) * time.Millisecond
+	p.Times.ChildSys = time.Duration(up.Parse(fields[7])) * time.Millisecond
+	p.Times.ChildReal = time.Duration(up.Parse(fields[8])) * time.Millisecond
+	p.MemUsed, err = strconv.ParseInt(fields[9], 10, 64)
+	if err != nil {
+		return err
+	}
+	p.BasePriority = up.Parse(fields[10])
+	p.Priority = up.Parse(fields[11])
+	return up.err
+}
+
+func readTime(file string, t *Time) error {
+	b, err := ioutil.ReadFile(file)
+	if err != nil {
+		return err
+	}
+	fields := strings.Fields(string(b))
+	if len(fields) != 4 {
+		return errors.New("invalid format")
+	}
+	n, err := strconv.ParseInt(fields[0], 10, 32)
+	if err != nil {
+		return err
+	}
+	t.Unix = time.Duration(n) * time.Second
+	v, err := strconv.ParseInt(fields[1], 10, 64)
+	if err != nil {
+		return err
+	}
+	t.UnixNano = time.Duration(v) * time.Nanosecond
+	t.Ticks, err = strconv.ParseInt(fields[2], 10, 64)
+	if err != nil {
+		return err
+	}
+	t.Freq, err = strconv.ParseInt(fields[3], 10, 64)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+type uint32parser struct {
+	err error
+}
+
+func (p *uint32parser) Parse(s string) uint32 {
+	if p.err != nil {
+		return 0
+	}
+	n, err := strconv.ParseUint(s, 10, 32)
+	if err != nil {
+		p.err = err
+		return 0
+	}
+	return uint32(n)
+}
diff --git a/vendor/github.com/lufia/plan9stats/doc.go b/vendor/github.com/lufia/plan9stats/doc.go
new file mode 100644
index 000000000..10e398e7a
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/doc.go
@@ -0,0 +1,2 @@
+// Package stats provides statistic utilities for Plan 9.
+package stats
diff --git a/vendor/github.com/lufia/plan9stats/host.go b/vendor/github.com/lufia/plan9stats/host.go
new file mode 100644
index 000000000..957e90348
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/host.go
@@ -0,0 +1,303 @@
+package stats
+
+import (
+	"bufio"
+	"bytes"
+	"context"
+	"fmt"
+	"io/ioutil"
+	"net"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+)
+
+var (
+	delim = []byte{' '}
+)
+
+// Host represents host status.
+type Host struct {
+	Sysname    string
+	Storages   []*Storage
+	Interfaces []*Interface
+}
+
+// MemStats represents the memory statistics.
+type MemStats struct {
+	Total       int64 // total memory in byte
+	PageSize    int64 // a page size in byte
+	KernelPages int64
+	UserPages   Gauge
+	SwapPages   Gauge
+
+	Malloced Gauge // kernel malloced data in byte
+	Graphics Gauge // kernel graphics data in byte
+}
+
+// Gauge is used/available gauge.
+type Gauge struct {
+	Used  int64
+	Avail int64
+}
+
+func (g Gauge) Free() int64 {
+	return g.Avail - g.Used
+}
+
+// ReadMemStats reads memory statistics from /dev/swap.
+func ReadMemStats(ctx context.Context, opts ...Option) (*MemStats, error) {
+	cfg := newConfig(opts...)
+	swap := filepath.Join(cfg.rootdir, "/dev/swap")
+	f, err := os.Open(swap)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	var stat MemStats
+	m := map[string]interface{}{
+		"memory":        &stat.Total,
+		"pagesize":      &stat.PageSize,
+		"kernel":        &stat.KernelPages,
+		"user":          &stat.UserPages,
+		"swap":          &stat.SwapPages,
+		"kernel malloc": &stat.Malloced,
+		"kernel draw":   &stat.Graphics,
+	}
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		fields := bytes.SplitN(scanner.Bytes(), delim, 2)
+		if len(fields) < 2 {
+			continue
+		}
+		switch key := string(fields[1]); key {
+		case "memory", "pagesize", "kernel":
+			v := m[key].(*int64)
+			n, err := strconv.ParseInt(string(fields[0]), 10, 64)
+			if err != nil {
+				return nil, err
+			}
+			*v = n
+		case "user", "swap", "kernel malloc", "kernel draw":
+			v := m[key].(*Gauge)
+			if err := parseGauge(string(fields[0]), v); err != nil {
+				return nil, err
+			}
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		return nil, err
+	}
+	return &stat, nil
+}
+
+func parseGauge(s string, r *Gauge) error {
+	a := strings.SplitN(s, "/", 2)
+	if len(a) != 2 {
+		return fmt.Errorf("can't parse ratio: %s", s)
+	}
+	var p intParser
+	u := p.ParseInt64(a[0], 10)
+	n := p.ParseInt64(a[1], 10)
+	if err := p.Err(); err != nil {
+		return err
+	}
+	r.Used = u
+	r.Avail = n
+	return nil
+}
+
+type Storage struct {
+	Name     string
+	Model    string
+	Capacity int64
+}
+
+type Interface struct {
+	Name string
+	Addr string
+}
+
+const (
+	numEther = 8  // see ether(3)
+	numIpifc = 16 // see ip(3)
+)
+
+// ReadInterfaces reads network interfaces from etherN.
+func ReadInterfaces(ctx context.Context, opts ...Option) ([]*Interface, error) {
+	cfg := newConfig(opts...)
+	var a []*Interface
+	for i := 0; i < numEther; i++ {
+		p, err := readInterface(cfg.rootdir, i)
+		if os.IsNotExist(err) {
+			continue
+		}
+		if err != nil {
+			return nil, err
+		}
+		a = append(a, p)
+	}
+	return a, nil
+}
+
+func readInterface(netroot string, i int) (*Interface, error) {
+	ether := fmt.Sprintf("ether%d", i)
+	dir := filepath.Join(netroot, ether)
+	info, err := os.Stat(dir)
+	if err != nil {
+		return nil, err
+	}
+	if !info.IsDir() {
+		return nil, fmt.Errorf("%s: is not directory", dir)
+	}
+
+	addr, err := ioutil.ReadFile(filepath.Join(dir, "addr"))
+	if err != nil {
+		return nil, err
+	}
+	return &Interface{
+		Name: ether,
+		Addr: string(addr),
+	}, nil
+}
+
+var (
+	netdirs = []string{"/net", "/net.alt"}
+)
+
+// ReadHost reads host status.
+func ReadHost(ctx context.Context, opts ...Option) (*Host, error) {
+	cfg := newConfig(opts...)
+	var h Host
+	name, err := readSysname(cfg.rootdir)
+	if err != nil {
+		return nil, err
+	}
+	h.Sysname = name
+
+	a, err := readStorages(cfg.rootdir)
+	if err != nil {
+		return nil, err
+	}
+	h.Storages = a
+
+	for _, s := range netdirs {
+		netroot := filepath.Join(cfg.rootdir, s)
+		ifaces, err := ReadInterfaces(ctx, WithRootDir(netroot))
+		if err != nil {
+			return nil, err
+		}
+		h.Interfaces = append(h.Interfaces, ifaces...)
+	}
+	return &h, nil
+}
+
+func readSysname(rootdir string) (string, error) {
+	file := filepath.Join(rootdir, "/dev/sysname")
+	b, err := ioutil.ReadFile(file)
+	if err != nil {
+		return "", err
+	}
+	return string(bytes.TrimSpace(b)), nil
+}
+
+func readStorages(rootdir string) ([]*Storage, error) {
+	sdctl := filepath.Join(rootdir, "/dev/sdctl")
+	f, err := os.Open(sdctl)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	var a []*Storage
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		fields := bytes.Split(scanner.Bytes(), delim)
+		if len(fields) == 0 {
+			continue
+		}
+		exp := string(fields[0]) + "*"
+		if !strings.HasPrefix(exp, "sd") {
+			continue
+		}
+		dir := filepath.Join(rootdir, "/dev", exp)
+		m, err := filepath.Glob(dir)
+		if err != nil {
+			return nil, err
+		}
+		for _, dir := range m {
+			s, err := readStorage(dir)
+			if err != nil {
+				return nil, err
+			}
+			a = append(a, s)
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		return nil, err
+	}
+	return a, nil
+}
+
+func readStorage(dir string) (*Storage, error) {
+	ctl := filepath.Join(dir, "ctl")
+	f, err := os.Open(ctl)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	var s Storage
+	s.Name = filepath.Base(dir)
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		line := scanner.Bytes()
+		switch {
+		case bytes.HasPrefix(line, []byte("inquiry")):
+			s.Model = string(bytes.TrimSpace(line[7:]))
+		case bytes.HasPrefix(line, []byte("geometry")):
+			fields := bytes.Split(line, delim)
+			if len(fields) < 3 {
+				continue
+			}
+			var p intParser
+			sec := p.ParseInt64(string(fields[1]), 10)
+			size := p.ParseInt64(string(fields[2]), 10)
+			if err := p.Err(); err != nil {
+				return nil, err
+			}
+			s.Capacity = sec * size
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		return nil, err
+	}
+	return &s, nil
+}
+
+type IPStats struct {
+	ID      int    // number of interface in ipifc dir
+	Device  string // associated physical device
+	MTU     int    // max transfer unit
+	Sendra6 uint8  // on == send router adv
+	Recvra6 uint8  // on == recv router adv
+
+	Pktin  int64 // packets read
+	Pktout int64 // packets written
+	Errin  int64 // read errors
+	Errout int64 // write errors
+}
+
+type Iplifc struct {
+	IP            net.IP
+	Mask          net.IPMask
+	Net           net.IP // ip & mask
+	PerfLifetime  int64  // preferred lifetime
+	ValidLifetime int64  // valid lifetime
+}
+
+type Ipv6rp struct {
+	// TODO(lufia): see ip(2)
+}
diff --git a/vendor/github.com/lufia/plan9stats/int.go b/vendor/github.com/lufia/plan9stats/int.go
new file mode 100644
index 000000000..db133c43e
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/int.go
@@ -0,0 +1,31 @@
+package stats
+
+import (
+	"strconv"
+)
+
+type intParser struct {
+	err error
+}
+
+func (p *intParser) ParseInt(s string, base int) int {
+	if p.err != nil {
+		return 0
+	}
+	var n int64
+	n, p.err = strconv.ParseInt(s, base, 0)
+	return int(n)
+}
+
+func (p *intParser) ParseInt64(s string, base int) int64 {
+	if p.err != nil {
+		return 0
+	}
+	var n int64
+	n, p.err = strconv.ParseInt(s, base, 64)
+	return n
+}
+
+func (p *intParser) Err() error {
+	return p.err
+}
diff --git a/vendor/github.com/lufia/plan9stats/opts.go b/vendor/github.com/lufia/plan9stats/opts.go
new file mode 100644
index 000000000..05b7d036a
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/opts.go
@@ -0,0 +1,21 @@
+package stats
+
+type Config struct {
+	rootdir string
+}
+
+type Option func(*Config)
+
+func newConfig(opts ...Option) *Config {
+	var cfg Config
+	for _, opt := range opts {
+		opt(&cfg)
+	}
+	return &cfg
+}
+
+func WithRootDir(dir string) Option {
+	return func(cfg *Config) {
+		cfg.rootdir = dir
+	}
+}
diff --git a/vendor/github.com/lufia/plan9stats/stats.go b/vendor/github.com/lufia/plan9stats/stats.go
new file mode 100644
index 000000000..d4ecdcfa0
--- /dev/null
+++ b/vendor/github.com/lufia/plan9stats/stats.go
@@ -0,0 +1,88 @@
+package stats
+
+import (
+	"bufio"
+	"context"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+type InterfaceStats struct {
+	PacketsReceived  int64 // in packets
+	Link             int   // link status
+	PacketsSent      int64 // out packets
+	NumCRCErr        int   // input CRC errors
+	NumOverflows     int   // packet overflows
+	NumSoftOverflows int   // software overflow
+	NumFramingErr    int   // framing errors
+	NumBufferingErr  int   // buffering errors
+	NumOutputErr     int   // output errors
+	Promiscuous      int   // number of promiscuous opens
+	Mbps             int   // megabits per sec
+	Addr             string
+}
+
+func ReadInterfaceStats(ctx context.Context, opts ...Option) (*InterfaceStats, error) {
+	cfg := newConfig(opts...)
+	file := filepath.Join(cfg.rootdir, "stats")
+	f, err := os.Open(file)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	var stats InterfaceStats
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		s := strings.TrimSpace(scanner.Text())
+		a := strings.SplitN(s, ":", 2)
+		if len(a) != 2 {
+			continue
+		}
+		var p intParser
+		v := strings.TrimSpace(a[1])
+		switch a[0] {
+		case "in":
+			stats.PacketsReceived = p.ParseInt64(v, 10)
+		case "link":
+			stats.Link = p.ParseInt(v, 10)
+		case "out":
+			stats.PacketsSent = p.ParseInt64(v, 10)
+		case "crc":
+			stats.NumCRCErr = p.ParseInt(v, 10)
+		case "overflows":
+			stats.NumOverflows = p.ParseInt(v, 10)
+		case "soft overflows":
+			stats.NumSoftOverflows = p.ParseInt(v, 10)
+		case "framing errs":
+			stats.NumFramingErr = p.ParseInt(v, 10)
+		case "buffer errs":
+			stats.NumBufferingErr = p.ParseInt(v, 10)
+		case "output errs":
+			stats.NumOutputErr = p.ParseInt(v, 10)
+		case "prom":
+			stats.Promiscuous = p.ParseInt(v, 10)
+		case "mbps":
+			stats.Mbps = p.ParseInt(v, 10)
+		case "addr":
+			stats.Addr = v
+		}
+		if err := p.Err(); err != nil {
+			return nil, err
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		return nil, err
+	}
+	return &stats, nil
+}
+
+type TCPStats struct {
+	MaxConn            int
+	MaxSegment         int
+	ActiveOpens        int
+	PassiveOpens       int
+	EstablishedResets  int
+	CurrentEstablished int
+}
diff --git a/vendor/github.com/magiconair/properties/.gitignore b/vendor/github.com/magiconair/properties/.gitignore
new file mode 100644
index 000000000..e7081ff52
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/.gitignore
@@ -0,0 +1,6 @@
+*.sublime-project
+*.sublime-workspace
+*.un~
+*.swp
+.idea/
+*.iml
diff --git a/vendor/github.com/magiconair/properties/LICENSE.md b/vendor/github.com/magiconair/properties/LICENSE.md
new file mode 100644
index 000000000..79c87e3e6
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/LICENSE.md
@@ -0,0 +1,24 @@
+Copyright (c) 2013-2020, Frank Schroeder
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/magiconair/properties/README.md b/vendor/github.com/magiconair/properties/README.md
new file mode 100644
index 000000000..4872685f4
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/README.md
@@ -0,0 +1,98 @@
+[![](https://img.shields.io/github/tag/magiconair/properties.svg?style=flat-square&label=release)](https://github.com/magiconair/properties/releases)
+[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg?style=flat-square)](https://raw.githubusercontent.com/magiconair/properties/master/LICENSE)
+[![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/magiconair/properties)
+
+# Overview
+
+properties is a Go library for reading and writing properties files.
+
+It supports reading from multiple files or URLs and Spring style recursive
+property expansion of expressions like `${key}` to their corresponding value.
+Value expressions can refer to other keys like in `${key}` or to environment
+variables like in `${USER}`.  Filenames can also contain environment variables
+like in `/home/${USER}/myapp.properties`.
+
+Properties can be decoded into structs, maps, arrays and values through
+struct tags.
+
+Comments and the order of keys are preserved. Comments can be modified
+and can be written to the output.
+
+The properties library supports both ISO-8859-1 and UTF-8 encoded data.
+
+Starting from version 1.3.0 the behavior of the MustXXX() functions is
+configurable by providing a custom `ErrorHandler` function. The default has
+changed from `panic` to `log.Fatal` but this is configurable and custom
+error handling functions can be provided. See the package documentation for
+details.
+
+Read the full documentation on [![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/magiconair/properties)
+
+## Getting Started
+
+```go
+import (
+	"flag"
+	"github.com/magiconair/properties"
+)
+
+func main() {
+	// init from a file
+	p := properties.MustLoadFile("${HOME}/config.properties", properties.UTF8)
+
+	// or multiple files
+	p = properties.MustLoadFiles([]string{
+			"${HOME}/config.properties",
+			"${HOME}/config-${USER}.properties",
+		}, properties.UTF8, true)
+
+	// or from a map
+	p = properties.LoadMap(map[string]string{"key": "value", "abc": "def"})
+
+	// or from a string
+	p = properties.MustLoadString("key=value\nabc=def")
+
+	// or from a URL
+	p = properties.MustLoadURL("http://host/path")
+
+	// or from multiple URLs
+	p = properties.MustLoadURL([]string{
+			"http://host/config",
+			"http://host/config-${USER}",
+		}, true)
+
+	// or from flags
+	p.MustFlag(flag.CommandLine)
+
+	// get values through getters
+	host := p.MustGetString("host")
+	port := p.GetInt("port", 8080)
+
+	// or through Decode
+	type Config struct {
+		Host    string        `properties:"host"`
+		Port    int           `properties:"port,default=9000"`
+		Accept  []string      `properties:"accept,default=image/png;image;gif"`
+		Timeout time.Duration `properties:"timeout,default=5s"`
+	}
+	var cfg Config
+	if err := p.Decode(&cfg); err != nil {
+		log.Fatal(err)
+	}
+}
+
+```
+
+## Installation and Upgrade
+
+```
+$ go get -u github.com/magiconair/properties
+```
+
+## License
+
+2 clause BSD license. See [LICENSE](https://github.com/magiconair/properties/blob/master/LICENSE) file for details.
+
+## ToDo
+
+* Dump contents with passwords and secrets obscured
diff --git a/vendor/github.com/magiconair/properties/decode.go b/vendor/github.com/magiconair/properties/decode.go
new file mode 100644
index 000000000..f5e252f8d
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/decode.go
@@ -0,0 +1,289 @@
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// Decode assigns property values to exported fields of a struct.
+//
+// Decode traverses v recursively and returns an error if a value cannot be
+// converted to the field type or a required value is missing for a field.
+//
+// The following type dependent decodings are used:
+//
+// String, boolean, numeric fields have the value of the property key assigned.
+// The property key name is the name of the field. A different key and a default
+// value can be set in the field's tag. Fields without default value are
+// required. If the value cannot be converted to the field type an error is
+// returned.
+//
+// time.Duration fields have the result of time.ParseDuration() assigned.
+//
+// time.Time fields have the vaule of time.Parse() assigned. The default layout
+// is time.RFC3339 but can be set in the field's tag.
+//
+// Arrays and slices of string, boolean, numeric, time.Duration and time.Time
+// fields have the value interpreted as a comma separated list of values. The
+// individual values are trimmed of whitespace and empty values are ignored. A
+// default value can be provided as a semicolon separated list in the field's
+// tag.
+//
+// Struct fields are decoded recursively using the field name plus "." as
+// prefix. The prefix (without dot) can be overridden in the field's tag.
+// Default values are not supported in the field's tag. Specify them on the
+// fields of the inner struct instead.
+//
+// Map fields must have a key of type string and are decoded recursively by
+// using the field's name plus ".' as prefix and the next element of the key
+// name as map key. The prefix (without dot) can be overridden in the field's
+// tag. Default values are not supported.
+//
+// Examples:
+//
+//	// Field is ignored.
+//	Field int `properties:"-"`
+//
+//	// Field is assigned value of 'Field'.
+//	Field int
+//
+//	// Field is assigned value of 'myName'.
+//	Field int `properties:"myName"`
+//
+//	// Field is assigned value of key 'myName' and has a default
+//	// value 15 if the key does not exist.
+//	Field int `properties:"myName,default=15"`
+//
+//	// Field is assigned value of key 'Field' and has a default
+//	// value 15 if the key does not exist.
+//	Field int `properties:",default=15"`
+//
+//	// Field is assigned value of key 'date' and the date
+//	// is in format 2006-01-02
+//	Field time.Time `properties:"date,layout=2006-01-02"`
+//
+//	// Field is assigned the non-empty and whitespace trimmed
+//	// values of key 'Field' split by commas.
+//	Field []string
+//
+//	// Field is assigned the non-empty and whitespace trimmed
+//	// values of key 'Field' split by commas and has a default
+//	// value ["a", "b", "c"] if the key does not exist.
+//	Field []string `properties:",default=a;b;c"`
+//
+//	// Field is decoded recursively with "Field." as key prefix.
+//	Field SomeStruct
+//
+//	// Field is decoded recursively with "myName." as key prefix.
+//	Field SomeStruct `properties:"myName"`
+//
+//	// Field is decoded recursively with "Field." as key prefix
+//	// and the next dotted element of the key as map key.
+//	Field map[string]string
+//
+//	// Field is decoded recursively with "myName." as key prefix
+//	// and the next dotted element of the key as map key.
+//	Field map[string]string `properties:"myName"`
+func (p *Properties) Decode(x interface{}) error {
+	t, v := reflect.TypeOf(x), reflect.ValueOf(x)
+	if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct {
+		return fmt.Errorf("not a pointer to struct: %s", t)
+	}
+	if err := dec(p, "", nil, nil, v); err != nil {
+		return err
+	}
+	return nil
+}
+
+func dec(p *Properties, key string, def *string, opts map[string]string, v reflect.Value) error {
+	t := v.Type()
+
+	// value returns the property value for key or the default if provided.
+	value := func() (string, error) {
+		if val, ok := p.Get(key); ok {
+			return val, nil
+		}
+		if def != nil {
+			return *def, nil
+		}
+		return "", fmt.Errorf("missing required key %s", key)
+	}
+
+	// conv converts a string to a value of the given type.
+	conv := func(s string, t reflect.Type) (val reflect.Value, err error) {
+		var v interface{}
+
+		switch {
+		case isDuration(t):
+			v, err = time.ParseDuration(s)
+
+		case isTime(t):
+			layout := opts["layout"]
+			if layout == "" {
+				layout = time.RFC3339
+			}
+			v, err = time.Parse(layout, s)
+
+		case isBool(t):
+			v, err = boolVal(s), nil
+
+		case isString(t):
+			v, err = s, nil
+
+		case isFloat(t):
+			v, err = strconv.ParseFloat(s, 64)
+
+		case isInt(t):
+			v, err = strconv.ParseInt(s, 10, 64)
+
+		case isUint(t):
+			v, err = strconv.ParseUint(s, 10, 64)
+
+		default:
+			return reflect.Zero(t), fmt.Errorf("unsupported type %s", t)
+		}
+		if err != nil {
+			return reflect.Zero(t), err
+		}
+		return reflect.ValueOf(v).Convert(t), nil
+	}
+
+	// keydef returns the property key and the default value based on the
+	// name of the struct field and the options in the tag.
+	keydef := func(f reflect.StructField) (string, *string, map[string]string) {
+		_key, _opts := parseTag(f.Tag.Get("properties"))
+
+		var _def *string
+		if d, ok := _opts["default"]; ok {
+			_def = &d
+		}
+		if _key != "" {
+			return _key, _def, _opts
+		}
+		return f.Name, _def, _opts
+	}
+
+	switch {
+	case isDuration(t) || isTime(t) || isBool(t) || isString(t) || isFloat(t) || isInt(t) || isUint(t):
+		s, err := value()
+		if err != nil {
+			return err
+		}
+		val, err := conv(s, t)
+		if err != nil {
+			return err
+		}
+		v.Set(val)
+
+	case isPtr(t):
+		return dec(p, key, def, opts, v.Elem())
+
+	case isStruct(t):
+		for i := 0; i < v.NumField(); i++ {
+			fv := v.Field(i)
+			fk, def, opts := keydef(t.Field(i))
+			if fk == "-" {
+				continue
+			}
+			if !fv.CanSet() {
+				return fmt.Errorf("cannot set %s", t.Field(i).Name)
+			}
+			if key != "" {
+				fk = key + "." + fk
+			}
+			if err := dec(p, fk, def, opts, fv); err != nil {
+				return err
+			}
+		}
+		return nil
+
+	case isArray(t):
+		val, err := value()
+		if err != nil {
+			return err
+		}
+		vals := split(val, ";")
+		a := reflect.MakeSlice(t, 0, len(vals))
+		for _, s := range vals {
+			val, err := conv(s, t.Elem())
+			if err != nil {
+				return err
+			}
+			a = reflect.Append(a, val)
+		}
+		v.Set(a)
+
+	case isMap(t):
+		valT := t.Elem()
+		m := reflect.MakeMap(t)
+		for postfix := range p.FilterStripPrefix(key + ".").m {
+			pp := strings.SplitN(postfix, ".", 2)
+			mk, mv := pp[0], reflect.New(valT)
+			if err := dec(p, key+"."+mk, nil, nil, mv); err != nil {
+				return err
+			}
+			m.SetMapIndex(reflect.ValueOf(mk), mv.Elem())
+		}
+		v.Set(m)
+
+	default:
+		return fmt.Errorf("unsupported type %s", t)
+	}
+	return nil
+}
+
+// split splits a string on sep, trims whitespace of elements
+// and omits empty elements
+func split(s string, sep string) []string {
+	var a []string
+	for _, v := range strings.Split(s, sep) {
+		if v = strings.TrimSpace(v); v != "" {
+			a = append(a, v)
+		}
+	}
+	return a
+}
+
+// parseTag parses a "key,k=v,k=v,..."
+func parseTag(tag string) (key string, opts map[string]string) {
+	opts = map[string]string{}
+	for i, s := range strings.Split(tag, ",") {
+		if i == 0 {
+			key = s
+			continue
+		}
+
+		pp := strings.SplitN(s, "=", 2)
+		if len(pp) == 1 {
+			opts[pp[0]] = ""
+		} else {
+			opts[pp[0]] = pp[1]
+		}
+	}
+	return key, opts
+}
+
+func isArray(t reflect.Type) bool    { return t.Kind() == reflect.Array || t.Kind() == reflect.Slice }
+func isBool(t reflect.Type) bool     { return t.Kind() == reflect.Bool }
+func isDuration(t reflect.Type) bool { return t == reflect.TypeOf(time.Second) }
+func isMap(t reflect.Type) bool      { return t.Kind() == reflect.Map }
+func isPtr(t reflect.Type) bool      { return t.Kind() == reflect.Ptr }
+func isString(t reflect.Type) bool   { return t.Kind() == reflect.String }
+func isStruct(t reflect.Type) bool   { return t.Kind() == reflect.Struct }
+func isTime(t reflect.Type) bool     { return t == reflect.TypeOf(time.Time{}) }
+func isFloat(t reflect.Type) bool {
+	return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64
+}
+func isInt(t reflect.Type) bool {
+	return t.Kind() == reflect.Int || t.Kind() == reflect.Int8 || t.Kind() == reflect.Int16 || t.Kind() == reflect.Int32 || t.Kind() == reflect.Int64
+}
+func isUint(t reflect.Type) bool {
+	return t.Kind() == reflect.Uint || t.Kind() == reflect.Uint8 || t.Kind() == reflect.Uint16 || t.Kind() == reflect.Uint32 || t.Kind() == reflect.Uint64
+}
diff --git a/vendor/github.com/magiconair/properties/doc.go b/vendor/github.com/magiconair/properties/doc.go
new file mode 100644
index 000000000..7c7979315
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/doc.go
@@ -0,0 +1,155 @@
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package properties provides functions for reading and writing
+// ISO-8859-1 and UTF-8 encoded .properties files and has
+// support for recursive property expansion.
+//
+// Java properties files are ISO-8859-1 encoded and use Unicode
+// literals for characters outside the ISO character set. Unicode
+// literals can be used in UTF-8 encoded properties files but
+// aren't necessary.
+//
+// To load a single properties file use MustLoadFile():
+//
+//	p := properties.MustLoadFile(filename, properties.UTF8)
+//
+// To load multiple properties files use MustLoadFiles()
+// which loads the files in the given order and merges the
+// result. Missing properties files can be ignored if the
+// 'ignoreMissing' flag is set to true.
+//
+// Filenames can contain environment variables which are expanded
+// before loading.
+//
+//	f1 := "/etc/myapp/myapp.conf"
+//	f2 := "/home/${USER}/myapp.conf"
+//	p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true)
+//
+// All of the different key/value delimiters ' ', ':' and '=' are
+// supported as well as the comment characters '!' and '#' and
+// multi-line values.
+//
+//	! this is a comment
+//	# and so is this
+//
+//	# the following expressions are equal
+//	key value
+//	key=value
+//	key:value
+//	key = value
+//	key : value
+//	key = val\
+//	      ue
+//
+// Properties stores all comments preceding a key and provides
+// GetComments() and SetComments() methods to retrieve and
+// update them. The convenience functions GetComment() and
+// SetComment() allow access to the last comment. The
+// WriteComment() method writes properties files including
+// the comments and with the keys in the original order.
+// This can be used for sanitizing properties files.
+//
+// Property expansion is recursive and circular references
+// and malformed expressions are not allowed and cause an
+// error. Expansion of environment variables is supported.
+//
+//	# standard property
+//	key = value
+//
+//	# property expansion: key2 = value
+//	key2 = ${key}
+//
+//	# recursive expansion: key3 = value
+//	key3 = ${key2}
+//
+//	# circular reference (error)
+//	key = ${key}
+//
+//	# malformed expression (error)
+//	key = ${ke
+//
+//	# refers to the users' home dir
+//	home = ${HOME}
+//
+//	# local key takes precedence over env var: u = foo
+//	USER = foo
+//	u = ${USER}
+//
+// The default property expansion format is ${key} but can be
+// changed by setting different pre- and postfix values on the
+// Properties object.
+//
+//	p := properties.NewProperties()
+//	p.Prefix = "#["
+//	p.Postfix = "]#"
+//
+// Properties provides convenience functions for getting typed
+// values with default values if the key does not exist or the
+// type conversion failed.
+//
+//	# Returns true if the value is either "1", "on", "yes" or "true"
+//	# Returns false for every other value and the default value if
+//	# the key does not exist.
+//	v = p.GetBool("key", false)
+//
+//	# Returns the value if the key exists and the format conversion
+//	# was successful. Otherwise, the default value is returned.
+//	v = p.GetInt64("key", 999)
+//	v = p.GetUint64("key", 999)
+//	v = p.GetFloat64("key", 123.0)
+//	v = p.GetString("key", "def")
+//	v = p.GetDuration("key", 999)
+//
+// As an alternative properties may be applied with the standard
+// library's flag implementation at any time.
+//
+//	# Standard configuration
+//	v = flag.Int("key", 999, "help message")
+//	flag.Parse()
+//
+//	# Merge p into the flag set
+//	p.MustFlag(flag.CommandLine)
+//
+// Properties provides several MustXXX() convenience functions
+// which will terminate the app if an error occurs. The behavior
+// of the failure is configurable and the default is to call
+// log.Fatal(err). To have the MustXXX() functions panic instead
+// of logging the error set a different ErrorHandler before
+// you use the Properties package.
+//
+//	properties.ErrorHandler = properties.PanicHandler
+//
+//	# Will panic instead of logging an error
+//	p := properties.MustLoadFile("config.properties")
+//
+// You can also provide your own ErrorHandler function. The only requirement
+// is that the error handler function must exit after handling the error.
+//
+//	  properties.ErrorHandler = func(err error) {
+//		     fmt.Println(err)
+//	      os.Exit(1)
+//	  }
+//
+//	  # Will write to stdout and then exit
+//	  p := properties.MustLoadFile("config.properties")
+//
+// Properties can also be loaded into a struct via the `Decode`
+// method, e.g.
+//
+//	type S struct {
+//	    A string        `properties:"a,default=foo"`
+//	    D time.Duration `properties:"timeout,default=5s"`
+//	    E time.Time     `properties:"expires,layout=2006-01-02,default=2015-01-01"`
+//	}
+//
+// See `Decode()` method for the full documentation.
+//
+// The following documents provide a description of the properties
+// file format.
+//
+// http://en.wikipedia.org/wiki/.properties
+//
+// http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29
+package properties
diff --git a/vendor/github.com/magiconair/properties/integrate.go b/vendor/github.com/magiconair/properties/integrate.go
new file mode 100644
index 000000000..35d0ae97b
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/integrate.go
@@ -0,0 +1,35 @@
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import "flag"
+
+// MustFlag sets flags that are skipped by dst.Parse when p contains
+// the respective key for flag.Flag.Name.
+//
+// It's use is recommended with command line arguments as in:
+//
+//	flag.Parse()
+//	p.MustFlag(flag.CommandLine)
+func (p *Properties) MustFlag(dst *flag.FlagSet) {
+	m := make(map[string]*flag.Flag)
+	dst.VisitAll(func(f *flag.Flag) {
+		m[f.Name] = f
+	})
+	dst.Visit(func(f *flag.Flag) {
+		delete(m, f.Name) // overridden
+	})
+
+	for name, f := range m {
+		v, ok := p.Get(name)
+		if !ok {
+			continue
+		}
+
+		if err := f.Value.Set(v); err != nil {
+			ErrorHandler(err)
+		}
+	}
+}
diff --git a/vendor/github.com/magiconair/properties/lex.go b/vendor/github.com/magiconair/properties/lex.go
new file mode 100644
index 000000000..3d15a1f6e
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/lex.go
@@ -0,0 +1,395 @@
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Parts of the lexer are from the template/text/parser package
+// For these parts the following applies:
+//
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file of the go 1.2
+// distribution.
+
+package properties
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"unicode/utf8"
+)
+
+// item represents a token or text string returned from the scanner.
+type item struct {
+	typ itemType // The type of this item.
+	pos int      // The starting position, in bytes, of this item in the input string.
+	val string   // The value of this item.
+}
+
+func (i item) String() string {
+	switch {
+	case i.typ == itemEOF:
+		return "EOF"
+	case i.typ == itemError:
+		return i.val
+	case len(i.val) > 10:
+		return fmt.Sprintf("%.10q...", i.val)
+	}
+	return fmt.Sprintf("%q", i.val)
+}
+
+// itemType identifies the type of lex items.
+type itemType int
+
+const (
+	itemError itemType = iota // error occurred; value is text of error
+	itemEOF
+	itemKey     // a key
+	itemValue   // a value
+	itemComment // a comment
+)
+
+// defines a constant for EOF
+const eof = -1
+
+// permitted whitespace characters space, FF and TAB
+const whitespace = " \f\t"
+
+// stateFn represents the state of the scanner as a function that returns the next state.
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner.
+type lexer struct {
+	input   string    // the string being scanned
+	state   stateFn   // the next lexing function to enter
+	pos     int       // current position in the input
+	start   int       // start position of this item
+	width   int       // width of last rune read from input
+	lastPos int       // position of most recent item returned by nextItem
+	runes   []rune    // scanned runes for this item
+	items   chan item // channel of scanned items
+}
+
+// next returns the next rune in the input.
+func (l *lexer) next() rune {
+	if l.pos >= len(l.input) {
+		l.width = 0
+		return eof
+	}
+	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
+	l.width = w
+	l.pos += l.width
+	return r
+}
+
+// peek returns but does not consume the next rune in the input.
+func (l *lexer) peek() rune {
+	r := l.next()
+	l.backup()
+	return r
+}
+
+// backup steps back one rune. Can only be called once per call of next.
+func (l *lexer) backup() {
+	l.pos -= l.width
+}
+
+// emit passes an item back to the client.
+func (l *lexer) emit(t itemType) {
+	i := item{t, l.start, string(l.runes)}
+	l.items <- i
+	l.start = l.pos
+	l.runes = l.runes[:0]
+}
+
+// ignore skips over the pending input before this point.
+func (l *lexer) ignore() {
+	l.start = l.pos
+}
+
+// appends the rune to the current value
+func (l *lexer) appendRune(r rune) {
+	l.runes = append(l.runes, r)
+}
+
+// accept consumes the next rune if it's from the valid set.
+func (l *lexer) accept(valid string) bool {
+	if strings.ContainsRune(valid, l.next()) {
+		return true
+	}
+	l.backup()
+	return false
+}
+
+// acceptRun consumes a run of runes from the valid set.
+func (l *lexer) acceptRun(valid string) {
+	for strings.ContainsRune(valid, l.next()) {
+	}
+	l.backup()
+}
+
+// lineNumber reports which line we're on, based on the position of
+// the previous item returned by nextItem. Doing it this way
+// means we don't have to worry about peek double counting.
+func (l *lexer) lineNumber() int {
+	return 1 + strings.Count(l.input[:l.lastPos], "\n")
+}
+
+// errorf returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.nextItem.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+	l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
+	return nil
+}
+
+// nextItem returns the next item from the input.
+func (l *lexer) nextItem() item {
+	i := <-l.items
+	l.lastPos = i.pos
+	return i
+}
+
+// lex creates a new scanner for the input string.
+func lex(input string) *lexer {
+	l := &lexer{
+		input: input,
+		items: make(chan item),
+		runes: make([]rune, 0, 32),
+	}
+	go l.run()
+	return l
+}
+
+// run runs the state machine for the lexer.
+func (l *lexer) run() {
+	for l.state = lexBeforeKey(l); l.state != nil; {
+		l.state = l.state(l)
+	}
+}
+
+// state functions
+
+// lexBeforeKey scans until a key begins.
+func lexBeforeKey(l *lexer) stateFn {
+	switch r := l.next(); {
+	case isEOF(r):
+		l.emit(itemEOF)
+		return nil
+
+	case isEOL(r):
+		l.ignore()
+		return lexBeforeKey
+
+	case isComment(r):
+		return lexComment
+
+	case isWhitespace(r):
+		l.ignore()
+		return lexBeforeKey
+
+	default:
+		l.backup()
+		return lexKey
+	}
+}
+
+// lexComment scans a comment line. The comment character has already been scanned.
+func lexComment(l *lexer) stateFn {
+	l.acceptRun(whitespace)
+	l.ignore()
+	for {
+		switch r := l.next(); {
+		case isEOF(r):
+			l.ignore()
+			l.emit(itemEOF)
+			return nil
+		case isEOL(r):
+			l.emit(itemComment)
+			return lexBeforeKey
+		default:
+			l.appendRune(r)
+		}
+	}
+}
+
+// lexKey scans the key up to a delimiter
+func lexKey(l *lexer) stateFn {
+	var r rune
+
+Loop:
+	for {
+		switch r = l.next(); {
+
+		case isEscape(r):
+			err := l.scanEscapeSequence()
+			if err != nil {
+				return l.errorf(err.Error())
+			}
+
+		case isEndOfKey(r):
+			l.backup()
+			break Loop
+
+		case isEOF(r):
+			break Loop
+
+		default:
+			l.appendRune(r)
+		}
+	}
+
+	if len(l.runes) > 0 {
+		l.emit(itemKey)
+	}
+
+	if isEOF(r) {
+		l.emit(itemEOF)
+		return nil
+	}
+
+	return lexBeforeValue
+}
+
+// lexBeforeValue scans the delimiter between key and value.
+// Leading and trailing whitespace is ignored.
+// We expect to be just after the key.
+func lexBeforeValue(l *lexer) stateFn {
+	l.acceptRun(whitespace)
+	l.accept(":=")
+	l.acceptRun(whitespace)
+	l.ignore()
+	return lexValue
+}
+
+// lexValue scans text until the end of the line. We expect to be just after the delimiter.
+func lexValue(l *lexer) stateFn {
+	for {
+		switch r := l.next(); {
+		case isEscape(r):
+			if isEOL(l.peek()) {
+				l.next()
+				l.acceptRun(whitespace)
+			} else {
+				err := l.scanEscapeSequence()
+				if err != nil {
+					return l.errorf(err.Error())
+				}
+			}
+
+		case isEOL(r):
+			l.emit(itemValue)
+			l.ignore()
+			return lexBeforeKey
+
+		case isEOF(r):
+			l.emit(itemValue)
+			l.emit(itemEOF)
+			return nil
+
+		default:
+			l.appendRune(r)
+		}
+	}
+}
+
+// scanEscapeSequence scans either one of the escaped characters
+// or a unicode literal. We expect to be after the escape character.
+func (l *lexer) scanEscapeSequence() error {
+	switch r := l.next(); {
+
+	case isEscapedCharacter(r):
+		l.appendRune(decodeEscapedCharacter(r))
+		return nil
+
+	case atUnicodeLiteral(r):
+		return l.scanUnicodeLiteral()
+
+	case isEOF(r):
+		return fmt.Errorf("premature EOF")
+
+	// silently drop the escape character and append the rune as is
+	default:
+		l.appendRune(r)
+		return nil
+	}
+}
+
+// scans a unicode literal in the form \uXXXX. We expect to be after the \u.
+func (l *lexer) scanUnicodeLiteral() error {
+	// scan the digits
+	d := make([]rune, 4)
+	for i := 0; i < 4; i++ {
+		d[i] = l.next()
+		if d[i] == eof || !strings.ContainsRune("0123456789abcdefABCDEF", d[i]) {
+			return fmt.Errorf("invalid unicode literal")
+		}
+	}
+
+	// decode the digits into a rune
+	r, err := strconv.ParseInt(string(d), 16, 0)
+	if err != nil {
+		return err
+	}
+
+	l.appendRune(rune(r))
+	return nil
+}
+
+// decodeEscapedCharacter returns the unescaped rune. We expect to be after the escape character.
+func decodeEscapedCharacter(r rune) rune {
+	switch r {
+	case 'f':
+		return '\f'
+	case 'n':
+		return '\n'
+	case 'r':
+		return '\r'
+	case 't':
+		return '\t'
+	default:
+		return r
+	}
+}
+
+// atUnicodeLiteral reports whether we are at a unicode literal.
+// The escape character has already been consumed.
+func atUnicodeLiteral(r rune) bool {
+	return r == 'u'
+}
+
+// isComment reports whether we are at the start of a comment.
+func isComment(r rune) bool {
+	return r == '#' || r == '!'
+}
+
+// isEndOfKey reports whether the rune terminates the current key.
+func isEndOfKey(r rune) bool {
+	return strings.ContainsRune(" \f\t\r\n:=", r)
+}
+
+// isEOF reports whether we are at EOF.
+func isEOF(r rune) bool {
+	return r == eof
+}
+
+// isEOL reports whether we are at a new line character.
+func isEOL(r rune) bool {
+	return r == '\n' || r == '\r'
+}
+
+// isEscape reports whether the rune is the escape character which
+// prefixes unicode literals and other escaped characters.
+func isEscape(r rune) bool {
+	return r == '\\'
+}
+
+// isEscapedCharacter reports whether we are at one of the characters that need escaping.
+// The escape character has already been consumed.
+func isEscapedCharacter(r rune) bool {
+	return strings.ContainsRune(" :=fnrt", r)
+}
+
+// isWhitespace reports whether the rune is a whitespace character.
+func isWhitespace(r rune) bool {
+	return strings.ContainsRune(whitespace, r)
+}
diff --git a/vendor/github.com/magiconair/properties/load.go b/vendor/github.com/magiconair/properties/load.go
new file mode 100644
index 000000000..6567e0c71
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/load.go
@@ -0,0 +1,314 @@
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+	"strings"
+)
+
+// Encoding specifies encoding of the input data.
+type Encoding uint
+
+const (
+	// utf8Default is a private placeholder for the zero value of Encoding to
+	// ensure that it has the correct meaning. UTF8 is the default encoding but
+	// was assigned a non-zero value which cannot be changed without breaking
+	// existing code. Clients should continue to use the public constants.
+	utf8Default Encoding = iota
+
+	// UTF8 interprets the input data as UTF-8.
+	UTF8
+
+	// ISO_8859_1 interprets the input data as ISO-8859-1.
+	ISO_8859_1
+)
+
+type Loader struct {
+	// Encoding determines how the data from files and byte buffers
+	// is interpreted. For URLs the Content-Type header is used
+	// to determine the encoding of the data.
+	Encoding Encoding
+
+	// DisableExpansion configures the property expansion of the
+	// returned property object. When set to true, the property values
+	// will not be expanded and the Property object will not be checked
+	// for invalid expansion expressions.
+	DisableExpansion bool
+
+	// IgnoreMissing configures whether missing files or URLs which return
+	// 404 are reported as errors. When set to true, missing files and 404
+	// status codes are not reported as errors.
+	IgnoreMissing bool
+}
+
+// Load reads a buffer into a Properties struct.
+func (l *Loader) LoadBytes(buf []byte) (*Properties, error) {
+	return l.loadBytes(buf, l.Encoding)
+}
+
+// LoadReader reads an io.Reader into a Properties struct.
+func (l *Loader) LoadReader(r io.Reader) (*Properties, error) {
+	if buf, err := io.ReadAll(r); err != nil {
+		return nil, err
+	} else {
+		return l.loadBytes(buf, l.Encoding)
+	}
+}
+
+// LoadAll reads the content of multiple URLs or files in the given order into
+// a Properties struct. If IgnoreMissing is true then a 404 status code or
+// missing file will not be reported as error. Encoding sets the encoding for
+// files. For the URLs see LoadURL for the Content-Type header and the
+// encoding.
+func (l *Loader) LoadAll(names []string) (*Properties, error) {
+	all := NewProperties()
+	for _, name := range names {
+		n, err := expandName(name)
+		if err != nil {
+			return nil, err
+		}
+
+		var p *Properties
+		switch {
+		case strings.HasPrefix(n, "http://"):
+			p, err = l.LoadURL(n)
+		case strings.HasPrefix(n, "https://"):
+			p, err = l.LoadURL(n)
+		default:
+			p, err = l.LoadFile(n)
+		}
+		if err != nil {
+			return nil, err
+		}
+		all.Merge(p)
+	}
+
+	all.DisableExpansion = l.DisableExpansion
+	if all.DisableExpansion {
+		return all, nil
+	}
+	return all, all.check()
+}
+
+// LoadFile reads a file into a Properties struct.
+// If IgnoreMissing is true then a missing file will not be
+// reported as error.
+func (l *Loader) LoadFile(filename string) (*Properties, error) {
+	data, err := os.ReadFile(filename)
+	if err != nil {
+		if l.IgnoreMissing && os.IsNotExist(err) {
+			LogPrintf("properties: %s not found. skipping", filename)
+			return NewProperties(), nil
+		}
+		return nil, err
+	}
+	return l.loadBytes(data, l.Encoding)
+}
+
+// LoadURL reads the content of the URL into a Properties struct.
+//
+// The encoding is determined via the Content-Type header which
+// should be set to 'text/plain'. If the 'charset' parameter is
+// missing, 'iso-8859-1' or 'latin1' the encoding is set to
+// ISO-8859-1. If the 'charset' parameter is set to 'utf-8' the
+// encoding is set to UTF-8. A missing content type header is
+// interpreted as 'text/plain; charset=utf-8'.
+func (l *Loader) LoadURL(url string) (*Properties, error) {
+	resp, err := http.Get(url)
+	if err != nil {
+		return nil, fmt.Errorf("properties: error fetching %q. %s", url, err)
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode == 404 && l.IgnoreMissing {
+		LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode)
+		return NewProperties(), nil
+	}
+
+	if resp.StatusCode != 200 {
+		return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode)
+	}
+
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return nil, fmt.Errorf("properties: %s error reading response. %s", url, err)
+	}
+
+	ct := resp.Header.Get("Content-Type")
+	ct = strings.Join(strings.Fields(ct), "")
+	var enc Encoding
+	switch strings.ToLower(ct) {
+	case "text/plain", "text/plain;charset=iso-8859-1", "text/plain;charset=latin1":
+		enc = ISO_8859_1
+	case "", "text/plain;charset=utf-8":
+		enc = UTF8
+	default:
+		return nil, fmt.Errorf("properties: invalid content type %s", ct)
+	}
+
+	return l.loadBytes(body, enc)
+}
+
+func (l *Loader) loadBytes(buf []byte, enc Encoding) (*Properties, error) {
+	p, err := parse(convert(buf, enc))
+	if err != nil {
+		return nil, err
+	}
+	p.DisableExpansion = l.DisableExpansion
+	if p.DisableExpansion {
+		return p, nil
+	}
+	return p, p.check()
+}
+
+// Load reads a buffer into a Properties struct.
+func Load(buf []byte, enc Encoding) (*Properties, error) {
+	l := &Loader{Encoding: enc}
+	return l.LoadBytes(buf)
+}
+
+// LoadString reads an UTF8 string into a properties struct.
+func LoadString(s string) (*Properties, error) {
+	l := &Loader{Encoding: UTF8}
+	return l.LoadBytes([]byte(s))
+}
+
+// LoadMap creates a new Properties struct from a string map.
+func LoadMap(m map[string]string) *Properties {
+	p := NewProperties()
+	for k, v := range m {
+		p.Set(k, v)
+	}
+	return p
+}
+
+// LoadFile reads a file into a Properties struct.
+func LoadFile(filename string, enc Encoding) (*Properties, error) {
+	l := &Loader{Encoding: enc}
+	return l.LoadAll([]string{filename})
+}
+
+// LoadReader reads an io.Reader into a Properties struct.
+func LoadReader(r io.Reader, enc Encoding) (*Properties, error) {
+	l := &Loader{Encoding: enc}
+	return l.LoadReader(r)
+}
+
+// LoadFiles reads multiple files in the given order into
+// a Properties struct. If 'ignoreMissing' is true then
+// non-existent files will not be reported as error.
+func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
+	l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing}
+	return l.LoadAll(filenames)
+}
+
+// LoadURL reads the content of the URL into a Properties struct.
+// See Loader#LoadURL for details.
+func LoadURL(url string) (*Properties, error) {
+	l := &Loader{Encoding: UTF8}
+	return l.LoadAll([]string{url})
+}
+
+// LoadURLs reads the content of multiple URLs in the given order into a
+// Properties struct. If IgnoreMissing is true then a 404 status code will
+// not be reported as error. See Loader#LoadURL for the Content-Type header
+// and the encoding.
+func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) {
+	l := &Loader{Encoding: UTF8, IgnoreMissing: ignoreMissing}
+	return l.LoadAll(urls)
+}
+
+// LoadAll reads the content of multiple URLs or files in the given order into a
+// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will
+// not be reported as error. Encoding sets the encoding for files. For the URLs please see
+// LoadURL for the Content-Type header and the encoding.
+func LoadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
+	l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing}
+	return l.LoadAll(names)
+}
+
+// MustLoadString reads an UTF8 string into a Properties struct and
+// panics on error.
+func MustLoadString(s string) *Properties {
+	return must(LoadString(s))
+}
+
+// MustLoadSReader reads an io.Reader into a Properties struct and
+// panics on error.
+func MustLoadReader(r io.Reader, enc Encoding) *Properties {
+	return must(LoadReader(r, enc))
+}
+
+// MustLoadFile reads a file into a Properties struct and
+// panics on error.
+func MustLoadFile(filename string, enc Encoding) *Properties {
+	return must(LoadFile(filename, enc))
+}
+
+// MustLoadFiles reads multiple files in the given order into
+// a Properties struct and panics on error. If 'ignoreMissing'
+// is true then non-existent files will not be reported as error.
+func MustLoadFiles(filenames []string, enc Encoding, ignoreMissing bool) *Properties {
+	return must(LoadFiles(filenames, enc, ignoreMissing))
+}
+
+// MustLoadURL reads the content of a URL into a Properties struct and
+// panics on error.
+func MustLoadURL(url string) *Properties {
+	return must(LoadURL(url))
+}
+
+// MustLoadURLs reads the content of multiple URLs in the given order into a
+// Properties struct and panics on error. If 'ignoreMissing' is true then a 404
+// status code will not be reported as error.
+func MustLoadURLs(urls []string, ignoreMissing bool) *Properties {
+	return must(LoadURLs(urls, ignoreMissing))
+}
+
+// MustLoadAll reads the content of multiple URLs or files in the given order into a
+// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will
+// not be reported as error. Encoding sets the encoding for files. For the URLs please see
+// LoadURL for the Content-Type header and the encoding. It panics on error.
+func MustLoadAll(names []string, enc Encoding, ignoreMissing bool) *Properties {
+	return must(LoadAll(names, enc, ignoreMissing))
+}
+
+func must(p *Properties, err error) *Properties {
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return p
+}
+
+// expandName expands ${ENV_VAR} expressions in a name.
+// If the environment variable does not exist then it will be replaced
+// with an empty string. Malformed expressions like "${ENV_VAR" will
+// be reported as error.
+func expandName(name string) (string, error) {
+	return expand(name, []string{}, "${", "}", make(map[string]string))
+}
+
+// Interprets a byte buffer either as an ISO-8859-1 or UTF-8 encoded string.
+// For ISO-8859-1 we can convert each byte straight into a rune since the
+// first 256 unicode code points cover ISO-8859-1.
+func convert(buf []byte, enc Encoding) string {
+	switch enc {
+	case utf8Default, UTF8:
+		return string(buf)
+	case ISO_8859_1:
+		runes := make([]rune, len(buf))
+		for i, b := range buf {
+			runes[i] = rune(b)
+		}
+		return string(runes)
+	default:
+		ErrorHandler(fmt.Errorf("unsupported encoding %v", enc))
+	}
+	panic("ErrorHandler should exit")
+}
diff --git a/vendor/github.com/magiconair/properties/parser.go b/vendor/github.com/magiconair/properties/parser.go
new file mode 100644
index 000000000..fccfd39f6
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/parser.go
@@ -0,0 +1,86 @@
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+	"fmt"
+	"runtime"
+)
+
+type parser struct {
+	lex *lexer
+}
+
+func parse(input string) (properties *Properties, err error) {
+	p := &parser{lex: lex(input)}
+	defer p.recover(&err)
+
+	properties = NewProperties()
+	key := ""
+	comments := []string{}
+
+	for {
+		token := p.expectOneOf(itemComment, itemKey, itemEOF)
+		switch token.typ {
+		case itemEOF:
+			goto done
+		case itemComment:
+			comments = append(comments, token.val)
+			continue
+		case itemKey:
+			key = token.val
+			if _, ok := properties.m[key]; !ok {
+				properties.k = append(properties.k, key)
+			}
+		}
+
+		token = p.expectOneOf(itemValue, itemEOF)
+		if len(comments) > 0 {
+			properties.c[key] = comments
+			comments = []string{}
+		}
+		switch token.typ {
+		case itemEOF:
+			properties.m[key] = ""
+			goto done
+		case itemValue:
+			properties.m[key] = token.val
+		}
+	}
+
+done:
+	return properties, nil
+}
+
+func (p *parser) errorf(format string, args ...interface{}) {
+	format = fmt.Sprintf("properties: Line %d: %s", p.lex.lineNumber(), format)
+	panic(fmt.Errorf(format, args...))
+}
+
+func (p *parser) expectOneOf(expected ...itemType) (token item) {
+	token = p.lex.nextItem()
+	for _, v := range expected {
+		if token.typ == v {
+			return token
+		}
+	}
+	p.unexpected(token)
+	panic("unexpected token")
+}
+
+func (p *parser) unexpected(token item) {
+	p.errorf(token.String())
+}
+
+// recover is the handler that turns panics into returns from the top level of Parse.
+func (p *parser) recover(errp *error) {
+	e := recover()
+	if e != nil {
+		if _, ok := e.(runtime.Error); ok {
+			panic(e)
+		}
+		*errp = e.(error)
+	}
+}
diff --git a/vendor/github.com/magiconair/properties/properties.go b/vendor/github.com/magiconair/properties/properties.go
new file mode 100644
index 000000000..58297611d
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/properties.go
@@ -0,0 +1,958 @@
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+// BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer.
+// BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used.
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+	"unicode"
+	"unicode/utf8"
+)
+
+const maxExpansionDepth = 64
+
+// ErrorHandlerFunc defines the type of function which handles failures
+// of the MustXXX() functions. An error handler function must exit
+// the application after handling the error.
+type ErrorHandlerFunc func(error)
+
+// ErrorHandler is the function which handles failures of the MustXXX()
+// functions. The default is LogFatalHandler.
+var ErrorHandler ErrorHandlerFunc = LogFatalHandler
+
+// LogHandlerFunc defines the function prototype for logging errors.
+type LogHandlerFunc func(fmt string, args ...interface{})
+
+// LogPrintf defines a log handler which uses log.Printf.
+var LogPrintf LogHandlerFunc = log.Printf
+
+// LogFatalHandler handles the error by logging a fatal error and exiting.
+func LogFatalHandler(err error) {
+	log.Fatal(err)
+}
+
+// PanicHandler handles the error by panicking.
+func PanicHandler(err error) {
+	panic(err)
+}
+
+// -----------------------------------------------------------------------------
+
+// A Properties contains the key/value pairs from the properties input.
+// All values are stored in unexpanded form and are expanded at runtime
+type Properties struct {
+	// Pre-/Postfix for property expansion.
+	Prefix  string
+	Postfix string
+
+	// DisableExpansion controls the expansion of properties on Get()
+	// and the check for circular references on Set(). When set to
+	// true Properties behaves like a simple key/value store and does
+	// not check for circular references on Get() or on Set().
+	DisableExpansion bool
+
+	// Stores the key/value pairs
+	m map[string]string
+
+	// Stores the comments per key.
+	c map[string][]string
+
+	// Stores the keys in order of appearance.
+	k []string
+
+	// WriteSeparator specifies the separator of key and value while writing the properties.
+	WriteSeparator string
+}
+
+// NewProperties creates a new Properties struct with the default
+// configuration for "${key}" expressions.
+func NewProperties() *Properties {
+	return &Properties{
+		Prefix:  "${",
+		Postfix: "}",
+		m:       map[string]string{},
+		c:       map[string][]string{},
+		k:       []string{},
+	}
+}
+
+// Load reads a buffer into the given Properties struct.
+func (p *Properties) Load(buf []byte, enc Encoding) error {
+	l := &Loader{Encoding: enc, DisableExpansion: p.DisableExpansion}
+	newProperties, err := l.LoadBytes(buf)
+	if err != nil {
+		return err
+	}
+	p.Merge(newProperties)
+	return nil
+}
+
+// Get returns the expanded value for the given key if exists.
+// Otherwise, ok is false.
+func (p *Properties) Get(key string) (value string, ok bool) {
+	v, ok := p.m[key]
+	if p.DisableExpansion {
+		return v, ok
+	}
+	if !ok {
+		return "", false
+	}
+
+	expanded, err := p.expand(key, v)
+
+	// we guarantee that the expanded value is free of
+	// circular references and malformed expressions
+	// so we panic if we still get an error here.
+	if err != nil {
+		ErrorHandler(err)
+	}
+
+	return expanded, true
+}
+
+// MustGet returns the expanded value for the given key if exists.
+// Otherwise, it panics.
+func (p *Properties) MustGet(key string) string {
+	if v, ok := p.Get(key); ok {
+		return v
+	}
+	ErrorHandler(invalidKeyError(key))
+	panic("ErrorHandler should exit")
+}
+
+// ----------------------------------------------------------------------------
+
+// ClearComments removes the comments for all keys.
+func (p *Properties) ClearComments() {
+	p.c = map[string][]string{}
+}
+
+// ----------------------------------------------------------------------------
+
+// GetComment returns the last comment before the given key or an empty string.
+func (p *Properties) GetComment(key string) string {
+	comments, ok := p.c[key]
+	if !ok || len(comments) == 0 {
+		return ""
+	}
+	return comments[len(comments)-1]
+}
+
+// ----------------------------------------------------------------------------
+
+// GetComments returns all comments that appeared before the given key or nil.
+func (p *Properties) GetComments(key string) []string {
+	if comments, ok := p.c[key]; ok {
+		return comments
+	}
+	return nil
+}
+
+// ----------------------------------------------------------------------------
+
+// SetComment sets the comment for the key.
+func (p *Properties) SetComment(key, comment string) {
+	p.c[key] = []string{comment}
+}
+
+// ----------------------------------------------------------------------------
+
+// SetComments sets the comments for the key. If the comments are nil then
+// all comments for this key are deleted.
+func (p *Properties) SetComments(key string, comments []string) {
+	if comments == nil {
+		delete(p.c, key)
+		return
+	}
+	p.c[key] = comments
+}
+
+// ----------------------------------------------------------------------------
+
+// GetBool checks if the expanded value is one of '1', 'yes',
+// 'true' or 'on' if the key exists. The comparison is case-insensitive.
+// If the key does not exist the default value is returned.
+func (p *Properties) GetBool(key string, def bool) bool {
+	v, err := p.getBool(key)
+	if err != nil {
+		return def
+	}
+	return v
+}
+
+// MustGetBool checks if the expanded value is one of '1', 'yes',
+// 'true' or 'on' if the key exists. The comparison is case-insensitive.
+// If the key does not exist the function panics.
+func (p *Properties) MustGetBool(key string) bool {
+	v, err := p.getBool(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return v
+}
+
+func (p *Properties) getBool(key string) (value bool, err error) {
+	if v, ok := p.Get(key); ok {
+		return boolVal(v), nil
+	}
+	return false, invalidKeyError(key)
+}
+
+func boolVal(v string) bool {
+	v = strings.ToLower(v)
+	return v == "1" || v == "true" || v == "yes" || v == "on"
+}
+
+// ----------------------------------------------------------------------------
+
+// GetDuration parses the expanded value as an time.Duration (in ns) if the
+// key exists. If key does not exist or the value cannot be parsed the default
+// value is returned. In almost all cases you want to use GetParsedDuration().
+func (p *Properties) GetDuration(key string, def time.Duration) time.Duration {
+	v, err := p.getInt64(key)
+	if err != nil {
+		return def
+	}
+	return time.Duration(v)
+}
+
+// MustGetDuration parses the expanded value as an time.Duration (in ns) if
+// the key exists. If key does not exist or the value cannot be parsed the
+// function panics. In almost all cases you want to use MustGetParsedDuration().
+func (p *Properties) MustGetDuration(key string) time.Duration {
+	v, err := p.getInt64(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return time.Duration(v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration {
+	s, ok := p.Get(key)
+	if !ok {
+		return def
+	}
+	v, err := time.ParseDuration(s)
+	if err != nil {
+		return def
+	}
+	return v
+}
+
+// MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetParsedDuration(key string) time.Duration {
+	s, ok := p.Get(key)
+	if !ok {
+		ErrorHandler(invalidKeyError(key))
+	}
+	v, err := time.ParseDuration(s)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return v
+}
+
+// ----------------------------------------------------------------------------
+
+// GetFloat64 parses the expanded value as a float64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetFloat64(key string, def float64) float64 {
+	v, err := p.getFloat64(key)
+	if err != nil {
+		return def
+	}
+	return v
+}
+
+// MustGetFloat64 parses the expanded value as a float64 if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetFloat64(key string) float64 {
+	v, err := p.getFloat64(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return v
+}
+
+func (p *Properties) getFloat64(key string) (value float64, err error) {
+	if v, ok := p.Get(key); ok {
+		value, err = strconv.ParseFloat(v, 64)
+		if err != nil {
+			return 0, err
+		}
+		return value, nil
+	}
+	return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetFloat32 parses the expanded value as a float32 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetFloat32(key string, def float32) float32 {
+	v, err := p.getFloat32(key)
+	if err != nil {
+		return def
+	}
+	return v
+}
+
+// MustGetFloat32 parses the expanded value as a float32 if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetFloat32(key string) float32 {
+	v, err := p.getFloat32(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return v
+}
+
+func (p *Properties) getFloat32(key string) (value float32, err error) {
+	if v, ok := p.Get(key); ok {
+		n, err := strconv.ParseFloat(v, 32)
+		if err != nil {
+			return 0, err
+		}
+		return float32(n), nil
+	}
+	return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetInt parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned. If the value does not fit into an int the
+// function panics with an out of range error.
+func (p *Properties) GetInt(key string, def int) int {
+	v, err := p.getInt64(key)
+	if err != nil {
+		return def
+	}
+	return intRangeCheck(key, v)
+}
+
+// MustGetInt parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+// If the value does not fit into an int the function panics with
+// an out of range error.
+func (p *Properties) MustGetInt(key string) int {
+	v, err := p.getInt64(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return intRangeCheck(key, v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetInt64 parses the expanded value as an int64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetInt64(key string, def int64) int64 {
+	v, err := p.getInt64(key)
+	if err != nil {
+		return def
+	}
+	return v
+}
+
+// MustGetInt64 parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetInt64(key string) int64 {
+	v, err := p.getInt64(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return v
+}
+
+func (p *Properties) getInt64(key string) (value int64, err error) {
+	if v, ok := p.Get(key); ok {
+		value, err = strconv.ParseInt(v, 10, 64)
+		if err != nil {
+			return 0, err
+		}
+		return value, nil
+	}
+	return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetInt32 parses the expanded value as an int32 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetInt32(key string, def int32) int32 {
+	v, err := p.getInt32(key)
+	if err != nil {
+		return def
+	}
+	return v
+}
+
+// MustGetInt32 parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetInt32(key string) int32 {
+	v, err := p.getInt32(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return v
+}
+
+func (p *Properties) getInt32(key string) (value int32, err error) {
+	if v, ok := p.Get(key); ok {
+		n, err := strconv.ParseInt(v, 10, 32)
+		if err != nil {
+			return 0, err
+		}
+		return int32(n), nil
+	}
+	return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetUint parses the expanded value as an uint if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned. If the value does not fit into an int the
+// function panics with an out of range error.
+func (p *Properties) GetUint(key string, def uint) uint {
+	v, err := p.getUint64(key)
+	if err != nil {
+		return def
+	}
+	return uintRangeCheck(key, v)
+}
+
+// MustGetUint parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+// If the value does not fit into an int the function panics with
+// an out of range error.
+func (p *Properties) MustGetUint(key string) uint {
+	v, err := p.getUint64(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return uintRangeCheck(key, v)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetUint64 parses the expanded value as an uint64 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetUint64(key string, def uint64) uint64 {
+	v, err := p.getUint64(key)
+	if err != nil {
+		return def
+	}
+	return v
+}
+
+// MustGetUint64 parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetUint64(key string) uint64 {
+	v, err := p.getUint64(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return v
+}
+
+func (p *Properties) getUint64(key string) (value uint64, err error) {
+	if v, ok := p.Get(key); ok {
+		value, err = strconv.ParseUint(v, 10, 64)
+		if err != nil {
+			return 0, err
+		}
+		return value, nil
+	}
+	return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetUint32 parses the expanded value as an uint32 if the key exists.
+// If key does not exist or the value cannot be parsed the default
+// value is returned.
+func (p *Properties) GetUint32(key string, def uint32) uint32 {
+	v, err := p.getUint32(key)
+	if err != nil {
+		return def
+	}
+	return v
+}
+
+// MustGetUint32 parses the expanded value as an int if the key exists.
+// If key does not exist or the value cannot be parsed the function panics.
+func (p *Properties) MustGetUint32(key string) uint32 {
+	v, err := p.getUint32(key)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return v
+}
+
+func (p *Properties) getUint32(key string) (value uint32, err error) {
+	if v, ok := p.Get(key); ok {
+		n, err := strconv.ParseUint(v, 10, 32)
+		if err != nil {
+			return 0, err
+		}
+		return uint32(n), nil
+	}
+	return 0, invalidKeyError(key)
+}
+
+// ----------------------------------------------------------------------------
+
+// GetString returns the expanded value for the given key if exists or
+// the default value otherwise.
+func (p *Properties) GetString(key, def string) string {
+	if v, ok := p.Get(key); ok {
+		return v
+	}
+	return def
+}
+
+// MustGetString returns the expanded value for the given key if exists or
+// panics otherwise.
+func (p *Properties) MustGetString(key string) string {
+	if v, ok := p.Get(key); ok {
+		return v
+	}
+	ErrorHandler(invalidKeyError(key))
+	panic("ErrorHandler should exit")
+}
+
+// ----------------------------------------------------------------------------
+
+// Filter returns a new properties object which contains all properties
+// for which the key matches the pattern.
+func (p *Properties) Filter(pattern string) (*Properties, error) {
+	re, err := regexp.Compile(pattern)
+	if err != nil {
+		return nil, err
+	}
+
+	return p.FilterRegexp(re), nil
+}
+
+// FilterRegexp returns a new properties object which contains all properties
+// for which the key matches the regular expression.
+func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties {
+	pp := NewProperties()
+	for _, k := range p.k {
+		if re.MatchString(k) {
+			// TODO(fs): we are ignoring the error which flags a circular reference.
+			// TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
+			pp.Set(k, p.m[k])
+		}
+	}
+	return pp
+}
+
+// FilterPrefix returns a new properties object with a subset of all keys
+// with the given prefix.
+func (p *Properties) FilterPrefix(prefix string) *Properties {
+	pp := NewProperties()
+	for _, k := range p.k {
+		if strings.HasPrefix(k, prefix) {
+			// TODO(fs): we are ignoring the error which flags a circular reference.
+			// TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
+			pp.Set(k, p.m[k])
+		}
+	}
+	return pp
+}
+
+// FilterStripPrefix returns a new properties object with a subset of all keys
+// with the given prefix and the prefix removed from the keys.
+func (p *Properties) FilterStripPrefix(prefix string) *Properties {
+	pp := NewProperties()
+	n := len(prefix)
+	for _, k := range p.k {
+		if len(k) > len(prefix) && strings.HasPrefix(k, prefix) {
+			// TODO(fs): we are ignoring the error which flags a circular reference.
+			// TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference
+			// TODO(fs): this function should probably return an error but the signature is fixed
+			pp.Set(k[n:], p.m[k])
+		}
+	}
+	return pp
+}
+
+// Len returns the number of keys.
+func (p *Properties) Len() int {
+	return len(p.m)
+}
+
+// Keys returns all keys in the same order as in the input.
+func (p *Properties) Keys() []string {
+	keys := make([]string, len(p.k))
+	copy(keys, p.k)
+	return keys
+}
+
+// Set sets the property key to the corresponding value.
+// If a value for key existed before then ok is true and prev
+// contains the previous value. If the value contains a
+// circular reference or a malformed expression then
+// an error is returned.
+// An empty key is silently ignored.
+func (p *Properties) Set(key, value string) (prev string, ok bool, err error) {
+	if key == "" {
+		return "", false, nil
+	}
+
+	// if expansion is disabled we allow circular references
+	if p.DisableExpansion {
+		prev, ok = p.Get(key)
+		p.m[key] = value
+		if !ok {
+			p.k = append(p.k, key)
+		}
+		return prev, ok, nil
+	}
+
+	// to check for a circular reference we temporarily need
+	// to set the new value. If there is an error then revert
+	// to the previous state. Only if all tests are successful
+	// then we add the key to the p.k list.
+	prev, ok = p.Get(key)
+	p.m[key] = value
+
+	// now check for a circular reference
+	_, err = p.expand(key, value)
+	if err != nil {
+
+		// revert to the previous state
+		if ok {
+			p.m[key] = prev
+		} else {
+			delete(p.m, key)
+		}
+
+		return "", false, err
+	}
+
+	if !ok {
+		p.k = append(p.k, key)
+	}
+
+	return prev, ok, nil
+}
+
+// SetValue sets property key to the default string value
+// as defined by fmt.Sprintf("%v").
+func (p *Properties) SetValue(key string, value interface{}) error {
+	_, _, err := p.Set(key, fmt.Sprintf("%v", value))
+	return err
+}
+
+// MustSet sets the property key to the corresponding value.
+// If a value for key existed before then ok is true and prev
+// contains the previous value. An empty key is silently ignored.
+func (p *Properties) MustSet(key, value string) (prev string, ok bool) {
+	prev, ok, err := p.Set(key, value)
+	if err != nil {
+		ErrorHandler(err)
+	}
+	return prev, ok
+}
+
+// String returns a string of all expanded 'key = value' pairs.
+func (p *Properties) String() string {
+	var s string
+	for _, key := range p.k {
+		value, _ := p.Get(key)
+		s = fmt.Sprintf("%s%s = %s\n", s, key, value)
+	}
+	return s
+}
+
+// Sort sorts the properties keys in alphabetical order.
+// This is helpfully before writing the properties.
+func (p *Properties) Sort() {
+	sort.Strings(p.k)
+}
+
+// Write writes all unexpanded 'key = value' pairs to the given writer.
+// Write returns the number of bytes written and any write error encountered.
+func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) {
+	return p.WriteComment(w, "", enc)
+}
+
+// WriteComment writes all unexpanced 'key = value' pairs to the given writer.
+// If prefix is not empty then comments are written with a blank line and the
+// given prefix. The prefix should be either "# " or "! " to be compatible with
+// the properties file format. Otherwise, the properties parser will not be
+// able to read the file back in. It returns the number of bytes written and
+// any write error encountered.
+func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) {
+	var x int
+
+	for _, key := range p.k {
+		value := p.m[key]
+
+		if prefix != "" {
+			if comments, ok := p.c[key]; ok {
+				// don't print comments if they are all empty
+				allEmpty := true
+				for _, c := range comments {
+					if c != "" {
+						allEmpty = false
+						break
+					}
+				}
+
+				if !allEmpty {
+					// add a blank line between entries but not at the top
+					if len(comments) > 0 && n > 0 {
+						x, err = fmt.Fprintln(w)
+						if err != nil {
+							return
+						}
+						n += x
+					}
+
+					for _, c := range comments {
+						x, err = fmt.Fprintf(w, "%s%s\n", prefix, c)
+						if err != nil {
+							return
+						}
+						n += x
+					}
+				}
+			}
+		}
+		sep := " = "
+		if p.WriteSeparator != "" {
+			sep = p.WriteSeparator
+		}
+		x, err = fmt.Fprintf(w, "%s%s%s\n", encode(key, " :", enc), sep, encode(value, "", enc))
+		if err != nil {
+			return
+		}
+		n += x
+	}
+	return
+}
+
+// Map returns a copy of the properties as a map.
+func (p *Properties) Map() map[string]string {
+	m := make(map[string]string)
+	for k, v := range p.m {
+		m[k] = v
+	}
+	return m
+}
+
+// FilterFunc returns a copy of the properties which includes the values which passed all filters.
+func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties {
+	pp := NewProperties()
+outer:
+	for k, v := range p.m {
+		for _, f := range filters {
+			if !f(k, v) {
+				continue outer
+			}
+			pp.Set(k, v)
+		}
+	}
+	return pp
+}
+
+// ----------------------------------------------------------------------------
+
+// Delete removes the key and its comments.
+func (p *Properties) Delete(key string) {
+	delete(p.m, key)
+	delete(p.c, key)
+	newKeys := []string{}
+	for _, k := range p.k {
+		if k != key {
+			newKeys = append(newKeys, k)
+		}
+	}
+	p.k = newKeys
+}
+
+// Merge merges properties, comments and keys from other *Properties into p
+func (p *Properties) Merge(other *Properties) {
+	for _, k := range other.k {
+		if _, ok := p.m[k]; !ok {
+			p.k = append(p.k, k)
+		}
+	}
+	for k, v := range other.m {
+		p.m[k] = v
+	}
+	for k, v := range other.c {
+		p.c[k] = v
+	}
+}
+
+// ----------------------------------------------------------------------------
+
+// check expands all values and returns an error if a circular reference or
+// a malformed expression was found.
+func (p *Properties) check() error {
+	for key, value := range p.m {
+		if _, err := p.expand(key, value); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (p *Properties) expand(key, input string) (string, error) {
+	// no pre/postfix -> nothing to expand
+	if p.Prefix == "" && p.Postfix == "" {
+		return input, nil
+	}
+
+	return expand(input, []string{key}, p.Prefix, p.Postfix, p.m)
+}
+
+// expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values.
+// The function keeps track of the keys that were already expanded and stops if it
+// detects a circular reference or a malformed expression of the form '(prefix)key'.
+func expand(s string, keys []string, prefix, postfix string, values map[string]string) (string, error) {
+	if len(keys) > maxExpansionDepth {
+		return "", fmt.Errorf("expansion too deep")
+	}
+
+	for {
+		start := strings.Index(s, prefix)
+		if start == -1 {
+			return s, nil
+		}
+
+		keyStart := start + len(prefix)
+		keyLen := strings.Index(s[keyStart:], postfix)
+		if keyLen == -1 {
+			return "", fmt.Errorf("malformed expression")
+		}
+
+		end := keyStart + keyLen + len(postfix) - 1
+		key := s[keyStart : keyStart+keyLen]
+
+		// fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key)
+
+		for _, k := range keys {
+			if key == k {
+				var b bytes.Buffer
+				b.WriteString("circular reference in:\n")
+				for _, k1 := range keys {
+					fmt.Fprintf(&b, "%s=%s\n", k1, values[k1])
+				}
+				return "", fmt.Errorf(b.String())
+			}
+		}
+
+		val, ok := values[key]
+		if !ok {
+			val = os.Getenv(key)
+		}
+		new_val, err := expand(val, append(keys, key), prefix, postfix, values)
+		if err != nil {
+			return "", err
+		}
+		s = s[:start] + new_val + s[end+1:]
+	}
+}
+
+// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters.
+func encode(s string, special string, enc Encoding) string {
+	switch enc {
+	case UTF8:
+		return encodeUtf8(s, special)
+	case ISO_8859_1:
+		return encodeIso(s, special)
+	default:
+		panic(fmt.Sprintf("unsupported encoding %v", enc))
+	}
+}
+
+func encodeUtf8(s string, special string) string {
+	v := ""
+	for pos := 0; pos < len(s); {
+		r, w := utf8.DecodeRuneInString(s[pos:])
+		switch {
+		case pos == 0 && unicode.IsSpace(r): // escape leading whitespace
+			v += escape(r, " ")
+		default:
+			v += escape(r, special) // escape special chars only
+		}
+		pos += w
+	}
+	return v
+}
+
+func encodeIso(s string, special string) string {
+	var r rune
+	var w int
+	var v string
+	for pos := 0; pos < len(s); {
+		switch r, w = utf8.DecodeRuneInString(s[pos:]); {
+		case pos == 0 && unicode.IsSpace(r): // escape leading whitespace
+			v += escape(r, " ")
+		case r < 1<<8: // single byte rune -> escape special chars only
+			v += escape(r, special)
+		case r < 1<<16: // two byte rune -> unicode literal
+			v += fmt.Sprintf("\\u%04x", r)
+		default: // more than two bytes per rune -> can't encode
+			v += "?"
+		}
+		pos += w
+	}
+	return v
+}
+
+func escape(r rune, special string) string {
+	switch r {
+	case '\f':
+		return "\\f"
+	case '\n':
+		return "\\n"
+	case '\r':
+		return "\\r"
+	case '\t':
+		return "\\t"
+	case '\\':
+		return "\\\\"
+	default:
+		if strings.ContainsRune(special, r) {
+			return "\\" + string(r)
+		}
+		return string(r)
+	}
+}
+
+func invalidKeyError(key string) error {
+	return fmt.Errorf("unknown property: %s", key)
+}
diff --git a/vendor/github.com/magiconair/properties/rangecheck.go b/vendor/github.com/magiconair/properties/rangecheck.go
new file mode 100644
index 000000000..dbd60b36e
--- /dev/null
+++ b/vendor/github.com/magiconair/properties/rangecheck.go
@@ -0,0 +1,31 @@
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package properties
+
+import (
+	"fmt"
+	"math"
+)
+
+// make this a var to overwrite it in a test
+var is32Bit = ^uint(0) == math.MaxUint32
+
+// intRangeCheck checks if the value fits into the int type and
+// panics if it does not.
+func intRangeCheck(key string, v int64) int {
+	if is32Bit && (v < math.MinInt32 || v > math.MaxInt32) {
+		panic(fmt.Sprintf("Value %d for key %s out of range", v, key))
+	}
+	return int(v)
+}
+
+// uintRangeCheck checks if the value fits into the uint type and
+// panics if it does not.
+func uintRangeCheck(key string, v uint64) uint {
+	if is32Bit && v > math.MaxUint32 {
+		panic(fmt.Sprintf("Value %d for key %s out of range", v, key))
+	}
+	return uint(v)
+}
diff --git a/vendor/github.com/moby/docker-image-spec/LICENSE b/vendor/github.com/moby/docker-image-spec/LICENSE
new file mode 100644
index 000000000..261eeb9e9
--- /dev/null
+++ b/vendor/github.com/moby/docker-image-spec/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/moby/docker-image-spec/specs-go/v1/image.go b/vendor/github.com/moby/docker-image-spec/specs-go/v1/image.go
new file mode 100644
index 000000000..167261763
--- /dev/null
+++ b/vendor/github.com/moby/docker-image-spec/specs-go/v1/image.go
@@ -0,0 +1,54 @@
+package v1
+
+import (
+	"time"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+const DockerOCIImageMediaType = "application/vnd.docker.container.image.v1+json"
+
+// DockerOCIImage is a ocispec.Image extended with Docker specific Config.
+type DockerOCIImage struct {
+	ocispec.Image
+
+	// Shadow ocispec.Image.Config
+	Config DockerOCIImageConfig `json:"config,omitempty"`
+}
+
+// DockerOCIImageConfig is a ocispec.ImageConfig extended with Docker specific fields.
+type DockerOCIImageConfig struct {
+	ocispec.ImageConfig
+
+	DockerOCIImageConfigExt
+}
+
+// DockerOCIImageConfigExt contains Docker-specific fields in DockerImageConfig.
+type DockerOCIImageConfigExt struct {
+	Healthcheck *HealthcheckConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
+
+	OnBuild []string `json:",omitempty"` // ONBUILD metadata that were defined on the image Dockerfile
+	Shell   []string `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
+}
+
+// HealthcheckConfig holds configuration settings for the HEALTHCHECK feature.
+type HealthcheckConfig struct {
+	// Test is the test to perform to check that the container is healthy.
+	// An empty slice means to inherit the default.
+	// The options are:
+	// {} : inherit healthcheck
+	// {"NONE"} : disable healthcheck
+	// {"CMD", args...} : exec arguments directly
+	// {"CMD-SHELL", command} : run command with system's default shell
+	Test []string `json:",omitempty"`
+
+	// Zero means to inherit. Durations are expressed as integer nanoseconds.
+	Interval      time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
+	Timeout       time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
+	StartPeriod   time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down.
+	StartInterval time.Duration `json:",omitempty"` // The interval to attempt healthchecks at during the start period
+
+	// Retries is the number of consecutive failures needed to consider a container as unhealthy.
+	// Zero means inherit.
+	Retries int `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/go-archive/.gitattributes b/vendor/github.com/moby/go-archive/.gitattributes
new file mode 100644
index 000000000..4bb139d90
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/.gitattributes
@@ -0,0 +1,2 @@
+*.go -text diff=golang
+*.go text eol=lf
diff --git a/vendor/github.com/moby/go-archive/.gitignore b/vendor/github.com/moby/go-archive/.gitignore
new file mode 100644
index 000000000..3f2bc4741
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/.gitignore
@@ -0,0 +1 @@
+/coverage.txt
diff --git a/vendor/github.com/moby/go-archive/.golangci.yml b/vendor/github.com/moby/go-archive/.golangci.yml
new file mode 100644
index 000000000..21439e5c6
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/.golangci.yml
@@ -0,0 +1,33 @@
+version: "2"
+
+issues:
+  # Disable maximum issues count per one linter.
+  max-issues-per-linter: 0
+  # Disable maximum count of issues with the same text.
+  max-same-issues: 0
+
+linters:
+  enable:
+    - errorlint
+    - unconvert
+    - unparam
+  exclusions:
+    generated: disable
+    presets:
+      - comments
+      - std-error-handling
+  settings:
+    staticcheck:
+      # Enable all options, with some exceptions.
+      # For defaults, see https://golangci-lint.run/usage/linters/#staticcheck
+      checks:
+        - all
+        - -QF1008     # Omit embedded fields from selector expression; https://staticcheck.dev/docs/checks/#QF1008
+        - -ST1003     # Poorly chosen identifier; https://staticcheck.dev/docs/checks/#ST1003
+
+formatters:
+  enable:
+    - gofumpt
+    - goimports
+  exclusions:
+    generated: disable
diff --git a/vendor/github.com/moby/go-archive/LICENSE b/vendor/github.com/moby/go-archive/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/moby/go-archive/archive.go b/vendor/github.com/moby/go-archive/archive.go
new file mode 100644
index 000000000..8dce2e6e2
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/archive.go
@@ -0,0 +1,1129 @@
+// Package archive provides helper functions for dealing with archive files.
+package archive
+
+import (
+	"archive/tar"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"syscall"
+	"time"
+
+	"github.com/containerd/log"
+	"github.com/moby/patternmatcher"
+	"github.com/moby/sys/sequential"
+	"github.com/moby/sys/user"
+
+	"github.com/moby/go-archive/compression"
+	"github.com/moby/go-archive/tarheader"
+)
+
+// ImpliedDirectoryMode represents the mode (Unix permissions) applied to directories that are implied by files in a
+// tar, but that do not have their own header entry.
+//
+// The permissions mask is stored in a constant instead of locally to ensure that magic numbers do not
+// proliferate in the codebase. The default value 0755 has been selected based on the default umask of 0022, and
+// a convention of mkdir(1) calling mkdir(2) with permissions of 0777, resulting in a final value of 0755.
+//
+// This value is currently implementation-defined, and not captured in any cross-runtime specification. Thus, it is
+// subject to change in Moby at any time -- image authors who require consistent or known directory permissions
+// should explicitly control them by ensuring that header entries exist for any applicable path.
+const ImpliedDirectoryMode = 0o755
+
+type (
+	// WhiteoutFormat is the format of whiteouts unpacked
+	WhiteoutFormat int
+
+	ChownOpts struct {
+		UID int
+		GID int
+	}
+
+	// TarOptions wraps the tar options.
+	TarOptions struct {
+		IncludeFiles     []string
+		ExcludePatterns  []string
+		Compression      compression.Compression
+		NoLchown         bool
+		IDMap            user.IdentityMapping
+		ChownOpts        *ChownOpts
+		IncludeSourceDir bool
+		// WhiteoutFormat is the expected on disk format for whiteout files.
+		// This format will be converted to the standard format on pack
+		// and from the standard format on unpack.
+		WhiteoutFormat WhiteoutFormat
+		// When unpacking, specifies whether overwriting a directory with a
+		// non-directory is allowed and vice versa.
+		NoOverwriteDirNonDir bool
+		// For each include when creating an archive, the included name will be
+		// replaced with the matching name from this map.
+		RebaseNames map[string]string
+		InUserNS    bool
+		// Allow unpacking to succeed in spite of failures to set extended
+		// attributes on the unpacked files due to the destination filesystem
+		// not supporting them or a lack of permissions. Extended attributes
+		// were probably in the archive for a reason, so set this option at
+		// your own peril.
+		BestEffortXattrs bool
+	}
+)
+
+// Archiver implements the Archiver interface and allows the reuse of most utility functions of
+// this package with a pluggable Untar function. Also, to facilitate the passing of specific id
+// mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations.
+type Archiver struct {
+	Untar     func(io.Reader, string, *TarOptions) error
+	IDMapping user.IdentityMapping
+}
+
+// NewDefaultArchiver returns a new Archiver without any IdentityMapping
+func NewDefaultArchiver() *Archiver {
+	return &Archiver{Untar: Untar}
+}
+
+// breakoutError is used to differentiate errors related to breaking out
+// When testing archive breakout in the unit tests, this error is expected
+// in order for the test to pass.
+type breakoutError error
+
+const (
+	AUFSWhiteoutFormat    WhiteoutFormat = 0 // AUFSWhiteoutFormat is the default format for whiteouts
+	OverlayWhiteoutFormat WhiteoutFormat = 1 // OverlayWhiteoutFormat formats whiteout according to the overlay standard.
+)
+
+// IsArchivePath checks if the (possibly compressed) file at the given path
+// starts with a tar file header.
+func IsArchivePath(path string) bool {
+	file, err := os.Open(path)
+	if err != nil {
+		return false
+	}
+	defer file.Close()
+	rdr, err := compression.DecompressStream(file)
+	if err != nil {
+		return false
+	}
+	defer rdr.Close()
+	r := tar.NewReader(rdr)
+	_, err = r.Next()
+	return err == nil
+}
+
+// TarModifierFunc is a function that can be passed to ReplaceFileTarWrapper to
+// modify the contents or header of an entry in the archive. If the file already
+// exists in the archive the TarModifierFunc will be called with the Header and
+// a reader which will return the files content. If the file does not exist both
+// header and content will be nil.
+type TarModifierFunc func(path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error)
+
+// ReplaceFileTarWrapper converts inputTarStream to a new tar stream. Files in the
+// tar stream are modified if they match any of the keys in mods.
+func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModifierFunc) io.ReadCloser {
+	pipeReader, pipeWriter := io.Pipe()
+
+	go func() {
+		tarReader := tar.NewReader(inputTarStream)
+		tarWriter := tar.NewWriter(pipeWriter)
+		defer inputTarStream.Close()
+		defer tarWriter.Close()
+
+		modify := func(name string, original *tar.Header, modifier TarModifierFunc, tarReader io.Reader) error {
+			header, data, err := modifier(name, original, tarReader)
+			switch {
+			case err != nil:
+				return err
+			case header == nil:
+				return nil
+			}
+
+			if header.Name == "" {
+				header.Name = name
+			}
+			header.Size = int64(len(data))
+			if err := tarWriter.WriteHeader(header); err != nil {
+				return err
+			}
+			if len(data) != 0 {
+				if _, err := tarWriter.Write(data); err != nil {
+					return err
+				}
+			}
+			return nil
+		}
+
+		var err error
+		var originalHeader *tar.Header
+		for {
+			originalHeader, err = tarReader.Next()
+			if errors.Is(err, io.EOF) {
+				break
+			}
+			if err != nil {
+				pipeWriter.CloseWithError(err)
+				return
+			}
+
+			modifier, ok := mods[originalHeader.Name]
+			if !ok {
+				// No modifiers for this file, copy the header and data
+				if err := tarWriter.WriteHeader(originalHeader); err != nil {
+					pipeWriter.CloseWithError(err)
+					return
+				}
+				if err := copyWithBuffer(tarWriter, tarReader); err != nil {
+					pipeWriter.CloseWithError(err)
+					return
+				}
+				continue
+			}
+			delete(mods, originalHeader.Name)
+
+			if err := modify(originalHeader.Name, originalHeader, modifier, tarReader); err != nil {
+				pipeWriter.CloseWithError(err)
+				return
+			}
+		}
+
+		// Apply the modifiers that haven't matched any files in the archive
+		for name, modifier := range mods {
+			if err := modify(name, nil, modifier, nil); err != nil {
+				pipeWriter.CloseWithError(err)
+				return
+			}
+		}
+
+		pipeWriter.Close()
+	}()
+	return pipeReader
+}
+
+// FileInfoHeader creates a populated Header from fi.
+//
+// Compared to the archive/tar package, this function fills in less information
+// but is safe to call from a chrooted process. The AccessTime and ChangeTime
+// fields are not set in the returned header, ModTime is truncated to one-second
+// precision, and the Uname and Gname fields are only set when fi is a FileInfo
+// value returned from tar.Header.FileInfo().
+func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, error) {
+	hdr, err := tarheader.FileInfoHeaderNoLookups(fi, link)
+	if err != nil {
+		return nil, err
+	}
+	hdr.Format = tar.FormatPAX
+	hdr.ModTime = hdr.ModTime.Truncate(time.Second)
+	hdr.AccessTime = time.Time{}
+	hdr.ChangeTime = time.Time{}
+	hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
+	hdr.Name = canonicalTarName(name, fi.IsDir())
+	return hdr, nil
+}
+
+const paxSchilyXattr = "SCHILY.xattr."
+
+// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
+// to a tar header
+func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
+	const (
+		// Values based on linux/include/uapi/linux/capability.h
+		xattrCapsSz2    = 20
+		versionOffset   = 3
+		vfsCapRevision2 = 2
+		vfsCapRevision3 = 3
+	)
+	capability, _ := lgetxattr(path, "security.capability")
+	if capability != nil {
+		if capability[versionOffset] == vfsCapRevision3 {
+			// Convert VFS_CAP_REVISION_3 to VFS_CAP_REVISION_2 as root UID makes no
+			// sense outside the user namespace the archive is built in.
+			capability[versionOffset] = vfsCapRevision2
+			capability = capability[:xattrCapsSz2]
+		}
+		if hdr.PAXRecords == nil {
+			hdr.PAXRecords = make(map[string]string)
+		}
+		hdr.PAXRecords[paxSchilyXattr+"security.capability"] = string(capability)
+	}
+	return nil
+}
+
+type tarWhiteoutConverter interface {
+	ConvertWrite(*tar.Header, string, os.FileInfo) (*tar.Header, error)
+	ConvertRead(*tar.Header, string) (bool, error)
+}
+
+type tarAppender struct {
+	TarWriter *tar.Writer
+
+	// for hardlink mapping
+	SeenFiles       map[uint64]string
+	IdentityMapping user.IdentityMapping
+	ChownOpts       *ChownOpts
+
+	// For packing and unpacking whiteout files in the
+	// non standard format. The whiteout files defined
+	// by the AUFS standard are used as the tar whiteout
+	// standard.
+	WhiteoutConverter tarWhiteoutConverter
+}
+
+func newTarAppender(idMapping user.IdentityMapping, writer io.Writer, chownOpts *ChownOpts) *tarAppender {
+	return &tarAppender{
+		SeenFiles:       make(map[uint64]string),
+		TarWriter:       tar.NewWriter(writer),
+		IdentityMapping: idMapping,
+		ChownOpts:       chownOpts,
+	}
+}
+
+// canonicalTarName provides a platform-independent and consistent POSIX-style
+// path for files and directories to be archived regardless of the platform.
+func canonicalTarName(name string, isDir bool) string {
+	name = filepath.ToSlash(name)
+
+	// suffix with '/' for directories
+	if isDir && !strings.HasSuffix(name, "/") {
+		name += "/"
+	}
+	return name
+}
+
+// addTarFile adds to the tar archive a file from `path` as `name`
+func (ta *tarAppender) addTarFile(path, name string) error {
+	fi, err := os.Lstat(path)
+	if err != nil {
+		return err
+	}
+
+	var link string
+	if fi.Mode()&os.ModeSymlink != 0 {
+		var err error
+		link, err = os.Readlink(path)
+		if err != nil {
+			return err
+		}
+	}
+
+	hdr, err := FileInfoHeader(name, fi, link)
+	if err != nil {
+		return err
+	}
+	if err := ReadSecurityXattrToTarHeader(path, hdr); err != nil {
+		return err
+	}
+
+	// if it's not a directory and has more than 1 link,
+	// it's hard linked, so set the type flag accordingly
+	if !fi.IsDir() && hasHardlinks(fi) {
+		inode, err := getInodeFromStat(fi.Sys())
+		if err != nil {
+			return err
+		}
+		// a link should have a name that it links too
+		// and that linked name should be first in the tar archive
+		if oldpath, ok := ta.SeenFiles[inode]; ok {
+			hdr.Typeflag = tar.TypeLink
+			hdr.Linkname = oldpath
+			hdr.Size = 0 // This Must be here for the writer math to add up!
+		} else {
+			ta.SeenFiles[inode] = name
+		}
+	}
+
+	// check whether the file is overlayfs whiteout
+	// if yes, skip re-mapping container ID mappings.
+	isOverlayWhiteout := fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0
+
+	// handle re-mapping container ID mappings back to host ID mappings before
+	// writing tar headers/files. We skip whiteout files because they were written
+	// by the kernel and already have proper ownership relative to the host
+	if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
+		uid, gid, err := getFileUIDGID(fi.Sys())
+		if err != nil {
+			return err
+		}
+		hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(uid, gid)
+		if err != nil {
+			return err
+		}
+	}
+
+	// explicitly override with ChownOpts
+	if ta.ChownOpts != nil {
+		hdr.Uid = ta.ChownOpts.UID
+		hdr.Gid = ta.ChownOpts.GID
+	}
+
+	if ta.WhiteoutConverter != nil {
+		wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, path, fi)
+		if err != nil {
+			return err
+		}
+
+		// If a new whiteout file exists, write original hdr, then
+		// replace hdr with wo to be written after. Whiteouts should
+		// always be written after the original. Note the original
+		// hdr may have been updated to be a whiteout with returning
+		// a whiteout header
+		if wo != nil {
+			if err := ta.TarWriter.WriteHeader(hdr); err != nil {
+				return err
+			}
+			if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
+				return fmt.Errorf("tar: cannot use whiteout for non-empty file")
+			}
+			hdr = wo
+		}
+	}
+
+	if err := ta.TarWriter.WriteHeader(hdr); err != nil {
+		return err
+	}
+
+	if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
+		// We use sequential file access to avoid depleting the standby list on
+		// Windows. On Linux, this equates to a regular os.Open.
+		file, err := sequential.Open(path)
+		if err != nil {
+			return err
+		}
+
+		err = copyWithBuffer(ta.TarWriter, file)
+		file.Close()
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, opts *TarOptions) error {
+	var (
+		Lchown                     = true
+		inUserns, bestEffortXattrs bool
+		chownOpts                  *ChownOpts
+	)
+
+	// TODO(thaJeztah): make opts a required argument.
+	if opts != nil {
+		Lchown = !opts.NoLchown
+		inUserns = opts.InUserNS // TODO(thaJeztah): consider deprecating opts.InUserNS and detect locally.
+		chownOpts = opts.ChownOpts
+		bestEffortXattrs = opts.BestEffortXattrs
+	}
+
+	// hdr.Mode is in linux format, which we can use for sycalls,
+	// but for os.Foo() calls we need the mode converted to os.FileMode,
+	// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
+	hdrInfo := hdr.FileInfo()
+
+	switch hdr.Typeflag {
+	case tar.TypeDir:
+		// Create directory unless it exists as a directory already.
+		// In that case we just want to merge the two
+		if fi, err := os.Lstat(path); err != nil || !fi.IsDir() {
+			if err := os.Mkdir(path, hdrInfo.Mode()); err != nil {
+				return err
+			}
+		}
+
+	case tar.TypeReg:
+		// Source is regular file. We use sequential file access to avoid depleting
+		// the standby list on Windows. On Linux, this equates to a regular os.OpenFile.
+		file, err := sequential.OpenFile(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode())
+		if err != nil {
+			return err
+		}
+		if err := copyWithBuffer(file, reader); err != nil {
+			_ = file.Close()
+			return err
+		}
+		_ = file.Close()
+
+	case tar.TypeBlock, tar.TypeChar:
+		if inUserns { // cannot create devices in a userns
+			log.G(context.TODO()).WithFields(log.Fields{"path": path, "type": hdr.Typeflag}).Debug("skipping device nodes in a userns")
+			return nil
+		}
+		// Handle this is an OS-specific way
+		if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
+			return err
+		}
+
+	case tar.TypeFifo:
+		// Handle this is an OS-specific way
+		if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
+			if inUserns && errors.Is(err, syscall.EPERM) {
+				// In most cases, cannot create a fifo if running in user namespace
+				log.G(context.TODO()).WithFields(log.Fields{"error": err, "path": path, "type": hdr.Typeflag}).Debug("creating fifo node in a userns")
+				return nil
+			}
+			return err
+		}
+
+	case tar.TypeLink:
+		// #nosec G305 -- The target path is checked for path traversal.
+		targetPath := filepath.Join(extractDir, hdr.Linkname)
+		// check for hardlink breakout
+		if !strings.HasPrefix(targetPath, extractDir) {
+			return breakoutError(fmt.Errorf("invalid hardlink %q -> %q", targetPath, hdr.Linkname))
+		}
+		if err := os.Link(targetPath, path); err != nil {
+			return err
+		}
+
+	case tar.TypeSymlink:
+		// 	path 				-> hdr.Linkname = targetPath
+		// e.g. /extractDir/path/to/symlink 	-> ../2/file	= /extractDir/path/2/file
+		targetPath := filepath.Join(filepath.Dir(path), hdr.Linkname) // #nosec G305 -- The target path is checked for path traversal.
+
+		// the reason we don't need to check symlinks in the path (with FollowSymlinkInScope) is because
+		// that symlink would first have to be created, which would be caught earlier, at this very check:
+		if !strings.HasPrefix(targetPath, extractDir) {
+			return breakoutError(fmt.Errorf("invalid symlink %q -> %q", path, hdr.Linkname))
+		}
+		if err := os.Symlink(hdr.Linkname, path); err != nil {
+			return err
+		}
+
+	case tar.TypeXGlobalHeader:
+		log.G(context.TODO()).Debug("PAX Global Extended Headers found and ignored")
+		return nil
+
+	default:
+		return fmt.Errorf("unhandled tar header type %d", hdr.Typeflag)
+	}
+
+	// Lchown is not supported on Windows.
+	if Lchown && runtime.GOOS != "windows" {
+		if chownOpts == nil {
+			chownOpts = &ChownOpts{UID: hdr.Uid, GID: hdr.Gid}
+		}
+		if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
+			var msg string
+			if inUserns && errors.Is(err, syscall.EINVAL) {
+				msg = " (try increasing the number of subordinate IDs in /etc/subuid and /etc/subgid)"
+			}
+			return fmt.Errorf("failed to Lchown %q for UID %d, GID %d%s: %w", path, hdr.Uid, hdr.Gid, msg, err)
+		}
+	}
+
+	var xattrErrs []string
+	for key, value := range hdr.PAXRecords {
+		xattr, ok := strings.CutPrefix(key, paxSchilyXattr)
+		if !ok {
+			continue
+		}
+		if err := lsetxattr(path, xattr, []byte(value), 0); err != nil {
+			if bestEffortXattrs && errors.Is(err, syscall.ENOTSUP) || errors.Is(err, syscall.EPERM) {
+				// EPERM occurs if modifying xattrs is not allowed. This can
+				// happen when running in userns with restrictions (ChromeOS).
+				xattrErrs = append(xattrErrs, err.Error())
+				continue
+			}
+			return err
+		}
+	}
+
+	if len(xattrErrs) > 0 {
+		log.G(context.TODO()).WithFields(log.Fields{
+			"errors": xattrErrs,
+		}).Warn("ignored xattrs in archive: underlying filesystem doesn't support them")
+	}
+
+	// There is no LChmod, so ignore mode for symlink. Also, this
+	// must happen after chown, as that can modify the file mode
+	if err := handleLChmod(hdr, path, hdrInfo); err != nil {
+		return err
+	}
+
+	aTime := boundTime(latestTime(hdr.AccessTime, hdr.ModTime))
+	mTime := boundTime(hdr.ModTime)
+
+	// chtimes doesn't support a NOFOLLOW flag atm
+	if hdr.Typeflag == tar.TypeLink {
+		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
+			if err := chtimes(path, aTime, mTime); err != nil {
+				return err
+			}
+		}
+	} else if hdr.Typeflag != tar.TypeSymlink {
+		if err := chtimes(path, aTime, mTime); err != nil {
+			return err
+		}
+	} else {
+		if err := lchtimes(path, aTime, mTime); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// Tar creates an archive from the directory at `path`, and returns it as a
+// stream of bytes.
+func Tar(path string, comp compression.Compression) (io.ReadCloser, error) {
+	return TarWithOptions(path, &TarOptions{Compression: comp})
+}
+
+// TarWithOptions creates an archive from the directory at `path`, only including files whose relative
+// paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`.
+func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
+	tb, err := NewTarballer(srcPath, options)
+	if err != nil {
+		return nil, err
+	}
+	go tb.Do()
+	return tb.Reader(), nil
+}
+
+// Tarballer is a lower-level interface to TarWithOptions which gives the caller
+// control over which goroutine the archiving operation executes on.
+type Tarballer struct {
+	srcPath           string
+	options           *TarOptions
+	pm                *patternmatcher.PatternMatcher
+	pipeReader        *io.PipeReader
+	pipeWriter        *io.PipeWriter
+	compressWriter    io.WriteCloser
+	whiteoutConverter tarWhiteoutConverter
+}
+
+// NewTarballer constructs a new tarballer. The arguments are the same as for
+// TarWithOptions.
+func NewTarballer(srcPath string, options *TarOptions) (*Tarballer, error) {
+	pm, err := patternmatcher.New(options.ExcludePatterns)
+	if err != nil {
+		return nil, err
+	}
+
+	pipeReader, pipeWriter := io.Pipe()
+
+	compressWriter, err := compression.CompressStream(pipeWriter, options.Compression)
+	if err != nil {
+		return nil, err
+	}
+
+	return &Tarballer{
+		// Fix the source path to work with long path names. This is a no-op
+		// on platforms other than Windows.
+		srcPath:           addLongPathPrefix(srcPath),
+		options:           options,
+		pm:                pm,
+		pipeReader:        pipeReader,
+		pipeWriter:        pipeWriter,
+		compressWriter:    compressWriter,
+		whiteoutConverter: getWhiteoutConverter(options.WhiteoutFormat),
+	}, nil
+}
+
+// Reader returns the reader for the created archive.
+func (t *Tarballer) Reader() io.ReadCloser {
+	return t.pipeReader
+}
+
+// Do performs the archiving operation in the background. The resulting archive
+// can be read from t.Reader(). Do should only be called once on each Tarballer
+// instance.
+func (t *Tarballer) Do() {
+	ta := newTarAppender(
+		t.options.IDMap,
+		t.compressWriter,
+		t.options.ChownOpts,
+	)
+	ta.WhiteoutConverter = t.whiteoutConverter
+
+	defer func() {
+		// Make sure to check the error on Close.
+		if err := ta.TarWriter.Close(); err != nil {
+			log.G(context.TODO()).Errorf("Can't close tar writer: %s", err)
+		}
+		if err := t.compressWriter.Close(); err != nil {
+			log.G(context.TODO()).Errorf("Can't close compress writer: %s", err)
+		}
+		if err := t.pipeWriter.Close(); err != nil {
+			log.G(context.TODO()).Errorf("Can't close pipe writer: %s", err)
+		}
+	}()
+
+	// In general we log errors here but ignore them because
+	// during e.g. a diff operation the container can continue
+	// mutating the filesystem and we can see transient errors
+	// from this
+
+	stat, err := os.Lstat(t.srcPath)
+	if err != nil {
+		return
+	}
+
+	if !stat.IsDir() {
+		// We can't later join a non-dir with any includes because the
+		// 'walk' will error if "file/." is stat-ed and "file" is not a
+		// directory. So, we must split the source path and use the
+		// basename as the include.
+		if len(t.options.IncludeFiles) > 0 {
+			log.G(context.TODO()).Warn("Tar: Can't archive a file with includes")
+		}
+
+		dir, base := SplitPathDirEntry(t.srcPath)
+		t.srcPath = dir
+		t.options.IncludeFiles = []string{base}
+	}
+
+	if len(t.options.IncludeFiles) == 0 {
+		t.options.IncludeFiles = []string{"."}
+	}
+
+	seen := make(map[string]bool)
+
+	for _, include := range t.options.IncludeFiles {
+		rebaseName := t.options.RebaseNames[include]
+
+		var (
+			parentMatchInfo []patternmatcher.MatchInfo
+			parentDirs      []string
+		)
+
+		walkRoot := getWalkRoot(t.srcPath, include)
+		// TODO(thaJeztah): should this error be handled?
+		_ = filepath.WalkDir(walkRoot, func(filePath string, f os.DirEntry, err error) error {
+			if err != nil {
+				log.G(context.TODO()).Errorf("Tar: Can't stat file %s to tar: %s", t.srcPath, err)
+				return nil
+			}
+
+			relFilePath, err := filepath.Rel(t.srcPath, filePath)
+			if err != nil || (!t.options.IncludeSourceDir && relFilePath == "." && f.IsDir()) {
+				// Error getting relative path OR we are looking
+				// at the source directory path. Skip in both situations.
+				return nil
+			}
+
+			if t.options.IncludeSourceDir && include == "." && relFilePath != "." {
+				relFilePath = strings.Join([]string{".", relFilePath}, string(filepath.Separator))
+			}
+
+			skip := false
+
+			// If "include" is an exact match for the current file
+			// then even if there's an "excludePatterns" pattern that
+			// matches it, don't skip it. IOW, assume an explicit 'include'
+			// is asking for that file no matter what - which is true
+			// for some files, like .dockerignore and Dockerfile (sometimes)
+			if include != relFilePath {
+				for len(parentDirs) != 0 {
+					lastParentDir := parentDirs[len(parentDirs)-1]
+					if strings.HasPrefix(relFilePath, lastParentDir+string(os.PathSeparator)) {
+						break
+					}
+					parentDirs = parentDirs[:len(parentDirs)-1]
+					parentMatchInfo = parentMatchInfo[:len(parentMatchInfo)-1]
+				}
+
+				var matchInfo patternmatcher.MatchInfo
+				if len(parentMatchInfo) != 0 {
+					skip, matchInfo, err = t.pm.MatchesUsingParentResults(relFilePath, parentMatchInfo[len(parentMatchInfo)-1])
+				} else {
+					skip, matchInfo, err = t.pm.MatchesUsingParentResults(relFilePath, patternmatcher.MatchInfo{})
+				}
+				if err != nil {
+					log.G(context.TODO()).Errorf("Error matching %s: %v", relFilePath, err)
+					return err
+				}
+
+				if f.IsDir() {
+					parentDirs = append(parentDirs, relFilePath)
+					parentMatchInfo = append(parentMatchInfo, matchInfo)
+				}
+			}
+
+			if skip {
+				// If we want to skip this file and its a directory
+				// then we should first check to see if there's an
+				// excludes pattern (e.g. !dir/file) that starts with this
+				// dir. If so then we can't skip this dir.
+
+				// Its not a dir then so we can just return/skip.
+				if !f.IsDir() {
+					return nil
+				}
+
+				// No exceptions (!...) in patterns so just skip dir
+				if !t.pm.Exclusions() {
+					return filepath.SkipDir
+				}
+
+				dirSlash := relFilePath + string(filepath.Separator)
+
+				for _, pat := range t.pm.Patterns() {
+					if !pat.Exclusion() {
+						continue
+					}
+					if strings.HasPrefix(pat.String()+string(filepath.Separator), dirSlash) {
+						// found a match - so can't skip this dir
+						return nil
+					}
+				}
+
+				// No matching exclusion dir so just skip dir
+				return filepath.SkipDir
+			}
+
+			if seen[relFilePath] {
+				return nil
+			}
+			seen[relFilePath] = true
+
+			// Rename the base resource.
+			if rebaseName != "" {
+				var replacement string
+				if rebaseName != string(filepath.Separator) {
+					// Special case the root directory to replace with an
+					// empty string instead so that we don't end up with
+					// double slashes in the paths.
+					replacement = rebaseName
+				}
+
+				relFilePath = strings.Replace(relFilePath, include, replacement, 1)
+			}
+
+			if err := ta.addTarFile(filePath, relFilePath); err != nil {
+				log.G(context.TODO()).Errorf("Can't add file %s to tar: %s", filePath, err)
+				// if pipe is broken, stop writing tar stream to it
+				if errors.Is(err, io.ErrClosedPipe) {
+					return err
+				}
+			}
+			return nil
+		})
+	}
+}
+
+// Unpack unpacks the decompressedArchive to dest with options.
+func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) error {
+	tr := tar.NewReader(decompressedArchive)
+
+	var dirs []*tar.Header
+	whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
+
+	// Iterate through the files in the archive.
+loop:
+	for {
+		hdr, err := tr.Next()
+		if errors.Is(err, io.EOF) {
+			// end of tar archive
+			break
+		}
+		if err != nil {
+			return err
+		}
+
+		// ignore XGlobalHeader early to avoid creating parent directories for them
+		if hdr.Typeflag == tar.TypeXGlobalHeader {
+			log.G(context.TODO()).Debugf("PAX Global Extended Headers found for %s and ignored", hdr.Name)
+			continue
+		}
+
+		// Normalize name, for safety and for a simple is-root check
+		// This keeps "../" as-is, but normalizes "/../" to "/". Or Windows:
+		// This keeps "..\" as-is, but normalizes "\..\" to "\".
+		hdr.Name = filepath.Clean(hdr.Name)
+
+		for _, exclude := range options.ExcludePatterns {
+			if strings.HasPrefix(hdr.Name, exclude) {
+				continue loop
+			}
+		}
+
+		// Ensure that the parent directory exists.
+		err = createImpliedDirectories(dest, hdr, options)
+		if err != nil {
+			return err
+		}
+
+		// #nosec G305 -- The joined path is checked for path traversal.
+		path := filepath.Join(dest, hdr.Name)
+		rel, err := filepath.Rel(dest, path)
+		if err != nil {
+			return err
+		}
+		if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
+			return breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
+		}
+
+		// If path exits we almost always just want to remove and replace it
+		// The only exception is when it is a directory *and* the file from
+		// the layer is also a directory. Then we want to merge them (i.e.
+		// just apply the metadata from the layer).
+		if fi, err := os.Lstat(path); err == nil {
+			if options.NoOverwriteDirNonDir && fi.IsDir() && hdr.Typeflag != tar.TypeDir {
+				// If NoOverwriteDirNonDir is true then we cannot replace
+				// an existing directory with a non-directory from the archive.
+				return fmt.Errorf("cannot overwrite directory %q with non-directory %q", path, dest)
+			}
+
+			if options.NoOverwriteDirNonDir && !fi.IsDir() && hdr.Typeflag == tar.TypeDir {
+				// If NoOverwriteDirNonDir is true then we cannot replace
+				// an existing non-directory with a directory from the archive.
+				return fmt.Errorf("cannot overwrite non-directory %q with directory %q", path, dest)
+			}
+
+			if fi.IsDir() && hdr.Name == "." {
+				continue
+			}
+
+			if !fi.IsDir() || hdr.Typeflag != tar.TypeDir {
+				if err := os.RemoveAll(path); err != nil {
+					return err
+				}
+			}
+		}
+
+		if err := remapIDs(options.IDMap, hdr); err != nil {
+			return err
+		}
+
+		if whiteoutConverter != nil {
+			writeFile, err := whiteoutConverter.ConvertRead(hdr, path)
+			if err != nil {
+				return err
+			}
+			if !writeFile {
+				continue
+			}
+		}
+
+		if err := createTarFile(path, dest, hdr, tr, options); err != nil {
+			return err
+		}
+
+		// Directory mtimes must be handled at the end to avoid further
+		// file creation in them to modify the directory mtime
+		if hdr.Typeflag == tar.TypeDir {
+			dirs = append(dirs, hdr)
+		}
+	}
+
+	for _, hdr := range dirs {
+		// #nosec G305 -- The header was checked for path traversal before it was appended to the dirs slice.
+		path := filepath.Join(dest, hdr.Name)
+
+		if err := chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime)); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// createImpliedDirectories will create all parent directories of the current path with default permissions, if they do
+// not already exist. This is possible as the tar format supports 'implicit' directories, where their existence is
+// defined by the paths of files in the tar, but there are no header entries for the directories themselves, and thus
+// we most both create them and choose metadata like permissions.
+//
+// The caller should have performed filepath.Clean(hdr.Name), so hdr.Name will now be in the filepath format for the OS
+// on which the daemon is running. This precondition is required because this function assumes a OS-specific path
+// separator when checking that a path is not the root.
+func createImpliedDirectories(dest string, hdr *tar.Header, options *TarOptions) error {
+	// Not the root directory, ensure that the parent directory exists
+	if !strings.HasSuffix(hdr.Name, string(os.PathSeparator)) {
+		parent := filepath.Dir(hdr.Name)
+		parentPath := filepath.Join(dest, parent)
+		if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
+			// RootPair() is confined inside this loop as most cases will not require a call, so we can spend some
+			// unneeded function calls in the uncommon case to encapsulate logic -- implied directories are a niche
+			// usage that reduces the portability of an image.
+			uid, gid := options.IDMap.RootPair()
+
+			err = user.MkdirAllAndChown(parentPath, ImpliedDirectoryMode, uid, gid, user.WithOnlyNew)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+// Untar reads a stream of bytes from `archive`, parses it as a tar archive,
+// and unpacks it into the directory at `dest`.
+// The archive may be compressed with one of the following algorithms:
+// identity (uncompressed), gzip, bzip2, xz.
+//
+// FIXME: specify behavior when target path exists vs. doesn't exist.
+func Untar(tarArchive io.Reader, dest string, options *TarOptions) error {
+	return untarHandler(tarArchive, dest, options, true)
+}
+
+// UntarUncompressed reads a stream of bytes from `archive`, parses it as a tar archive,
+// and unpacks it into the directory at `dest`.
+// The archive must be an uncompressed stream.
+func UntarUncompressed(tarArchive io.Reader, dest string, options *TarOptions) error {
+	return untarHandler(tarArchive, dest, options, false)
+}
+
+// Handler for teasing out the automatic decompression
+func untarHandler(tarArchive io.Reader, dest string, options *TarOptions, decompress bool) error {
+	if tarArchive == nil {
+		return errors.New("empty archive")
+	}
+	dest = filepath.Clean(dest)
+	if options == nil {
+		options = &TarOptions{}
+	}
+	if options.ExcludePatterns == nil {
+		options.ExcludePatterns = []string{}
+	}
+
+	r := tarArchive
+	if decompress {
+		decompressedArchive, err := compression.DecompressStream(tarArchive)
+		if err != nil {
+			return err
+		}
+		defer decompressedArchive.Close()
+		r = decompressedArchive
+	}
+
+	return Unpack(r, dest, options)
+}
+
+// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
+// If either Tar or Untar fails, TarUntar aborts and returns the error.
+func (archiver *Archiver) TarUntar(src, dst string) error {
+	archive, err := Tar(src, compression.None)
+	if err != nil {
+		return err
+	}
+	defer archive.Close()
+	return archiver.Untar(archive, dst, &TarOptions{
+		IDMap: archiver.IDMapping,
+	})
+}
+
+// UntarPath untar a file from path to a destination, src is the source tar file path.
+func (archiver *Archiver) UntarPath(src, dst string) error {
+	archive, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer archive.Close()
+	return archiver.Untar(archive, dst, &TarOptions{
+		IDMap: archiver.IDMapping,
+	})
+}
+
+// CopyWithTar creates a tar archive of filesystem path `src`, and
+// unpacks it at filesystem path `dst`.
+// The archive is streamed directly with fixed buffering and no
+// intermediary disk IO.
+func (archiver *Archiver) CopyWithTar(src, dst string) error {
+	srcSt, err := os.Stat(src)
+	if err != nil {
+		return err
+	}
+	if !srcSt.IsDir() {
+		return archiver.CopyFileWithTar(src, dst)
+	}
+
+	// if this Archiver is set up with ID mapping we need to create
+	// the new destination directory with the remapped root UID/GID pair
+	// as owner
+	uid, gid := archiver.IDMapping.RootPair()
+	// Create dst, copy src's content into it
+	if err := user.MkdirAllAndChown(dst, 0o755, uid, gid, user.WithOnlyNew); err != nil {
+		return err
+	}
+	return archiver.TarUntar(src, dst)
+}
+
+// CopyFileWithTar emulates the behavior of the 'cp' command-line
+// for a single file. It copies a regular file from path `src` to
+// path `dst`, and preserves all its metadata.
+func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
+	srcSt, err := os.Stat(src)
+	if err != nil {
+		return err
+	}
+
+	if srcSt.IsDir() {
+		return errors.New("can't copy a directory")
+	}
+
+	// Clean up the trailing slash. This must be done in an operating
+	// system specific manner.
+	if dst[len(dst)-1] == os.PathSeparator {
+		dst = filepath.Join(dst, filepath.Base(src))
+	}
+	// Create the holding directory if necessary
+	if err := os.MkdirAll(filepath.Dir(dst), 0o700); err != nil {
+		return err
+	}
+
+	r, w := io.Pipe()
+	errC := make(chan error, 1)
+
+	go func() {
+		defer close(errC)
+
+		errC <- func() error {
+			defer w.Close()
+
+			srcF, err := os.Open(src)
+			if err != nil {
+				return err
+			}
+			defer srcF.Close()
+
+			hdr, err := tarheader.FileInfoHeaderNoLookups(srcSt, "")
+			if err != nil {
+				return err
+			}
+			hdr.Format = tar.FormatPAX
+			hdr.ModTime = hdr.ModTime.Truncate(time.Second)
+			hdr.AccessTime = time.Time{}
+			hdr.ChangeTime = time.Time{}
+			hdr.Name = filepath.Base(dst)
+			hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
+
+			if err := remapIDs(archiver.IDMapping, hdr); err != nil {
+				return err
+			}
+
+			tw := tar.NewWriter(w)
+			defer tw.Close()
+			if err := tw.WriteHeader(hdr); err != nil {
+				return err
+			}
+			if err := copyWithBuffer(tw, srcF); err != nil {
+				return err
+			}
+			return nil
+		}()
+	}()
+	defer func() {
+		if er := <-errC; err == nil && er != nil {
+			err = er
+		}
+	}()
+
+	err = archiver.Untar(r, filepath.Dir(dst), nil)
+	if err != nil {
+		r.CloseWithError(err)
+	}
+	return err
+}
+
+// IdentityMapping returns the IdentityMapping of the archiver.
+func (archiver *Archiver) IdentityMapping() user.IdentityMapping {
+	return archiver.IDMapping
+}
+
+func remapIDs(idMapping user.IdentityMapping, hdr *tar.Header) error {
+	uid, gid, err := idMapping.ToHost(hdr.Uid, hdr.Gid)
+	hdr.Uid, hdr.Gid = uid, gid
+	return err
+}
diff --git a/vendor/github.com/moby/go-archive/archive_linux.go b/vendor/github.com/moby/go-archive/archive_linux.go
new file mode 100644
index 000000000..7b6c3e02b
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/archive_linux.go
@@ -0,0 +1,107 @@
+package archive
+
+import (
+	"archive/tar"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/moby/sys/userns"
+	"golang.org/x/sys/unix"
+)
+
+func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
+	if format == OverlayWhiteoutFormat {
+		return overlayWhiteoutConverter{}
+	}
+	return nil
+}
+
+type overlayWhiteoutConverter struct{}
+
+func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, _ error) {
+	// convert whiteouts to AUFS format
+	if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 {
+		// we just rename the file and make it normal
+		dir, filename := filepath.Split(hdr.Name)
+		hdr.Name = filepath.Join(dir, WhiteoutPrefix+filename)
+		hdr.Mode = 0o600
+		hdr.Typeflag = tar.TypeReg
+		hdr.Size = 0
+	}
+
+	if fi.Mode()&os.ModeDir == 0 {
+		// FIXME(thaJeztah): return a sentinel error instead of nil, nil
+		return nil, nil
+	}
+
+	opaqueXattrName := "trusted.overlay.opaque"
+	if userns.RunningInUserNS() {
+		opaqueXattrName = "user.overlay.opaque"
+	}
+
+	// convert opaque dirs to AUFS format by writing an empty file with the prefix
+	opaque, err := lgetxattr(path, opaqueXattrName)
+	if err != nil {
+		return nil, err
+	}
+	if len(opaque) != 1 || opaque[0] != 'y' {
+		// FIXME(thaJeztah): return a sentinel error instead of nil, nil
+		return nil, nil
+	}
+	delete(hdr.PAXRecords, paxSchilyXattr+opaqueXattrName)
+
+	// create a header for the whiteout file
+	// it should inherit some properties from the parent, but be a regular file
+	return &tar.Header{
+		Typeflag:   tar.TypeReg,
+		Mode:       hdr.Mode & int64(os.ModePerm),
+		Name:       filepath.Join(hdr.Name, WhiteoutOpaqueDir), // #nosec G305 -- An archive is being created, not extracted.
+		Size:       0,
+		Uid:        hdr.Uid,
+		Uname:      hdr.Uname,
+		Gid:        hdr.Gid,
+		Gname:      hdr.Gname,
+		AccessTime: hdr.AccessTime,
+		ChangeTime: hdr.ChangeTime,
+	}, nil
+}
+
+func (c overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) {
+	base := filepath.Base(path)
+	dir := filepath.Dir(path)
+
+	// if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay
+	if base == WhiteoutOpaqueDir {
+		opaqueXattrName := "trusted.overlay.opaque"
+		if userns.RunningInUserNS() {
+			opaqueXattrName = "user.overlay.opaque"
+		}
+
+		err := unix.Setxattr(dir, opaqueXattrName, []byte{'y'}, 0)
+		if err != nil {
+			return false, fmt.Errorf("setxattr('%s', %s=y): %w", dir, opaqueXattrName, err)
+		}
+		// don't write the file itself
+		return false, err
+	}
+
+	// if a file was deleted and we are using overlay, we need to create a character device
+	if strings.HasPrefix(base, WhiteoutPrefix) {
+		originalBase := base[len(WhiteoutPrefix):]
+		originalPath := filepath.Join(dir, originalBase)
+
+		if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil {
+			return false, fmt.Errorf("failed to mknod('%s', S_IFCHR, 0): %w", originalPath, err)
+		}
+		if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil {
+			return false, err
+		}
+
+		// don't write the file itself
+		return false, nil
+	}
+
+	return true, nil
+}
diff --git a/vendor/github.com/moby/go-archive/archive_other.go b/vendor/github.com/moby/go-archive/archive_other.go
new file mode 100644
index 000000000..6495549f6
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/archive_other.go
@@ -0,0 +1,7 @@
+//go:build !linux
+
+package archive
+
+func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
+	return nil
+}
diff --git a/vendor/github.com/moby/go-archive/archive_unix.go b/vendor/github.com/moby/go-archive/archive_unix.go
new file mode 100644
index 000000000..3a9f5b0b5
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/archive_unix.go
@@ -0,0 +1,86 @@
+//go:build !windows
+
+package archive
+
+import (
+	"archive/tar"
+	"errors"
+	"os"
+	"path/filepath"
+	"strings"
+	"syscall"
+
+	"golang.org/x/sys/unix"
+)
+
+// addLongPathPrefix adds the Windows long path prefix to the path provided if
+// it does not already have it. It is a no-op on platforms other than Windows.
+func addLongPathPrefix(srcPath string) string {
+	return srcPath
+}
+
+// getWalkRoot calculates the root path when performing a TarWithOptions.
+// We use a separate function as this is platform specific. On Linux, we
+// can't use filepath.Join(srcPath,include) because this will clean away
+// a trailing "." or "/" which may be important.
+func getWalkRoot(srcPath string, include string) string {
+	return strings.TrimSuffix(srcPath, string(filepath.Separator)) + string(filepath.Separator) + include
+}
+
+// chmodTarEntry is used to adjust the file permissions used in tar header based
+// on the platform the archival is done.
+func chmodTarEntry(perm os.FileMode) os.FileMode {
+	return perm // noop for unix as golang APIs provide perm bits correctly
+}
+
+func getInodeFromStat(stat interface{}) (uint64, error) {
+	s, ok := stat.(*syscall.Stat_t)
+	if !ok {
+		// FIXME(thaJeztah): this should likely return an error; see https://github.com/moby/moby/pull/49493#discussion_r1979152897
+		return 0, nil
+	}
+	return s.Ino, nil
+}
+
+func getFileUIDGID(stat interface{}) (int, int, error) {
+	s, ok := stat.(*syscall.Stat_t)
+
+	if !ok {
+		return 0, 0, errors.New("cannot convert stat value to syscall.Stat_t")
+	}
+	return int(s.Uid), int(s.Gid), nil
+}
+
+// handleTarTypeBlockCharFifo is an OS-specific helper function used by
+// createTarFile to handle the following types of header: Block; Char; Fifo.
+//
+// Creating device nodes is not supported when running in a user namespace,
+// produces a [syscall.EPERM] in most cases.
+func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
+	mode := uint32(hdr.Mode & 0o7777)
+	switch hdr.Typeflag {
+	case tar.TypeBlock:
+		mode |= unix.S_IFBLK
+	case tar.TypeChar:
+		mode |= unix.S_IFCHR
+	case tar.TypeFifo:
+		mode |= unix.S_IFIFO
+	}
+
+	return mknod(path, mode, unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor)))
+}
+
+func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
+	if hdr.Typeflag == tar.TypeLink {
+		if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
+			if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
+				return err
+			}
+		}
+	} else if hdr.Typeflag != tar.TypeSymlink {
+		if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/moby/go-archive/archive_windows.go b/vendor/github.com/moby/go-archive/archive_windows.go
new file mode 100644
index 000000000..0e3e316af
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/archive_windows.go
@@ -0,0 +1,62 @@
+package archive
+
+import (
+	"archive/tar"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+// longPathPrefix is the longpath prefix for Windows file paths.
+const longPathPrefix = `\\?\`
+
+// addLongPathPrefix adds the Windows long path prefix to the path provided if
+// it does not already have it. It is a no-op on platforms other than Windows.
+//
+// addLongPathPrefix is a copy of [github.com/docker/docker/pkg/longpath.AddPrefix].
+func addLongPathPrefix(srcPath string) string {
+	if strings.HasPrefix(srcPath, longPathPrefix) {
+		return srcPath
+	}
+	if strings.HasPrefix(srcPath, `\\`) {
+		// This is a UNC path, so we need to add 'UNC' to the path as well.
+		return longPathPrefix + `UNC` + srcPath[1:]
+	}
+	return longPathPrefix + srcPath
+}
+
+// getWalkRoot calculates the root path when performing a TarWithOptions.
+// We use a separate function as this is platform specific.
+func getWalkRoot(srcPath string, include string) string {
+	return filepath.Join(srcPath, include)
+}
+
+// chmodTarEntry is used to adjust the file permissions used in tar header based
+// on the platform the archival is done.
+func chmodTarEntry(perm os.FileMode) os.FileMode {
+	// Remove group- and world-writable bits.
+	perm &= 0o755
+
+	// Add the x bit: make everything +x on Windows
+	return perm | 0o111
+}
+
+func getInodeFromStat(stat interface{}) (uint64, error) {
+	// do nothing. no notion of Inode in stat on Windows
+	return 0, nil
+}
+
+// handleTarTypeBlockCharFifo is an OS-specific helper function used by
+// createTarFile to handle the following types of header: Block; Char; Fifo
+func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
+	return nil
+}
+
+func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
+	return nil
+}
+
+func getFileUIDGID(stat interface{}) (int, int, error) {
+	// no notion of file ownership mapping yet on Windows
+	return 0, 0, nil
+}
diff --git a/vendor/github.com/moby/go-archive/changes.go b/vendor/github.com/moby/go-archive/changes.go
new file mode 100644
index 000000000..02a0372c6
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/changes.go
@@ -0,0 +1,430 @@
+package archive
+
+import (
+	"archive/tar"
+	"bytes"
+	"context"
+	"fmt"
+	"io"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+	"time"
+
+	"github.com/containerd/log"
+	"github.com/moby/sys/user"
+)
+
+// ChangeType represents the change type.
+type ChangeType int
+
+const (
+	ChangeModify = 0 // ChangeModify represents the modify operation.
+	ChangeAdd    = 1 // ChangeAdd represents the add operation.
+	ChangeDelete = 2 // ChangeDelete represents the delete operation.
+)
+
+func (c ChangeType) String() string {
+	switch c {
+	case ChangeModify:
+		return "C"
+	case ChangeAdd:
+		return "A"
+	case ChangeDelete:
+		return "D"
+	}
+	return ""
+}
+
+// Change represents a change, it wraps the change type and path.
+// It describes changes of the files in the path respect to the
+// parent layers. The change could be modify, add, delete.
+// This is used for layer diff.
+type Change struct {
+	Path string
+	Kind ChangeType
+}
+
+func (change *Change) String() string {
+	return fmt.Sprintf("%s %s", change.Kind, change.Path)
+}
+
+// for sort.Sort
+type changesByPath []Change
+
+func (c changesByPath) Less(i, j int) bool { return c[i].Path < c[j].Path }
+func (c changesByPath) Len() int           { return len(c) }
+func (c changesByPath) Swap(i, j int)      { c[j], c[i] = c[i], c[j] }
+
+// Gnu tar doesn't have sub-second mtime precision. The go tar
+// writer (1.10+) does when using PAX format, but we round times to seconds
+// to ensure archives have the same hashes for backwards compatibility.
+// See https://github.com/moby/moby/pull/35739/commits/fb170206ba12752214630b269a40ac7be6115ed4.
+//
+// Non-sub-second is problematic when we apply changes via tar
+// files. We handle this by comparing for exact times, *or* same
+// second count and either a or b having exactly 0 nanoseconds
+func sameFsTime(a, b time.Time) bool {
+	return a.Equal(b) ||
+		(a.Unix() == b.Unix() &&
+			(a.Nanosecond() == 0 || b.Nanosecond() == 0))
+}
+
+// Changes walks the path rw and determines changes for the files in the path,
+// with respect to the parent layers
+func Changes(layers []string, rw string) ([]Change, error) {
+	return collectChanges(layers, rw, aufsDeletedFile, aufsMetadataSkip)
+}
+
+func aufsMetadataSkip(path string) (skip bool, err error) {
+	skip, err = filepath.Match(string(os.PathSeparator)+WhiteoutMetaPrefix+"*", path)
+	if err != nil {
+		skip = true
+	}
+	return skip, err
+}
+
+func aufsDeletedFile(root, path string, fi os.FileInfo) (string, error) {
+	f := filepath.Base(path)
+
+	// If there is a whiteout, then the file was removed
+	if strings.HasPrefix(f, WhiteoutPrefix) {
+		originalFile := f[len(WhiteoutPrefix):]
+		return filepath.Join(filepath.Dir(path), originalFile), nil
+	}
+
+	return "", nil
+}
+
+type (
+	skipChange   func(string) (bool, error)
+	deleteChange func(string, string, os.FileInfo) (string, error)
+)
+
+func collectChanges(layers []string, rw string, dc deleteChange, sc skipChange) ([]Change, error) {
+	var (
+		changes     []Change
+		changedDirs = make(map[string]struct{})
+	)
+
+	err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		// Rebase path
+		path, err = filepath.Rel(rw, path)
+		if err != nil {
+			return err
+		}
+
+		// As this runs on the daemon side, file paths are OS specific.
+		path = filepath.Join(string(os.PathSeparator), path)
+
+		// Skip root
+		if path == string(os.PathSeparator) {
+			return nil
+		}
+
+		if sc != nil {
+			if skip, err := sc(path); skip {
+				return err
+			}
+		}
+
+		change := Change{
+			Path: path,
+		}
+
+		deletedFile, err := dc(rw, path, f)
+		if err != nil {
+			return err
+		}
+
+		// Find out what kind of modification happened
+		if deletedFile != "" {
+			change.Path = deletedFile
+			change.Kind = ChangeDelete
+		} else {
+			// Otherwise, the file was added
+			change.Kind = ChangeAdd
+
+			// ...Unless it already existed in a top layer, in which case, it's a modification
+			for _, layer := range layers {
+				stat, err := os.Stat(filepath.Join(layer, path))
+				if err != nil && !os.IsNotExist(err) {
+					return err
+				}
+				if err == nil {
+					// The file existed in the top layer, so that's a modification
+
+					// However, if it's a directory, maybe it wasn't actually modified.
+					// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
+					if stat.IsDir() && f.IsDir() {
+						if f.Size() == stat.Size() && f.Mode() == stat.Mode() && sameFsTime(f.ModTime(), stat.ModTime()) {
+							// Both directories are the same, don't record the change
+							return nil
+						}
+					}
+					change.Kind = ChangeModify
+					break
+				}
+			}
+		}
+
+		// If /foo/bar/file.txt is modified, then /foo/bar must be part of the changed files.
+		// This block is here to ensure the change is recorded even if the
+		// modify time, mode and size of the parent directory in the rw and ro layers are all equal.
+		// Check https://github.com/docker/docker/pull/13590 for details.
+		if f.IsDir() {
+			changedDirs[path] = struct{}{}
+		}
+		if change.Kind == ChangeAdd || change.Kind == ChangeDelete {
+			parent := filepath.Dir(path)
+			if _, ok := changedDirs[parent]; !ok && parent != "/" {
+				changes = append(changes, Change{Path: parent, Kind: ChangeModify})
+				changedDirs[parent] = struct{}{}
+			}
+		}
+
+		// Record change
+		changes = append(changes, change)
+		return nil
+	})
+	if err != nil && !os.IsNotExist(err) {
+		return nil, err
+	}
+	return changes, nil
+}
+
+// FileInfo describes the information of a file.
+type FileInfo struct {
+	parent     *FileInfo
+	name       string
+	stat       fs.FileInfo
+	children   map[string]*FileInfo
+	capability []byte
+	added      bool
+}
+
+// LookUp looks up the file information of a file.
+func (info *FileInfo) LookUp(path string) *FileInfo {
+	// As this runs on the daemon side, file paths are OS specific.
+	parent := info
+	if path == string(os.PathSeparator) {
+		return info
+	}
+
+	pathElements := strings.Split(path, string(os.PathSeparator))
+	for _, elem := range pathElements {
+		if elem != "" {
+			child := parent.children[elem]
+			if child == nil {
+				return nil
+			}
+			parent = child
+		}
+	}
+	return parent
+}
+
+func (info *FileInfo) path() string {
+	if info.parent == nil {
+		// As this runs on the daemon side, file paths are OS specific.
+		return string(os.PathSeparator)
+	}
+	return filepath.Join(info.parent.path(), info.name)
+}
+
+func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
+	sizeAtEntry := len(*changes)
+
+	if oldInfo == nil {
+		// add
+		change := Change{
+			Path: info.path(),
+			Kind: ChangeAdd,
+		}
+		*changes = append(*changes, change)
+		info.added = true
+	}
+
+	// We make a copy so we can modify it to detect additions
+	// also, we only recurse on the old dir if the new info is a directory
+	// otherwise any previous delete/change is considered recursive
+	oldChildren := make(map[string]*FileInfo)
+	if oldInfo != nil && info.isDir() {
+		for k, v := range oldInfo.children {
+			oldChildren[k] = v
+		}
+	}
+
+	for name, newChild := range info.children {
+		oldChild := oldChildren[name]
+		if oldChild != nil {
+			// change?
+			oldStat := oldChild.stat
+			newStat := newChild.stat
+			// Note: We can't compare inode or ctime or blocksize here, because these change
+			// when copying a file into a container. However, that is not generally a problem
+			// because any content change will change mtime, and any status change should
+			// be visible when actually comparing the stat fields. The only time this
+			// breaks down is if some code intentionally hides a change by setting
+			// back mtime
+			if statDifferent(oldStat, newStat) ||
+				!bytes.Equal(oldChild.capability, newChild.capability) {
+				change := Change{
+					Path: newChild.path(),
+					Kind: ChangeModify,
+				}
+				*changes = append(*changes, change)
+				newChild.added = true
+			}
+
+			// Remove from copy so we can detect deletions
+			delete(oldChildren, name)
+		}
+
+		newChild.addChanges(oldChild, changes)
+	}
+	for _, oldChild := range oldChildren {
+		// delete
+		change := Change{
+			Path: oldChild.path(),
+			Kind: ChangeDelete,
+		}
+		*changes = append(*changes, change)
+	}
+
+	// If there were changes inside this directory, we need to add it, even if the directory
+	// itself wasn't changed. This is needed to properly save and restore filesystem permissions.
+	// As this runs on the daemon side, file paths are OS specific.
+	if len(*changes) > sizeAtEntry && info.isDir() && !info.added && info.path() != string(os.PathSeparator) {
+		change := Change{
+			Path: info.path(),
+			Kind: ChangeModify,
+		}
+		// Let's insert the directory entry before the recently added entries located inside this dir
+		*changes = append(*changes, change) // just to resize the slice, will be overwritten
+		copy((*changes)[sizeAtEntry+1:], (*changes)[sizeAtEntry:])
+		(*changes)[sizeAtEntry] = change
+	}
+}
+
+// Changes add changes to file information.
+func (info *FileInfo) Changes(oldInfo *FileInfo) []Change {
+	var changes []Change
+
+	info.addChanges(oldInfo, &changes)
+
+	return changes
+}
+
+func newRootFileInfo() *FileInfo {
+	// As this runs on the daemon side, file paths are OS specific.
+	root := &FileInfo{
+		name:     string(os.PathSeparator),
+		children: make(map[string]*FileInfo),
+	}
+	return root
+}
+
+// ChangesDirs compares two directories and generates an array of Change objects describing the changes.
+// If oldDir is "", then all files in newDir will be Add-Changes.
+func ChangesDirs(newDir, oldDir string) ([]Change, error) {
+	var oldRoot, newRoot *FileInfo
+	if oldDir == "" {
+		emptyDir, err := os.MkdirTemp("", "empty")
+		if err != nil {
+			return nil, err
+		}
+		defer os.Remove(emptyDir)
+		oldDir = emptyDir
+	}
+	oldRoot, newRoot, err := collectFileInfoForChanges(oldDir, newDir)
+	if err != nil {
+		return nil, err
+	}
+
+	return newRoot.Changes(oldRoot), nil
+}
+
+// ChangesSize calculates the size in bytes of the provided changes, based on newDir.
+func ChangesSize(newDir string, changes []Change) int64 {
+	var (
+		size int64
+		sf   = make(map[uint64]struct{})
+	)
+	for _, change := range changes {
+		if change.Kind == ChangeModify || change.Kind == ChangeAdd {
+			file := filepath.Join(newDir, change.Path)
+			fileInfo, err := os.Lstat(file)
+			if err != nil {
+				log.G(context.TODO()).Errorf("Can not stat %q: %s", file, err)
+				continue
+			}
+
+			if fileInfo != nil && !fileInfo.IsDir() {
+				if hasHardlinks(fileInfo) {
+					inode := getIno(fileInfo)
+					if _, ok := sf[inode]; !ok {
+						size += fileInfo.Size()
+						sf[inode] = struct{}{}
+					}
+				} else {
+					size += fileInfo.Size()
+				}
+			}
+		}
+	}
+	return size
+}
+
+// ExportChanges produces an Archive from the provided changes, relative to dir.
+func ExportChanges(dir string, changes []Change, idMap user.IdentityMapping) (io.ReadCloser, error) {
+	reader, writer := io.Pipe()
+	go func() {
+		ta := newTarAppender(idMap, writer, nil)
+
+		sort.Sort(changesByPath(changes))
+
+		// In general we log errors here but ignore them because
+		// during e.g. a diff operation the container can continue
+		// mutating the filesystem and we can see transient errors
+		// from this
+		for _, change := range changes {
+			if change.Kind == ChangeDelete {
+				whiteOutDir := filepath.Dir(change.Path)
+				whiteOutBase := filepath.Base(change.Path)
+				whiteOut := filepath.Join(whiteOutDir, WhiteoutPrefix+whiteOutBase)
+				timestamp := time.Now()
+				hdr := &tar.Header{
+					Name:       whiteOut[1:],
+					Size:       0,
+					ModTime:    timestamp,
+					AccessTime: timestamp,
+					ChangeTime: timestamp,
+				}
+				if err := ta.TarWriter.WriteHeader(hdr); err != nil {
+					log.G(context.TODO()).Debugf("Can't write whiteout header: %s", err)
+				}
+			} else {
+				path := filepath.Join(dir, change.Path)
+				if err := ta.addTarFile(path, change.Path[1:]); err != nil {
+					log.G(context.TODO()).Debugf("Can't add file %s to tar: %s", path, err)
+				}
+			}
+		}
+
+		// Make sure to check the error on Close.
+		if err := ta.TarWriter.Close(); err != nil {
+			log.G(context.TODO()).Debugf("Can't close layer: %s", err)
+		}
+		if err := writer.Close(); err != nil {
+			log.G(context.TODO()).Debugf("failed close Changes writer: %s", err)
+		}
+	}()
+	return reader, nil
+}
diff --git a/vendor/github.com/moby/go-archive/changes_linux.go b/vendor/github.com/moby/go-archive/changes_linux.go
new file mode 100644
index 000000000..8289fe17d
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/changes_linux.go
@@ -0,0 +1,274 @@
+package archive
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+)
+
+// walker is used to implement collectFileInfoForChanges on linux. Where this
+// method in general returns the entire contents of two directory trees, we
+// optimize some FS calls out on linux. In particular, we take advantage of the
+// fact that getdents(2) returns the inode of each file in the directory being
+// walked, which, when walking two trees in parallel to generate a list of
+// changes, can be used to prune subtrees without ever having to lstat(2) them
+// directly. Eliminating stat calls in this way can save up to seconds on large
+// images.
+type walker struct {
+	dir1  string
+	dir2  string
+	root1 *FileInfo
+	root2 *FileInfo
+}
+
+// collectFileInfoForChanges returns a complete representation of the trees
+// rooted at dir1 and dir2, with one important exception: any subtree or
+// leaf where the inode and device numbers are an exact match between dir1
+// and dir2 will be pruned from the results. This method is *only* to be used
+// to generating a list of changes between the two directories, as it does not
+// reflect the full contents.
+func collectFileInfoForChanges(dir1, dir2 string) (*FileInfo, *FileInfo, error) {
+	w := &walker{
+		dir1:  dir1,
+		dir2:  dir2,
+		root1: newRootFileInfo(),
+		root2: newRootFileInfo(),
+	}
+
+	i1, err := os.Lstat(w.dir1)
+	if err != nil {
+		return nil, nil, err
+	}
+	i2, err := os.Lstat(w.dir2)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	if err := w.walk("/", i1, i2); err != nil {
+		return nil, nil, err
+	}
+
+	return w.root1, w.root2, nil
+}
+
+// Given a FileInfo, its path info, and a reference to the root of the tree
+// being constructed, register this file with the tree.
+func walkchunk(path string, fi os.FileInfo, dir string, root *FileInfo) error {
+	if fi == nil {
+		return nil
+	}
+	parent := root.LookUp(filepath.Dir(path))
+	if parent == nil {
+		return fmt.Errorf("walkchunk: Unexpectedly no parent for %s", path)
+	}
+	info := &FileInfo{
+		name:     filepath.Base(path),
+		children: make(map[string]*FileInfo),
+		parent:   parent,
+	}
+	cpath := filepath.Join(dir, path)
+	info.stat = fi
+	info.capability, _ = lgetxattr(cpath, "security.capability") // lgetxattr(2): fs access
+	parent.children[info.name] = info
+	return nil
+}
+
+// Walk a subtree rooted at the same path in both trees being iterated. For
+// example, /docker/overlay/1234/a/b/c/d and /docker/overlay/8888/a/b/c/d
+func (w *walker) walk(path string, i1, i2 os.FileInfo) (err error) {
+	// Register these nodes with the return trees, unless we're still at the
+	// (already-created) roots:
+	if path != "/" {
+		if err := walkchunk(path, i1, w.dir1, w.root1); err != nil {
+			return err
+		}
+		if err := walkchunk(path, i2, w.dir2, w.root2); err != nil {
+			return err
+		}
+	}
+
+	is1Dir := i1 != nil && i1.IsDir()
+	is2Dir := i2 != nil && i2.IsDir()
+
+	sameDevice := false
+	if i1 != nil && i2 != nil {
+		si1 := i1.Sys().(*syscall.Stat_t)
+		si2 := i2.Sys().(*syscall.Stat_t)
+		if si1.Dev == si2.Dev {
+			sameDevice = true
+		}
+	}
+
+	// If these files are both non-existent, or leaves (non-dirs), we are done.
+	if !is1Dir && !is2Dir {
+		return nil
+	}
+
+	// Fetch the names of all the files contained in both directories being walked:
+	var names1, names2 []nameIno
+	if is1Dir {
+		names1, err = readdirnames(filepath.Join(w.dir1, path)) // getdents(2): fs access
+		if err != nil {
+			return err
+		}
+	}
+	if is2Dir {
+		names2, err = readdirnames(filepath.Join(w.dir2, path)) // getdents(2): fs access
+		if err != nil {
+			return err
+		}
+	}
+
+	// We have lists of the files contained in both parallel directories, sorted
+	// in the same order. Walk them in parallel, generating a unique merged list
+	// of all items present in either or both directories.
+	var names []string
+	ix1 := 0
+	ix2 := 0
+
+	for ix1 < len(names1) && ix2 < len(names2) {
+		ni1 := names1[ix1]
+		ni2 := names2[ix2]
+
+		switch strings.Compare(ni1.name, ni2.name) {
+		case -1: // ni1 < ni2 -- advance ni1
+			// we will not encounter ni1 in names2
+			names = append(names, ni1.name)
+			ix1++
+		case 0: // ni1 == ni2
+			if ni1.ino != ni2.ino || !sameDevice {
+				names = append(names, ni1.name)
+			}
+			ix1++
+			ix2++
+		case 1: // ni1 > ni2 -- advance ni2
+			// we will not encounter ni2 in names1
+			names = append(names, ni2.name)
+			ix2++
+		}
+	}
+	for ix1 < len(names1) {
+		names = append(names, names1[ix1].name)
+		ix1++
+	}
+	for ix2 < len(names2) {
+		names = append(names, names2[ix2].name)
+		ix2++
+	}
+
+	// For each of the names present in either or both of the directories being
+	// iterated, stat the name under each root, and recurse the pair of them:
+	for _, name := range names {
+		fname := filepath.Join(path, name)
+		var cInfo1, cInfo2 os.FileInfo
+		if is1Dir {
+			cInfo1, err = os.Lstat(filepath.Join(w.dir1, fname)) // lstat(2): fs access
+			if err != nil && !os.IsNotExist(err) {
+				return err
+			}
+		}
+		if is2Dir {
+			cInfo2, err = os.Lstat(filepath.Join(w.dir2, fname)) // lstat(2): fs access
+			if err != nil && !os.IsNotExist(err) {
+				return err
+			}
+		}
+		if err = w.walk(fname, cInfo1, cInfo2); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// {name,inode} pairs used to support the early-pruning logic of the walker type
+type nameIno struct {
+	name string
+	ino  uint64
+}
+
+type nameInoSlice []nameIno
+
+func (s nameInoSlice) Len() int           { return len(s) }
+func (s nameInoSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+func (s nameInoSlice) Less(i, j int) bool { return s[i].name < s[j].name }
+
+// readdirnames is a hacked-apart version of the Go stdlib code, exposing inode
+// numbers further up the stack when reading directory contents. Unlike
+// os.Readdirnames, which returns a list of filenames, this function returns a
+// list of {filename,inode} pairs.
+func readdirnames(dirname string) (names []nameIno, err error) {
+	var (
+		size = 100
+		buf  = make([]byte, 4096)
+		nbuf int
+		bufp int
+		nb   int
+	)
+
+	f, err := os.Open(dirname)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	names = make([]nameIno, 0, size) // Empty with room to grow.
+	for {
+		// Refill the buffer if necessary
+		if bufp >= nbuf {
+			bufp = 0
+			nbuf, err = unix.ReadDirent(int(f.Fd()), buf) // getdents on linux
+			if nbuf < 0 {
+				nbuf = 0
+			}
+			if err != nil {
+				return nil, os.NewSyscallError("readdirent", err)
+			}
+			if nbuf <= 0 {
+				break // EOF
+			}
+		}
+
+		// Drain the buffer
+		nb, names = parseDirent(buf[bufp:nbuf], names)
+		bufp += nb
+	}
+
+	sl := nameInoSlice(names)
+	sort.Sort(sl)
+	return sl, nil
+}
+
+// parseDirent is a minor modification of unix.ParseDirent (linux version)
+// which returns {name,inode} pairs instead of just names.
+func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno) {
+	origlen := len(buf)
+	for len(buf) > 0 {
+		dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited"
+		buf = buf[dirent.Reclen:]
+		if dirent.Ino == 0 { // File absent in directory.
+			continue
+		}
+		b := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited"
+		name := string(b[0:clen(b[:])])
+		if name == "." || name == ".." { // Useless names
+			continue
+		}
+		names = append(names, nameIno{name, dirent.Ino})
+	}
+	return origlen - len(buf), names
+}
+
+func clen(n []byte) int {
+	for i := 0; i < len(n); i++ {
+		if n[i] == 0 {
+			return i
+		}
+	}
+	return len(n)
+}
diff --git a/vendor/github.com/moby/go-archive/changes_other.go b/vendor/github.com/moby/go-archive/changes_other.go
new file mode 100644
index 000000000..a8a3a5a6f
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/changes_other.go
@@ -0,0 +1,95 @@
+//go:build !linux
+
+package archive
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+)
+
+func collectFileInfoForChanges(oldDir, newDir string) (*FileInfo, *FileInfo, error) {
+	var (
+		oldRoot, newRoot *FileInfo
+		err1, err2       error
+		errs             = make(chan error, 2)
+	)
+	go func() {
+		oldRoot, err1 = collectFileInfo(oldDir)
+		errs <- err1
+	}()
+	go func() {
+		newRoot, err2 = collectFileInfo(newDir)
+		errs <- err2
+	}()
+
+	// block until both routines have returned
+	for i := 0; i < 2; i++ {
+		if err := <-errs; err != nil {
+			return nil, nil, err
+		}
+	}
+
+	return oldRoot, newRoot, nil
+}
+
+func collectFileInfo(sourceDir string) (*FileInfo, error) {
+	root := newRootFileInfo()
+
+	err := filepath.WalkDir(sourceDir, func(path string, _ os.DirEntry, err error) error {
+		if err != nil {
+			return err
+		}
+
+		// Rebase path
+		relPath, err := filepath.Rel(sourceDir, path)
+		if err != nil {
+			return err
+		}
+
+		// As this runs on the daemon side, file paths are OS specific.
+		relPath = filepath.Join(string(os.PathSeparator), relPath)
+
+		// See https://github.com/golang/go/issues/9168 - bug in filepath.Join.
+		// Temporary workaround. If the returned path starts with two backslashes,
+		// trim it down to a single backslash. Only relevant on Windows.
+		if runtime.GOOS == "windows" {
+			if strings.HasPrefix(relPath, `\\`) {
+				relPath = relPath[1:]
+			}
+		}
+
+		if relPath == string(os.PathSeparator) {
+			return nil
+		}
+
+		parent := root.LookUp(filepath.Dir(relPath))
+		if parent == nil {
+			return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath)
+		}
+
+		s, err := os.Lstat(path)
+		if err != nil {
+			return err
+		}
+
+		info := &FileInfo{
+			name:     filepath.Base(relPath),
+			children: make(map[string]*FileInfo),
+			parent:   parent,
+			stat:     s,
+		}
+
+		info.capability, _ = lgetxattr(path, "security.capability")
+
+		parent.children[info.name] = info
+
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+	return root, nil
+}
diff --git a/vendor/github.com/moby/go-archive/changes_unix.go b/vendor/github.com/moby/go-archive/changes_unix.go
new file mode 100644
index 000000000..4dd98bd29
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/changes_unix.go
@@ -0,0 +1,43 @@
+//go:build !windows
+
+package archive
+
+import (
+	"io/fs"
+	"os"
+	"syscall"
+)
+
+func statDifferent(oldStat fs.FileInfo, newStat fs.FileInfo) bool {
+	oldSys := oldStat.Sys().(*syscall.Stat_t)
+	newSys := newStat.Sys().(*syscall.Stat_t)
+	// Don't look at size for dirs, its not a good measure of change
+	if oldStat.Mode() != newStat.Mode() ||
+		oldSys.Uid != newSys.Uid ||
+		oldSys.Gid != newSys.Gid ||
+		oldSys.Rdev != newSys.Rdev ||
+		// Don't look at size or modification time for dirs, its not a good
+		// measure of change. See https://github.com/moby/moby/issues/9874
+		// for a description of the issue with modification time, and
+		// https://github.com/moby/moby/pull/11422 for the change.
+		// (Note that in the Windows implementation of this function,
+		// modification time IS taken as a change). See
+		// https://github.com/moby/moby/pull/37982 for more information.
+		(!oldStat.Mode().IsDir() &&
+			(!sameFsTime(oldStat.ModTime(), newStat.ModTime()) || (oldStat.Size() != newStat.Size()))) {
+		return true
+	}
+	return false
+}
+
+func (info *FileInfo) isDir() bool {
+	return info.parent == nil || info.stat.Mode().IsDir()
+}
+
+func getIno(fi os.FileInfo) uint64 {
+	return fi.Sys().(*syscall.Stat_t).Ino
+}
+
+func hasHardlinks(fi os.FileInfo) bool {
+	return fi.Sys().(*syscall.Stat_t).Nlink > 1
+}
diff --git a/vendor/github.com/moby/go-archive/changes_windows.go b/vendor/github.com/moby/go-archive/changes_windows.go
new file mode 100644
index 000000000..c89605c78
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/changes_windows.go
@@ -0,0 +1,33 @@
+package archive
+
+import (
+	"io/fs"
+	"os"
+)
+
+func statDifferent(oldStat fs.FileInfo, newStat fs.FileInfo) bool {
+	// Note there is slight difference between the Linux and Windows
+	// implementations here. Due to https://github.com/moby/moby/issues/9874,
+	// and the fix at https://github.com/moby/moby/pull/11422, Linux does not
+	// consider a change to the directory time as a change. Windows on NTFS
+	// does. See https://github.com/moby/moby/pull/37982 for more information.
+
+	if !sameFsTime(oldStat.ModTime(), newStat.ModTime()) ||
+		oldStat.Mode() != newStat.Mode() ||
+		oldStat.Size() != newStat.Size() && !oldStat.Mode().IsDir() {
+		return true
+	}
+	return false
+}
+
+func (info *FileInfo) isDir() bool {
+	return info.parent == nil || info.stat.Mode().IsDir()
+}
+
+func getIno(fi os.FileInfo) (inode uint64) {
+	return
+}
+
+func hasHardlinks(fi os.FileInfo) bool {
+	return false
+}
diff --git a/vendor/github.com/moby/go-archive/compression/compression.go b/vendor/github.com/moby/go-archive/compression/compression.go
new file mode 100644
index 000000000..e298cefb3
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/compression/compression.go
@@ -0,0 +1,263 @@
+package compression
+
+import (
+	"bufio"
+	"bytes"
+	"compress/bzip2"
+	"compress/gzip"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"strconv"
+	"sync"
+
+	"github.com/containerd/log"
+	"github.com/klauspost/compress/zstd"
+)
+
+// Compression is the state represents if compressed or not.
+type Compression int
+
+const (
+	None  Compression = 0 // None represents the uncompressed.
+	Bzip2 Compression = 1 // Bzip2 is bzip2 compression algorithm.
+	Gzip  Compression = 2 // Gzip is gzip compression algorithm.
+	Xz    Compression = 3 // Xz is xz compression algorithm.
+	Zstd  Compression = 4 // Zstd is zstd compression algorithm.
+)
+
+// Extension returns the extension of a file that uses the specified compression algorithm.
+func (c *Compression) Extension() string {
+	switch *c {
+	case None:
+		return "tar"
+	case Bzip2:
+		return "tar.bz2"
+	case Gzip:
+		return "tar.gz"
+	case Xz:
+		return "tar.xz"
+	case Zstd:
+		return "tar.zst"
+	default:
+		return ""
+	}
+}
+
+type readCloserWrapper struct {
+	io.Reader
+	closer func() error
+}
+
+func (r *readCloserWrapper) Close() error {
+	if r.closer != nil {
+		return r.closer()
+	}
+	return nil
+}
+
+type nopWriteCloser struct {
+	io.Writer
+}
+
+func (nopWriteCloser) Close() error { return nil }
+
+var bufioReader32KPool = &sync.Pool{
+	New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
+}
+
+type bufferedReader struct {
+	buf *bufio.Reader
+}
+
+func newBufferedReader(r io.Reader) *bufferedReader {
+	buf := bufioReader32KPool.Get().(*bufio.Reader)
+	buf.Reset(r)
+	return &bufferedReader{buf}
+}
+
+func (r *bufferedReader) Read(p []byte) (int, error) {
+	if r.buf == nil {
+		return 0, io.EOF
+	}
+	n, err := r.buf.Read(p)
+	if errors.Is(err, io.EOF) {
+		r.buf.Reset(nil)
+		bufioReader32KPool.Put(r.buf)
+		r.buf = nil
+	}
+	return n, err
+}
+
+func (r *bufferedReader) Peek(n int) ([]byte, error) {
+	if r.buf == nil {
+		return nil, io.EOF
+	}
+	return r.buf.Peek(n)
+}
+
+// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive.
+func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
+	buf := newBufferedReader(archive)
+	bs, err := buf.Peek(10)
+	if err != nil && !errors.Is(err, io.EOF) {
+		// Note: we'll ignore any io.EOF error because there are some odd
+		// cases where the layer.tar file will be empty (zero bytes) and
+		// that results in an io.EOF from the Peek() call. So, in those
+		// cases we'll just treat it as a non-compressed stream and
+		// that means just create an empty layer.
+		// See Issue 18170
+		return nil, err
+	}
+
+	switch compression := Detect(bs); compression {
+	case None:
+		return &readCloserWrapper{
+			Reader: buf,
+		}, nil
+	case Gzip:
+		ctx, cancel := context.WithCancel(context.Background())
+		gzReader, err := gzipDecompress(ctx, buf)
+		if err != nil {
+			cancel()
+			return nil, err
+		}
+
+		return &readCloserWrapper{
+			Reader: gzReader,
+			closer: func() error {
+				cancel()
+				return gzReader.Close()
+			},
+		}, nil
+	case Bzip2:
+		bz2Reader := bzip2.NewReader(buf)
+		return &readCloserWrapper{
+			Reader: bz2Reader,
+		}, nil
+	case Xz:
+		ctx, cancel := context.WithCancel(context.Background())
+
+		xzReader, err := xzDecompress(ctx, buf)
+		if err != nil {
+			cancel()
+			return nil, err
+		}
+
+		return &readCloserWrapper{
+			Reader: xzReader,
+			closer: func() error {
+				cancel()
+				return xzReader.Close()
+			},
+		}, nil
+	case Zstd:
+		zstdReader, err := zstd.NewReader(buf)
+		if err != nil {
+			return nil, err
+		}
+		return &readCloserWrapper{
+			Reader: zstdReader,
+			closer: func() error {
+				zstdReader.Close()
+				return nil
+			},
+		}, nil
+
+	default:
+		return nil, fmt.Errorf("unsupported compression format (%d)", compression)
+	}
+}
+
+// CompressStream compresses the dest with specified compression algorithm.
+func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) {
+	switch compression {
+	case None:
+		return nopWriteCloser{dest}, nil
+	case Gzip:
+		return gzip.NewWriter(dest), nil
+	case Bzip2:
+		// archive/bzip2 does not support writing.
+		return nil, errors.New("unsupported compression format: tar.bz2")
+	case Xz:
+		// there is no xz support at all
+		// However, this is not a problem as docker only currently generates gzipped tars
+		return nil, errors.New("unsupported compression format: tar.xz")
+	default:
+		return nil, fmt.Errorf("unsupported compression format (%d)", compression)
+	}
+}
+
+func xzDecompress(ctx context.Context, archive io.Reader) (io.ReadCloser, error) {
+	args := []string{"xz", "-d", "-c", "-q"}
+
+	return cmdStream(exec.CommandContext(ctx, args[0], args[1:]...), archive)
+}
+
+func gzipDecompress(ctx context.Context, buf io.Reader) (io.ReadCloser, error) {
+	if noPigzEnv := os.Getenv("MOBY_DISABLE_PIGZ"); noPigzEnv != "" {
+		noPigz, err := strconv.ParseBool(noPigzEnv)
+		if err != nil {
+			log.G(ctx).WithError(err).Warn("invalid value in MOBY_DISABLE_PIGZ env var")
+		}
+		if noPigz {
+			log.G(ctx).Debugf("Use of pigz is disabled due to MOBY_DISABLE_PIGZ=%s", noPigzEnv)
+			return gzip.NewReader(buf)
+		}
+	}
+
+	unpigzPath, err := exec.LookPath("unpigz")
+	if err != nil {
+		log.G(ctx).Debugf("unpigz binary not found, falling back to go gzip library")
+		return gzip.NewReader(buf)
+	}
+
+	log.G(ctx).Debugf("Using %s to decompress", unpigzPath)
+
+	return cmdStream(exec.CommandContext(ctx, unpigzPath, "-d", "-c"), buf)
+}
+
+// cmdStream executes a command, and returns its stdout as a stream.
+// If the command fails to run or doesn't complete successfully, an error
+// will be returned, including anything written on stderr.
+func cmdStream(cmd *exec.Cmd, in io.Reader) (io.ReadCloser, error) {
+	reader, writer := io.Pipe()
+
+	cmd.Stdin = in
+	cmd.Stdout = writer
+
+	var errBuf bytes.Buffer
+	cmd.Stderr = &errBuf
+
+	// Run the command and return the pipe
+	if err := cmd.Start(); err != nil {
+		return nil, err
+	}
+
+	// Ensure the command has exited before we clean anything up
+	done := make(chan struct{})
+
+	// Copy stdout to the returned pipe
+	go func() {
+		if err := cmd.Wait(); err != nil {
+			_ = writer.CloseWithError(fmt.Errorf("%w: %s", err, errBuf.String()))
+		} else {
+			_ = writer.Close()
+		}
+		close(done)
+	}()
+
+	return &readCloserWrapper{
+		Reader: reader,
+		closer: func() error {
+			// Close pipeR, and then wait for the command to complete before returning. We have to close pipeR first, as
+			// cmd.Wait waits for any non-file stdout/stderr/stdin to close.
+			err := reader.Close()
+			<-done
+			return err
+		},
+	}, nil
+}
diff --git a/vendor/github.com/moby/go-archive/compression/compression_detect.go b/vendor/github.com/moby/go-archive/compression/compression_detect.go
new file mode 100644
index 000000000..85eda927c
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/compression/compression_detect.go
@@ -0,0 +1,65 @@
+package compression
+
+import (
+	"bytes"
+	"encoding/binary"
+)
+
+const (
+	zstdMagicSkippableStart = 0x184D2A50
+	zstdMagicSkippableMask  = 0xFFFFFFF0
+)
+
+var (
+	bzip2Magic = []byte{0x42, 0x5A, 0x68}
+	gzipMagic  = []byte{0x1F, 0x8B, 0x08}
+	xzMagic    = []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}
+	zstdMagic  = []byte{0x28, 0xb5, 0x2f, 0xfd}
+)
+
+type matcher = func([]byte) bool
+
+// Detect detects the compression algorithm of the source.
+func Detect(source []byte) Compression {
+	compressionMap := map[Compression]matcher{
+		Bzip2: magicNumberMatcher(bzip2Magic),
+		Gzip:  magicNumberMatcher(gzipMagic),
+		Xz:    magicNumberMatcher(xzMagic),
+		Zstd:  zstdMatcher(),
+	}
+	for _, compression := range []Compression{Bzip2, Gzip, Xz, Zstd} {
+		fn := compressionMap[compression]
+		if fn(source) {
+			return compression
+		}
+	}
+	return None
+}
+
+func magicNumberMatcher(m []byte) matcher {
+	return func(source []byte) bool {
+		return bytes.HasPrefix(source, m)
+	}
+}
+
+// zstdMatcher detects zstd compression algorithm.
+// Zstandard compressed data is made of one or more frames.
+// There are two frame formats defined by Zstandard: Zstandard frames and Skippable frames.
+// See https://datatracker.ietf.org/doc/html/rfc8878#section-3 for more details.
+func zstdMatcher() matcher {
+	return func(source []byte) bool {
+		if bytes.HasPrefix(source, zstdMagic) {
+			// Zstandard frame
+			return true
+		}
+		// skippable frame
+		if len(source) < 8 {
+			return false
+		}
+		// magic number from 0x184D2A50 to 0x184D2A5F.
+		if binary.LittleEndian.Uint32(source[:4])&zstdMagicSkippableMask == zstdMagicSkippableStart {
+			return true
+		}
+		return false
+	}
+}
diff --git a/vendor/github.com/moby/go-archive/copy.go b/vendor/github.com/moby/go-archive/copy.go
new file mode 100644
index 000000000..77d038c42
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/copy.go
@@ -0,0 +1,496 @@
+package archive
+
+import (
+	"archive/tar"
+	"context"
+	"errors"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+
+	"github.com/containerd/log"
+)
+
+// Errors used or returned by this file.
+var (
+	ErrNotDirectory      = errors.New("not a directory")
+	ErrDirNotExists      = errors.New("no such directory")
+	ErrCannotCopyDir     = errors.New("cannot copy directory")
+	ErrInvalidCopySource = errors.New("invalid copy source content")
+)
+
+var copyPool = sync.Pool{
+	New: func() interface{} { s := make([]byte, 32*1024); return &s },
+}
+
+func copyWithBuffer(dst io.Writer, src io.Reader) error {
+	buf := copyPool.Get().(*[]byte)
+	_, err := io.CopyBuffer(dst, src, *buf)
+	copyPool.Put(buf)
+	return err
+}
+
+// PreserveTrailingDotOrSeparator returns the given cleaned path (after
+// processing using any utility functions from the path or filepath stdlib
+// packages) and appends a trailing `/.` or `/` if its corresponding  original
+// path (from before being processed by utility functions from the path or
+// filepath stdlib packages) ends with a trailing `/.` or `/`. If the cleaned
+// path already ends in a `.` path segment, then another is not added. If the
+// clean path already ends in a path separator, then another is not added.
+func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string) string {
+	// Ensure paths are in platform semantics
+	cleanedPath = normalizePath(cleanedPath)
+	originalPath = normalizePath(originalPath)
+
+	if !specifiesCurrentDir(cleanedPath) && specifiesCurrentDir(originalPath) {
+		if !hasTrailingPathSeparator(cleanedPath) {
+			// Add a separator if it doesn't already end with one (a cleaned
+			// path would only end in a separator if it is the root).
+			cleanedPath += string(filepath.Separator)
+		}
+		cleanedPath += "."
+	}
+
+	if !hasTrailingPathSeparator(cleanedPath) && hasTrailingPathSeparator(originalPath) {
+		cleanedPath += string(filepath.Separator)
+	}
+
+	return cleanedPath
+}
+
+// assertsDirectory returns whether the given path is
+// asserted to be a directory, i.e., the path ends with
+// a trailing '/' or `/.`, assuming a path separator of `/`.
+func assertsDirectory(path string) bool {
+	return hasTrailingPathSeparator(path) || specifiesCurrentDir(path)
+}
+
+// hasTrailingPathSeparator returns whether the given
+// path ends with the system's path separator character.
+func hasTrailingPathSeparator(path string) bool {
+	return len(path) > 0 && path[len(path)-1] == filepath.Separator
+}
+
+// specifiesCurrentDir returns whether the given path specifies
+// a "current directory", i.e., the last path segment is `.`.
+func specifiesCurrentDir(path string) bool {
+	return filepath.Base(path) == "."
+}
+
+// SplitPathDirEntry splits the given path between its directory name and its
+// basename by first cleaning the path but preserves a trailing "." if the
+// original path specified the current directory.
+func SplitPathDirEntry(path string) (dir, base string) {
+	cleanedPath := filepath.Clean(filepath.FromSlash(path))
+
+	if specifiesCurrentDir(path) {
+		cleanedPath += string(os.PathSeparator) + "."
+	}
+
+	return filepath.Dir(cleanedPath), filepath.Base(cleanedPath)
+}
+
+// TarResource archives the resource described by the given CopyInfo to a Tar
+// archive. A non-nil error is returned if sourcePath does not exist or is
+// asserted to be a directory but exists as another type of file.
+//
+// This function acts as a convenient wrapper around TarWithOptions, which
+// requires a directory as the source path. TarResource accepts either a
+// directory or a file path and correctly sets the Tar options.
+func TarResource(sourceInfo CopyInfo) (content io.ReadCloser, err error) {
+	return TarResourceRebase(sourceInfo.Path, sourceInfo.RebaseName)
+}
+
+// TarResourceRebase is like TarResource but renames the first path element of
+// items in the resulting tar archive to match the given rebaseName if not "".
+func TarResourceRebase(sourcePath, rebaseName string) (content io.ReadCloser, _ error) {
+	sourcePath = normalizePath(sourcePath)
+	if _, err := os.Lstat(sourcePath); err != nil {
+		// Catches the case where the source does not exist or is not a
+		// directory if asserted to be a directory, as this also causes an
+		// error.
+		return nil, err
+	}
+
+	// Separate the source path between its directory and
+	// the entry in that directory which we are archiving.
+	sourceDir, sourceBase := SplitPathDirEntry(sourcePath)
+	opts := TarResourceRebaseOpts(sourceBase, rebaseName)
+
+	log.G(context.TODO()).Debugf("copying %q from %q", sourceBase, sourceDir)
+	return TarWithOptions(sourceDir, opts)
+}
+
+// TarResourceRebaseOpts does not preform the Tar, but instead just creates the rebase
+// parameters to be sent to TarWithOptions (the TarOptions struct)
+func TarResourceRebaseOpts(sourceBase string, rebaseName string) *TarOptions {
+	filter := []string{sourceBase}
+	return &TarOptions{
+		IncludeFiles:     filter,
+		IncludeSourceDir: true,
+		RebaseNames: map[string]string{
+			sourceBase: rebaseName,
+		},
+	}
+}
+
+// CopyInfo holds basic info about the source
+// or destination path of a copy operation.
+type CopyInfo struct {
+	Path       string
+	Exists     bool
+	IsDir      bool
+	RebaseName string
+}
+
+// CopyInfoSourcePath stats the given path to create a CopyInfo
+// struct representing that resource for the source of an archive copy
+// operation. The given path should be an absolute local path. A source path
+// has all symlinks evaluated that appear before the last path separator ("/"
+// on Unix). As it is to be a copy source, the path must exist.
+func CopyInfoSourcePath(path string, followLink bool) (CopyInfo, error) {
+	// normalize the file path and then evaluate the symbol link
+	// we will use the target file instead of the symbol link if
+	// followLink is set
+	path = normalizePath(path)
+
+	resolvedPath, rebaseName, err := ResolveHostSourcePath(path, followLink)
+	if err != nil {
+		return CopyInfo{}, err
+	}
+
+	stat, err := os.Lstat(resolvedPath)
+	if err != nil {
+		return CopyInfo{}, err
+	}
+
+	return CopyInfo{
+		Path:       resolvedPath,
+		Exists:     true,
+		IsDir:      stat.IsDir(),
+		RebaseName: rebaseName,
+	}, nil
+}
+
+// CopyInfoDestinationPath stats the given path to create a CopyInfo
+// struct representing that resource for the destination of an archive copy
+// operation. The given path should be an absolute local path.
+func CopyInfoDestinationPath(path string) (info CopyInfo, err error) {
+	maxSymlinkIter := 10 // filepath.EvalSymlinks uses 255, but 10 already seems like a lot.
+	path = normalizePath(path)
+	originalPath := path
+
+	stat, err := os.Lstat(path)
+
+	if err == nil && stat.Mode()&os.ModeSymlink == 0 {
+		// The path exists and is not a symlink.
+		return CopyInfo{
+			Path:   path,
+			Exists: true,
+			IsDir:  stat.IsDir(),
+		}, nil
+	}
+
+	// While the path is a symlink.
+	for n := 0; err == nil && stat.Mode()&os.ModeSymlink != 0; n++ {
+		if n > maxSymlinkIter {
+			// Don't follow symlinks more than this arbitrary number of times.
+			return CopyInfo{}, errors.New("too many symlinks in " + originalPath)
+		}
+
+		// The path is a symbolic link. We need to evaluate it so that the
+		// destination of the copy operation is the link target and not the
+		// link itself. This is notably different than CopyInfoSourcePath which
+		// only evaluates symlinks before the last appearing path separator.
+		// Also note that it is okay if the last path element is a broken
+		// symlink as the copy operation should create the target.
+		var linkTarget string
+
+		linkTarget, err = os.Readlink(path)
+		if err != nil {
+			return CopyInfo{}, err
+		}
+
+		if !filepath.IsAbs(linkTarget) {
+			// Join with the parent directory.
+			dstParent, _ := SplitPathDirEntry(path)
+			linkTarget = filepath.Join(dstParent, linkTarget)
+		}
+
+		path = linkTarget
+		stat, err = os.Lstat(path)
+	}
+
+	if err != nil {
+		// It's okay if the destination path doesn't exist. We can still
+		// continue the copy operation if the parent directory exists.
+		if !os.IsNotExist(err) {
+			return CopyInfo{}, err
+		}
+
+		// Ensure destination parent dir exists.
+		dstParent, _ := SplitPathDirEntry(path)
+
+		parentDirStat, err := os.Stat(dstParent)
+		if err != nil {
+			return CopyInfo{}, err
+		}
+		if !parentDirStat.IsDir() {
+			return CopyInfo{}, ErrNotDirectory
+		}
+
+		return CopyInfo{Path: path}, nil
+	}
+
+	// The path exists after resolving symlinks.
+	return CopyInfo{
+		Path:   path,
+		Exists: true,
+		IsDir:  stat.IsDir(),
+	}, nil
+}
+
+// PrepareArchiveCopy prepares the given srcContent archive, which should
+// contain the archived resource described by srcInfo, to the destination
+// described by dstInfo. Returns the possibly modified content archive along
+// with the path to the destination directory which it should be extracted to.
+func PrepareArchiveCopy(srcContent io.Reader, srcInfo, dstInfo CopyInfo) (dstDir string, content io.ReadCloser, err error) {
+	// Ensure in platform semantics
+	srcInfo.Path = normalizePath(srcInfo.Path)
+	dstInfo.Path = normalizePath(dstInfo.Path)
+
+	// Separate the destination path between its directory and base
+	// components in case the source archive contents need to be rebased.
+	dstDir, dstBase := SplitPathDirEntry(dstInfo.Path)
+	_, srcBase := SplitPathDirEntry(srcInfo.Path)
+
+	switch {
+	case dstInfo.Exists && dstInfo.IsDir:
+		// The destination exists as a directory. No alteration
+		// to srcContent is needed as its contents can be
+		// simply extracted to the destination directory.
+		return dstInfo.Path, io.NopCloser(srcContent), nil
+	case dstInfo.Exists && srcInfo.IsDir:
+		// The destination exists as some type of file and the source
+		// content is a directory. This is an error condition since
+		// you cannot copy a directory to an existing file location.
+		return "", nil, ErrCannotCopyDir
+	case dstInfo.Exists:
+		// The destination exists as some type of file and the source content
+		// is also a file. The source content entry will have to be renamed to
+		// have a basename which matches the destination path's basename.
+		if len(srcInfo.RebaseName) != 0 {
+			srcBase = srcInfo.RebaseName
+		}
+		return dstDir, RebaseArchiveEntries(srcContent, srcBase, dstBase), nil
+	case srcInfo.IsDir:
+		// The destination does not exist and the source content is an archive
+		// of a directory. The archive should be extracted to the parent of
+		// the destination path instead, and when it is, the directory that is
+		// created as a result should take the name of the destination path.
+		// The source content entries will have to be renamed to have a
+		// basename which matches the destination path's basename.
+		if len(srcInfo.RebaseName) != 0 {
+			srcBase = srcInfo.RebaseName
+		}
+		return dstDir, RebaseArchiveEntries(srcContent, srcBase, dstBase), nil
+	case assertsDirectory(dstInfo.Path):
+		// The destination does not exist and is asserted to be created as a
+		// directory, but the source content is not a directory. This is an
+		// error condition since you cannot create a directory from a file
+		// source.
+		return "", nil, ErrDirNotExists
+	default:
+		// The last remaining case is when the destination does not exist, is
+		// not asserted to be a directory, and the source content is not an
+		// archive of a directory. It this case, the destination file will need
+		// to be created when the archive is extracted and the source content
+		// entry will have to be renamed to have a basename which matches the
+		// destination path's basename.
+		if len(srcInfo.RebaseName) != 0 {
+			srcBase = srcInfo.RebaseName
+		}
+		return dstDir, RebaseArchiveEntries(srcContent, srcBase, dstBase), nil
+	}
+}
+
+// RebaseArchiveEntries rewrites the given srcContent archive replacing
+// an occurrence of oldBase with newBase at the beginning of entry names.
+func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.ReadCloser {
+	if oldBase == string(os.PathSeparator) {
+		// If oldBase specifies the root directory, use an empty string as
+		// oldBase instead so that newBase doesn't replace the path separator
+		// that all paths will start with.
+		oldBase = ""
+	}
+
+	rebased, w := io.Pipe()
+
+	go func() {
+		srcTar := tar.NewReader(srcContent)
+		rebasedTar := tar.NewWriter(w)
+
+		for {
+			hdr, err := srcTar.Next()
+			if errors.Is(err, io.EOF) {
+				// Signals end of archive.
+				rebasedTar.Close()
+				w.Close()
+				return
+			}
+			if err != nil {
+				w.CloseWithError(err)
+				return
+			}
+
+			// srcContent tar stream, as served by TarWithOptions(), is
+			// definitely in PAX format, but tar.Next() mistakenly guesses it
+			// as USTAR, which creates a problem: if the newBase is >100
+			// characters long, WriteHeader() returns an error like
+			// "archive/tar: cannot encode header: Format specifies USTAR; and USTAR cannot encode Name=...".
+			//
+			// To fix, set the format to PAX here. See docker/for-linux issue #484.
+			hdr.Format = tar.FormatPAX
+			hdr.Name = strings.Replace(hdr.Name, oldBase, newBase, 1)
+			if hdr.Typeflag == tar.TypeLink {
+				hdr.Linkname = strings.Replace(hdr.Linkname, oldBase, newBase, 1)
+			}
+
+			if err = rebasedTar.WriteHeader(hdr); err != nil {
+				w.CloseWithError(err)
+				return
+			}
+
+			// Ignoring GoSec G110. See https://github.com/securego/gosec/pull/433
+			// and https://cure53.de/pentest-report_opa.pdf, which recommends to
+			// replace io.Copy with io.CopyN7. The latter allows to specify the
+			// maximum number of bytes that should be read. By properly defining
+			// the limit, it can be assured that a GZip compression bomb cannot
+			// easily cause a Denial-of-Service.
+			// After reviewing with @tonistiigi and @cpuguy83, this should not
+			// affect us, because here we do not read into memory, hence should
+			// not be vulnerable to this code consuming memory.
+			//nolint:gosec // G110: Potential DoS vulnerability via decompression bomb (gosec)
+			if _, err = io.Copy(rebasedTar, srcTar); err != nil {
+				w.CloseWithError(err)
+				return
+			}
+		}
+	}()
+
+	return rebased
+}
+
+// CopyResource performs an archive copy from the given source path to the
+// given destination path. The source path MUST exist and the destination
+// path's parent directory must exist.
+func CopyResource(srcPath, dstPath string, followLink bool) error {
+	var (
+		srcInfo CopyInfo
+		err     error
+	)
+
+	// Ensure in platform semantics
+	srcPath = normalizePath(srcPath)
+	dstPath = normalizePath(dstPath)
+
+	// Clean the source and destination paths.
+	srcPath = PreserveTrailingDotOrSeparator(filepath.Clean(srcPath), srcPath)
+	dstPath = PreserveTrailingDotOrSeparator(filepath.Clean(dstPath), dstPath)
+
+	if srcInfo, err = CopyInfoSourcePath(srcPath, followLink); err != nil {
+		return err
+	}
+
+	content, err := TarResource(srcInfo)
+	if err != nil {
+		return err
+	}
+	defer content.Close()
+
+	return CopyTo(content, srcInfo, dstPath)
+}
+
+// CopyTo handles extracting the given content whose
+// entries should be sourced from srcInfo to dstPath.
+func CopyTo(content io.Reader, srcInfo CopyInfo, dstPath string) error {
+	// The destination path need not exist, but CopyInfoDestinationPath will
+	// ensure that at least the parent directory exists.
+	dstInfo, err := CopyInfoDestinationPath(normalizePath(dstPath))
+	if err != nil {
+		return err
+	}
+
+	dstDir, copyArchive, err := PrepareArchiveCopy(content, srcInfo, dstInfo)
+	if err != nil {
+		return err
+	}
+	defer copyArchive.Close()
+
+	options := &TarOptions{
+		NoLchown:             true,
+		NoOverwriteDirNonDir: true,
+	}
+
+	return Untar(copyArchive, dstDir, options)
+}
+
+// ResolveHostSourcePath decides real path need to be copied with parameters such as
+// whether to follow symbol link or not, if followLink is true, resolvedPath will return
+// link target of any symbol link file, else it will only resolve symlink of directory
+// but return symbol link file itself without resolving.
+func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseName string, _ error) {
+	if followLink {
+		var err error
+		resolvedPath, err = filepath.EvalSymlinks(path)
+		if err != nil {
+			return "", "", err
+		}
+
+		resolvedPath, rebaseName = GetRebaseName(path, resolvedPath)
+	} else {
+		dirPath, basePath := filepath.Split(path)
+
+		// if not follow symbol link, then resolve symbol link of parent dir
+		resolvedDirPath, err := filepath.EvalSymlinks(dirPath)
+		if err != nil {
+			return "", "", err
+		}
+		// resolvedDirPath will have been cleaned (no trailing path separators) so
+		// we can manually join it with the base path element.
+		resolvedPath = resolvedDirPath + string(filepath.Separator) + basePath
+		if hasTrailingPathSeparator(path) &&
+			filepath.Base(path) != filepath.Base(resolvedPath) {
+			rebaseName = filepath.Base(path)
+		}
+	}
+	return resolvedPath, rebaseName, nil
+}
+
+// GetRebaseName normalizes and compares path and resolvedPath,
+// return completed resolved path and rebased file name
+func GetRebaseName(path, resolvedPath string) (string, string) {
+	// linkTarget will have been cleaned (no trailing path separators and dot) so
+	// we can manually join it with them
+	var rebaseName string
+	if specifiesCurrentDir(path) &&
+		!specifiesCurrentDir(resolvedPath) {
+		resolvedPath += string(filepath.Separator) + "."
+	}
+
+	if hasTrailingPathSeparator(path) &&
+		!hasTrailingPathSeparator(resolvedPath) {
+		resolvedPath += string(filepath.Separator)
+	}
+
+	if filepath.Base(path) != filepath.Base(resolvedPath) {
+		// In the case where the path had a trailing separator and a symlink
+		// evaluation has changed the last path component, we will need to
+		// rebase the name in the archive that is being copied to match the
+		// originally requested name.
+		rebaseName = filepath.Base(path)
+	}
+	return resolvedPath, rebaseName
+}
diff --git a/vendor/github.com/moby/go-archive/copy_unix.go b/vendor/github.com/moby/go-archive/copy_unix.go
new file mode 100644
index 000000000..f57928244
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/copy_unix.go
@@ -0,0 +1,11 @@
+//go:build !windows
+
+package archive
+
+import (
+	"path/filepath"
+)
+
+func normalizePath(path string) string {
+	return filepath.ToSlash(path)
+}
diff --git a/vendor/github.com/moby/go-archive/copy_windows.go b/vendor/github.com/moby/go-archive/copy_windows.go
new file mode 100644
index 000000000..2b775b45c
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/copy_windows.go
@@ -0,0 +1,9 @@
+package archive
+
+import (
+	"path/filepath"
+)
+
+func normalizePath(path string) string {
+	return filepath.FromSlash(path)
+}
diff --git a/vendor/github.com/moby/go-archive/dev_freebsd.go b/vendor/github.com/moby/go-archive/dev_freebsd.go
new file mode 100644
index 000000000..b3068fce9
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/dev_freebsd.go
@@ -0,0 +1,9 @@
+//go:build freebsd
+
+package archive
+
+import "golang.org/x/sys/unix"
+
+func mknod(path string, mode uint32, dev uint64) error {
+	return unix.Mknod(path, mode, dev)
+}
diff --git a/vendor/github.com/moby/go-archive/dev_unix.go b/vendor/github.com/moby/go-archive/dev_unix.go
new file mode 100644
index 000000000..dffc596f9
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/dev_unix.go
@@ -0,0 +1,9 @@
+//go:build !windows && !freebsd
+
+package archive
+
+import "golang.org/x/sys/unix"
+
+func mknod(path string, mode uint32, dev uint64) error {
+	return unix.Mknod(path, mode, int(dev))
+}
diff --git a/vendor/github.com/moby/go-archive/diff.go b/vendor/github.com/moby/go-archive/diff.go
new file mode 100644
index 000000000..96db972d1
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/diff.go
@@ -0,0 +1,261 @@
+package archive
+
+import (
+	"archive/tar"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+
+	"github.com/containerd/log"
+
+	"github.com/moby/go-archive/compression"
+)
+
+// UnpackLayer unpack `layer` to a `dest`. The stream `layer` can be
+// compressed or uncompressed.
+// Returns the size in bytes of the contents of the layer.
+func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64, err error) {
+	tr := tar.NewReader(layer)
+
+	var dirs []*tar.Header
+	unpackedPaths := make(map[string]struct{})
+
+	if options == nil {
+		options = &TarOptions{}
+	}
+	if options.ExcludePatterns == nil {
+		options.ExcludePatterns = []string{}
+	}
+
+	aufsTempdir := ""
+	aufsHardlinks := make(map[string]*tar.Header)
+
+	// Iterate through the files in the archive.
+	for {
+		hdr, err := tr.Next()
+		if errors.Is(err, io.EOF) {
+			// end of tar archive
+			break
+		}
+		if err != nil {
+			return 0, err
+		}
+
+		size += hdr.Size
+
+		// Normalize name, for safety and for a simple is-root check
+		hdr.Name = filepath.Clean(hdr.Name)
+
+		// Windows does not support filenames with colons in them. Ignore
+		// these files. This is not a problem though (although it might
+		// appear that it is). Let's suppose a client is running docker pull.
+		// The daemon it points to is Windows. Would it make sense for the
+		// client to be doing a docker pull Ubuntu for example (which has files
+		// with colons in the name under /usr/share/man/man3)? No, absolutely
+		// not as it would really only make sense that they were pulling a
+		// Windows image. However, for development, it is necessary to be able
+		// to pull Linux images which are in the repository.
+		//
+		// TODO Windows. Once the registry is aware of what images are Windows-
+		// specific or Linux-specific, this warning should be changed to an error
+		// to cater for the situation where someone does manage to upload a Linux
+		// image but have it tagged as Windows inadvertently.
+		if runtime.GOOS == "windows" {
+			if strings.Contains(hdr.Name, ":") {
+				log.G(context.TODO()).Warnf("Windows: Ignoring %s (is this a Linux image?)", hdr.Name)
+				continue
+			}
+		}
+
+		// Ensure that the parent directory exists.
+		err = createImpliedDirectories(dest, hdr, options)
+		if err != nil {
+			return 0, err
+		}
+
+		// Skip AUFS metadata dirs
+		if strings.HasPrefix(hdr.Name, WhiteoutMetaPrefix) {
+			// Regular files inside /.wh..wh.plnk can be used as hardlink targets
+			// We don't want this directory, but we need the files in them so that
+			// such hardlinks can be resolved.
+			if strings.HasPrefix(hdr.Name, WhiteoutLinkDir) && hdr.Typeflag == tar.TypeReg {
+				basename := filepath.Base(hdr.Name)
+				aufsHardlinks[basename] = hdr
+				if aufsTempdir == "" {
+					if aufsTempdir, err = os.MkdirTemp(dest, "dockerplnk"); err != nil {
+						return 0, err
+					}
+					defer os.RemoveAll(aufsTempdir)
+				}
+				if err := createTarFile(filepath.Join(aufsTempdir, basename), dest, hdr, tr, options); err != nil {
+					return 0, err
+				}
+			}
+
+			if hdr.Name != WhiteoutOpaqueDir {
+				continue
+			}
+		}
+		// #nosec G305 -- The joined path is guarded against path traversal.
+		path := filepath.Join(dest, hdr.Name)
+		rel, err := filepath.Rel(dest, path)
+		if err != nil {
+			return 0, err
+		}
+
+		// Note as these operations are platform specific, so must the slash be.
+		if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
+			return 0, breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
+		}
+		base := filepath.Base(path)
+
+		if strings.HasPrefix(base, WhiteoutPrefix) {
+			dir := filepath.Dir(path)
+			if base == WhiteoutOpaqueDir {
+				_, err := os.Lstat(dir)
+				if err != nil {
+					return 0, err
+				}
+				err = filepath.WalkDir(dir, func(path string, info os.DirEntry, err error) error {
+					if err != nil {
+						if os.IsNotExist(err) {
+							err = nil // parent was deleted
+						}
+						return err
+					}
+					if path == dir {
+						return nil
+					}
+					if _, exists := unpackedPaths[path]; !exists {
+						return os.RemoveAll(path)
+					}
+					return nil
+				})
+				if err != nil {
+					return 0, err
+				}
+			} else {
+				originalBase := base[len(WhiteoutPrefix):]
+				originalPath := filepath.Join(dir, originalBase)
+				if err := os.RemoveAll(originalPath); err != nil {
+					return 0, err
+				}
+			}
+		} else {
+			// If path exits we almost always just want to remove and replace it.
+			// The only exception is when it is a directory *and* the file from
+			// the layer is also a directory. Then we want to merge them (i.e.
+			// just apply the metadata from the layer).
+			if fi, err := os.Lstat(path); err == nil {
+				if !fi.IsDir() || hdr.Typeflag != tar.TypeDir {
+					if err := os.RemoveAll(path); err != nil {
+						return 0, err
+					}
+				}
+			}
+
+			srcData := io.Reader(tr)
+			srcHdr := hdr
+
+			// Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so
+			// we manually retarget these into the temporary files we extracted them into
+			if hdr.Typeflag == tar.TypeLink && strings.HasPrefix(filepath.Clean(hdr.Linkname), WhiteoutLinkDir) {
+				linkBasename := filepath.Base(hdr.Linkname)
+				srcHdr = aufsHardlinks[linkBasename]
+				if srcHdr == nil {
+					return 0, errors.New("invalid aufs hardlink")
+				}
+				tmpFile, err := os.Open(filepath.Join(aufsTempdir, linkBasename))
+				if err != nil {
+					return 0, err
+				}
+				defer tmpFile.Close()
+				srcData = tmpFile
+			}
+
+			if err := remapIDs(options.IDMap, srcHdr); err != nil {
+				return 0, err
+			}
+
+			if err := createTarFile(path, dest, srcHdr, srcData, options); err != nil {
+				return 0, err
+			}
+
+			// Directory mtimes must be handled at the end to avoid further
+			// file creation in them to modify the directory mtime
+			if hdr.Typeflag == tar.TypeDir {
+				dirs = append(dirs, hdr)
+			}
+			unpackedPaths[path] = struct{}{}
+		}
+	}
+
+	for _, hdr := range dirs {
+		// #nosec G305 -- The header was checked for path traversal before it was appended to the dirs slice.
+		path := filepath.Join(dest, hdr.Name)
+		if err := chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
+			return 0, err
+		}
+	}
+
+	return size, nil
+}
+
+// ApplyLayer parses a diff in the standard layer format from `layer`,
+// and applies it to the directory `dest`. The stream `layer` can be
+// compressed or uncompressed.
+// Returns the size in bytes of the contents of the layer.
+func ApplyLayer(dest string, layer io.Reader) (int64, error) {
+	return applyLayerHandler(dest, layer, &TarOptions{}, true)
+}
+
+// ApplyUncompressedLayer parses a diff in the standard layer format from
+// `layer`, and applies it to the directory `dest`. The stream `layer`
+// can only be uncompressed.
+// Returns the size in bytes of the contents of the layer.
+func ApplyUncompressedLayer(dest string, layer io.Reader, options *TarOptions) (int64, error) {
+	return applyLayerHandler(dest, layer, options, false)
+}
+
+// IsEmpty checks if the tar archive is empty (doesn't contain any entries).
+func IsEmpty(rd io.Reader) (bool, error) {
+	decompRd, err := compression.DecompressStream(rd)
+	if err != nil {
+		return true, fmt.Errorf("failed to decompress archive: %w", err)
+	}
+	defer decompRd.Close()
+
+	tarReader := tar.NewReader(decompRd)
+	if _, err := tarReader.Next(); err != nil {
+		if errors.Is(err, io.EOF) {
+			return true, nil
+		}
+		return false, fmt.Errorf("failed to read next archive header: %w", err)
+	}
+
+	return false, nil
+}
+
+// do the bulk load of ApplyLayer, but allow for not calling DecompressStream
+func applyLayerHandler(dest string, layer io.Reader, options *TarOptions, decompress bool) (int64, error) {
+	dest = filepath.Clean(dest)
+
+	// We need to be able to set any perms
+	restore := overrideUmask(0)
+	defer restore()
+
+	if decompress {
+		decompLayer, err := compression.DecompressStream(layer)
+		if err != nil {
+			return 0, err
+		}
+		defer decompLayer.Close()
+		layer = decompLayer
+	}
+	return UnpackLayer(dest, layer, options)
+}
diff --git a/vendor/github.com/moby/go-archive/diff_unix.go b/vendor/github.com/moby/go-archive/diff_unix.go
new file mode 100644
index 000000000..7216f2f4f
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/diff_unix.go
@@ -0,0 +1,21 @@
+//go:build !windows
+
+package archive
+
+import "golang.org/x/sys/unix"
+
+// overrideUmask sets current process's file mode creation mask to newmask
+// and returns a function to restore it.
+//
+// WARNING for readers stumbling upon this code. Changing umask in a multi-
+// threaded environment isn't safe. Don't use this without understanding the
+// risks, and don't export this function for others to use (we shouldn't even
+// be using this ourself).
+//
+// FIXME(thaJeztah): we should get rid of these hacks if possible.
+func overrideUmask(newMask int) func() {
+	oldMask := unix.Umask(newMask)
+	return func() {
+		unix.Umask(oldMask)
+	}
+}
diff --git a/vendor/github.com/moby/go-archive/diff_windows.go b/vendor/github.com/moby/go-archive/diff_windows.go
new file mode 100644
index 000000000..d28f5b2df
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/diff_windows.go
@@ -0,0 +1,6 @@
+package archive
+
+// overrideUmask is a no-op on windows.
+func overrideUmask(newmask int) func() {
+	return func() {}
+}
diff --git a/vendor/github.com/moby/go-archive/path.go b/vendor/github.com/moby/go-archive/path.go
new file mode 100644
index 000000000..888a69758
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/path.go
@@ -0,0 +1,20 @@
+package archive
+
+// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter,
+// is the system drive.
+// On Linux: this is a no-op.
+// On Windows: this does the following>
+// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path.
+// This is used, for example, when validating a user provided path in docker cp.
+// If a drive letter is supplied, it must be the system drive. The drive letter
+// is always removed. Also, it translates it to OS semantics (IOW / to \). We
+// need the path in this syntax so that it can ultimately be concatenated with
+// a Windows long-path which doesn't support drive-letters. Examples:
+// C:			--> Fail
+// C:\			--> \
+// a			--> a
+// /a			--> \a
+// d:\			--> Fail
+func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) {
+	return checkSystemDriveAndRemoveDriveLetter(path)
+}
diff --git a/vendor/github.com/moby/go-archive/path_unix.go b/vendor/github.com/moby/go-archive/path_unix.go
new file mode 100644
index 000000000..390264bf8
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/path_unix.go
@@ -0,0 +1,9 @@
+//go:build !windows
+
+package archive
+
+// checkSystemDriveAndRemoveDriveLetter is the non-Windows implementation
+// of CheckSystemDriveAndRemoveDriveLetter
+func checkSystemDriveAndRemoveDriveLetter(path string) (string, error) {
+	return path, nil
+}
diff --git a/vendor/github.com/moby/go-archive/path_windows.go b/vendor/github.com/moby/go-archive/path_windows.go
new file mode 100644
index 000000000..7e18c8e44
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/path_windows.go
@@ -0,0 +1,22 @@
+package archive
+
+import (
+	"fmt"
+	"path/filepath"
+	"strings"
+)
+
+// checkSystemDriveAndRemoveDriveLetter is the Windows implementation
+// of CheckSystemDriveAndRemoveDriveLetter
+func checkSystemDriveAndRemoveDriveLetter(path string) (string, error) {
+	if len(path) == 2 && string(path[1]) == ":" {
+		return "", fmt.Errorf("no relative path specified in %q", path)
+	}
+	if !filepath.IsAbs(path) || len(path) < 2 {
+		return filepath.FromSlash(path), nil
+	}
+	if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") {
+		return "", fmt.Errorf("the specified path is not on the system drive (C:)")
+	}
+	return filepath.FromSlash(path[2:]), nil
+}
diff --git a/vendor/github.com/moby/go-archive/tarheader/tarheader.go b/vendor/github.com/moby/go-archive/tarheader/tarheader.go
new file mode 100644
index 000000000..03732a4f8
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/tarheader/tarheader.go
@@ -0,0 +1,67 @@
+package tarheader
+
+import (
+	"archive/tar"
+	"os"
+)
+
+// assert that we implement [tar.FileInfoNames].
+var _ tar.FileInfoNames = (*nosysFileInfo)(nil)
+
+// nosysFileInfo hides the system-dependent info of the wrapped FileInfo to
+// prevent tar.FileInfoHeader from introspecting it and potentially calling into
+// glibc.
+//
+// It implements [tar.FileInfoNames] to further prevent [tar.FileInfoHeader]
+// from performing any lookups on go1.23 and up. see https://go.dev/issue/50102
+type nosysFileInfo struct {
+	os.FileInfo
+}
+
+// Uname stubs out looking up username. It implements [tar.FileInfoNames]
+// to prevent [tar.FileInfoHeader] from loading libraries to perform
+// username lookups.
+func (fi nosysFileInfo) Uname() (string, error) {
+	return "", nil
+}
+
+// Gname stubs out looking up group-name. It implements [tar.FileInfoNames]
+// to prevent [tar.FileInfoHeader] from loading libraries to perform
+// username lookups.
+func (fi nosysFileInfo) Gname() (string, error) {
+	return "", nil
+}
+
+func (fi nosysFileInfo) Sys() interface{} {
+	// A Sys value of type *tar.Header is safe as it is system-independent.
+	// The tar.FileInfoHeader function copies the fields into the returned
+	// header without performing any OS lookups.
+	if sys, ok := fi.FileInfo.Sys().(*tar.Header); ok {
+		return sys
+	}
+	return nil
+}
+
+// FileInfoHeaderNoLookups creates a partially-populated tar.Header from fi.
+//
+// Compared to the archive/tar.FileInfoHeader function, this function is safe to
+// call from a chrooted process as it does not populate fields which would
+// require operating system lookups. It behaves identically to
+// tar.FileInfoHeader when fi is a FileInfo value returned from
+// tar.Header.FileInfo().
+//
+// When fi is a FileInfo for a native file, such as returned from os.Stat() and
+// os.Lstat(), the returned Header value differs from one returned from
+// tar.FileInfoHeader in the following ways. The Uname and Gname fields are not
+// set as OS lookups would be required to populate them. The AccessTime and
+// ChangeTime fields are not currently set (not yet implemented) although that
+// is subject to change. Callers which require the AccessTime or ChangeTime
+// fields to be zeroed should explicitly zero them out in the returned Header
+// value to avoid any compatibility issues in the future.
+func FileInfoHeaderNoLookups(fi os.FileInfo, link string) (*tar.Header, error) {
+	hdr, err := tar.FileInfoHeader(nosysFileInfo{fi}, link)
+	if err != nil {
+		return nil, err
+	}
+	return hdr, sysStat(fi, hdr)
+}
diff --git a/vendor/github.com/moby/go-archive/tarheader/tarheader_unix.go b/vendor/github.com/moby/go-archive/tarheader/tarheader_unix.go
new file mode 100644
index 000000000..9c3311c63
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/tarheader/tarheader_unix.go
@@ -0,0 +1,46 @@
+//go:build !windows
+
+package tarheader
+
+import (
+	"archive/tar"
+	"os"
+	"runtime"
+	"syscall"
+
+	"golang.org/x/sys/unix"
+)
+
+// sysStat populates hdr from system-dependent fields of fi without performing
+// any OS lookups.
+func sysStat(fi os.FileInfo, hdr *tar.Header) error {
+	// Devmajor and Devminor are only needed for special devices.
+
+	// In FreeBSD, RDev for regular files is -1 (unless overridden by FS):
+	// https://cgit.freebsd.org/src/tree/sys/kern/vfs_default.c?h=stable/13#n1531
+	// (NODEV is -1: https://cgit.freebsd.org/src/tree/sys/sys/param.h?h=stable/13#n241).
+
+	// ZFS in particular does not override the default:
+	// https://cgit.freebsd.org/src/tree/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c?h=stable/13#n2027
+
+	// Since `Stat_t.Rdev` is uint64, the cast turns -1 into (2^64 - 1).
+	// Such large values cannot be encoded in a tar header.
+	if runtime.GOOS == "freebsd" && hdr.Typeflag != tar.TypeBlock && hdr.Typeflag != tar.TypeChar {
+		return nil
+	}
+	s, ok := fi.Sys().(*syscall.Stat_t)
+	if !ok {
+		return nil
+	}
+
+	hdr.Uid = int(s.Uid)
+	hdr.Gid = int(s.Gid)
+
+	if s.Mode&unix.S_IFBLK != 0 ||
+		s.Mode&unix.S_IFCHR != 0 {
+		hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint: unconvert
+		hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint: unconvert
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/moby/go-archive/tarheader/tarheader_windows.go b/vendor/github.com/moby/go-archive/tarheader/tarheader_windows.go
new file mode 100644
index 000000000..5d4483ce2
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/tarheader/tarheader_windows.go
@@ -0,0 +1,12 @@
+package tarheader
+
+import (
+	"archive/tar"
+	"os"
+)
+
+// sysStat populates hdr from system-dependent fields of fi without performing
+// any OS lookups. It is a no-op on Windows.
+func sysStat(os.FileInfo, *tar.Header) error {
+	return nil
+}
diff --git a/vendor/github.com/moby/go-archive/time.go b/vendor/github.com/moby/go-archive/time.go
new file mode 100644
index 000000000..4e9ae9508
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/time.go
@@ -0,0 +1,38 @@
+package archive
+
+import (
+	"syscall"
+	"time"
+	"unsafe"
+)
+
+var (
+	minTime = time.Unix(0, 0)
+	maxTime time.Time
+)
+
+func init() {
+	if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 {
+		// This is a 64 bit timespec
+		// os.Chtimes limits time to the following
+		maxTime = time.Unix(0, 1<<63-1)
+	} else {
+		// This is a 32 bit timespec
+		maxTime = time.Unix(1<<31-1, 0)
+	}
+}
+
+func boundTime(t time.Time) time.Time {
+	if t.Before(minTime) || t.After(maxTime) {
+		return minTime
+	}
+
+	return t
+}
+
+func latestTime(t1, t2 time.Time) time.Time {
+	if t1.Before(t2) {
+		return t2
+	}
+	return t1
+}
diff --git a/vendor/github.com/moby/go-archive/time_nonwindows.go b/vendor/github.com/moby/go-archive/time_nonwindows.go
new file mode 100644
index 000000000..5bfdfa2f1
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/time_nonwindows.go
@@ -0,0 +1,41 @@
+//go:build !windows
+
+package archive
+
+import (
+	"os"
+	"time"
+
+	"golang.org/x/sys/unix"
+)
+
+// chtimes changes the access time and modified time of a file at the given path.
+// If the modified time is prior to the Unix Epoch (unixMinTime), or after the
+// end of Unix Time (unixEpochTime), os.Chtimes has undefined behavior. In this
+// case, Chtimes defaults to Unix Epoch, just in case.
+func chtimes(name string, atime time.Time, mtime time.Time) error {
+	return os.Chtimes(name, atime, mtime)
+}
+
+func timeToTimespec(time time.Time) unix.Timespec {
+	if time.IsZero() {
+		// Return UTIME_OMIT special value
+		return unix.Timespec{
+			Sec:  0,
+			Nsec: (1 << 30) - 2,
+		}
+	}
+	return unix.NsecToTimespec(time.UnixNano())
+}
+
+func lchtimes(name string, atime time.Time, mtime time.Time) error {
+	utimes := [2]unix.Timespec{
+		timeToTimespec(atime),
+		timeToTimespec(mtime),
+	}
+	err := unix.UtimesNanoAt(unix.AT_FDCWD, name, utimes[0:], unix.AT_SYMLINK_NOFOLLOW)
+	if err != nil && err != unix.ENOSYS {
+		return err
+	}
+	return err
+}
diff --git a/vendor/github.com/moby/go-archive/time_windows.go b/vendor/github.com/moby/go-archive/time_windows.go
new file mode 100644
index 000000000..af1f7c8f3
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/time_windows.go
@@ -0,0 +1,32 @@
+package archive
+
+import (
+	"os"
+	"time"
+
+	"golang.org/x/sys/windows"
+)
+
+func chtimes(name string, atime time.Time, mtime time.Time) error {
+	if err := os.Chtimes(name, atime, mtime); err != nil {
+		return err
+	}
+
+	pathp, err := windows.UTF16PtrFromString(name)
+	if err != nil {
+		return err
+	}
+	h, err := windows.CreateFile(pathp,
+		windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil,
+		windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0)
+	if err != nil {
+		return err
+	}
+	defer windows.Close(h)
+	c := windows.NsecToFiletime(mtime.UnixNano())
+	return windows.SetFileTime(h, &c, nil, nil)
+}
+
+func lchtimes(name string, atime time.Time, mtime time.Time) error {
+	return nil
+}
diff --git a/vendor/github.com/moby/go-archive/whiteouts.go b/vendor/github.com/moby/go-archive/whiteouts.go
new file mode 100644
index 000000000..d20478a10
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/whiteouts.go
@@ -0,0 +1,23 @@
+package archive
+
+// Whiteouts are files with a special meaning for the layered filesystem.
+// Docker uses AUFS whiteout files inside exported archives. In other
+// filesystems these files are generated/handled on tar creation/extraction.
+
+// WhiteoutPrefix prefix means file is a whiteout. If this is followed by a
+// filename this means that file has been removed from the base layer.
+const WhiteoutPrefix = ".wh."
+
+// WhiteoutMetaPrefix prefix means whiteout has a special meaning and is not
+// for removing an actual file. Normally these files are excluded from exported
+// archives.
+const WhiteoutMetaPrefix = WhiteoutPrefix + WhiteoutPrefix
+
+// WhiteoutLinkDir is a directory AUFS uses for storing hardlink links to other
+// layers. Normally these should not go into exported archives and all changed
+// hardlinks should be copied to the top layer.
+const WhiteoutLinkDir = WhiteoutMetaPrefix + "plnk"
+
+// WhiteoutOpaqueDir file means directory has been made opaque - meaning
+// readdir calls to this directory do not follow to lower layers.
+const WhiteoutOpaqueDir = WhiteoutMetaPrefix + ".opq"
diff --git a/vendor/github.com/moby/go-archive/wrap.go b/vendor/github.com/moby/go-archive/wrap.go
new file mode 100644
index 000000000..f8a97254e
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/wrap.go
@@ -0,0 +1,59 @@
+package archive
+
+import (
+	"archive/tar"
+	"bytes"
+	"io"
+)
+
+// Generate generates a new archive from the content provided
+// as input.
+//
+// `files` is a sequence of path/content pairs. A new file is
+// added to the archive for each pair.
+// If the last pair is incomplete, the file is created with an
+// empty content. For example:
+//
+// Generate("foo.txt", "hello world", "emptyfile")
+//
+// The above call will return an archive with 2 files:
+//   - ./foo.txt with content "hello world"
+//   - ./empty with empty content
+//
+// FIXME: stream content instead of buffering
+// FIXME: specify permissions and other archive metadata
+func Generate(input ...string) (io.Reader, error) {
+	files := parseStringPairs(input...)
+	buf := new(bytes.Buffer)
+	tw := tar.NewWriter(buf)
+	for _, file := range files {
+		name, content := file[0], file[1]
+		hdr := &tar.Header{
+			Name: name,
+			Size: int64(len(content)),
+		}
+		if err := tw.WriteHeader(hdr); err != nil {
+			return nil, err
+		}
+		if _, err := tw.Write([]byte(content)); err != nil {
+			return nil, err
+		}
+	}
+	if err := tw.Close(); err != nil {
+		return nil, err
+	}
+	return buf, nil
+}
+
+func parseStringPairs(input ...string) [][2]string {
+	output := make([][2]string, 0, len(input)/2+1)
+	for i := 0; i < len(input); i += 2 {
+		var pair [2]string
+		pair[0] = input[i]
+		if i+1 < len(input) {
+			pair[1] = input[i+1]
+		}
+		output = append(output, pair)
+	}
+	return output
+}
diff --git a/vendor/github.com/moby/go-archive/xattr_supported.go b/vendor/github.com/moby/go-archive/xattr_supported.go
new file mode 100644
index 000000000..652a1f0f3
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/xattr_supported.go
@@ -0,0 +1,52 @@
+//go:build linux || darwin || freebsd || netbsd
+
+package archive
+
+import (
+	"errors"
+	"fmt"
+	"io/fs"
+
+	"golang.org/x/sys/unix"
+)
+
+// lgetxattr retrieves the value of the extended attribute identified by attr
+// and associated with the given path in the file system.
+// It returns a nil slice and nil error if the xattr is not set.
+func lgetxattr(path string, attr string) ([]byte, error) {
+	// Start with a 128 length byte array
+	dest := make([]byte, 128)
+	sz, err := unix.Lgetxattr(path, attr, dest)
+
+	for errors.Is(err, unix.ERANGE) {
+		// Buffer too small, use zero-sized buffer to get the actual size
+		sz, err = unix.Lgetxattr(path, attr, []byte{})
+		if err != nil {
+			return nil, wrapPathError("lgetxattr", path, attr, err)
+		}
+		dest = make([]byte, sz)
+		sz, err = unix.Lgetxattr(path, attr, dest)
+	}
+
+	if err != nil {
+		if errors.Is(err, noattr) {
+			return nil, nil
+		}
+		return nil, wrapPathError("lgetxattr", path, attr, err)
+	}
+
+	return dest[:sz], nil
+}
+
+// lsetxattr sets the value of the extended attribute identified by attr
+// and associated with the given path in the file system.
+func lsetxattr(path string, attr string, data []byte, flags int) error {
+	return wrapPathError("lsetxattr", path, attr, unix.Lsetxattr(path, attr, data, flags))
+}
+
+func wrapPathError(op, path, attr string, err error) error {
+	if err == nil {
+		return nil
+	}
+	return &fs.PathError{Op: op, Path: path, Err: fmt.Errorf("xattr %q: %w", attr, err)}
+}
diff --git a/vendor/github.com/moby/go-archive/xattr_supported_linux.go b/vendor/github.com/moby/go-archive/xattr_supported_linux.go
new file mode 100644
index 000000000..f2e76465a
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/xattr_supported_linux.go
@@ -0,0 +1,5 @@
+package archive
+
+import "golang.org/x/sys/unix"
+
+var noattr = unix.ENODATA
diff --git a/vendor/github.com/moby/go-archive/xattr_supported_unix.go b/vendor/github.com/moby/go-archive/xattr_supported_unix.go
new file mode 100644
index 000000000..58a03e4a6
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/xattr_supported_unix.go
@@ -0,0 +1,7 @@
+//go:build darwin || freebsd || netbsd
+
+package archive
+
+import "golang.org/x/sys/unix"
+
+var noattr = unix.ENOATTR
diff --git a/vendor/github.com/moby/go-archive/xattr_unsupported.go b/vendor/github.com/moby/go-archive/xattr_unsupported.go
new file mode 100644
index 000000000..b0d9165cd
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/xattr_unsupported.go
@@ -0,0 +1,11 @@
+//go:build !linux && !darwin && !freebsd && !netbsd
+
+package archive
+
+func lgetxattr(path string, attr string) ([]byte, error) {
+	return nil, nil
+}
+
+func lsetxattr(path string, attr string, data []byte, flags int) error {
+	return nil
+}
diff --git a/vendor/github.com/moby/moby/api/LICENSE b/vendor/github.com/moby/moby/api/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/moby/moby/api/pkg/authconfig/authconfig.go b/vendor/github.com/moby/moby/api/pkg/authconfig/authconfig.go
new file mode 100644
index 000000000..d1b0105a6
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/pkg/authconfig/authconfig.go
@@ -0,0 +1,96 @@
+package authconfig
+
+import (
+	"bytes"
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+
+	"github.com/moby/moby/api/types/registry"
+)
+
+// Encode serializes the auth configuration as a base64url encoded
+// ([RFC4648, section 5]) JSON string for sending through the X-Registry-Auth header.
+//
+// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5
+func Encode(authConfig registry.AuthConfig) (string, error) {
+	// Older daemons (or registries) may not handle an empty string,
+	// which resulted in an "io.EOF" when unmarshaling or decoding.
+	//
+	// FIXME(thaJeztah): find exactly what code-paths are impacted by this.
+	// if authConfig == (AuthConfig{}) { return "", nil }
+	buf, err := json.Marshal(authConfig)
+	if err != nil {
+		return "", errInvalidParameter{err}
+	}
+	return base64.URLEncoding.EncodeToString(buf), nil
+}
+
+// Decode decodes base64url encoded ([RFC4648, section 5]) JSON
+// authentication information as sent through the X-Registry-Auth header.
+//
+// This function always returns an [AuthConfig], even if an error occurs. It is up
+// to the caller to decide if authentication is required, and if the error can
+// be ignored.
+//
+// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5
+func Decode(authEncoded string) (*registry.AuthConfig, error) {
+	if authEncoded == "" {
+		return &registry.AuthConfig{}, nil
+	}
+
+	decoded, err := base64.URLEncoding.DecodeString(authEncoded)
+	if err != nil {
+		var e base64.CorruptInputError
+		if errors.As(err, &e) {
+			return &registry.AuthConfig{}, invalid(errors.New("must be a valid base64url-encoded string"))
+		}
+		return &registry.AuthConfig{}, invalid(err)
+	}
+
+	if bytes.Equal(decoded, []byte("{}")) {
+		return &registry.AuthConfig{}, nil
+	}
+
+	return decode(bytes.NewReader(decoded))
+}
+
+// DecodeRequestBody decodes authentication information as sent as JSON in the
+// body of a request. This function is to provide backward compatibility with old
+// clients and API versions. Current clients and API versions expect authentication
+// to be provided through the X-Registry-Auth header.
+//
+// Like [Decode], this function always returns an [AuthConfig], even if an
+// error occurs. It is up to the caller to decide if authentication is required,
+// and if the error can be ignored.
+func DecodeRequestBody(r io.ReadCloser) (*registry.AuthConfig, error) {
+	return decode(r)
+}
+
+func decode(r io.Reader) (*registry.AuthConfig, error) {
+	authConfig := &registry.AuthConfig{}
+	dec := json.NewDecoder(r)
+	if err := dec.Decode(authConfig); err != nil {
+		// always return an (empty) AuthConfig to increase compatibility with
+		// the existing API.
+		return &registry.AuthConfig{}, invalid(fmt.Errorf("invalid JSON: %w", err))
+	}
+	if dec.More() {
+		return &registry.AuthConfig{}, invalid(errors.New("multiple JSON documents not allowed"))
+	}
+	return authConfig, nil
+}
+
+func invalid(err error) error {
+	return errInvalidParameter{fmt.Errorf("invalid X-Registry-Auth header: %w", err)}
+}
+
+type errInvalidParameter struct{ error }
+
+func (errInvalidParameter) InvalidParameter() {}
+
+func (e errInvalidParameter) Cause() error { return e.error }
+
+func (e errInvalidParameter) Unwrap() error { return e.error }
diff --git a/vendor/github.com/moby/moby/api/pkg/stdcopy/stdcopy.go b/vendor/github.com/moby/moby/api/pkg/stdcopy/stdcopy.go
new file mode 100644
index 000000000..948c6b675
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/pkg/stdcopy/stdcopy.go
@@ -0,0 +1,146 @@
+package stdcopy
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+)
+
+// StdType is the type of standard stream
+// a writer can multiplex to.
+type StdType byte
+
+const (
+	Stdin     StdType = 0 // Stdin represents standard input stream. It is present for completeness and should NOT be used. When reading the stream with [StdCopy] it is output on [Stdout].
+	Stdout    StdType = 1 // Stdout represents standard output stream.
+	Stderr    StdType = 2 // Stderr represents standard error steam.
+	Systemerr StdType = 3 // Systemerr represents errors originating from the system. When reading the stream with [StdCopy] it is returned as an error.
+)
+
+const (
+	stdWriterPrefixLen = 8
+	stdWriterFdIndex   = 0
+	stdWriterSizeIndex = 4
+
+	startingBufLen = 32*1024 + stdWriterPrefixLen + 1
+)
+
+// StdCopy is a modified version of [io.Copy] to de-multiplex messages
+// from "multiplexedSource" and copy them to destination streams
+// "destOut" and "destErr".
+//
+// StdCopy demultiplexes "multiplexedSource", assuming that it contains
+// two streams, previously multiplexed using a writer created with
+// [NewStdWriter].
+//
+// As it reads from "multiplexedSource", StdCopy writes [Stdout] messages
+// to "destOut", and [Stderr] message to "destErr]. For backward-compatibility,
+// [Stdin] messages are output to "destOut". The [Systemerr] stream provides
+// errors produced by the daemon. It is returned as an error, and terminates
+// processing the stream.
+//
+// StdCopy it reads until it hits [io.EOF] on "multiplexedSource", after
+// which it returns a nil error. In other words: any error returned indicates
+// a real underlying error, which may be when an unknown [StdType] stream
+// is received.
+//
+// The "written" return holds the total number of bytes written to "destOut"
+// and "destErr" combined.
+func StdCopy(destOut, destErr io.Writer, multiplexedSource io.Reader) (written int64, _ error) {
+	var (
+		buf       = make([]byte, startingBufLen)
+		bufLen    = len(buf)
+		nr, nw    int
+		err       error
+		out       io.Writer
+		frameSize int
+	)
+
+	for {
+		// Make sure we have at least a full header
+		for nr < stdWriterPrefixLen {
+			var nr2 int
+			nr2, err = multiplexedSource.Read(buf[nr:])
+			nr += nr2
+			if errors.Is(err, io.EOF) {
+				if nr < stdWriterPrefixLen {
+					return written, nil
+				}
+				break
+			}
+			if err != nil {
+				return 0, err
+			}
+		}
+
+		// Check the first byte to know where to write
+		stream := StdType(buf[stdWriterFdIndex])
+		switch stream {
+		case Stdin:
+			fallthrough
+		case Stdout:
+			// Write on stdout
+			out = destOut
+		case Stderr:
+			// Write on stderr
+			out = destErr
+		case Systemerr:
+			// If we're on Systemerr, we won't write anywhere.
+			// NB: if this code changes later, make sure you don't try to write
+			// to outstream if Systemerr is the stream
+			out = nil
+		default:
+			return 0, fmt.Errorf("unrecognized stream: %d", stream)
+		}
+
+		// Retrieve the size of the frame
+		frameSize = int(binary.BigEndian.Uint32(buf[stdWriterSizeIndex : stdWriterSizeIndex+4]))
+
+		// Check if the buffer is big enough to read the frame.
+		// Extend it if necessary.
+		if frameSize+stdWriterPrefixLen > bufLen {
+			buf = append(buf, make([]byte, frameSize+stdWriterPrefixLen-bufLen+1)...)
+			bufLen = len(buf)
+		}
+
+		// While the amount of bytes read is less than the size of the frame + header, we keep reading
+		for nr < frameSize+stdWriterPrefixLen {
+			var nr2 int
+			nr2, err = multiplexedSource.Read(buf[nr:])
+			nr += nr2
+			if errors.Is(err, io.EOF) {
+				if nr < frameSize+stdWriterPrefixLen {
+					return written, nil
+				}
+				break
+			}
+			if err != nil {
+				return 0, err
+			}
+		}
+
+		// we might have an error from the source mixed up in our multiplexed
+		// stream. if we do, return it.
+		if stream == Systemerr {
+			return written, fmt.Errorf("error from daemon in stream: %s", string(buf[stdWriterPrefixLen:frameSize+stdWriterPrefixLen]))
+		}
+
+		// Write the retrieved frame (without header)
+		nw, err = out.Write(buf[stdWriterPrefixLen : frameSize+stdWriterPrefixLen])
+		if err != nil {
+			return 0, err
+		}
+
+		// If the frame has not been fully written: error
+		if nw != frameSize {
+			return 0, io.ErrShortWrite
+		}
+		written += int64(nw)
+
+		// Move the rest of the buffer to the beginning
+		copy(buf, buf[frameSize+stdWriterPrefixLen:])
+		// Move the index
+		nr -= frameSize + stdWriterPrefixLen
+	}
+}
diff --git a/vendor/github.com/moby/moby/api/types/blkiodev/blkio.go b/vendor/github.com/moby/moby/api/types/blkiodev/blkio.go
new file mode 100644
index 000000000..931ae10ab
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/blkiodev/blkio.go
@@ -0,0 +1,23 @@
+package blkiodev
+
+import "fmt"
+
+// WeightDevice is a structure that holds device:weight pair
+type WeightDevice struct {
+	Path   string
+	Weight uint16
+}
+
+func (w *WeightDevice) String() string {
+	return fmt.Sprintf("%s:%d", w.Path, w.Weight)
+}
+
+// ThrottleDevice is a structure that holds device:rate_per_second pair
+type ThrottleDevice struct {
+	Path string
+	Rate uint64
+}
+
+func (t *ThrottleDevice) String() string {
+	return fmt.Sprintf("%s:%d", t.Path, t.Rate)
+}
diff --git a/vendor/github.com/moby/moby/api/types/build/build.go b/vendor/github.com/moby/moby/api/types/build/build.go
new file mode 100644
index 000000000..db9839773
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/build/build.go
@@ -0,0 +1,16 @@
+package build
+
+// BuilderVersion sets the version of underlying builder to use
+type BuilderVersion string
+
+const (
+	// BuilderV1 is the first generation builder in docker daemon
+	BuilderV1 BuilderVersion = "1"
+	// BuilderBuildKit is builder based on moby/buildkit project
+	BuilderBuildKit BuilderVersion = "2"
+)
+
+// Result contains the image id of a successful build.
+type Result struct {
+	ID string
+}
diff --git a/vendor/github.com/moby/moby/api/types/build/cache.go b/vendor/github.com/moby/moby/api/types/build/cache.go
new file mode 100644
index 000000000..39dd23a5f
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/build/cache.go
@@ -0,0 +1,35 @@
+package build
+
+import (
+	"time"
+)
+
+// CacheRecord contains information about a build cache record.
+type CacheRecord struct {
+	// ID is the unique ID of the build cache record.
+	ID string
+	// Parents is the list of parent build cache record IDs.
+	Parents []string `json:" Parents,omitempty"`
+	// Type is the cache record type.
+	Type string
+	// Description is a description of the build-step that produced the build cache.
+	Description string
+	// InUse indicates if the build cache is in use.
+	InUse bool
+	// Shared indicates if the build cache is shared.
+	Shared bool
+	// Size is the amount of disk space used by the build cache (in bytes).
+	Size int64
+	// CreatedAt is the date and time at which the build cache was created.
+	CreatedAt time.Time
+	// LastUsedAt is the date and time at which the build cache was last used.
+	LastUsedAt *time.Time
+	UsageCount int
+}
+
+// CachePruneReport contains the response for Engine API:
+// POST "/build/prune"
+type CachePruneReport struct {
+	CachesDeleted  []string
+	SpaceReclaimed uint64
+}
diff --git a/vendor/github.com/moby/moby/api/types/build/disk_usage.go b/vendor/github.com/moby/moby/api/types/build/disk_usage.go
new file mode 100644
index 000000000..3613797db
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/build/disk_usage.go
@@ -0,0 +1,36 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package build
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// DiskUsage represents system data usage for build cache resources.
+//
+// swagger:model DiskUsage
+type DiskUsage struct {
+
+	// Count of active build cache records.
+	//
+	// Example: 1
+	ActiveCount int64 `json:"ActiveCount,omitempty"`
+
+	// List of build cache records.
+	//
+	Items []CacheRecord `json:"Items,omitempty"`
+
+	// Disk space that can be reclaimed by removing inactive build cache records.
+	//
+	// Example: 12345678
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
+
+	// Count of all build cache records.
+	//
+	// Example: 4
+	TotalCount int64 `json:"TotalCount,omitempty"`
+
+	// Disk space in use by build cache records.
+	//
+	// Example: 98765432
+	TotalSize int64 `json:"TotalSize,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/checkpoint/create_request.go b/vendor/github.com/moby/moby/api/types/checkpoint/create_request.go
new file mode 100644
index 000000000..c363783f2
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/checkpoint/create_request.go
@@ -0,0 +1,8 @@
+package checkpoint
+
+// CreateRequest holds parameters to create a checkpoint from a container.
+type CreateRequest struct {
+	CheckpointID  string
+	CheckpointDir string
+	Exit          bool
+}
diff --git a/vendor/github.com/moby/moby/api/types/checkpoint/list.go b/vendor/github.com/moby/moby/api/types/checkpoint/list.go
new file mode 100644
index 000000000..94a9c0a47
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/checkpoint/list.go
@@ -0,0 +1,7 @@
+package checkpoint
+
+// Summary represents the details of a checkpoint when listing endpoints.
+type Summary struct {
+	// Name is the name of the checkpoint.
+	Name string
+}
diff --git a/vendor/github.com/moby/moby/api/types/common/error_response.go b/vendor/github.com/moby/moby/api/types/common/error_response.go
new file mode 100644
index 000000000..b49d3eea0
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/common/error_response.go
@@ -0,0 +1,17 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package common
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// ErrorResponse Represents an error.
+// Example: {"message":"Something went wrong."}
+//
+// swagger:model ErrorResponse
+type ErrorResponse struct {
+
+	// The error message.
+	// Required: true
+	Message string `json:"message"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/common/error_response_ext.go b/vendor/github.com/moby/moby/api/types/common/error_response_ext.go
new file mode 100644
index 000000000..c92dfe4b1
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/common/error_response_ext.go
@@ -0,0 +1,6 @@
+package common
+
+// Error returns the error message
+func (e ErrorResponse) Error() string {
+	return e.Message
+}
diff --git a/vendor/github.com/moby/moby/api/types/common/id_response.go b/vendor/github.com/moby/moby/api/types/common/id_response.go
new file mode 100644
index 000000000..7dfe4bf12
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/common/id_response.go
@@ -0,0 +1,16 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package common
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// IDResponse Response to an API call that returns just an Id
+//
+// swagger:model IDResponse
+type IDResponse struct {
+
+	// The id of the newly created object.
+	// Required: true
+	ID string `json:"Id"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/change_type.go b/vendor/github.com/moby/moby/api/types/container/change_type.go
new file mode 100644
index 000000000..52fc99235
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/change_type.go
@@ -0,0 +1,17 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// ChangeType Kind of change
+//
+// Can be one of:
+//
+// - `0`: Modified ("C")
+// - `1`: Added ("A")
+// - `2`: Deleted ("D")
+//
+// swagger:model ChangeType
+type ChangeType uint8
diff --git a/vendor/github.com/moby/moby/api/types/container/change_types.go b/vendor/github.com/moby/moby/api/types/container/change_types.go
new file mode 100644
index 000000000..3a3a83866
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/change_types.go
@@ -0,0 +1,23 @@
+package container
+
+const (
+	// ChangeModify represents the modify operation.
+	ChangeModify ChangeType = 0
+	// ChangeAdd represents the add operation.
+	ChangeAdd ChangeType = 1
+	// ChangeDelete represents the delete operation.
+	ChangeDelete ChangeType = 2
+)
+
+func (ct ChangeType) String() string {
+	switch ct {
+	case ChangeModify:
+		return "C"
+	case ChangeAdd:
+		return "A"
+	case ChangeDelete:
+		return "D"
+	default:
+		return ""
+	}
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/commit.go b/vendor/github.com/moby/moby/api/types/container/commit.go
new file mode 100644
index 000000000..c5aab26ff
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/commit.go
@@ -0,0 +1,7 @@
+package container
+
+import "github.com/moby/moby/api/types/common"
+
+// CommitResponse response for the commit API call, containing the ID of the
+// image that was produced.
+type CommitResponse = common.IDResponse
diff --git a/vendor/github.com/moby/moby/api/types/container/config.go b/vendor/github.com/moby/moby/api/types/container/config.go
new file mode 100644
index 000000000..78fa9f910
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/config.go
@@ -0,0 +1,50 @@
+package container
+
+import (
+	"time"
+
+	dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
+	"github.com/moby/moby/api/types/network"
+)
+
+// MinimumDuration puts a minimum on user configured duration.
+// This is to prevent API error on time unit. For example, API may
+// set 3 as healthcheck interval with intention of 3 seconds, but
+// Docker interprets it as 3 nanoseconds.
+const MinimumDuration = 1 * time.Millisecond
+
+// HealthConfig holds configuration settings for the HEALTHCHECK feature.
+type HealthConfig = dockerspec.HealthcheckConfig
+
+// Config contains the configuration data about a container.
+// It should hold only portable information about the container.
+// Here, "portable" means "independent from the host we are running on".
+// Non-portable information *should* appear in HostConfig.
+// All fields added to this struct must be marked `omitempty` to keep getting
+// predictable hashes from the old `v1Compatibility` configuration.
+type Config struct {
+	Hostname        string              // Hostname
+	Domainname      string              // Domainname
+	User            string              // User that will run the command(s) inside the container, also support user:group
+	AttachStdin     bool                // Attach the standard input, makes possible user interaction
+	AttachStdout    bool                // Attach the standard output
+	AttachStderr    bool                // Attach the standard error
+	ExposedPorts    network.PortSet     `json:",omitempty"` // List of exposed ports
+	Tty             bool                // Attach standard streams to a tty, including stdin if it is not closed.
+	OpenStdin       bool                // Open stdin
+	StdinOnce       bool                // If true, close stdin after the 1 attached client disconnects.
+	Env             []string            // List of environment variable to set in the container
+	Cmd             []string            // Command to run when starting the container
+	Healthcheck     *HealthConfig       `json:",omitempty"` // Healthcheck describes how to check the container is healthy
+	ArgsEscaped     bool                `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific).
+	Image           string              // Name of the image as it was passed by the operator (e.g. could be symbolic)
+	Volumes         map[string]struct{} // List of volumes (mounts) used for the container
+	WorkingDir      string              // Current directory (PWD) in the command will be launched
+	Entrypoint      []string            // Entrypoint to run when starting the container
+	NetworkDisabled bool                `json:",omitempty"` // Is network disabled
+	OnBuild         []string            `json:",omitempty"` // ONBUILD metadata that were defined on the image Dockerfile
+	Labels          map[string]string   // List of labels set to this container
+	StopSignal      string              `json:",omitempty"` // Signal to stop a container
+	StopTimeout     *int                `json:",omitempty"` // Timeout (in seconds) to stop a container
+	Shell           []string            `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/container.go b/vendor/github.com/moby/moby/api/types/container/container.go
new file mode 100644
index 000000000..bffb3de87
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/container.go
@@ -0,0 +1,151 @@
+package container
+
+import (
+	"os"
+	"time"
+
+	"github.com/moby/moby/api/types/mount"
+	"github.com/moby/moby/api/types/storage"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// PruneReport contains the response for Engine API:
+// POST "/containers/prune"
+type PruneReport struct {
+	ContainersDeleted []string
+	SpaceReclaimed    uint64
+}
+
+// PathStat is used to encode the header from
+// GET "/containers/{name:.*}/archive"
+// "Name" is the file or directory name.
+type PathStat struct {
+	Name       string      `json:"name"`
+	Size       int64       `json:"size"`
+	Mode       os.FileMode `json:"mode"`
+	Mtime      time.Time   `json:"mtime"`
+	LinkTarget string      `json:"linkTarget"`
+}
+
+// MountPoint represents a mount point configuration inside the container.
+// This is used for reporting the mountpoints in use by a container.
+type MountPoint struct {
+	// Type is the type of mount, see [mount.Type] definitions for details.
+	Type mount.Type `json:",omitempty"`
+
+	// Name is the name reference to the underlying data defined by `Source`
+	// e.g., the volume name.
+	Name string `json:",omitempty"`
+
+	// Source is the source location of the mount.
+	//
+	// For volumes, this contains the storage location of the volume (within
+	// `/var/lib/docker/volumes/`). For bind-mounts, and `npipe`, this contains
+	// the source (host) part of the bind-mount. For `tmpfs` mount points, this
+	// field is empty.
+	Source string
+
+	// Destination is the path relative to the container root (`/`) where the
+	// Source is mounted inside the container.
+	Destination string
+
+	// Driver is the volume driver used to create the volume (if it is a volume).
+	Driver string `json:",omitempty"`
+
+	// Mode is a comma separated list of options supplied by the user when
+	// creating the bind/volume mount.
+	//
+	// The default is platform-specific (`"z"` on Linux, empty on Windows).
+	Mode string
+
+	// RW indicates whether the mount is mounted writable (read-write).
+	RW bool
+
+	// Propagation describes how mounts are propagated from the host into the
+	// mount point, and vice-versa. Refer to the Linux kernel documentation
+	// for details:
+	// https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt
+	//
+	// This field is not used on Windows.
+	Propagation mount.Propagation
+}
+
+// State stores container's running state
+// it's part of ContainerJSONBase and returned by "inspect" command
+type State struct {
+	Status     ContainerState // String representation of the container state. Can be one of "created", "running", "paused", "restarting", "removing", "exited", or "dead"
+	Running    bool
+	Paused     bool
+	Restarting bool
+	OOMKilled  bool
+	Dead       bool
+	Pid        int
+	ExitCode   int
+	Error      string
+	StartedAt  string
+	FinishedAt string
+	Health     *Health `json:",omitempty"`
+}
+
+// Summary contains response of Engine API:
+// GET "/containers/json"
+type Summary struct {
+	ID                      string `json:"Id"`
+	Names                   []string
+	Image                   string
+	ImageID                 string
+	ImageManifestDescriptor *ocispec.Descriptor `json:"ImageManifestDescriptor,omitempty"`
+	Command                 string
+	Created                 int64
+	Ports                   []PortSummary
+	SizeRw                  int64 `json:",omitempty"`
+	SizeRootFs              int64 `json:",omitempty"`
+	Labels                  map[string]string
+	State                   ContainerState
+	Status                  string
+	HostConfig              struct {
+		NetworkMode string            `json:",omitempty"`
+		Annotations map[string]string `json:",omitempty"`
+	}
+	Health          *HealthSummary `json:",omitempty"`
+	NetworkSettings *NetworkSettingsSummary
+	Mounts          []MountPoint
+}
+
+// InspectResponse is the response for the GET "/containers/{name:.*}/json"
+// endpoint.
+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"`
+
+	// 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"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/create_request.go b/vendor/github.com/moby/moby/api/types/container/create_request.go
new file mode 100644
index 000000000..decb208af
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/create_request.go
@@ -0,0 +1,13 @@
+package container
+
+import "github.com/moby/moby/api/types/network"
+
+// CreateRequest is the request message sent to the server for container
+// create calls. It is a config wrapper that holds the container [Config]
+// (portable) and the corresponding [HostConfig] (non-portable) and
+// [network.NetworkingConfig].
+type CreateRequest struct {
+	*Config
+	HostConfig       *HostConfig               `json:"HostConfig,omitempty"`
+	NetworkingConfig *network.NetworkingConfig `json:"NetworkingConfig,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/create_response.go b/vendor/github.com/moby/moby/api/types/container/create_response.go
new file mode 100644
index 000000000..39d761aa9
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/create_response.go
@@ -0,0 +1,24 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// CreateResponse ContainerCreateResponse
+//
+// # OK response to ContainerCreate operation
+//
+// swagger:model CreateResponse
+type CreateResponse struct {
+
+	// The ID of the created container
+	// Example: ede54ee1afda366ab42f824e8a5ffd195155d853ceaec74a927f249ea270c743
+	// Required: true
+	ID string `json:"Id"`
+
+	// Warnings encountered when creating the container
+	// Example: []
+	// Required: true
+	Warnings []string `json:"Warnings"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/disk_usage.go b/vendor/github.com/moby/moby/api/types/container/disk_usage.go
new file mode 100644
index 000000000..c36721d3b
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/disk_usage.go
@@ -0,0 +1,36 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// DiskUsage represents system data usage information for container resources.
+//
+// swagger:model DiskUsage
+type DiskUsage struct {
+
+	// Count of active containers.
+	//
+	// Example: 1
+	ActiveCount int64 `json:"ActiveCount,omitempty"`
+
+	// List of container summaries.
+	//
+	Items []Summary `json:"Items,omitempty"`
+
+	// Disk space that can be reclaimed by removing inactive containers.
+	//
+	// Example: 12345678
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
+
+	// Count of all containers.
+	//
+	// Example: 4
+	TotalCount int64 `json:"TotalCount,omitempty"`
+
+	// Disk space in use by containers.
+	//
+	// Example: 98765432
+	TotalSize int64 `json:"TotalSize,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/errors.go b/vendor/github.com/moby/moby/api/types/container/errors.go
new file mode 100644
index 000000000..32c978037
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/errors.go
@@ -0,0 +1,9 @@
+package container
+
+type errInvalidParameter struct{ error }
+
+func (e *errInvalidParameter) InvalidParameter() {}
+
+func (e *errInvalidParameter) Unwrap() error {
+	return e.error
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/exec.go b/vendor/github.com/moby/moby/api/types/container/exec.go
new file mode 100644
index 000000000..6895926ae
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/exec.go
@@ -0,0 +1,35 @@
+package container
+
+import "github.com/moby/moby/api/types/common"
+
+// ExecCreateResponse is the response for a successful exec-create request.
+// It holds the ID of the exec that was created.
+//
+// TODO(thaJeztah): make this a distinct type.
+type ExecCreateResponse = common.IDResponse
+
+// ExecInspectResponse is the API response for the "GET /exec/{id}/json"
+// endpoint and holds information about and exec.
+type ExecInspectResponse struct {
+	ID            string `json:"ID"`
+	Running       bool   `json:"Running"`
+	ExitCode      *int   `json:"ExitCode"`
+	ProcessConfig *ExecProcessConfig
+	OpenStdin     bool   `json:"OpenStdin"`
+	OpenStderr    bool   `json:"OpenStderr"`
+	OpenStdout    bool   `json:"OpenStdout"`
+	CanRemove     bool   `json:"CanRemove"`
+	ContainerID   string `json:"ContainerID"`
+	DetachKeys    []byte `json:"DetachKeys"`
+	Pid           int    `json:"Pid"`
+}
+
+// ExecProcessConfig holds information about the exec process
+// running on the host.
+type ExecProcessConfig struct {
+	Tty        bool     `json:"tty"`
+	Entrypoint string   `json:"entrypoint"`
+	Arguments  []string `json:"arguments"`
+	Privileged *bool    `json:"privileged,omitempty"`
+	User       string   `json:"user,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/exec_create_request.go b/vendor/github.com/moby/moby/api/types/container/exec_create_request.go
new file mode 100644
index 000000000..dd7437cd2
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/exec_create_request.go
@@ -0,0 +1,17 @@
+package container
+
+// ExecCreateRequest is a small subset of the Config struct that holds the configuration
+// for the exec feature of docker.
+type ExecCreateRequest struct {
+	User         string   // User that will run the command
+	Privileged   bool     // Is the container in privileged mode
+	Tty          bool     // Attach standard streams to a tty.
+	ConsoleSize  *[2]uint `json:",omitempty"` // Initial console size [height, width]
+	AttachStdin  bool     // Attach the standard input, makes possible user interaction
+	AttachStderr bool     // Attach the standard error
+	AttachStdout bool     // Attach the standard output
+	DetachKeys   string   // Escape keys for detach
+	Env          []string // Environment variables
+	WorkingDir   string   // Working directory
+	Cmd          []string // Execution commands and args
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/exec_start_request.go b/vendor/github.com/moby/moby/api/types/container/exec_start_request.go
new file mode 100644
index 000000000..4c2ba0a77
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/exec_start_request.go
@@ -0,0 +1,12 @@
+package container
+
+// ExecStartRequest is a temp struct used by execStart
+// Config fields is part of ExecConfig in runconfig package
+type ExecStartRequest struct {
+	// ExecStart will first check if it's detached
+	Detach bool
+	// Check if there's a tty
+	Tty bool
+	// Terminal size [height, width], unused if Tty == false
+	ConsoleSize *[2]uint `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/filesystem_change.go b/vendor/github.com/moby/moby/api/types/container/filesystem_change.go
new file mode 100644
index 000000000..b9ec83e52
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/filesystem_change.go
@@ -0,0 +1,21 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// FilesystemChange Change in the container's filesystem.
+//
+// swagger:model FilesystemChange
+type FilesystemChange struct {
+
+	// kind
+	// Required: true
+	Kind ChangeType `json:"Kind"`
+
+	// Path to file or directory that has changed.
+	//
+	// Required: true
+	Path string `json:"Path"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/health.go b/vendor/github.com/moby/moby/api/types/container/health.go
new file mode 100644
index 000000000..1a1ba84b4
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/health.go
@@ -0,0 +1,57 @@
+package container
+
+import (
+	"fmt"
+	"strings"
+	"time"
+)
+
+// HealthStatus is a string representation of the container's health.
+type HealthStatus string
+
+// Health states
+const (
+	NoHealthcheck HealthStatus = "none"      // Indicates there is no healthcheck
+	Starting      HealthStatus = "starting"  // Starting indicates that the container is not yet ready
+	Healthy       HealthStatus = "healthy"   // Healthy indicates that the container is running correctly
+	Unhealthy     HealthStatus = "unhealthy" // Unhealthy indicates that the container has a problem
+)
+
+// Health stores information about the container's healthcheck results
+type Health struct {
+	Status        HealthStatus         // Status is one of [Starting], [Healthy] or [Unhealthy].
+	FailingStreak int                  // FailingStreak is the number of consecutive failures
+	Log           []*HealthcheckResult // Log contains the last few results (oldest first)
+}
+
+// HealthSummary stores a summary of the container's healthcheck results.
+type HealthSummary struct {
+	Status        HealthStatus // Status is one of [NoHealthcheck], [Starting], [Healthy] or [Unhealthy].
+	FailingStreak int          // FailingStreak is the number of consecutive failures
+}
+
+// HealthcheckResult stores information about a single run of a healthcheck probe
+type HealthcheckResult struct {
+	Start    time.Time // Start is the time this check started
+	End      time.Time // End is the time this check ended
+	ExitCode int       // ExitCode meanings: 0=healthy, 1=unhealthy, 2=reserved (considered unhealthy), else=error running probe
+	Output   string    // Output from last check
+}
+
+var validHealths = []string{
+	string(NoHealthcheck),
+	string(Starting),
+	string(Healthy),
+	string(Unhealthy),
+}
+
+// ValidateHealthStatus checks if the provided string is a valid
+// container [HealthStatus].
+func ValidateHealthStatus(s HealthStatus) error {
+	switch s {
+	case NoHealthcheck, Starting, Healthy, Unhealthy:
+		return nil
+	default:
+		return errInvalidParameter{error: fmt.Errorf("invalid value for health (%s): must be one of %s", s, strings.Join(validHealths, ", "))}
+	}
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/hostconfig.go b/vendor/github.com/moby/moby/api/types/container/hostconfig.go
new file mode 100644
index 000000000..0f889c651
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/hostconfig.go
@@ -0,0 +1,495 @@
+package container
+
+import (
+	"errors"
+	"fmt"
+	"net/netip"
+	"strings"
+
+	"github.com/docker/go-units"
+	"github.com/moby/moby/api/types/blkiodev"
+	"github.com/moby/moby/api/types/mount"
+	"github.com/moby/moby/api/types/network"
+)
+
+// CgroupnsMode represents the cgroup namespace mode of the container
+type CgroupnsMode string
+
+// cgroup namespace modes for containers
+const (
+	CgroupnsModeEmpty   CgroupnsMode = ""
+	CgroupnsModePrivate CgroupnsMode = "private"
+	CgroupnsModeHost    CgroupnsMode = "host"
+)
+
+// IsPrivate indicates whether the container uses its own private cgroup namespace
+func (c CgroupnsMode) IsPrivate() bool {
+	return c == CgroupnsModePrivate
+}
+
+// IsHost indicates whether the container shares the host's cgroup namespace
+func (c CgroupnsMode) IsHost() bool {
+	return c == CgroupnsModeHost
+}
+
+// IsEmpty indicates whether the container cgroup namespace mode is unset
+func (c CgroupnsMode) IsEmpty() bool {
+	return c == CgroupnsModeEmpty
+}
+
+// Valid indicates whether the cgroup namespace mode is valid
+func (c CgroupnsMode) Valid() bool {
+	return c.IsEmpty() || c.IsPrivate() || c.IsHost()
+}
+
+// Isolation represents the isolation technology of a container. The supported
+// values are platform specific
+type Isolation string
+
+// Isolation modes for containers
+const (
+	IsolationEmpty   Isolation = ""        // IsolationEmpty is unspecified (same behavior as default)
+	IsolationDefault Isolation = "default" // IsolationDefault is the default isolation mode on current daemon
+	IsolationProcess Isolation = "process" // IsolationProcess is process isolation mode
+	IsolationHyperV  Isolation = "hyperv"  // IsolationHyperV is HyperV isolation mode
+)
+
+// IsDefault indicates the default isolation technology of a container. On Linux this
+// is the native driver. On Windows, this is a Windows Server Container.
+func (i Isolation) IsDefault() bool {
+	// TODO consider making isolation-mode strict (case-sensitive)
+	v := Isolation(strings.ToLower(string(i)))
+	return v == IsolationDefault || v == IsolationEmpty
+}
+
+// IsHyperV indicates the use of a Hyper-V partition for isolation
+func (i Isolation) IsHyperV() bool {
+	// TODO consider making isolation-mode strict (case-sensitive)
+	return Isolation(strings.ToLower(string(i))) == IsolationHyperV
+}
+
+// IsProcess indicates the use of process isolation
+func (i Isolation) IsProcess() bool {
+	// TODO consider making isolation-mode strict (case-sensitive)
+	return Isolation(strings.ToLower(string(i))) == IsolationProcess
+}
+
+// IpcMode represents the container ipc stack.
+type IpcMode string
+
+// IpcMode constants
+const (
+	IPCModeNone      IpcMode = "none"
+	IPCModeHost      IpcMode = "host"
+	IPCModeContainer IpcMode = "container"
+	IPCModePrivate   IpcMode = "private"
+	IPCModeShareable IpcMode = "shareable"
+)
+
+// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared.
+func (n IpcMode) IsPrivate() bool {
+	return n == IPCModePrivate
+}
+
+// IsHost indicates whether the container shares the host's ipc namespace.
+func (n IpcMode) IsHost() bool {
+	return n == IPCModeHost
+}
+
+// IsShareable indicates whether the container's ipc namespace can be shared with another container.
+func (n IpcMode) IsShareable() bool {
+	return n == IPCModeShareable
+}
+
+// IsContainer indicates whether the container uses another container's ipc namespace.
+func (n IpcMode) IsContainer() bool {
+	_, ok := containerID(string(n))
+	return ok
+}
+
+// IsNone indicates whether container IpcMode is set to "none".
+func (n IpcMode) IsNone() bool {
+	return n == IPCModeNone
+}
+
+// IsEmpty indicates whether container IpcMode is empty
+func (n IpcMode) IsEmpty() bool {
+	return n == ""
+}
+
+// Valid indicates whether the ipc mode is valid.
+func (n IpcMode) Valid() bool {
+	// TODO(thaJeztah): align with PidMode, and consider container-mode without a container name/ID to be invalid.
+	return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer()
+}
+
+// Container returns the name of the container ipc stack is going to be used.
+func (n IpcMode) Container() (idOrName string) {
+	idOrName, _ = containerID(string(n))
+	return idOrName
+}
+
+// NetworkMode represents the container network stack.
+type NetworkMode string
+
+// IsNone indicates whether container isn't using a network stack.
+func (n NetworkMode) IsNone() bool {
+	return n == network.NetworkNone
+}
+
+// IsDefault indicates whether container uses the default network stack.
+func (n NetworkMode) IsDefault() bool {
+	return n == network.NetworkDefault
+}
+
+// IsPrivate indicates whether container uses its private network stack.
+func (n NetworkMode) IsPrivate() bool {
+	return !n.IsHost() && !n.IsContainer()
+}
+
+// IsContainer indicates whether container uses a container network stack.
+func (n NetworkMode) IsContainer() bool {
+	_, ok := containerID(string(n))
+	return ok
+}
+
+// ConnectedContainer is the id of the container which network this container is connected to.
+func (n NetworkMode) ConnectedContainer() (idOrName string) {
+	idOrName, _ = containerID(string(n))
+	return idOrName
+}
+
+// UserDefined indicates user-created network
+func (n NetworkMode) UserDefined() string {
+	if n.IsUserDefined() {
+		return string(n)
+	}
+	return ""
+}
+
+// UsernsMode represents userns mode in the container.
+type UsernsMode string
+
+// IsHost indicates whether the container uses the host's userns.
+func (n UsernsMode) IsHost() bool {
+	return n == "host"
+}
+
+// IsPrivate indicates whether the container uses the a private userns.
+func (n UsernsMode) IsPrivate() bool {
+	return !n.IsHost()
+}
+
+// Valid indicates whether the userns is valid.
+func (n UsernsMode) Valid() bool {
+	return n == "" || n.IsHost()
+}
+
+// CgroupSpec represents the cgroup to use for the container.
+type CgroupSpec string
+
+// IsContainer indicates whether the container is using another container cgroup
+func (c CgroupSpec) IsContainer() bool {
+	_, ok := containerID(string(c))
+	return ok
+}
+
+// Valid indicates whether the cgroup spec is valid.
+func (c CgroupSpec) Valid() bool {
+	// TODO(thaJeztah): align with PidMode, and consider container-mode without a container name/ID to be invalid.
+	return c == "" || c.IsContainer()
+}
+
+// Container returns the ID or name of the container whose cgroup will be used.
+func (c CgroupSpec) Container() (idOrName string) {
+	idOrName, _ = containerID(string(c))
+	return idOrName
+}
+
+// UTSMode represents the UTS namespace of the container.
+type UTSMode string
+
+// IsPrivate indicates whether the container uses its private UTS namespace.
+func (n UTSMode) IsPrivate() bool {
+	return !n.IsHost()
+}
+
+// IsHost indicates whether the container uses the host's UTS namespace.
+func (n UTSMode) IsHost() bool {
+	return n == "host"
+}
+
+// Valid indicates whether the UTS namespace is valid.
+func (n UTSMode) Valid() bool {
+	return n == "" || n.IsHost()
+}
+
+// PidMode represents the pid namespace of the container.
+type PidMode string
+
+// IsPrivate indicates whether the container uses its own new pid namespace.
+func (n PidMode) IsPrivate() bool {
+	return !n.IsHost() && !n.IsContainer()
+}
+
+// IsHost indicates whether the container uses the host's pid namespace.
+func (n PidMode) IsHost() bool {
+	return n == "host"
+}
+
+// IsContainer indicates whether the container uses a container's pid namespace.
+func (n PidMode) IsContainer() bool {
+	_, ok := containerID(string(n))
+	return ok
+}
+
+// Valid indicates whether the pid namespace is valid.
+func (n PidMode) Valid() bool {
+	return n == "" || n.IsHost() || validContainer(string(n))
+}
+
+// Container returns the name of the container whose pid namespace is going to be used.
+func (n PidMode) Container() (idOrName string) {
+	idOrName, _ = containerID(string(n))
+	return idOrName
+}
+
+// DeviceRequest represents a request for devices from a device driver.
+// Used by GPU device drivers.
+type DeviceRequest struct {
+	Driver       string            // Name of device driver
+	Count        int               // Number of devices to request (-1 = All)
+	DeviceIDs    []string          // List of device IDs as recognizable by the device driver
+	Capabilities [][]string        // An OR list of AND lists of device capabilities (e.g. "gpu")
+	Options      map[string]string // Options to pass onto the device driver
+}
+
+// DeviceMapping represents the device mapping between the host and the container.
+type DeviceMapping struct {
+	PathOnHost        string
+	PathInContainer   string
+	CgroupPermissions string
+}
+
+// RestartPolicy represents the restart policies of the container.
+type RestartPolicy struct {
+	Name              RestartPolicyMode
+	MaximumRetryCount int
+}
+
+type RestartPolicyMode string
+
+const (
+	RestartPolicyDisabled      RestartPolicyMode = "no"
+	RestartPolicyAlways        RestartPolicyMode = "always"
+	RestartPolicyOnFailure     RestartPolicyMode = "on-failure"
+	RestartPolicyUnlessStopped RestartPolicyMode = "unless-stopped"
+)
+
+// IsNone indicates whether the container has the "no" restart policy.
+// This means the container will not automatically restart when exiting.
+func (rp *RestartPolicy) IsNone() bool {
+	return rp.Name == RestartPolicyDisabled || rp.Name == ""
+}
+
+// IsAlways indicates whether the container has the "always" restart policy.
+// This means the container will automatically restart regardless of the exit status.
+func (rp *RestartPolicy) IsAlways() bool {
+	return rp.Name == RestartPolicyAlways
+}
+
+// IsOnFailure indicates whether the container has the "on-failure" restart policy.
+// This means the container will automatically restart of exiting with a non-zero exit status.
+func (rp *RestartPolicy) IsOnFailure() bool {
+	return rp.Name == RestartPolicyOnFailure
+}
+
+// IsUnlessStopped indicates whether the container has the
+// "unless-stopped" restart policy. This means the container will
+// automatically restart unless user has put it to stopped state.
+func (rp *RestartPolicy) IsUnlessStopped() bool {
+	return rp.Name == RestartPolicyUnlessStopped
+}
+
+// IsSame compares two RestartPolicy to see if they are the same
+func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool {
+	return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount
+}
+
+// ValidateRestartPolicy validates the given RestartPolicy.
+func ValidateRestartPolicy(policy RestartPolicy) error {
+	switch policy.Name {
+	case RestartPolicyAlways, RestartPolicyUnlessStopped, RestartPolicyDisabled:
+		if policy.MaximumRetryCount != 0 {
+			msg := "invalid restart policy: maximum retry count can only be used with 'on-failure'"
+			if policy.MaximumRetryCount < 0 {
+				msg += " and cannot be negative"
+			}
+			return &errInvalidParameter{errors.New(msg)}
+		}
+		return nil
+	case RestartPolicyOnFailure:
+		if policy.MaximumRetryCount < 0 {
+			return &errInvalidParameter{errors.New("invalid restart policy: maximum retry count cannot be negative")}
+		}
+		return nil
+	case "":
+		// Versions before v25.0.0 created an empty restart-policy "name" as
+		// default. Allow an empty name with "any" MaximumRetryCount for
+		// backward-compatibility.
+		return nil
+	default:
+		return &errInvalidParameter{fmt.Errorf("invalid restart policy: unknown policy '%s'; use one of '%s', '%s', '%s', or '%s'", policy.Name, RestartPolicyDisabled, RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyUnlessStopped)}
+	}
+}
+
+// LogMode is a type to define the available modes for logging
+// These modes affect how logs are handled when log messages start piling up.
+type LogMode string
+
+// Available logging modes
+const (
+	LogModeUnset    LogMode = ""
+	LogModeBlocking LogMode = "blocking"
+	LogModeNonBlock LogMode = "non-blocking"
+)
+
+// LogConfig represents the logging configuration of the container.
+type LogConfig struct {
+	Type   string
+	Config map[string]string
+}
+
+// Ulimit is an alias for [units.Ulimit], which may be moving to a different
+// location or become a local type. This alias is to help transitioning.
+//
+// Users are recommended to use this alias instead of using [units.Ulimit] directly.
+type Ulimit = units.Ulimit
+
+// Resources contains container's resources (cgroups config, ulimits...)
+type Resources struct {
+	// Applicable to all platforms
+	CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers)
+	Memory    int64 // Memory limit (in bytes)
+	NanoCPUs  int64 `json:"NanoCpus"` // CPU quota in units of 10<sup>-9</sup> CPUs.
+
+	// Applicable to UNIX platforms
+	CgroupParent         string // Parent cgroup.
+	BlkioWeight          uint16 // Block IO weight (relative weight vs. other containers)
+	BlkioWeightDevice    []*blkiodev.WeightDevice
+	BlkioDeviceReadBps   []*blkiodev.ThrottleDevice
+	BlkioDeviceWriteBps  []*blkiodev.ThrottleDevice
+	BlkioDeviceReadIOps  []*blkiodev.ThrottleDevice
+	BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice
+	CPUPeriod            int64           `json:"CpuPeriod"`          // CPU CFS (Completely Fair Scheduler) period
+	CPUQuota             int64           `json:"CpuQuota"`           // CPU CFS (Completely Fair Scheduler) quota
+	CPURealtimePeriod    int64           `json:"CpuRealtimePeriod"`  // CPU real-time period
+	CPURealtimeRuntime   int64           `json:"CpuRealtimeRuntime"` // CPU real-time runtime
+	CpusetCpus           string          // CpusetCpus 0-2, 0,1
+	CpusetMems           string          // CpusetMems 0-2, 0,1
+	Devices              []DeviceMapping // List of devices to map inside the container
+	DeviceCgroupRules    []string        // List of rule to be added to the device cgroup
+	DeviceRequests       []DeviceRequest // List of device requests for device drivers
+	MemoryReservation    int64           // Memory soft limit (in bytes)
+	MemorySwap           int64           // Total memory usage (memory + swap); set `-1` to enable unlimited swap
+	MemorySwappiness     *int64          // Tuning container memory swappiness behaviour
+	OomKillDisable       *bool           // Whether to disable OOM Killer or not
+	PidsLimit            *int64          // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change.
+	Ulimits              []*Ulimit       // List of ulimits to be set in the container
+
+	// Applicable to Windows
+	CPUCount           int64  `json:"CpuCount"`   // CPU count
+	CPUPercent         int64  `json:"CpuPercent"` // CPU percent
+	IOMaximumIOps      uint64 // Maximum IOps for the container system drive
+	IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive
+}
+
+// UpdateConfig holds the mutable attributes of a Container.
+// Those attributes can be updated at runtime.
+type UpdateConfig struct {
+	// Contains container's resources (cgroups, ulimits)
+	Resources
+	RestartPolicy RestartPolicy
+}
+
+// HostConfig the non-portable Config structure of a container.
+// Here, "non-portable" means "dependent of the host we are running on".
+// Portable information *should* appear in Config.
+type HostConfig struct {
+	// Applicable to all platforms
+	Binds           []string          // List of volume bindings for this container
+	ContainerIDFile string            // File (path) where the containerId is written
+	LogConfig       LogConfig         // Configuration of the logs for this container
+	NetworkMode     NetworkMode       // Network mode to use for the container
+	PortBindings    network.PortMap   // Port mapping between the exposed port (container) and the host
+	RestartPolicy   RestartPolicy     // Restart policy to be used for the container
+	AutoRemove      bool              // Automatically remove container when it exits
+	VolumeDriver    string            // Name of the volume driver used to mount volumes
+	VolumesFrom     []string          // List of volumes to take from other container
+	ConsoleSize     [2]uint           // Initial console size (height,width)
+	Annotations     map[string]string `json:",omitempty"` // Arbitrary non-identifying metadata attached to container and provided to the runtime
+
+	// Applicable to UNIX platforms
+	CapAdd          []string          // List of kernel capabilities to add to the container
+	CapDrop         []string          // List of kernel capabilities to remove from the container
+	CgroupnsMode    CgroupnsMode      // Cgroup namespace mode to use for the container
+	DNS             []netip.Addr      `json:"Dns"`        // List of DNS server to lookup
+	DNSOptions      []string          `json:"DnsOptions"` // List of DNSOption to look for
+	DNSSearch       []string          `json:"DnsSearch"`  // List of DNSSearch to look for
+	ExtraHosts      []string          // List of extra hosts
+	GroupAdd        []string          // List of additional groups that the container process will run as
+	IpcMode         IpcMode           // IPC namespace to use for the container
+	Cgroup          CgroupSpec        // Cgroup to use for the container
+	Links           []string          // List of links (in the name:alias form)
+	OomScoreAdj     int               // Container preference for OOM-killing
+	PidMode         PidMode           // PID namespace to use for the container
+	Privileged      bool              // Is the container in privileged mode
+	PublishAllPorts bool              // Should docker publish all exposed port for the container
+	ReadonlyRootfs  bool              // Is the container root filesystem in read-only
+	SecurityOpt     []string          // List of string values to customize labels for MLS systems, such as SELinux.
+	StorageOpt      map[string]string `json:",omitempty"` // Storage driver options per container.
+	Tmpfs           map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container
+	UTSMode         UTSMode           // UTS namespace to use for the container
+	UsernsMode      UsernsMode        // The user namespace to use for the container
+	ShmSize         int64             // Total shm memory usage
+	Sysctls         map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container
+	Runtime         string            `json:",omitempty"` // Runtime to use with this container
+
+	// Applicable to Windows
+	Isolation Isolation // Isolation technology of the container (e.g. default, hyperv)
+
+	// Contains container's resources (cgroups, ulimits)
+	Resources
+
+	// Mounts specs used by the container
+	Mounts []mount.Mount `json:",omitempty"`
+
+	// MaskedPaths is the list of paths to be masked inside the container (this overrides the default set of paths)
+	MaskedPaths []string
+
+	// ReadonlyPaths is the list of paths to be set as read-only inside the container (this overrides the default set of paths)
+	ReadonlyPaths []string
+
+	// Run a custom init inside the container, if null, use the daemon's configured settings
+	Init *bool `json:",omitempty"`
+}
+
+// containerID splits "container:<ID|name>" values. It returns the container
+// ID or name, and whether an ID/name was found. It returns an empty string and
+// a "false" if the value does not have a "container:" prefix. Further validation
+// of the returned, including checking if the value is empty, should be handled
+// by the caller.
+func containerID(val string) (idOrName string, ok bool) {
+	k, v, hasSep := strings.Cut(val, ":")
+	if !hasSep || k != "container" {
+		return "", false
+	}
+	return v, true
+}
+
+// validContainer checks if the given value is a "container:" mode with
+// a non-empty name/ID.
+func validContainer(val string) bool {
+	id, ok := containerID(val)
+	return ok && id != ""
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/hostconfig_unix.go b/vendor/github.com/moby/moby/api/types/container/hostconfig_unix.go
new file mode 100644
index 000000000..326a5da7e
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/hostconfig_unix.go
@@ -0,0 +1,45 @@
+//go:build !windows
+
+package container
+
+import "github.com/moby/moby/api/types/network"
+
+// IsValid indicates if an isolation technology is valid
+func (i Isolation) IsValid() bool {
+	return i.IsDefault()
+}
+
+// IsBridge indicates whether container uses the bridge network stack
+func (n NetworkMode) IsBridge() bool {
+	return n == network.NetworkBridge
+}
+
+// IsHost indicates whether container uses the host network stack.
+func (n NetworkMode) IsHost() bool {
+	return n == network.NetworkHost
+}
+
+// IsUserDefined indicates user-created network
+func (n NetworkMode) IsUserDefined() bool {
+	return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer()
+}
+
+// NetworkName returns the name of the network stack.
+func (n NetworkMode) NetworkName() string {
+	switch {
+	case n.IsDefault():
+		return network.NetworkDefault
+	case n.IsBridge():
+		return network.NetworkBridge
+	case n.IsHost():
+		return network.NetworkHost
+	case n.IsNone():
+		return network.NetworkNone
+	case n.IsContainer():
+		return "container"
+	case n.IsUserDefined():
+		return n.UserDefined()
+	default:
+		return ""
+	}
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/hostconfig_windows.go b/vendor/github.com/moby/moby/api/types/container/hostconfig_windows.go
new file mode 100644
index 000000000..977a37602
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/hostconfig_windows.go
@@ -0,0 +1,47 @@
+package container
+
+import "github.com/moby/moby/api/types/network"
+
+// IsValid indicates if an isolation technology is valid
+func (i Isolation) IsValid() bool {
+	return i.IsDefault() || i.IsHyperV() || i.IsProcess()
+}
+
+// IsBridge indicates whether container uses the bridge network stack
+// in windows it is given the name NAT
+func (n NetworkMode) IsBridge() bool {
+	return n == network.NetworkNat
+}
+
+// IsHost indicates whether container uses the host network stack.
+// returns false as this is not supported by windows
+func (n NetworkMode) IsHost() bool {
+	return false
+}
+
+// IsUserDefined indicates user-created network
+func (n NetworkMode) IsUserDefined() bool {
+	return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer()
+}
+
+// NetworkName returns the name of the network stack.
+func (n NetworkMode) NetworkName() string {
+	switch {
+	case n.IsDefault():
+		return network.NetworkDefault
+	case n.IsBridge():
+		return network.NetworkNat
+	case n.IsHost():
+		// Windows currently doesn't support host network-mode, so
+		// this would currently never happen..
+		return network.NetworkHost
+	case n.IsNone():
+		return network.NetworkNone
+	case n.IsContainer():
+		return "container"
+	case n.IsUserDefined():
+		return n.UserDefined()
+	default:
+		return ""
+	}
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/network_settings.go b/vendor/github.com/moby/moby/api/types/container/network_settings.go
new file mode 100644
index 000000000..c51c0839d
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/network_settings.go
@@ -0,0 +1,22 @@
+package container
+
+import (
+	"github.com/moby/moby/api/types/network"
+)
+
+// NetworkSettings exposes the network settings in the api
+type NetworkSettings struct {
+	SandboxID  string // SandboxID uniquely represents a container's network stack
+	SandboxKey string // SandboxKey identifies the sandbox
+
+	// Ports is a collection of [network.PortBinding] indexed by [network.Port]
+	Ports network.PortMap
+
+	Networks map[string]*network.EndpointSettings
+}
+
+// NetworkSettingsSummary provides a summary of container's networks
+// in /containers/json
+type NetworkSettingsSummary struct {
+	Networks map[string]*network.EndpointSettings
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/port_summary.go b/vendor/github.com/moby/moby/api/types/container/port_summary.go
new file mode 100644
index 000000000..68148eece
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/port_summary.go
@@ -0,0 +1,33 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+	"net/netip"
+)
+
+// PortSummary Describes a port-mapping between the container and the host.
+//
+// Example: {"PrivatePort":8080,"PublicPort":80,"Type":"tcp"}
+//
+// swagger:model PortSummary
+type PortSummary struct {
+
+	// Host IP address that the container's port is mapped to
+	IP netip.Addr `json:"IP,omitempty"`
+
+	// Port on the container
+	// Required: true
+	PrivatePort uint16 `json:"PrivatePort"`
+
+	// Port exposed on the host
+	PublicPort uint16 `json:"PublicPort,omitempty"`
+
+	// type
+	// Required: true
+	// Enum: ["tcp","udp","sctp"]
+	Type string `json:"Type"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/state.go b/vendor/github.com/moby/moby/api/types/container/state.go
new file mode 100644
index 000000000..47c6d1249
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/state.go
@@ -0,0 +1,40 @@
+package container
+
+import (
+	"fmt"
+	"strings"
+)
+
+// ContainerState is a string representation of the container's current state.
+type ContainerState string
+
+const (
+	StateCreated    ContainerState = "created"    // StateCreated indicates the container is created, but not (yet) started.
+	StateRunning    ContainerState = "running"    // StateRunning indicates that the container is running.
+	StatePaused     ContainerState = "paused"     // StatePaused indicates that the container's current state is paused.
+	StateRestarting ContainerState = "restarting" // StateRestarting indicates that the container is currently restarting.
+	StateRemoving   ContainerState = "removing"   // StateRemoving indicates that the container is being removed.
+	StateExited     ContainerState = "exited"     // StateExited indicates that the container exited.
+	StateDead       ContainerState = "dead"       // StateDead indicates that the container failed to be deleted. Containers in this state are attempted to be cleaned up when the daemon restarts.
+)
+
+var validStates = []string{
+	string(StateCreated),
+	string(StateRunning),
+	string(StatePaused),
+	string(StateRestarting),
+	string(StateRemoving),
+	string(StateExited),
+	string(StateDead),
+}
+
+// ValidateContainerState checks if the provided string is a valid
+// container [ContainerState].
+func ValidateContainerState(s ContainerState) error {
+	switch s {
+	case StateCreated, StateRunning, StatePaused, StateRestarting, StateRemoving, StateExited, StateDead:
+		return nil
+	default:
+		return errInvalidParameter{error: fmt.Errorf("invalid value for state (%s): must be one of %s", s, strings.Join(validStates, ", "))}
+	}
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/stats.go b/vendor/github.com/moby/moby/api/types/container/stats.go
new file mode 100644
index 000000000..6a34f6ab7
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/stats.go
@@ -0,0 +1,224 @@
+package container
+
+import "time"
+
+// ThrottlingData stores CPU throttling stats of one running container.
+// Not used on Windows.
+type ThrottlingData struct {
+	// Number of periods with throttling active
+	Periods uint64 `json:"periods"`
+	// Number of periods when the container hits its throttling limit.
+	ThrottledPeriods uint64 `json:"throttled_periods"`
+	// Aggregate time the container was throttled for in nanoseconds.
+	ThrottledTime uint64 `json:"throttled_time"`
+}
+
+// CPUUsage stores All CPU stats aggregated since container inception.
+type CPUUsage struct {
+	// Total CPU time consumed.
+	// Units: nanoseconds (Linux)
+	// Units: 100's of nanoseconds (Windows)
+	TotalUsage uint64 `json:"total_usage"`
+
+	// Total CPU time consumed per core (Linux). Not used on Windows.
+	// Units: nanoseconds.
+	PercpuUsage []uint64 `json:"percpu_usage,omitempty"`
+
+	// Time spent by tasks of the cgroup in kernel mode (Linux).
+	// Time spent by all container processes in kernel mode (Windows).
+	// Units: nanoseconds (Linux).
+	// Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers.
+	UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
+
+	// Time spent by tasks of the cgroup in user mode (Linux).
+	// Time spent by all container processes in user mode (Windows).
+	// Units: nanoseconds (Linux).
+	// Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers
+	UsageInUsermode uint64 `json:"usage_in_usermode"`
+}
+
+// CPUStats aggregates and wraps all CPU related info of container
+type CPUStats struct {
+	// CPU Usage. Linux and Windows.
+	CPUUsage CPUUsage `json:"cpu_usage"`
+
+	// System Usage. Linux only.
+	SystemUsage uint64 `json:"system_cpu_usage,omitempty"`
+
+	// Online CPUs. Linux only.
+	OnlineCPUs uint32 `json:"online_cpus,omitempty"`
+
+	// Throttling Data. Linux only.
+	ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
+}
+
+// MemoryStats aggregates all memory stats since container inception on Linux.
+// Windows returns stats for commit and private working set only.
+type MemoryStats struct {
+	// Linux Memory Stats
+
+	// current res_counter usage for memory
+	Usage uint64 `json:"usage,omitempty"`
+	// maximum usage ever recorded.
+	MaxUsage uint64 `json:"max_usage,omitempty"`
+	// TODO(vishh): Export these as stronger types.
+	// all the stats exported via memory.stat.
+	Stats map[string]uint64 `json:"stats,omitempty"`
+	// number of times memory usage hits limits.
+	Failcnt uint64 `json:"failcnt,omitempty"`
+	Limit   uint64 `json:"limit,omitempty"`
+
+	// Windows Memory Stats
+	// See https://technet.microsoft.com/en-us/magazine/ff382715.aspx
+
+	// committed bytes
+	Commit uint64 `json:"commitbytes,omitempty"`
+	// peak committed bytes
+	CommitPeak uint64 `json:"commitpeakbytes,omitempty"`
+	// private working set
+	PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"`
+}
+
+// BlkioStatEntry is one small entity to store a piece of Blkio stats
+// Not used on Windows.
+type BlkioStatEntry struct {
+	Major uint64 `json:"major"`
+	Minor uint64 `json:"minor"`
+	Op    string `json:"op"`
+	Value uint64 `json:"value"`
+}
+
+// BlkioStats stores All IO service stats for data read and write.
+// This is a Linux specific structure as the differences between expressing
+// block I/O on Windows and Linux are sufficiently significant to make
+// little sense attempting to morph into a combined structure.
+type BlkioStats struct {
+	// number of bytes transferred to and from the block device
+	IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"`
+	IoServicedRecursive     []BlkioStatEntry `json:"io_serviced_recursive"`
+	IoQueuedRecursive       []BlkioStatEntry `json:"io_queue_recursive"`
+	IoServiceTimeRecursive  []BlkioStatEntry `json:"io_service_time_recursive"`
+	IoWaitTimeRecursive     []BlkioStatEntry `json:"io_wait_time_recursive"`
+	IoMergedRecursive       []BlkioStatEntry `json:"io_merged_recursive"`
+	IoTimeRecursive         []BlkioStatEntry `json:"io_time_recursive"`
+	SectorsRecursive        []BlkioStatEntry `json:"sectors_recursive"`
+}
+
+// StorageStats is the disk I/O stats for read/write on Windows.
+type StorageStats struct {
+	ReadCountNormalized  uint64 `json:"read_count_normalized,omitempty"`
+	ReadSizeBytes        uint64 `json:"read_size_bytes,omitempty"`
+	WriteCountNormalized uint64 `json:"write_count_normalized,omitempty"`
+	WriteSizeBytes       uint64 `json:"write_size_bytes,omitempty"`
+}
+
+// NetworkStats aggregates the network stats of one container
+type NetworkStats struct {
+	// Bytes received. Windows and Linux.
+	RxBytes uint64 `json:"rx_bytes"`
+	// Packets received. Windows and Linux.
+	RxPackets uint64 `json:"rx_packets"`
+	// Received errors. Not used on Windows. Note that we don't `omitempty` this
+	// field as it is expected in the >=v1.21 API stats structure.
+	RxErrors uint64 `json:"rx_errors"`
+	// Incoming packets dropped. Windows and Linux.
+	RxDropped uint64 `json:"rx_dropped"`
+	// Bytes sent. Windows and Linux.
+	TxBytes uint64 `json:"tx_bytes"`
+	// Packets sent. Windows and Linux.
+	TxPackets uint64 `json:"tx_packets"`
+	// Sent errors. Not used on Windows. Note that we don't `omitempty` this
+	// field as it is expected in the >=v1.21 API stats structure.
+	TxErrors uint64 `json:"tx_errors"`
+	// Outgoing packets dropped. Windows and Linux.
+	TxDropped uint64 `json:"tx_dropped"`
+	// Endpoint ID. Not used on Linux.
+	EndpointID string `json:"endpoint_id,omitempty"`
+	// Instance ID. Not used on Linux.
+	InstanceID string `json:"instance_id,omitempty"`
+}
+
+// PidsStats contains the stats of a container's pids
+type PidsStats struct {
+	// Current is the number of pids in the cgroup
+	Current uint64 `json:"current,omitempty"`
+	// Limit is the hard limit on the number of pids in the cgroup.
+	// A "Limit" of 0 means that there is no limit.
+	Limit uint64 `json:"limit,omitempty"`
+}
+
+// StatsResponse aggregates all types of stats of one container.
+type StatsResponse struct {
+	// ID is the ID of the container for which the stats were collected.
+	ID string `json:"id,omitempty"`
+
+	// Name is the name of the container for which the stats were collected.
+	Name string `json:"name,omitempty"`
+
+	// OSType is the OS of the container ("linux" or "windows") to allow
+	// platform-specific handling of stats.
+	OSType string `json:"os_type,omitempty"`
+
+	// Read is the date and time at which this sample was collected.
+	Read time.Time `json:"read"`
+
+	// CPUStats contains CPU related info of the container.
+	CPUStats CPUStats `json:"cpu_stats,omitempty"`
+
+	// MemoryStats aggregates all memory stats since container inception on Linux.
+	// Windows returns stats for commit and private working set only.
+	MemoryStats MemoryStats `json:"memory_stats,omitempty"`
+
+	// Networks contains Nntwork statistics for the container per interface.
+	//
+	// This field is omitted if the container has no networking enabled.
+	Networks map[string]NetworkStats `json:"networks,omitempty"`
+
+	// -------------------------------------------------------------------------
+	// Linux-specific stats, not populated on Windows.
+	// -------------------------------------------------------------------------
+
+	// PidsStats contains Linux-specific stats of a container's process-IDs (PIDs).
+	//
+	// This field is Linux-specific and omitted for Windows containers.
+	PidsStats PidsStats `json:"pids_stats,omitempty"`
+
+	// BlkioStats stores all IO service stats for data read and write.
+	//
+	// This type is Linux-specific and holds many fields that are specific
+	// to cgroups v1.
+	//
+	// On a cgroup v2 host, all fields other than "io_service_bytes_recursive"
+	// are omitted or "null".
+	//
+	// This type is only populated on Linux and omitted for Windows containers.
+	BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
+
+	// -------------------------------------------------------------------------
+	// Windows-specific stats, not populated on Linux.
+	// -------------------------------------------------------------------------
+
+	// NumProcs is the number of processors on the system.
+	//
+	// This field is Windows-specific and always zero for Linux containers.
+	NumProcs uint32 `json:"num_procs"`
+
+	// StorageStats is the disk I/O stats for read/write on Windows.
+	//
+	// This type is Windows-specific and omitted for Linux containers.
+	StorageStats StorageStats `json:"storage_stats,omitempty"`
+
+	// -------------------------------------------------------------------------
+	// PreRead and PreCPUStats contain the previous sample of stats for
+	// the container, and can be used to perform delta-calculation.
+	// -------------------------------------------------------------------------
+
+	// PreRead is the date and time at which this first sample was collected.
+	// This field is not propagated if the "one-shot" option is set. If the
+	// "one-shot" option is set, this field may be omitted, empty, or set
+	// to a default date (`0001-01-01T00:00:00Z`).
+	PreRead time.Time `json:"preread"`
+
+	// PreCPUStats contains the CPUStats of the previous sample.
+	PreCPUStats CPUStats `json:"precpu_stats,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/top_response.go b/vendor/github.com/moby/moby/api/types/container/top_response.go
new file mode 100644
index 000000000..966603617
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/top_response.go
@@ -0,0 +1,23 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// TopResponse ContainerTopResponse
+//
+// Container "top" response.
+//
+// swagger:model TopResponse
+type TopResponse struct {
+
+	// Each process running in the container, where each process
+	// is an array of values corresponding to the titles.
+	// Example: {"Processes":[["root","13642","882","0","17:03","pts/0","00:00:00","/bin/bash"],["root","13735","13642","0","17:06","pts/0","00:00:00","sleep 10"]]}
+	Processes [][]string `json:"Processes"`
+
+	// The ps column titles
+	// Example: {"Titles":["UID","PID","PPID","C","STIME","TTY","TIME","CMD"]}
+	Titles []string `json:"Titles"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/update_response.go b/vendor/github.com/moby/moby/api/types/container/update_response.go
new file mode 100644
index 000000000..2f7263b14
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/update_response.go
@@ -0,0 +1,18 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// UpdateResponse ContainerUpdateResponse
+//
+// Response for a successful container-update.
+//
+// swagger:model UpdateResponse
+type UpdateResponse struct {
+
+	// Warnings encountered when updating the container.
+	// Example: ["Published ports are discarded when using host network mode"]
+	Warnings []string `json:"Warnings"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/wait_exit_error.go b/vendor/github.com/moby/moby/api/types/container/wait_exit_error.go
new file mode 100644
index 000000000..96a7770c3
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/wait_exit_error.go
@@ -0,0 +1,15 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// WaitExitError container waiting error, if any
+//
+// swagger:model WaitExitError
+type WaitExitError struct {
+
+	// Details of an error
+	Message string `json:"Message,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/wait_response.go b/vendor/github.com/moby/moby/api/types/container/wait_response.go
new file mode 100644
index 000000000..68d3c3872
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/wait_response.go
@@ -0,0 +1,21 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package container
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// WaitResponse ContainerWaitResponse
+//
+// # OK response to ContainerWait operation
+//
+// swagger:model WaitResponse
+type WaitResponse struct {
+
+	// error
+	Error *WaitExitError `json:"Error,omitempty"`
+
+	// Exit code of the container
+	// Required: true
+	StatusCode int64 `json:"StatusCode"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/container/waitcondition.go b/vendor/github.com/moby/moby/api/types/container/waitcondition.go
new file mode 100644
index 000000000..64820fe35
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/container/waitcondition.go
@@ -0,0 +1,22 @@
+package container
+
+// WaitCondition is a type used to specify a container state for which
+// to wait.
+type WaitCondition string
+
+// Possible WaitCondition Values.
+//
+// WaitConditionNotRunning (default) is used to wait for any of the non-running
+// states: "created", "exited", "dead", "removing", or "removed".
+//
+// WaitConditionNextExit is used to wait for the next time the state changes
+// to a non-running state. If the state is currently "created" or "exited",
+// this would cause Wait() to block until either the container runs and exits
+// or is removed.
+//
+// WaitConditionRemoved is used to wait for the container to be removed.
+const (
+	WaitConditionNotRunning WaitCondition = "not-running"
+	WaitConditionNextExit   WaitCondition = "next-exit"
+	WaitConditionRemoved    WaitCondition = "removed"
+)
diff --git a/vendor/github.com/moby/moby/api/types/events/events.go b/vendor/github.com/moby/moby/api/types/events/events.go
new file mode 100644
index 000000000..b8393addd
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/events/events.go
@@ -0,0 +1,121 @@
+package events
+
+// Type is used for event-types.
+type Type string
+
+// List of known event types.
+const (
+	BuilderEventType   Type = "builder"   // BuilderEventType is the event type that the builder generates.
+	ConfigEventType    Type = "config"    // ConfigEventType is the event type that configs generate.
+	ContainerEventType Type = "container" // ContainerEventType is the event type that containers generate.
+	DaemonEventType    Type = "daemon"    // DaemonEventType is the event type that daemon generate.
+	ImageEventType     Type = "image"     // ImageEventType is the event type that images generate.
+	NetworkEventType   Type = "network"   // NetworkEventType is the event type that networks generate.
+	NodeEventType      Type = "node"      // NodeEventType is the event type that nodes generate.
+	PluginEventType    Type = "plugin"    // PluginEventType is the event type that plugins generate.
+	SecretEventType    Type = "secret"    // SecretEventType is the event type that secrets generate.
+	ServiceEventType   Type = "service"   // ServiceEventType is the event type that services generate.
+	VolumeEventType    Type = "volume"    // VolumeEventType is the event type that volumes generate.
+)
+
+// Action is used for event-actions.
+type Action string
+
+const (
+	ActionCreate       Action = "create"
+	ActionStart        Action = "start"
+	ActionRestart      Action = "restart"
+	ActionStop         Action = "stop"
+	ActionCheckpoint   Action = "checkpoint"
+	ActionPause        Action = "pause"
+	ActionUnPause      Action = "unpause"
+	ActionAttach       Action = "attach"
+	ActionDetach       Action = "detach"
+	ActionResize       Action = "resize"
+	ActionUpdate       Action = "update"
+	ActionRename       Action = "rename"
+	ActionKill         Action = "kill"
+	ActionDie          Action = "die"
+	ActionOOM          Action = "oom"
+	ActionDestroy      Action = "destroy"
+	ActionRemove       Action = "remove"
+	ActionCommit       Action = "commit"
+	ActionTop          Action = "top"
+	ActionCopy         Action = "copy"
+	ActionArchivePath  Action = "archive-path"
+	ActionExtractToDir Action = "extract-to-dir"
+	ActionExport       Action = "export"
+	ActionImport       Action = "import"
+	ActionSave         Action = "save"
+	ActionLoad         Action = "load"
+	ActionTag          Action = "tag"
+	ActionUnTag        Action = "untag"
+	ActionPush         Action = "push"
+	ActionPull         Action = "pull"
+	ActionPrune        Action = "prune"
+	ActionDelete       Action = "delete"
+	ActionEnable       Action = "enable"
+	ActionDisable      Action = "disable"
+	ActionConnect      Action = "connect"
+	ActionDisconnect   Action = "disconnect"
+	ActionReload       Action = "reload"
+	ActionMount        Action = "mount"
+	ActionUnmount      Action = "unmount"
+
+	// ActionExecCreate is the prefix used for exec_create events. These
+	// event-actions are commonly followed by a colon and space (": "),
+	// and the command that's defined for the exec, for example:
+	//
+	//	exec_create: /bin/sh -c 'echo hello'
+	//
+	// This is far from ideal; it's a compromise to allow filtering and
+	// to preserve backward-compatibility.
+	ActionExecCreate Action = "exec_create"
+	// ActionExecStart is the prefix used for exec_create events. These
+	// event-actions are commonly followed by a colon and space (": "),
+	// and the command that's defined for the exec, for example:
+	//
+	//	exec_start: /bin/sh -c 'echo hello'
+	//
+	// This is far from ideal; it's a compromise to allow filtering and
+	// to preserve backward-compatibility.
+	ActionExecStart  Action = "exec_start"
+	ActionExecDie    Action = "exec_die"
+	ActionExecDetach Action = "exec_detach"
+
+	// ActionHealthStatus is the prefix to use for health_status events.
+	//
+	// Health-status events can either have a pre-defined status, in which
+	// case the "health_status" action is followed by a colon, or can be
+	// "free-form", in which case they're followed by the output of the
+	// health-check output.
+	//
+	// This is far form ideal, and a compromise to allow filtering, and
+	// to preserve backward-compatibility.
+	ActionHealthStatus          Action = "health_status"
+	ActionHealthStatusRunning   Action = "health_status: running"
+	ActionHealthStatusHealthy   Action = "health_status: healthy"
+	ActionHealthStatusUnhealthy Action = "health_status: unhealthy"
+)
+
+// Actor describes something that generates events,
+// like a container, or a network, or a volume.
+// It has a defined name and a set of attributes.
+// The container attributes are its labels, other actors
+// can generate these attributes from other properties.
+type Actor struct {
+	ID         string
+	Attributes map[string]string
+}
+
+// Message represents the information an event contains
+type Message struct {
+	Type   Type
+	Action Action
+	Actor  Actor
+	// Engine events are local scope. Cluster events are swarm scope.
+	Scope string `json:"scope,omitempty"`
+
+	Time     int64 `json:"time,omitempty"`
+	TimeNano int64 `json:"timeNano,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/build_identity.go b/vendor/github.com/moby/moby/api/types/image/build_identity.go
new file mode 100644
index 000000000..1e827dc43
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/build_identity.go
@@ -0,0 +1,15 @@
+package image
+
+import (
+	"time"
+)
+
+// BuildIdentity contains build reference information if image was created via build.
+type BuildIdentity struct {
+	// Ref is the identifier for the build request. This reference can be used to
+	// look up the build details in BuildKit history API.
+	Ref string `json:"Ref,omitempty"`
+
+	// CreatedAt is the time when the build ran.
+	CreatedAt time.Time `json:"CreatedAt,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/delete_response.go b/vendor/github.com/moby/moby/api/types/image/delete_response.go
new file mode 100644
index 000000000..b19119a38
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/delete_response.go
@@ -0,0 +1,18 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package image
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// DeleteResponse delete response
+//
+// swagger:model DeleteResponse
+type DeleteResponse struct {
+
+	// The image ID of an image that was deleted
+	Deleted string `json:"Deleted,omitempty"`
+
+	// The image ID of an image that was untagged
+	Untagged string `json:"Untagged,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/disk_usage.go b/vendor/github.com/moby/moby/api/types/image/disk_usage.go
new file mode 100644
index 000000000..7297813c1
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/disk_usage.go
@@ -0,0 +1,36 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package image
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// DiskUsage represents system data usage for image resources.
+//
+// swagger:model DiskUsage
+type DiskUsage struct {
+
+	// Count of active images.
+	//
+	// Example: 1
+	ActiveCount int64 `json:"ActiveCount,omitempty"`
+
+	// List of image summaries.
+	//
+	Items []Summary `json:"Items,omitempty"`
+
+	// Disk space that can be reclaimed by removing unused images.
+	//
+	// Example: 12345678
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
+
+	// Count of all images.
+	//
+	// Example: 4
+	TotalCount int64 `json:"TotalCount,omitempty"`
+
+	// Disk space in use by images.
+	//
+	// Example: 98765432
+	TotalSize int64 `json:"TotalSize,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/history_response_item.go b/vendor/github.com/moby/moby/api/types/image/history_response_item.go
new file mode 100644
index 000000000..3de3181ab
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/history_response_item.go
@@ -0,0 +1,38 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package image
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// HistoryResponseItem HistoryResponseItem
+//
+// individual image layer information in response to ImageHistory operation
+//
+// swagger:model HistoryResponseItem
+type HistoryResponseItem struct {
+
+	// comment
+	// Required: true
+	Comment string `json:"Comment"`
+
+	// created
+	// Required: true
+	Created int64 `json:"Created"`
+
+	// created by
+	// Required: true
+	CreatedBy string `json:"CreatedBy"`
+
+	// Id
+	// Required: true
+	ID string `json:"Id"`
+
+	// size
+	// Required: true
+	Size int64 `json:"Size"`
+
+	// tags
+	// Required: true
+	Tags []string `json:"Tags"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/identity.go b/vendor/github.com/moby/moby/api/types/image/identity.go
new file mode 100644
index 000000000..3e0304563
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/identity.go
@@ -0,0 +1,15 @@
+package image
+
+// Identity holds information about the identity and origin of the image.
+// This is trusted information verified by the daemon and cannot be modified
+// by tagging an image to a different name.
+type Identity struct {
+	// Signature contains the properties of verified signatures for the image.
+	Signature []SignatureIdentity `json:"Signature,omitzero"`
+	// Pull contains remote location information if image was created via pull.
+	// If image was pulled via mirror, this contains the original repository location.
+	// After successful push this images also contains the pushed repository location.
+	Pull []PullIdentity `json:"Pull,omitzero"`
+	// Build contains build reference information if image was created via build.
+	Build []BuildIdentity `json:"Build,omitzero"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/image.go b/vendor/github.com/moby/moby/api/types/image/image.go
new file mode 100644
index 000000000..1c8990ae9
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/image.go
@@ -0,0 +1,18 @@
+package image
+
+import (
+	"time"
+)
+
+// Metadata contains engine-local data about the image.
+type Metadata struct {
+	// LastTagTime is the date and time at which the image was last tagged.
+	LastTagTime time.Time `json:",omitempty"`
+}
+
+// PruneReport contains the response for Engine API:
+// POST "/images/prune"
+type PruneReport struct {
+	ImagesDeleted  []DeleteResponse
+	SpaceReclaimed uint64
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/image_inspect.go b/vendor/github.com/moby/moby/api/types/image/image_inspect.go
new file mode 100644
index 000000000..df09c9511
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/image_inspect.go
@@ -0,0 +1,137 @@
+package image
+
+import (
+	dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
+	"github.com/moby/moby/api/types/storage"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// RootFS returns Image's RootFS description including the layer IDs.
+type RootFS struct {
+	Type   string   `json:",omitempty"`
+	Layers []string `json:",omitempty"`
+}
+
+// InspectResponse contains response of Engine API:
+// GET "/images/{name:.*}/json"
+type InspectResponse struct {
+	// ID is the content-addressable ID of an image.
+	//
+	// This identifier is a content-addressable digest calculated from the
+	// image's configuration (which includes the digests of layers used by
+	// the image).
+	//
+	// Note that this digest differs from the `RepoDigests` below, which
+	// holds digests of image manifests that reference the image.
+	ID string `json:"Id"`
+
+	// RepoTags is a list of image names/tags in the local image cache that
+	// reference this image.
+	//
+	// Multiple image tags can refer to the same image, and this list may be
+	// empty if no tags reference the image, in which case the image is
+	// "untagged", in which case it can still be referenced by its ID.
+	RepoTags []string
+
+	// RepoDigests is a list of content-addressable digests of locally available
+	// image manifests that the image is referenced from. Multiple manifests can
+	// refer to the same image.
+	//
+	// These digests are usually only available if the image was either pulled
+	// from a registry, or if the image was pushed to a registry, which is when
+	// the manifest is generated and its digest calculated.
+	RepoDigests []string
+
+	// Comment is an optional message that can be set when committing or
+	// importing the image. This field is omitted if not set.
+	Comment string `json:",omitempty"`
+
+	// Created is the date and time at which the image was created, formatted in
+	// RFC 3339 nano-seconds (time.RFC3339Nano).
+	//
+	// This information is only available if present in the image,
+	// and omitted otherwise.
+	Created string `json:",omitempty"`
+
+	// Author is the name of the author that was specified when committing the
+	// image, or as specified through MAINTAINER (deprecated) in the Dockerfile.
+	// This field is omitted if not set.
+	Author string `json:",omitempty"`
+	Config *dockerspec.DockerOCIImageConfig
+
+	// Architecture is the hardware CPU architecture that the image runs on.
+	Architecture string
+
+	// Variant is the CPU architecture variant (presently ARM-only).
+	Variant string `json:",omitempty"`
+
+	// OS is the Operating System the image is built to run on.
+	Os string
+
+	// OsVersion is the version of the Operating System the image is built to
+	// run on (especially for Windows).
+	OsVersion string `json:",omitempty"`
+
+	// Size is the total size of the image including all layers it is composed of.
+	Size int64
+
+	// GraphDriver holds information about the storage driver used to store the
+	// container's and image's filesystem.
+	GraphDriver *storage.DriverData `json:"GraphDriver,omitempty"`
+
+	// RootFS contains information about the image's RootFS, including the
+	// layer IDs.
+	RootFS RootFS
+
+	// Metadata of the image in the local cache.
+	//
+	// This information is local to the daemon, and not part of the image itself.
+	Metadata Metadata
+
+	// Descriptor is the OCI descriptor of the image target.
+	// It's only set if the daemon provides a multi-platform image store.
+	//
+	// WARNING: This is experimental and may change at any time without any backward
+	// compatibility.
+	Descriptor *ocispec.Descriptor `json:"Descriptor,omitempty"`
+
+	// Manifests is a list of image manifests available in this image. It
+	// provides a more detailed view of the platform-specific image manifests or
+	// other image-attached data like build attestations.
+	//
+	// Only available if the daemon provides a multi-platform image store, the client
+	// requests manifests AND does not request a specific platform.
+	//
+	// WARNING: This is experimental and may change at any time without any backward
+	// compatibility.
+	Manifests []ManifestSummary `json:"Manifests,omitempty"`
+
+	// Identity holds information about the identity and origin of the image.
+	// This is trusted information verified by the daemon and cannot be modified
+	// by tagging an image to a different name.
+	Identity *Identity `json:"Identity,omitempty"`
+}
+
+// SignatureTimestampType is the type of timestamp used in the signature.
+type SignatureTimestampType string
+
+const (
+	SignatureTimestampTlog      SignatureTimestampType = "Tlog"
+	SignatureTimestampAuthority SignatureTimestampType = "TimestampAuthority"
+)
+
+// SignatureType is the type of signature format.
+type SignatureType string
+
+const (
+	SignatureTypeBundleV03       SignatureType = "bundle-v0.3"
+	SignatureTypeSimpleSigningV1 SignatureType = "simplesigning-v1"
+)
+
+// KnownSignerIdentity is an identifier for a special signer identity that is known to the implementation.
+type KnownSignerIdentity string
+
+const (
+	// KnownSignerDHI is the known identity for Docker Hardened Images.
+	KnownSignerDHI KnownSignerIdentity = "DHI"
+)
diff --git a/vendor/github.com/moby/moby/api/types/image/manifest.go b/vendor/github.com/moby/moby/api/types/image/manifest.go
new file mode 100644
index 000000000..bcd00a079
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/manifest.go
@@ -0,0 +1,104 @@
+package image
+
+import (
+	"github.com/opencontainers/go-digest"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+type ManifestKind string
+
+const (
+	ManifestKindImage       ManifestKind = "image"
+	ManifestKindAttestation ManifestKind = "attestation"
+	ManifestKindUnknown     ManifestKind = "unknown"
+)
+
+type ManifestSummary struct {
+	// ID is the content-addressable ID of an image and is the same as the
+	// digest of the image manifest.
+	//
+	// Required: true
+	ID string `json:"ID"`
+
+	// Descriptor is the OCI descriptor of the image.
+	//
+	// Required: true
+	Descriptor ocispec.Descriptor `json:"Descriptor"`
+
+	// Indicates whether all the child content (image config, layers) is
+	// fully available locally
+	//
+	// Required: true
+	Available bool `json:"Available"`
+
+	// Size is the size information of the content related to this manifest.
+	// Note: These sizes only take the locally available content into account.
+	//
+	// Required: true
+	Size struct {
+		// Content is the size (in bytes) of all the locally present
+		// content in the content store (e.g. image config, layers)
+		// referenced by this manifest and its children.
+		// This only includes blobs in the content store.
+		Content int64 `json:"Content"`
+
+		// Total is the total size (in bytes) of all the locally present
+		// data (both distributable and non-distributable) that's related to
+		// this manifest and its children.
+		// This equal to the sum of [Content] size AND all the sizes in the
+		// [Size] struct present in the Kind-specific data struct.
+		// For example, for an image kind (Kind == ManifestKindImage),
+		// this would include the size of the image content and unpacked
+		// image snapshots ([Size.Content] + [ImageData.Size.Unpacked]).
+		Total int64 `json:"Total"`
+	} `json:"Size"`
+
+	// Kind is the kind of the image manifest.
+	//
+	// Required: true
+	Kind ManifestKind `json:"Kind"`
+
+	// Fields below are specific to the kind of the image manifest.
+
+	// Present only if Kind == ManifestKindImage.
+	ImageData *ImageProperties `json:"ImageData,omitempty"`
+
+	// Present only if Kind == ManifestKindAttestation.
+	AttestationData *AttestationProperties `json:"AttestationData,omitempty"`
+}
+
+type ImageProperties struct {
+	// Platform is the OCI platform object describing the platform of the image.
+	//
+	// Required: true
+	Platform ocispec.Platform `json:"Platform"`
+
+	// Identity holds information about the identity and origin of the image.
+	// For image list responses, this can duplicate Build/Pull fields across
+	// image manifests, because those parts of identity are image-level metadata.
+	Identity *Identity `json:"Identity,omitempty"`
+
+	Size struct {
+		// Unpacked is the size (in bytes) of the locally unpacked
+		// (uncompressed) image content that's directly usable by the containers
+		// running this image.
+		// It's independent of the distributable content - e.g.
+		// the image might still have an unpacked data that's still used by
+		// some container even when the distributable/compressed content is
+		// already gone.
+		//
+		// Required: true
+		Unpacked int64 `json:"Unpacked"`
+	}
+
+	// Containers is an array containing the IDs of the containers that are
+	// using this image.
+	//
+	// Required: true
+	Containers []string `json:"Containers"`
+}
+
+type AttestationProperties struct {
+	// For is the digest of the image manifest that this attestation is for.
+	For digest.Digest `json:"For"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/pull_identity.go b/vendor/github.com/moby/moby/api/types/image/pull_identity.go
new file mode 100644
index 000000000..711492b5c
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/pull_identity.go
@@ -0,0 +1,8 @@
+package image
+
+// PullIdentity contains remote location information if image was created via pull.
+// If image was pulled via mirror, this contains the original repository location.
+type PullIdentity struct {
+	// Repository is the remote repository location the image was pulled from.
+	Repository string `json:"Repository,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/signature_identity.go b/vendor/github.com/moby/moby/api/types/image/signature_identity.go
new file mode 100644
index 000000000..243c2997c
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/signature_identity.go
@@ -0,0 +1,26 @@
+package image
+
+// SignatureIdentity contains the properties of verified signatures for the image.
+type SignatureIdentity struct {
+	// Name is a textual description summarizing the type of signature.
+	Name string `json:"Name,omitempty"`
+	// Timestamps contains a list of verified signed timestamps for the signature.
+	Timestamps []SignatureTimestamp `json:"Timestamps,omitzero"`
+	// KnownSigner is an identifier for a special signer identity that is known to the implementation.
+	KnownSigner KnownSignerIdentity `json:"KnownSigner,omitempty"`
+	// DockerReference is the Docker image reference associated with the signature.
+	// This is an optional field only present in older hashedrecord signatures.
+	DockerReference string `json:"DockerReference,omitempty"`
+	// Signer contains information about the signer certificate used to sign the image.
+	Signer *SignerIdentity `json:"Signer,omitempty"`
+	// SignatureType is the type of signature format. E.g. "bundle-v0.3" or "hashedrecord".
+	SignatureType SignatureType `json:"SignatureType,omitempty"`
+
+	// Error contains error information if signature verification failed.
+	// Other fields will be empty in this case.
+	Error string `json:"Error,omitempty"`
+	// Warnings contains any warnings that occurred during signature verification.
+	// For example, if there was no internet connectivity and cached trust roots were used.
+	// Warning does not indicate a failed verification but may point to configuration issues.
+	Warnings []string `json:"Warnings,omitzero"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/signature_timestamp.go b/vendor/github.com/moby/moby/api/types/image/signature_timestamp.go
new file mode 100644
index 000000000..a975ef0ee
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/signature_timestamp.go
@@ -0,0 +1,12 @@
+package image
+
+import (
+	"time"
+)
+
+// SignatureTimestamp contains information about a verified signed timestamp for an image signature.
+type SignatureTimestamp struct {
+	Type      SignatureTimestampType `json:"Type"`
+	URI       string                 `json:"URI"`
+	Timestamp time.Time              `json:"Timestamp"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/signer_identity.go b/vendor/github.com/moby/moby/api/types/image/signer_identity.go
new file mode 100644
index 000000000..87419e148
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/signer_identity.go
@@ -0,0 +1,57 @@
+package image
+
+// SignerIdentity contains information about the signer certificate used to sign the image.
+// This is [certificate.Summary] with deprecated fields removed and keys in Moby uppercase style.
+//
+// [certificate.Summary]: https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg/fulcio/certificate#Summary
+type SignerIdentity struct {
+	CertificateIssuer      string `json:"CertificateIssuer"`
+	SubjectAlternativeName string `json:"SubjectAlternativeName"`
+	// The OIDC issuer. Should match `iss` claim of ID token or, in the case of
+	// a federated login like Dex it should match the issuer URL of the
+	// upstream issuer. The issuer is not set the extensions are invalid and
+	// will fail to render.
+	Issuer string `json:"Issuer,omitempty"` // OID 1.3.6.1.4.1.57264.1.8 and 1.3.6.1.4.1.57264.1.1 (Deprecated)
+
+	// Reference to specific build instructions that are responsible for signing.
+	BuildSignerURI string `json:"BuildSignerURI,omitempty"` // 1.3.6.1.4.1.57264.1.9
+
+	// Immutable reference to the specific version of the build instructions that is responsible for signing.
+	BuildSignerDigest string `json:"BuildSignerDigest,omitempty"` // 1.3.6.1.4.1.57264.1.10
+
+	// Specifies whether the build took place in platform-hosted cloud infrastructure or customer/self-hosted infrastructure.
+	RunnerEnvironment string `json:"RunnerEnvironment,omitempty"` // 1.3.6.1.4.1.57264.1.11
+
+	// Source repository URL that the build was based on.
+	SourceRepositoryURI string `json:"SourceRepositoryURI,omitempty"` // 1.3.6.1.4.1.57264.1.12
+
+	// Immutable reference to a specific version of the source code that the build was based upon.
+	SourceRepositoryDigest string `json:"SourceRepositoryDigest,omitempty"` // 1.3.6.1.4.1.57264.1.13
+
+	// Source Repository Ref that the build run was based upon.
+	SourceRepositoryRef string `json:"SourceRepositoryRef,omitempty"` // 1.3.6.1.4.1.57264.1.14
+
+	// Immutable identifier for the source repository the workflow was based upon.
+	SourceRepositoryIdentifier string `json:"SourceRepositoryIdentifier,omitempty"` // 1.3.6.1.4.1.57264.1.15
+
+	// Source repository owner URL of the owner of the source repository that the build was based on.
+	SourceRepositoryOwnerURI string `json:"SourceRepositoryOwnerURI,omitempty"` // 1.3.6.1.4.1.57264.1.16
+
+	// Immutable identifier for the owner of the source repository that the workflow was based upon.
+	SourceRepositoryOwnerIdentifier string `json:"SourceRepositoryOwnerIdentifier,omitempty"` // 1.3.6.1.4.1.57264.1.17
+
+	// Build Config URL to the top-level/initiating build instructions.
+	BuildConfigURI string `json:"BuildConfigURI,omitempty"` // 1.3.6.1.4.1.57264.1.18
+
+	// Immutable reference to the specific version of the top-level/initiating build instructions.
+	BuildConfigDigest string `json:"BuildConfigDigest,omitempty"` // 1.3.6.1.4.1.57264.1.19
+
+	// Event or action that initiated the build.
+	BuildTrigger string `json:"BuildTrigger,omitempty"` // 1.3.6.1.4.1.57264.1.20
+
+	// Run Invocation URL to uniquely identify the build execution.
+	RunInvocationURI string `json:"RunInvocationURI,omitempty"` // 1.3.6.1.4.1.57264.1.21
+
+	// Source repository visibility at the time of signing the certificate.
+	SourceRepositoryVisibilityAtSigning string `json:"SourceRepositoryVisibilityAtSigning,omitempty"` // 1.3.6.1.4.1.57264.1.22
+}
diff --git a/vendor/github.com/moby/moby/api/types/image/summary.go b/vendor/github.com/moby/moby/api/types/image/summary.go
new file mode 100644
index 000000000..3d4dd165a
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/image/summary.go
@@ -0,0 +1,95 @@
+package image
+
+import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+
+type Summary struct {
+	// Number of containers using this image. Includes both stopped and running
+	// containers.
+	//
+	// This size is not calculated by default, and depends on which API endpoint
+	// is used. `-1` indicates that the value has not been set / calculated.
+	//
+	// Required: true
+	Containers int64 `json:"Containers"`
+
+	// Date and time at which the image was created as a Unix timestamp
+	// (number of seconds since EPOCH).
+	//
+	// Required: true
+	Created int64 `json:"Created"`
+
+	// ID is the content-addressable ID of an image.
+	//
+	// This identifier is a content-addressable digest calculated from the
+	// image's configuration (which includes the digests of layers used by
+	// the image).
+	//
+	// Note that this digest differs from the `RepoDigests` below, which
+	// holds digests of image manifests that reference the image.
+	//
+	// Required: true
+	ID string `json:"Id"`
+
+	// User-defined key/value metadata.
+	// Required: true
+	Labels map[string]string `json:"Labels"`
+
+	// ID of the parent image.
+	//
+	// Depending on how the image was created, this field may be empty and
+	// is only set for images that were built/created locally. This field
+	// is empty if the image was pulled from an image registry.
+	//
+	// Required: true
+	ParentID string `json:"ParentId"`
+
+	// Descriptor is the OCI descriptor of the image target.
+	// It's only set if the daemon provides a multi-platform image store.
+	//
+	// WARNING: This is experimental and may change at any time without any backward
+	// compatibility.
+	Descriptor *ocispec.Descriptor `json:"Descriptor,omitempty"`
+
+	// Manifests is a list of image manifests available in this image.  It
+	// provides a more detailed view of the platform-specific image manifests or
+	// other image-attached data like build attestations.
+	//
+	// WARNING: This is experimental and may change at any time without any backward
+	// compatibility.
+	Manifests []ManifestSummary `json:"Manifests,omitempty"`
+
+	// List of content-addressable digests of locally available image manifests
+	// that the image is referenced from. Multiple manifests can refer to the
+	// same image.
+	//
+	// These digests are usually only available if the image was either pulled
+	// from a registry, or if the image was pushed to a registry, which is when
+	// the manifest is generated and its digest calculated.
+	//
+	// Required: true
+	RepoDigests []string `json:"RepoDigests"`
+
+	// List of image names/tags in the local image cache that reference this
+	// image.
+	//
+	// Multiple image tags can refer to the same image, and this list may be
+	// empty if no tags reference the image, in which case the image is
+	// "untagged", in which case it can still be referenced by its ID.
+	//
+	// Required: true
+	RepoTags []string `json:"RepoTags"`
+
+	// Total size of image layers that are shared between this image and other
+	// images.
+	//
+	// This size is not calculated by default. `-1` indicates that the value
+	// has not been set / calculated.
+	//
+	// Required: true
+	SharedSize int64 `json:"SharedSize"`
+
+	// Total size of the image including all layers it is composed of.
+	//
+	// Required: true
+	Size int64 `json:"Size"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go b/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go
new file mode 100644
index 000000000..0dcc9337d
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go
@@ -0,0 +1,15 @@
+package jsonstream
+
+// Error wraps a concrete Code and Message, Code is
+// an integer error code, Message is the error message.
+type Error struct {
+	Code    int    `json:"code,omitempty"`
+	Message string `json:"message,omitempty"`
+}
+
+func (e *Error) Error() string {
+	if e == nil {
+		return "<nil>"
+	}
+	return e.Message
+}
diff --git a/vendor/github.com/moby/moby/api/types/jsonstream/message.go b/vendor/github.com/moby/moby/api/types/jsonstream/message.go
new file mode 100644
index 000000000..6b74bd932
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/jsonstream/message.go
@@ -0,0 +1,15 @@
+package jsonstream
+
+import "encoding/json"
+
+// Message defines a message struct. It describes
+// the created time, where it from, status, ID of the
+// message.
+type Message struct {
+	Stream   string           `json:"stream,omitempty"`
+	Status   string           `json:"status,omitempty"`
+	Progress *Progress        `json:"progressDetail,omitempty"`
+	ID       string           `json:"id,omitempty"`
+	Error    *Error           `json:"errorDetail,omitempty"`
+	Aux      *json.RawMessage `json:"aux,omitempty"` // Aux contains out-of-band data, such as digests for push signing and image id after building.
+}
diff --git a/vendor/github.com/moby/moby/api/types/jsonstream/progress.go b/vendor/github.com/moby/moby/api/types/jsonstream/progress.go
new file mode 100644
index 000000000..5c38b3b5e
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/jsonstream/progress.go
@@ -0,0 +1,10 @@
+package jsonstream
+
+// Progress describes a progress message in a JSON stream.
+type Progress struct {
+	Current    int64  `json:"current,omitempty"`    // Current is the current status and value of the progress made towards Total.
+	Total      int64  `json:"total,omitempty"`      // Total is the end value describing when we made 100% progress for an operation.
+	Start      int64  `json:"start,omitempty"`      // Start is the initial value for the operation.
+	HideCounts bool   `json:"hidecounts,omitempty"` // HideCounts. if true, hides the progress count indicator (xB/yB).
+	Units      string `json:"units,omitempty"`      // Units is the unit to print for progress. It defaults to "bytes" if empty.
+}
diff --git a/vendor/github.com/moby/moby/api/types/mount/mount.go b/vendor/github.com/moby/moby/api/types/mount/mount.go
new file mode 100644
index 000000000..090d436c6
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/mount/mount.go
@@ -0,0 +1,157 @@
+package mount
+
+import (
+	"os"
+)
+
+// Type represents the type of a mount.
+type Type string
+
+// Type constants
+const (
+	// TypeBind is the type for mounting host dir
+	TypeBind Type = "bind"
+	// TypeVolume is the type for remote storage volumes
+	TypeVolume Type = "volume"
+	// TypeTmpfs is the type for mounting tmpfs
+	TypeTmpfs Type = "tmpfs"
+	// TypeNamedPipe is the type for mounting Windows named pipes
+	TypeNamedPipe Type = "npipe"
+	// TypeCluster is the type for Swarm Cluster Volumes.
+	TypeCluster Type = "cluster"
+	// TypeImage is the type for mounting another image's filesystem
+	TypeImage Type = "image"
+)
+
+// Mount represents a mount (volume).
+type Mount struct {
+	Type Type `json:",omitempty"`
+	// Source specifies the name of the mount. Depending on mount type, this
+	// may be a volume name or a host path, or even ignored.
+	// Source is not supported for tmpfs (must be an empty value)
+	Source      string      `json:",omitempty"`
+	Target      string      `json:",omitempty"`
+	ReadOnly    bool        `json:",omitempty"` // attempts recursive read-only if possible
+	Consistency Consistency `json:",omitempty"`
+
+	BindOptions    *BindOptions    `json:",omitempty"`
+	VolumeOptions  *VolumeOptions  `json:",omitempty"`
+	ImageOptions   *ImageOptions   `json:",omitempty"`
+	TmpfsOptions   *TmpfsOptions   `json:",omitempty"`
+	ClusterOptions *ClusterOptions `json:",omitempty"`
+}
+
+// Propagation represents the propagation of a mount.
+type Propagation string
+
+const (
+	// PropagationRPrivate RPRIVATE
+	PropagationRPrivate Propagation = "rprivate"
+	// PropagationPrivate PRIVATE
+	PropagationPrivate Propagation = "private"
+	// PropagationRShared RSHARED
+	PropagationRShared Propagation = "rshared"
+	// PropagationShared SHARED
+	PropagationShared Propagation = "shared"
+	// PropagationRSlave RSLAVE
+	PropagationRSlave Propagation = "rslave"
+	// PropagationSlave SLAVE
+	PropagationSlave Propagation = "slave"
+)
+
+// Propagations is the list of all valid mount propagations
+var Propagations = []Propagation{
+	PropagationRPrivate,
+	PropagationPrivate,
+	PropagationRShared,
+	PropagationShared,
+	PropagationRSlave,
+	PropagationSlave,
+}
+
+// Consistency represents the consistency requirements of a mount.
+type Consistency string
+
+const (
+	// ConsistencyFull guarantees bind mount-like consistency
+	ConsistencyFull Consistency = "consistent"
+	// ConsistencyCached mounts can cache read data and FS structure
+	ConsistencyCached Consistency = "cached"
+	// ConsistencyDelegated mounts can cache read and written data and structure
+	ConsistencyDelegated Consistency = "delegated"
+	// ConsistencyDefault provides "consistent" behavior unless overridden
+	ConsistencyDefault Consistency = "default"
+)
+
+// BindOptions defines options specific to mounts of type "bind".
+type BindOptions struct {
+	Propagation      Propagation `json:",omitempty"`
+	NonRecursive     bool        `json:",omitempty"`
+	CreateMountpoint bool        `json:",omitempty"`
+	// ReadOnlyNonRecursive makes the mount non-recursively read-only, but still leaves the mount recursive
+	// (unless NonRecursive is set to true in conjunction).
+	ReadOnlyNonRecursive bool `json:",omitempty"`
+	// ReadOnlyForceRecursive raises an error if the mount cannot be made recursively read-only.
+	ReadOnlyForceRecursive bool `json:",omitempty"`
+}
+
+// VolumeOptions represents the options for a mount of type volume.
+type VolumeOptions struct {
+	NoCopy       bool              `json:",omitempty"`
+	Labels       map[string]string `json:",omitempty"`
+	Subpath      string            `json:",omitempty"`
+	DriverConfig *Driver           `json:",omitempty"`
+}
+
+type ImageOptions struct {
+	Subpath string `json:",omitempty"`
+}
+
+// Driver represents a volume driver.
+type Driver struct {
+	Name    string            `json:",omitempty"`
+	Options map[string]string `json:",omitempty"`
+}
+
+// TmpfsOptions defines options specific to mounts of type "tmpfs".
+type TmpfsOptions struct {
+	// Size sets the size of the tmpfs, in bytes.
+	//
+	// This will be converted to an operating system specific value
+	// depending on the host. For example, on linux, it will be converted to
+	// use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with
+	// docker, uses a straight byte value.
+	//
+	// Percentages are not supported.
+	SizeBytes int64 `json:",omitempty"`
+	// Mode of the tmpfs upon creation
+	Mode os.FileMode `json:",omitempty"`
+	// Options to be passed to the tmpfs mount. An array of arrays. Flag
+	// options should be provided as 1-length arrays. Other types should be
+	// provided as 2-length arrays, where the first item is the key and the
+	// second the value.
+	Options [][]string `json:",omitempty"`
+	// TODO(stevvooe): There are several more tmpfs flags, specified in the
+	// daemon, that are accepted. Only the most basic are added for now.
+	//
+	// From https://github.com/moby/sys/blob/mount/v0.1.1/mount/flags.go#L47-L56
+	//
+	// var validFlags = map[string]bool{
+	// 	"":          true,
+	// 	"size":      true, X
+	// 	"mode":      true, X
+	// 	"uid":       true,
+	// 	"gid":       true,
+	// 	"nr_inodes": true,
+	// 	"nr_blocks": true,
+	// 	"mpol":      true,
+	// }
+	//
+	// Some of these may be straightforward to add, but others, such as
+	// uid/gid have implications in a clustered system.
+}
+
+// ClusterOptions specifies options for a Cluster volume.
+type ClusterOptions struct {
+	// intentionally empty
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/config_reference.go b/vendor/github.com/moby/moby/api/types/network/config_reference.go
new file mode 100644
index 000000000..1158afe65
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/config_reference.go
@@ -0,0 +1,20 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// ConfigReference The config-only network source to provide the configuration for
+// this network.
+//
+// swagger:model ConfigReference
+type ConfigReference struct {
+
+	// The name of the config-only network that provides the network's
+	// configuration. The specified network must be an existing config-only
+	// network. Only network names are allowed, not network IDs.
+	//
+	// Example: config_only_network_01
+	Network string `json:"Network"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/connect_request.go b/vendor/github.com/moby/moby/api/types/network/connect_request.go
new file mode 100644
index 000000000..2ff14d360
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/connect_request.go
@@ -0,0 +1,20 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// ConnectRequest NetworkConnectRequest represents the data to be used to connect a container to a network.
+//
+// swagger:model ConnectRequest
+type ConnectRequest struct {
+
+	// The ID or name of the container to connect to the network.
+	// Example: 3613f73ba0e4
+	// Required: true
+	Container string `json:"Container"`
+
+	// endpoint config
+	EndpointConfig *EndpointSettings `json:"EndpointConfig,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/create_response.go b/vendor/github.com/moby/moby/api/types/network/create_response.go
new file mode 100644
index 000000000..199705991
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/create_response.go
@@ -0,0 +1,23 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// CreateResponse NetworkCreateResponse
+//
+// # OK response to NetworkCreate operation
+//
+// swagger:model CreateResponse
+type CreateResponse struct {
+
+	// The ID of the created network.
+	// Example: b5c4fc71e8022147cd25de22b22173de4e3b170134117172eb595cb91b4e7e5d
+	// Required: true
+	ID string `json:"Id"`
+
+	// Warnings encountered when creating the container
+	// Required: true
+	Warning string `json:"Warning"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/disconnect_request.go b/vendor/github.com/moby/moby/api/types/network/disconnect_request.go
new file mode 100644
index 000000000..7b1f521e7
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/disconnect_request.go
@@ -0,0 +1,21 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// DisconnectRequest NetworkDisconnectRequest represents the data to be used to disconnect a container from a network.
+//
+// swagger:model DisconnectRequest
+type DisconnectRequest struct {
+
+	// The ID or name of the container to disconnect from the network.
+	// Example: 3613f73ba0e4
+	// Required: true
+	Container string `json:"Container"`
+
+	// Force the container to disconnect from the network.
+	// Example: false
+	Force bool `json:"Force"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/endpoint.go b/vendor/github.com/moby/moby/api/types/network/endpoint.go
new file mode 100644
index 000000000..c4c1766cf
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/endpoint.go
@@ -0,0 +1,74 @@
+package network
+
+import (
+	"maps"
+	"net/netip"
+	"slices"
+)
+
+// EndpointSettings stores the network endpoint details
+type EndpointSettings struct {
+	// Configuration data
+	IPAMConfig *EndpointIPAMConfig
+	Links      []string
+	Aliases    []string // Aliases holds the list of extra, user-specified DNS names for this endpoint.
+	DriverOpts map[string]string
+
+	// GwPriority determines which endpoint will provide the default gateway
+	// for the container. The endpoint with the highest priority will be used.
+	// If multiple endpoints have the same priority, they are lexicographically
+	// sorted based on their network name, and the one that sorts first is picked.
+	GwPriority int
+
+	// Operational data
+
+	NetworkID  string
+	EndpointID string
+	Gateway    netip.Addr
+	IPAddress  netip.Addr
+
+	// MacAddress may be used to specify a MAC address when the container is created.
+	// Once the container is running, it becomes operational data (it may contain a
+	// generated address).
+	MacAddress          HardwareAddr
+	IPPrefixLen         int
+	IPv6Gateway         netip.Addr
+	GlobalIPv6Address   netip.Addr
+	GlobalIPv6PrefixLen int
+	// DNSNames holds all the (non fully qualified) DNS names associated to this
+	// endpoint. The first entry is used to generate PTR records.
+	DNSNames []string
+}
+
+// Copy makes a deep copy of `EndpointSettings`
+func (es *EndpointSettings) Copy() *EndpointSettings {
+	if es == nil {
+		return nil
+	}
+
+	epCopy := *es
+	epCopy.IPAMConfig = es.IPAMConfig.Copy()
+	epCopy.Links = slices.Clone(es.Links)
+	epCopy.Aliases = slices.Clone(es.Aliases)
+	epCopy.DNSNames = slices.Clone(es.DNSNames)
+	epCopy.DriverOpts = maps.Clone(es.DriverOpts)
+
+	return &epCopy
+}
+
+// EndpointIPAMConfig represents IPAM configurations for the endpoint
+type EndpointIPAMConfig struct {
+	IPv4Address  netip.Addr   `json:"IPv4Address,omitzero"`
+	IPv6Address  netip.Addr   `json:"IPv6Address,omitzero"`
+	LinkLocalIPs []netip.Addr `json:"LinkLocalIPs,omitempty"`
+}
+
+// Copy makes a copy of the endpoint ipam config
+func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig {
+	if cfg == nil {
+		return nil
+	}
+	cfgCopy := *cfg
+	cfgCopy.LinkLocalIPs = slices.Clone(cfg.LinkLocalIPs)
+	return &cfgCopy
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go b/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go
new file mode 100644
index 000000000..bf493ad5d
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go
@@ -0,0 +1,35 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+	"net/netip"
+)
+
+// EndpointResource contains network resources allocated and used for a container in a network.
+//
+// swagger:model EndpointResource
+type EndpointResource struct {
+
+	// name
+	// Example: container_1
+	Name string `json:"Name"`
+
+	// endpoint ID
+	// Example: 628cadb8bcb92de107b2a1e516cbffe463e321f548feb37697cce00ad694f21a
+	EndpointID string `json:"EndpointID"`
+
+	// mac address
+	// Example: 02:42:ac:13:00:02
+	MacAddress HardwareAddr `json:"MacAddress"`
+
+	// IPv4 address
+	// Example: 172.19.0.2/16
+	IPv4Address netip.Prefix `json:"IPv4Address"`
+
+	// IPv6 address
+	IPv6Address netip.Prefix `json:"IPv6Address"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/hwaddr.go b/vendor/github.com/moby/moby/api/types/network/hwaddr.go
new file mode 100644
index 000000000..b2a4dfb1a
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/hwaddr.go
@@ -0,0 +1,39 @@
+package network
+
+import (
+	"encoding"
+	"fmt"
+	"net"
+)
+
+// A HardwareAddr represents a physical hardware address.
+// It implements [encoding.TextMarshaler] and [encoding.TextUnmarshaler]
+// in the absence of go.dev/issue/29678.
+type HardwareAddr net.HardwareAddr
+
+var (
+	_ encoding.TextMarshaler   = (HardwareAddr)(nil)
+	_ encoding.TextUnmarshaler = (*HardwareAddr)(nil)
+	_ fmt.Stringer             = (HardwareAddr)(nil)
+)
+
+func (m *HardwareAddr) UnmarshalText(text []byte) error {
+	if len(text) == 0 {
+		*m = nil
+		return nil
+	}
+	hw, err := net.ParseMAC(string(text))
+	if err != nil {
+		return err
+	}
+	*m = HardwareAddr(hw)
+	return nil
+}
+
+func (m HardwareAddr) MarshalText() ([]byte, error) {
+	return []byte(net.HardwareAddr(m).String()), nil
+}
+
+func (m HardwareAddr) String() string {
+	return net.HardwareAddr(m).String()
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/inspect.go b/vendor/github.com/moby/moby/api/types/network/inspect.go
new file mode 100644
index 000000000..cded5e608
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/inspect.go
@@ -0,0 +1,27 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Inspect The body of the "get network" http response message.
+//
+// swagger:model Inspect
+type Inspect struct {
+	Network
+
+	// Contains endpoints attached to the network.
+	//
+	// Example: {"19a4d5d687db25203351ed79d478946f861258f018fe384f229f2efa4b23513c":{"EndpointID":"628cadb8bcb92de107b2a1e516cbffe463e321f548feb37697cce00ad694f21a","IPv4Address":"172.19.0.2/16","IPv6Address":"","MacAddress":"02:42:ac:13:00:02","Name":"test"}}
+	Containers map[string]EndpointResource `json:"Containers"`
+
+	// List of services using the network. This field is only present for
+	// swarm scope networks, and omitted for local scope networks.
+	//
+	Services map[string]ServiceInfo `json:"Services,omitempty"`
+
+	// provides runtime information about the network such as the number of allocated IPs.
+	//
+	Status *Status `json:"Status,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/ipam.go b/vendor/github.com/moby/moby/api/types/network/ipam.go
new file mode 100644
index 000000000..3fb357fc6
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/ipam.go
@@ -0,0 +1,22 @@
+package network
+
+import (
+	"net/netip"
+)
+
+// IPAM represents IP Address Management
+type IPAM struct {
+	Driver  string
+	Options map[string]string // Per network IPAM driver options
+	Config  []IPAMConfig
+}
+
+// IPAMConfig represents IPAM configurations
+type IPAMConfig struct {
+	Subnet     netip.Prefix          `json:"Subnet,omitzero"`
+	IPRange    netip.Prefix          `json:"IPRange,omitzero"`
+	Gateway    netip.Addr            `json:"Gateway,omitzero"`
+	AuxAddress map[string]netip.Addr `json:"AuxiliaryAddresses,omitempty"`
+}
+
+type SubnetStatuses = map[netip.Prefix]SubnetStatus
diff --git a/vendor/github.com/moby/moby/api/types/network/ipam_status.go b/vendor/github.com/moby/moby/api/types/network/ipam_status.go
new file mode 100644
index 000000000..7eb4e8487
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/ipam_status.go
@@ -0,0 +1,16 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// IPAMStatus IPAM status
+//
+// swagger:model IPAMStatus
+type IPAMStatus struct {
+
+	// subnets
+	// Example: {"172.16.0.0/16":{"DynamicIPsAvailable":65533,"IPsInUse":3},"2001:db8:abcd:0012::0/96":{"DynamicIPsAvailable":4294967291,"IPsInUse":5}}
+	Subnets SubnetStatuses `json:"Subnets,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/network.go b/vendor/github.com/moby/moby/api/types/network/network.go
new file mode 100644
index 000000000..a7d9c0f6a
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/network.go
@@ -0,0 +1,100 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+	timeext "time"
+)
+
+// Network network
+//
+// swagger:model Network
+type Network struct {
+
+	// Name of the network.
+	//
+	// Example: my_network
+	Name string `json:"Name"`
+
+	// ID that uniquely identifies a network on a single machine.
+	//
+	// Example: 7d86d31b1478e7cca9ebed7e73aa0fdeec46c5ca29497431d3007d2d9e15ed99
+	ID string `json:"Id"`
+
+	// Date and time at which the network was created in
+	// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format with nano-seconds.
+	//
+	// Example: 2016-10-19T04:33:30.360899459Z
+	Created timeext.Time `json:"Created"`
+
+	// The level at which the network exists (e.g. `swarm` for cluster-wide
+	// or `local` for machine level)
+	//
+	// Example: local
+	Scope string `json:"Scope"`
+
+	// The name of the driver used to create the network (e.g. `bridge`,
+	// `overlay`).
+	//
+	// Example: overlay
+	Driver string `json:"Driver"`
+
+	// Whether the network was created with IPv4 enabled.
+	//
+	// Example: true
+	EnableIPv4 bool `json:"EnableIPv4"`
+
+	// Whether the network was created with IPv6 enabled.
+	//
+	// Example: false
+	EnableIPv6 bool `json:"EnableIPv6"`
+
+	// The network's IP Address Management.
+	//
+	IPAM IPAM `json:"IPAM"`
+
+	// Whether the network is created to only allow internal networking
+	// connectivity.
+	//
+	// Example: false
+	Internal bool `json:"Internal"`
+
+	// Whether a global / swarm scope network is manually attachable by regular
+	// containers from workers in swarm mode.
+	//
+	// Example: false
+	Attachable bool `json:"Attachable"`
+
+	// Whether the network is providing the routing-mesh for the swarm cluster.
+	//
+	// Example: false
+	Ingress bool `json:"Ingress"`
+
+	// config from
+	ConfigFrom ConfigReference `json:"ConfigFrom"`
+
+	// Whether the network is a config-only network. Config-only networks are
+	// placeholder networks for network configurations to be used by other
+	// networks. Config-only networks cannot be used directly to run containers
+	// or services.
+	//
+	ConfigOnly bool `json:"ConfigOnly"`
+
+	// Network-specific options uses when creating the network.
+	//
+	// Example: {"com.docker.network.bridge.default_bridge":"true","com.docker.network.bridge.enable_icc":"true","com.docker.network.bridge.enable_ip_masquerade":"true","com.docker.network.bridge.host_binding_ipv4":"0.0.0.0","com.docker.network.bridge.name":"docker0","com.docker.network.driver.mtu":"1500"}
+	Options map[string]string `json:"Options"`
+
+	// Metadata specific to the network being created.
+	//
+	// Example: {"com.example.some-label":"some-value","com.example.some-other-label":"some-other-value"}
+	Labels map[string]string `json:"Labels"`
+
+	// List of peer nodes for an overlay network. This field is only present
+	// for overlay networks, and omitted for other network types.
+	//
+	Peers []PeerInfo `json:"Peers,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/network_types.go b/vendor/github.com/moby/moby/api/types/network/network_types.go
new file mode 100644
index 000000000..5401f55f8
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/network_types.go
@@ -0,0 +1,43 @@
+package network
+
+const (
+	// NetworkDefault is a platform-independent alias to choose the platform-specific default network stack.
+	NetworkDefault = "default"
+	// NetworkHost is the name of the predefined network used when the NetworkMode host is selected (only available on Linux)
+	NetworkHost = "host"
+	// NetworkNone is the name of the predefined network used when the NetworkMode none is selected (available on both Linux and Windows)
+	NetworkNone = "none"
+	// NetworkBridge is the name of the default network on Linux
+	NetworkBridge = "bridge"
+	// NetworkNat is the name of the default network on Windows
+	NetworkNat = "nat"
+)
+
+// CreateRequest is the request message sent to the server for network create call.
+type CreateRequest struct {
+	Name       string            // Name is the requested name of the network.
+	Driver     string            // Driver is the driver-name used to create the network (e.g. `bridge`, `overlay`)
+	Scope      string            // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level).
+	EnableIPv4 *bool             `json:",omitempty"` // EnableIPv4 represents whether to enable IPv4.
+	EnableIPv6 *bool             `json:",omitempty"` // EnableIPv6 represents whether to enable IPv6.
+	IPAM       *IPAM             // IPAM is the network's IP Address Management.
+	Internal   bool              // Internal represents if the network is used internal only.
+	Attachable bool              // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode.
+	Ingress    bool              // Ingress indicates the network is providing the routing-mesh for the swarm cluster.
+	ConfigOnly bool              // ConfigOnly creates a config-only network. Config-only networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services.
+	ConfigFrom *ConfigReference  // ConfigFrom specifies the source which will provide the configuration for this network. The specified network must be a config-only network; see [CreateOptions.ConfigOnly].
+	Options    map[string]string // Options specifies the network-specific options to use for when creating the network.
+	Labels     map[string]string // Labels holds metadata specific to the network being created.
+}
+
+// NetworkingConfig represents the container's networking configuration for each of its interfaces
+// Carries the networking configs specified in the `docker run` and `docker network connect` commands
+type NetworkingConfig struct {
+	EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network
+}
+
+// PruneReport contains the response for Engine API:
+// POST "/networks/prune"
+type PruneReport struct {
+	NetworksDeleted []string
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/peer_info.go b/vendor/github.com/moby/moby/api/types/network/peer_info.go
new file mode 100644
index 000000000..dc88ec16f
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/peer_info.go
@@ -0,0 +1,24 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+	"net/netip"
+)
+
+// PeerInfo represents one peer of an overlay network.
+//
+// swagger:model PeerInfo
+type PeerInfo struct {
+
+	// ID of the peer-node in the Swarm cluster.
+	// Example: 6869d7c1732b
+	Name string `json:"Name"`
+
+	// IP-address of the peer-node in the Swarm cluster.
+	// Example: 10.133.77.91
+	IP netip.Addr `json:"IP"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/port.go b/vendor/github.com/moby/moby/api/types/network/port.go
new file mode 100644
index 000000000..d12d55ab3
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/port.go
@@ -0,0 +1,372 @@
+package network
+
+import (
+	"errors"
+	"fmt"
+	"iter"
+	"net/netip"
+	"strconv"
+	"strings"
+	"unique"
+)
+
+// IPProtocol represents a network protocol for a port.
+type IPProtocol string
+
+const (
+	TCP  IPProtocol = "tcp"
+	UDP  IPProtocol = "udp"
+	SCTP IPProtocol = "sctp"
+)
+
+// Sentinel port proto value for zero Port and PortRange values.
+var protoZero unique.Handle[IPProtocol]
+
+// Port is a type representing a single port number and protocol in the format "<portnum>/[<proto>]".
+//
+// The zero port value, i.e. Port{}, is invalid; use [ParsePort] to create a valid Port value.
+type Port struct {
+	num   uint16
+	proto unique.Handle[IPProtocol]
+}
+
+// ParsePort parses s as a [Port].
+//
+// It normalizes the provided protocol such that "80/tcp", "80/TCP", and "80/tCp" are equivalent.
+// If a port number is provided, but no protocol, the default ("tcp") protocol is returned.
+func ParsePort(s string) (Port, error) {
+	if s == "" {
+		return Port{}, errors.New("invalid port: value is empty")
+	}
+
+	port, proto, _ := strings.Cut(s, "/")
+
+	portNum, err := parsePortNumber(port)
+	if err != nil {
+		return Port{}, fmt.Errorf("invalid port '%s': %w", port, err)
+	}
+
+	normalizedPortProto := normalizePortProto(proto)
+	return Port{num: portNum, proto: normalizedPortProto}, nil
+}
+
+// MustParsePort calls [ParsePort](s) and panics on error.
+//
+// It is intended for use in tests with hard-coded strings.
+func MustParsePort(s string) Port {
+	p, err := ParsePort(s)
+	if err != nil {
+		panic(err)
+	}
+	return p
+}
+
+// PortFrom returns a [Port] with the given number and protocol.
+//
+// If no protocol is specified (i.e. proto == ""), then PortFrom returns Port{}, false.
+func PortFrom(num uint16, proto IPProtocol) (p Port, ok bool) {
+	if proto == "" {
+		return Port{}, false
+	}
+	normalized := normalizePortProto(string(proto))
+	return Port{num: num, proto: normalized}, true
+}
+
+// Num returns p's port number.
+func (p Port) Num() uint16 {
+	return p.num
+}
+
+// Port returns p's port number as a string.
+//
+// It returns an empty string for zero-values.
+func (p Port) Port() string {
+	if p.proto == protoZero {
+		return ""
+	}
+	return strconv.Itoa(int(p.num))
+}
+
+// Proto returns p's network protocol.
+func (p Port) Proto() IPProtocol {
+	if p.proto == protoZero {
+		return ""
+	}
+	return p.proto.Value()
+}
+
+// IsZero reports whether p is the zero value.
+func (p Port) IsZero() bool {
+	return p.proto == protoZero
+}
+
+// IsValid reports whether p is an initialized valid port (not the zero value).
+func (p Port) IsValid() bool {
+	return p.proto != protoZero
+}
+
+// String returns a string representation of the port in the format "<portnum>/<proto>".
+// If the port is the zero value, it returns "invalid port", and users should
+// check [PortRange.IsValid] or [PortRange.IsZero] before using this method.
+func (p Port) String() string {
+	switch p.proto {
+	case protoZero:
+		return "invalid port"
+	default:
+		return string(p.AppendTo(nil))
+	}
+}
+
+// AppendText implements [encoding.TextAppender] interface.
+// It is the same as [Port.AppendTo] but returns an error to satisfy the interface.
+func (p Port) AppendText(b []byte) ([]byte, error) {
+	return p.AppendTo(b), nil
+}
+
+// AppendTo appends a text encoding of p to b and returns the extended buffer.
+func (p Port) AppendTo(b []byte) []byte {
+	if p.IsZero() {
+		return b
+	}
+	return fmt.Appendf(b, "%d/%s", p.num, p.proto.Value())
+}
+
+// MarshalText implements [encoding.TextMarshaler] interface.
+func (p Port) MarshalText() ([]byte, error) {
+	return p.AppendText(nil)
+}
+
+// UnmarshalText implements [encoding.TextUnmarshaler] interface.
+func (p *Port) UnmarshalText(text []byte) error {
+	if len(text) == 0 {
+		*p = Port{}
+		return nil
+	}
+
+	port, err := ParsePort(string(text))
+	if err != nil {
+		return err
+	}
+
+	*p = port
+	return nil
+}
+
+// Range returns a [PortRange] representing the single port.
+func (p Port) Range() PortRange {
+	return PortRange{start: p.num, end: p.num, proto: p.proto}
+}
+
+// PortSet is a collection of structs indexed by [Port].
+type PortSet = map[Port]struct{}
+
+// PortBinding represents a binding between a Host IP address and a Host Port.
+type PortBinding struct {
+	// HostIP is the host IP Address
+	HostIP netip.Addr `json:"HostIp"`
+	// HostPort is the host port number
+	HostPort string `json:"HostPort"`
+}
+
+// PortMap is a collection of [PortBinding] indexed by [Port].
+type PortMap = map[Port][]PortBinding
+
+// PortRange represents a range of port numbers and a protocol in the format "8000-9000/tcp".
+//
+// The zero port range value, i.e. PortRange{}, is invalid; use [ParsePortRange] to create a valid PortRange value.
+type PortRange struct {
+	start uint16
+	end   uint16
+	proto unique.Handle[IPProtocol]
+}
+
+// ParsePortRange parses s as a [PortRange].
+//
+// It normalizes the provided protocol such that "80-90/tcp", "80-90/TCP", and "80-90/tCp" are equivalent.
+// If a port number range is provided, but no protocol, the default ("tcp") protocol is returned.
+func ParsePortRange(s string) (PortRange, error) {
+	if s == "" {
+		return PortRange{}, errors.New("invalid port range: value is empty")
+	}
+
+	portRange, proto, _ := strings.Cut(s, "/")
+
+	start, end, ok := strings.Cut(portRange, "-")
+	startVal, err := parsePortNumber(start)
+	if err != nil {
+		return PortRange{}, fmt.Errorf("invalid start port '%s': %w", start, err)
+	}
+
+	portProto := normalizePortProto(proto)
+
+	if !ok || start == end {
+		return PortRange{start: startVal, end: startVal, proto: portProto}, nil
+	}
+
+	endVal, err := parsePortNumber(end)
+	if err != nil {
+		return PortRange{}, fmt.Errorf("invalid end port '%s': %w", end, err)
+	}
+	if endVal < startVal {
+		return PortRange{}, errors.New("invalid port range: " + s)
+	}
+	return PortRange{start: startVal, end: endVal, proto: portProto}, nil
+}
+
+// MustParsePortRange calls [ParsePortRange](s) and panics on error.
+// It is intended for use in tests with hard-coded strings.
+func MustParsePortRange(s string) PortRange {
+	pr, err := ParsePortRange(s)
+	if err != nil {
+		panic(err)
+	}
+	return pr
+}
+
+// PortRangeFrom returns a [PortRange] with the given start and end port numbers and protocol.
+//
+// If end < start or no protocol is specified (i.e. proto == ""), then PortRangeFrom returns PortRange{}, false.
+func PortRangeFrom(start, end uint16, proto IPProtocol) (pr PortRange, ok bool) {
+	if end < start || proto == "" {
+		return PortRange{}, false
+	}
+	normalized := normalizePortProto(string(proto))
+	return PortRange{start: start, end: end, proto: normalized}, true
+}
+
+// Start returns pr's start port number.
+func (pr PortRange) Start() uint16 {
+	return pr.start
+}
+
+// End returns pr's end port number.
+func (pr PortRange) End() uint16 {
+	return pr.end
+}
+
+// Proto returns pr's network protocol.
+func (pr PortRange) Proto() IPProtocol {
+	if pr.proto == protoZero {
+		return ""
+	}
+	return pr.proto.Value()
+}
+
+// IsZero reports whether pr is the zero value.
+func (pr PortRange) IsZero() bool {
+	return pr.proto == protoZero
+}
+
+// IsValid reports whether pr is an initialized valid port range (not the zero value).
+func (pr PortRange) IsValid() bool {
+	return pr.proto != protoZero
+}
+
+// String returns a string representation of the port range in the format
+// "<start>-<end>/<proto>" or "<portnum>/<proto>" (if start == end).
+//
+// If the port range is the zero value, it returns "invalid port range",
+// and users should check [PortRange.IsValid] or [PortRange.IsZero] before
+// using this method.
+func (pr PortRange) String() string {
+	switch pr.proto {
+	case protoZero:
+		return "invalid port range"
+	default:
+		return string(pr.AppendTo(nil))
+	}
+}
+
+// AppendText implements [encoding.TextAppender] interface.
+// It is the same as [PortRange.AppendTo] but returns an error to satisfy the interface.
+func (pr PortRange) AppendText(b []byte) ([]byte, error) {
+	return pr.AppendTo(b), nil
+}
+
+// AppendTo appends a text encoding of pr to b and returns the extended buffer.
+func (pr PortRange) AppendTo(b []byte) []byte {
+	if pr.IsZero() {
+		return b
+	}
+	if pr.start == pr.end {
+		return fmt.Appendf(b, "%d/%s", pr.start, pr.proto.Value())
+	}
+	return fmt.Appendf(b, "%d-%d/%s", pr.start, pr.end, pr.proto.Value())
+}
+
+// MarshalText implements [encoding.TextMarshaler] interface.
+func (pr PortRange) MarshalText() ([]byte, error) {
+	return pr.AppendText(nil)
+}
+
+// UnmarshalText implements [encoding.TextUnmarshaler] interface.
+func (pr *PortRange) UnmarshalText(text []byte) error {
+	if len(text) == 0 {
+		*pr = PortRange{}
+		return nil
+	}
+
+	portRange, err := ParsePortRange(string(text))
+	if err != nil {
+		return err
+	}
+	*pr = portRange
+	return nil
+}
+
+// Range returns pr.
+func (pr PortRange) Range() PortRange {
+	return pr
+}
+
+// All returns an iterator over all the individual ports in the range.
+//
+// For example:
+//
+//	for port := range pr.All() {
+//	    // ...
+//	}
+func (pr PortRange) All() iter.Seq[Port] {
+	return func(yield func(Port) bool) {
+		// Do not skip zero values here, because a zero-value means
+		// "map the port to an ephemeral host port".
+		//
+		// For example, "--port 80" is shorthand for "--port 0:80"
+		// ("--port <ephemeral port>:80").
+		for i := uint32(pr.Start()); i <= uint32(pr.End()); i++ {
+			if !yield(Port{num: uint16(i), proto: pr.proto}) {
+				return
+			}
+		}
+	}
+}
+
+// parsePortNumber parses rawPort into an int, unwrapping strconv errors
+// and returning a single "out of range" error for any value outside 0–65535.
+func parsePortNumber(rawPort string) (uint16, error) {
+	if rawPort == "" {
+		return 0, errors.New("value is empty")
+	}
+	port, err := strconv.ParseUint(rawPort, 10, 16)
+	if err != nil {
+		var numErr *strconv.NumError
+		if errors.As(err, &numErr) {
+			err = numErr.Err
+		}
+		return 0, err
+	}
+
+	return uint16(port), nil
+}
+
+// normalizePortProto normalizes the protocol string such that "tcp", "TCP", and "tCp" are equivalent.
+// If proto is not specified, it defaults to "tcp".
+func normalizePortProto(proto string) unique.Handle[IPProtocol] {
+	if proto == "" {
+		return unique.Make(TCP)
+	}
+
+	proto = strings.ToLower(proto)
+
+	return unique.Make(IPProtocol(proto))
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/service_info.go b/vendor/github.com/moby/moby/api/types/network/service_info.go
new file mode 100644
index 000000000..fdd92f161
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/service_info.go
@@ -0,0 +1,28 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+	"net/netip"
+)
+
+// ServiceInfo represents service parameters with the list of service's tasks
+//
+// swagger:model ServiceInfo
+type ServiceInfo struct {
+
+	// v IP
+	VIP netip.Addr `json:"VIP"`
+
+	// ports
+	Ports []string `json:"Ports"`
+
+	// local l b index
+	LocalLBIndex int `json:"LocalLBIndex"`
+
+	// tasks
+	Tasks []Task `json:"Tasks"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/status.go b/vendor/github.com/moby/moby/api/types/network/status.go
new file mode 100644
index 000000000..94f4b4b2e
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/status.go
@@ -0,0 +1,15 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Status provides runtime information about the network such as the number of allocated IPs.
+//
+// swagger:model Status
+type Status struct {
+
+	// IPAM
+	IPAM IPAMStatus `json:"IPAM"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/subnet_status.go b/vendor/github.com/moby/moby/api/types/network/subnet_status.go
new file mode 100644
index 000000000..dd62429f5
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/subnet_status.go
@@ -0,0 +1,20 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// SubnetStatus subnet status
+//
+// swagger:model SubnetStatus
+type SubnetStatus struct {
+
+	// Number of IP addresses in the subnet that are in use or reserved and are therefore unavailable for allocation, saturating at 2<sup>64</sup> - 1.
+	//
+	IPsInUse uint64 `json:"IPsInUse"`
+
+	// Number of IP addresses within the network's IPRange for the subnet that are available for allocation, saturating at 2<sup>64</sup> - 1.
+	//
+	DynamicIPsAvailable uint64 `json:"DynamicIPsAvailable"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/summary.go b/vendor/github.com/moby/moby/api/types/network/summary.go
new file mode 100644
index 000000000..3f50ce227
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/summary.go
@@ -0,0 +1,13 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Summary Network list response item
+//
+// swagger:model Summary
+type Summary struct {
+	Network
+}
diff --git a/vendor/github.com/moby/moby/api/types/network/task.go b/vendor/github.com/moby/moby/api/types/network/task.go
new file mode 100644
index 000000000..a547523a4
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/network/task.go
@@ -0,0 +1,28 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package network
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+	"net/netip"
+)
+
+// Task carries the information about one backend task
+//
+// swagger:model Task
+type Task struct {
+
+	// name
+	Name string `json:"Name"`
+
+	// endpoint ID
+	EndpointID string `json:"EndpointID"`
+
+	// endpoint IP
+	EndpointIP netip.Addr `json:"EndpointIP"`
+
+	// info
+	Info map[string]string `json:"Info"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/plugin/.gitignore b/vendor/github.com/moby/moby/api/types/plugin/.gitignore
new file mode 100644
index 000000000..5cea8434d
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/plugin/.gitignore
@@ -0,0 +1 @@
+testdata/rapid/**
diff --git a/vendor/github.com/moby/moby/api/types/plugin/capability.go b/vendor/github.com/moby/moby/api/types/plugin/capability.go
new file mode 100644
index 000000000..d53f77a1f
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/plugin/capability.go
@@ -0,0 +1,55 @@
+package plugin
+
+import (
+	"bytes"
+	"encoding"
+	"fmt"
+	"strings"
+)
+
+type CapabilityID struct {
+	Capability string
+	Prefix     string
+	Version    string
+}
+
+var (
+	_ fmt.Stringer             = CapabilityID{}
+	_ encoding.TextUnmarshaler = (*CapabilityID)(nil)
+	_ encoding.TextMarshaler   = CapabilityID{}
+)
+
+// String implements [fmt.Stringer] for CapabilityID
+func (t CapabilityID) String() string {
+	return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version)
+}
+
+// UnmarshalText implements [encoding.TextUnmarshaler] for CapabilityID
+func (t *CapabilityID) UnmarshalText(p []byte) error {
+	fqcap, version, _ := bytes.Cut(p, []byte{'/'})
+	idx := bytes.LastIndexByte(fqcap, '.')
+	if idx < 0 {
+		t.Prefix = ""
+		t.Capability = string(fqcap)
+	} else {
+		t.Prefix = string(fqcap[:idx])
+		t.Capability = string(fqcap[idx+1:])
+	}
+	t.Version = string(version)
+	return nil
+}
+
+// MarshalText implements [encoding.TextMarshaler] for CapabilityID
+func (t CapabilityID) MarshalText() ([]byte, error) {
+	// Assert that the value can be round-tripped successfully.
+	if strings.Contains(t.Capability, ".") {
+		return nil, fmt.Errorf("capability %q cannot contain a dot", t.Capability)
+	}
+	if strings.Contains(t.Prefix, "/") {
+		return nil, fmt.Errorf("prefix %q cannot contain a slash", t.Prefix)
+	}
+	if strings.Contains(t.Capability, "/") {
+		return nil, fmt.Errorf("capability %q cannot contain a slash", t.Capability)
+	}
+	return []byte(t.String()), nil
+}
diff --git a/vendor/github.com/moby/moby/api/types/plugin/device.go b/vendor/github.com/moby/moby/api/types/plugin/device.go
new file mode 100644
index 000000000..ae9617704
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/plugin/device.go
@@ -0,0 +1,29 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package plugin
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Device device
+//
+// swagger:model Device
+type Device struct {
+
+	// description
+	// Required: true
+	Description string `json:"Description"`
+
+	// name
+	// Required: true
+	Name string `json:"Name"`
+
+	// path
+	// Example: /dev/fuse
+	// Required: true
+	Path *string `json:"Path"`
+
+	// settable
+	// Required: true
+	Settable []string `json:"Settable"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/plugin/env.go b/vendor/github.com/moby/moby/api/types/plugin/env.go
new file mode 100644
index 000000000..dcbe0b762
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/plugin/env.go
@@ -0,0 +1,28 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package plugin
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Env env
+//
+// swagger:model Env
+type Env struct {
+
+	// description
+	// Required: true
+	Description string `json:"Description"`
+
+	// name
+	// Required: true
+	Name string `json:"Name"`
+
+	// settable
+	// Required: true
+	Settable []string `json:"Settable"`
+
+	// value
+	// Required: true
+	Value *string `json:"Value"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/plugin/mount.go b/vendor/github.com/moby/moby/api/types/plugin/mount.go
new file mode 100644
index 000000000..7970306cc
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/plugin/mount.go
@@ -0,0 +1,46 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package plugin
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Mount mount
+//
+// swagger:model Mount
+type Mount struct {
+
+	// description
+	// Example: This is a mount that's used by the plugin.
+	// Required: true
+	Description string `json:"Description"`
+
+	// destination
+	// Example: /mnt/state
+	// Required: true
+	Destination string `json:"Destination"`
+
+	// name
+	// Example: some-mount
+	// Required: true
+	Name string `json:"Name"`
+
+	// options
+	// Example: ["rbind","rw"]
+	// Required: true
+	Options []string `json:"Options"`
+
+	// settable
+	// Required: true
+	Settable []string `json:"Settable"`
+
+	// source
+	// Example: /var/lib/docker/plugins/
+	// Required: true
+	Source *string `json:"Source"`
+
+	// type
+	// Example: bind
+	// Required: true
+	Type string `json:"Type"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/plugin/plugin.go b/vendor/github.com/moby/moby/api/types/plugin/plugin.go
new file mode 100644
index 000000000..3305170d5
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/plugin/plugin.go
@@ -0,0 +1,237 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package plugin
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Plugin A plugin for the Engine API
+//
+// swagger:model Plugin
+type Plugin struct {
+
+	// config
+	// Required: true
+	Config Config `json:"Config"`
+
+	// True if the plugin is running. False if the plugin is not running, only installed.
+	// Example: true
+	// Required: true
+	Enabled bool `json:"Enabled"`
+
+	// Id
+	// Example: 5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078
+	ID string `json:"Id,omitempty"`
+
+	// name
+	// Example: tiborvass/sample-volume-plugin
+	// Required: true
+	Name string `json:"Name"`
+
+	// plugin remote reference used to push/pull the plugin
+	// Example: localhost:5000/tiborvass/sample-volume-plugin:latest
+	PluginReference string `json:"PluginReference,omitempty"`
+
+	// settings
+	// Required: true
+	Settings Settings `json:"Settings"`
+}
+
+// Config The config of a plugin.
+//
+// swagger:model Config
+type Config struct {
+
+	// args
+	// Required: true
+	Args Args `json:"Args"`
+
+	// description
+	// Example: A sample volume plugin for Docker
+	// Required: true
+	Description string `json:"Description"`
+
+	// documentation
+	// Example: https://docs.docker.com/engine/extend/plugins/
+	// Required: true
+	Documentation string `json:"Documentation"`
+
+	// entrypoint
+	// Example: ["/usr/bin/sample-volume-plugin","/data"]
+	// Required: true
+	Entrypoint []string `json:"Entrypoint"`
+
+	// env
+	// Example: [{"Description":"If set, prints debug messages","Name":"DEBUG","Settable":null,"Value":"0"}]
+	// Required: true
+	Env []Env `json:"Env"`
+
+	// interface
+	// Required: true
+	Interface Interface `json:"Interface"`
+
+	// ipc host
+	// Example: false
+	// Required: true
+	IpcHost bool `json:"IpcHost"`
+
+	// linux
+	// Required: true
+	Linux LinuxConfig `json:"Linux"`
+
+	// mounts
+	// Required: true
+	Mounts []Mount `json:"Mounts"`
+
+	// network
+	// Required: true
+	Network NetworkConfig `json:"Network"`
+
+	// pid host
+	// Example: false
+	// Required: true
+	PidHost bool `json:"PidHost"`
+
+	// propagated mount
+	// Example: /mnt/volumes
+	// Required: true
+	PropagatedMount string `json:"PropagatedMount"`
+
+	// user
+	User User `json:"User,omitempty"`
+
+	// work dir
+	// Example: /bin/
+	// Required: true
+	WorkDir string `json:"WorkDir"`
+
+	// rootfs
+	Rootfs *RootFS `json:"rootfs,omitempty"`
+}
+
+// Args args
+//
+// swagger:model Args
+type Args struct {
+
+	// description
+	// Example: command line arguments
+	// Required: true
+	Description string `json:"Description"`
+
+	// name
+	// Example: args
+	// Required: true
+	Name string `json:"Name"`
+
+	// settable
+	// Required: true
+	Settable []string `json:"Settable"`
+
+	// value
+	// Required: true
+	Value []string `json:"Value"`
+}
+
+// Interface The interface between Docker and the plugin
+//
+// swagger:model Interface
+type Interface struct {
+
+	// Protocol to use for clients connecting to the plugin.
+	// Example: some.protocol/v1.0
+	// Enum: ["","moby.plugins.http/v1"]
+	ProtocolScheme string `json:"ProtocolScheme,omitempty"`
+
+	// socket
+	// Example: plugins.sock
+	// Required: true
+	Socket string `json:"Socket"`
+
+	// types
+	// Example: ["docker.volumedriver/1.0"]
+	// Required: true
+	Types []CapabilityID `json:"Types"`
+}
+
+// LinuxConfig linux config
+//
+// swagger:model LinuxConfig
+type LinuxConfig struct {
+
+	// allow all devices
+	// Example: false
+	// Required: true
+	AllowAllDevices bool `json:"AllowAllDevices"`
+
+	// capabilities
+	// Example: ["CAP_SYS_ADMIN","CAP_SYSLOG"]
+	// Required: true
+	Capabilities []string `json:"Capabilities"`
+
+	// devices
+	// Required: true
+	Devices []Device `json:"Devices"`
+}
+
+// NetworkConfig network config
+//
+// swagger:model NetworkConfig
+type NetworkConfig struct {
+
+	// type
+	// Example: host
+	// Required: true
+	Type string `json:"Type"`
+}
+
+// RootFS root f s
+//
+// swagger:model RootFS
+type RootFS struct {
+
+	// diff ids
+	// Example: ["sha256:675532206fbf3030b8458f88d6e26d4eb1577688a25efec97154c94e8b6b4887","sha256:e216a057b1cb1efc11f8a268f37ef62083e70b1b38323ba252e25ac88904a7e8"]
+	DiffIds []string `json:"diff_ids"`
+
+	// type
+	// Example: layers
+	Type string `json:"type,omitempty"`
+}
+
+// User user
+//
+// swagger:model User
+type User struct {
+
+	// g ID
+	// Example: 1000
+	GID uint32 `json:"GID,omitempty"`
+
+	// UID
+	// Example: 1000
+	UID uint32 `json:"UID,omitempty"`
+}
+
+// Settings user-configurable settings for the plugin.
+//
+// swagger:model Settings
+type Settings struct {
+
+	// args
+	// Required: true
+	Args []string `json:"Args"`
+
+	// devices
+	// Required: true
+	Devices []Device `json:"Devices"`
+
+	// env
+	// Example: ["DEBUG=0"]
+	// Required: true
+	Env []string `json:"Env"`
+
+	// mounts
+	// Required: true
+	Mounts []Mount `json:"Mounts"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/plugin/plugin_responses.go b/vendor/github.com/moby/moby/api/types/plugin/plugin_responses.go
new file mode 100644
index 000000000..91b327eb4
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/plugin/plugin_responses.go
@@ -0,0 +1,33 @@
+package plugin
+
+import (
+	"sort"
+)
+
+// ListResponse contains the response for the Engine API
+type ListResponse []Plugin
+
+// Privilege describes a permission the user has to accept
+// upon installing a plugin.
+type Privilege struct {
+	Name        string
+	Description string
+	Value       []string
+}
+
+// Privileges is a list of Privilege
+type Privileges []Privilege
+
+func (s Privileges) Len() int {
+	return len(s)
+}
+
+func (s Privileges) Less(i, j int) bool {
+	return s[i].Name < s[j].Name
+}
+
+func (s Privileges) Swap(i, j int) {
+	sort.Strings(s[i].Value)
+	sort.Strings(s[j].Value)
+	s[i], s[j] = s[j], s[i]
+}
diff --git a/vendor/github.com/moby/moby/api/types/registry/auth_response.go b/vendor/github.com/moby/moby/api/types/registry/auth_response.go
new file mode 100644
index 000000000..94c2e1bb3
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/registry/auth_response.go
@@ -0,0 +1,21 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package registry
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// AuthResponse An identity token was generated successfully.
+//
+// swagger:model AuthResponse
+type AuthResponse struct {
+
+	// An opaque token used to authenticate a user after a successful login
+	// Example: 9cbaf023786cd7...
+	IdentityToken string `json:"IdentityToken,omitempty"`
+
+	// The status of the authentication
+	// Example: Login Succeeded
+	// Required: true
+	Status string `json:"Status"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/registry/authconfig.go b/vendor/github.com/moby/moby/api/types/registry/authconfig.go
new file mode 100644
index 000000000..b612feeba
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/registry/authconfig.go
@@ -0,0 +1,35 @@
+package registry
+
+import "context"
+
+// AuthHeader is the name of the header used to send encoded registry
+// authorization credentials for registry operations (push/pull).
+const AuthHeader = "X-Registry-Auth"
+
+// RequestAuthConfig is a function interface that clients can supply
+// to retry operations after getting an authorization error.
+//
+// The function must return the [AuthHeader] value ([AuthConfig]), encoded
+// in base64url format ([RFC4648, section 5]), which can be decoded by
+// [DecodeAuthConfig].
+//
+// It must return an error if the privilege request fails.
+//
+// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5
+type RequestAuthConfig func(context.Context) (string, error)
+
+// AuthConfig contains authorization information for connecting to a Registry.
+type AuthConfig struct {
+	Username string `json:"username,omitempty"`
+	Password string `json:"password,omitempty"`
+	Auth     string `json:"auth,omitempty"`
+
+	ServerAddress string `json:"serveraddress,omitempty"`
+
+	// IdentityToken is used to authenticate the user and get
+	// an access token for the registry.
+	IdentityToken string `json:"identitytoken,omitempty"`
+
+	// RegistryToken is a bearer token to be sent to a registry
+	RegistryToken string `json:"registrytoken,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/registry/registry.go b/vendor/github.com/moby/moby/api/types/registry/registry.go
new file mode 100644
index 000000000..7361228d6
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/registry/registry.go
@@ -0,0 +1,67 @@
+package registry
+
+import (
+	"net/netip"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ServiceConfig stores daemon registry services configuration.
+type ServiceConfig struct {
+	InsecureRegistryCIDRs []netip.Prefix        `json:"InsecureRegistryCIDRs"`
+	IndexConfigs          map[string]*IndexInfo `json:"IndexConfigs"`
+	Mirrors               []string
+}
+
+// IndexInfo contains information about a registry
+//
+// RepositoryInfo Examples:
+//
+//	{
+//	  "Index" : {
+//	    "Name" : "docker.io",
+//	    "Mirrors" : ["https://registry-2.docker.io/v1/", "https://registry-3.docker.io/v1/"],
+//	    "Secure" : true,
+//	    "Official" : true,
+//	  },
+//	  "RemoteName" : "library/debian",
+//	  "LocalName" : "debian",
+//	  "CanonicalName" : "docker.io/debian"
+//	  "Official" : true,
+//	}
+//
+//	{
+//	  "Index" : {
+//	    "Name" : "127.0.0.1:5000",
+//	    "Mirrors" : [],
+//	    "Secure" : false,
+//	    "Official" : false,
+//	  },
+//	  "RemoteName" : "user/repo",
+//	  "LocalName" : "127.0.0.1:5000/user/repo",
+//	  "CanonicalName" : "127.0.0.1:5000/user/repo",
+//	  "Official" : false,
+//	}
+type IndexInfo struct {
+	// Name is the name of the registry, such as "docker.io"
+	Name string
+	// Mirrors is a list of mirrors, expressed as URIs
+	Mirrors []string
+	// Secure is set to false if the registry is part of the list of
+	// insecure registries. Insecure registries accept HTTP and/or accept
+	// HTTPS with certificates from unknown CAs.
+	Secure bool
+	// Official indicates whether this is an official registry
+	Official bool
+}
+
+// DistributionInspect describes the result obtained from contacting the
+// registry to retrieve image metadata
+type DistributionInspect struct {
+	// Descriptor contains information about the manifest, including
+	// the content addressable digest
+	Descriptor ocispec.Descriptor
+	// Platforms contains the list of platforms supported by the image,
+	// obtained by parsing the manifest
+	Platforms []ocispec.Platform
+}
diff --git a/vendor/github.com/moby/moby/api/types/registry/search.go b/vendor/github.com/moby/moby/api/types/registry/search.go
new file mode 100644
index 000000000..bd79462f6
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/registry/search.go
@@ -0,0 +1,27 @@
+package registry
+
+// SearchResult describes a search result returned from a registry
+type SearchResult struct {
+	// StarCount indicates the number of stars this repository has
+	StarCount int `json:"star_count"`
+	// IsOfficial is true if the result is from an official repository.
+	IsOfficial bool `json:"is_official"`
+	// Name is the name of the repository
+	Name string `json:"name"`
+	// IsAutomated indicates whether the result is automated.
+	//
+	// Deprecated: the "is_automated" field is deprecated and will always be "false".
+	IsAutomated bool `json:"is_automated"`
+	// Description is a textual description of the repository
+	Description string `json:"description"`
+}
+
+// SearchResults lists a collection search results returned from a registry
+type SearchResults struct {
+	// Query contains the query string that generated the search results
+	Query string `json:"query"`
+	// NumResults indicates the number of results the query returned
+	NumResults int `json:"num_results"`
+	// Results is a slice containing the actual results for the search
+	Results []SearchResult `json:"results"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/storage/driver_data.go b/vendor/github.com/moby/moby/api/types/storage/driver_data.go
new file mode 100644
index 000000000..65d5b4c20
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/storage/driver_data.go
@@ -0,0 +1,27 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package storage
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// DriverData Information about the storage driver used to store the container's and
+// image's filesystem.
+//
+// swagger:model DriverData
+type DriverData struct {
+
+	// Low-level storage metadata, provided as key/value pairs.
+	//
+	// This information is driver-specific, and depends on the storage-driver
+	// in use, and should be used for informational purposes only.
+	//
+	// Example: {"MergedDir":"/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/merged","UpperDir":"/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/diff","WorkDir":"/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/work"}
+	// Required: true
+	Data map[string]string `json:"Data"`
+
+	// Name of the storage driver.
+	// Example: overlay2
+	// Required: true
+	Name string `json:"Name"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage.go b/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage.go
new file mode 100644
index 000000000..d82f2b6bc
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage.go
@@ -0,0 +1,16 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package storage
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// RootFSStorage Information about the storage used for the container's root filesystem.
+//
+// swagger:model RootFSStorage
+type RootFSStorage struct {
+
+	// Information about the snapshot used for the container's root filesystem.
+	//
+	Snapshot *RootFSStorageSnapshot `json:"Snapshot,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage_snapshot.go b/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage_snapshot.go
new file mode 100644
index 000000000..dd2b82d24
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/storage/root_f_s_storage_snapshot.go
@@ -0,0 +1,15 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package storage
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// RootFSStorageSnapshot Information about a snapshot backend of the container's root filesystem.
+//
+// swagger:model RootFSStorageSnapshot
+type RootFSStorageSnapshot struct {
+
+	// Name of the snapshotter.
+	Name string `json:"Name,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/storage/storage.go b/vendor/github.com/moby/moby/api/types/storage/storage.go
new file mode 100644
index 000000000..77843db97
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/storage/storage.go
@@ -0,0 +1,16 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package storage
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Storage Information about the storage used by the container.
+//
+// swagger:model Storage
+type Storage struct {
+
+	// Information about the storage used for the container's root filesystem.
+	//
+	RootFS *RootFSStorage `json:"RootFS,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/common.go b/vendor/github.com/moby/moby/api/types/swarm/common.go
new file mode 100644
index 000000000..b42812e03
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/common.go
@@ -0,0 +1,48 @@
+package swarm
+
+import (
+	"strconv"
+	"time"
+)
+
+// Version represents the internal object version.
+type Version struct {
+	Index uint64 `json:",omitempty"`
+}
+
+// String implements fmt.Stringer interface.
+func (v Version) String() string {
+	return strconv.FormatUint(v.Index, 10)
+}
+
+// Meta is a base object inherited by most of the other once.
+type Meta struct {
+	Version   Version   `json:",omitempty"`
+	CreatedAt time.Time `json:",omitempty"`
+	UpdatedAt time.Time `json:",omitempty"`
+}
+
+// Annotations represents how to describe an object.
+type Annotations struct {
+	Name   string            `json:",omitempty"`
+	Labels map[string]string `json:"Labels"`
+}
+
+// Driver represents a driver (network, logging, secrets backend).
+type Driver struct {
+	Name    string            `json:",omitempty"`
+	Options map[string]string `json:",omitempty"`
+}
+
+// TLSInfo represents the TLS information about what CA certificate is trusted,
+// and who the issuer for a TLS certificate is
+type TLSInfo struct {
+	// TrustRoot is the trusted CA root certificate in PEM format
+	TrustRoot string `json:",omitempty"`
+
+	// CertIssuer is the raw subject bytes of the issuer
+	CertIssuerSubject []byte `json:",omitempty"`
+
+	// CertIssuerPublicKey is the raw public key bytes of the issuer
+	CertIssuerPublicKey []byte `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/config.go b/vendor/github.com/moby/moby/api/types/swarm/config.go
new file mode 100644
index 000000000..b029f2af8
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/config.go
@@ -0,0 +1,55 @@
+package swarm
+
+import (
+	"os"
+)
+
+// Config represents a config.
+type Config struct {
+	ID string
+	Meta
+	Spec ConfigSpec
+}
+
+// ConfigSpec represents a config specification from a config in swarm
+type ConfigSpec struct {
+	Annotations
+
+	// Data is the data to store as a config.
+	//
+	// The maximum allowed size is 1000KB, as defined in [MaxConfigSize].
+	//
+	// [MaxConfigSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/manager/controlapi#MaxConfigSize
+	Data []byte `json:",omitempty"`
+
+	// Templating controls whether and how to evaluate the config payload as
+	// a template. If it is not set, no templating is used.
+	Templating *Driver `json:",omitempty"`
+}
+
+// ConfigReferenceFileTarget is a file target in a config reference
+type ConfigReferenceFileTarget struct {
+	Name string
+	UID  string
+	GID  string
+	Mode os.FileMode
+}
+
+// ConfigReferenceRuntimeTarget is a target for a config specifying that it
+// isn't mounted into the container but instead has some other purpose.
+type ConfigReferenceRuntimeTarget struct{}
+
+// ConfigReference is a reference to a config in swarm
+type ConfigReference struct {
+	File       *ConfigReferenceFileTarget    `json:",omitempty"`
+	Runtime    *ConfigReferenceRuntimeTarget `json:",omitempty"`
+	ConfigID   string
+	ConfigName string
+}
+
+// ConfigCreateResponse contains the information returned to a client
+// on the creation of a new config.
+type ConfigCreateResponse struct {
+	// ID is the id of the created config.
+	ID string
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/container.go b/vendor/github.com/moby/moby/api/types/swarm/container.go
new file mode 100644
index 000000000..268565ec8
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/container.go
@@ -0,0 +1,120 @@
+package swarm
+
+import (
+	"net/netip"
+	"time"
+
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/mount"
+)
+
+// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf)
+// Detailed documentation is available in:
+// http://man7.org/linux/man-pages/man5/resolv.conf.5.html
+// `nameserver`, `search`, `options` have been supported.
+// TODO: `domain` is not supported yet.
+type DNSConfig struct {
+	// Nameservers specifies the IP addresses of the name servers
+	Nameservers []netip.Addr `json:",omitempty"`
+	// Search specifies the search list for host-name lookup
+	Search []string `json:",omitempty"`
+	// Options allows certain internal resolver variables to be modified
+	Options []string `json:",omitempty"`
+}
+
+// SELinuxContext contains the SELinux labels of the container.
+type SELinuxContext struct {
+	Disable bool
+
+	User  string
+	Role  string
+	Type  string
+	Level string
+}
+
+// SeccompMode is the type used for the enumeration of possible seccomp modes
+// in SeccompOpts
+type SeccompMode string
+
+const (
+	SeccompModeDefault    SeccompMode = "default"
+	SeccompModeUnconfined SeccompMode = "unconfined"
+	SeccompModeCustom     SeccompMode = "custom"
+)
+
+// SeccompOpts defines the options for configuring seccomp on a swarm-managed
+// container.
+type SeccompOpts struct {
+	// Mode is the SeccompMode used for the container.
+	Mode SeccompMode `json:",omitempty"`
+	// Profile is the custom seccomp profile as a json object to be used with
+	// the container. Mode should be set to SeccompModeCustom when using a
+	// custom profile in this manner.
+	Profile []byte `json:",omitempty"`
+}
+
+// AppArmorMode is type used for the enumeration of possible AppArmor modes in
+// AppArmorOpts
+type AppArmorMode string
+
+const (
+	AppArmorModeDefault  AppArmorMode = "default"
+	AppArmorModeDisabled AppArmorMode = "disabled"
+)
+
+// AppArmorOpts defines the options for configuring AppArmor on a swarm-managed
+// container.  Currently, custom AppArmor profiles are not supported.
+type AppArmorOpts struct {
+	Mode AppArmorMode `json:",omitempty"`
+}
+
+// CredentialSpec for managed service account (Windows only)
+type CredentialSpec struct {
+	Config   string
+	File     string
+	Registry string
+}
+
+// Privileges defines the security options for the container.
+type Privileges struct {
+	CredentialSpec  *CredentialSpec
+	SELinuxContext  *SELinuxContext
+	Seccomp         *SeccompOpts  `json:",omitempty"`
+	AppArmor        *AppArmorOpts `json:",omitempty"`
+	NoNewPrivileges bool
+}
+
+// ContainerSpec represents the spec of a container.
+type ContainerSpec struct {
+	Image           string                  `json:",omitempty"`
+	Labels          map[string]string       `json:",omitempty"`
+	Command         []string                `json:",omitempty"`
+	Args            []string                `json:",omitempty"`
+	Hostname        string                  `json:",omitempty"`
+	Env             []string                `json:",omitempty"`
+	Dir             string                  `json:",omitempty"`
+	User            string                  `json:",omitempty"`
+	Groups          []string                `json:",omitempty"`
+	Privileges      *Privileges             `json:",omitempty"`
+	Init            *bool                   `json:",omitempty"`
+	StopSignal      string                  `json:",omitempty"`
+	TTY             bool                    `json:",omitempty"`
+	OpenStdin       bool                    `json:",omitempty"`
+	ReadOnly        bool                    `json:",omitempty"`
+	Mounts          []mount.Mount           `json:",omitempty"`
+	StopGracePeriod *time.Duration          `json:",omitempty"`
+	Healthcheck     *container.HealthConfig `json:",omitempty"`
+	// The format of extra hosts on swarmkit is specified in:
+	// http://man7.org/linux/man-pages/man5/hosts.5.html
+	//    IP_address canonical_hostname [aliases...]
+	Hosts          []string            `json:",omitempty"`
+	DNSConfig      *DNSConfig          `json:",omitempty"`
+	Secrets        []*SecretReference  `json:",omitempty"`
+	Configs        []*ConfigReference  `json:",omitempty"`
+	Isolation      container.Isolation `json:",omitempty"`
+	Sysctls        map[string]string   `json:",omitempty"`
+	CapabilityAdd  []string            `json:",omitempty"`
+	CapabilityDrop []string            `json:",omitempty"`
+	Ulimits        []*container.Ulimit `json:",omitempty"`
+	OomScoreAdj    int64               `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/network.go b/vendor/github.com/moby/moby/api/types/swarm/network.go
new file mode 100644
index 000000000..b32c308f6
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/network.go
@@ -0,0 +1,139 @@
+package swarm
+
+import (
+	"cmp"
+	"net/netip"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+// Endpoint represents an endpoint.
+type Endpoint struct {
+	Spec       EndpointSpec        `json:",omitempty"`
+	Ports      []PortConfig        `json:",omitempty"`
+	VirtualIPs []EndpointVirtualIP `json:",omitempty"`
+}
+
+// EndpointSpec represents the spec of an endpoint.
+type EndpointSpec struct {
+	Mode  ResolutionMode `json:",omitempty"`
+	Ports []PortConfig   `json:",omitempty"`
+}
+
+// ResolutionMode represents a resolution mode.
+type ResolutionMode string
+
+const (
+	// ResolutionModeVIP VIP
+	ResolutionModeVIP ResolutionMode = "vip"
+	// ResolutionModeDNSRR DNSRR
+	ResolutionModeDNSRR ResolutionMode = "dnsrr"
+)
+
+// PortConfig represents the config of a port.
+type PortConfig struct {
+	Name     string             `json:",omitempty"`
+	Protocol network.IPProtocol `json:",omitempty"`
+	// TargetPort is the port inside the container
+	TargetPort uint32 `json:",omitempty"`
+	// PublishedPort is the port on the swarm hosts
+	PublishedPort uint32 `json:",omitempty"`
+	// PublishMode is the mode in which port is published
+	PublishMode PortConfigPublishMode `json:",omitempty"`
+}
+
+// Compare returns the lexical ordering of p and other, and can be used
+// with [slices.SortFunc].
+//
+// The comparison is performed in the following priority order:
+//  1. PublishedPort (host port)
+//  2. TargetPort (container port)
+//  3. Protocol
+//  4. PublishMode
+func (p PortConfig) Compare(other PortConfig) int {
+	if n := cmp.Compare(p.PublishedPort, other.PublishedPort); n != 0 {
+		return n
+	}
+	if n := cmp.Compare(p.TargetPort, other.TargetPort); n != 0 {
+		return n
+	}
+	if n := cmp.Compare(p.Protocol, other.Protocol); n != 0 {
+		return n
+	}
+	return cmp.Compare(p.PublishMode, other.PublishMode)
+}
+
+// PortConfigPublishMode represents the mode in which the port is to
+// be published.
+type PortConfigPublishMode string
+
+const (
+	// PortConfigPublishModeIngress is used for ports published
+	// for ingress load balancing using routing mesh.
+	PortConfigPublishModeIngress PortConfigPublishMode = "ingress"
+	// PortConfigPublishModeHost is used for ports published
+	// for direct host level access on the host where the task is running.
+	PortConfigPublishModeHost PortConfigPublishMode = "host"
+)
+
+// EndpointVirtualIP represents the virtual ip of a port.
+type EndpointVirtualIP struct {
+	NetworkID string `json:",omitempty"`
+
+	// Addr is the virtual ip address.
+	// This field accepts CIDR notation, for example `10.0.0.1/24`, to maintain backwards
+	// compatibility, but only the IP address is used.
+	Addr netip.Prefix `json:"Addr,omitzero"`
+}
+
+// Network represents a network.
+type Network struct {
+	ID string
+	Meta
+	Spec        NetworkSpec  `json:",omitempty"`
+	DriverState Driver       `json:",omitempty"`
+	IPAMOptions *IPAMOptions `json:",omitempty"`
+}
+
+// NetworkSpec represents the spec of a network.
+type NetworkSpec struct {
+	Annotations
+	DriverConfiguration *Driver                  `json:",omitempty"`
+	IPv6Enabled         bool                     `json:",omitempty"`
+	Internal            bool                     `json:",omitempty"`
+	Attachable          bool                     `json:",omitempty"`
+	Ingress             bool                     `json:",omitempty"`
+	IPAMOptions         *IPAMOptions             `json:",omitempty"`
+	ConfigFrom          *network.ConfigReference `json:",omitempty"`
+	Scope               string                   `json:",omitempty"`
+}
+
+// NetworkAttachmentConfig represents the configuration of a network attachment.
+type NetworkAttachmentConfig struct {
+	Target     string            `json:",omitempty"`
+	Aliases    []string          `json:",omitempty"`
+	DriverOpts map[string]string `json:",omitempty"`
+}
+
+// NetworkAttachment represents a network attachment.
+type NetworkAttachment struct {
+	Network Network `json:",omitempty"`
+
+	// Addresses contains the IP addresses associated with the endpoint in the network.
+	// This field accepts CIDR notation, for example `10.0.0.1/24`, to maintain backwards
+	// compatibility, but only the IP address is used.
+	Addresses []netip.Prefix `json:",omitempty"`
+}
+
+// IPAMOptions represents ipam options.
+type IPAMOptions struct {
+	Driver  Driver       `json:",omitempty"`
+	Configs []IPAMConfig `json:",omitempty"`
+}
+
+// IPAMConfig represents ipam configuration.
+type IPAMConfig struct {
+	Subnet  netip.Prefix `json:"Subnet,omitzero"`
+	Range   netip.Prefix `json:"Range,omitzero"`
+	Gateway netip.Addr   `json:"Gateway,omitzero"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/node.go b/vendor/github.com/moby/moby/api/types/swarm/node.go
new file mode 100644
index 000000000..9523799b6
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/node.go
@@ -0,0 +1,139 @@
+package swarm
+
+// Node represents a node.
+type Node struct {
+	ID string
+	Meta
+	// Spec defines the desired state of the node as specified by the user.
+	// The system will honor this and will *never* modify it.
+	Spec NodeSpec `json:",omitempty"`
+	// Description encapsulates the properties of the Node as reported by the
+	// agent.
+	Description NodeDescription `json:",omitempty"`
+	// Status provides the current status of the node, as seen by the manager.
+	Status NodeStatus `json:",omitempty"`
+	// ManagerStatus provides the current status of the node's manager
+	// component, if the node is a manager.
+	ManagerStatus *ManagerStatus `json:",omitempty"`
+}
+
+// NodeSpec represents the spec of a node.
+type NodeSpec struct {
+	Annotations
+	Role         NodeRole         `json:",omitempty"`
+	Availability NodeAvailability `json:",omitempty"`
+}
+
+// NodeRole represents the role of a node.
+type NodeRole string
+
+const (
+	// NodeRoleWorker WORKER
+	NodeRoleWorker NodeRole = "worker"
+	// NodeRoleManager MANAGER
+	NodeRoleManager NodeRole = "manager"
+)
+
+// NodeAvailability represents the availability of a node.
+type NodeAvailability string
+
+const (
+	// NodeAvailabilityActive ACTIVE
+	NodeAvailabilityActive NodeAvailability = "active"
+	// NodeAvailabilityPause PAUSE
+	NodeAvailabilityPause NodeAvailability = "pause"
+	// NodeAvailabilityDrain DRAIN
+	NodeAvailabilityDrain NodeAvailability = "drain"
+)
+
+// NodeDescription represents the description of a node.
+type NodeDescription struct {
+	Hostname  string            `json:",omitempty"`
+	Platform  Platform          `json:",omitempty"`
+	Resources Resources         `json:",omitempty"`
+	Engine    EngineDescription `json:",omitempty"`
+	TLSInfo   TLSInfo           `json:",omitempty"`
+	CSIInfo   []NodeCSIInfo     `json:",omitempty"`
+}
+
+// Platform represents the platform (Arch/OS).
+type Platform struct {
+	Architecture string `json:",omitempty"`
+	OS           string `json:",omitempty"`
+}
+
+// EngineDescription represents the description of an engine.
+type EngineDescription struct {
+	EngineVersion string              `json:",omitempty"`
+	Labels        map[string]string   `json:",omitempty"`
+	Plugins       []PluginDescription `json:",omitempty"`
+}
+
+// NodeCSIInfo represents information about a CSI plugin available on the node
+type NodeCSIInfo struct {
+	// PluginName is the name of the CSI plugin.
+	PluginName string `json:",omitempty"`
+	// NodeID is the ID of the node as reported by the CSI plugin. This is
+	// different from the swarm node ID.
+	NodeID string `json:",omitempty"`
+	// MaxVolumesPerNode is the maximum number of volumes that may be published
+	// to this node
+	MaxVolumesPerNode int64 `json:",omitempty"`
+	// AccessibleTopology indicates the location of this node in the CSI
+	// plugin's topology
+	AccessibleTopology *Topology `json:",omitempty"`
+}
+
+// PluginDescription represents the description of an engine plugin.
+type PluginDescription struct {
+	Type string `json:",omitempty"`
+	Name string `json:",omitempty"`
+}
+
+// NodeStatus represents the status of a node.
+type NodeStatus struct {
+	State   NodeState `json:",omitempty"`
+	Message string    `json:",omitempty"`
+	Addr    string    `json:",omitempty"`
+}
+
+// Reachability represents the reachability of a node.
+type Reachability string
+
+const (
+	// ReachabilityUnknown UNKNOWN
+	ReachabilityUnknown Reachability = "unknown"
+	// ReachabilityUnreachable UNREACHABLE
+	ReachabilityUnreachable Reachability = "unreachable"
+	// ReachabilityReachable REACHABLE
+	ReachabilityReachable Reachability = "reachable"
+)
+
+// ManagerStatus represents the status of a manager.
+type ManagerStatus struct {
+	Leader       bool         `json:",omitempty"`
+	Reachability Reachability `json:",omitempty"`
+	Addr         string       `json:",omitempty"`
+}
+
+// NodeState represents the state of a node.
+type NodeState string
+
+const (
+	// NodeStateUnknown UNKNOWN
+	NodeStateUnknown NodeState = "unknown"
+	// NodeStateDown DOWN
+	NodeStateDown NodeState = "down"
+	// NodeStateReady READY
+	NodeStateReady NodeState = "ready"
+	// NodeStateDisconnected DISCONNECTED
+	NodeStateDisconnected NodeState = "disconnected"
+)
+
+// Topology defines the CSI topology of this node. This type is a duplicate of
+// [github.com/moby/moby/api/types/volume.Topology]. Because the type definition
+// is so simple and to avoid complicated structure or circular imports, we just
+// duplicate it here. See that type for full documentation
+type Topology struct {
+	Segments map[string]string `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/runtime.go b/vendor/github.com/moby/moby/api/types/swarm/runtime.go
new file mode 100644
index 000000000..23ea712c4
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/runtime.go
@@ -0,0 +1,45 @@
+package swarm
+
+// RuntimeType is the type of runtime used for the TaskSpec
+type RuntimeType string
+
+// RuntimeURL is the proto type url
+type RuntimeURL string
+
+const (
+	// RuntimeContainer is the container based runtime
+	RuntimeContainer RuntimeType = "container"
+	// RuntimePlugin is the plugin based runtime
+	RuntimePlugin RuntimeType = "plugin"
+	// RuntimeNetworkAttachment is the network attachment runtime
+	RuntimeNetworkAttachment RuntimeType = "attachment"
+
+	// RuntimeURLContainer is the proto url for the container type
+	RuntimeURLContainer RuntimeURL = "types.docker.com/RuntimeContainer"
+	// RuntimeURLPlugin is the proto url for the plugin type
+	RuntimeURLPlugin RuntimeURL = "types.docker.com/RuntimePlugin"
+)
+
+// NetworkAttachmentSpec represents the runtime spec type for network
+// attachment tasks
+type NetworkAttachmentSpec struct {
+	ContainerID string
+}
+
+// RuntimeSpec defines the base payload which clients can specify for creating
+// a service with the plugin runtime.
+type RuntimeSpec struct {
+	Name       string              `json:"name,omitempty"`
+	Remote     string              `json:"remote,omitempty"`
+	Privileges []*RuntimePrivilege `json:"privileges,omitempty"`
+	Disabled   bool                `json:"disabled,omitempty"`
+	Env        []string            `json:"env,omitempty"`
+}
+
+// RuntimePrivilege describes a permission the user has to accept
+// upon installing a plugin.
+type RuntimePrivilege struct {
+	Name        string   `json:"name,omitempty"`
+	Description string   `json:"description,omitempty"`
+	Value       []string `json:"value,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/secret.go b/vendor/github.com/moby/moby/api/types/swarm/secret.go
new file mode 100644
index 000000000..0e27ed9b0
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/secret.go
@@ -0,0 +1,59 @@
+package swarm
+
+import (
+	"os"
+)
+
+// Secret represents a secret.
+type Secret struct {
+	ID string
+	Meta
+	Spec SecretSpec
+}
+
+// SecretSpec represents a secret specification from a secret in swarm
+type SecretSpec struct {
+	Annotations
+
+	// Data is the data to store as a secret. It must be empty if a
+	// [Driver] is used, in which case the data is loaded from an external
+	// secret store. The maximum allowed size is 500KB, as defined in
+	// [MaxSecretSize].
+	//
+	// This field is only used to create the secret, and is not returned
+	// by other endpoints.
+	//
+	// [MaxSecretSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0/api/validation#MaxSecretSize
+	Data []byte `json:",omitempty"`
+
+	// Driver is the name of the secrets driver used to fetch the secret's
+	// value from an external secret store. If not set, the default built-in
+	// store is used.
+	Driver *Driver `json:",omitempty"`
+
+	// Templating controls whether and how to evaluate the secret payload as
+	// a template. If it is not set, no templating is used.
+	Templating *Driver `json:",omitempty"`
+}
+
+// SecretReferenceFileTarget is a file target in a secret reference
+type SecretReferenceFileTarget struct {
+	Name string
+	UID  string
+	GID  string
+	Mode os.FileMode
+}
+
+// SecretReference is a reference to a secret in swarm
+type SecretReference struct {
+	File       *SecretReferenceFileTarget
+	SecretID   string
+	SecretName string
+}
+
+// SecretCreateResponse contains the information returned to a client
+// on the creation of a new secret.
+type SecretCreateResponse struct {
+	// ID is the id of the created secret.
+	ID string
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/service.go b/vendor/github.com/moby/moby/api/types/swarm/service.go
new file mode 100644
index 000000000..0b678dea3
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/service.go
@@ -0,0 +1,218 @@
+package swarm
+
+import (
+	"time"
+)
+
+// Service represents a service.
+type Service struct {
+	ID string
+	Meta
+	Spec         ServiceSpec   `json:",omitempty"`
+	PreviousSpec *ServiceSpec  `json:",omitempty"`
+	Endpoint     Endpoint      `json:",omitempty"`
+	UpdateStatus *UpdateStatus `json:",omitempty"`
+
+	// ServiceStatus is an optional, extra field indicating the number of
+	// desired and running tasks. It is provided primarily as a shortcut to
+	// calculating these values client-side, which otherwise would require
+	// listing all tasks for a service, an operation that could be
+	// computation and network expensive.
+	ServiceStatus *ServiceStatus `json:",omitempty"`
+
+	// JobStatus is the status of a Service which is in one of ReplicatedJob or
+	// GlobalJob modes. It is absent on Replicated and Global services.
+	JobStatus *JobStatus `json:",omitempty"`
+}
+
+// ServiceSpec represents the spec of a service.
+type ServiceSpec struct {
+	Annotations
+
+	// TaskTemplate defines how the service should construct new tasks when
+	// orchestrating this service.
+	TaskTemplate   TaskSpec      `json:",omitempty"`
+	Mode           ServiceMode   `json:",omitempty"`
+	UpdateConfig   *UpdateConfig `json:",omitempty"`
+	RollbackConfig *UpdateConfig `json:",omitempty"`
+	EndpointSpec   *EndpointSpec `json:",omitempty"`
+}
+
+// ServiceMode represents the mode of a service.
+type ServiceMode struct {
+	Replicated    *ReplicatedService `json:",omitempty"`
+	Global        *GlobalService     `json:",omitempty"`
+	ReplicatedJob *ReplicatedJob     `json:",omitempty"`
+	GlobalJob     *GlobalJob         `json:",omitempty"`
+}
+
+// UpdateState is the state of a service update.
+type UpdateState string
+
+const (
+	// UpdateStateUpdating is the updating state.
+	UpdateStateUpdating UpdateState = "updating"
+	// UpdateStatePaused is the paused state.
+	UpdateStatePaused UpdateState = "paused"
+	// UpdateStateCompleted is the completed state.
+	UpdateStateCompleted UpdateState = "completed"
+	// UpdateStateRollbackStarted is the state with a rollback in progress.
+	UpdateStateRollbackStarted UpdateState = "rollback_started"
+	// UpdateStateRollbackPaused is the state with a rollback in progress.
+	UpdateStateRollbackPaused UpdateState = "rollback_paused"
+	// UpdateStateRollbackCompleted is the state with a rollback in progress.
+	UpdateStateRollbackCompleted UpdateState = "rollback_completed"
+)
+
+// UpdateStatus reports the status of a service update.
+type UpdateStatus struct {
+	State       UpdateState `json:",omitempty"`
+	StartedAt   *time.Time  `json:",omitempty"`
+	CompletedAt *time.Time  `json:",omitempty"`
+	Message     string      `json:",omitempty"`
+}
+
+// ReplicatedService is a kind of ServiceMode.
+type ReplicatedService struct {
+	Replicas *uint64 `json:",omitempty"`
+}
+
+// GlobalService is a kind of ServiceMode.
+type GlobalService struct{}
+
+// ReplicatedJob is the a type of Service which executes a defined Tasks
+// in parallel until the specified number of Tasks have succeeded.
+type ReplicatedJob struct {
+	// MaxConcurrent indicates the maximum number of Tasks that should be
+	// executing simultaneously for this job at any given time. There may be
+	// fewer Tasks that MaxConcurrent executing simultaneously; for example, if
+	// there are fewer than MaxConcurrent tasks needed to reach
+	// TotalCompletions.
+	//
+	// If this field is empty, it will default to a max concurrency of 1.
+	MaxConcurrent *uint64 `json:",omitempty"`
+
+	// TotalCompletions is the total number of Tasks desired to run to
+	// completion.
+	//
+	// If this field is empty, the value of MaxConcurrent will be used.
+	TotalCompletions *uint64 `json:",omitempty"`
+}
+
+// GlobalJob is the type of a Service which executes a Task on every Node
+// matching the Service's placement constraints. These tasks run to completion
+// and then exit.
+//
+// This type is deliberately empty.
+type GlobalJob struct{}
+
+// FailureAction is the action to perform when updating a service fails.
+type FailureAction string
+
+const (
+	// UpdateFailureActionPause PAUSE
+	UpdateFailureActionPause FailureAction = "pause"
+	// UpdateFailureActionContinue CONTINUE
+	UpdateFailureActionContinue FailureAction = "continue"
+	// UpdateFailureActionRollback ROLLBACK
+	UpdateFailureActionRollback FailureAction = "rollback"
+)
+
+// UpdateOrder is the order of operations when rolling out or rolling back
+// an updated tasks for a service.
+type UpdateOrder string
+
+const (
+	// UpdateOrderStopFirst STOP_FIRST
+	UpdateOrderStopFirst UpdateOrder = "stop-first"
+	// UpdateOrderStartFirst START_FIRST
+	UpdateOrderStartFirst UpdateOrder = "start-first"
+)
+
+// UpdateConfig represents the update configuration.
+type UpdateConfig struct {
+	// Maximum number of tasks to be updated in one iteration.
+	// 0 means unlimited parallelism.
+	Parallelism uint64
+
+	// Amount of time between updates.
+	Delay time.Duration `json:",omitempty"`
+
+	// FailureAction is the action to take when an update failures.
+	FailureAction FailureAction `json:",omitempty"`
+
+	// Monitor indicates how long to monitor a task for failure after it is
+	// created. If the task fails by ending up in one of the states
+	// REJECTED, COMPLETED, or FAILED, within Monitor from its creation,
+	// this counts as a failure. If it fails after Monitor, it does not
+	// count as a failure. If Monitor is unspecified, a default value will
+	// be used.
+	Monitor time.Duration `json:",omitempty"`
+
+	// MaxFailureRatio is the fraction of tasks that may fail during
+	// an update before the failure action is invoked. Any task created by
+	// the current update which ends up in one of the states REJECTED,
+	// COMPLETED or FAILED within Monitor from its creation counts as a
+	// failure. The number of failures is divided by the number of tasks
+	// being updated, and if this fraction is greater than
+	// MaxFailureRatio, the failure action is invoked.
+	//
+	// If the failure action is CONTINUE, there is no effect.
+	// If the failure action is PAUSE, no more tasks will be updated until
+	// another update is started.
+	MaxFailureRatio float32
+
+	// Order indicates the order of operations when rolling out an updated
+	// task. Either the old task is shut down before the new task is
+	// started, or the new task is started before the old task is shut down.
+	Order UpdateOrder
+}
+
+// ServiceStatus represents the number of running tasks in a service and the
+// number of tasks desired to be running.
+type ServiceStatus struct {
+	// RunningTasks is the number of tasks for the service actually in the
+	// Running state
+	RunningTasks uint64
+
+	// DesiredTasks is the number of tasks desired to be running by the
+	// service. For replicated services, this is the replica count. For global
+	// services, this is computed by taking the number of tasks with desired
+	// state of not-Shutdown.
+	DesiredTasks uint64
+
+	// CompletedTasks is the number of tasks in the state Completed, if this
+	// service is in ReplicatedJob or GlobalJob mode. This field must be
+	// cross-referenced with the service type, because the default value of 0
+	// may mean that a service is not in a job mode, or it may mean that the
+	// job has yet to complete any tasks.
+	CompletedTasks uint64
+}
+
+// JobStatus is the status of a job-type service.
+type JobStatus struct {
+	// JobIteration is a value increased each time a Job is executed,
+	// successfully or otherwise. "Executed", in this case, means the job as a
+	// whole has been started, not that an individual Task has been launched. A
+	// job is "Executed" when its ServiceSpec is updated. JobIteration can be
+	// used to disambiguate Tasks belonging to different executions of a job.
+	//
+	// Though JobIteration will increase with each subsequent execution, it may
+	// not necessarily increase by 1, and so JobIteration should not be used to
+	// keep track of the number of times a job has been executed.
+	JobIteration Version
+
+	// LastExecution is the time that the job was last executed, as observed by
+	// Swarm manager.
+	LastExecution time.Time `json:",omitempty"`
+}
+
+// RegistryAuthSource defines options for the "registryAuthFrom" query parameter
+// on service update.
+type RegistryAuthSource string
+
+// Values for RegistryAuthFrom in ServiceUpdateOptions
+const (
+	RegistryAuthFromSpec         RegistryAuthSource = "spec"
+	RegistryAuthFromPreviousSpec RegistryAuthSource = "previous-spec"
+)
diff --git a/vendor/github.com/moby/moby/api/types/swarm/service_create_response.go b/vendor/github.com/moby/moby/api/types/swarm/service_create_response.go
new file mode 100644
index 000000000..ebbc097d9
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/service_create_response.go
@@ -0,0 +1,24 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package swarm
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// ServiceCreateResponse contains the information returned to a client on the
+// creation of a new service.
+//
+// swagger:model ServiceCreateResponse
+type ServiceCreateResponse struct {
+
+	// The ID of the created service.
+	// Example: ak7w3gjqoa3kuz8xcpnyy0pvl
+	ID string `json:"ID,omitempty"`
+
+	// Optional warning message.
+	//
+	// FIXME(thaJeztah): this should have "omitempty" in the generated type.
+	//
+	// Example: ["unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"]
+	Warnings []string `json:"Warnings"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/service_update_response.go b/vendor/github.com/moby/moby/api/types/swarm/service_update_response.go
new file mode 100644
index 000000000..b7649096a
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/service_update_response.go
@@ -0,0 +1,16 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package swarm
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// ServiceUpdateResponse service update response
+// Example: {"Warnings":["unable to pin image doesnotexist:latest to digest: image library/doesnotexist:latest not found"]}
+//
+// swagger:model ServiceUpdateResponse
+type ServiceUpdateResponse struct {
+
+	// Optional warning messages
+	Warnings []string `json:"Warnings"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/swarm.go b/vendor/github.com/moby/moby/api/types/swarm/swarm.go
new file mode 100644
index 000000000..842185031
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/swarm.go
@@ -0,0 +1,228 @@
+package swarm
+
+import (
+	"net/netip"
+	"time"
+)
+
+// ClusterInfo represents info about the cluster for outputting in "info"
+// it contains the same information as "Swarm", but without the JoinTokens
+type ClusterInfo struct {
+	ID string
+	Meta
+	Spec                   Spec
+	TLSInfo                TLSInfo
+	RootRotationInProgress bool
+	DefaultAddrPool        []netip.Prefix
+	SubnetSize             uint32
+	DataPathPort           uint32
+}
+
+// Swarm represents a swarm.
+type Swarm struct {
+	ClusterInfo
+	JoinTokens JoinTokens
+}
+
+// JoinTokens contains the tokens workers and managers need to join the swarm.
+type JoinTokens struct {
+	// Worker is the join token workers may use to join the swarm.
+	Worker string
+	// Manager is the join token managers may use to join the swarm.
+	Manager string
+}
+
+// Spec represents the spec of a swarm.
+type Spec struct {
+	Annotations
+
+	Orchestration    OrchestrationConfig `json:",omitempty"`
+	Raft             RaftConfig          `json:",omitempty"`
+	Dispatcher       DispatcherConfig    `json:",omitempty"`
+	CAConfig         CAConfig            `json:",omitempty"`
+	TaskDefaults     TaskDefaults        `json:",omitempty"`
+	EncryptionConfig EncryptionConfig    `json:",omitempty"`
+}
+
+// OrchestrationConfig represents orchestration configuration.
+type OrchestrationConfig struct {
+	// TaskHistoryRetentionLimit is the number of historic tasks to keep per instance or
+	// node. If negative, never remove completed or failed tasks.
+	TaskHistoryRetentionLimit *int64 `json:",omitempty"`
+}
+
+// TaskDefaults parameterizes cluster-level task creation with default values.
+type TaskDefaults struct {
+	// LogDriver selects the log driver to use for tasks created in the
+	// orchestrator if unspecified by a service.
+	//
+	// Updating this value will only have an affect on new tasks. Old tasks
+	// will continue use their previously configured log driver until
+	// recreated.
+	LogDriver *Driver `json:",omitempty"`
+}
+
+// EncryptionConfig controls at-rest encryption of data and keys.
+type EncryptionConfig struct {
+	// AutoLockManagers specifies whether or not managers TLS keys and raft data
+	// should be encrypted at rest in such a way that they must be unlocked
+	// before the manager node starts up again.
+	AutoLockManagers bool
+}
+
+// RaftConfig represents raft configuration.
+type RaftConfig struct {
+	// SnapshotInterval is the number of log entries between snapshots.
+	SnapshotInterval uint64 `json:",omitempty"`
+
+	// KeepOldSnapshots is the number of snapshots to keep beyond the
+	// current snapshot.
+	KeepOldSnapshots *uint64 `json:",omitempty"`
+
+	// LogEntriesForSlowFollowers is the number of log entries to keep
+	// around to sync up slow followers after a snapshot is created.
+	LogEntriesForSlowFollowers uint64 `json:",omitempty"`
+
+	// ElectionTick is the number of ticks that a follower will wait for a message
+	// from the leader before becoming a candidate and starting an election.
+	// ElectionTick must be greater than HeartbeatTick.
+	//
+	// A tick currently defaults to one second, so these translate directly to
+	// seconds currently, but this is NOT guaranteed.
+	ElectionTick int
+
+	// HeartbeatTick is the number of ticks between heartbeats. Every
+	// HeartbeatTick ticks, the leader will send a heartbeat to the
+	// followers.
+	//
+	// A tick currently defaults to one second, so these translate directly to
+	// seconds currently, but this is NOT guaranteed.
+	HeartbeatTick int
+}
+
+// DispatcherConfig represents dispatcher configuration.
+type DispatcherConfig struct {
+	// HeartbeatPeriod defines how often agent should send heartbeats to
+	// dispatcher.
+	HeartbeatPeriod time.Duration `json:",omitempty"`
+}
+
+// CAConfig represents CA configuration.
+type CAConfig struct {
+	// NodeCertExpiry is the duration certificates should be issued for
+	NodeCertExpiry time.Duration `json:",omitempty"`
+
+	// ExternalCAs is a list of CAs to which a manager node will make
+	// certificate signing requests for node certificates.
+	ExternalCAs []*ExternalCA `json:",omitempty"`
+
+	// SigningCACert and SigningCAKey specify the desired signing root CA and
+	// root CA key for the swarm.  When inspecting the cluster, the key will
+	// be redacted.
+	SigningCACert string `json:",omitempty"`
+	SigningCAKey  string `json:",omitempty"`
+
+	// If this value changes, and there is no specified signing cert and key,
+	// then the swarm is forced to generate a new root certificate and key.
+	ForceRotate uint64 `json:",omitempty"`
+}
+
+// ExternalCAProtocol represents type of external CA.
+type ExternalCAProtocol string
+
+// ExternalCAProtocolCFSSL CFSSL
+const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl"
+
+// ExternalCA defines external CA to be used by the cluster.
+type ExternalCA struct {
+	// Protocol is the protocol used by this external CA.
+	Protocol ExternalCAProtocol
+
+	// URL is the URL where the external CA can be reached.
+	URL string
+
+	// Options is a set of additional key/value pairs whose interpretation
+	// depends on the specified CA type.
+	Options map[string]string `json:",omitempty"`
+
+	// CACert specifies which root CA is used by this external CA.  This certificate must
+	// be in PEM format.
+	CACert string
+}
+
+// InitRequest is the request used to init a swarm.
+type InitRequest struct {
+	ListenAddr       string
+	AdvertiseAddr    string
+	DataPathAddr     string
+	DataPathPort     uint32
+	ForceNewCluster  bool
+	Spec             Spec
+	AutoLockManagers bool
+	Availability     NodeAvailability
+	DefaultAddrPool  []netip.Prefix
+	SubnetSize       uint32
+}
+
+// JoinRequest is the request used to join a swarm.
+type JoinRequest struct {
+	ListenAddr    string
+	AdvertiseAddr string
+	DataPathAddr  string
+	RemoteAddrs   []string
+	JoinToken     string // accept by secret
+	Availability  NodeAvailability
+}
+
+// UnlockRequest is the request used to unlock a swarm.
+type UnlockRequest struct {
+	// UnlockKey is the unlock key in ASCII-armored format.
+	UnlockKey string
+}
+
+// LocalNodeState represents the state of the local node.
+type LocalNodeState string
+
+const (
+	// LocalNodeStateInactive INACTIVE
+	LocalNodeStateInactive LocalNodeState = "inactive"
+	// LocalNodeStatePending PENDING
+	LocalNodeStatePending LocalNodeState = "pending"
+	// LocalNodeStateActive ACTIVE
+	LocalNodeStateActive LocalNodeState = "active"
+	// LocalNodeStateError ERROR
+	LocalNodeStateError LocalNodeState = "error"
+	// LocalNodeStateLocked LOCKED
+	LocalNodeStateLocked LocalNodeState = "locked"
+)
+
+// Info represents generic information about swarm.
+type Info struct {
+	NodeID   string
+	NodeAddr string
+
+	LocalNodeState   LocalNodeState
+	ControlAvailable bool
+	Error            string
+
+	RemoteManagers []Peer
+	Nodes          int `json:",omitempty"`
+	Managers       int `json:",omitempty"`
+
+	Cluster *ClusterInfo `json:",omitempty"`
+
+	Warnings []string `json:",omitempty"`
+}
+
+// Peer represents a peer.
+type Peer struct {
+	NodeID string
+	Addr   string
+}
+
+// UnlockKeyResponse contains the response for Engine API:
+// GET /swarm/unlockkey
+type UnlockKeyResponse struct {
+	// UnlockKey is the unlock key in ASCII-armored format.
+	UnlockKey string
+}
diff --git a/vendor/github.com/moby/moby/api/types/swarm/task.go b/vendor/github.com/moby/moby/api/types/swarm/task.go
new file mode 100644
index 000000000..e2633037d
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/swarm/task.go
@@ -0,0 +1,234 @@
+package swarm
+
+import (
+	"time"
+)
+
+// TaskState represents the state of a task.
+type TaskState string
+
+const (
+	// TaskStateNew NEW
+	TaskStateNew TaskState = "new"
+	// TaskStateAllocated ALLOCATED
+	TaskStateAllocated TaskState = "allocated"
+	// TaskStatePending PENDING
+	TaskStatePending TaskState = "pending"
+	// TaskStateAssigned ASSIGNED
+	TaskStateAssigned TaskState = "assigned"
+	// TaskStateAccepted ACCEPTED
+	TaskStateAccepted TaskState = "accepted"
+	// TaskStatePreparing PREPARING
+	TaskStatePreparing TaskState = "preparing"
+	// TaskStateReady READY
+	TaskStateReady TaskState = "ready"
+	// TaskStateStarting STARTING
+	TaskStateStarting TaskState = "starting"
+	// TaskStateRunning RUNNING
+	TaskStateRunning TaskState = "running"
+	// TaskStateComplete COMPLETE
+	TaskStateComplete TaskState = "complete"
+	// TaskStateShutdown SHUTDOWN
+	TaskStateShutdown TaskState = "shutdown"
+	// TaskStateFailed FAILED
+	TaskStateFailed TaskState = "failed"
+	// TaskStateRejected REJECTED
+	TaskStateRejected TaskState = "rejected"
+	// TaskStateRemove REMOVE
+	TaskStateRemove TaskState = "remove"
+	// TaskStateOrphaned ORPHANED
+	TaskStateOrphaned TaskState = "orphaned"
+)
+
+// Task represents a task.
+type Task struct {
+	ID string
+	Meta
+	Annotations
+
+	Spec                TaskSpec            `json:",omitempty"`
+	ServiceID           string              `json:",omitempty"`
+	Slot                int                 `json:",omitempty"`
+	NodeID              string              `json:",omitempty"`
+	Status              TaskStatus          `json:",omitempty"`
+	DesiredState        TaskState           `json:",omitempty"`
+	NetworksAttachments []NetworkAttachment `json:",omitempty"`
+	GenericResources    []GenericResource   `json:",omitempty"`
+
+	// JobIteration is the JobIteration of the Service that this Task was
+	// spawned from, if the Service is a ReplicatedJob or GlobalJob. This is
+	// used to determine which Tasks belong to which run of the job. This field
+	// is absent if the Service mode is Replicated or Global.
+	JobIteration *Version `json:",omitempty"`
+
+	// Volumes is the list of VolumeAttachments for this task. It specifies
+	// which particular volumes are to be used by this particular task, and
+	// fulfilling what mounts in the spec.
+	Volumes []VolumeAttachment
+}
+
+// TaskSpec represents the spec of a task.
+type TaskSpec struct {
+	// ContainerSpec, NetworkAttachmentSpec, and PluginSpec are mutually exclusive.
+	// PluginSpec is only used when the `Runtime` field is set to `plugin`
+	// NetworkAttachmentSpec is used if the `Runtime` field is set to
+	// `attachment`.
+	ContainerSpec         *ContainerSpec         `json:",omitempty"`
+	PluginSpec            *RuntimeSpec           `json:",omitempty"`
+	NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"`
+
+	Resources     *ResourceRequirements     `json:",omitempty"`
+	RestartPolicy *RestartPolicy            `json:",omitempty"`
+	Placement     *Placement                `json:",omitempty"`
+	Networks      []NetworkAttachmentConfig `json:",omitempty"`
+
+	// LogDriver specifies the LogDriver to use for tasks created from this
+	// spec. If not present, the one on cluster default on swarm.Spec will be
+	// used, finally falling back to the engine default if not specified.
+	LogDriver *Driver `json:",omitempty"`
+
+	// ForceUpdate is a counter that triggers an update even if no relevant
+	// parameters have been changed.
+	ForceUpdate uint64
+
+	Runtime RuntimeType `json:",omitempty"`
+}
+
+// Resources represents resources (CPU/Memory) which can be advertised by a
+// node and requested to be reserved for a task.
+type Resources struct {
+	NanoCPUs         int64             `json:",omitempty"`
+	MemoryBytes      int64             `json:",omitempty"`
+	GenericResources []GenericResource `json:",omitempty"`
+}
+
+// Limit describes limits on resources which can be requested by a task.
+type Limit struct {
+	NanoCPUs    int64 `json:",omitempty"`
+	MemoryBytes int64 `json:",omitempty"`
+	Pids        int64 `json:",omitempty"`
+}
+
+// GenericResource represents a "user-defined" resource which can
+// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1)
+type GenericResource struct {
+	NamedResourceSpec    *NamedGenericResource    `json:",omitempty"`
+	DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"`
+}
+
+// NamedGenericResource represents a "user-defined" resource which is defined
+// as a string.
+// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
+// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...)
+type NamedGenericResource struct {
+	Kind  string `json:",omitempty"`
+	Value string `json:",omitempty"`
+}
+
+// DiscreteGenericResource represents a "user-defined" resource which is defined
+// as an integer
+// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
+// Value is used to count the resource (SSD=5, HDD=3, ...)
+type DiscreteGenericResource struct {
+	Kind  string `json:",omitempty"`
+	Value int64  `json:",omitempty"`
+}
+
+// ResourceRequirements represents resources requirements.
+type ResourceRequirements struct {
+	Limits       *Limit     `json:",omitempty"`
+	Reservations *Resources `json:",omitempty"`
+
+	// Amount of swap in bytes - can only be used together with a memory limit
+	// -1 means unlimited
+	// a null pointer keeps the default behaviour of granting twice the memory
+	// amount in swap
+	SwapBytes *int64 `json:"SwapBytes,omitzero"`
+
+	// Tune container memory swappiness (0 to 100) - if not specified, defaults
+	// to the container OS's default - generally 60, or the value predefined in
+	// the image; set to -1 to unset a previously set value
+	MemorySwappiness *int64 `json:"MemorySwappiness,omitzero"`
+}
+
+// Placement represents orchestration parameters.
+type Placement struct {
+	Constraints []string              `json:",omitempty"`
+	Preferences []PlacementPreference `json:",omitempty"`
+	MaxReplicas uint64                `json:",omitempty"`
+
+	// Platforms stores all the platforms that the image can run on.
+	// This field is used in the platform filter for scheduling. If empty,
+	// then the platform filter is off, meaning there are no scheduling restrictions.
+	Platforms []Platform `json:",omitempty"`
+}
+
+// PlacementPreference provides a way to make the scheduler aware of factors
+// such as topology.
+type PlacementPreference struct {
+	Spread *SpreadOver
+}
+
+// SpreadOver is a scheduling preference that instructs the scheduler to spread
+// tasks evenly over groups of nodes identified by labels.
+type SpreadOver struct {
+	// label descriptor, such as engine.labels.az
+	SpreadDescriptor string
+}
+
+// RestartPolicy represents the restart policy.
+type RestartPolicy struct {
+	Condition   RestartPolicyCondition `json:",omitempty"`
+	Delay       *time.Duration         `json:",omitempty"`
+	MaxAttempts *uint64                `json:",omitempty"`
+	Window      *time.Duration         `json:",omitempty"`
+}
+
+// RestartPolicyCondition represents when to restart.
+type RestartPolicyCondition string
+
+const (
+	// RestartPolicyConditionNone NONE
+	RestartPolicyConditionNone RestartPolicyCondition = "none"
+	// RestartPolicyConditionOnFailure ON_FAILURE
+	RestartPolicyConditionOnFailure RestartPolicyCondition = "on-failure"
+	// RestartPolicyConditionAny ANY
+	RestartPolicyConditionAny RestartPolicyCondition = "any"
+)
+
+// TaskStatus represents the status of a task.
+type TaskStatus struct {
+	Timestamp       time.Time        `json:",omitempty"`
+	State           TaskState        `json:",omitempty"`
+	Message         string           `json:",omitempty"`
+	Err             string           `json:",omitempty"`
+	ContainerStatus *ContainerStatus `json:",omitempty"`
+	PortStatus      PortStatus       `json:",omitempty"`
+}
+
+// ContainerStatus represents the status of a container.
+type ContainerStatus struct {
+	ContainerID string
+	PID         int
+	ExitCode    int
+}
+
+// PortStatus represents the port status of a task's host ports whose
+// service has published host ports
+type PortStatus struct {
+	Ports []PortConfig `json:",omitempty"`
+}
+
+// VolumeAttachment contains the associating a Volume to a Task.
+type VolumeAttachment struct {
+	// ID is the Swarmkit ID of the Volume. This is not the CSI VolumeId.
+	ID string `json:",omitempty"`
+
+	// Source, together with Target, indicates the Mount, as specified in the
+	// ContainerSpec, that this volume fulfills.
+	Source string `json:",omitempty"`
+
+	// Target, together with Source, indicates the Mount, as specified
+	// in the ContainerSpec, that this volume fulfills.
+	Target string `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/system/disk_usage.go b/vendor/github.com/moby/moby/api/types/system/disk_usage.go
new file mode 100644
index 000000000..33230aed2
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/system/disk_usage.go
@@ -0,0 +1,31 @@
+package system
+
+import (
+	"github.com/moby/moby/api/types/build"
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/image"
+	"github.com/moby/moby/api/types/volume"
+)
+
+// DiskUsageObject represents an object type used for disk usage query filtering.
+type DiskUsageObject string
+
+const (
+	// ContainerObject represents a container DiskUsageObject.
+	ContainerObject DiskUsageObject = "container"
+	// ImageObject represents an image DiskUsageObject.
+	ImageObject DiskUsageObject = "image"
+	// VolumeObject represents a volume DiskUsageObject.
+	VolumeObject DiskUsageObject = "volume"
+	// BuildCacheObject represents a build-cache DiskUsageObject.
+	BuildCacheObject DiskUsageObject = "build-cache"
+)
+
+// DiskUsage contains response of Engine API:
+// GET "/system/df"
+type DiskUsage struct {
+	ImageUsage      *image.DiskUsage     `json:"ImageUsage,omitempty"`
+	ContainerUsage  *container.DiskUsage `json:"ContainerUsage,omitempty"`
+	VolumeUsage     *volume.DiskUsage    `json:"VolumeUsage,omitempty"`
+	BuildCacheUsage *build.DiskUsage     `json:"BuildCacheUsage,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/system/info.go b/vendor/github.com/moby/moby/api/types/system/info.go
new file mode 100644
index 000000000..20df949e4
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/system/info.go
@@ -0,0 +1,171 @@
+package system
+
+import (
+	"net/netip"
+
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/registry"
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// Info contains response of Engine API:
+// GET "/info"
+type Info struct {
+	ID                 string
+	Containers         int
+	ContainersRunning  int
+	ContainersPaused   int
+	ContainersStopped  int
+	Images             int
+	Driver             string
+	DriverStatus       [][2]string
+	SystemStatus       [][2]string `json:",omitempty"` // SystemStatus is only propagated by the Swarm standalone API
+	Plugins            PluginsInfo
+	MemoryLimit        bool
+	SwapLimit          bool
+	CPUCfsPeriod       bool `json:"CpuCfsPeriod"`
+	CPUCfsQuota        bool `json:"CpuCfsQuota"`
+	CPUShares          bool
+	CPUSet             bool
+	PidsLimit          bool
+	IPv4Forwarding     bool
+	Debug              bool
+	NFd                int
+	OomKillDisable     bool
+	NGoroutines        int
+	SystemTime         string
+	LoggingDriver      string
+	CgroupDriver       string
+	CgroupVersion      string `json:",omitempty"`
+	NEventsListener    int
+	KernelVersion      string
+	OperatingSystem    string
+	OSVersion          string
+	OSType             string
+	Architecture       string
+	IndexServerAddress string
+	RegistryConfig     *registry.ServiceConfig
+	NCPU               int
+	MemTotal           int64
+	GenericResources   []swarm.GenericResource
+	DockerRootDir      string
+	HTTPProxy          string `json:"HttpProxy"`
+	HTTPSProxy         string `json:"HttpsProxy"`
+	NoProxy            string
+	Name               string
+	Labels             []string
+	ExperimentalBuild  bool
+	ServerVersion      string
+	Runtimes           map[string]RuntimeWithStatus
+	DefaultRuntime     string
+	Swarm              swarm.Info
+	// LiveRestoreEnabled determines whether containers should be kept
+	// running when the daemon is shutdown or upon daemon start if
+	// running containers are detected
+	LiveRestoreEnabled  bool
+	Isolation           container.Isolation
+	InitBinary          string
+	ContainerdCommit    Commit
+	RuncCommit          Commit
+	InitCommit          Commit
+	SecurityOptions     []string
+	ProductLicense      string               `json:",omitempty"`
+	DefaultAddressPools []NetworkAddressPool `json:",omitempty"`
+	FirewallBackend     *FirewallInfo        `json:"FirewallBackend,omitempty"`
+	CDISpecDirs         []string
+	DiscoveredDevices   []DeviceInfo `json:",omitempty"`
+	NRI                 *NRIInfo     `json:",omitempty"`
+
+	Containerd *ContainerdInfo `json:",omitempty"`
+
+	// Warnings contains a slice of warnings that occurred  while collecting
+	// system information. These warnings are intended to be informational
+	// messages for the user, and are not intended to be parsed / used for
+	// other purposes, as they do not have a fixed format.
+	Warnings []string
+}
+
+// ContainerdInfo holds information about the containerd instance used by the daemon.
+type ContainerdInfo struct {
+	// Address is the path to the containerd socket.
+	Address string `json:",omitempty"`
+	// Namespaces is the containerd namespaces used by the daemon.
+	Namespaces ContainerdNamespaces
+}
+
+// ContainerdNamespaces reflects the containerd namespaces used by the daemon.
+//
+// These namespaces can be configured in the daemon configuration, and are
+// considered to be used exclusively by the daemon,
+//
+// As these namespaces are considered to be exclusively accessed
+// by the daemon, it is not recommended to change these values,
+// or to change them to a value that is used by other systems,
+// such as cri-containerd.
+type ContainerdNamespaces struct {
+	// Containers holds the default containerd namespace used for
+	// containers managed by the daemon.
+	//
+	// The default namespace for containers is "moby", but will be
+	// suffixed with the `<uid>.<gid>` of the remapped `root` if
+	// user-namespaces are enabled and the containerd image-store
+	// is used.
+	Containers string
+
+	// Plugins holds the default containerd namespace used for
+	// plugins managed by the daemon.
+	//
+	// The default namespace for plugins is "moby", but will be
+	// suffixed with the `<uid>.<gid>` of the remapped `root` if
+	// user-namespaces are enabled and the containerd image-store
+	// is used.
+	Plugins string
+}
+
+// PluginsInfo is a temp struct holding Plugins name
+// registered with docker daemon. It is used by [Info] struct
+type PluginsInfo struct {
+	// List of Volume plugins registered
+	Volume []string
+	// List of Network plugins registered
+	Network []string
+	// List of Authorization plugins registered
+	Authorization []string
+	// List of Log plugins registered
+	Log []string
+}
+
+// Commit holds the Git-commit (SHA1) that a binary was built from, as reported
+// in the version-string of external tools, such as containerd, or runC.
+type Commit struct {
+	// ID is the actual commit ID or version of external tool.
+	ID string
+}
+
+// NetworkAddressPool is a temp struct used by [Info] struct.
+type NetworkAddressPool struct {
+	Base netip.Prefix
+	Size int
+}
+
+// FirewallInfo describes the firewall backend.
+type FirewallInfo struct {
+	// Driver is the name of the firewall backend driver.
+	Driver string `json:"Driver"`
+	// Info is a list of label/value pairs, containing information related to the firewall.
+	Info [][2]string `json:"Info,omitempty"`
+}
+
+// DeviceInfo represents a discoverable device from a device driver.
+type DeviceInfo struct {
+	// Source indicates the origin device driver.
+	Source string `json:"Source"`
+	// ID is the unique identifier for the device.
+	// Example: CDI FQDN like "vendor.com/gpu=0", or other driver-specific device ID
+	ID string `json:"ID"`
+}
+
+// NRIInfo describes the NRI configuration.
+type NRIInfo struct {
+	Info [][2]string `json:"Info,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/system/runtime.go b/vendor/github.com/moby/moby/api/types/system/runtime.go
new file mode 100644
index 000000000..33cad3674
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/system/runtime.go
@@ -0,0 +1,20 @@
+package system
+
+// Runtime describes an OCI runtime
+type Runtime struct {
+	// "Legacy" runtime configuration for runc-compatible runtimes.
+
+	Path string   `json:"path,omitempty"`
+	Args []string `json:"runtimeArgs,omitempty"`
+
+	// Shimv2 runtime configuration. Mutually exclusive with the legacy config above.
+
+	Type    string         `json:"runtimeType,omitempty"`
+	Options map[string]any `json:"options,omitempty"`
+}
+
+// RuntimeWithStatus extends [Runtime] to hold [RuntimeStatus].
+type RuntimeWithStatus struct {
+	Runtime
+	Status map[string]string `json:"status,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/system/version_response.go b/vendor/github.com/moby/moby/api/types/system/version_response.go
new file mode 100644
index 000000000..61cd1b6e2
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/system/version_response.go
@@ -0,0 +1,58 @@
+package system
+
+// VersionResponse contains information about the Docker server host.
+// GET "/version"
+type VersionResponse struct {
+	// Platform is the platform (product name) the server is running on.
+	Platform PlatformInfo `json:",omitempty"`
+
+	// Version is the version of the daemon.
+	Version string
+
+	// APIVersion is the highest API version supported by the server.
+	APIVersion string `json:"ApiVersion"`
+
+	// MinAPIVersion is the minimum API version the server supports.
+	MinAPIVersion string `json:"MinAPIVersion,omitempty"`
+
+	// Os is the operating system the server runs on.
+	Os string
+
+	// Arch is the hardware architecture the server runs on.
+	Arch string
+
+	// Components contains version information for the components making
+	// up the server. Information in this field is for informational
+	// purposes, and not part of the API contract.
+	Components []ComponentVersion `json:",omitempty"`
+
+	// The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility
+
+	GitCommit     string `json:",omitempty"`
+	GoVersion     string `json:",omitempty"`
+	KernelVersion string `json:",omitempty"`
+	Experimental  bool   `json:",omitempty"`
+	BuildTime     string `json:",omitempty"`
+}
+
+// PlatformInfo holds information about the platform (product name) the
+// server is running on.
+type PlatformInfo struct {
+	// Name is the name of the platform (for example, "Docker Engine - Community",
+	// or "Docker Desktop 4.49.0 (208003)")
+	Name string
+}
+
+// ComponentVersion describes the version information for a specific component.
+type ComponentVersion struct {
+	Name    string
+	Version string
+
+	// Details contains Key/value pairs of strings with additional information
+	// about the component. These values are intended for informational purposes
+	// only, and their content is not defined, and not part of the API
+	// specification.
+	//
+	// These messages can be printed by the client as information to the user.
+	Details map[string]string `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/types.go b/vendor/github.com/moby/moby/api/types/types.go
new file mode 100644
index 000000000..5da64796e
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/types.go
@@ -0,0 +1,33 @@
+package types
+
+// MediaType represents an HTTP media type (MIME type) used in API
+// Content-Type and Accept headers.
+//
+// In addition to standard media types (for example, "application/json"),
+// this package defines vendor-specific vendor media types for streaming
+// endpoints, such as raw TTY streams and multiplexed stdout/stderr streams.
+type MediaType = string
+
+const (
+	// MediaTypeRawStream is a vendor-specific media type for raw TTY streams.
+	MediaTypeRawStream MediaType = "application/vnd.docker.raw-stream"
+
+	// MediaTypeMultiplexedStream is a vendor-specific media type for streams
+	// where stdin, stdout, and stderr are multiplexed into a single byte stream.
+	//
+	// Use stdcopy.StdCopy (https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy)
+	// to demultiplex the stream.
+	MediaTypeMultiplexedStream MediaType = "application/vnd.docker.multiplexed-stream"
+
+	// MediaTypeJSON is the media type for JSON objects.
+	MediaTypeJSON MediaType = "application/json"
+
+	// MediaTypeNDJSON is the media type for newline-delimited JSON streams (https://github.com/ndjson/ndjson-spec).
+	MediaTypeNDJSON MediaType = "application/x-ndjson"
+
+	// MediaTypeJSONLines is the media type for JSON Lines streams (https://jsonlines.org/).
+	MediaTypeJSONLines MediaType = "application/jsonl"
+
+	// MediaTypeJSONSequence is the media type for JSON text sequences (RFC 7464).
+	MediaTypeJSONSequence MediaType = "application/json-seq"
+)
diff --git a/vendor/github.com/moby/moby/api/types/volume/cluster_volume.go b/vendor/github.com/moby/moby/api/types/volume/cluster_volume.go
new file mode 100644
index 000000000..07b75d12a
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/volume/cluster_volume.go
@@ -0,0 +1,420 @@
+package volume
+
+import (
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// ClusterVolume contains options and information specific to, and only present
+// on, Swarm CSI cluster volumes.
+type ClusterVolume struct {
+	// ID is the Swarm ID of the volume. Because cluster volumes are Swarm
+	// objects, they have an ID, unlike non-cluster volumes, which only have a
+	// Name. This ID can be used to refer to the cluster volume.
+	ID string
+
+	// Meta is the swarm metadata about this volume.
+	swarm.Meta
+
+	// Spec is the cluster-specific options from which this volume is derived.
+	Spec ClusterVolumeSpec
+
+	// PublishStatus contains the status of the volume as it pertains to its
+	// publishing on Nodes.
+	PublishStatus []*PublishStatus `json:",omitempty"`
+
+	// Info is information about the global status of the volume.
+	Info *Info `json:",omitempty"`
+}
+
+// ClusterVolumeSpec contains the spec used to create this volume.
+type ClusterVolumeSpec struct {
+	// Group defines the volume group of this volume. Volumes belonging to the
+	// same group can be referred to by group name when creating Services.
+	// Referring to a volume by group instructs swarm to treat volumes in that
+	// group interchangeably for the purpose of scheduling. Volumes with an
+	// empty string for a group technically all belong to the same, emptystring
+	// group.
+	Group string `json:",omitempty"`
+
+	// AccessMode defines how the volume is used by tasks.
+	AccessMode *AccessMode `json:",omitempty"`
+
+	// AccessibilityRequirements specifies where in the cluster a volume must
+	// be accessible from.
+	//
+	// This field must be empty if the plugin does not support
+	// VOLUME_ACCESSIBILITY_CONSTRAINTS capabilities. If it is present but the
+	// plugin does not support it, volume will not be created.
+	//
+	// If AccessibilityRequirements is empty, but the plugin does support
+	// VOLUME_ACCESSIBILITY_CONSTRAINTS, then Swarmkit will assume the entire
+	// cluster is a valid target for the volume.
+	AccessibilityRequirements *TopologyRequirement `json:",omitempty"`
+
+	// CapacityRange defines the desired capacity that the volume should be
+	// created with. If nil, the plugin will decide the capacity.
+	CapacityRange *CapacityRange `json:",omitempty"`
+
+	// Secrets defines Swarm Secrets that are passed to the CSI storage plugin
+	// when operating on this volume.
+	Secrets []Secret `json:",omitempty"`
+
+	// Availability is the Volume's desired availability. Analogous to Node
+	// Availability, this allows the user to take volumes offline in order to
+	// update or delete them.
+	Availability Availability `json:",omitempty"`
+}
+
+// Availability specifies the availability of the volume.
+type Availability string
+
+const (
+	// AvailabilityActive indicates that the volume is active and fully
+	// schedulable on the cluster.
+	AvailabilityActive Availability = "active"
+
+	// AvailabilityPause indicates that no new workloads should use the
+	// volume, but existing workloads can continue to use it.
+	AvailabilityPause Availability = "pause"
+
+	// AvailabilityDrain indicates that all workloads using this volume
+	// should be rescheduled, and the volume unpublished from all nodes.
+	AvailabilityDrain Availability = "drain"
+)
+
+// AccessMode defines the access mode of a volume.
+type AccessMode struct {
+	// Scope defines the set of nodes this volume can be used on at one time.
+	Scope Scope `json:",omitempty"`
+
+	// Sharing defines the number and way that different tasks can use this
+	// volume at one time.
+	Sharing SharingMode `json:",omitempty"`
+
+	// MountVolume defines options for using this volume as a Mount-type
+	// volume.
+	//
+	// Either BlockVolume or MountVolume, but not both, must be present.
+	MountVolume *TypeMount `json:",omitempty"`
+
+	// BlockVolume defines options for using this volume as a Block-type
+	// volume.
+	//
+	// Either BlockVolume or MountVolume, but not both, must be present.
+	BlockVolume *TypeBlock `json:",omitempty"`
+}
+
+// Scope defines the Scope of a Cluster Volume. This is how many nodes a
+// Volume can be accessed simultaneously on.
+type Scope string
+
+const (
+	// ScopeSingleNode indicates the volume can be used on one node at a
+	// time.
+	ScopeSingleNode Scope = "single"
+
+	// ScopeMultiNode indicates the volume can be used on many nodes at
+	// the same time.
+	ScopeMultiNode Scope = "multi"
+)
+
+// SharingMode defines the Sharing of a Cluster Volume. This is how Tasks using a
+// Volume at the same time can use it.
+type SharingMode string
+
+const (
+	// SharingNone indicates that only one Task may use the Volume at a
+	// time.
+	SharingNone SharingMode = "none"
+
+	// SharingReadOnly indicates that the Volume may be shared by any
+	// number of Tasks, but they must be read-only.
+	SharingReadOnly SharingMode = "readonly"
+
+	// SharingOneWriter indicates that the Volume may be shared by any
+	// number of Tasks, but all after the first must be read-only.
+	SharingOneWriter SharingMode = "onewriter"
+
+	// SharingAll means that the Volume may be shared by any number of
+	// Tasks, as readers or writers.
+	SharingAll SharingMode = "all"
+)
+
+// TypeBlock defines options for using a volume as a block-type volume.
+//
+// Intentionally empty.
+type TypeBlock struct{}
+
+// TypeMount contains options for using a volume as a Mount-type
+// volume.
+type TypeMount struct {
+	// FsType specifies the filesystem type for the mount volume. Optional.
+	FsType string `json:",omitempty"`
+
+	// MountFlags defines flags to pass when mounting the volume. Optional.
+	MountFlags []string `json:",omitempty"`
+}
+
+// TopologyRequirement expresses the user's requirements for a volume's
+// accessible topology.
+type TopologyRequirement struct {
+	// Requisite specifies a list of Topologies, at least one of which the
+	// volume must be accessible from.
+	//
+	// Taken verbatim from the CSI Spec:
+	//
+	// Specifies the list of topologies the provisioned volume MUST be
+	// accessible from.
+	// This field is OPTIONAL. If TopologyRequirement is specified either
+	// requisite or preferred or both MUST be specified.
+	//
+	// If requisite is specified, the provisioned volume MUST be
+	// accessible from at least one of the requisite topologies.
+	//
+	// Given
+	//   x = number of topologies provisioned volume is accessible from
+	//   n = number of requisite topologies
+	// The CO MUST ensure n >= 1. The SP MUST ensure x >= 1
+	// If x==n, then the SP MUST make the provisioned volume available to
+	// all topologies from the list of requisite topologies. If it is
+	// unable to do so, the SP MUST fail the CreateVolume call.
+	// For example, if a volume should be accessible from a single zone,
+	// and requisite =
+	//   {"region": "R1", "zone": "Z2"}
+	// then the provisioned volume MUST be accessible from the "region"
+	// "R1" and the "zone" "Z2".
+	// Similarly, if a volume should be accessible from two zones, and
+	// requisite =
+	//   {"region": "R1", "zone": "Z2"},
+	//   {"region": "R1", "zone": "Z3"}
+	// then the provisioned volume MUST be accessible from the "region"
+	// "R1" and both "zone" "Z2" and "zone" "Z3".
+	//
+	// If x<n, then the SP SHALL choose x unique topologies from the list
+	// of requisite topologies. If it is unable to do so, the SP MUST fail
+	// the CreateVolume call.
+	// For example, if a volume should be accessible from a single zone,
+	// and requisite =
+	//   {"region": "R1", "zone": "Z2"},
+	//   {"region": "R1", "zone": "Z3"}
+	// then the SP may choose to make the provisioned volume available in
+	// either the "zone" "Z2" or the "zone" "Z3" in the "region" "R1".
+	// Similarly, if a volume should be accessible from two zones, and
+	// requisite =
+	//   {"region": "R1", "zone": "Z2"},
+	//   {"region": "R1", "zone": "Z3"},
+	//   {"region": "R1", "zone": "Z4"}
+	// then the provisioned volume MUST be accessible from any combination
+	// of two unique topologies: e.g. "R1/Z2" and "R1/Z3", or "R1/Z2" and
+	//  "R1/Z4", or "R1/Z3" and "R1/Z4".
+	//
+	// If x>n, then the SP MUST make the provisioned volume available from
+	// all topologies from the list of requisite topologies and MAY choose
+	// the remaining x-n unique topologies from the list of all possible
+	// topologies. If it is unable to do so, the SP MUST fail the
+	// CreateVolume call.
+	// For example, if a volume should be accessible from two zones, and
+	// requisite =
+	//   {"region": "R1", "zone": "Z2"}
+	// then the provisioned volume MUST be accessible from the "region"
+	// "R1" and the "zone" "Z2" and the SP may select the second zone
+	// independently, e.g. "R1/Z4".
+	Requisite []Topology `json:",omitempty"`
+
+	// Preferred is a list of Topologies that the volume should attempt to be
+	// provisioned in.
+	//
+	// Taken from the CSI spec:
+	//
+	// Specifies the list of topologies the CO would prefer the volume to
+	// be provisioned in.
+	//
+	// This field is OPTIONAL. If TopologyRequirement is specified either
+	// requisite or preferred or both MUST be specified.
+	//
+	// An SP MUST attempt to make the provisioned volume available using
+	// the preferred topologies in order from first to last.
+	//
+	// If requisite is specified, all topologies in preferred list MUST
+	// also be present in the list of requisite topologies.
+	//
+	// If the SP is unable to make the provisioned volume available
+	// from any of the preferred topologies, the SP MAY choose a topology
+	// from the list of requisite topologies.
+	// If the list of requisite topologies is not specified, then the SP
+	// MAY choose from the list of all possible topologies.
+	// If the list of requisite topologies is specified and the SP is
+	// unable to make the provisioned volume available from any of the
+	// requisite topologies it MUST fail the CreateVolume call.
+	//
+	// Example 1:
+	// Given a volume should be accessible from a single zone, and
+	// requisite =
+	//   {"region": "R1", "zone": "Z2"},
+	//   {"region": "R1", "zone": "Z3"}
+	// preferred =
+	//   {"region": "R1", "zone": "Z3"}
+	// then the SP SHOULD first attempt to make the provisioned volume
+	// available from "zone" "Z3" in the "region" "R1" and fall back to
+	// "zone" "Z2" in the "region" "R1" if that is not possible.
+	//
+	// Example 2:
+	// Given a volume should be accessible from a single zone, and
+	// requisite =
+	//   {"region": "R1", "zone": "Z2"},
+	//   {"region": "R1", "zone": "Z3"},
+	//   {"region": "R1", "zone": "Z4"},
+	//   {"region": "R1", "zone": "Z5"}
+	// preferred =
+	//   {"region": "R1", "zone": "Z4"},
+	//   {"region": "R1", "zone": "Z2"}
+	// then the SP SHOULD first attempt to make the provisioned volume
+	// accessible from "zone" "Z4" in the "region" "R1" and fall back to
+	// "zone" "Z2" in the "region" "R1" if that is not possible. If that
+	// is not possible, the SP may choose between either the "zone"
+	// "Z3" or "Z5" in the "region" "R1".
+	//
+	// Example 3:
+	// Given a volume should be accessible from TWO zones (because an
+	// opaque parameter in CreateVolumeRequest, for example, specifies
+	// the volume is accessible from two zones, aka synchronously
+	// replicated), and
+	// requisite =
+	//   {"region": "R1", "zone": "Z2"},
+	//   {"region": "R1", "zone": "Z3"},
+	//   {"region": "R1", "zone": "Z4"},
+	//   {"region": "R1", "zone": "Z5"}
+	// preferred =
+	//   {"region": "R1", "zone": "Z5"},
+	//   {"region": "R1", "zone": "Z3"}
+	// then the SP SHOULD first attempt to make the provisioned volume
+	// accessible from the combination of the two "zones" "Z5" and "Z3" in
+	// the "region" "R1". If that's not possible, it should fall back to
+	// a combination of "Z5" and other possibilities from the list of
+	// requisite. If that's not possible, it should fall back  to a
+	// combination of "Z3" and other possibilities from the list of
+	// requisite. If that's not possible, it should fall back  to a
+	// combination of other possibilities from the list of requisite.
+	Preferred []Topology `json:",omitempty"`
+}
+
+// Topology is a map of topological domains to topological segments.
+//
+// This description is taken verbatim from the CSI Spec:
+//
+// A topological domain is a sub-division of a cluster, like "region",
+// "zone", "rack", etc.
+// A topological segment is a specific instance of a topological domain,
+// like "zone3", "rack3", etc.
+// For example {"com.company/zone": "Z1", "com.company/rack": "R3"}
+// Valid keys have two segments: an OPTIONAL prefix and name, separated
+// by a slash (/), for example: "com.company.example/zone".
+// The key name segment is REQUIRED. The prefix is OPTIONAL.
+// The key name MUST be 63 characters or less, begin and end with an
+// alphanumeric character ([a-z0-9A-Z]), and contain only dashes (-),
+// underscores (_), dots (.), or alphanumerics in between, for example
+// "zone".
+// The key prefix MUST be 63 characters or less, begin and end with a
+// lower-case alphanumeric character ([a-z0-9]), contain only
+// dashes (-), dots (.), or lower-case alphanumerics in between, and
+// follow domain name notation format
+// (https://tools.ietf.org/html/rfc1035#section-2.3.1).
+// The key prefix SHOULD include the plugin's host company name and/or
+// the plugin name, to minimize the possibility of collisions with keys
+// from other plugins.
+// If a key prefix is specified, it MUST be identical across all
+// topology keys returned by the SP (across all RPCs).
+// Keys MUST be case-insensitive. Meaning the keys "Zone" and "zone"
+// MUST not both exist.
+// Each value (topological segment) MUST contain 1 or more strings.
+// Each string MUST be 63 characters or less and begin and end with an
+// alphanumeric character with '-', '_', '.', or alphanumerics in
+// between.
+type Topology struct {
+	Segments map[string]string `json:",omitempty"`
+}
+
+// CapacityRange describes the minimum and maximum capacity a volume should be
+// created with
+type CapacityRange struct {
+	// RequiredBytes specifies that a volume must be at least this big. The
+	// value of 0 indicates an unspecified minimum.
+	RequiredBytes int64
+
+	// LimitBytes specifies that a volume must not be bigger than this. The
+	// value of 0 indicates an unspecified maximum
+	LimitBytes int64
+}
+
+// Secret represents a Swarm Secret value that must be passed to the CSI
+// storage plugin when operating on this Volume. It represents one key-value
+// pair of possibly many.
+type Secret struct {
+	// Key is the name of the key of the key-value pair passed to the plugin.
+	Key string
+
+	// Secret is the swarm Secret object from which to read data. This can be a
+	// Secret name or ID. The Secret data is retrieved by Swarm and used as the
+	// value of the key-value pair passed to the plugin.
+	Secret string
+}
+
+// PublishState represents the state of a Volume as it pertains to its
+// use on a particular Node.
+type PublishState string
+
+const (
+	// StatePending indicates that the volume should be published on
+	// this node, but the call to ControllerPublishVolume has not been
+	// successfully completed yet and the result recorded by swarmkit.
+	StatePending PublishState = "pending-publish"
+
+	// StatePublished means the volume is published successfully to the node.
+	StatePublished PublishState = "published"
+
+	// StatePendingNodeUnpublish indicates that the Volume should be
+	// unpublished on the Node, and we're waiting for confirmation that it has
+	// done so.  After the Node has confirmed that the Volume has been
+	// unpublished, the state will move to StatePendingUnpublish.
+	StatePendingNodeUnpublish PublishState = "pending-node-unpublish"
+
+	// StatePendingUnpublish means the volume is still published to the node
+	// by the controller, awaiting the operation to unpublish it.
+	StatePendingUnpublish PublishState = "pending-controller-unpublish"
+)
+
+// PublishStatus represents the status of the volume as published to an
+// individual node
+type PublishStatus struct {
+	// NodeID is the ID of the swarm node this Volume is published to.
+	NodeID string `json:",omitempty"`
+
+	// State is the publish state of the volume.
+	State PublishState `json:",omitempty"`
+
+	// PublishContext is the PublishContext returned by the CSI plugin when
+	// a volume is published.
+	PublishContext map[string]string `json:",omitempty"`
+}
+
+// Info contains information about the Volume as a whole as provided by
+// the CSI storage plugin.
+type Info struct {
+	// CapacityBytes is the capacity of the volume in bytes. A value of 0
+	// indicates that the capacity is unknown.
+	CapacityBytes int64 `json:",omitempty"`
+
+	// VolumeContext is the context originating from the CSI storage plugin
+	// when the Volume is created.
+	VolumeContext map[string]string `json:",omitempty"`
+
+	// VolumeID is the ID of the Volume as seen by the CSI storage plugin. This
+	// is distinct from the Volume's Swarm ID, which is the ID used by all of
+	// the Docker Engine to refer to the Volume. If this field is blank, then
+	// the Volume has not been successfully created yet.
+	VolumeID string `json:",omitempty"`
+
+	// AccessibleTopology is the topology this volume is actually accessible
+	// from.
+	AccessibleTopology []Topology `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/volume/create_request.go b/vendor/github.com/moby/moby/api/types/volume/create_request.go
new file mode 100644
index 000000000..3217df827
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/volume/create_request.go
@@ -0,0 +1,36 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package volume
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// CreateRequest VolumeConfig
+//
+// # Volume configuration
+//
+// swagger:model CreateRequest
+type CreateRequest struct {
+
+	// cluster volume spec
+	ClusterVolumeSpec *ClusterVolumeSpec `json:"ClusterVolumeSpec,omitempty"`
+
+	// Name of the volume driver to use.
+	// Example: custom
+	Driver string `json:"Driver,omitempty"`
+
+	// A mapping of driver options and values. These options are
+	// passed directly to the driver and are driver specific.
+	//
+	// Example: {"device":"tmpfs","o":"size=100m,uid=1000","type":"tmpfs"}
+	DriverOpts map[string]string `json:"DriverOpts,omitempty"`
+
+	// User-defined key/value metadata.
+	// Example: {"com.example.some-label":"some-value","com.example.some-other-label":"some-other-value"}
+	Labels map[string]string `json:"Labels,omitempty"`
+
+	// The new volume's name. If not specified, Docker generates a name.
+	//
+	// Example: tardis
+	Name string `json:"Name,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/volume/disk_usage.go b/vendor/github.com/moby/moby/api/types/volume/disk_usage.go
new file mode 100644
index 000000000..e2afbac65
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/volume/disk_usage.go
@@ -0,0 +1,36 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package volume
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// DiskUsage represents system data usage for volume resources.
+//
+// swagger:model DiskUsage
+type DiskUsage struct {
+
+	// Count of active volumes.
+	//
+	// Example: 1
+	ActiveCount int64 `json:"ActiveCount,omitempty"`
+
+	// List of volumes.
+	//
+	Items []Volume `json:"Items,omitempty"`
+
+	// Disk space that can be reclaimed by removing inactive volumes.
+	//
+	// Example: 12345678
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
+
+	// Count of all volumes.
+	//
+	// Example: 4
+	TotalCount int64 `json:"TotalCount,omitempty"`
+
+	// Disk space in use by volumes.
+	//
+	// Example: 98765432
+	TotalSize int64 `json:"TotalSize,omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/volume/list_response.go b/vendor/github.com/moby/moby/api/types/volume/list_response.go
new file mode 100644
index 000000000..f257762f0
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/volume/list_response.go
@@ -0,0 +1,22 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package volume
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// ListResponse VolumeListResponse
+//
+// # Volume list response
+//
+// swagger:model ListResponse
+type ListResponse struct {
+
+	// List of volumes
+	Volumes []Volume `json:"Volumes"`
+
+	// Warnings that occurred when fetching the list of volumes.
+	//
+	// Example: []
+	Warnings []string `json:"Warnings"`
+}
diff --git a/vendor/github.com/moby/moby/api/types/volume/prune_report.go b/vendor/github.com/moby/moby/api/types/volume/prune_report.go
new file mode 100644
index 000000000..7f501d01a
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/volume/prune_report.go
@@ -0,0 +1,8 @@
+package volume
+
+// PruneReport contains the response for Engine API:
+// POST "/volumes/prune"
+type PruneReport struct {
+	VolumesDeleted []string
+	SpaceReclaimed uint64
+}
diff --git a/vendor/github.com/moby/moby/api/types/volume/volume.go b/vendor/github.com/moby/moby/api/types/volume/volume.go
new file mode 100644
index 000000000..524ebfb8a
--- /dev/null
+++ b/vendor/github.com/moby/moby/api/types/volume/volume.go
@@ -0,0 +1,87 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+package volume
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+// Volume volume
+//
+// swagger:model Volume
+type Volume struct {
+
+	// cluster volume
+	ClusterVolume *ClusterVolume `json:"ClusterVolume,omitempty"`
+
+	// Date/Time the volume was created.
+	// Example: 2016-06-07T20:31:11.853781916Z
+	CreatedAt string `json:"CreatedAt,omitempty"`
+
+	// Name of the volume driver used by the volume.
+	// Example: custom
+	// Required: true
+	Driver string `json:"Driver"`
+
+	// User-defined key/value metadata.
+	// Example: {"com.example.some-label":"some-value","com.example.some-other-label":"some-other-value"}
+	// Required: true
+	Labels map[string]string `json:"Labels"`
+
+	// Mount path of the volume on the host.
+	// Example: /var/lib/docker/volumes/tardis
+	// Required: true
+	Mountpoint string `json:"Mountpoint"`
+
+	// Name of the volume.
+	// Example: tardis
+	// Required: true
+	Name string `json:"Name"`
+
+	// The driver specific options used when creating the volume.
+	//
+	// Example: {"device":"tmpfs","o":"size=100m,uid=1000","type":"tmpfs"}
+	// Required: true
+	Options map[string]string `json:"Options"`
+
+	// The level at which the volume exists. Either `global` for cluster-wide,
+	// or `local` for machine level.
+	//
+	// Example: local
+	// Required: true
+	// Enum: ["local","global"]
+	Scope string `json:"Scope"`
+
+	// Low-level details about the volume, provided by the volume driver.
+	// Details are returned as a map with key/value pairs:
+	// `{"key":"value","key2":"value2"}`.
+	//
+	// The `Status` field is optional, and is omitted if the volume driver
+	// does not support this feature.
+	//
+	// Example: {"hello":"world"}
+	Status map[string]any `json:"Status,omitempty"`
+
+	// usage data
+	UsageData *UsageData `json:"UsageData,omitempty"`
+}
+
+// UsageData Usage details about the volume. This information is used by the
+// `GET /system/df` endpoint, and omitted in other endpoints.
+//
+// swagger:model UsageData
+type UsageData struct {
+
+	// The number of containers referencing this volume. This field
+	// is set to `-1` if the reference-count is not available.
+	//
+	// Required: true
+	RefCount int64 `json:"RefCount"`
+
+	// Amount of disk space used by the volume (in bytes). This information
+	// is only available for volumes created with the `"local"` volume
+	// driver. For volumes created with other volume drivers, this field
+	// is set to `-1` ("not available")
+	//
+	// Required: true
+	Size int64 `json:"Size"`
+}
diff --git a/vendor/github.com/moby/moby/client/LICENSE b/vendor/github.com/moby/moby/client/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/moby/moby/client/README.md b/vendor/github.com/moby/moby/client/README.md
new file mode 100644
index 000000000..aed3e641d
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/README.md
@@ -0,0 +1,57 @@
+# Go client for the Docker Engine API
+
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/moby/moby/client)](https://pkg.go.dev/github.com/moby/moby/client)
+![GitHub License](https://img.shields.io/github/license/moby/moby)
+[![Go Report Card](https://goreportcard.com/badge/github.com/moby/moby/client)](https://goreportcard.com/report/github.com/moby/moby/client)
+[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/moby/moby/badge)](https://scorecard.dev/viewer/?uri=github.com/moby/moby)
+[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/10989/badge)](https://www.bestpractices.dev/projects/10989)
+
+The `docker` command uses this package to communicate with the daemon. It can
+also be used by your own Go applications to do anything the command-line
+interface does; running containers, pulling or pushing images, etc.
+
+For example, to list all containers (the equivalent of `docker ps --all`):
+
+```go
+package main
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/moby/moby/client"
+)
+
+func main() {
+	// Create a new client with "client.FromEnv" (configuring the client
+	// from commonly used environment variables such as DOCKER_HOST and
+	// DOCKER_API_VERSION) and set a custom User-Agent.
+	//
+	// API-version negotiation is enabled by default to allow downgrading
+	// the API version when connecting with an older daemon version.
+	apiClient, err := client.New(
+		client.FromEnv,
+		client.WithUserAgent("my-application/1.0.0"),
+	)
+	if err != nil {
+		panic(err)
+	}
+	defer apiClient.Close()
+
+	// List all containers (both stopped and running).
+	result, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{
+		All: true,
+	})
+	if err != nil {
+		panic(err)
+	}
+
+	// Print each container's ID, status and the image it was created from.
+	fmt.Printf("%s  %-22s  %s\n", "ID", "STATUS", "IMAGE")
+	for _, ctr := range result.Items {
+		fmt.Printf("%s  %-22s  %s\n", ctr.ID, ctr.Status, ctr.Image)
+	}
+}
+```
+
+Full documentation is available on [pkg.go.dev](https://pkg.go.dev/github.com/moby/moby/client).
diff --git a/vendor/github.com/moby/moby/client/auth.go b/vendor/github.com/moby/moby/client/auth.go
new file mode 100644
index 000000000..8baf39d2c
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/auth.go
@@ -0,0 +1,14 @@
+package client
+
+import (
+	"context"
+
+	"github.com/moby/moby/api/types/registry"
+)
+
+// staticAuth creates a privilegeFn from the given registryAuth.
+func staticAuth(registryAuth string) registry.RequestAuthConfig {
+	return func(ctx context.Context) (string, error) {
+		return registryAuth, nil
+	}
+}
diff --git a/vendor/github.com/moby/moby/client/build_cancel.go b/vendor/github.com/moby/moby/client/build_cancel.go
new file mode 100644
index 000000000..a31dced97
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/build_cancel.go
@@ -0,0 +1,23 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// BuildCancelOptions holds options for [Client.BuildCancel].
+type BuildCancelOptions struct{}
+
+// BuildCancelResult holds the result of [Client.BuildCancel].
+type BuildCancelResult struct{}
+
+// BuildCancel requests the daemon to cancel the ongoing build request
+// with the given id.
+func (cli *Client) BuildCancel(ctx context.Context, id string, _ BuildCancelOptions) (BuildCancelResult, error) {
+	query := url.Values{}
+	query.Set("id", id)
+
+	resp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	return BuildCancelResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/build_prune.go b/vendor/github.com/moby/moby/client/build_prune.go
new file mode 100644
index 000000000..a22e9685e
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/build_prune.go
@@ -0,0 +1,67 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strconv"
+
+	"github.com/moby/moby/api/types/build"
+	"github.com/moby/moby/client/pkg/versions"
+)
+
+// BuildCachePruneOptions hold parameters to prune the build cache.
+type BuildCachePruneOptions struct {
+	All           bool
+	ReservedSpace int64
+	MaxUsedSpace  int64
+	MinFreeSpace  int64
+	Filters       Filters
+}
+
+// BuildCachePruneResult holds the result from the BuildCachePrune method.
+type BuildCachePruneResult struct {
+	Report build.CachePruneReport
+}
+
+// BuildCachePrune requests the daemon to delete unused cache data.
+func (cli *Client) BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (BuildCachePruneResult, error) {
+	var out BuildCachePruneResult
+	query := url.Values{}
+	if opts.All {
+		query.Set("all", "1")
+	}
+
+	if opts.ReservedSpace != 0 {
+		// Prior to API v1.48, 'keep-storage' was used to set the reserved space for the build cache.
+		// TODO(austinvazquez): remove once API v1.47 is no longer supported. See https://github.com/moby/moby/issues/50902
+		if versions.LessThanOrEqualTo(cli.version, "1.47") {
+			query.Set("keep-storage", strconv.Itoa(int(opts.ReservedSpace)))
+		} else {
+			query.Set("reserved-space", strconv.Itoa(int(opts.ReservedSpace)))
+		}
+	}
+	if opts.MaxUsedSpace != 0 {
+		query.Set("max-used-space", strconv.Itoa(int(opts.MaxUsedSpace)))
+	}
+	if opts.MinFreeSpace != 0 {
+		query.Set("min-free-space", strconv.Itoa(int(opts.MinFreeSpace)))
+	}
+	opts.Filters.updateURLValues(query)
+
+	resp, err := cli.post(ctx, "/build/prune", query, nil, nil)
+	defer ensureReaderClosed(resp)
+
+	if err != nil {
+		return BuildCachePruneResult{}, err
+	}
+
+	report := build.CachePruneReport{}
+	if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
+		return BuildCachePruneResult{}, fmt.Errorf("error retrieving disk usage: %w", err)
+	}
+
+	out.Report = report
+	return out, nil
+}
diff --git a/vendor/github.com/moby/moby/client/checkpoint_create.go b/vendor/github.com/moby/moby/client/checkpoint_create.go
new file mode 100644
index 000000000..b3ba5459d
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/checkpoint_create.go
@@ -0,0 +1,36 @@
+package client
+
+import (
+	"context"
+
+	"github.com/moby/moby/api/types/checkpoint"
+)
+
+// CheckpointCreateOptions holds parameters to create a checkpoint from a container.
+type CheckpointCreateOptions struct {
+	CheckpointID  string
+	CheckpointDir string
+	Exit          bool
+}
+
+// CheckpointCreateResult holds the result from [client.CheckpointCreate].
+type CheckpointCreateResult struct {
+	// Add future fields here
+}
+
+// CheckpointCreate creates a checkpoint from the given container.
+func (cli *Client) CheckpointCreate(ctx context.Context, containerID string, options CheckpointCreateOptions) (CheckpointCreateResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return CheckpointCreateResult{}, err
+	}
+	requestBody := checkpoint.CreateRequest{
+		CheckpointID:  options.CheckpointID,
+		CheckpointDir: options.CheckpointDir,
+		Exit:          options.Exit,
+	}
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/checkpoints", nil, requestBody, nil)
+	defer ensureReaderClosed(resp)
+	return CheckpointCreateResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/checkpoint_list.go b/vendor/github.com/moby/moby/client/checkpoint_list.go
new file mode 100644
index 000000000..5815f836a
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/checkpoint_list.go
@@ -0,0 +1,38 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/checkpoint"
+)
+
+// CheckpointListOptions holds parameters to list checkpoints for a container.
+type CheckpointListOptions struct {
+	CheckpointDir string
+}
+
+// CheckpointListResult holds the result from the CheckpointList method.
+type CheckpointListResult struct {
+	Items []checkpoint.Summary
+}
+
+// CheckpointList returns the checkpoints of the given container in the docker host.
+func (cli *Client) CheckpointList(ctx context.Context, container string, options CheckpointListOptions) (CheckpointListResult, error) {
+	var out CheckpointListResult
+
+	query := url.Values{}
+	if options.CheckpointDir != "" {
+		query.Set("dir", options.CheckpointDir)
+	}
+
+	resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return out, err
+	}
+
+	err = json.NewDecoder(resp.Body).Decode(&out.Items)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/checkpoint_remove.go b/vendor/github.com/moby/moby/client/checkpoint_remove.go
new file mode 100644
index 000000000..8042c5088
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/checkpoint_remove.go
@@ -0,0 +1,34 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// CheckpointRemoveOptions holds parameters to delete a checkpoint from a container.
+type CheckpointRemoveOptions struct {
+	CheckpointID  string
+	CheckpointDir string
+}
+
+// CheckpointRemoveResult represents the result of [Client.CheckpointRemove].
+type CheckpointRemoveResult struct {
+	// No fields currently; placeholder for future use.
+}
+
+// CheckpointRemove deletes the checkpoint with the given name from the given container.
+func (cli *Client) CheckpointRemove(ctx context.Context, containerID string, options CheckpointRemoveOptions) (CheckpointRemoveResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return CheckpointRemoveResult{}, err
+	}
+
+	query := url.Values{}
+	if options.CheckpointDir != "" {
+		query.Set("dir", options.CheckpointDir)
+	}
+
+	resp, err := cli.delete(ctx, "/containers/"+containerID+"/checkpoints/"+options.CheckpointID, query, nil)
+	defer ensureReaderClosed(resp)
+	return CheckpointRemoveResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/client.go b/vendor/github.com/moby/moby/client/client.go
new file mode 100644
index 000000000..89ba88ee5
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/client.go
@@ -0,0 +1,455 @@
+/*
+Package client is a Go client for the Docker Engine API.
+
+For more information about the Engine API, see the documentation:
+https://docs.docker.com/reference/api/engine/
+
+# Usage
+
+You use the library by constructing a client object using [New]
+and calling methods on it. The client can be configured from environment
+variables by passing the [FromEnv] option. Other options can be configured
+manually by passing any of the available [Opt] options.
+
+For example, to list running containers (the equivalent of "docker ps"):
+
+	package main
+
+	import (
+		"context"
+		"fmt"
+		"log"
+
+		"github.com/moby/moby/client"
+	)
+
+	func main() {
+		// Create a new client that handles common environment variables
+		// for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does
+		// API-version negotiation to allow downgrading the API version
+		// when connecting with an older daemon version.
+		apiClient, err := client.New(client.FromEnv)
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		// List all containers (both stopped and running).
+		result, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{
+			All: true,
+		})
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		// Print each container's ID, status and the image it was created from.
+		fmt.Printf("%s  %-22s  %s\n", "ID", "STATUS", "IMAGE")
+		for _, ctr := range result.Items {
+			fmt.Printf("%s  %-22s  %s\n", ctr.ID, ctr.Status, ctr.Image)
+		}
+	}
+*/
+package client
+
+import (
+	"context"
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"net"
+	"net/http"
+	"net/url"
+	"path"
+	"runtime"
+	"slices"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/docker/go-connections/sockets"
+	"github.com/moby/moby/client/internal/mod"
+	"github.com/moby/moby/client/pkg/versions"
+	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
+)
+
+// DummyHost is a hostname used for local communication.
+//
+// It acts as a valid formatted hostname for local connections (such as "unix://"
+// or "npipe://") which do not require a hostname. It should never be resolved,
+// but uses the special-purpose ".localhost" TLD (as defined in [RFC 2606, Section 2]
+// and [RFC 6761, Section 6.3]).
+//
+// [RFC 7230, Section 5.4] defines that an empty header must be used for such
+// cases:
+//
+//	If the authority component is missing or undefined for the target URI,
+//	then a client MUST send a Host header field with an empty field-value.
+//
+// However, [Go stdlib] enforces the semantics of HTTP(S) over TCP, does not
+// allow an empty header to be used, and requires req.URL.Scheme to be either
+// "http" or "https".
+//
+// For further details, refer to:
+//
+//   - https://github.com/docker/engine-api/issues/189
+//   - https://github.com/golang/go/issues/13624
+//   - https://github.com/golang/go/issues/61076
+//   - https://github.com/moby/moby/issues/45935
+//
+// [RFC 2606, Section 2]: https://www.rfc-editor.org/rfc/rfc2606.html#section-2
+// [RFC 6761, Section 6.3]: https://www.rfc-editor.org/rfc/rfc6761#section-6.3
+// [RFC 7230, Section 5.4]: https://datatracker.ietf.org/doc/html/rfc7230#section-5.4
+// [Go stdlib]: https://github.com/golang/go/blob/6244b1946bc2101b01955468f1be502dbadd6807/src/net/http/transport.go#L558-L569
+const DummyHost = "api.moby.localhost"
+
+// MaxAPIVersion is the highest REST API version supported by the client.
+// If API-version negotiation is enabled, the client may downgrade its API version.
+// Similarly, the [WithAPIVersion] and [WithAPIVersionFromEnv] options allow
+// overriding the version and disable API-version negotiation.
+//
+// This version may be lower than the version of the api library module used.
+const MaxAPIVersion = "1.54"
+
+// MinAPIVersion is the minimum API version supported by the client. API versions
+// below this version are not considered when performing API-version negotiation.
+const MinAPIVersion = "1.40"
+
+// defaultUserAgent returns the default User-Agent to use if none is set.
+// It defaults to "moby-client/<module version> os/arch"
+var defaultUserAgent = sync.OnceValue(userAgent)
+
+// Ensure that Client always implements APIClient.
+var _ APIClient = &Client{}
+
+// Client is the API client that performs all operations
+// against a docker server.
+type Client struct {
+	clientConfig
+
+	// negotiated indicates that API version negotiation took place
+	negotiated atomic.Bool
+
+	// negotiateLock is used to single-flight the version negotiation process
+	negotiateLock sync.Mutex
+
+	// When the client transport is an *http.Transport (default) we need to do some extra things (like closing idle connections).
+	// Store the original transport as the http.Client transport will be wrapped with tracing libs.
+	baseTransport *http.Transport
+}
+
+// ErrRedirect is the error returned by checkRedirect when the request is non-GET.
+var ErrRedirect = errors.New("unexpected redirect in response")
+
+// CheckRedirect specifies the policy for dealing with redirect responses. It
+// can be set on [http.Client.CheckRedirect] to prevent HTTP redirects for
+// non-GET requests. It returns an [ErrRedirect] for non-GET request, otherwise
+// returns a [http.ErrUseLastResponse], which is special-cased by http.Client
+// to use the last response.
+//
+// Go 1.8 changed behavior for HTTP redirects (specifically 301, 307, and 308)
+// in the client. The client (and by extension API client) can be made to send
+// a request like "POST /containers//start" where what would normally be in the
+// name section of the URL is empty. This triggers an HTTP 301 from the daemon.
+//
+// In go 1.8 this 301 is converted to a GET request, and ends up getting
+// a 404 from the daemon. This behavior change manifests in the client in that
+// before, the 301 was not followed and the client did not generate an error,
+// but now results in a message like "Error response from daemon: page not found".
+func CheckRedirect(_ *http.Request, via []*http.Request) error {
+	if via[0].Method == http.MethodGet {
+		return http.ErrUseLastResponse
+	}
+	return ErrRedirect
+}
+
+// NewClientWithOpts initializes a new API client.
+//
+// Deprecated: use [New]. This function will be removed in the next release.
+//
+//go:fix inline
+func NewClientWithOpts(ops ...Opt) (*Client, error) {
+	return New(ops...)
+}
+
+// New initializes a new API client with a default HTTPClient, and
+// default API host and version. It also initializes the custom HTTP headers to
+// add to each request.
+//
+// It takes an optional list of [Opt] functional arguments, which are applied in
+// the order they're provided, which allows modifying the defaults when creating
+// the client. For example, the following initializes a client that configures
+// itself with values from environment variables ([FromEnv]).
+//
+// By default, the client automatically negotiates the API version to use when
+// making requests. API version negotiation is performed on the first request;
+// subsequent requests do not re-negotiate. Use [WithAPIVersion] or
+// [WithAPIVersionFromEnv] to configure the client with a fixed API version
+// and disable API version negotiation.
+//
+//	cli, err := client.New(client.FromEnv)
+func New(ops ...Opt) (*Client, error) {
+	hostURL, err := ParseHostURL(DefaultDockerHost)
+	if err != nil {
+		return nil, err
+	}
+
+	client, err := defaultHTTPClient(hostURL)
+	if err != nil {
+		return nil, err
+	}
+	c := &Client{
+		clientConfig: clientConfig{
+			host:    DefaultDockerHost,
+			version: MaxAPIVersion,
+			client:  client,
+			proto:   hostURL.Scheme,
+			addr:    hostURL.Host,
+			traceOpts: []otelhttp.Option{
+				otelhttp.WithSpanNameFormatter(func(_ string, req *http.Request) string {
+					return req.Method + " " + req.URL.Path
+				}),
+			},
+		},
+	}
+	cfg := &c.clientConfig
+
+	for _, op := range ops {
+		if op == nil {
+			continue
+		}
+		if err := op(cfg); err != nil {
+			return nil, err
+		}
+	}
+
+	if cfg.envAPIVersion != "" {
+		c.setAPIVersion(cfg.envAPIVersion)
+	} else if cfg.manualAPIVersion != "" {
+		c.setAPIVersion(cfg.manualAPIVersion)
+	}
+
+	if tr, ok := c.client.Transport.(*http.Transport); ok {
+		// Store the base transport before we wrap it in tracing libs below
+		// This is used, as an example, to close idle connections when the client is closed
+		c.baseTransport = tr
+	}
+
+	if c.scheme == "" {
+		// TODO(stevvooe): This isn't really the right way to write clients in Go.
+		// `NewClient` should probably only take an `*http.Client` and work from there.
+		// Unfortunately, the model of having a host-ish/url-thingy as the connection
+		// string has us confusing protocol and transport layers. We continue doing
+		// this to avoid breaking existing clients but this should be addressed.
+		if c.tlsConfig() != nil {
+			c.scheme = "https"
+		} else {
+			c.scheme = "http"
+		}
+	}
+
+	c.client.Transport = otelhttp.NewTransport(c.client.Transport, c.traceOpts...)
+
+	if len(cfg.responseHooks) > 0 {
+		c.client.Transport = &responseHookTransport{
+			base:  c.client.Transport,
+			hooks: slices.Clone(cfg.responseHooks),
+		}
+	}
+
+	return c, nil
+}
+
+func (cli *Client) tlsConfig() *tls.Config {
+	if cli.baseTransport == nil {
+		return nil
+	}
+	return cli.baseTransport.TLSClientConfig
+}
+
+func defaultHTTPClient(hostURL *url.URL) (*http.Client, error) {
+	transport := &http.Transport{}
+	// Necessary to prevent long-lived processes using the
+	// client from leaking connections due to idle connections
+	// not being released.
+	// TODO: see if we can also address this from the server side,
+	// or in go-connections.
+	// see: https://github.com/moby/moby/issues/45539
+	transport.MaxIdleConns = 6
+	transport.IdleConnTimeout = 30 * time.Second
+	err := sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host)
+	if err != nil {
+		return nil, err
+	}
+	return &http.Client{
+		Transport:     transport,
+		CheckRedirect: CheckRedirect,
+	}, nil
+}
+
+// Close the transport used by the client
+func (cli *Client) Close() error {
+	if cli.baseTransport != nil {
+		cli.baseTransport.CloseIdleConnections()
+		return nil
+	}
+	return nil
+}
+
+// checkVersion manually triggers API version negotiation (if configured).
+// This allows for version-dependent code to use the same version as will
+// be negotiated when making the actual requests, and for which cases
+// we cannot do the negotiation lazily.
+func (cli *Client) checkVersion(ctx context.Context) error {
+	if cli.negotiated.Load() {
+		return nil
+	}
+	_, err := cli.Ping(ctx, PingOptions{
+		NegotiateAPIVersion: true,
+	})
+	return err
+}
+
+// getAPIPath returns the versioned request path to call the API.
+// It appends the query parameters to the path if they are not empty.
+func (cli *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
+	var apiPath string
+	_ = cli.checkVersion(ctx)
+	if cli.version != "" {
+		apiPath = path.Join(cli.basePath, "/v"+strings.TrimPrefix(cli.version, "v"), p)
+	} else {
+		apiPath = path.Join(cli.basePath, p)
+	}
+	return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String()
+}
+
+// ClientVersion returns the API version used by this client.
+func (cli *Client) ClientVersion() string {
+	return cli.version
+}
+
+// negotiateAPIVersion updates the version to match the API version from
+// the ping response.
+//
+// It returns an error if version is invalid, or lower than the minimum
+// supported API version in which case the client's API version is not
+// updated, and negotiation is not marked as completed.
+func (cli *Client) negotiateAPIVersion(pingVersion string) error {
+	var err error
+	pingVersion, err = parseAPIVersion(pingVersion)
+	if err != nil {
+		return err
+	}
+
+	if versions.LessThan(pingVersion, MinAPIVersion) {
+		return cerrdefs.ErrInvalidArgument.WithMessage(fmt.Sprintf("API version %s is not supported by this client: the minimum supported API version is %s", pingVersion, MinAPIVersion))
+	}
+
+	// if the client is not initialized with a version, start with the latest supported version
+	negotiatedVersion := cli.version
+	if negotiatedVersion == "" {
+		negotiatedVersion = MaxAPIVersion
+	}
+
+	// if server version is lower than the client version, downgrade
+	if versions.LessThan(pingVersion, negotiatedVersion) {
+		negotiatedVersion = pingVersion
+	}
+
+	// Store the results, so that automatic API version negotiation (if enabled)
+	// won't be performed on the next request.
+	cli.setAPIVersion(negotiatedVersion)
+	return nil
+}
+
+// setAPIVersion sets the client's API version and marks API version negotiation
+// as completed, so that automatic API version negotiation (if enabled) won't
+// be performed on the next request.
+func (cli *Client) setAPIVersion(version string) {
+	cli.version = version
+	cli.negotiated.Store(true)
+}
+
+// DaemonHost returns the host address used by the client
+func (cli *Client) DaemonHost() string {
+	return cli.host
+}
+
+// ParseHostURL parses a url string, validates the string is a host url, and
+// returns the parsed URL
+func ParseHostURL(host string) (*url.URL, error) {
+	proto, addr, ok := strings.Cut(host, "://")
+	if !ok || addr == "" {
+		return nil, fmt.Errorf("unable to parse docker host `%s`", host)
+	}
+
+	var basePath string
+	if proto == "tcp" {
+		parsed, err := url.Parse("tcp://" + addr)
+		if err != nil {
+			return nil, err
+		}
+		addr = parsed.Host
+		basePath = parsed.Path
+	}
+	return &url.URL{
+		Scheme: proto,
+		Host:   addr,
+		Path:   basePath,
+	}, nil
+}
+
+func (cli *Client) dialerFromTransport() func(context.Context, string, string) (net.Conn, error) {
+	if cli.baseTransport == nil || cli.baseTransport.DialContext == nil {
+		return nil
+	}
+
+	if cli.baseTransport.TLSClientConfig != nil {
+		// When using a tls config we don't use the configured dialer but instead a fallback dialer...
+		// Note: It seems like this should use the normal dialer and wrap the returned net.Conn in a tls.Conn
+		// I honestly don't know why it doesn't do that, but it doesn't and such a change is entirely unrelated to the change in this commit.
+		return nil
+	}
+	return cli.baseTransport.DialContext
+}
+
+// Dialer returns a dialer for a raw stream connection, with an HTTP/1.1 header,
+// that can be used for proxying the daemon connection. It is used by
+// ["docker dial-stdio"].
+//
+// ["docker dial-stdio"]: https://github.com/docker/cli/pull/1014
+func (cli *Client) Dialer() func(context.Context) (net.Conn, error) {
+	return cli.dialer()
+}
+
+func (cli *Client) dialer() func(context.Context) (net.Conn, error) {
+	return func(ctx context.Context) (net.Conn, error) {
+		if dialFn := cli.dialerFromTransport(); dialFn != nil {
+			return dialFn(ctx, cli.proto, cli.addr)
+		}
+		switch cli.proto {
+		case "unix":
+			return net.Dial(cli.proto, cli.addr)
+		case "npipe":
+			ctx, cancel := context.WithTimeout(ctx, 32*time.Second)
+			defer cancel()
+			return dialPipeContext(ctx, cli.addr)
+		default:
+			if tlsConfig := cli.tlsConfig(); tlsConfig != nil {
+				return tls.Dial(cli.proto, cli.addr, tlsConfig)
+			}
+			return net.Dial(cli.proto, cli.addr)
+		}
+	}
+}
+
+func userAgent() string {
+	const defaultVersion = "v0.0.0+unknown"
+	const moduleName = "github.com/moby/moby/client"
+
+	version := defaultVersion
+	if v := mod.Version(moduleName); v != "" {
+		version = v
+	}
+	return "moby-client/" + version + " " + runtime.GOOS + "/" + runtime.GOARCH
+}
diff --git a/vendor/github.com/moby/moby/client/client_interfaces.go b/vendor/github.com/moby/moby/client/client_interfaces.go
new file mode 100644
index 000000000..4bbd45a6e
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/client_interfaces.go
@@ -0,0 +1,242 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net"
+)
+
+// APIClient is an interface that clients that talk with a docker server must implement.
+type APIClient interface {
+	stableAPIClient
+	CheckpointAPIClient // CheckpointAPIClient is still experimental.
+}
+
+type stableAPIClient interface {
+	ConfigAPIClient
+	ContainerAPIClient
+	DistributionAPIClient
+	RegistrySearchClient
+	ExecAPIClient
+	ImageBuildAPIClient
+	ImageAPIClient
+	NetworkAPIClient
+	PluginAPIClient
+	SystemAPIClient
+	VolumeAPIClient
+	ClientVersion() string
+	DaemonHost() string
+	ServerVersion(ctx context.Context, options ServerVersionOptions) (ServerVersionResult, error)
+	HijackDialer
+	Dialer() func(context.Context) (net.Conn, error)
+	Close() error
+	SwarmManagementAPIClient
+}
+
+// SwarmManagementAPIClient defines all methods for managing Swarm-specific
+// objects.
+type SwarmManagementAPIClient interface {
+	SwarmAPIClient
+	NodeAPIClient
+	ServiceAPIClient
+	TaskAPIClient
+	SecretAPIClient
+	ConfigAPIClient
+}
+
+// HijackDialer defines methods for a hijack dialer.
+type HijackDialer interface {
+	DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error)
+}
+
+// CheckpointAPIClient defines API client methods for the checkpoints.
+//
+// Experimental: checkpoint and restore is still an experimental feature,
+// and only available if the daemon is running with experimental features
+// enabled.
+type CheckpointAPIClient interface {
+	CheckpointCreate(ctx context.Context, container string, options CheckpointCreateOptions) (CheckpointCreateResult, error)
+	CheckpointRemove(ctx context.Context, container string, options CheckpointRemoveOptions) (CheckpointRemoveResult, error)
+	CheckpointList(ctx context.Context, container string, options CheckpointListOptions) (CheckpointListResult, error)
+}
+
+// ContainerAPIClient defines API client methods for the containers
+type ContainerAPIClient interface {
+	ContainerCreate(ctx context.Context, options ContainerCreateOptions) (ContainerCreateResult, error)
+	ContainerInspect(ctx context.Context, container string, options ContainerInspectOptions) (ContainerInspectResult, error)
+	ContainerList(ctx context.Context, options ContainerListOptions) (ContainerListResult, error)
+	ContainerUpdate(ctx context.Context, container string, updateConfig ContainerUpdateOptions) (ContainerUpdateResult, error)
+	ContainerRemove(ctx context.Context, container string, options ContainerRemoveOptions) (ContainerRemoveResult, error)
+	ContainerPrune(ctx context.Context, opts ContainerPruneOptions) (ContainerPruneResult, error)
+
+	ContainerLogs(ctx context.Context, container string, options ContainerLogsOptions) (ContainerLogsResult, error)
+
+	ContainerStart(ctx context.Context, container string, options ContainerStartOptions) (ContainerStartResult, error)
+	ContainerStop(ctx context.Context, container string, options ContainerStopOptions) (ContainerStopResult, error)
+	ContainerRestart(ctx context.Context, container string, options ContainerRestartOptions) (ContainerRestartResult, error)
+	ContainerPause(ctx context.Context, container string, options ContainerPauseOptions) (ContainerPauseResult, error)
+	ContainerUnpause(ctx context.Context, container string, options ContainerUnpauseOptions) (ContainerUnpauseResult, error)
+	ContainerWait(ctx context.Context, container string, options ContainerWaitOptions) ContainerWaitResult
+	ContainerKill(ctx context.Context, container string, options ContainerKillOptions) (ContainerKillResult, error)
+
+	ContainerRename(ctx context.Context, container string, options ContainerRenameOptions) (ContainerRenameResult, error)
+	ContainerResize(ctx context.Context, container string, options ContainerResizeOptions) (ContainerResizeResult, error)
+	ContainerAttach(ctx context.Context, container string, options ContainerAttachOptions) (ContainerAttachResult, error)
+	ContainerCommit(ctx context.Context, container string, options ContainerCommitOptions) (ContainerCommitResult, error)
+	ContainerDiff(ctx context.Context, container string, options ContainerDiffOptions) (ContainerDiffResult, error)
+	ContainerExport(ctx context.Context, container string, options ContainerExportOptions) (ContainerExportResult, error)
+
+	ContainerStats(ctx context.Context, container string, options ContainerStatsOptions) (ContainerStatsResult, error)
+	ContainerTop(ctx context.Context, container string, options ContainerTopOptions) (ContainerTopResult, error)
+
+	ContainerStatPath(ctx context.Context, container string, options ContainerStatPathOptions) (ContainerStatPathResult, error)
+	CopyFromContainer(ctx context.Context, container string, options CopyFromContainerOptions) (CopyFromContainerResult, error)
+	CopyToContainer(ctx context.Context, container string, options CopyToContainerOptions) (CopyToContainerResult, error)
+}
+
+type ExecAPIClient interface {
+	ExecCreate(ctx context.Context, container string, options ExecCreateOptions) (ExecCreateResult, error)
+	ExecInspect(ctx context.Context, execID string, options ExecInspectOptions) (ExecInspectResult, error)
+	ExecResize(ctx context.Context, execID string, options ExecResizeOptions) (ExecResizeResult, error)
+
+	ExecStart(ctx context.Context, execID string, options ExecStartOptions) (ExecStartResult, error)
+	ExecAttach(ctx context.Context, execID string, options ExecAttachOptions) (ExecAttachResult, error)
+}
+
+// DistributionAPIClient defines API client methods for the registry
+type DistributionAPIClient interface {
+	DistributionInspect(ctx context.Context, image string, options DistributionInspectOptions) (DistributionInspectResult, error)
+}
+
+type RegistrySearchClient interface {
+	ImageSearch(ctx context.Context, term string, options ImageSearchOptions) (ImageSearchResult, error)
+}
+
+// ImageBuildAPIClient defines API client methods for building images
+// using the REST API.
+type ImageBuildAPIClient interface {
+	ImageBuild(ctx context.Context, context io.Reader, options ImageBuildOptions) (ImageBuildResult, error)
+	BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (BuildCachePruneResult, error)
+	BuildCancel(ctx context.Context, id string, opts BuildCancelOptions) (BuildCancelResult, error)
+}
+
+// ImageAPIClient defines API client methods for the images
+type ImageAPIClient interface {
+	ImageImport(ctx context.Context, source ImageImportSource, ref string, options ImageImportOptions) (ImageImportResult, error)
+
+	ImageList(ctx context.Context, options ImageListOptions) (ImageListResult, error)
+	ImagePull(ctx context.Context, ref string, options ImagePullOptions) (ImagePullResponse, error)
+	ImagePush(ctx context.Context, ref string, options ImagePushOptions) (ImagePushResponse, error)
+	ImageRemove(ctx context.Context, image string, options ImageRemoveOptions) (ImageRemoveResult, error)
+	ImageTag(ctx context.Context, options ImageTagOptions) (ImageTagResult, error)
+	ImagePrune(ctx context.Context, opts ImagePruneOptions) (ImagePruneResult, error)
+
+	ImageInspect(ctx context.Context, image string, _ ...ImageInspectOption) (ImageInspectResult, error)
+	ImageHistory(ctx context.Context, image string, _ ...ImageHistoryOption) (ImageHistoryResult, error)
+
+	ImageLoad(ctx context.Context, input io.Reader, _ ...ImageLoadOption) (ImageLoadResult, error)
+	ImageSave(ctx context.Context, images []string, _ ...ImageSaveOption) (ImageSaveResult, error)
+}
+
+// NetworkAPIClient defines API client methods for the networks
+type NetworkAPIClient interface {
+	NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (NetworkCreateResult, error)
+	NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (NetworkInspectResult, error)
+	NetworkList(ctx context.Context, options NetworkListOptions) (NetworkListResult, error)
+	NetworkRemove(ctx context.Context, network string, options NetworkRemoveOptions) (NetworkRemoveResult, error)
+	NetworkPrune(ctx context.Context, opts NetworkPruneOptions) (NetworkPruneResult, error)
+
+	NetworkConnect(ctx context.Context, network string, options NetworkConnectOptions) (NetworkConnectResult, error)
+	NetworkDisconnect(ctx context.Context, network string, options NetworkDisconnectOptions) (NetworkDisconnectResult, error)
+}
+
+// NodeAPIClient defines API client methods for the nodes
+type NodeAPIClient interface {
+	NodeInspect(ctx context.Context, nodeID string, options NodeInspectOptions) (NodeInspectResult, error)
+	NodeList(ctx context.Context, options NodeListOptions) (NodeListResult, error)
+	NodeUpdate(ctx context.Context, nodeID string, options NodeUpdateOptions) (NodeUpdateResult, error)
+	NodeRemove(ctx context.Context, nodeID string, options NodeRemoveOptions) (NodeRemoveResult, error)
+}
+
+// PluginAPIClient defines API client methods for the plugins
+type PluginAPIClient interface {
+	PluginCreate(ctx context.Context, createContext io.Reader, options PluginCreateOptions) (PluginCreateResult, error)
+	PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (PluginInstallResult, error)
+	PluginInspect(ctx context.Context, name string, options PluginInspectOptions) (PluginInspectResult, error)
+	PluginList(ctx context.Context, options PluginListOptions) (PluginListResult, error)
+	PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) (PluginRemoveResult, error)
+
+	PluginEnable(ctx context.Context, name string, options PluginEnableOptions) (PluginEnableResult, error)
+	PluginDisable(ctx context.Context, name string, options PluginDisableOptions) (PluginDisableResult, error)
+	PluginUpgrade(ctx context.Context, name string, options PluginUpgradeOptions) (PluginUpgradeResult, error)
+	PluginPush(ctx context.Context, name string, options PluginPushOptions) (PluginPushResult, error)
+	PluginSet(ctx context.Context, name string, options PluginSetOptions) (PluginSetResult, error)
+}
+
+// ServiceAPIClient defines API client methods for the services
+type ServiceAPIClient interface {
+	ServiceCreate(ctx context.Context, options ServiceCreateOptions) (ServiceCreateResult, error)
+	ServiceInspect(ctx context.Context, serviceID string, options ServiceInspectOptions) (ServiceInspectResult, error)
+	ServiceList(ctx context.Context, options ServiceListOptions) (ServiceListResult, error)
+	ServiceUpdate(ctx context.Context, serviceID string, options ServiceUpdateOptions) (ServiceUpdateResult, error)
+	ServiceRemove(ctx context.Context, serviceID string, options ServiceRemoveOptions) (ServiceRemoveResult, error)
+
+	ServiceLogs(ctx context.Context, serviceID string, options ServiceLogsOptions) (ServiceLogsResult, error)
+}
+
+// TaskAPIClient defines API client methods to manage swarm tasks.
+type TaskAPIClient interface {
+	TaskInspect(ctx context.Context, taskID string, options TaskInspectOptions) (TaskInspectResult, error)
+	TaskList(ctx context.Context, options TaskListOptions) (TaskListResult, error)
+
+	TaskLogs(ctx context.Context, taskID string, options TaskLogsOptions) (TaskLogsResult, error)
+}
+
+// SwarmAPIClient defines API client methods for the swarm
+type SwarmAPIClient interface {
+	SwarmInit(ctx context.Context, options SwarmInitOptions) (SwarmInitResult, error)
+	SwarmJoin(ctx context.Context, options SwarmJoinOptions) (SwarmJoinResult, error)
+	SwarmInspect(ctx context.Context, options SwarmInspectOptions) (SwarmInspectResult, error)
+	SwarmUpdate(ctx context.Context, options SwarmUpdateOptions) (SwarmUpdateResult, error)
+	SwarmLeave(ctx context.Context, options SwarmLeaveOptions) (SwarmLeaveResult, error)
+
+	SwarmGetUnlockKey(ctx context.Context) (SwarmGetUnlockKeyResult, error)
+	SwarmUnlock(ctx context.Context, options SwarmUnlockOptions) (SwarmUnlockResult, error)
+}
+
+// SystemAPIClient defines API client methods for the system
+type SystemAPIClient interface {
+	Events(ctx context.Context, options EventsListOptions) EventsResult
+	Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error)
+	RegistryLogin(ctx context.Context, auth RegistryLoginOptions) (RegistryLoginResult, error)
+	DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error)
+	Ping(ctx context.Context, options PingOptions) (PingResult, error)
+}
+
+// VolumeAPIClient defines API client methods for the volumes
+type VolumeAPIClient interface {
+	VolumeCreate(ctx context.Context, options VolumeCreateOptions) (VolumeCreateResult, error)
+	VolumeInspect(ctx context.Context, volumeID string, options VolumeInspectOptions) (VolumeInspectResult, error)
+	VolumeList(ctx context.Context, options VolumeListOptions) (VolumeListResult, error)
+	VolumeUpdate(ctx context.Context, volumeID string, options VolumeUpdateOptions) (VolumeUpdateResult, error)
+	VolumeRemove(ctx context.Context, volumeID string, options VolumeRemoveOptions) (VolumeRemoveResult, error)
+	VolumePrune(ctx context.Context, options VolumePruneOptions) (VolumePruneResult, error)
+}
+
+// SecretAPIClient defines API client methods for secrets
+type SecretAPIClient interface {
+	SecretCreate(ctx context.Context, options SecretCreateOptions) (SecretCreateResult, error)
+	SecretInspect(ctx context.Context, id string, options SecretInspectOptions) (SecretInspectResult, error)
+	SecretList(ctx context.Context, options SecretListOptions) (SecretListResult, error)
+	SecretUpdate(ctx context.Context, id string, options SecretUpdateOptions) (SecretUpdateResult, error)
+	SecretRemove(ctx context.Context, id string, options SecretRemoveOptions) (SecretRemoveResult, error)
+}
+
+// ConfigAPIClient defines API client methods for configs
+type ConfigAPIClient interface {
+	ConfigCreate(ctx context.Context, options ConfigCreateOptions) (ConfigCreateResult, error)
+	ConfigInspect(ctx context.Context, id string, options ConfigInspectOptions) (ConfigInspectResult, error)
+	ConfigList(ctx context.Context, options ConfigListOptions) (ConfigListResult, error)
+	ConfigUpdate(ctx context.Context, id string, options ConfigUpdateOptions) (ConfigUpdateResult, error)
+	ConfigRemove(ctx context.Context, id string, options ConfigRemoveOptions) (ConfigRemoveResult, error)
+}
diff --git a/vendor/github.com/moby/moby/client/client_options.go b/vendor/github.com/moby/moby/client/client_options.go
new file mode 100644
index 000000000..399255723
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/client_options.go
@@ -0,0 +1,427 @@
+package client
+
+import (
+	"context"
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"net"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/docker/go-connections/sockets"
+	"github.com/docker/go-connections/tlsconfig"
+	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
+	"go.opentelemetry.io/otel/trace"
+)
+
+type clientConfig struct {
+	// scheme sets the scheme for the client
+	scheme string
+	// host holds the server address to connect to
+	host string
+	// proto holds the client protocol i.e. unix.
+	proto string
+	// addr holds the client address.
+	addr string
+	// basePath holds the path to prepend to the requests.
+	basePath string
+	// client used to send and receive http requests.
+	client *http.Client
+	// version of the server to talk to.
+	version string
+	// userAgent is the User-Agent header to use for HTTP requests. It takes
+	// precedence over User-Agent headers set in customHTTPHeaders, and other
+	// header variables. When set to an empty string, the User-Agent header
+	// is removed, and no header is sent.
+	userAgent *string
+	// custom HTTP headers configured by users.
+	customHTTPHeaders map[string]string
+
+	// manualAPIVersion contains the API version set by users. This field
+	// will only be non-empty if a valid-formed version was set through
+	// [WithAPIVersion].
+	//
+	// If both manualAPIVersion and envAPIVersion are set, manualAPIVersion
+	// takes precedence. Either field disables API-version negotiation.
+	manualAPIVersion string
+
+	// envAPIVersion contains the API version set by users. This field
+	// will only be non-empty if a valid-formed version was set through
+	// [WithAPIVersionFromEnv].
+	//
+	// If both manualAPIVersion and envAPIVersion are set, manualAPIVersion
+	// takes precedence. Either field disables API-version negotiation.
+	envAPIVersion string
+
+	// responseHooks is a list of custom response hooks to call on responses.
+	responseHooks []ResponseHook
+
+	// traceOpts is a list of options to configure the tracing span.
+	traceOpts []otelhttp.Option
+}
+
+// ResponseHook is called for each HTTP response returned by the daemon.
+// Hooks are invoked in the order they were added.
+//
+// Hooks must not read or close resp.Body.
+type ResponseHook func(*http.Response)
+
+// Opt is a configuration option to initialize a [Client].
+type Opt func(*clientConfig) error
+
+// FromEnv configures the client with values from environment variables. It
+// is the equivalent of using the [WithTLSClientConfigFromEnv], [WithHostFromEnv],
+// and [WithAPIVersionFromEnv] options.
+//
+// FromEnv uses the following environment variables:
+//
+//   - DOCKER_HOST ([EnvOverrideHost]) to set the URL to the docker server.
+//   - DOCKER_API_VERSION ([EnvOverrideAPIVersion]) to set the version of the
+//     API to use, leave empty for latest.
+//   - DOCKER_CERT_PATH ([EnvOverrideCertPath]) to specify the directory from
+//     which to load the TLS certificates ("ca.pem", "cert.pem", "key.pem').
+//   - DOCKER_TLS_VERIFY ([EnvTLSVerify]) to enable or disable TLS verification
+//     (off by default).
+func FromEnv(c *clientConfig) error {
+	ops := []Opt{
+		WithTLSClientConfigFromEnv(),
+		WithHostFromEnv(),
+		WithAPIVersionFromEnv(),
+	}
+	for _, op := range ops {
+		if err := op(c); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// WithDialContext applies the dialer to the client transport. This can be
+// used to set the Timeout and KeepAlive settings of the client. It returns
+// an error if the client does not have a [http.Transport] configured.
+func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) Opt {
+	return func(c *clientConfig) error {
+		if transport, ok := c.client.Transport.(*http.Transport); ok {
+			transport.DialContext = dialContext
+			return nil
+		}
+		return fmt.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
+	}
+}
+
+// WithHost overrides the client host with the specified one.
+func WithHost(host string) Opt {
+	return func(c *clientConfig) error {
+		hostURL, err := ParseHostURL(host)
+		if err != nil {
+			return err
+		}
+		c.host = host
+		c.proto = hostURL.Scheme
+		c.addr = hostURL.Host
+		c.basePath = hostURL.Path
+		if transport, ok := c.client.Transport.(*http.Transport); ok {
+			return sockets.ConfigureTransport(transport, c.proto, c.addr)
+		}
+		// For test transports, we skip transport configuration but still
+		// set the host fields so that the client can use them for headers
+		if _, ok := c.client.Transport.(testRoundTripper); ok {
+			return nil
+		}
+		return fmt.Errorf("cannot apply host to transport: %T", c.client.Transport)
+	}
+}
+
+// testRoundTripper allows us to inject a mock-transport for testing. We define it
+// here so we can detect the tlsconfig and return nil for only this type.
+type testRoundTripper func(*http.Request) (*http.Response, error)
+
+func (tf testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
+	return tf(req)
+}
+
+// WithHostFromEnv overrides the client host with the host specified in the
+// DOCKER_HOST ([EnvOverrideHost]) environment variable. If DOCKER_HOST is not set,
+// or set to an empty value, the host is not modified.
+func WithHostFromEnv() Opt {
+	return func(c *clientConfig) error {
+		if host := os.Getenv(EnvOverrideHost); host != "" {
+			return WithHost(host)(c)
+		}
+		return nil
+	}
+}
+
+// WithHTTPClient overrides the client's HTTP client with the specified one.
+func WithHTTPClient(client *http.Client) Opt {
+	return func(c *clientConfig) error {
+		if client != nil {
+			// Make a clone of client so modifications do not affect
+			// the caller's client. Clone here instead of in New()
+			// as other options (WithHost) also mutate c.client.
+			// Cloned clients share the same CookieJar as the
+			// original.
+			hc := *client
+			if ht, ok := hc.Transport.(*http.Transport); ok {
+				hc.Transport = ht.Clone()
+			}
+			c.client = &hc
+		}
+		return nil
+	}
+}
+
+// WithTimeout configures the time limit for requests made by the HTTP client.
+func WithTimeout(timeout time.Duration) Opt {
+	return func(c *clientConfig) error {
+		c.client.Timeout = timeout
+		return nil
+	}
+}
+
+// WithUserAgent configures the User-Agent header to use for HTTP requests.
+// It overrides any User-Agent set in headers. When set to an empty string,
+// the User-Agent header is removed, and no header is sent.
+func WithUserAgent(ua string) Opt {
+	return func(c *clientConfig) error {
+		c.userAgent = &ua
+		return nil
+	}
+}
+
+// WithHTTPHeaders appends custom HTTP headers to the client's default headers.
+// It does not allow overriding built-in headers (such as "User-Agent").
+// Also see [WithUserAgent].
+//
+// It replaces any existing custom headers. Keys are case-insensitive and
+// canonicalized using [http.CanonicalHeaderKey]. If multiple entries map
+// to the same canonical key, a [cerrdefs.ErrInvalidArgument] is returned.
+func WithHTTPHeaders(headers map[string]string) Opt {
+	return func(c *clientConfig) error {
+		c.customHTTPHeaders = make(map[string]string)
+		for k, v := range headers {
+			k = http.CanonicalHeaderKey(k)
+			_, ok := c.customHTTPHeaders[k]
+			if ok {
+				return cerrdefs.ErrInvalidArgument.WithMessage(fmt.Sprintf("duplicate custom HTTP header (%s)", k))
+			}
+			c.customHTTPHeaders[k] = v
+		}
+		return nil
+	}
+}
+
+// WithScheme overrides the client scheme with the specified one.
+func WithScheme(scheme string) Opt {
+	return func(c *clientConfig) error {
+		c.scheme = scheme
+		return nil
+	}
+}
+
+// WithTLSClientConfig configures the client's existing HTTP transport to use TLS.
+// The minimum TLS version is TLS 1.2.
+//
+// If caFile is non-empty, it specifies the CA certificate file to use for
+// server verification, and replaces the system root pool for that verification.
+// If certFile is empty, the system root pool is used.
+//
+// If either certFile or keyFile is set, both must point to readable files
+// containing a valid client certificate and unencrypted private key, or this
+// option returns an error.
+//
+// If both certPath and keyPath are empty, no client certificate is configured.
+// The connection will use TLS without client authentication (i.e., not mTLS).
+func WithTLSClientConfig(caFile, certFile, keyFile string) Opt {
+	return func(c *clientConfig) error {
+		transport, ok := c.client.Transport.(*http.Transport)
+		if !ok {
+			return fmt.Errorf("cannot configure TLS: unsupported HTTP transport %T", c.client.Transport)
+		}
+		config, err := tlsconfig.Client(tlsconfig.Options{
+			CAFile:             caFile,
+			CertFile:           certFile,
+			KeyFile:            keyFile,
+			ExclusiveRootPools: true,
+			MinVersion:         tls.VersionTLS12,
+		})
+		if err != nil {
+			return fmt.Errorf("configure TLS: %w", err)
+		}
+		transport.TLSClientConfig = config
+		return nil
+	}
+}
+
+// WithTLSClientConfigFromEnv configures the client for TLS using the
+// DOCKER_CERT_PATH ([EnvOverrideCertPath]) and DOCKER_TLS_VERIFY
+// ([EnvTLSVerify]) environment variables. The minimum TLS version is TLS 1.2.
+//
+// If DOCKER_CERT_PATH is unset or empty, this option leaves the client
+// unchanged.
+//
+// When DOCKER_CERT_PATH is set, the following files are loaded from that
+// directory:
+//
+//   - "ca.pem" as the CA certificate
+//   - "cert.pem" as the client certificate
+//   - "key.pem" as the client private key
+//
+// These files must exist, be readable, and contain valid TLS material, or this
+// option returns an error. A client certificate is always loaded from "cert.pem"
+// and "key.pem" (mTLS is expected).
+//
+// If DOCKER_TLS_VERIFY is set to a non-empty value, server certificate
+// verification is enabled. In that case, "ca.pem" is added to the system root
+// pool used for verification.
+//
+// If DOCKER_TLS_VERIFY is unset or empty, server certificate verification is
+// disabled.
+func WithTLSClientConfigFromEnv() Opt {
+	return func(c *clientConfig) error {
+		dockerCertPath := os.Getenv(EnvOverrideCertPath)
+		if dockerCertPath == "" {
+			return nil
+		}
+		tlsConfig, err := tlsconfig.Client(tlsconfig.Options{
+			CAFile:             filepath.Join(dockerCertPath, "ca.pem"),
+			CertFile:           filepath.Join(dockerCertPath, "cert.pem"),
+			KeyFile:            filepath.Join(dockerCertPath, "key.pem"),
+			InsecureSkipVerify: os.Getenv(EnvTLSVerify) == "",
+			MinVersion:         tls.VersionTLS12,
+		})
+		if err != nil {
+			return fmt.Errorf("configure TLS from %q: %w", EnvOverrideCertPath+"="+dockerCertPath, err)
+		}
+
+		// FIXME(thaJeztah): unlike WithTLSClientConfig, this option replaces the client's http.Client and transport; consider updating just the transport.
+		c.client = &http.Client{
+			Transport:     &http.Transport{TLSClientConfig: tlsConfig},
+			CheckRedirect: CheckRedirect,
+		}
+		return nil
+	}
+}
+
+// WithAPIVersion overrides the client's API version with the specified one,
+// and disables API version negotiation. If an empty version is provided,
+// this option is ignored to allow version negotiation. The given version
+// should be formatted "<major>.<minor>" (for example, "1.52"). It returns
+// an error if the given value not in the correct format.
+//
+// WithAPIVersion does not validate if the client supports the given version,
+// and callers should verify if the version lower than the maximum supported
+// version as defined by [MaxAPIVersion].
+//
+// [WithAPIVersionFromEnv] takes precedence if [WithAPIVersion] and
+// [WithAPIVersionFromEnv] are both set.
+func WithAPIVersion(version string) Opt {
+	return func(c *clientConfig) error {
+		version = strings.TrimSpace(version)
+		if val := strings.TrimPrefix(version, "v"); val != "" {
+			ver, err := parseAPIVersion(val)
+			if err != nil {
+				return fmt.Errorf("invalid API version (%s): %w", version, err)
+			}
+			c.manualAPIVersion = ver
+		}
+		return nil
+	}
+}
+
+// WithVersion overrides the client version with the specified one.
+//
+// Deprecated: use [WithAPIVersion] instead.
+//
+//go:fix inline
+func WithVersion(version string) Opt {
+	return WithAPIVersion(version)
+}
+
+// WithAPIVersionFromEnv overrides the client version with the version specified in
+// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
+// If DOCKER_API_VERSION is not set, or set to an empty value, the version
+// is not modified.
+//
+// WithAPIVersion does not validate if the client supports the given version,
+// and callers should verify if the version lower than the maximum supported
+// version as defined by [MaxAPIVersion].
+//
+// [WithAPIVersionFromEnv] takes precedence if [WithAPIVersion] and
+// [WithAPIVersionFromEnv] are both set.
+func WithAPIVersionFromEnv() Opt {
+	return func(c *clientConfig) error {
+		version := strings.TrimSpace(os.Getenv(EnvOverrideAPIVersion))
+		if val := strings.TrimPrefix(version, "v"); val != "" {
+			ver, err := parseAPIVersion(val)
+			if err != nil {
+				return fmt.Errorf("invalid API version (%s): %w", version, err)
+			}
+			c.envAPIVersion = ver
+		}
+		return nil
+	}
+}
+
+// WithVersionFromEnv overrides the client version with the version specified in
+// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
+//
+// Deprecated: use [WithAPIVersionFromEnv] instead.
+//
+//go:fix inline
+func WithVersionFromEnv() Opt {
+	return WithAPIVersionFromEnv()
+}
+
+// WithAPIVersionNegotiation enables automatic API version negotiation for the client.
+// With this option enabled, the client automatically negotiates the API version
+// to use when making requests. API version negotiation is performed on the first
+// request; subsequent requests do not re-negotiate.
+//
+// Deprecated: API-version negotiation is now enabled by default and this options
+// is now a no-op.
+//
+// Use [WithAPIVersion] or [WithAPIVersionFromEnv] to set a fixed API version
+// instead of using automatic negotiation.
+func WithAPIVersionNegotiation() Opt {
+	return func(c *clientConfig) error {
+		return nil
+	}
+}
+
+// WithTraceProvider sets the trace provider for the client.
+// If this is not set then the global trace provider is used.
+func WithTraceProvider(provider trace.TracerProvider) Opt {
+	return func(c *clientConfig) error {
+		c.traceOpts = append(c.traceOpts, otelhttp.WithTracerProvider(provider))
+		return nil
+	}
+}
+
+// WithTraceOptions sets tracing span options for the client.
+func WithTraceOptions(opts ...otelhttp.Option) Opt {
+	return func(c *clientConfig) error {
+		c.traceOpts = append(c.traceOpts, opts...)
+		return nil
+	}
+}
+
+// WithResponseHook adds a ResponseHook to the client. ResponseHooks are called
+// for each HTTP response returned by the daemon. Hooks are invoked in the order
+// they were added.
+//
+// Hooks must not read or close resp.Body.
+func WithResponseHook(h ResponseHook) Opt {
+	return func(c *clientConfig) error {
+		if h == nil {
+			return errors.New("invalid response hook: hook is nil")
+		}
+		c.responseHooks = append(c.responseHooks, h)
+		return nil
+	}
+}
diff --git a/vendor/github.com/moby/moby/client/client_responsehook.go b/vendor/github.com/moby/moby/client/client_responsehook.go
new file mode 100644
index 000000000..7c93f111c
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/client_responsehook.go
@@ -0,0 +1,23 @@
+package client
+
+import (
+	"net/http"
+)
+
+type responseHookTransport struct {
+	base  http.RoundTripper
+	hooks []ResponseHook
+}
+
+func (t *responseHookTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+	resp, err := t.base.RoundTrip(req)
+	if err != nil {
+		return resp, err
+	}
+
+	for _, h := range t.hooks {
+		h(resp)
+	}
+
+	return resp, nil
+}
diff --git a/vendor/github.com/moby/moby/client/client_unix.go b/vendor/github.com/moby/moby/client/client_unix.go
new file mode 100644
index 000000000..1fb9fbfb9
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/client_unix.go
@@ -0,0 +1,18 @@
+//go:build !windows
+
+package client
+
+import (
+	"context"
+	"net"
+	"syscall"
+)
+
+// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
+// (EnvOverrideHost) environment variable is unset or empty.
+const DefaultDockerHost = "unix:///var/run/docker.sock"
+
+// dialPipeContext connects to a Windows named pipe. It is not supported on non-Windows.
+func dialPipeContext(_ context.Context, _ string) (net.Conn, error) {
+	return nil, syscall.EAFNOSUPPORT
+}
diff --git a/vendor/github.com/moby/moby/client/client_windows.go b/vendor/github.com/moby/moby/client/client_windows.go
new file mode 100644
index 000000000..b471c0612
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/client_windows.go
@@ -0,0 +1,17 @@
+package client
+
+import (
+	"context"
+	"net"
+
+	"github.com/Microsoft/go-winio"
+)
+
+// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
+// (EnvOverrideHost) environment variable is unset or empty.
+const DefaultDockerHost = "npipe:////./pipe/docker_engine"
+
+// dialPipeContext connects to a Windows named pipe. It is not supported on non-Windows.
+func dialPipeContext(ctx context.Context, addr string) (net.Conn, error) {
+	return winio.DialPipeContext(ctx, addr)
+}
diff --git a/vendor/github.com/moby/moby/client/config_create.go b/vendor/github.com/moby/moby/client/config_create.go
new file mode 100644
index 000000000..874e2c947
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/config_create.go
@@ -0,0 +1,34 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// ConfigCreateOptions holds options for creating a config.
+type ConfigCreateOptions struct {
+	Spec swarm.ConfigSpec
+}
+
+// ConfigCreateResult holds the result from the ConfigCreate method.
+type ConfigCreateResult struct {
+	ID string
+}
+
+// ConfigCreate creates a new config.
+func (cli *Client) ConfigCreate(ctx context.Context, options ConfigCreateOptions) (ConfigCreateResult, error) {
+	resp, err := cli.post(ctx, "/configs/create", nil, options.Spec, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ConfigCreateResult{}, err
+	}
+
+	var out swarm.ConfigCreateResponse
+	err = json.NewDecoder(resp.Body).Decode(&out)
+	if err != nil {
+		return ConfigCreateResult{}, err
+	}
+	return ConfigCreateResult{ID: out.ID}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/config_inspect.go b/vendor/github.com/moby/moby/client/config_inspect.go
new file mode 100644
index 000000000..0bf0ff791
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/config_inspect.go
@@ -0,0 +1,35 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// ConfigInspectOptions holds options for inspecting a config.
+type ConfigInspectOptions struct {
+	// Add future optional parameters here
+}
+
+// ConfigInspectResult holds the result from the ConfigInspect method.
+type ConfigInspectResult struct {
+	Config swarm.Config
+	Raw    json.RawMessage
+}
+
+// ConfigInspect returns the config information with raw data
+func (cli *Client) ConfigInspect(ctx context.Context, id string, options ConfigInspectOptions) (ConfigInspectResult, error) {
+	id, err := trimID("config", id)
+	if err != nil {
+		return ConfigInspectResult{}, err
+	}
+	resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
+	if err != nil {
+		return ConfigInspectResult{}, err
+	}
+
+	var out ConfigInspectResult
+	out.Raw, err = decodeWithRaw(resp, &out.Config)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/config_list.go b/vendor/github.com/moby/moby/client/config_list.go
new file mode 100644
index 000000000..ee5e7fee7
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/config_list.go
@@ -0,0 +1,38 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// ConfigListOptions holds parameters to list configs
+type ConfigListOptions struct {
+	Filters Filters
+}
+
+// ConfigListResult holds the result from the [client.ConfigList] method.
+type ConfigListResult struct {
+	Items []swarm.Config
+}
+
+// ConfigList returns the list of configs.
+func (cli *Client) ConfigList(ctx context.Context, options ConfigListOptions) (ConfigListResult, error) {
+	query := url.Values{}
+	options.Filters.updateURLValues(query)
+
+	resp, err := cli.get(ctx, "/configs", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ConfigListResult{}, err
+	}
+
+	var out ConfigListResult
+	err = json.NewDecoder(resp.Body).Decode(&out.Items)
+	if err != nil {
+		return ConfigListResult{}, err
+	}
+	return out, nil
+}
diff --git a/vendor/github.com/moby/moby/client/config_remove.go b/vendor/github.com/moby/moby/client/config_remove.go
new file mode 100644
index 000000000..5cde5e143
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/config_remove.go
@@ -0,0 +1,27 @@
+package client
+
+import "context"
+
+// ConfigRemoveOptions holds options for [Client.ConfigRemove].
+type ConfigRemoveOptions struct {
+	// Add future optional parameters here
+}
+
+// ConfigRemoveResult holds the result of [Client.ConfigRemove].
+type ConfigRemoveResult struct {
+	// Add future fields here
+}
+
+// ConfigRemove removes a config.
+func (cli *Client) ConfigRemove(ctx context.Context, id string, options ConfigRemoveOptions) (ConfigRemoveResult, error) {
+	id, err := trimID("config", id)
+	if err != nil {
+		return ConfigRemoveResult{}, err
+	}
+	resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ConfigRemoveResult{}, err
+	}
+	return ConfigRemoveResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/config_update.go b/vendor/github.com/moby/moby/client/config_update.go
new file mode 100644
index 000000000..31bdd7956
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/config_update.go
@@ -0,0 +1,33 @@
+package client
+
+import (
+	"context"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// ConfigUpdateOptions holds options for updating a config.
+type ConfigUpdateOptions struct {
+	Version swarm.Version
+	Spec    swarm.ConfigSpec
+}
+
+// ConfigUpdateResult holds the result of [Client.ConfigUpdate].
+type ConfigUpdateResult struct{}
+
+// ConfigUpdate attempts to update a config
+func (cli *Client) ConfigUpdate(ctx context.Context, id string, options ConfigUpdateOptions) (ConfigUpdateResult, error) {
+	id, err := trimID("config", id)
+	if err != nil {
+		return ConfigUpdateResult{}, err
+	}
+	query := url.Values{}
+	query.Set("version", options.Version.String())
+	resp, err := cli.post(ctx, "/configs/"+id+"/update", query, options.Spec, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ConfigUpdateResult{}, err
+	}
+	return ConfigUpdateResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_attach.go b/vendor/github.com/moby/moby/client/container_attach.go
new file mode 100644
index 000000000..ce84122d3
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_attach.go
@@ -0,0 +1,86 @@
+package client
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+)
+
+// ContainerAttachOptions holds parameters to attach to a container.
+type ContainerAttachOptions struct {
+	Stream     bool
+	Stdin      bool
+	Stdout     bool
+	Stderr     bool
+	DetachKeys string
+	Logs       bool
+}
+
+// ContainerAttachResult is the result from attaching to a container.
+type ContainerAttachResult struct {
+	HijackedResponse
+}
+
+// ContainerAttach attaches a connection to a container in the server.
+// It returns a [HijackedResponse] with the hijacked connection
+// and a reader to get output. It's up to the caller to close
+// the hijacked connection by calling [HijackedResponse.Close].
+//
+// The stream format on the response uses one of two formats:
+//
+//   - If the container is using a TTY, there is only a single stream (stdout)
+//     and data is copied directly from the container output stream, no extra
+//     multiplexing or headers.
+//   - If the container is *not* using a TTY, streams for stdout and stderr are
+//     multiplexed.
+//
+// The format of the multiplexed stream is defined in the [stdcopy] package,
+// and as follows:
+//
+//	[8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT}
+//
+// STREAM_TYPE can be 1 for [Stdout] and 2 for [Stderr]. Refer to [stdcopy.StdType]
+// for details. SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded
+// as big endian, this is the size of OUTPUT. You can use [stdcopy.StdCopy]
+// to demultiplex this stream.
+//
+// [stdcopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy
+// [stdcopy.StdCopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdCopy
+// [stdcopy.StdType]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdType
+// [Stdout]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stdout
+// [Stderr]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stderr
+func (cli *Client) ContainerAttach(ctx context.Context, containerID string, options ContainerAttachOptions) (ContainerAttachResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerAttachResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Stream {
+		query.Set("stream", "1")
+	}
+	if options.Stdin {
+		query.Set("stdin", "1")
+	}
+	if options.Stdout {
+		query.Set("stdout", "1")
+	}
+	if options.Stderr {
+		query.Set("stderr", "1")
+	}
+	if options.DetachKeys != "" {
+		query.Set("detachKeys", options.DetachKeys)
+	}
+	if options.Logs {
+		query.Set("logs", "1")
+	}
+
+	hijacked, err := cli.postHijacked(ctx, "/containers/"+containerID+"/attach", query, nil, http.Header{
+		"Content-Type": {"text/plain"},
+	})
+	if err != nil {
+		return ContainerAttachResult{}, err
+	}
+
+	return ContainerAttachResult{HijackedResponse: hijacked}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_commit.go b/vendor/github.com/moby/moby/client/container_commit.go
new file mode 100644
index 000000000..79da44a54
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_commit.go
@@ -0,0 +1,75 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"net/url"
+
+	"github.com/distribution/reference"
+	"github.com/moby/moby/api/types/container"
+)
+
+// ContainerCommitOptions holds parameters to commit changes into a container.
+type ContainerCommitOptions struct {
+	Reference string
+	Comment   string
+	Author    string
+	Changes   []string
+	NoPause   bool // NoPause disables pausing the container during commit.
+	Config    *container.Config
+}
+
+// ContainerCommitResult is the result from committing a container.
+type ContainerCommitResult struct {
+	ID string
+}
+
+// ContainerCommit applies changes to a container and creates a new tagged image.
+func (cli *Client) ContainerCommit(ctx context.Context, containerID string, options ContainerCommitOptions) (ContainerCommitResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerCommitResult{}, err
+	}
+
+	var repository, tag string
+	if options.Reference != "" {
+		ref, err := reference.ParseNormalizedNamed(options.Reference)
+		if err != nil {
+			return ContainerCommitResult{}, err
+		}
+
+		if _, ok := ref.(reference.Digested); ok {
+			return ContainerCommitResult{}, errors.New("refusing to create a tag with a digest reference")
+		}
+		ref = reference.TagNameOnly(ref)
+
+		if tagged, ok := ref.(reference.Tagged); ok {
+			tag = tagged.Tag()
+		}
+		repository = ref.Name()
+	}
+
+	query := url.Values{}
+	query.Set("container", containerID)
+	query.Set("repo", repository)
+	query.Set("tag", tag)
+	query.Set("comment", options.Comment)
+	query.Set("author", options.Author)
+	for _, change := range options.Changes {
+		query.Add("changes", change)
+	}
+	if options.NoPause {
+		query.Set("pause", "0")
+	}
+
+	var response container.CommitResponse
+	resp, err := cli.post(ctx, "/commit", query, options.Config, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerCommitResult{}, err
+	}
+
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	return ContainerCommitResult{ID: response.ID}, err
+}
diff --git a/vendor/github.com/moby/moby/client/container_copy.go b/vendor/github.com/moby/moby/client/container_copy.go
new file mode 100644
index 000000000..b37d1765f
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_copy.go
@@ -0,0 +1,142 @@
+package client
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+	"path/filepath"
+	"strings"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+// ContainerStatPathOptions holds options for [Client.ContainerStatPath].
+type ContainerStatPathOptions struct {
+	Path string
+}
+
+// ContainerStatPathResult holds the result of [Client.ContainerStatPath].
+type ContainerStatPathResult struct {
+	Stat container.PathStat
+}
+
+// ContainerStatPath returns stat information about a path inside the container filesystem.
+func (cli *Client) ContainerStatPath(ctx context.Context, containerID string, options ContainerStatPathOptions) (ContainerStatPathResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerStatPathResult{}, err
+	}
+
+	query := url.Values{}
+	query.Set("path", filepath.ToSlash(options.Path)) // Normalize the paths used in the API.
+
+	resp, err := cli.head(ctx, "/containers/"+containerID+"/archive", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerStatPathResult{}, err
+	}
+	stat, err := getContainerPathStatFromHeader(resp.Header)
+	if err != nil {
+		return ContainerStatPathResult{}, err
+	}
+	return ContainerStatPathResult{Stat: stat}, nil
+}
+
+// CopyToContainerOptions holds information
+// about files to copy into a container
+type CopyToContainerOptions struct {
+	DestinationPath           string
+	Content                   io.Reader
+	AllowOverwriteDirWithFile bool
+	CopyUIDGID                bool
+}
+
+// CopyToContainerResult holds the result of [Client.CopyToContainer].
+type CopyToContainerResult struct{}
+
+// CopyToContainer copies content into the container filesystem.
+// Note that `content` must be a Reader for a TAR archive
+func (cli *Client) CopyToContainer(ctx context.Context, containerID string, options CopyToContainerOptions) (CopyToContainerResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return CopyToContainerResult{}, err
+	}
+
+	query := url.Values{}
+	query.Set("path", filepath.ToSlash(options.DestinationPath)) // Normalize the paths used in the API.
+	// Do not allow for an existing directory to be overwritten by a non-directory and vice versa.
+	if !options.AllowOverwriteDirWithFile {
+		query.Set("noOverwriteDirNonDir", "true")
+	}
+
+	if options.CopyUIDGID {
+		query.Set("copyUIDGID", "true")
+	}
+
+	response, err := cli.putRaw(ctx, "/containers/"+containerID+"/archive", query, options.Content, nil)
+	defer ensureReaderClosed(response)
+	if err != nil {
+		return CopyToContainerResult{}, err
+	}
+
+	return CopyToContainerResult{}, nil
+}
+
+// CopyFromContainerOptions holds options for [Client.CopyFromContainer].
+type CopyFromContainerOptions struct {
+	SourcePath string
+}
+
+// CopyFromContainerResult holds the result of [Client.CopyFromContainer].
+type CopyFromContainerResult struct {
+	Content io.ReadCloser
+	Stat    container.PathStat
+}
+
+// CopyFromContainer gets the content from the container and returns it as a Reader
+// for a TAR archive to manipulate it in the host. It's up to the caller to close the reader.
+func (cli *Client) CopyFromContainer(ctx context.Context, containerID string, options CopyFromContainerOptions) (CopyFromContainerResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return CopyFromContainerResult{}, err
+	}
+
+	query := make(url.Values, 1)
+	query.Set("path", filepath.ToSlash(options.SourcePath)) // Normalize the paths used in the API.
+
+	resp, err := cli.get(ctx, "/containers/"+containerID+"/archive", query, nil)
+	if err != nil {
+		return CopyFromContainerResult{}, err
+	}
+
+	// In order to get the copy behavior right, we need to know information
+	// about both the source and the destination. The response headers include
+	// stat info about the source that we can use in deciding exactly how to
+	// copy it locally. Along with the stat info about the local destination,
+	// we have everything we need to handle the multiple possibilities there
+	// can be when copying a file/dir from one location to another file/dir.
+	stat, err := getContainerPathStatFromHeader(resp.Header)
+	if err != nil {
+		ensureReaderClosed(resp)
+		return CopyFromContainerResult{Stat: stat}, fmt.Errorf("unable to get resource stat from response: %s", err)
+	}
+	return CopyFromContainerResult{Content: resp.Body, Stat: stat}, nil
+}
+
+func getContainerPathStatFromHeader(header http.Header) (container.PathStat, error) {
+	var stat container.PathStat
+
+	encodedStat := header.Get("X-Docker-Container-Path-Stat")
+	statDecoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encodedStat))
+
+	err := json.NewDecoder(statDecoder).Decode(&stat)
+	if err != nil {
+		err = fmt.Errorf("unable to decode container path stat header: %s", err)
+	}
+
+	return stat, err
+}
diff --git a/vendor/github.com/moby/moby/client/container_create.go b/vendor/github.com/moby/moby/client/container_create.go
new file mode 100644
index 000000000..d941a3720
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_create.go
@@ -0,0 +1,125 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+	"path"
+	"sort"
+	"strings"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/moby/moby/api/types/container"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ContainerCreate creates a new container based on the given configuration.
+// It can be associated with a name, but it's not mandatory.
+func (cli *Client) ContainerCreate(ctx context.Context, options ContainerCreateOptions) (ContainerCreateResult, error) {
+	cfg := options.Config
+
+	if cfg == nil {
+		cfg = &container.Config{}
+	}
+
+	if options.Image != "" {
+		if cfg.Image != "" {
+			return ContainerCreateResult{}, cerrdefs.ErrInvalidArgument.WithMessage("either Image or config.Image should be set")
+		}
+		newCfg := *cfg
+		newCfg.Image = options.Image
+		cfg = &newCfg
+	}
+
+	if cfg.Image == "" {
+		return ContainerCreateResult{}, cerrdefs.ErrInvalidArgument.WithMessage("config.Image or Image is required")
+	}
+
+	var response container.CreateResponse
+
+	if options.HostConfig != nil {
+		options.HostConfig.CapAdd = normalizeCapabilities(options.HostConfig.CapAdd)
+		options.HostConfig.CapDrop = normalizeCapabilities(options.HostConfig.CapDrop)
+	}
+
+	query := url.Values{}
+	if options.Platform != nil {
+		if p := formatPlatform(*options.Platform); p != "unknown" {
+			query.Set("platform", p)
+		}
+	}
+
+	if options.Name != "" {
+		query.Set("name", options.Name)
+	}
+
+	body := container.CreateRequest{
+		Config:           cfg,
+		HostConfig:       options.HostConfig,
+		NetworkingConfig: options.NetworkingConfig,
+	}
+
+	resp, err := cli.post(ctx, "/containers/create", query, body, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerCreateResult{}, err
+	}
+
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	return ContainerCreateResult{ID: response.ID, Warnings: response.Warnings}, err
+}
+
+// formatPlatform returns a formatted string representing platform (e.g., "linux/arm/v7").
+//
+// It is a fork of [platforms.Format], and does not yet support "os.version",
+// as [platforms.FormatAll] does.
+//
+// [platforms.Format]: https://github.com/containerd/platforms/blob/v1.0.0-rc.1/platforms.go#L309-L316
+// [platforms.FormatAll]: https://github.com/containerd/platforms/blob/v1.0.0-rc.1/platforms.go#L318-L330
+func formatPlatform(platform ocispec.Platform) string {
+	if platform.OS == "" {
+		return "unknown"
+	}
+	return path.Join(platform.OS, platform.Architecture, platform.Variant)
+}
+
+// allCapabilities is a magic value for "all capabilities"
+const allCapabilities = "ALL"
+
+// normalizeCapabilities normalizes capabilities to their canonical form,
+// removes duplicates, and sorts the results.
+//
+// It is similar to [caps.NormalizeLegacyCapabilities],
+// but performs no validation based on supported capabilities.
+//
+// [caps.NormalizeLegacyCapabilities]: https://github.com/moby/moby/blob/v28.3.2/oci/caps/utils.go#L56
+func normalizeCapabilities(caps []string) []string {
+	var normalized []string
+
+	unique := make(map[string]struct{})
+	for _, c := range caps {
+		c = normalizeCap(c)
+		if _, ok := unique[c]; ok {
+			continue
+		}
+		unique[c] = struct{}{}
+		normalized = append(normalized, c)
+	}
+
+	sort.Strings(normalized)
+	return normalized
+}
+
+// normalizeCap normalizes a capability to its canonical format by upper-casing
+// and adding a "CAP_" prefix (if not yet present). It also accepts the "ALL"
+// magic-value.
+func normalizeCap(capability string) string {
+	capability = strings.ToUpper(capability)
+	if capability == allCapabilities {
+		return capability
+	}
+	if !strings.HasPrefix(capability, "CAP_") {
+		capability = "CAP_" + capability
+	}
+	return capability
+}
diff --git a/vendor/github.com/moby/moby/client/container_create_opts.go b/vendor/github.com/moby/moby/client/container_create_opts.go
new file mode 100644
index 000000000..8580e20d3
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_create_opts.go
@@ -0,0 +1,25 @@
+package client
+
+import (
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ContainerCreateOptions holds parameters to create a container.
+type ContainerCreateOptions struct {
+	Config           *container.Config
+	HostConfig       *container.HostConfig
+	NetworkingConfig *network.NetworkingConfig
+	Platform         *ocispec.Platform
+	Name             string
+
+	// Image is a shortcut for Config.Image - only one of Image or Config.Image should be set.
+	Image string
+}
+
+// ContainerCreateResult is the result from creating a container.
+type ContainerCreateResult struct {
+	ID       string
+	Warnings []string
+}
diff --git a/vendor/github.com/moby/moby/client/container_diff.go b/vendor/github.com/moby/moby/client/container_diff.go
new file mode 100644
index 000000000..ec904337e
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_diff.go
@@ -0,0 +1,30 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+// ContainerDiff shows differences in a container filesystem since it was started.
+func (cli *Client) ContainerDiff(ctx context.Context, containerID string, options ContainerDiffOptions) (ContainerDiffResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerDiffResult{}, err
+	}
+
+	resp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerDiffResult{}, err
+	}
+
+	var changes []container.FilesystemChange
+	err = json.NewDecoder(resp.Body).Decode(&changes)
+	if err != nil {
+		return ContainerDiffResult{}, err
+	}
+	return ContainerDiffResult{Changes: changes}, err
+}
diff --git a/vendor/github.com/moby/moby/client/container_diff_opts.go b/vendor/github.com/moby/moby/client/container_diff_opts.go
new file mode 100644
index 000000000..5e3c37ab4
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_diff_opts.go
@@ -0,0 +1,13 @@
+package client
+
+import "github.com/moby/moby/api/types/container"
+
+// ContainerDiffOptions holds parameters to show differences in a container filesystem.
+type ContainerDiffOptions struct {
+	// Currently no options, but this allows for future extensibility
+}
+
+// ContainerDiffResult is the result from showing differences in a container filesystem.
+type ContainerDiffResult struct {
+	Changes []container.FilesystemChange
+}
diff --git a/vendor/github.com/moby/moby/client/container_exec.go b/vendor/github.com/moby/moby/client/container_exec.go
new file mode 100644
index 000000000..30ed00ea5
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_exec.go
@@ -0,0 +1,203 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/moby/moby/api/types/container"
+)
+
+// ExecCreateOptions is a small subset of the Config struct that holds the configuration
+// for the exec feature of docker.
+type ExecCreateOptions struct {
+	User         string      // User that will run the command
+	Privileged   bool        // Is the container in privileged mode
+	TTY          bool        // Attach standard streams to a tty.
+	ConsoleSize  ConsoleSize // Initial terminal size [height, width], unused if TTY == false
+	AttachStdin  bool        // Attach the standard input, makes possible user interaction
+	AttachStderr bool        // Attach the standard error
+	AttachStdout bool        // Attach the standard output
+	DetachKeys   string      // Escape keys for detach
+	Env          []string    // Environment variables
+	WorkingDir   string      // Working directory
+	Cmd          []string    // Execution commands and args
+}
+
+// ExecCreateResult holds the result of creating a container exec.
+type ExecCreateResult struct {
+	ID string
+}
+
+// ExecCreate creates a new exec configuration to run an exec process.
+func (cli *Client) ExecCreate(ctx context.Context, containerID string, options ExecCreateOptions) (ExecCreateResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ExecCreateResult{}, err
+	}
+
+	consoleSize, err := getConsoleSize(options.TTY, options.ConsoleSize)
+	if err != nil {
+		return ExecCreateResult{}, err
+	}
+
+	req := container.ExecCreateRequest{
+		User:         options.User,
+		Privileged:   options.Privileged,
+		Tty:          options.TTY,
+		ConsoleSize:  consoleSize,
+		AttachStdin:  options.AttachStdin,
+		AttachStderr: options.AttachStderr,
+		AttachStdout: options.AttachStdout,
+		DetachKeys:   options.DetachKeys,
+		Env:          options.Env,
+		WorkingDir:   options.WorkingDir,
+		Cmd:          options.Cmd,
+	}
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/exec", nil, req, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ExecCreateResult{}, err
+	}
+
+	var response container.ExecCreateResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	return ExecCreateResult{ID: response.ID}, err
+}
+
+type ConsoleSize struct {
+	Height, Width uint
+}
+
+// ExecStartOptions holds options for starting a container exec.
+type ExecStartOptions struct {
+	// ExecStart will first check if it's detached
+	Detach bool
+	// Check if there's a tty
+	TTY bool
+	// Terminal size [height, width], unused if TTY == false
+	ConsoleSize ConsoleSize
+}
+
+// ExecStartResult holds the result of starting a container exec.
+type ExecStartResult struct{}
+
+// ExecStart starts an exec process already created in the docker host.
+func (cli *Client) ExecStart(ctx context.Context, execID string, options ExecStartOptions) (ExecStartResult, error) {
+	consoleSize, err := getConsoleSize(options.TTY, options.ConsoleSize)
+	if err != nil {
+		return ExecStartResult{}, err
+	}
+
+	req := container.ExecStartRequest{
+		Detach:      options.Detach,
+		Tty:         options.TTY,
+		ConsoleSize: consoleSize,
+	}
+	resp, err := cli.post(ctx, "/exec/"+execID+"/start", nil, req, nil)
+	defer ensureReaderClosed(resp)
+	return ExecStartResult{}, err
+}
+
+// ExecAttachOptions holds options for attaching to a container exec.
+type ExecAttachOptions struct {
+	// Check if there's a tty
+	TTY bool
+	// Terminal size [height, width], unused if TTY == false
+	ConsoleSize ConsoleSize `json:",omitzero"`
+}
+
+// ExecAttachResult holds the result of attaching to a container exec.
+type ExecAttachResult struct {
+	HijackedResponse
+}
+
+// ExecAttach attaches a connection to an exec process in the server.
+//
+// It returns a [HijackedResponse] with the hijacked connection
+// and a reader to get output. It's up to the caller to close
+// the hijacked connection by calling [HijackedResponse.Close].
+//
+// The stream format on the response uses one of two formats:
+//
+//   - If the container is using a TTY, there is only a single stream (stdout)
+//     and data is copied directly from the container output stream, no extra
+//     multiplexing or headers.
+//   - If the container is *not* using a TTY, streams for stdout and stderr are
+//     multiplexed.
+//
+// You can use [stdcopy.StdCopy] to demultiplex this stream. Refer to
+// [Client.ContainerAttach] for details about the multiplexed stream.
+//
+// [stdcopy.StdCopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdCopy
+func (cli *Client) ExecAttach(ctx context.Context, execID string, options ExecAttachOptions) (ExecAttachResult, error) {
+	consoleSize, err := getConsoleSize(options.TTY, options.ConsoleSize)
+	if err != nil {
+		return ExecAttachResult{}, err
+	}
+	req := container.ExecStartRequest{
+		Detach:      false,
+		Tty:         options.TTY,
+		ConsoleSize: consoleSize,
+	}
+	response, err := cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, req, http.Header{
+		"Content-Type": {"application/json"},
+	})
+	return ExecAttachResult{HijackedResponse: response}, err
+}
+
+func getConsoleSize(hasTTY bool, consoleSize ConsoleSize) (*[2]uint, error) {
+	if consoleSize.Height != 0 || consoleSize.Width != 0 {
+		if !hasTTY {
+			return nil, cerrdefs.ErrInvalidArgument.WithMessage("console size is only supported when TTY is enabled")
+		}
+		return &[2]uint{consoleSize.Height, consoleSize.Width}, nil
+	}
+	return nil, nil
+}
+
+// ExecInspectOptions holds options for inspecting a container exec.
+type ExecInspectOptions struct{}
+
+// ExecInspectResult holds the result of inspecting a container exec.
+//
+// It provides a subset of the information included in [container.ExecInspectResponse].
+//
+// TODO(thaJeztah): include all fields of [container.ExecInspectResponse] ?
+type ExecInspectResult struct {
+	ID          string
+	ContainerID string
+	Running     bool
+	ExitCode    int
+	PID         int
+}
+
+// ExecInspect returns information about a specific exec process on the docker host.
+func (cli *Client) ExecInspect(ctx context.Context, execID string, options ExecInspectOptions) (ExecInspectResult, error) {
+	resp, err := cli.get(ctx, "/exec/"+execID+"/json", nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ExecInspectResult{}, err
+	}
+
+	var response container.ExecInspectResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	if err != nil {
+		return ExecInspectResult{}, err
+	}
+
+	var ec int
+	if response.ExitCode != nil {
+		ec = *response.ExitCode
+	}
+
+	return ExecInspectResult{
+		ID:          response.ID,
+		ContainerID: response.ContainerID,
+		Running:     response.Running,
+		ExitCode:    ec,
+		PID:         response.Pid,
+	}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_export.go b/vendor/github.com/moby/moby/client/container_export.go
new file mode 100644
index 000000000..2d33efb7d
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_export.go
@@ -0,0 +1,47 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net/url"
+)
+
+// ContainerExportOptions specifies options for container export operations.
+type ContainerExportOptions struct {
+	// Currently no options are defined for ContainerExport
+}
+
+// ContainerExportResult represents the result of a container export operation.
+type ContainerExportResult interface {
+	io.ReadCloser
+}
+
+// ContainerExport retrieves the raw contents of a container
+// and returns them as an [io.ReadCloser]. It's up to the caller
+// to close the stream.
+//
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
+func (cli *Client) ContainerExport(ctx context.Context, containerID string, options ContainerExportOptions) (ContainerExportResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := cli.get(ctx, "/containers/"+containerID+"/export", url.Values{}, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return &containerExportResult{
+		ReadCloser: newCancelReadCloser(ctx, resp.Body),
+	}, nil
+}
+
+type containerExportResult struct {
+	io.ReadCloser
+}
+
+var (
+	_ io.ReadCloser         = (*containerExportResult)(nil)
+	_ ContainerExportResult = (*containerExportResult)(nil)
+)
diff --git a/vendor/github.com/moby/moby/client/container_inspect.go b/vendor/github.com/moby/moby/client/container_inspect.go
new file mode 100644
index 000000000..4f12c4657
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_inspect.go
@@ -0,0 +1,47 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+// ContainerInspectOptions holds options for inspecting a container using
+// the [Client.ConfigInspect] method.
+type ContainerInspectOptions struct {
+	// Size controls whether the container's filesystem size should be calculated.
+	// When set, the [container.InspectResponse.SizeRw] and [container.InspectResponse.SizeRootFs]
+	// fields in [ContainerInspectResult.Container] are populated with the result.
+	//
+	// Calculating the size can be a costly operation, and should not be used
+	// unless needed.
+	Size bool
+}
+
+// ContainerInspectResult holds the result from the [Client.ConfigInspect] method.
+type ContainerInspectResult struct {
+	Container container.InspectResponse
+	Raw       json.RawMessage
+}
+
+// ContainerInspect returns the container information.
+func (cli *Client) ContainerInspect(ctx context.Context, containerID string, options ContainerInspectOptions) (ContainerInspectResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerInspectResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Size {
+		query.Set("size", "1")
+	}
+	resp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
+	if err != nil {
+		return ContainerInspectResult{}, err
+	}
+	var out ContainerInspectResult
+	out.Raw, err = decodeWithRaw(resp, &out.Container)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/container_kill.go b/vendor/github.com/moby/moby/client/container_kill.go
new file mode 100644
index 000000000..ae7a4ebd8
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_kill.go
@@ -0,0 +1,39 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// ContainerKillOptions holds options for [Client.ContainerKill].
+type ContainerKillOptions struct {
+	// Signal (optional) is the signal to send to the container to (gracefully)
+	// stop it before forcibly terminating the container with SIGKILL after a
+	// timeout. If no value is set, the default (SIGKILL) is used.
+	Signal string `json:",omitempty"`
+}
+
+// ContainerKillResult holds the result of [Client.ContainerKill],
+type ContainerKillResult struct {
+	// Add future fields here.
+}
+
+// ContainerKill terminates the container process but does not remove the container from the docker host.
+func (cli *Client) ContainerKill(ctx context.Context, containerID string, options ContainerKillOptions) (ContainerKillResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerKillResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Signal != "" {
+		query.Set("signal", options.Signal)
+	}
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/kill", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerKillResult{}, err
+	}
+	return ContainerKillResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_list.go b/vendor/github.com/moby/moby/client/container_list.go
new file mode 100644
index 000000000..d9334c544
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_list.go
@@ -0,0 +1,66 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+	"strconv"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+// ContainerListOptions holds parameters to list containers with.
+type ContainerListOptions struct {
+	Size    bool
+	All     bool
+	Limit   int
+	Filters Filters
+
+	// Latest is non-functional and should not be used. Use Limit: 1 instead.
+	//
+	// Deprecated: the Latest option is non-functional and should not be used. Use Limit: 1 instead.
+	Latest bool
+
+	// Since is no longer supported. Use the "since" filter instead.
+	//
+	// Deprecated: the Since option is no longer supported since docker 1.12 (API 1.24). Use the "since" filter instead.
+	Since string
+
+	// Before is no longer supported. Use the "since" filter instead.
+	//
+	// Deprecated: the Before option is no longer supported since docker 1.12 (API 1.24). Use the "before" filter instead.
+	Before string
+}
+
+type ContainerListResult struct {
+	Items []container.Summary
+}
+
+// ContainerList returns the list of containers in the docker host.
+func (cli *Client) ContainerList(ctx context.Context, options ContainerListOptions) (ContainerListResult, error) {
+	query := url.Values{}
+
+	if options.All {
+		query.Set("all", "1")
+	}
+
+	if options.Limit > 0 {
+		query.Set("limit", strconv.Itoa(options.Limit))
+	}
+
+	if options.Size {
+		query.Set("size", "1")
+	}
+
+	options.Filters.updateURLValues(query)
+
+	resp, err := cli.get(ctx, "/containers/json", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerListResult{}, err
+	}
+
+	var containers []container.Summary
+	err = json.NewDecoder(resp.Body).Decode(&containers)
+	return ContainerListResult{Items: containers}, err
+}
diff --git a/vendor/github.com/moby/moby/client/container_logs.go b/vendor/github.com/moby/moby/client/container_logs.go
new file mode 100644
index 000000000..b26a3568a
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_logs.go
@@ -0,0 +1,134 @@
+package client
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/url"
+	"time"
+
+	"github.com/moby/moby/client/internal/timestamp"
+)
+
+// ContainerLogsOptions holds parameters to filter logs with.
+type ContainerLogsOptions struct {
+	ShowStdout bool
+	ShowStderr bool
+	Since      string
+	Until      string
+	Timestamps bool
+	Follow     bool
+	Tail       string
+	Details    bool
+}
+
+// ContainerLogsResult is the result of a container logs operation.
+type ContainerLogsResult interface {
+	io.ReadCloser
+}
+
+// ContainerLogs returns the logs generated by a container in an [io.ReadCloser].
+// It's up to the caller to close the stream.
+//
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
+//
+// The stream format on the response uses one of two formats:
+//
+//   - If the container is using a TTY, there is only a single stream (stdout)
+//     and data is copied directly from the container output stream, no extra
+//     multiplexing or headers.
+//   - If the container is *not* using a TTY, streams for stdout and stderr are
+//     multiplexed.
+//
+// The format of the multiplexed stream is defined in the [stdcopy] package,
+// and as follows:
+//
+//	[8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT}
+//
+// STREAM_TYPE can be 1 for [Stdout] and 2 for [Stderr]. Refer to [stdcopy.StdType]
+// for details. SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded
+// as big endian, this is the size of OUTPUT. You can use [stdcopy.StdCopy]
+// to demultiplex this stream.
+//
+// [stdcopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy
+// [stdcopy.StdCopy]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdCopy
+// [stdcopy.StdType]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#StdType
+// [Stdout]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stdout
+// [Stderr]: https://pkg.go.dev/github.com/moby/moby/api/pkg/stdcopy#Stderr
+func (cli *Client) ContainerLogs(ctx context.Context, containerID string, options ContainerLogsOptions) (ContainerLogsResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return nil, err
+	}
+
+	query := url.Values{}
+	if options.ShowStdout {
+		query.Set("stdout", "1")
+	}
+
+	if options.ShowStderr {
+		query.Set("stderr", "1")
+	}
+
+	if options.Since != "" {
+		ts, err := timestamp.GetTimestamp(options.Since, time.Now())
+		if err != nil {
+			return nil, fmt.Errorf(`invalid value for "since": %w`, err)
+		}
+		query.Set("since", ts)
+	}
+
+	if options.Until != "" {
+		ts, err := timestamp.GetTimestamp(options.Until, time.Now())
+		if err != nil {
+			return nil, fmt.Errorf(`invalid value for "until": %w`, err)
+		}
+		query.Set("until", ts)
+	}
+
+	if options.Timestamps {
+		query.Set("timestamps", "1")
+	}
+
+	if options.Details {
+		query.Set("details", "1")
+	}
+
+	if options.Follow {
+		query.Set("follow", "1")
+	}
+
+	switch options.Tail {
+	case "", "all":
+		// don't send option; default is to show all logs.
+		//
+		// The default on the daemon-side is to show all logs; account for
+		// some special values. The CLI may set a magic "all" value that's
+		// used as default.
+		//
+		// Given that the default is to show all logs, we can ignore these
+		// values, and don't send "tail".
+		//
+		// see https://github.com/moby/moby/blob/0df791cb72b568eeadba2267fe9a5040d12b0487/daemon/logs.go#L75-L78
+		// see https://github.com/moby/moby/blob/4d20b6fe56dfb2b06f4a5dd1f32913215a9c317b/daemon/cluster/services.go#L425-L449
+	default:
+		query.Set("tail", options.Tail)
+	}
+
+	resp, err := cli.get(ctx, "/containers/"+containerID+"/logs", query, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &containerLogsResult{
+		ReadCloser: newCancelReadCloser(ctx, resp.Body),
+	}, nil
+}
+
+type containerLogsResult struct {
+	io.ReadCloser
+}
+
+var (
+	_ io.ReadCloser       = (*containerLogsResult)(nil)
+	_ ContainerLogsResult = (*containerLogsResult)(nil)
+)
diff --git a/vendor/github.com/moby/moby/client/container_pause.go b/vendor/github.com/moby/moby/client/container_pause.go
new file mode 100644
index 000000000..07669c897
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_pause.go
@@ -0,0 +1,28 @@
+package client
+
+import "context"
+
+// ContainerPauseOptions holds options for [Client.ContainerPause].
+type ContainerPauseOptions struct {
+	// Add future optional parameters here.
+}
+
+// ContainerPauseResult holds the result of [Client.ContainerPause],
+type ContainerPauseResult struct {
+	// Add future fields here.
+}
+
+// ContainerPause pauses the main process of a given container without terminating it.
+func (cli *Client) ContainerPause(ctx context.Context, containerID string, options ContainerPauseOptions) (ContainerPauseResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerPauseResult{}, err
+	}
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/pause", nil, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerPauseResult{}, err
+	}
+	return ContainerPauseResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_prune.go b/vendor/github.com/moby/moby/client/container_prune.go
new file mode 100644
index 000000000..f826f8b6f
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_prune.go
@@ -0,0 +1,39 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+// ContainerPruneOptions holds parameters to prune containers.
+type ContainerPruneOptions struct {
+	Filters Filters
+}
+
+// ContainerPruneResult holds the result from the [Client.ContainerPrune] method.
+type ContainerPruneResult struct {
+	Report container.PruneReport
+}
+
+// ContainerPrune requests the daemon to delete unused data
+func (cli *Client) ContainerPrune(ctx context.Context, opts ContainerPruneOptions) (ContainerPruneResult, error) {
+	query := url.Values{}
+	opts.Filters.updateURLValues(query)
+
+	resp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerPruneResult{}, err
+	}
+
+	var report container.PruneReport
+	if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
+		return ContainerPruneResult{}, fmt.Errorf("Error retrieving disk usage: %v", err)
+	}
+
+	return ContainerPruneResult{Report: report}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_remove.go b/vendor/github.com/moby/moby/client/container_remove.go
new file mode 100644
index 000000000..0fbfa05fa
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_remove.go
@@ -0,0 +1,45 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// ContainerRemoveOptions holds parameters to remove containers.
+type ContainerRemoveOptions struct {
+	RemoveVolumes bool
+	RemoveLinks   bool
+	Force         bool
+}
+
+// ContainerRemoveResult holds the result of [Client.ContainerRemove],
+type ContainerRemoveResult struct {
+	// Add future fields here.
+}
+
+// ContainerRemove kills and removes a container from the docker host.
+func (cli *Client) ContainerRemove(ctx context.Context, containerID string, options ContainerRemoveOptions) (ContainerRemoveResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerRemoveResult{}, err
+	}
+
+	query := url.Values{}
+	if options.RemoveVolumes {
+		query.Set("v", "1")
+	}
+	if options.RemoveLinks {
+		query.Set("link", "1")
+	}
+
+	if options.Force {
+		query.Set("force", "1")
+	}
+
+	resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerRemoveResult{}, err
+	}
+	return ContainerRemoveResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_rename.go b/vendor/github.com/moby/moby/client/container_rename.go
new file mode 100644
index 000000000..4fd28a498
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_rename.go
@@ -0,0 +1,39 @@
+package client
+
+import (
+	"context"
+	"net/url"
+	"strings"
+
+	cerrdefs "github.com/containerd/errdefs"
+)
+
+// ContainerRenameOptions represents the options for renaming a container.
+type ContainerRenameOptions struct {
+	NewName string
+}
+
+// ContainerRenameResult represents the result of a container rename operation.
+type ContainerRenameResult struct {
+	// This struct can be expanded in the future if needed
+}
+
+// ContainerRename changes the name of a given container.
+func (cli *Client) ContainerRename(ctx context.Context, containerID string, options ContainerRenameOptions) (ContainerRenameResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerRenameResult{}, err
+	}
+	options.NewName = strings.TrimSpace(options.NewName)
+	if options.NewName == "" || strings.TrimPrefix(options.NewName, "/") == "" {
+		// daemons before v29.0 did not handle the canonical name ("/") well
+		// let's be nice and validate it here before sending
+		return ContainerRenameResult{}, cerrdefs.ErrInvalidArgument.WithMessage("new name cannot be blank")
+	}
+
+	query := url.Values{}
+	query.Set("name", options.NewName)
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/rename", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	return ContainerRenameResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/container_resize.go b/vendor/github.com/moby/moby/client/container_resize.go
new file mode 100644
index 000000000..8ce26fb58
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_resize.go
@@ -0,0 +1,64 @@
+package client
+
+import (
+	"context"
+	"net/url"
+	"strconv"
+)
+
+// ContainerResizeOptions holds parameters to resize a TTY.
+// It can be used to resize container TTYs and
+// exec process TTYs too.
+type ContainerResizeOptions struct {
+	Height uint
+	Width  uint
+}
+
+// ContainerResizeResult holds the result of [Client.ContainerResize],
+type ContainerResizeResult struct {
+	// Add future fields here.
+}
+
+// ContainerResize changes the size of the pseudo-TTY for a container.
+func (cli *Client) ContainerResize(ctx context.Context, containerID string, options ContainerResizeOptions) (ContainerResizeResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerResizeResult{}, err
+	}
+	// FIXME(thaJeztah): the API / backend accepts uint32, but container.ResizeOptions uses uint.
+	query := url.Values{}
+	query.Set("h", strconv.FormatUint(uint64(options.Height), 10))
+	query.Set("w", strconv.FormatUint(uint64(options.Width), 10))
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/resize", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerResizeResult{}, err
+	}
+	return ContainerResizeResult{}, nil
+}
+
+// ExecResizeOptions holds options for resizing a container exec TTY.
+type ExecResizeOptions ContainerResizeOptions
+
+// ExecResizeResult holds the result of resizing a container exec TTY.
+type ExecResizeResult struct{}
+
+// ExecResize changes the size of the tty for an exec process running inside a container.
+func (cli *Client) ExecResize(ctx context.Context, execID string, options ExecResizeOptions) (ExecResizeResult, error) {
+	execID, err := trimID("exec", execID)
+	if err != nil {
+		return ExecResizeResult{}, err
+	}
+	// FIXME(thaJeztah): the API / backend accepts uint32, but container.ResizeOptions uses uint.
+	query := url.Values{}
+	query.Set("h", strconv.FormatUint(uint64(options.Height), 10))
+	query.Set("w", strconv.FormatUint(uint64(options.Width), 10))
+
+	resp, err := cli.post(ctx, "/exec/"+execID+"/resize", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ExecResizeResult{}, err
+	}
+	return ExecResizeResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_restart.go b/vendor/github.com/moby/moby/client/container_restart.go
new file mode 100644
index 000000000..e883f7589
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_restart.go
@@ -0,0 +1,54 @@
+package client
+
+import (
+	"context"
+	"net/url"
+	"strconv"
+)
+
+// ContainerRestartOptions holds options for [Client.ContainerRestart].
+type ContainerRestartOptions struct {
+	// Signal (optional) is the signal to send to the container to (gracefully)
+	// stop it before forcibly terminating the container with SIGKILL after the
+	// timeout expires. If no value is set, the default (SIGTERM) is used.
+	Signal string `json:",omitempty"`
+
+	// Timeout (optional) is the timeout (in seconds) to wait for the container
+	// to stop gracefully before forcibly terminating it with SIGKILL.
+	//
+	// - Use nil to use the default timeout (10 seconds).
+	// - Use '-1' to wait indefinitely.
+	// - Use '0' to not wait for the container to exit gracefully, and
+	//   immediately proceeds to forcibly terminating the container.
+	// - Other positive values are used as timeout (in seconds).
+	Timeout *int `json:",omitempty"`
+}
+
+// ContainerRestartResult holds the result of [Client.ContainerRestart],
+type ContainerRestartResult struct {
+	// Add future fields here.
+}
+
+// ContainerRestart stops, and starts a container again.
+// It makes the daemon wait for the container to be up again for
+// a specific amount of time, given the timeout.
+func (cli *Client) ContainerRestart(ctx context.Context, containerID string, options ContainerRestartOptions) (ContainerRestartResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerRestartResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Timeout != nil {
+		query.Set("t", strconv.Itoa(*options.Timeout))
+	}
+	if options.Signal != "" {
+		query.Set("signal", options.Signal)
+	}
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/restart", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerRestartResult{}, err
+	}
+	return ContainerRestartResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_start.go b/vendor/github.com/moby/moby/client/container_start.go
new file mode 100644
index 000000000..dfb821d1d
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_start.go
@@ -0,0 +1,40 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// ContainerStartOptions holds options for [Client.ContainerStart].
+type ContainerStartOptions struct {
+	CheckpointID  string
+	CheckpointDir string
+}
+
+// ContainerStartResult holds the result of [Client.ContainerStart],
+type ContainerStartResult struct {
+	// Add future fields here.
+}
+
+// ContainerStart sends a request to the docker daemon to start a container.
+func (cli *Client) ContainerStart(ctx context.Context, containerID string, options ContainerStartOptions) (ContainerStartResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerStartResult{}, err
+	}
+
+	query := url.Values{}
+	if options.CheckpointID != "" {
+		query.Set("checkpoint", options.CheckpointID)
+	}
+	if options.CheckpointDir != "" {
+		query.Set("checkpoint-dir", options.CheckpointDir)
+	}
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/start", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerStartResult{}, err
+	}
+	return ContainerStartResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_stats.go b/vendor/github.com/moby/moby/client/container_stats.go
new file mode 100644
index 000000000..277769dbf
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_stats.go
@@ -0,0 +1,75 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net/url"
+)
+
+// ContainerStatsOptions holds parameters to retrieve container statistics
+// using the [Client.ContainerStats] method.
+type ContainerStatsOptions struct {
+	// Stream enables streaming [container.StatsResponse] results instead
+	// of collecting a single sample. If enabled, the client remains attached
+	// until the [ContainerStatsResult.Body] is closed or the context is
+	// cancelled.
+	Stream bool
+
+	// IncludePreviousSample asks the daemon to  collect a prior sample to populate the
+	// [container.StatsResponse.PreRead] and [container.StatsResponse.PreCPUStats]
+	// fields.
+	//
+	// It set, the daemon collects two samples at a one-second interval before
+	// returning the result. The first sample populates the PreCPUStats (“previous
+	// CPU”) field, allowing delta calculations for CPU usage. If false, only
+	// a single sample is taken and returned immediately, leaving PreRead and
+	// PreCPUStats empty.
+	//
+	// This option has no effect if Stream is enabled. If Stream is enabled,
+	// [container.StatsResponse.PreCPUStats] is never populated for the first
+	// record.
+	IncludePreviousSample bool
+}
+
+// ContainerStatsResult holds the result from [Client.ContainerStats].
+//
+// It wraps an [io.ReadCloser] that provides one or more [container.StatsResponse]
+// objects for a container, as produced by the "GET /containers/{id}/stats" endpoint.
+// If streaming is disabled, the stream contains a single record.
+type ContainerStatsResult struct {
+	Body io.ReadCloser
+}
+
+// ContainerStats retrieves live resource usage statistics for the specified
+// container. The caller must close the [io.ReadCloser] in the returned result
+// to release associated resources.
+//
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
+func (cli *Client) ContainerStats(ctx context.Context, containerID string, options ContainerStatsOptions) (ContainerStatsResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerStatsResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Stream {
+		query.Set("stream", "true")
+	} else {
+		// Note: daemons before v29.0 return an error if both set: "cannot have stream=true and one-shot=true"
+		//
+		// TODO(thaJeztah): consider making "stream=false" the default for the API as well, or using Accept Header to switch.
+		query.Set("stream", "false")
+		if !options.IncludePreviousSample {
+			query.Set("one-shot", "true")
+		}
+	}
+
+	resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
+	if err != nil {
+		return ContainerStatsResult{}, err
+	}
+
+	return ContainerStatsResult{
+		Body: newCancelReadCloser(ctx, resp.Body),
+	}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_stop.go b/vendor/github.com/moby/moby/client/container_stop.go
new file mode 100644
index 000000000..d4d47d8fd
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_stop.go
@@ -0,0 +1,58 @@
+package client
+
+import (
+	"context"
+	"net/url"
+	"strconv"
+)
+
+// ContainerStopOptions holds the options for [Client.ContainerStop].
+type ContainerStopOptions struct {
+	// Signal (optional) is the signal to send to the container to (gracefully)
+	// stop it before forcibly terminating the container with SIGKILL after the
+	// timeout expires. If no value is set, the default (SIGTERM) is used.
+	Signal string `json:",omitempty"`
+
+	// Timeout (optional) is the timeout (in seconds) to wait for the container
+	// to stop gracefully before forcibly terminating it with SIGKILL.
+	//
+	// - Use nil to use the default timeout (10 seconds).
+	// - Use '-1' to wait indefinitely.
+	// - Use '0' to not wait for the container to exit gracefully, and
+	//   immediately proceeds to forcibly terminating the container.
+	// - Other positive values are used as timeout (in seconds).
+	Timeout *int `json:",omitempty"`
+}
+
+// ContainerStopResult holds the result of [Client.ContainerStop],
+type ContainerStopResult struct {
+	// Add future fields here.
+}
+
+// ContainerStop stops a container. In case the container fails to stop
+// gracefully within a time frame specified by the timeout argument,
+// it is forcefully terminated (killed).
+//
+// If the timeout is nil, the container's StopTimeout value is used, if set,
+// otherwise the engine default. A negative timeout value can be specified,
+// meaning no timeout, i.e. no forceful termination is performed.
+func (cli *Client) ContainerStop(ctx context.Context, containerID string, options ContainerStopOptions) (ContainerStopResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerStopResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Timeout != nil {
+		query.Set("t", strconv.Itoa(*options.Timeout))
+	}
+	if options.Signal != "" {
+		query.Set("signal", options.Signal)
+	}
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/stop", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerStopResult{}, err
+	}
+	return ContainerStopResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_top.go b/vendor/github.com/moby/moby/client/container_top.go
new file mode 100644
index 000000000..dc0af8ae4
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_top.go
@@ -0,0 +1,44 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+	"strings"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+// ContainerTopOptions defines options for container top operations.
+type ContainerTopOptions struct {
+	Arguments []string
+}
+
+// ContainerTopResult represents the result of a ContainerTop operation.
+type ContainerTopResult struct {
+	Processes [][]string
+	Titles    []string
+}
+
+// ContainerTop shows process information from within a container.
+func (cli *Client) ContainerTop(ctx context.Context, containerID string, options ContainerTopOptions) (ContainerTopResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerTopResult{}, err
+	}
+
+	query := url.Values{}
+	if len(options.Arguments) > 0 {
+		query.Set("ps_args", strings.Join(options.Arguments, " "))
+	}
+
+	resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerTopResult{}, err
+	}
+
+	var response container.TopResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	return ContainerTopResult{Processes: response.Processes, Titles: response.Titles}, err
+}
diff --git a/vendor/github.com/moby/moby/client/container_unpause.go b/vendor/github.com/moby/moby/client/container_unpause.go
new file mode 100644
index 000000000..627d60c96
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_unpause.go
@@ -0,0 +1,28 @@
+package client
+
+import "context"
+
+// ContainerUnpauseOptions holds options for [Client.ContainerUnpause].
+type ContainerUnpauseOptions struct {
+	// Add future optional parameters here.
+}
+
+// ContainerUnpauseResult holds the result of [Client.ContainerUnpause],
+type ContainerUnpauseResult struct {
+	// Add future fields here.
+}
+
+// ContainerUnpause resumes the process execution within a container.
+func (cli *Client) ContainerUnpause(ctx context.Context, containerID string, options ContainerUnpauseOptions) (ContainerUnpauseResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerUnpauseResult{}, err
+	}
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/unpause", nil, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerUnpauseResult{}, err
+	}
+	return ContainerUnpauseResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/container_update.go b/vendor/github.com/moby/moby/client/container_update.go
new file mode 100644
index 000000000..a1d4d249a
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_update.go
@@ -0,0 +1,46 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+// ContainerUpdateOptions holds options for [Client.ContainerUpdate].
+type ContainerUpdateOptions struct {
+	Resources     *container.Resources
+	RestartPolicy *container.RestartPolicy
+}
+
+// ContainerUpdateResult is the result from updating a container.
+type ContainerUpdateResult struct {
+	// Warnings encountered when updating the container.
+	Warnings []string
+}
+
+// ContainerUpdate updates the resources of a container.
+func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, options ContainerUpdateOptions) (ContainerUpdateResult, error) {
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		return ContainerUpdateResult{}, err
+	}
+
+	updateConfig := container.UpdateConfig{}
+	if options.Resources != nil {
+		updateConfig.Resources = *options.Resources
+	}
+	if options.RestartPolicy != nil {
+		updateConfig.RestartPolicy = *options.RestartPolicy
+	}
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ContainerUpdateResult{}, err
+	}
+
+	var response container.UpdateResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	return ContainerUpdateResult{Warnings: response.Warnings}, err
+}
diff --git a/vendor/github.com/moby/moby/client/container_wait.go b/vendor/github.com/moby/moby/client/container_wait.go
new file mode 100644
index 000000000..6f71ed051
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/container_wait.go
@@ -0,0 +1,92 @@
+package client
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"io"
+	"net/url"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+const containerWaitErrorMsgLimit = 2 * 1024 /* Max: 2KiB */
+
+// ContainerWaitOptions holds options for [Client.ContainerWait].
+type ContainerWaitOptions struct {
+	Condition container.WaitCondition
+}
+
+// ContainerWaitResult defines the result from the [Client.ContainerWait] method.
+type ContainerWaitResult struct {
+	Result <-chan container.WaitResponse
+	Error  <-chan error
+}
+
+// ContainerWait waits until the specified container is in a certain state
+// indicated by the given condition, either;
+//
+//   - "not-running" ([container.WaitConditionNotRunning]) (default)
+//   - "next-exit" ([container.WaitConditionNextExit])
+//   - "removed" ([container.WaitConditionRemoved])
+//
+// ContainerWait blocks until the request has been acknowledged by the server
+// (with a response header), then returns two channels on which the caller can
+// wait for the exit status of the container or an error if there was a problem
+// either beginning the wait request or in getting the response. This allows the
+// caller to synchronize ContainerWait with other calls, such as specifying a
+// "next-exit" condition ([container.WaitConditionNextExit]) before issuing a
+// [Client.ContainerStart] request.
+func (cli *Client) ContainerWait(ctx context.Context, containerID string, options ContainerWaitOptions) ContainerWaitResult {
+	resultC := make(chan container.WaitResponse)
+	errC := make(chan error, 1)
+
+	containerID, err := trimID("container", containerID)
+	if err != nil {
+		errC <- err
+		return ContainerWaitResult{Result: resultC, Error: errC}
+	}
+
+	query := url.Values{}
+	if options.Condition != "" {
+		query.Set("condition", string(options.Condition))
+	}
+
+	resp, err := cli.post(ctx, "/containers/"+containerID+"/wait", query, nil, nil)
+	if err != nil {
+		defer ensureReaderClosed(resp)
+		errC <- err
+		return ContainerWaitResult{Result: resultC, Error: errC}
+	}
+
+	go func() {
+		defer ensureReaderClosed(resp)
+
+		responseText := bytes.NewBuffer(nil)
+		stream := io.TeeReader(resp.Body, responseText)
+
+		var res container.WaitResponse
+		if err := json.NewDecoder(stream).Decode(&res); err != nil {
+			// NOTE(nicks): The /wait API does not work well with HTTP proxies.
+			// At any time, the proxy could cut off the response stream.
+			//
+			// But because the HTTP status has already been written, the proxy's
+			// only option is to write a plaintext error message.
+			//
+			// If there's a JSON parsing error, read the real error message
+			// off the body and send it to the client.
+			if errors.As(err, new(*json.SyntaxError)) {
+				_, _ = io.ReadAll(io.LimitReader(stream, containerWaitErrorMsgLimit))
+				errC <- errors.New(responseText.String())
+			} else {
+				errC <- err
+			}
+			return
+		}
+
+		resultC <- res
+	}()
+
+	return ContainerWaitResult{Result: resultC, Error: errC}
+}
diff --git a/vendor/github.com/moby/moby/client/distribution_inspect.go b/vendor/github.com/moby/moby/client/distribution_inspect.go
new file mode 100644
index 000000000..ffbf869d3
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/distribution_inspect.go
@@ -0,0 +1,45 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"net/url"
+
+	"github.com/moby/moby/api/types/registry"
+)
+
+// DistributionInspectResult holds the result of the DistributionInspect operation.
+type DistributionInspectResult struct {
+	registry.DistributionInspect
+}
+
+// DistributionInspectOptions holds options for the DistributionInspect operation.
+type DistributionInspectOptions struct {
+	EncodedRegistryAuth string
+}
+
+// DistributionInspect returns the image digest with the full manifest.
+func (cli *Client) DistributionInspect(ctx context.Context, imageRef string, options DistributionInspectOptions) (DistributionInspectResult, error) {
+	if imageRef == "" {
+		return DistributionInspectResult{}, objectNotFoundError{object: "distribution", id: imageRef}
+	}
+
+	var headers http.Header
+	if options.EncodedRegistryAuth != "" {
+		headers = http.Header{
+			registry.AuthHeader: {options.EncodedRegistryAuth},
+		}
+	}
+
+	// Contact the registry to retrieve digest and platform information
+	resp, err := cli.get(ctx, "/distribution/"+imageRef+"/json", url.Values{}, headers)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return DistributionInspectResult{}, err
+	}
+
+	var distributionInspect registry.DistributionInspect
+	err = json.NewDecoder(resp.Body).Decode(&distributionInspect)
+	return DistributionInspectResult{DistributionInspect: distributionInspect}, err
+}
diff --git a/vendor/github.com/moby/moby/client/envvars.go b/vendor/github.com/moby/moby/client/envvars.go
new file mode 100644
index 000000000..a02295d16
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/envvars.go
@@ -0,0 +1,95 @@
+package client
+
+const (
+	// EnvOverrideHost is the name of the environment variable that can be used
+	// to override the default host to connect to (DefaultDockerHost).
+	//
+	// This env-var is read by [FromEnv] and [WithHostFromEnv] and when set to a
+	// non-empty value, takes precedence over the default host (which is platform
+	// specific), or any host already set.
+	EnvOverrideHost = "DOCKER_HOST"
+
+	// EnvOverrideAPIVersion is the name of the environment variable that can
+	// be used to override the API version to use. Value must be
+	// formatted as MAJOR.MINOR, for example, "1.19".
+	//
+	// This env-var is read by [FromEnv] and [WithAPIVersionFromEnv] and when set to a
+	// non-empty value, takes precedence over API version negotiation.
+	//
+	// This environment variable should be used for debugging purposes only, as
+	// it can set the client to use an incompatible (or invalid) API version.
+	EnvOverrideAPIVersion = "DOCKER_API_VERSION"
+
+	// EnvOverrideCertPath is the name of the environment variable that can be
+	// used to specify the directory from which to load the TLS certificates
+	// (ca.pem, cert.pem, key.pem) from. These certificates are used to configure
+	// the [Client] for a TCP connection protected by TLS client authentication.
+	//
+	// TLS certificate verification is enabled by default if the Client is configured
+	// to use a TLS connection. Refer to [EnvTLSVerify] below to learn how to
+	// disable verification for testing purposes.
+	//
+	// WARNING: Access to the remote API is equivalent to root access to the
+	// host where the daemon runs. Do not expose the API without protection,
+	// and only if needed. Make sure you are familiar with the ["daemon attack surface"].
+	//
+	// For local access to the API, it is recommended to connect with the daemon
+	// using the default local socket connection (on Linux), or the named pipe
+	// (on Windows).
+	//
+	// If you need to access the API of a remote daemon, consider using an SSH
+	// (ssh://) connection, which is easier to set up, and requires no additional
+	// configuration if the host is accessible using ssh.
+	//
+	// If you cannot use the alternatives above, and you must expose the API over
+	// a TCP connection. Refer to [Protect the Docker daemon socket]
+	// to learn how to configure the daemon and client to use a TCP connection
+	// with TLS client authentication. Make sure you know the differences between
+	// a regular TLS connection and a TLS connection protected by TLS client
+	// authentication, and verify that the API cannot be accessed by other clients.
+	//
+	// ["daemon attack surface"]: https://docs.docker.com/go/attack-surface/
+	// [Protect the Docker daemon socket]: https://docs.docker.com/engine/security/protect-access/
+	EnvOverrideCertPath = "DOCKER_CERT_PATH"
+
+	// EnvTLSVerify is the name of the environment variable that can be used to
+	// enable or disable TLS certificate verification. When set to a non-empty
+	// value, TLS certificate verification is enabled, and the client is configured
+	// to use a TLS connection, using certificates from the default directories
+	// (within `~/.docker`); refer to EnvOverrideCertPath above for additional
+	// details.
+	//
+	// WARNING: Access to the remote API is equivalent to root access to the
+	// host where the daemon runs. Do not expose the API without protection,
+	// and only if needed. Make sure you are familiar with the ["daemon attack surface"].
+	//
+	// Before setting up your client and daemon to use a TCP connection with TLS
+	// client authentication, consider using one of the alternatives mentioned
+	// in [EnvOverrideCertPath].
+	//
+	// Disabling TLS certificate verification (for testing purposes)
+	//
+	// TLS certificate verification is enabled by default if the Client is configured
+	// to use a TLS connection, and it is highly recommended to keep verification
+	// enabled to prevent machine-in-the-middle attacks. Refer to [Protect the Docker daemon socket]
+	// in the documentation and pages linked from that page to learn how to
+	// configure the daemon and client to use a TCP connection with TLS client
+	// authentication enabled.
+	//
+	// Set the "DOCKER_TLS_VERIFY" environment to an empty string ("") to
+	// disable TLS certificate verification. Disabling verification is insecure,
+	// so should only be done for testing purposes.
+	//
+	// From the[crypto/tls.Config] documentation:
+	//
+	// InsecureSkipVerify controls whether a client verifies the server's
+	// certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
+	// accepts any certificate presented by the server and any host name in that
+	// certificate. In this mode, TLS is susceptible to machine-in-the-middle
+	// attacks unless custom verification is used. This should be used only for
+	// testing or in combination with VerifyConnection or VerifyPeerCertificate.
+	//
+	// ["daemon attack surface"]: https://docs.docker.com/go/attack-surface/
+	// [Protect the Docker daemon socket]: https://docs.docker.com/engine/security/protect-access/
+	EnvTLSVerify = "DOCKER_TLS_VERIFY"
+)
diff --git a/vendor/github.com/moby/moby/client/errors.go b/vendor/github.com/moby/moby/client/errors.go
new file mode 100644
index 000000000..9fbfa7666
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/errors.go
@@ -0,0 +1,114 @@
+package client
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net/http"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/containerd/errdefs/pkg/errhttp"
+	"github.com/moby/moby/client/pkg/versions"
+)
+
+// errConnectionFailed implements an error returned when connection failed.
+type errConnectionFailed struct {
+	error
+}
+
+// Error returns a string representation of an errConnectionFailed
+func (e errConnectionFailed) Error() string {
+	return e.error.Error()
+}
+
+func (e errConnectionFailed) Unwrap() error {
+	return e.error
+}
+
+// IsErrConnectionFailed returns true if the error is caused by connection failed.
+func IsErrConnectionFailed(err error) bool {
+	return errors.As(err, &errConnectionFailed{})
+}
+
+// connectionFailed returns an error with host in the error message when connection
+// to docker daemon failed.
+func connectionFailed(host string) error {
+	var err error
+	if host == "" {
+		err = errors.New("Cannot connect to the Docker daemon. Is the docker daemon running on this host?")
+	} else {
+		err = fmt.Errorf("Cannot connect to the Docker daemon at %s. Is the docker daemon running?", host)
+	}
+	return errConnectionFailed{error: err}
+}
+
+type objectNotFoundError struct {
+	object string
+	id     string
+}
+
+func (e objectNotFoundError) NotFound() {}
+
+func (e objectNotFoundError) Error() string {
+	return fmt.Sprintf("Error: No such %s: %s", e.object, e.id)
+}
+
+// requiresVersion returns an error if the APIVersion required is less than the
+// current supported version.
+//
+// It performs API-version negotiation if the Client is configured with this
+// option, otherwise it assumes the latest API version is used.
+func (cli *Client) requiresVersion(ctx context.Context, apiRequired, feature string) error {
+	// Make sure we negotiated (if the client is configured to do so),
+	// as code below contains API-version specific handling of options.
+	//
+	// Normally, version-negotiation (if enabled) would not happen until
+	// the API request is made.
+	if err := cli.checkVersion(ctx); err != nil {
+		return err
+	}
+	if cli.version != "" && versions.LessThan(cli.version, apiRequired) {
+		return fmt.Errorf("%q requires API version %s, but the Docker daemon API version is %s", feature, apiRequired, cli.version)
+	}
+	return nil
+}
+
+type httpError struct {
+	err    error
+	errdef error
+}
+
+func (e *httpError) Error() string {
+	return e.err.Error()
+}
+
+func (e *httpError) Unwrap() error {
+	return e.err
+}
+
+func (e *httpError) Is(target error) bool {
+	return errors.Is(e.errdef, target)
+}
+
+// httpErrorFromStatusCode creates an errdef error, based on the provided HTTP status-code
+func httpErrorFromStatusCode(err error, statusCode int) error {
+	if err == nil {
+		return nil
+	}
+	base := errhttp.ToNative(statusCode)
+	if base != nil {
+		return &httpError{err: err, errdef: base}
+	}
+
+	switch {
+	case statusCode >= http.StatusOK && statusCode < http.StatusBadRequest:
+		// it's a client error
+		return err
+	case statusCode >= http.StatusBadRequest && statusCode < http.StatusInternalServerError:
+		return &httpError{err: err, errdef: cerrdefs.ErrInvalidArgument}
+	case statusCode >= http.StatusInternalServerError && statusCode < 600:
+		return &httpError{err: err, errdef: cerrdefs.ErrInternal}
+	default:
+		return &httpError{err: err, errdef: cerrdefs.ErrUnknown}
+	}
+}
diff --git a/vendor/github.com/moby/moby/client/filters.go b/vendor/github.com/moby/moby/client/filters.go
new file mode 100644
index 000000000..3669ae0d4
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/filters.go
@@ -0,0 +1,58 @@
+package client
+
+import (
+	"encoding/json"
+	"maps"
+	"net/url"
+)
+
+// Filters describes a predicate for an API request.
+//
+// Each entry in the map is a filter term.
+// Each term is evaluated against the set of values.
+// A filter term is satisfied if any one of the values in the set is a match.
+// An item matches the filters when all terms are satisfied.
+//
+// Like all other map types in Go, the zero value is empty and read-only.
+type Filters map[string]map[string]bool
+
+// Add appends values to the value-set of term.
+//
+// The receiver f is returned for chaining.
+//
+//	f := make(Filters).Add("name", "foo", "bar").Add("status", "exited")
+func (f Filters) Add(term string, values ...string) Filters {
+	if _, ok := f[term]; !ok {
+		f[term] = make(map[string]bool)
+	}
+	for _, v := range values {
+		f[term][v] = true
+	}
+	return f
+}
+
+// Clone returns a deep copy of f.
+func (f Filters) Clone() Filters {
+	out := make(Filters, len(f))
+	for term, values := range f {
+		inner := make(map[string]bool, len(values))
+		maps.Copy(inner, values)
+		out[term] = inner
+	}
+	return out
+}
+
+// updateURLValues sets the "filters" key in values to the marshalled value of
+// f, replacing any existing values. When f is empty, any existing "filters" key
+// is removed.
+func (f Filters) updateURLValues(values url.Values) {
+	if len(f) > 0 {
+		b, err := json.Marshal(f)
+		if err != nil {
+			panic(err) // Marshaling builtin types should never fail
+		}
+		values.Set("filters", string(b))
+	} else {
+		values.Del("filters")
+	}
+}
diff --git a/vendor/github.com/moby/moby/client/hijack.go b/vendor/github.com/moby/moby/client/hijack.go
new file mode 100644
index 000000000..31c44e598
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/hijack.go
@@ -0,0 +1,172 @@
+package client
+
+import (
+	"bufio"
+	"context"
+	"fmt"
+	"net"
+	"net/http"
+	"net/url"
+	"time"
+
+	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
+)
+
+// postHijacked sends a POST request and hijacks the connection.
+func (cli *Client) postHijacked(ctx context.Context, path string, query url.Values, body any, headers map[string][]string) (HijackedResponse, error) {
+	jsonBody, err := jsonEncode(body)
+	if err != nil {
+		return HijackedResponse{}, err
+	}
+	req, err := cli.buildRequest(ctx, http.MethodPost, cli.getAPIPath(ctx, path, query), jsonBody, headers)
+	if err != nil {
+		return HijackedResponse{}, err
+	}
+	conn, mediaType, err := setupHijackConn(cli.dialer(), req, "tcp")
+	if err != nil {
+		return HijackedResponse{}, err
+	}
+
+	return NewHijackedResponse(conn, mediaType), nil
+}
+
+// DialHijack returns a hijacked connection with negotiated protocol proto.
+func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) {
+	req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, http.NoBody)
+	if err != nil {
+		return nil, err
+	}
+	req = cli.addHeaders(req, meta)
+
+	conn, _, err := setupHijackConn(cli.Dialer(), req, proto)
+	return conn, err
+}
+
+func setupHijackConn(dialer func(context.Context) (net.Conn, error), req *http.Request, proto string) (_ net.Conn, _ string, retErr error) {
+	ctx := req.Context()
+	req.Header.Set("Connection", "Upgrade")
+	req.Header.Set("Upgrade", proto)
+
+	conn, err := dialer(ctx)
+	if err != nil {
+		return nil, "", fmt.Errorf("cannot connect to the Docker daemon. Is 'docker daemon' running on this host?: %w", err)
+	}
+	defer func() {
+		if retErr != nil {
+			_ = conn.Close()
+		}
+	}()
+
+	// When we set up a TCP connection for hijack, there could be long periods
+	// of inactivity (a long running command with no output) that in certain
+	// network setups may cause ECONNTIMEOUT, leaving the client in an unknown
+	// state. Setting TCP KeepAlive on the socket connection prohibits
+	// ECONNTIMEOUT unless the socket connection truly is broken
+	if tcpConn, ok := conn.(*net.TCPConn); ok {
+		_ = tcpConn.SetKeepAlive(true)
+		_ = tcpConn.SetKeepAlivePeriod(30 * time.Second)
+	}
+
+	hc := &hijackedConn{conn, bufio.NewReader(conn)}
+
+	// Server hijacks the connection, error 'connection closed' expected
+	resp, err := otelhttp.NewTransport(hc).RoundTrip(req)
+	if err != nil {
+		return nil, "", err
+	}
+	if resp.StatusCode != http.StatusSwitchingProtocols {
+		_ = resp.Body.Close()
+		return nil, "", fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
+	}
+
+	if hc.r.Buffered() > 0 {
+		// If there is buffered content, wrap the connection.  We return an
+		// object that implements CloseWrite if the underlying connection
+		// implements it.
+		if _, ok := hc.Conn.(CloseWriter); ok {
+			conn = &hijackedConnCloseWriter{hc}
+		} else {
+			conn = hc
+		}
+	} else {
+		hc.r.Reset(nil)
+	}
+
+	return conn, resp.Header.Get("Content-Type"), nil
+}
+
+// hijackedConn wraps a net.Conn and is returned by setupHijackConn in the case
+// that a) there was already buffered data in the http layer when Hijack() was
+// called, and b) the underlying net.Conn does *not* implement CloseWrite().
+// hijackedConn does not implement CloseWrite() either.
+type hijackedConn struct {
+	net.Conn
+	r *bufio.Reader
+}
+
+func (c *hijackedConn) RoundTrip(req *http.Request) (*http.Response, error) {
+	if err := req.Write(c.Conn); err != nil {
+		return nil, err
+	}
+	return http.ReadResponse(c.r, req)
+}
+
+func (c *hijackedConn) Read(b []byte) (int, error) {
+	return c.r.Read(b)
+}
+
+// hijackedConnCloseWriter is a hijackedConn which additionally implements
+// CloseWrite().  It is returned by setupHijackConn in the case that a) there
+// was already buffered data in the http layer when Hijack() was called, and b)
+// the underlying net.Conn *does* implement CloseWrite().
+type hijackedConnCloseWriter struct {
+	*hijackedConn
+}
+
+var _ CloseWriter = &hijackedConnCloseWriter{}
+
+func (c *hijackedConnCloseWriter) CloseWrite() error {
+	conn := c.Conn.(CloseWriter)
+	return conn.CloseWrite()
+}
+
+// NewHijackedResponse initializes a [HijackedResponse] type.
+func NewHijackedResponse(conn net.Conn, mediaType string) HijackedResponse {
+	return HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn), mediaType: mediaType}
+}
+
+// HijackedResponse holds connection information for a hijacked request.
+type HijackedResponse struct {
+	mediaType string
+	Conn      net.Conn
+	Reader    *bufio.Reader
+}
+
+// Close closes the hijacked connection and reader.
+func (h *HijackedResponse) Close() {
+	h.Conn.Close()
+}
+
+// MediaType let client know if HijackedResponse hold a raw or multiplexed stream.
+// returns false if HTTP Content-Type is not relevant, and the container must be
+// inspected.
+func (h *HijackedResponse) MediaType() (string, bool) {
+	if h.mediaType == "" {
+		return "", false
+	}
+	return h.mediaType, true
+}
+
+// CloseWriter is an interface that implements structs
+// that close input streams to prevent from writing.
+type CloseWriter interface {
+	CloseWrite() error
+}
+
+// CloseWrite closes a readWriter for writing.
+func (h *HijackedResponse) CloseWrite() error {
+	if conn, ok := h.Conn.(CloseWriter); ok {
+		return conn.CloseWrite()
+	}
+	return nil
+}
diff --git a/vendor/github.com/moby/moby/client/image_build.go b/vendor/github.com/moby/moby/client/image_build.go
new file mode 100644
index 000000000..67ac204aa
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_build.go
@@ -0,0 +1,179 @@
+package client
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/json"
+	"io"
+	"net/http"
+	"net/url"
+	"strconv"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+)
+
+// ImageBuild sends a request to the daemon to build images.
+// The Body in the response implements an [io.ReadCloser] and it's up to the caller to
+// close it.
+func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, options ImageBuildOptions) (ImageBuildResult, error) {
+	query, err := cli.imageBuildOptionsToQuery(ctx, options)
+	if err != nil {
+		return ImageBuildResult{}, err
+	}
+
+	buf, err := json.Marshal(options.AuthConfigs) // #nosec G117 -- ignore "Marshaled struct field "Password" (JSON key "password") matches secret pattern"
+	if err != nil {
+		return ImageBuildResult{}, err
+	}
+
+	headers := http.Header{}
+	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
+	headers.Set("Content-Type", "application/x-tar")
+
+	resp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
+	if err != nil {
+		return ImageBuildResult{}, err
+	}
+
+	return ImageBuildResult{
+		Body: resp.Body,
+	}, nil
+}
+
+func (cli *Client) imageBuildOptionsToQuery(_ context.Context, options ImageBuildOptions) (url.Values, error) {
+	query := url.Values{}
+	if len(options.Tags) > 0 {
+		query["t"] = options.Tags
+	}
+	if len(options.SecurityOpt) > 0 {
+		query["securityopt"] = options.SecurityOpt
+	}
+	if len(options.ExtraHosts) > 0 {
+		query["extrahosts"] = options.ExtraHosts
+	}
+	if options.SuppressOutput {
+		query.Set("q", "1")
+	}
+	if options.RemoteContext != "" {
+		query.Set("remote", options.RemoteContext)
+	}
+	if options.NoCache {
+		query.Set("nocache", "1")
+	}
+	if !options.Remove {
+		// only send value when opting out because the daemon's default is
+		// to remove intermediate containers after a successful build,
+		//
+		// TODO(thaJeztah): deprecate "Remove" option, and provide a "NoRemove" or "Keep" option instead.
+		query.Set("rm", "0")
+	}
+
+	if options.ForceRemove {
+		query.Set("forcerm", "1")
+	}
+
+	if options.PullParent {
+		query.Set("pull", "1")
+	}
+
+	if options.Squash {
+		// TODO(thaJeztah): squash is experimental, and deprecated when using BuildKit?
+		query.Set("squash", "1")
+	}
+
+	if !container.Isolation.IsDefault(options.Isolation) {
+		query.Set("isolation", string(options.Isolation))
+	}
+
+	if options.CPUSetCPUs != "" {
+		query.Set("cpusetcpus", options.CPUSetCPUs)
+	}
+	if options.NetworkMode != "" && options.NetworkMode != network.NetworkDefault {
+		query.Set("networkmode", options.NetworkMode)
+	}
+	if options.CPUSetMems != "" {
+		query.Set("cpusetmems", options.CPUSetMems)
+	}
+	if options.CPUShares != 0 {
+		query.Set("cpushares", strconv.FormatInt(options.CPUShares, 10))
+	}
+	if options.CPUQuota != 0 {
+		query.Set("cpuquota", strconv.FormatInt(options.CPUQuota, 10))
+	}
+	if options.CPUPeriod != 0 {
+		query.Set("cpuperiod", strconv.FormatInt(options.CPUPeriod, 10))
+	}
+	if options.Memory != 0 {
+		query.Set("memory", strconv.FormatInt(options.Memory, 10))
+	}
+	if options.MemorySwap != 0 {
+		query.Set("memswap", strconv.FormatInt(options.MemorySwap, 10))
+	}
+	if options.CgroupParent != "" {
+		query.Set("cgroupparent", options.CgroupParent)
+	}
+	if options.ShmSize != 0 {
+		query.Set("shmsize", strconv.FormatInt(options.ShmSize, 10))
+	}
+	if options.Dockerfile != "" {
+		query.Set("dockerfile", options.Dockerfile)
+	}
+	if options.Target != "" {
+		query.Set("target", options.Target)
+	}
+	if len(options.Ulimits) != 0 {
+		ulimitsJSON, err := json.Marshal(options.Ulimits)
+		if err != nil {
+			return query, err
+		}
+		query.Set("ulimits", string(ulimitsJSON))
+	}
+	if len(options.BuildArgs) != 0 {
+		buildArgsJSON, err := json.Marshal(options.BuildArgs)
+		if err != nil {
+			return query, err
+		}
+		query.Set("buildargs", string(buildArgsJSON))
+	}
+	if len(options.Labels) != 0 {
+		labelsJSON, err := json.Marshal(options.Labels)
+		if err != nil {
+			return query, err
+		}
+		query.Set("labels", string(labelsJSON))
+	}
+	if len(options.CacheFrom) != 0 {
+		cacheFromJSON, err := json.Marshal(options.CacheFrom)
+		if err != nil {
+			return query, err
+		}
+		query.Set("cachefrom", string(cacheFromJSON))
+	}
+	if options.SessionID != "" {
+		query.Set("session", options.SessionID)
+	}
+	if len(options.Platforms) > 0 {
+		if len(options.Platforms) > 1 {
+			// TODO(thaJeztah): update API spec and add equivalent check on the daemon. We need this still for older daemons, which would ignore it.
+			return query, cerrdefs.ErrInvalidArgument.WithMessage("specifying multiple platforms is not yet supported")
+		}
+		query.Set("platform", formatPlatform(options.Platforms[0]))
+	}
+	if options.BuildID != "" {
+		query.Set("buildid", options.BuildID)
+	}
+	if options.Version != "" {
+		query.Set("version", string(options.Version))
+	}
+
+	if options.Outputs != nil {
+		outputsJSON, err := json.Marshal(options.Outputs)
+		if err != nil {
+			return query, err
+		}
+		query.Set("outputs", string(outputsJSON))
+	}
+	return query, nil
+}
diff --git a/vendor/github.com/moby/moby/client/image_build_opts.go b/vendor/github.com/moby/moby/client/image_build_opts.go
new file mode 100644
index 000000000..f65ad0f2b
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_build_opts.go
@@ -0,0 +1,79 @@
+package client
+
+import (
+	"io"
+
+	"github.com/moby/moby/api/types/build"
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/registry"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageBuildOptions holds the information
+// necessary to build images.
+type ImageBuildOptions struct {
+	Tags           []string
+	SuppressOutput bool
+	RemoteContext  string
+	NoCache        bool
+	Remove         bool
+	ForceRemove    bool
+	PullParent     bool
+	Isolation      container.Isolation
+	CPUSetCPUs     string
+	CPUSetMems     string
+	CPUShares      int64
+	CPUQuota       int64
+	CPUPeriod      int64
+	Memory         int64
+	MemorySwap     int64
+	CgroupParent   string
+	NetworkMode    string
+	ShmSize        int64
+	Dockerfile     string
+	Ulimits        []*container.Ulimit
+	// BuildArgs needs to be a *string instead of just a string so that
+	// we can tell the difference between "" (empty string) and no value
+	// at all (nil). See the parsing of buildArgs in
+	// api/server/router/build/build_routes.go for even more info.
+	BuildArgs   map[string]*string
+	AuthConfigs map[string]registry.AuthConfig
+	Context     io.Reader
+	Labels      map[string]string
+	// squash the resulting image's layers to the parent
+	// preserves the original image and creates a new one from the parent with all
+	// the changes applied to a single layer
+	Squash bool
+	// CacheFrom specifies images that are used for matching cache. Images
+	// specified here do not need to have a valid parent chain to match cache.
+	CacheFrom   []string
+	SecurityOpt []string
+	ExtraHosts  []string // List of extra hosts
+	Target      string
+	SessionID   string
+	// Platforms selects the platforms to build the image for. Multiple platforms
+	// can be provided if the daemon supports multi-platform builds.
+	Platforms []ocispec.Platform
+	// Version specifies the version of the underlying builder to use
+	Version build.BuilderVersion
+	// BuildID is an optional identifier that can be passed together with the
+	// build request. The same identifier can be used to gracefully cancel the
+	// build with the cancel request.
+	BuildID string
+	// Outputs defines configurations for exporting build results. Only supported
+	// in BuildKit mode
+	Outputs []ImageBuildOutput
+}
+
+// ImageBuildOutput defines configuration for exporting a build result
+type ImageBuildOutput struct {
+	Type  string
+	Attrs map[string]string
+}
+
+// ImageBuildResult holds information
+// returned by a server after building
+// an image.
+type ImageBuildResult struct {
+	Body io.ReadCloser
+}
diff --git a/vendor/github.com/moby/moby/client/image_history.go b/vendor/github.com/moby/moby/client/image_history.go
new file mode 100644
index 000000000..8618f1553
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_history.go
@@ -0,0 +1,55 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageHistoryWithPlatform sets the platform for the image history operation.
+func ImageHistoryWithPlatform(platform ocispec.Platform) ImageHistoryOption {
+	return imageHistoryOptionFunc(func(opt *imageHistoryOpts) error {
+		if opt.apiOptions.Platform != nil {
+			return fmt.Errorf("platform already set to %s", *opt.apiOptions.Platform)
+		}
+		opt.apiOptions.Platform = &platform
+		return nil
+	})
+}
+
+// ImageHistory returns the changes in an image in history format.
+func (cli *Client) ImageHistory(ctx context.Context, imageID string, historyOpts ...ImageHistoryOption) (ImageHistoryResult, error) {
+	query := url.Values{}
+
+	var opts imageHistoryOpts
+	for _, o := range historyOpts {
+		if err := o.Apply(&opts); err != nil {
+			return ImageHistoryResult{}, err
+		}
+	}
+
+	if opts.apiOptions.Platform != nil {
+		if err := cli.requiresVersion(ctx, "1.48", "platform"); err != nil {
+			return ImageHistoryResult{}, err
+		}
+
+		p, err := encodePlatform(opts.apiOptions.Platform)
+		if err != nil {
+			return ImageHistoryResult{}, err
+		}
+		query.Set("platform", p)
+	}
+
+	resp, err := cli.get(ctx, "/images/"+imageID+"/history", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ImageHistoryResult{}, err
+	}
+
+	var history ImageHistoryResult
+	err = json.NewDecoder(resp.Body).Decode(&history.Items)
+	return history, err
+}
diff --git a/vendor/github.com/moby/moby/client/image_history_opts.go b/vendor/github.com/moby/moby/client/image_history_opts.go
new file mode 100644
index 000000000..7fc57afd1
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_history_opts.go
@@ -0,0 +1,29 @@
+package client
+
+import (
+	"github.com/moby/moby/api/types/image"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageHistoryOption is a type representing functional options for the image history operation.
+type ImageHistoryOption interface {
+	Apply(*imageHistoryOpts) error
+}
+type imageHistoryOptionFunc func(opt *imageHistoryOpts) error
+
+func (f imageHistoryOptionFunc) Apply(o *imageHistoryOpts) error {
+	return f(o)
+}
+
+type imageHistoryOpts struct {
+	apiOptions imageHistoryOptions
+}
+
+type imageHistoryOptions struct {
+	// Platform from the manifest list to use for history.
+	Platform *ocispec.Platform
+}
+
+type ImageHistoryResult struct {
+	Items []image.HistoryResponseItem
+}
diff --git a/vendor/github.com/moby/moby/client/image_import.go b/vendor/github.com/moby/moby/client/image_import.go
new file mode 100644
index 000000000..6c9f22866
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_import.go
@@ -0,0 +1,66 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net/url"
+
+	"github.com/distribution/reference"
+)
+
+// ImageImportResult holds the response body returned by the daemon for image import.
+type ImageImportResult interface {
+	io.ReadCloser
+}
+
+// ImageImport creates a new image based on the source options. It returns the
+// JSON content in the [ImageImportResult].
+//
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
+func (cli *Client) ImageImport(ctx context.Context, source ImageImportSource, ref string, options ImageImportOptions) (ImageImportResult, error) {
+	if ref != "" {
+		// Check if the given image name can be resolved
+		if _, err := reference.ParseNormalizedNamed(ref); err != nil {
+			return nil, err
+		}
+	}
+
+	query := url.Values{}
+	if source.SourceName != "" {
+		query.Set("fromSrc", source.SourceName)
+	}
+	if ref != "" {
+		query.Set("repo", ref)
+	}
+	if options.Tag != "" {
+		query.Set("tag", options.Tag)
+	}
+	if options.Message != "" {
+		query.Set("message", options.Message)
+	}
+	if p := formatPlatform(options.Platform); p != "unknown" {
+		// TODO(thaJeztah): would we ever support multiple platforms here? (would require multiple rootfs tars as well?)
+		query.Set("platform", p)
+	}
+	for _, change := range options.Changes {
+		query.Add("changes", change)
+	}
+
+	resp, err := cli.postRaw(ctx, "/images/create", query, source.Source, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &imageImportResult{
+		ReadCloser: newCancelReadCloser(ctx, resp.Body),
+	}, nil
+}
+
+// ImageImportResult holds the response body returned by the daemon for image import.
+type imageImportResult struct {
+	io.ReadCloser
+}
+
+var (
+	_ io.ReadCloser     = (*imageImportResult)(nil)
+	_ ImageImportResult = (*imageImportResult)(nil)
+)
diff --git a/vendor/github.com/moby/moby/client/image_import_opts.go b/vendor/github.com/moby/moby/client/image_import_opts.go
new file mode 100644
index 000000000..c70473bdd
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_import_opts.go
@@ -0,0 +1,21 @@
+package client
+
+import (
+	"io"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageImportSource holds source information for ImageImport
+type ImageImportSource struct {
+	Source     io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this.
+	SourceName string    // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute.
+}
+
+// ImageImportOptions holds information to import images from the client host.
+type ImageImportOptions struct {
+	Tag      string           // Tag is the name to tag this image with. This attribute is deprecated.
+	Message  string           // Message is the message to tag the image with
+	Changes  []string         // Changes are the raw changes to apply to this image
+	Platform ocispec.Platform // Platform is the target platform of the image
+}
diff --git a/vendor/github.com/moby/moby/client/image_inspect.go b/vendor/github.com/moby/moby/client/image_inspect.go
new file mode 100644
index 000000000..635931fd0
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_inspect.go
@@ -0,0 +1,62 @@
+package client
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/url"
+)
+
+// ImageInspect returns the image information.
+func (cli *Client) ImageInspect(ctx context.Context, imageID string, inspectOpts ...ImageInspectOption) (ImageInspectResult, error) {
+	if imageID == "" {
+		return ImageInspectResult{}, objectNotFoundError{object: "image", id: imageID}
+	}
+
+	var opts imageInspectOpts
+	for _, opt := range inspectOpts {
+		if err := opt.Apply(&opts); err != nil {
+			return ImageInspectResult{}, fmt.Errorf("error applying image inspect option: %w", err)
+		}
+	}
+
+	query := url.Values{}
+	if opts.apiOptions.Manifests {
+		if err := cli.requiresVersion(ctx, "1.48", "manifests"); err != nil {
+			return ImageInspectResult{}, err
+		}
+		query.Set("manifests", "1")
+	}
+
+	if opts.apiOptions.Platform != nil {
+		if err := cli.requiresVersion(ctx, "1.49", "platform"); err != nil {
+			return ImageInspectResult{}, err
+		}
+		platform, err := encodePlatform(opts.apiOptions.Platform)
+		if err != nil {
+			return ImageInspectResult{}, err
+		}
+		query.Set("platform", platform)
+	}
+
+	resp, err := cli.get(ctx, "/images/"+imageID+"/json", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ImageInspectResult{}, err
+	}
+
+	buf := opts.raw
+	if buf == nil {
+		buf = &bytes.Buffer{}
+	}
+
+	if _, err := io.Copy(buf, resp.Body); err != nil {
+		return ImageInspectResult{}, err
+	}
+
+	var response ImageInspectResult
+	err = json.Unmarshal(buf.Bytes(), &response)
+	return response, err
+}
diff --git a/vendor/github.com/moby/moby/client/image_inspect_opts.go b/vendor/github.com/moby/moby/client/image_inspect_opts.go
new file mode 100644
index 000000000..266c1fe81
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_inspect_opts.go
@@ -0,0 +1,69 @@
+package client
+
+import (
+	"bytes"
+
+	"github.com/moby/moby/api/types/image"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageInspectOption is a type representing functional options for the image inspect operation.
+type ImageInspectOption interface {
+	Apply(*imageInspectOpts) error
+}
+type imageInspectOptionFunc func(opt *imageInspectOpts) error
+
+func (f imageInspectOptionFunc) Apply(o *imageInspectOpts) error {
+	return f(o)
+}
+
+// ImageInspectWithRawResponse instructs the client to additionally store the
+// raw inspect response in the provided buffer.
+func ImageInspectWithRawResponse(raw *bytes.Buffer) ImageInspectOption {
+	return imageInspectOptionFunc(func(opts *imageInspectOpts) error {
+		opts.raw = raw
+		return nil
+	})
+}
+
+// ImageInspectWithManifests sets manifests API option for the image inspect operation.
+// This option is only available for API version 1.48 and up.
+// With this option set, the image inspect operation response includes
+// the [image.InspectResponse.Manifests] field if the server is multi-platform
+// capable.
+func ImageInspectWithManifests(manifests bool) ImageInspectOption {
+	return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
+		clientOpts.apiOptions.Manifests = manifests
+		return nil
+	})
+}
+
+// ImageInspectWithPlatform sets platform API option for the image inspect operation.
+// This option is only available for API version 1.49 and up.
+// With this option set, the image inspect operation returns information for the
+// specified platform variant of the multi-platform image.
+func ImageInspectWithPlatform(platform *ocispec.Platform) ImageInspectOption {
+	return imageInspectOptionFunc(func(clientOpts *imageInspectOpts) error {
+		clientOpts.apiOptions.Platform = platform
+		return nil
+	})
+}
+
+type imageInspectOpts struct {
+	raw        *bytes.Buffer
+	apiOptions imageInspectOptions
+}
+
+type imageInspectOptions struct {
+	// Manifests returns the image manifests.
+	Manifests bool
+
+	// Platform selects the specific platform of a multi-platform image to inspect.
+	//
+	// This option is only available for API version 1.49 and up.
+	Platform *ocispec.Platform
+}
+
+type ImageInspectResult struct {
+	image.InspectResponse
+}
diff --git a/vendor/github.com/moby/moby/client/image_list.go b/vendor/github.com/moby/moby/client/image_list.go
new file mode 100644
index 000000000..8570709a7
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_list.go
@@ -0,0 +1,61 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/image"
+	"github.com/moby/moby/client/pkg/versions"
+)
+
+// ImageList returns a list of images in the docker host.
+//
+// Experimental: Set the [image.ListOptions.Manifest] option
+// to include [image.Summary.Manifests] with information about image manifests.
+// This is experimental and might change in the future without any backward
+// compatibility.
+func (cli *Client) ImageList(ctx context.Context, options ImageListOptions) (ImageListResult, error) {
+	var images []image.Summary
+
+	query := url.Values{}
+
+	options.Filters.updateURLValues(query)
+	if options.All {
+		query.Set("all", "1")
+	}
+	if options.SharedSize {
+		query.Set("shared-size", "1")
+	}
+	if options.Manifests {
+		// Make sure we negotiated (if the client is configured to do so),
+		// as code below contains API-version specific handling of options.
+		//
+		// Normally, version-negotiation (if enabled) would not happen until
+		// the API request is made.
+		if err := cli.checkVersion(ctx); err != nil {
+			return ImageListResult{}, err
+		}
+
+		if versions.GreaterThanOrEqualTo(cli.version, "1.47") {
+			query.Set("manifests", "1")
+		}
+	}
+	if options.Identity {
+		if err := cli.requiresVersion(ctx, "1.54", "identity"); err != nil {
+			return ImageListResult{}, err
+		}
+		// Identity data in image list is scoped to manifests.
+		query.Set("manifests", "1")
+		query.Set("identity", "1")
+	}
+
+	resp, err := cli.get(ctx, "/images/json", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ImageListResult{}, err
+	}
+
+	err = json.NewDecoder(resp.Body).Decode(&images)
+	return ImageListResult{Items: images}, err
+}
diff --git a/vendor/github.com/moby/moby/client/image_list_opts.go b/vendor/github.com/moby/moby/client/image_list_opts.go
new file mode 100644
index 000000000..297ab960c
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_list_opts.go
@@ -0,0 +1,27 @@
+package client
+
+import "github.com/moby/moby/api/types/image"
+
+// ImageListOptions holds parameters to list images with.
+type ImageListOptions struct {
+	// All controls whether all images in the graph are filtered, or just
+	// the heads.
+	All bool
+
+	// Filters is a JSON-encoded set of filter arguments.
+	Filters Filters
+
+	// SharedSize indicates whether the shared size of images should be computed.
+	SharedSize bool
+
+	// Manifests indicates whether the image manifests should be returned.
+	Manifests bool
+
+	// Identity indicates whether image identity information should be returned.
+	Identity bool
+}
+
+// ImageListResult holds the result from ImageList.
+type ImageListResult struct {
+	Items []image.Summary
+}
diff --git a/vendor/github.com/moby/moby/client/image_load.go b/vendor/github.com/moby/moby/client/image_load.go
new file mode 100644
index 000000000..ec5fcae6e
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_load.go
@@ -0,0 +1,64 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"net/url"
+)
+
+// ImageLoadResult returns information to the client about a load process.
+// It implements [io.ReadCloser] and must be closed to avoid a resource leak.
+type ImageLoadResult interface {
+	io.ReadCloser
+}
+
+// ImageLoad loads an image in the docker host from the client host. It's up
+// to the caller to close the [ImageLoadResult] returned by this function.
+//
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
+func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, loadOpts ...ImageLoadOption) (ImageLoadResult, error) {
+	var opts imageLoadOpts
+	for _, opt := range loadOpts {
+		if err := opt.Apply(&opts); err != nil {
+			return nil, err
+		}
+	}
+
+	query := url.Values{}
+	query.Set("quiet", "0")
+	if opts.apiOptions.Quiet {
+		query.Set("quiet", "1")
+	}
+	if len(opts.apiOptions.Platforms) > 0 {
+		if err := cli.requiresVersion(ctx, "1.48", "platform"); err != nil {
+			return nil, err
+		}
+
+		p, err := encodePlatforms(opts.apiOptions.Platforms...)
+		if err != nil {
+			return nil, err
+		}
+		query["platform"] = p
+	}
+
+	resp, err := cli.postRaw(ctx, "/images/load", query, input, http.Header{
+		"Content-Type": {"application/x-tar"},
+	})
+	if err != nil {
+		return nil, err
+	}
+	return &imageLoadResult{
+		ReadCloser: newCancelReadCloser(ctx, resp.Body),
+	}, nil
+}
+
+// imageLoadResult returns information to the client about a load process.
+type imageLoadResult struct {
+	io.ReadCloser
+}
+
+var (
+	_ io.ReadCloser   = (*imageLoadResult)(nil)
+	_ ImageLoadResult = (*imageLoadResult)(nil)
+)
diff --git a/vendor/github.com/moby/moby/client/image_load_opts.go b/vendor/github.com/moby/moby/client/image_load_opts.go
new file mode 100644
index 000000000..aeb4fcf83
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_load_opts.go
@@ -0,0 +1,53 @@
+package client
+
+import (
+	"fmt"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageLoadOption is a type representing functional options for the image load operation.
+type ImageLoadOption interface {
+	Apply(*imageLoadOpts) error
+}
+type imageLoadOptionFunc func(opt *imageLoadOpts) error
+
+func (f imageLoadOptionFunc) Apply(o *imageLoadOpts) error {
+	return f(o)
+}
+
+type imageLoadOpts struct {
+	apiOptions imageLoadOptions
+}
+
+type imageLoadOptions struct {
+	// Quiet suppresses progress output
+	Quiet bool
+
+	// Platforms selects the platforms to load if the image is a
+	// multi-platform image and has multiple variants.
+	Platforms []ocispec.Platform
+}
+
+// ImageLoadWithQuiet sets the quiet option for the image load operation.
+func ImageLoadWithQuiet(quiet bool) ImageLoadOption {
+	return imageLoadOptionFunc(func(opt *imageLoadOpts) error {
+		opt.apiOptions.Quiet = quiet
+		return nil
+	})
+}
+
+// ImageLoadWithPlatforms sets the platforms to be loaded from the image.
+//
+// Platform is an optional parameter that specifies the platform to load from
+// the provided multi-platform image. Passing a platform only has an effect
+// if the input image is a multi-platform image.
+func ImageLoadWithPlatforms(platforms ...ocispec.Platform) ImageLoadOption {
+	return imageLoadOptionFunc(func(opt *imageLoadOpts) error {
+		if opt.apiOptions.Platforms != nil {
+			return fmt.Errorf("platforms already set to %v", opt.apiOptions.Platforms)
+		}
+		opt.apiOptions.Platforms = platforms
+		return nil
+	})
+}
diff --git a/vendor/github.com/moby/moby/client/image_prune.go b/vendor/github.com/moby/moby/client/image_prune.go
new file mode 100644
index 000000000..7f3a25b89
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_prune.go
@@ -0,0 +1,39 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	"github.com/moby/moby/api/types/image"
+)
+
+// ImagePruneOptions holds parameters to prune images.
+type ImagePruneOptions struct {
+	Filters Filters
+}
+
+// ImagePruneResult holds the result from the [Client.ImagePrune] method.
+type ImagePruneResult struct {
+	Report image.PruneReport
+}
+
+// ImagePrune requests the daemon to delete unused data
+func (cli *Client) ImagePrune(ctx context.Context, opts ImagePruneOptions) (ImagePruneResult, error) {
+	query := url.Values{}
+	opts.Filters.updateURLValues(query)
+
+	resp, err := cli.post(ctx, "/images/prune", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ImagePruneResult{}, err
+	}
+
+	var report image.PruneReport
+	if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
+		return ImagePruneResult{}, fmt.Errorf("Error retrieving disk usage: %v", err)
+	}
+
+	return ImagePruneResult{Report: report}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/image_pull.go b/vendor/github.com/moby/moby/client/image_pull.go
new file mode 100644
index 000000000..11c0afa41
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_pull.go
@@ -0,0 +1,93 @@
+package client
+
+import (
+	"context"
+	"io"
+	"iter"
+	"net/http"
+	"net/url"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/distribution/reference"
+	"github.com/moby/moby/api/types/jsonstream"
+	"github.com/moby/moby/api/types/registry"
+	"github.com/moby/moby/client/internal"
+)
+
+type ImagePullResponse interface {
+	io.ReadCloser
+	JSONMessages(ctx context.Context) iter.Seq2[jsonstream.Message, error]
+	Wait(ctx context.Context) error
+}
+
+// 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.
+// Callers can:
+//   - use [ImagePullResponse.Wait] to wait for pull to complete
+//   - use [ImagePullResponse.JSONMessages] to monitor pull progress as a sequence
+//     of JSONMessages, [ImagePullResponse.Close] does not need to be called in this case.
+//   - use the [io.Reader] interface and call [ImagePullResponse.Close] after processing.
+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)
+	if err != nil {
+		return nil, err
+	}
+
+	query := url.Values{}
+	query.Set("fromImage", ref.Name())
+	if !options.All {
+		query.Set("tag", getAPITagFromNamedRef(ref))
+	}
+	if len(options.Platforms) > 0 {
+		if len(options.Platforms) > 1 {
+			// TODO(thaJeztah): update API spec and add equivalent check on the daemon. We need this still for older daemons, which would ignore it.
+			return nil, cerrdefs.ErrInvalidArgument.WithMessage("specifying multiple platforms is not yet supported")
+		}
+		query.Set("platform", formatPlatform(options.Platforms[0]))
+	}
+	resp, err := cli.tryImageCreate(ctx, query, staticAuth(options.RegistryAuth))
+	if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
+		resp, err = cli.tryImageCreate(ctx, query, options.PrivilegeFunc)
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	return internal.NewJSONMessageStream(resp.Body), nil
+}
+
+// getAPITagFromNamedRef returns a tag from the specified reference.
+// This function is necessary as long as the docker "server" api expects
+// digests to be sent as tags and makes a distinction between the name
+// and tag/digest part of a reference.
+func getAPITagFromNamedRef(ref reference.Named) string {
+	if digested, ok := ref.(reference.Digested); ok {
+		return digested.Digest().String()
+	}
+	ref = reference.TagNameOnly(ref)
+	if tagged, ok := ref.(reference.Tagged); ok {
+		return tagged.Tag()
+	}
+	return ""
+}
+
+func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, resolveAuth registry.RequestAuthConfig) (*http.Response, error) {
+	hdr := http.Header{}
+	if resolveAuth != nil {
+		registryAuth, err := resolveAuth(ctx)
+		if err != nil {
+			return nil, err
+		}
+		if registryAuth != "" {
+			hdr.Set(registry.AuthHeader, registryAuth)
+		}
+	}
+	return cli.post(ctx, "/images/create", query, nil, hdr)
+}
diff --git a/vendor/github.com/moby/moby/client/image_pull_opts.go b/vendor/github.com/moby/moby/client/image_pull_opts.go
new file mode 100644
index 000000000..1b78185dd
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_pull_opts.go
@@ -0,0 +1,25 @@
+package client
+
+import (
+	"context"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImagePullOptions holds information to pull images.
+type ImagePullOptions struct {
+	All          bool
+	RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
+
+	// PrivilegeFunc is a function that clients can supply to retry operations
+	// after getting an authorization error. This function returns the registry
+	// authentication header value in base64 encoded format, or an error if the
+	// privilege request fails.
+	//
+	// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
+	PrivilegeFunc func(context.Context) (string, error)
+
+	// Platforms selects the platforms to pull. Multiple platforms can be
+	// specified if the image ia a multi-platform image.
+	Platforms []ocispec.Platform
+}
diff --git a/vendor/github.com/moby/moby/client/image_push.go b/vendor/github.com/moby/moby/client/image_push.go
new file mode 100644
index 000000000..5dd8bc140
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_push.go
@@ -0,0 +1,98 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"iter"
+	"net/http"
+	"net/url"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/distribution/reference"
+	"github.com/moby/moby/api/types/jsonstream"
+	"github.com/moby/moby/api/types/registry"
+	"github.com/moby/moby/client/internal"
+)
+
+type ImagePushResponse interface {
+	io.ReadCloser
+	JSONMessages(ctx context.Context) iter.Seq2[jsonstream.Message, error]
+	Wait(ctx context.Context) error
+}
+
+// ImagePush requests the docker host to push an image to a remote registry.
+// It executes the privileged function if the operation is unauthorized
+// and it tries one more time.
+// Callers can
+//   - use [ImagePushResponse.Wait] to wait for push to complete
+//   - use [ImagePushResponse.JSONMessages] to monitor pull progress as a sequence
+//     of JSONMessages, [ImagePushResponse.Close] does not need to be called in this case.
+//   - use the [io.Reader] interface and call [ImagePushResponse.Close] after processing.
+func (cli *Client) ImagePush(ctx context.Context, image string, options ImagePushOptions) (ImagePushResponse, error) {
+	ref, err := reference.ParseNormalizedNamed(image)
+	if err != nil {
+		return nil, err
+	}
+
+	if _, ok := ref.(reference.Digested); ok {
+		return nil, errors.New("cannot push a digest reference")
+	}
+
+	query := url.Values{}
+	if !options.All {
+		ref = reference.TagNameOnly(ref)
+		if tagged, ok := ref.(reference.Tagged); ok {
+			query.Set("tag", tagged.Tag())
+		}
+	}
+
+	if options.Platform != nil {
+		if err := cli.requiresVersion(ctx, "1.46", "platform"); err != nil {
+			return nil, err
+		}
+
+		p := *options.Platform
+		pJson, err := json.Marshal(p)
+		if err != nil {
+			return nil, fmt.Errorf("invalid platform: %v", err)
+		}
+
+		query.Set("platform", string(pJson))
+	}
+
+	resp, err := cli.tryImagePush(ctx, ref.Name(), query, staticAuth(options.RegistryAuth))
+	if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
+		resp, err = cli.tryImagePush(ctx, ref.Name(), query, options.PrivilegeFunc)
+	}
+	if err != nil {
+		return nil, err
+	}
+	return internal.NewJSONMessageStream(resp.Body), nil
+}
+
+func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, resolveAuth registry.RequestAuthConfig) (*http.Response, error) {
+	hdr := http.Header{}
+	if resolveAuth != nil {
+		registryAuth, err := resolveAuth(ctx)
+		if err != nil {
+			return nil, err
+		}
+		if registryAuth != "" {
+			hdr.Set(registry.AuthHeader, registryAuth)
+		}
+	}
+
+	// Always send a body (which may be an empty JSON document ("{}")) to prevent
+	// EOF errors on older daemons which had faulty fallback code for handling
+	// authentication in the body when no auth-header was set, resulting in;
+	//
+	//	Error response from daemon: bad parameters and missing X-Registry-Auth: invalid X-Registry-Auth header: EOF
+	//
+	// We use [http.NoBody], which gets marshaled to an empty JSON document.
+	//
+	// see: https://github.com/moby/moby/commit/ea29dffaa541289591aa44fa85d2a596ce860e16
+	return cli.post(ctx, "/images/"+imageID+"/push", query, http.NoBody, hdr)
+}
diff --git a/vendor/github.com/moby/moby/client/image_push_opts.go b/vendor/github.com/moby/moby/client/image_push_opts.go
new file mode 100644
index 000000000..591c6b605
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_push_opts.go
@@ -0,0 +1,26 @@
+package client
+
+import (
+	"context"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImagePushOptions holds information to push images.
+type ImagePushOptions struct {
+	All          bool
+	RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
+
+	// PrivilegeFunc is a function that clients can supply to retry operations
+	// after getting an authorization error. This function returns the registry
+	// authentication header value in base64 encoded format, or an error if the
+	// privilege request fails.
+	//
+	// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
+	PrivilegeFunc func(context.Context) (string, error)
+
+	// Platform is an optional field that selects a specific platform to push
+	// when the image is a multi-platform image.
+	// Using this will only push a single platform-specific manifest.
+	Platform *ocispec.Platform `json:",omitempty"`
+}
diff --git a/vendor/github.com/moby/moby/client/image_remove.go b/vendor/github.com/moby/moby/client/image_remove.go
new file mode 100644
index 000000000..095b4f04c
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_remove.go
@@ -0,0 +1,39 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/image"
+)
+
+// ImageRemove removes an image from the docker host.
+func (cli *Client) ImageRemove(ctx context.Context, imageID string, options ImageRemoveOptions) (ImageRemoveResult, error) {
+	query := url.Values{}
+
+	if options.Force {
+		query.Set("force", "1")
+	}
+	if !options.PruneChildren {
+		query.Set("noprune", "1")
+	}
+
+	if len(options.Platforms) > 0 {
+		p, err := encodePlatforms(options.Platforms...)
+		if err != nil {
+			return ImageRemoveResult{}, err
+		}
+		query["platforms"] = p
+	}
+
+	resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ImageRemoveResult{}, err
+	}
+
+	var dels []image.DeleteResponse
+	err = json.NewDecoder(resp.Body).Decode(&dels)
+	return ImageRemoveResult{Items: dels}, err
+}
diff --git a/vendor/github.com/moby/moby/client/image_remove_opts.go b/vendor/github.com/moby/moby/client/image_remove_opts.go
new file mode 100644
index 000000000..3b5d8a77f
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_remove_opts.go
@@ -0,0 +1,18 @@
+package client
+
+import (
+	"github.com/moby/moby/api/types/image"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageRemoveOptions holds parameters to remove images.
+type ImageRemoveOptions struct {
+	Platforms     []ocispec.Platform
+	Force         bool
+	PruneChildren bool
+}
+
+// ImageRemoveResult holds the delete responses returned by the daemon.
+type ImageRemoveResult struct {
+	Items []image.DeleteResponse
+}
diff --git a/vendor/github.com/moby/moby/client/image_save.go b/vendor/github.com/moby/moby/client/image_save.go
new file mode 100644
index 000000000..508f88b7d
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_save.go
@@ -0,0 +1,59 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net/url"
+)
+
+type ImageSaveResult interface {
+	io.ReadCloser
+}
+
+// ImageSave retrieves one or more images from the docker host as an
+// [ImageSaveResult]. Callers should close the reader, but the underlying
+// [io.ReadCloser] is automatically closed if the context is canceled,
+//
+// Platforms is an optional parameter that specifies the platforms to save
+// from the image. Passing a platform only has an effect if the input image
+// is a multi-platform image.
+func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, saveOpts ...ImageSaveOption) (ImageSaveResult, error) {
+	var opts imageSaveOpts
+	for _, opt := range saveOpts {
+		if err := opt.Apply(&opts); err != nil {
+			return nil, err
+		}
+	}
+
+	query := url.Values{
+		"names": imageIDs,
+	}
+
+	if len(opts.apiOptions.Platforms) > 0 {
+		if err := cli.requiresVersion(ctx, "1.48", "platform"); err != nil {
+			return nil, err
+		}
+		p, err := encodePlatforms(opts.apiOptions.Platforms...)
+		if err != nil {
+			return nil, err
+		}
+		query["platform"] = p
+	}
+
+	resp, err := cli.get(ctx, "/images/get", query, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &imageSaveResult{
+		ReadCloser: newCancelReadCloser(ctx, resp.Body),
+	}, nil
+}
+
+type imageSaveResult struct {
+	io.ReadCloser
+}
+
+var (
+	_ io.ReadCloser   = (*imageSaveResult)(nil)
+	_ ImageSaveResult = (*imageSaveResult)(nil)
+)
diff --git a/vendor/github.com/moby/moby/client/image_save_opts.go b/vendor/github.com/moby/moby/client/image_save_opts.go
new file mode 100644
index 000000000..9c0b3b74a
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_save_opts.go
@@ -0,0 +1,41 @@
+package client
+
+import (
+	"fmt"
+
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+type ImageSaveOption interface {
+	Apply(*imageSaveOpts) error
+}
+
+type imageSaveOptionFunc func(opt *imageSaveOpts) error
+
+func (f imageSaveOptionFunc) Apply(o *imageSaveOpts) error {
+	return f(o)
+}
+
+// ImageSaveWithPlatforms sets the platforms to be saved from the image. It
+// produces an error if platforms are already set. This option only has an
+// effect if the input image is a multi-platform image.
+func ImageSaveWithPlatforms(platforms ...ocispec.Platform) ImageSaveOption {
+	// TODO(thaJeztah): verify the GoDoc; do we produce an error for a single-platform image without the given platform?
+	return imageSaveOptionFunc(func(opt *imageSaveOpts) error {
+		if opt.apiOptions.Platforms != nil {
+			return fmt.Errorf("platforms already set to %v", opt.apiOptions.Platforms)
+		}
+		opt.apiOptions.Platforms = platforms
+		return nil
+	})
+}
+
+type imageSaveOpts struct {
+	apiOptions imageSaveOptions
+}
+
+type imageSaveOptions struct {
+	// Platforms selects the platforms to save if the image is a
+	// multi-platform image and has multiple variants.
+	Platforms []ocispec.Platform
+}
diff --git a/vendor/github.com/moby/moby/client/image_search.go b/vendor/github.com/moby/moby/client/image_search.go
new file mode 100644
index 000000000..6e280906a
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_search.go
@@ -0,0 +1,47 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"net/url"
+	"strconv"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/moby/moby/api/types/registry"
+)
+
+// ImageSearch makes the docker host search by a term in a remote registry.
+// The list of results is not sorted in any fashion.
+func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSearchOptions) (ImageSearchResult, error) {
+	var results []registry.SearchResult
+	query := url.Values{}
+	query.Set("term", term)
+	if options.Limit > 0 {
+		query.Set("limit", strconv.Itoa(options.Limit))
+	}
+
+	options.Filters.updateURLValues(query)
+
+	resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth)
+	defer ensureReaderClosed(resp)
+	if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
+		newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
+		if privilegeErr != nil {
+			return ImageSearchResult{}, privilegeErr
+		}
+		resp, err = cli.tryImageSearch(ctx, query, newAuthHeader)
+	}
+	if err != nil {
+		return ImageSearchResult{}, err
+	}
+
+	err = json.NewDecoder(resp.Body).Decode(&results)
+	return ImageSearchResult{Items: results}, err
+}
+
+func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
+	return cli.get(ctx, "/images/search", query, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
+}
diff --git a/vendor/github.com/moby/moby/client/image_search_opts.go b/vendor/github.com/moby/moby/client/image_search_opts.go
new file mode 100644
index 000000000..95a7d41fa
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_search_opts.go
@@ -0,0 +1,27 @@
+package client
+
+import (
+	"context"
+
+	"github.com/moby/moby/api/types/registry"
+)
+
+// ImageSearchResult wraps results returned by ImageSearch.
+type ImageSearchResult struct {
+	Items []registry.SearchResult
+}
+
+// ImageSearchOptions holds parameters to search images with.
+type ImageSearchOptions struct {
+	RegistryAuth string
+
+	// PrivilegeFunc is a function that clients can supply to retry operations
+	// after getting an authorization error. This function returns the registry
+	// authentication header value in base64 encoded format, or an error if the
+	// privilege request fails.
+	//
+	// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
+	PrivilegeFunc func(context.Context) (string, error)
+	Filters       Filters
+	Limit         int
+}
diff --git a/vendor/github.com/moby/moby/client/image_tag.go b/vendor/github.com/moby/moby/client/image_tag.go
new file mode 100644
index 000000000..37272914f
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/image_tag.go
@@ -0,0 +1,50 @@
+package client
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net/url"
+
+	"github.com/distribution/reference"
+)
+
+// ImageTagOptions holds options for [Client.ImageTag].
+type ImageTagOptions struct {
+	Source string
+	Target string
+}
+
+// ImageTagResult holds the result of [Client.ImageTag].
+type ImageTagResult struct{}
+
+// ImageTag tags an image in the docker host
+func (cli *Client) ImageTag(ctx context.Context, options ImageTagOptions) (ImageTagResult, error) {
+	source := options.Source
+	target := options.Target
+
+	if _, err := reference.ParseAnyReference(source); err != nil {
+		return ImageTagResult{}, fmt.Errorf("error parsing reference: %q is not a valid repository/tag: %w", source, err)
+	}
+
+	ref, err := reference.ParseNormalizedNamed(target)
+	if err != nil {
+		return ImageTagResult{}, fmt.Errorf("error parsing reference: %q is not a valid repository/tag: %w", target, err)
+	}
+
+	if _, ok := ref.(reference.Digested); ok {
+		return ImageTagResult{}, errors.New("refusing to create a tag with a digest reference")
+	}
+
+	ref = reference.TagNameOnly(ref)
+
+	query := url.Values{}
+	query.Set("repo", ref.Name())
+	if tagged, ok := ref.(reference.Tagged); ok {
+		query.Set("tag", tagged.Tag())
+	}
+
+	resp, err := cli.post(ctx, "/images/"+source+"/tag", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	return ImageTagResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/internal/json-stream.go b/vendor/github.com/moby/moby/client/internal/json-stream.go
new file mode 100644
index 000000000..d86b99da2
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/internal/json-stream.go
@@ -0,0 +1,62 @@
+package internal
+
+import (
+	"encoding/json"
+	"io"
+	"slices"
+
+	"github.com/moby/moby/api/types"
+)
+
+const rs = 0x1E
+
+type DecoderFn func(v any) error
+
+// NewJSONStreamDecoder builds a DecoderFn to read a stream of JSON records
+// formatted with the specified content-type.
+func NewJSONStreamDecoder(r io.Reader, contentType types.MediaType) DecoderFn {
+	switch contentType {
+	case types.MediaTypeJSONSequence:
+		return json.NewDecoder(NewRSFilterReader(r)).Decode
+	case types.MediaTypeJSON, types.MediaTypeNDJSON, types.MediaTypeJSONLines:
+		fallthrough
+	default:
+		return json.NewDecoder(r).Decode
+	}
+}
+
+type rsFilterReader struct {
+	reader io.Reader
+}
+
+// NewRSFilterReader creates an [io.Reader] that filters out ASCII Record Separators (RS).
+func NewRSFilterReader(r io.Reader) io.Reader {
+	return &rsFilterReader{reader: r}
+}
+
+func (r *rsFilterReader) Read(p []byte) (int, error) {
+	if len(p) == 0 {
+		return 0, nil
+	}
+
+	for {
+		n, err := r.reader.Read(p)
+		if n == 0 {
+			return 0, err
+		}
+
+		filtered := slices.DeleteFunc(p[:n], func(b byte) bool { return b == rs })
+		n = len(filtered)
+		if err != nil {
+			if err == io.EOF && n > 0 {
+				return n, nil
+			}
+			return n, err
+		}
+		if n == 0 {
+			// Avoid returning (0, nil) after consuming input; keep reading until data or an error (e.g., EOF).
+			continue
+		}
+		return n, nil
+	}
+}
diff --git a/vendor/github.com/moby/moby/client/internal/jsonmessages.go b/vendor/github.com/moby/moby/client/internal/jsonmessages.go
new file mode 100644
index 000000000..05210d0dc
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/internal/jsonmessages.go
@@ -0,0 +1,135 @@
+package internal
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"io"
+	"iter"
+	"sync"
+
+	"github.com/containerd/errdefs/pkg/errhttp"
+
+	"github.com/moby/moby/api/types/jsonstream"
+)
+
+func NewJSONMessageStream(rc io.ReadCloser) Stream {
+	if rc == nil {
+		panic("nil io.ReadCloser")
+	}
+	return Stream{
+		rc:    rc,
+		close: sync.OnceValue(rc.Close),
+	}
+}
+
+type Stream struct {
+	rc    io.ReadCloser
+	close func() error
+}
+
+// Read implements io.ReadCloser
+func (r Stream) Read(p []byte) (n int, err error) {
+	if r.rc == nil {
+		return 0, io.EOF
+	}
+	return r.rc.Read(p)
+}
+
+// Close implements io.ReadCloser
+func (r Stream) Close() error {
+	if r.close == nil {
+		return nil
+	}
+	return r.close()
+}
+
+var _ io.ReadCloser = Stream{}
+
+// JSONMessages decodes the response stream as a sequence of [jsonstream.Message].
+// The underlying [io.Reader] is closed when the stream ends or if the context
+// is cancelled.
+func (r Stream) JSONMessages(ctx context.Context) iter.Seq2[jsonstream.Message, error] {
+	stop := context.AfterFunc(ctx, func() {
+		_ = r.Close()
+	})
+	return func(yield func(jsonstream.Message, error) bool) {
+		defer func() {
+			stop() // unregister AfterFunc
+			_ = r.Close()
+		}()
+
+		dec := json.NewDecoder(r)
+		for {
+			var jm jsonstream.Message
+			if err := dec.Decode(&jm); err != nil {
+				if errors.Is(err, io.EOF) {
+					return
+				}
+				if err := ctx.Err(); err != nil {
+					// Do not return decoding errors if the context was
+					// cancelled, because the decoding errors may be due
+					// to the context being cancelled.
+					yield(jsonstream.Message{}, err)
+					return
+				}
+				yield(jsonstream.Message{}, err)
+				return
+			}
+			if !yield(jm, nil) {
+				return
+			}
+		}
+	}
+}
+
+// Wait consumes the stream until completion.
+//
+// It returns nil if the operation completes successfully. Errors are
+// returned if the context is canceled, a decoding/transport failure
+// occurs, or a JSON message reports an error ([jsonstream.Message.Error]).
+func (r Stream) Wait(ctx context.Context) error {
+	for jm, err := range r.JSONMessages(ctx) {
+		if err != nil {
+			// decode, transport and context cancellation errors.
+			return err
+		}
+		if jm.Error != nil {
+			// push/pull failures.
+			return httpErrorFromStatusCode(jm.Error, jm.Error.Code)
+		}
+	}
+	return nil
+}
+
+type httpError struct {
+	err    error
+	errdef error
+}
+
+func (e *httpError) Error() string {
+	return e.err.Error()
+}
+
+func (e *httpError) Unwrap() error {
+	return e.err
+}
+
+func (e *httpError) Is(target error) bool {
+	return errors.Is(e.errdef, target)
+}
+
+// httpErrorFromStatusCode creates an errdef error, based on the provided HTTP status-code
+//
+// TODO(thaJeztah): unify with the implementation in client and move to an internal package
+// see https://github.com/moby/moby/blob/client/v0.4.0/client/errors.go#L76-L114
+func httpErrorFromStatusCode(err error, statusCode int) error {
+	if err == nil {
+		return nil
+	}
+
+	return &httpError{
+		err:    err,
+		errdef: errhttp.ToNative(statusCode),
+	}
+}
diff --git a/vendor/github.com/moby/moby/client/internal/mod/mod.go b/vendor/github.com/moby/moby/client/internal/mod/mod.go
new file mode 100644
index 000000000..355eb9532
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/internal/mod/mod.go
@@ -0,0 +1,226 @@
+// Package mod provides a small helper to extract a module's version
+// from [debug.BuildInfo] without depending on [golang.org/x/mod].
+//
+// [golang.org/x/mod]: https://pkg.go.dev/golang.org/x/mod
+package mod
+
+import (
+	"fmt"
+	"runtime/debug"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+var readBuildInfo = sync.OnceValues(debug.ReadBuildInfo)
+
+// Version returns a best-effort version string for the given module path,
+// similar to [mod.Version] in the daemon.
+//
+// If the module is present in [debug.BuildInfo] dependencies, its version
+// is returned. Tagged versions are returned as-is (with "+incompatible"
+// stripped). [Pseudo-versions] are normalized to:
+//
+//	<base>+<revision>[+meta...][+dirty]
+//
+// Where "<base>" matches the behavior of [module.PseudoVersionBase] (i.e.,
+// downgrade to the previous tag for non-prerelease Pseudo-versions).
+//
+// If the module is replaced (for example via go.work or replace directives),
+// or no usable version information is available, Version returns an empty string.
+//
+// The returned value is intended for display purposes (e.g., in a default
+// User-Agent), not for version comparison.
+//
+// [mod.Version]: https://pkg.go.dev/github.com/moby/moby/v2@v2.0.0-beta.7/daemon/internal/builder-next/worker/mod#Version
+// [module.PseudoVersionBase]: https://pkg.go.dev/golang.org/x/mod@v0.34.0/module#PseudoVersionBase
+// [Pseudo-versions]: https://cs.opensource.google/go/x/mod/+/refs/tags/v0.34.0:module/pseudo.go;l=5-33
+func Version(name string) string {
+	bi, ok := readBuildInfo()
+	if !ok || bi == nil {
+		return ""
+	}
+	return moduleVersion(name, bi)
+}
+
+func moduleVersion(name string, bi *debug.BuildInfo) (modVersion string) {
+	if bi == nil {
+		return ""
+	}
+
+	// Check if we're the main module.
+	if v, ok := getVersion(name, &bi.Main); ok {
+		return v
+	}
+
+	// iterate over all dependencies and find name
+	for _, dep := range bi.Deps {
+		if v, ok := getVersion(name, dep); ok {
+			return v
+		}
+	}
+
+	return ""
+}
+
+func getVersion(name string, dep *debug.Module) (string, bool) {
+	if dep == nil || dep.Path != name {
+		return "", false
+	}
+
+	v := dep.Version
+	if dep.Replace != nil && dep.Replace.Version != "" {
+		v = dep.Replace.Version
+	}
+	if v == "" || v == "(devel)" {
+		return "", true
+	}
+
+	return normalize(v), true
+}
+
+// normalize converts a Go module version into a display-friendly form:
+//
+//   - strips "+incompatible" unconditionally
+//   - if pseudo: vX.Y.Z[-pre][+rev][+meta...][+dirty]
+//   - if tagged: vX.Y.Z[-pre][+meta...][+dirty]
+func normalize(v string) string {
+	base, metas, dirty := splitMetadata(v)
+
+	out := base
+	if base2, rev, undoPatch, ok := splitPseudo(base); ok {
+		if undoPatch {
+			// Downgrade the patch version that was raised by pseudo-versions:
+			//
+			//	(2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456
+			if major, minor, patch, ok := parseSemVer(base2); ok && patch > 0 {
+				patch--
+				base2 = fmt.Sprintf("v%d.%d.%d", major, minor, patch)
+			}
+		}
+		// Go pseudo rev is typically 12, but be defensive.
+		if len(rev) > 12 {
+			rev = rev[:12]
+		}
+		out = base2 + "+" + rev
+	}
+
+	// Preserve other metadata (except for "+incompatible").
+	for _, m := range metas {
+		out += m
+	}
+	if dirty {
+		// +dirty goes last
+		out += "+dirty"
+	}
+	return out
+}
+
+func splitMetadata(v string) (base string, metas []string, dirty bool) {
+	base, meta, ok := strings.Cut(v, "+")
+	if !ok || meta == "" {
+		return base, nil, false
+	}
+	for m := range strings.SplitSeq(meta, "+") {
+		// drop incompatible, extract dirty, preserve everything else.
+		switch m {
+		case "incompatible", "":
+			// drop "+incompatible" and empty strings
+		case "dirty":
+			dirty = true
+		default:
+			metas = append(metas, "+"+m)
+		}
+	}
+
+	return base, metas, dirty
+}
+
+// splitPseudo splits a pseudo-version into base + revision, and reports whether
+// it is a (Z+1) pseudo that needs patch undo.
+//
+// Supported (after stripping +incompatible/+dirty metadata):
+//
+// (1) vX.0.0-yyyymmddhhmmss-abcdef123456
+// (2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456
+// (4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456
+func splitPseudo(v string) (base, rev string, undoPatch bool, ok bool) {
+	// Split off revision at the last '-'.
+	last := strings.LastIndexByte(v, '-')
+	if last < 0 || last+1 >= len(v) {
+		return "", "", false, false
+	}
+	rev = v[last+1:]
+	left := v[:last]
+
+	// First try the dot-joined timestamp forms:
+	//   ...-0.<ts>   (release pseudo; undoPatch)
+	//   ....0.<ts>   (prerelease pseudo; preserve prerelease)
+	if dot := strings.LastIndexByte(left, '.'); dot > 0 && dot+1 < len(left) {
+		ts := left[dot+1:]
+		if isTimestamp(ts) {
+			prefix := left[:dot] // ends with "-0" or ".0" for forms (2)/(4)
+			switch {
+			case strings.HasSuffix(prefix, "-0"):
+				// (2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456
+				return prefix[:len(prefix)-2], rev, true, true
+			case strings.HasSuffix(prefix, ".0"):
+				// (4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456
+				return prefix[:len(prefix)-2], rev, false, true
+			}
+		}
+	}
+
+	// Fall back to form (1): ...-<ts>-<rev>
+	//
+	// (1) vX.0.0-yyyymmddhhmmss-abcdef123456
+	if dash := strings.LastIndexByte(left, '-'); dash > 0 && dash+1 < len(left) {
+		ts := left[dash+1:]
+		if isTimestamp(ts) {
+			return left[:dash], rev, false, true
+		}
+	}
+
+	return "", "", false, false
+}
+
+// isTimestamp checks whether s is a timestamp ("yyyymmddhhmmss")
+// component in a module version (vX.0.0-yyyymmddhhmmss-abcdef123456).
+func isTimestamp(s string) bool {
+	if len(s) != 14 {
+		return false
+	}
+	for i := range len(s) {
+		c := s[i]
+		if c < '0' || c > '9' {
+			return false
+		}
+	}
+	return true
+}
+
+// parseSemVer parses "vX.Y.Z" into numeric components.
+// It intentionally handles only the strict three-segment core form.
+func parseSemVer(v string) (major, minor, patch int, ok bool) {
+	if len(v) < 2 || v[0] != 'v' {
+		return 0, 0, 0, false
+	}
+	parts := strings.Split(v[1:], ".")
+	if len(parts) != 3 {
+		return 0, 0, 0, false
+	}
+	var err error
+	major, err = strconv.Atoi(parts[0])
+	if err != nil {
+		return 0, 0, 0, false
+	}
+	minor, err = strconv.Atoi(parts[1])
+	if err != nil {
+		return 0, 0, 0, false
+	}
+	patch, err = strconv.Atoi(parts[2])
+	if err != nil {
+		return 0, 0, 0, false
+	}
+	return major, minor, patch, true
+}
diff --git a/vendor/github.com/moby/moby/client/internal/timestamp/timestamp.go b/vendor/github.com/moby/moby/client/internal/timestamp/timestamp.go
new file mode 100644
index 000000000..7b175f0c9
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/internal/timestamp/timestamp.go
@@ -0,0 +1,131 @@
+package timestamp
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// These are additional predefined layouts for use in Time.Format and Time.Parse
+// with --since and --until parameters for `docker logs` and `docker events`
+const (
+	rFC3339Local     = "2006-01-02T15:04:05"           // RFC3339 with local timezone
+	rFC3339NanoLocal = "2006-01-02T15:04:05.999999999" // RFC3339Nano with local timezone
+	dateWithZone     = "2006-01-02Z07:00"              // RFC3339 with time at 00:00:00
+	dateLocal        = "2006-01-02"                    // RFC3339 with local timezone and time at 00:00:00
+)
+
+// GetTimestamp tries to parse given string as golang duration,
+// then RFC3339 time and finally as a Unix timestamp. If
+// any of these were successful, it returns a Unix timestamp
+// as string otherwise returns the given value back.
+// In case of duration input, the returned timestamp is computed
+// as the given reference time minus the amount of the duration.
+func GetTimestamp(value string, reference time.Time) (string, error) {
+	if d, err := time.ParseDuration(value); value != "0" && err == nil {
+		return strconv.FormatInt(reference.Add(-d).Unix(), 10), nil
+	}
+
+	var format string
+	// if the string has a Z or a + or three dashes use parse otherwise use parseinlocation
+	parseInLocation := !strings.ContainsAny(value, "zZ+") && strings.Count(value, "-") != 3
+
+	if strings.Contains(value, ".") {
+		if parseInLocation {
+			format = rFC3339NanoLocal
+		} else {
+			format = time.RFC3339Nano
+		}
+	} else if strings.Contains(value, "T") {
+		// we want the number of colons in the T portion of the timestamp
+		tcolons := strings.Count(value, ":")
+		// if parseInLocation is off and we have a +/- zone offset (not Z) then
+		// there will be an extra colon in the input for the tz offset subtract that
+		// colon from the tcolons count
+		if !parseInLocation && !strings.ContainsAny(value, "zZ") && tcolons > 0 {
+			tcolons--
+		}
+		if parseInLocation {
+			switch tcolons {
+			case 0:
+				format = "2006-01-02T15"
+			case 1:
+				format = "2006-01-02T15:04"
+			default:
+				format = rFC3339Local
+			}
+		} else {
+			switch tcolons {
+			case 0:
+				format = "2006-01-02T15Z07:00"
+			case 1:
+				format = "2006-01-02T15:04Z07:00"
+			default:
+				format = time.RFC3339
+			}
+		}
+	} else if parseInLocation {
+		format = dateLocal
+	} else {
+		format = dateWithZone
+	}
+
+	var t time.Time
+	var err error
+
+	if parseInLocation {
+		t, err = time.ParseInLocation(format, value, time.FixedZone(reference.Zone()))
+	} else {
+		t, err = time.Parse(format, value)
+	}
+
+	if err != nil {
+		// if there is a `-` then it's an RFC3339 like timestamp
+		if strings.Contains(value, "-") {
+			return "", err // was probably an RFC3339 like timestamp but the parser failed with an error
+		}
+		if _, _, err := parseTimestamp(value); err != nil {
+			return "", fmt.Errorf("failed to parse value as time or duration: %q", value)
+		}
+		return value, nil // unix timestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server)
+	}
+
+	return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil
+}
+
+// ParseTimestamps returns seconds and nanoseconds from a timestamp that has
+// the format ("%d.%09d", time.Unix(), int64(time.Nanosecond())).
+// If the incoming nanosecond portion is longer than 9 digits it is truncated.
+// The expectation is that the seconds and nanoseconds will be used to create a
+// time variable.  For example:
+//
+//	seconds, nanoseconds, _ := ParseTimestamp("1136073600.000000001",0)
+//	since := time.Unix(seconds, nanoseconds)
+//
+// returns seconds as defaultSeconds if value == ""
+func ParseTimestamps(value string, defaultSeconds int64) (seconds int64, nanoseconds int64, _ error) {
+	if value == "" {
+		return defaultSeconds, 0, nil
+	}
+	return parseTimestamp(value)
+}
+
+func parseTimestamp(value string) (seconds int64, nanoseconds int64, _ error) {
+	s, n, ok := strings.Cut(value, ".")
+	sec, err := strconv.ParseInt(s, 10, 64)
+	if err != nil {
+		return sec, 0, err
+	}
+	if !ok {
+		return sec, 0, nil
+	}
+	nsec, err := strconv.ParseInt(n, 10, 64)
+	if err != nil {
+		return sec, nsec, err
+	}
+	// should already be in nanoseconds but just in case convert n to nanoseconds
+	nsec = int64(float64(nsec) * math.Pow(float64(10), float64(9-len(n))))
+	return sec, nsec, nil
+}
diff --git a/vendor/github.com/moby/moby/client/login.go b/vendor/github.com/moby/moby/client/login.go
new file mode 100644
index 000000000..b295080ab
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/login.go
@@ -0,0 +1,45 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/registry"
+)
+
+type RegistryLoginOptions struct {
+	Username      string
+	Password      string
+	ServerAddress string
+	IdentityToken string
+	RegistryToken string
+}
+
+// RegistryLoginResult holds the result of a RegistryLogin query.
+type RegistryLoginResult struct {
+	Auth registry.AuthResponse
+}
+
+// RegistryLogin authenticates the docker server with a given docker registry.
+// It returns unauthorizedError when the authentication fails.
+func (cli *Client) RegistryLogin(ctx context.Context, options RegistryLoginOptions) (RegistryLoginResult, error) {
+	auth := registry.AuthConfig{
+		Username:      options.Username,
+		Password:      options.Password,
+		ServerAddress: options.ServerAddress,
+		IdentityToken: options.IdentityToken,
+		RegistryToken: options.RegistryToken,
+	}
+
+	resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil)
+	defer ensureReaderClosed(resp)
+
+	if err != nil {
+		return RegistryLoginResult{}, err
+	}
+
+	var response registry.AuthResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	return RegistryLoginResult{Auth: response}, err
+}
diff --git a/vendor/github.com/moby/moby/client/network_connect.go b/vendor/github.com/moby/moby/client/network_connect.go
new file mode 100644
index 000000000..40db955a9
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_connect.go
@@ -0,0 +1,40 @@
+package client
+
+import (
+	"context"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+// NetworkConnectOptions represents the data to be used to connect a container to the
+// network.
+type NetworkConnectOptions struct {
+	Container      string
+	EndpointConfig *network.EndpointSettings
+}
+
+// NetworkConnectResult represents the result of a NetworkConnect operation.
+type NetworkConnectResult struct {
+	// Currently empty; placeholder for future fields.
+}
+
+// NetworkConnect connects a container to an existent network in the docker host.
+func (cli *Client) NetworkConnect(ctx context.Context, networkID string, options NetworkConnectOptions) (NetworkConnectResult, error) {
+	networkID, err := trimID("network", networkID)
+	if err != nil {
+		return NetworkConnectResult{}, err
+	}
+
+	containerID, err := trimID("container", options.Container)
+	if err != nil {
+		return NetworkConnectResult{}, err
+	}
+
+	nc := network.ConnectRequest{
+		Container:      containerID,
+		EndpointConfig: options.EndpointConfig,
+	}
+	resp, err := cli.post(ctx, "/networks/"+networkID+"/connect", nil, nc, nil)
+	defer ensureReaderClosed(resp)
+	return NetworkConnectResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/network_create.go b/vendor/github.com/moby/moby/client/network_create.go
new file mode 100644
index 000000000..25ea32af4
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_create.go
@@ -0,0 +1,69 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+// NetworkCreateOptions holds options to create a network.
+type NetworkCreateOptions struct {
+	Driver     string            // Driver is the driver-name used to create the network (e.g. `bridge`, `overlay`)
+	Scope      string            // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level).
+	EnableIPv4 *bool             // EnableIPv4 represents whether to enable IPv4.
+	EnableIPv6 *bool             // EnableIPv6 represents whether to enable IPv6.
+	IPAM       *network.IPAM     // IPAM is the network's IP Address Management.
+	Internal   bool              // Internal represents if the network is used internal only.
+	Attachable bool              // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode.
+	Ingress    bool              // Ingress indicates the network is providing the routing-mesh for the swarm cluster.
+	ConfigOnly bool              // ConfigOnly creates a config-only network. Config-only networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services.
+	ConfigFrom string            // ConfigFrom specifies the source which will provide the configuration for this network. The specified network must be a config-only network; see [CreateOptions.ConfigOnly].
+	Options    map[string]string // Options specifies the network-specific options to use for when creating the network.
+	Labels     map[string]string // Labels holds metadata specific to the network being created.
+}
+
+// NetworkCreateResult represents the result of a network create operation.
+type NetworkCreateResult struct {
+	ID string
+
+	Warning []string
+}
+
+// NetworkCreate creates a new network in the docker host.
+func (cli *Client) NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (NetworkCreateResult, error) {
+	req := network.CreateRequest{
+		Name:       name,
+		Driver:     options.Driver,
+		Scope:      options.Scope,
+		EnableIPv4: options.EnableIPv4,
+		EnableIPv6: options.EnableIPv6,
+		IPAM:       options.IPAM,
+		Internal:   options.Internal,
+		Attachable: options.Attachable,
+		Ingress:    options.Ingress,
+		ConfigOnly: options.ConfigOnly,
+		Options:    options.Options,
+		Labels:     options.Labels,
+	}
+
+	if options.ConfigFrom != "" {
+		req.ConfigFrom = &network.ConfigReference{Network: options.ConfigFrom}
+	}
+
+	resp, err := cli.post(ctx, "/networks/create", nil, req, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return NetworkCreateResult{}, err
+	}
+
+	var response network.CreateResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+
+	var warnings []string
+	if response.Warning != "" {
+		warnings = []string{response.Warning}
+	}
+
+	return NetworkCreateResult{ID: response.ID, Warning: warnings}, err
+}
diff --git a/vendor/github.com/moby/moby/client/network_disconnect.go b/vendor/github.com/moby/moby/client/network_disconnect.go
new file mode 100644
index 000000000..64a1796b8
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_disconnect.go
@@ -0,0 +1,40 @@
+package client
+
+import (
+	"context"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+// NetworkDisconnectOptions represents the data to be used to disconnect a container
+// from the network.
+type NetworkDisconnectOptions struct {
+	Container string
+	Force     bool
+}
+
+// NetworkDisconnectResult represents the result of a NetworkDisconnect operation.
+type NetworkDisconnectResult struct {
+	// Currently empty; placeholder for future fields.
+}
+
+// NetworkDisconnect disconnects a container from an existent network in the docker host.
+func (cli *Client) NetworkDisconnect(ctx context.Context, networkID string, options NetworkDisconnectOptions) (NetworkDisconnectResult, error) {
+	networkID, err := trimID("network", networkID)
+	if err != nil {
+		return NetworkDisconnectResult{}, err
+	}
+
+	containerID, err := trimID("container", options.Container)
+	if err != nil {
+		return NetworkDisconnectResult{}, err
+	}
+
+	req := network.DisconnectRequest{
+		Container: containerID,
+		Force:     options.Force,
+	}
+	resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, req, nil)
+	defer ensureReaderClosed(resp)
+	return NetworkDisconnectResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/network_inspect.go b/vendor/github.com/moby/moby/client/network_inspect.go
new file mode 100644
index 000000000..775780527
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_inspect.go
@@ -0,0 +1,39 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+// NetworkInspectResult contains the result of a network inspection.
+type NetworkInspectResult struct {
+	Network network.Inspect
+	Raw     json.RawMessage
+}
+
+// NetworkInspect returns the information for a specific network configured in the docker host.
+func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options NetworkInspectOptions) (NetworkInspectResult, error) {
+	networkID, err := trimID("network", networkID)
+	if err != nil {
+		return NetworkInspectResult{}, err
+	}
+	query := url.Values{}
+	if options.Verbose {
+		query.Set("verbose", "true")
+	}
+	if options.Scope != "" {
+		query.Set("scope", options.Scope)
+	}
+
+	resp, err := cli.get(ctx, "/networks/"+networkID, query, nil)
+	if err != nil {
+		return NetworkInspectResult{}, err
+	}
+
+	var out NetworkInspectResult
+	out.Raw, err = decodeWithRaw(resp, &out.Network)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/network_inspect_opts.go b/vendor/github.com/moby/moby/client/network_inspect_opts.go
new file mode 100644
index 000000000..d83f113e1
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_inspect_opts.go
@@ -0,0 +1,7 @@
+package client
+
+// NetworkInspectOptions holds parameters to inspect network.
+type NetworkInspectOptions struct {
+	Scope   string
+	Verbose bool
+}
diff --git a/vendor/github.com/moby/moby/client/network_list.go b/vendor/github.com/moby/moby/client/network_list.go
new file mode 100644
index 000000000..d65f56097
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_list.go
@@ -0,0 +1,28 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+// NetworkListResult holds the result from the [Client.NetworkList] method.
+type NetworkListResult struct {
+	Items []network.Summary
+}
+
+// NetworkList returns the list of networks configured in the docker host.
+func (cli *Client) NetworkList(ctx context.Context, options NetworkListOptions) (NetworkListResult, error) {
+	query := url.Values{}
+	options.Filters.updateURLValues(query)
+	resp, err := cli.get(ctx, "/networks", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return NetworkListResult{}, err
+	}
+	var res NetworkListResult
+	err = json.NewDecoder(resp.Body).Decode(&res.Items)
+	return res, err
+}
diff --git a/vendor/github.com/moby/moby/client/network_list_opts.go b/vendor/github.com/moby/moby/client/network_list_opts.go
new file mode 100644
index 000000000..0d21ab313
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_list_opts.go
@@ -0,0 +1,6 @@
+package client
+
+// NetworkListOptions holds parameters to filter the list of networks with.
+type NetworkListOptions struct {
+	Filters Filters
+}
diff --git a/vendor/github.com/moby/moby/client/network_prune.go b/vendor/github.com/moby/moby/client/network_prune.go
new file mode 100644
index 000000000..55f7cac02
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_prune.go
@@ -0,0 +1,39 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+// NetworkPruneOptions holds parameters to prune networks.
+type NetworkPruneOptions struct {
+	Filters Filters
+}
+
+// NetworkPruneResult holds the result from the [Client.NetworkPrune] method.
+type NetworkPruneResult struct {
+	Report network.PruneReport
+}
+
+// NetworkPrune requests the daemon to delete unused networks
+func (cli *Client) NetworkPrune(ctx context.Context, opts NetworkPruneOptions) (NetworkPruneResult, error) {
+	query := url.Values{}
+	opts.Filters.updateURLValues(query)
+
+	resp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return NetworkPruneResult{}, err
+	}
+
+	var report network.PruneReport
+	if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
+		return NetworkPruneResult{}, fmt.Errorf("Error retrieving network prune report: %v", err)
+	}
+
+	return NetworkPruneResult{Report: report}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/network_remove.go b/vendor/github.com/moby/moby/client/network_remove.go
new file mode 100644
index 000000000..2bceb0d93
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/network_remove.go
@@ -0,0 +1,26 @@
+package client
+
+import (
+	"context"
+)
+
+// NetworkRemoveOptions specifies options for removing a network.
+type NetworkRemoveOptions struct {
+	// No options currently; placeholder for future use.
+}
+
+// NetworkRemoveResult represents the result of a network removal operation.
+type NetworkRemoveResult struct {
+	// No fields currently; placeholder for future use.
+}
+
+// NetworkRemove removes an existent network from the docker host.
+func (cli *Client) NetworkRemove(ctx context.Context, networkID string, options NetworkRemoveOptions) (NetworkRemoveResult, error) {
+	networkID, err := trimID("network", networkID)
+	if err != nil {
+		return NetworkRemoveResult{}, err
+	}
+	resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
+	defer ensureReaderClosed(resp)
+	return NetworkRemoveResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/node_inspect.go b/vendor/github.com/moby/moby/client/node_inspect.go
new file mode 100644
index 000000000..ed482152c
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/node_inspect.go
@@ -0,0 +1,42 @@
+package client
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"io"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// NodeInspectOptions holds parameters to inspect nodes with.
+type NodeInspectOptions struct{}
+
+// NodeInspectResult holds the result of [Client.NodeInspect].
+type NodeInspectResult struct {
+	Node swarm.Node
+	Raw  json.RawMessage
+}
+
+// NodeInspect returns the node information.
+func (cli *Client) NodeInspect(ctx context.Context, nodeID string, options NodeInspectOptions) (NodeInspectResult, error) {
+	nodeID, err := trimID("node", nodeID)
+	if err != nil {
+		return NodeInspectResult{}, err
+	}
+	resp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return NodeInspectResult{}, err
+	}
+
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return NodeInspectResult{}, err
+	}
+
+	var response swarm.Node
+	rdr := bytes.NewReader(body)
+	err = json.NewDecoder(rdr).Decode(&response)
+	return NodeInspectResult{Node: response, Raw: body}, err
+}
diff --git a/vendor/github.com/moby/moby/client/node_list.go b/vendor/github.com/moby/moby/client/node_list.go
new file mode 100644
index 000000000..aec3355e4
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/node_list.go
@@ -0,0 +1,34 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// NodeListOptions holds parameters to list nodes with.
+type NodeListOptions struct {
+	Filters Filters
+}
+
+// NodeListResult holds the result of [Client.NodeList].
+type NodeListResult struct {
+	Items []swarm.Node
+}
+
+// NodeList returns the list of nodes.
+func (cli *Client) NodeList(ctx context.Context, options NodeListOptions) (NodeListResult, error) {
+	query := url.Values{}
+	options.Filters.updateURLValues(query)
+	resp, err := cli.get(ctx, "/nodes", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return NodeListResult{}, err
+	}
+
+	var nodes []swarm.Node
+	err = json.NewDecoder(resp.Body).Decode(&nodes)
+	return NodeListResult{Items: nodes}, err
+}
diff --git a/vendor/github.com/moby/moby/client/node_remove.go b/vendor/github.com/moby/moby/client/node_remove.go
new file mode 100644
index 000000000..2a88cf80e
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/node_remove.go
@@ -0,0 +1,31 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// NodeRemoveOptions holds parameters to remove nodes with.
+type NodeRemoveOptions struct {
+	Force bool
+}
+
+// NodeRemoveResult holds the result of [Client.NodeRemove].
+type NodeRemoveResult struct{}
+
+// NodeRemove removes a Node.
+func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options NodeRemoveOptions) (NodeRemoveResult, error) {
+	nodeID, err := trimID("node", nodeID)
+	if err != nil {
+		return NodeRemoveResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Force {
+		query.Set("force", "1")
+	}
+
+	resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil)
+	defer ensureReaderClosed(resp)
+	return NodeRemoveResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/node_update.go b/vendor/github.com/moby/moby/client/node_update.go
new file mode 100644
index 000000000..24f87a4df
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/node_update.go
@@ -0,0 +1,31 @@
+package client
+
+import (
+	"context"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// NodeUpdateOptions holds parameters to update nodes with.
+type NodeUpdateOptions struct {
+	Version swarm.Version
+	Spec    swarm.NodeSpec
+}
+
+// NodeUpdateResult holds the result of [Client.NodeUpdate].
+type NodeUpdateResult struct{}
+
+// NodeUpdate updates a Node.
+func (cli *Client) NodeUpdate(ctx context.Context, nodeID string, options NodeUpdateOptions) (NodeUpdateResult, error) {
+	nodeID, err := trimID("node", nodeID)
+	if err != nil {
+		return NodeUpdateResult{}, err
+	}
+
+	query := url.Values{}
+	query.Set("version", options.Version.String())
+	resp, err := cli.post(ctx, "/nodes/"+nodeID+"/update", query, options.Spec, nil)
+	defer ensureReaderClosed(resp)
+	return NodeUpdateResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/ping.go b/vendor/github.com/moby/moby/client/ping.go
new file mode 100644
index 000000000..d315e4b98
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/ping.go
@@ -0,0 +1,166 @@
+package client
+
+import (
+	"context"
+	"net/http"
+	"path"
+	"strings"
+
+	"github.com/moby/moby/api/types/build"
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// PingOptions holds options for [client.Ping].
+type PingOptions struct {
+	// NegotiateAPIVersion queries the API and updates the version to match the API
+	// version. NegotiateAPIVersion downgrades the client's API version to match the
+	// APIVersion if the ping version is lower than the default version. If the API
+	// version reported by the server is higher than the maximum version supported
+	// by the client, it uses the client's maximum version.
+	//
+	// If a manual override is in place, either through the "DOCKER_API_VERSION"
+	// ([EnvOverrideAPIVersion]) environment variable, or if the client is initialized
+	// with a fixed version ([WithAPIVersion]), no negotiation is performed.
+	//
+	// If the API server's ping response does not contain an API version, or if the
+	// client did not get a successful ping response, it assumes it is connected with
+	// an old daemon that does not support API version negotiation, in which case it
+	// downgrades to the lowest supported API version.
+	NegotiateAPIVersion bool
+
+	// ForceNegotiate forces the client to re-negotiate the API version, even if
+	// API-version negotiation already happened or it the client is configured
+	// with a fixed version (using [WithAPIVersion] or [WithAPIVersionFromEnv]).
+	//
+	// This option has no effect if NegotiateAPIVersion is not set.
+	ForceNegotiate bool
+}
+
+// PingResult holds the result of a [Client.Ping] API call.
+type PingResult struct {
+	APIVersion     string
+	OSType         string
+	Experimental   bool
+	BuilderVersion build.BuilderVersion
+
+	// SwarmStatus provides information about the current swarm status of the
+	// engine, obtained from the "Swarm" header in the API response.
+	//
+	// It can be a nil struct if the API version does not provide this header
+	// in the ping response, or if an error occurred, in which case the client
+	// should use other ways to get the current swarm status, such as the /swarm
+	// endpoint.
+	SwarmStatus *SwarmStatus
+}
+
+// SwarmStatus provides information about the current swarm status and role,
+// obtained from the "Swarm" header in the API response.
+type SwarmStatus struct {
+	// NodeState represents the state of the node.
+	NodeState swarm.LocalNodeState
+
+	// ControlAvailable indicates if the node is a swarm manager.
+	ControlAvailable bool
+}
+
+// Ping pings the server and returns the value of the "Docker-Experimental",
+// "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use
+// a HEAD request on the endpoint, but falls back to GET if HEAD is not supported
+// by the daemon. It ignores internal server errors returned by the API, which
+// may be returned if the daemon is in an unhealthy state, but returns errors
+// for other non-success status codes, failing to connect to the API, or failing
+// to parse the API response.
+func (cli *Client) Ping(ctx context.Context, options PingOptions) (PingResult, error) {
+	if !options.NegotiateAPIVersion {
+		// No API version negotiation needed; just return ping response.
+		return cli.ping(ctx)
+	}
+	if cli.negotiated.Load() && !options.ForceNegotiate {
+		// API version was already negotiated or manually set.
+		return cli.ping(ctx)
+	}
+
+	// Ensure exclusive write access to version and negotiated fields
+	cli.negotiateLock.Lock()
+	defer cli.negotiateLock.Unlock()
+
+	ping, err := cli.ping(ctx)
+	if err != nil {
+		return ping, err
+	}
+
+	if cli.negotiated.Load() && !options.ForceNegotiate {
+		// API version was already negotiated or manually set.
+		//
+		// We check cli.negotiated again under lock, to account for race
+		// conditions with the check at the start of this function.
+		return ping, nil
+	}
+
+	if ping.APIVersion == "" {
+		cli.setAPIVersion(MaxAPIVersion)
+		return ping, nil
+	}
+
+	return ping, cli.negotiateAPIVersion(ping.APIVersion)
+}
+
+func (cli *Client) ping(ctx context.Context) (PingResult, error) {
+	// Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest()
+	// because ping requests are used during API version negotiation, so we want
+	// to hit the non-versioned /_ping endpoint, not /v1.xx/_ping
+	req, err := cli.buildRequest(ctx, http.MethodHead, path.Join(cli.basePath, "/_ping"), nil, nil)
+	if err != nil {
+		return PingResult{}, err
+	}
+	resp, err := cli.doRequest(req)
+	defer ensureReaderClosed(resp)
+	if err == nil && resp.StatusCode == http.StatusOK {
+		// Fast-path; successfully connected using a HEAD request and
+		// we got a "OK" (200) status. For non-200 status-codes, we fall
+		// back to doing a GET request, as a HEAD request won't have a
+		// response-body to get error details from.
+		return newPingResult(resp), nil
+	}
+	// close to allow reusing connection.
+	ensureReaderClosed(resp)
+
+	// HEAD failed or returned a non-OK status; fallback to GET.
+	req2, err := cli.buildRequest(ctx, http.MethodGet, path.Join(cli.basePath, "/_ping"), nil, nil)
+	if err != nil {
+		return PingResult{}, err
+	}
+	resp, err = cli.doRequest(req2)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		// Failed to connect.
+		return PingResult{}, err
+	}
+
+	// GET request succeeded but may have returned a non-200 status.
+	// Return a Ping response, together with any error returned by
+	// the API server.
+	return newPingResult(resp), checkResponseErr(resp)
+}
+
+func newPingResult(resp *http.Response) PingResult {
+	if resp == nil {
+		return PingResult{}
+	}
+	var swarmStatus *SwarmStatus
+	if si := resp.Header.Get("Swarm"); si != "" {
+		state, role, _ := strings.Cut(si, "/")
+		swarmStatus = &SwarmStatus{
+			NodeState:        swarm.LocalNodeState(state),
+			ControlAvailable: role == "manager",
+		}
+	}
+
+	return PingResult{
+		APIVersion:     resp.Header.Get("Api-Version"),
+		OSType:         resp.Header.Get("Ostype"),
+		Experimental:   resp.Header.Get("Docker-Experimental") == "true",
+		BuilderVersion: build.BuilderVersion(resp.Header.Get("Builder-Version")),
+		SwarmStatus:    swarmStatus,
+	}
+}
diff --git a/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go
new file mode 100644
index 000000000..e3ac43afd
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go
@@ -0,0 +1,294 @@
+package jsonmessage
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"iter"
+	"strings"
+	"time"
+
+	"github.com/docker/go-units"
+	"github.com/moby/moby/api/types/jsonstream"
+	"github.com/moby/term"
+)
+
+var timeNow = time.Now // For overriding in tests.
+
+// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to
+// ensure the formatted time is always the same number of characters.
+const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
+
+// DisplayOpt configures behavior for [DisplayStream] and [DisplayMessages].
+// Options are applied in order; if an option returns an error, processing
+// stops and the error is returned to the caller.
+type DisplayOpt func(*displayOpts) error
+
+type displayOpts struct {
+	auxCallback func(jsonstream.Message)
+}
+
+// WithAuxCallback registers a callback that is invoked for auxiliary
+// jsonstream messages as they are processed. The callback is optional;
+// if not provided, auxiliary messages are ignored.
+func WithAuxCallback(fn func(jsonstream.Message)) DisplayOpt {
+	return func(opts *displayOpts) error {
+		opts.auxCallback = fn
+		return nil
+	}
+}
+
+func RenderTUIProgress(p jsonstream.Progress, width uint16) string {
+	var (
+		pbBox      string
+		numbersBox string
+	)
+	if p.Current <= 0 && p.Total <= 0 {
+		return ""
+	}
+	if p.Total <= 0 {
+		switch p.Units {
+		case "":
+			return fmt.Sprintf("%8v", units.HumanSize(float64(p.Current)))
+		default:
+			return fmt.Sprintf("%d %s", p.Current, p.Units)
+		}
+	}
+
+	percentage := min(int(float64(p.Current)/float64(p.Total)*100)/2, 50)
+	if width > 110 {
+		// this number can't be negative gh#7136
+		numSpaces := max(50-percentage, 0)
+		pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces))
+	}
+
+	switch {
+	case p.HideCounts:
+	case p.Units == "": // no units, use bytes
+		current := units.HumanSize(float64(p.Current))
+		total := units.HumanSize(float64(p.Total))
+
+		numbersBox = fmt.Sprintf("%8v/%v", current, total)
+
+		if p.Current > p.Total {
+			// remove total display if the reported current is wonky.
+			numbersBox = fmt.Sprintf("%8v", current)
+		}
+	default:
+		numbersBox = fmt.Sprintf("%d/%d %s", p.Current, p.Total, p.Units)
+
+		if p.Current > p.Total {
+			// remove total display if the reported current is wonky.
+			numbersBox = fmt.Sprintf("%d %s", p.Current, p.Units)
+		}
+	}
+
+	// Show approximation of remaining time if there's enough width.
+	var timeLeftBox string
+	if width > 50 {
+		if p.Current > 0 && p.Start > 0 && percentage < 50 {
+			fromStart := timeNow().UTC().Sub(time.Unix(p.Start, 0))
+			perEntry := fromStart / time.Duration(p.Current)
+			left := time.Duration(p.Total-p.Current) * perEntry
+			timeLeftBox = " " + left.Round(time.Second).String()
+		}
+	}
+	return pbBox + numbersBox + timeLeftBox
+}
+
+// We can probably use [aec.EmptyBuilder] for managing the output, but
+// currently we're doing it all manually, so defining some consts for
+// the basics we use.
+//
+// [aec.EmptyBuilder]: https://pkg.go.dev/github.com/morikuni/aec#EmptyBuilder
+const (
+	ansiEraseLine     = "\x1b[2K"  // Erase entire line
+	ansiCursorUpFmt   = "\x1b[%dA" // Move cursor up N lines
+	ansiCursorDownFmt = "\x1b[%dB" // Move cursor down N lines
+)
+
+func clearLine(out io.Writer) {
+	_, _ = out.Write([]byte(ansiEraseLine))
+}
+
+func cursorUp(out io.Writer, l uint) {
+	if l == 0 {
+		return
+	}
+	_, _ = fmt.Fprintf(out, ansiCursorUpFmt, l)
+}
+
+func cursorDown(out io.Writer, l uint) {
+	if l == 0 {
+		return
+	}
+	_, _ = fmt.Fprintf(out, ansiCursorDownFmt, l)
+}
+
+// Display prints the JSONMessage to out. If isTerminal is true, it erases
+// the entire current line when displaying the progressbar. It returns an
+// error if the [JSONMessage.Error] field is non-nil.
+func Display(jm jsonstream.Message, out io.Writer, isTerminal bool, width uint16) error {
+	if jm.Error != nil {
+		return jm.Error
+	}
+	var endl string
+	if isTerminal && jm.Stream == "" && jm.Progress != nil {
+		clearLine(out)
+		endl = "\r"
+		_, _ = fmt.Fprint(out, endl)
+	} else if jm.Progress != nil && (jm.Progress.Current > 0 || jm.Progress.Total > 0) { // disable progressbar in non-terminal
+		return nil
+	}
+	if jm.ID != "" {
+		_, _ = fmt.Fprintf(out, "%s: ", jm.ID)
+	}
+	if jm.Progress != nil && isTerminal {
+		if width == 0 {
+			width = 200
+		}
+		_, _ = fmt.Fprintf(out, "%s %s%s", jm.Status, RenderTUIProgress(*jm.Progress, width), endl)
+	} else if jm.Stream != "" {
+		_, _ = fmt.Fprintf(out, "%s%s", jm.Stream, endl)
+	} else {
+		_, _ = fmt.Fprintf(out, "%s%s\n", jm.Status, endl)
+	}
+	return nil
+}
+
+type JSONMessagesStream = iter.Seq2[jsonstream.Message, error]
+
+// DisplayJSONMessagesStream is like [DisplayStream], but allows the caller to
+// explicitly provide the terminal file descriptor and whether out is a terminal.
+func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error {
+	var opts []DisplayOpt
+	if auxCallback != nil {
+		opts = append(opts, WithAuxCallback(auxCallback))
+	}
+	return displayJSONMessagesStream(in, out, terminalFd, isTerminal, opts...)
+}
+
+// DisplayStream reads a JSON message stream from in, and writes each
+// [jsonstream.Message] to out. See [DisplayMessages] for details.
+func DisplayStream(in io.Reader, out io.Writer, opts ...DisplayOpt) error {
+	terminalFd, isTerminal := term.GetFdInfo(out)
+	return displayJSONMessagesStream(in, out, terminalFd, isTerminal, opts...)
+}
+
+func displayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, opts ...DisplayOpt) error {
+	dec := json.NewDecoder(in)
+	f := func(yield func(jsonstream.Message, error) bool) {
+		for {
+			var jm jsonstream.Message
+			err := dec.Decode(&jm)
+			if errors.Is(err, io.EOF) {
+				break
+			}
+			if !yield(jm, err) {
+				return
+			}
+		}
+	}
+
+	return displayJSONMessages(f, out, terminalFd, isTerminal, opts...)
+}
+
+// DisplayJSONMessages is like [DisplayMessages], but allows the caller to
+// explicitly provide the terminal file descriptor and whether out is a terminal.
+func DisplayJSONMessages(messages iter.Seq2[jsonstream.Message, error], out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error {
+	var opts []DisplayOpt
+	if auxCallback != nil {
+		opts = append(opts, WithAuxCallback(auxCallback))
+	}
+	return displayJSONMessages(messages, out, terminalFd, isTerminal, opts...)
+}
+
+// DisplayMessages writes each [jsonstream.Message] from stream to out.
+// It returns an error if an invalid [jsonstream.Message] is received, or if
+// a message contains a non-zero [jsonstream.Message.Error].
+//
+// Presentation of the message depends on whether out is a terminal, and on the
+// terminal width. Progress bars ([jsonstream.Progress]) are suppressed on
+// narrower terminals (< 110 characters). If out is a terminal, it prints a
+// newline ("\n") at the end of each line and moves the cursor while displaying.
+//
+// auxCallback allows handling the [jsonstream.Message.Aux] field. It is called
+// if a message contains an Aux field, in which case DisplayMessages does not
+// present the message.
+func DisplayMessages(messages iter.Seq2[jsonstream.Message, error], out io.Writer, opts ...DisplayOpt) error {
+	terminalFd, isTerminal := term.GetFdInfo(out)
+	return displayJSONMessages(messages, out, terminalFd, isTerminal, opts...)
+}
+
+func displayJSONMessages(messages iter.Seq2[jsonstream.Message, error], out io.Writer, terminalFd uintptr, isTerminal bool, opts ...DisplayOpt) error {
+	var cfg displayOpts
+	for _, opt := range opts {
+		if opt == nil {
+			continue
+		}
+		if err := opt(&cfg); err != nil {
+			return err
+		}
+	}
+	auxCallback := cfg.auxCallback
+
+	ids := make(map[string]uint)
+	var width uint16 = 200
+	if isTerminal {
+		ws, err := term.GetWinsize(terminalFd)
+		if err == nil {
+			width = ws.Width
+		}
+	}
+
+	for jm, err := range messages {
+		var diff uint
+		if err != nil {
+			return err
+		}
+
+		if jm.Aux != nil {
+			if auxCallback != nil {
+				auxCallback(jm)
+			}
+			continue
+		}
+
+		if jm.ID != "" && jm.Progress != nil {
+			line, ok := ids[jm.ID]
+			if !ok {
+				// NOTE: This approach of using len(id) to
+				// figure out the number of lines of history
+				// only works as long as we clear the history
+				// when we output something that's not
+				// accounted for in the map, such as a line
+				// with no ID.
+				line = uint(len(ids))
+				ids[jm.ID] = line
+				if isTerminal {
+					_, _ = fmt.Fprintf(out, "\n")
+				}
+			}
+			diff = uint(len(ids)) - line
+			if isTerminal {
+				cursorUp(out, diff)
+			}
+		} else {
+			// When outputting something that isn't progress
+			// output, clear the history of previous lines. We
+			// don't want progress entries from some previous
+			// operation to be updated (for example, pull -a
+			// with multiple tags).
+			ids = make(map[string]uint)
+		}
+		err := Display(jm, out, isTerminal, width)
+		if jm.ID != "" && isTerminal {
+			cursorDown(out, diff)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/moby/moby/client/pkg/versions/compare.go b/vendor/github.com/moby/moby/client/pkg/versions/compare.go
new file mode 100644
index 000000000..fa0ad9b5a
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/pkg/versions/compare.go
@@ -0,0 +1,62 @@
+package versions
+
+import (
+	"strconv"
+	"strings"
+)
+
+// compare compares two version strings
+// returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise.
+func compare(v1, v2 string) int {
+	if v1 == v2 {
+		return 0
+	}
+	var (
+		currTab  = strings.Split(v1, ".")
+		otherTab = strings.Split(v2, ".")
+	)
+
+	maxVer := max(len(otherTab), len(currTab))
+	for i := range maxVer {
+		var currInt, otherInt int
+
+		if len(currTab) > i {
+			currInt, _ = strconv.Atoi(currTab[i])
+		}
+		if len(otherTab) > i {
+			otherInt, _ = strconv.Atoi(otherTab[i])
+		}
+		if currInt > otherInt {
+			return 1
+		}
+		if otherInt > currInt {
+			return -1
+		}
+	}
+	return 0
+}
+
+// LessThan checks if a version is less than another
+func LessThan(v, other string) bool {
+	return compare(v, other) == -1
+}
+
+// LessThanOrEqualTo checks if a version is less than or equal to another
+func LessThanOrEqualTo(v, other string) bool {
+	return compare(v, other) <= 0
+}
+
+// GreaterThan checks if a version is greater than another
+func GreaterThan(v, other string) bool {
+	return compare(v, other) == 1
+}
+
+// GreaterThanOrEqualTo checks if a version is greater than or equal to another
+func GreaterThanOrEqualTo(v, other string) bool {
+	return compare(v, other) >= 0
+}
+
+// Equal checks if a version is equal to another
+func Equal(v, other string) bool {
+	return compare(v, other) == 0
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_create.go b/vendor/github.com/moby/moby/client/plugin_create.go
new file mode 100644
index 000000000..c1a2dd5a6
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_create.go
@@ -0,0 +1,31 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net/http"
+	"net/url"
+)
+
+// PluginCreateOptions hold all options to plugin create.
+type PluginCreateOptions struct {
+	RepoName string
+}
+
+// PluginCreateResult represents the result of a plugin create operation.
+type PluginCreateResult struct {
+	// Currently empty; can be extended in the future if needed.
+}
+
+// PluginCreate creates a plugin
+func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions PluginCreateOptions) (PluginCreateResult, error) {
+	headers := http.Header(make(map[string][]string))
+	headers.Set("Content-Type", "application/x-tar")
+
+	query := url.Values{}
+	query.Set("name", createOptions.RepoName)
+
+	resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers)
+	defer ensureReaderClosed(resp)
+	return PluginCreateResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_disable.go b/vendor/github.com/moby/moby/client/plugin_disable.go
new file mode 100644
index 000000000..65ab0aa00
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_disable.go
@@ -0,0 +1,31 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// PluginDisableOptions holds parameters to disable plugins.
+type PluginDisableOptions struct {
+	Force bool
+}
+
+// PluginDisableResult represents the result of a plugin disable operation.
+type PluginDisableResult struct {
+	// Currently empty; can be extended in the future if needed.
+}
+
+// PluginDisable disables a plugin
+func (cli *Client) PluginDisable(ctx context.Context, name string, options PluginDisableOptions) (PluginDisableResult, error) {
+	name, err := trimID("plugin", name)
+	if err != nil {
+		return PluginDisableResult{}, err
+	}
+	query := url.Values{}
+	if options.Force {
+		query.Set("force", "1")
+	}
+	resp, err := cli.post(ctx, "/plugins/"+name+"/disable", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	return PluginDisableResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_enable.go b/vendor/github.com/moby/moby/client/plugin_enable.go
new file mode 100644
index 000000000..7c3e26b67
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_enable.go
@@ -0,0 +1,31 @@
+package client
+
+import (
+	"context"
+	"net/url"
+	"strconv"
+)
+
+// PluginEnableOptions holds parameters to enable plugins.
+type PluginEnableOptions struct {
+	Timeout int
+}
+
+// PluginEnableResult represents the result of a plugin enable operation.
+type PluginEnableResult struct {
+	// Currently empty; can be extended in the future if needed.
+}
+
+// PluginEnable enables a plugin
+func (cli *Client) PluginEnable(ctx context.Context, name string, options PluginEnableOptions) (PluginEnableResult, error) {
+	name, err := trimID("plugin", name)
+	if err != nil {
+		return PluginEnableResult{}, err
+	}
+	query := url.Values{}
+	query.Set("timeout", strconv.Itoa(options.Timeout))
+
+	resp, err := cli.post(ctx, "/plugins/"+name+"/enable", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	return PluginEnableResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_inspect.go b/vendor/github.com/moby/moby/client/plugin_inspect.go
new file mode 100644
index 000000000..8caf06a8e
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_inspect.go
@@ -0,0 +1,35 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/plugin"
+)
+
+// PluginInspectOptions holds parameters to inspect a plugin.
+type PluginInspectOptions struct {
+	// Add future optional parameters here
+}
+
+// PluginInspectResult holds the result from the [Client.PluginInspect] method.
+type PluginInspectResult struct {
+	Plugin plugin.Plugin
+	Raw    json.RawMessage
+}
+
+// PluginInspect inspects an existing plugin
+func (cli *Client) PluginInspect(ctx context.Context, name string, options PluginInspectOptions) (PluginInspectResult, error) {
+	name, err := trimID("plugin", name)
+	if err != nil {
+		return PluginInspectResult{}, err
+	}
+	resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil)
+	if err != nil {
+		return PluginInspectResult{}, err
+	}
+
+	var out PluginInspectResult
+	out.Raw, err = decodeWithRaw(resp, &out.Plugin)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_install.go b/vendor/github.com/moby/moby/client/plugin_install.go
new file mode 100644
index 000000000..a589b2e1f
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_install.go
@@ -0,0 +1,175 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/distribution/reference"
+	"github.com/moby/moby/api/types/plugin"
+	"github.com/moby/moby/api/types/registry"
+)
+
+// PluginInstallOptions holds parameters to install a plugin.
+type PluginInstallOptions struct {
+	Disabled             bool
+	AcceptAllPermissions bool
+	RegistryAuth         string // RegistryAuth is the base64 encoded credentials for the registry
+	RemoteRef            string // RemoteRef is the plugin name on the registry
+
+	// PrivilegeFunc is a function that clients can supply to retry operations
+	// after getting an authorization error. This function returns the registry
+	// authentication header value in base64 encoded format, or an error if the
+	// privilege request fails.
+	//
+	// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
+	PrivilegeFunc         func(context.Context) (string, error)
+	AcceptPermissionsFunc func(context.Context, plugin.Privileges) (bool, error)
+	Args                  []string
+}
+
+// PluginInstallResult holds the result of a plugin install operation.
+// It is an io.ReadCloser from which the caller can read installation progress or result.
+type PluginInstallResult struct {
+	io.ReadCloser
+}
+
+// PluginInstall installs a plugin
+func (cli *Client) PluginInstall(ctx context.Context, name string, options PluginInstallOptions) (_ PluginInstallResult, retErr error) {
+	query := url.Values{}
+	if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
+		return PluginInstallResult{}, fmt.Errorf("invalid remote reference: %w", err)
+	}
+	query.Set("remote", options.RemoteRef)
+
+	privileges, err := cli.checkPluginPermissions(ctx, query, &options)
+	if err != nil {
+		return PluginInstallResult{}, err
+	}
+
+	// set name for plugin pull, if empty should default to remote reference
+	query.Set("name", name)
+
+	resp, err := cli.tryPluginPull(ctx, query, privileges, options.RegistryAuth)
+	if err != nil {
+		return PluginInstallResult{}, err
+	}
+
+	name = resp.Header.Get("Docker-Plugin-Name")
+
+	pr, pw := io.Pipe()
+	go func() { // todo: the client should probably be designed more around the actual api
+		_, err := io.Copy(pw, resp.Body)
+		if err != nil {
+			_ = pw.CloseWithError(err)
+			return
+		}
+		defer func() {
+			if retErr != nil {
+				delResp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
+				ensureReaderClosed(delResp)
+			}
+		}()
+		if len(options.Args) > 0 {
+			if _, err := cli.PluginSet(ctx, name, PluginSetOptions{Args: options.Args}); err != nil {
+				_ = pw.CloseWithError(err)
+				return
+			}
+		}
+
+		if options.Disabled {
+			_ = pw.Close()
+			return
+		}
+
+		_, enableErr := cli.PluginEnable(ctx, name, PluginEnableOptions{Timeout: 0})
+		_ = pw.CloseWithError(enableErr)
+	}()
+	return PluginInstallResult{pr}, nil
+}
+
+func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
+	return cli.get(ctx, "/plugins/privileges", query, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
+}
+
+func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges plugin.Privileges, registryAuth string) (*http.Response, error) {
+	return cli.post(ctx, "/plugins/pull", query, privileges, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
+}
+
+func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options pluginOptions) (plugin.Privileges, error) {
+	resp, err := cli.tryPluginPrivileges(ctx, query, options.getRegistryAuth())
+	if cerrdefs.IsUnauthorized(err) && options.getPrivilegeFunc() != nil {
+		// TODO: do inspect before to check existing name before checking privileges
+		newAuthHeader, privilegeErr := options.getPrivilegeFunc()(ctx)
+		if privilegeErr != nil {
+			ensureReaderClosed(resp)
+			return nil, privilegeErr
+		}
+		options.setRegistryAuth(newAuthHeader)
+		resp, err = cli.tryPluginPrivileges(ctx, query, options.getRegistryAuth())
+	}
+	if err != nil {
+		ensureReaderClosed(resp)
+		return nil, err
+	}
+
+	var privileges plugin.Privileges
+	if err := json.NewDecoder(resp.Body).Decode(&privileges); err != nil {
+		ensureReaderClosed(resp)
+		return nil, err
+	}
+	ensureReaderClosed(resp)
+
+	if !options.getAcceptAllPermissions() && options.getAcceptPermissionsFunc() != nil && len(privileges) > 0 {
+		accept, err := options.getAcceptPermissionsFunc()(ctx, privileges)
+		if err != nil {
+			return nil, err
+		}
+		if !accept {
+			return nil, errors.New("permission denied while installing plugin " + options.getRemoteRef())
+		}
+	}
+	return privileges, nil
+}
+
+type pluginOptions interface {
+	getRegistryAuth() string
+	setRegistryAuth(string)
+	getPrivilegeFunc() func(context.Context) (string, error)
+	getAcceptAllPermissions() bool
+	getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error)
+	getRemoteRef() string
+}
+
+func (o *PluginInstallOptions) getRegistryAuth() string {
+	return o.RegistryAuth
+}
+
+func (o *PluginInstallOptions) setRegistryAuth(auth string) {
+	o.RegistryAuth = auth
+}
+
+func (o *PluginInstallOptions) getPrivilegeFunc() func(context.Context) (string, error) {
+	return o.PrivilegeFunc
+}
+
+func (o *PluginInstallOptions) getAcceptAllPermissions() bool {
+	return o.AcceptAllPermissions
+}
+
+func (o *PluginInstallOptions) getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error) {
+	return o.AcceptPermissionsFunc
+}
+
+func (o *PluginInstallOptions) getRemoteRef() string {
+	return o.RemoteRef
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_list.go b/vendor/github.com/moby/moby/client/plugin_list.go
new file mode 100644
index 000000000..cbd90b407
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_list.go
@@ -0,0 +1,35 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/plugin"
+)
+
+// PluginListOptions holds parameters to list plugins.
+type PluginListOptions struct {
+	Filters Filters
+}
+
+// PluginListResult represents the result of a plugin list operation.
+type PluginListResult struct {
+	Items []plugin.Plugin
+}
+
+// PluginList returns the installed plugins
+func (cli *Client) PluginList(ctx context.Context, options PluginListOptions) (PluginListResult, error) {
+	query := url.Values{}
+
+	options.Filters.updateURLValues(query)
+	resp, err := cli.get(ctx, "/plugins", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return PluginListResult{}, err
+	}
+
+	var plugins plugin.ListResponse
+	err = json.NewDecoder(resp.Body).Decode(&plugins)
+	return PluginListResult{Items: plugins}, err
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_push.go b/vendor/github.com/moby/moby/client/plugin_push.go
new file mode 100644
index 000000000..4ba25d133
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_push.go
@@ -0,0 +1,34 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net/http"
+
+	"github.com/moby/moby/api/types/registry"
+)
+
+// PluginPushOptions holds parameters to push a plugin.
+type PluginPushOptions struct {
+	RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
+}
+
+// PluginPushResult is the result of a plugin push operation
+type PluginPushResult struct {
+	io.ReadCloser
+}
+
+// PluginPush pushes a plugin to a registry
+func (cli *Client) PluginPush(ctx context.Context, name string, options PluginPushOptions) (PluginPushResult, error) {
+	name, err := trimID("plugin", name)
+	if err != nil {
+		return PluginPushResult{}, err
+	}
+	resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, http.Header{
+		registry.AuthHeader: {options.RegistryAuth},
+	})
+	if err != nil {
+		return PluginPushResult{}, err
+	}
+	return PluginPushResult{resp.Body}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_remove.go b/vendor/github.com/moby/moby/client/plugin_remove.go
new file mode 100644
index 000000000..229f40858
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_remove.go
@@ -0,0 +1,33 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// PluginRemoveOptions holds parameters to remove plugins.
+type PluginRemoveOptions struct {
+	Force bool
+}
+
+// PluginRemoveResult represents the result of a plugin removal.
+type PluginRemoveResult struct {
+	// Currently empty; can be extended in the future if needed.
+}
+
+// PluginRemove removes a plugin
+func (cli *Client) PluginRemove(ctx context.Context, name string, options PluginRemoveOptions) (PluginRemoveResult, error) {
+	name, err := trimID("plugin", name)
+	if err != nil {
+		return PluginRemoveResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Force {
+		query.Set("force", "1")
+	}
+
+	resp, err := cli.delete(ctx, "/plugins/"+name, query, nil)
+	defer ensureReaderClosed(resp)
+	return PluginRemoveResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_set.go b/vendor/github.com/moby/moby/client/plugin_set.go
new file mode 100644
index 000000000..c1f6bb5fa
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_set.go
@@ -0,0 +1,27 @@
+package client
+
+import (
+	"context"
+)
+
+// PluginSetOptions defines options for modifying a plugin's settings.
+type PluginSetOptions struct {
+	Args []string
+}
+
+// PluginSetResult represents the result of a plugin set operation.
+type PluginSetResult struct {
+	// Currently empty; can be extended in the future if needed.
+}
+
+// PluginSet modifies settings for an existing plugin
+func (cli *Client) PluginSet(ctx context.Context, name string, options PluginSetOptions) (PluginSetResult, error) {
+	name, err := trimID("plugin", name)
+	if err != nil {
+		return PluginSetResult{}, err
+	}
+
+	resp, err := cli.post(ctx, "/plugins/"+name+"/set", nil, options.Args, nil)
+	defer ensureReaderClosed(resp)
+	return PluginSetResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/plugin_upgrade.go b/vendor/github.com/moby/moby/client/plugin_upgrade.go
new file mode 100644
index 000000000..f9df6e584
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/plugin_upgrade.go
@@ -0,0 +1,89 @@
+package client
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+
+	"github.com/distribution/reference"
+	"github.com/moby/moby/api/types/plugin"
+	"github.com/moby/moby/api/types/registry"
+)
+
+// PluginUpgradeOptions holds parameters to upgrade a plugin.
+type PluginUpgradeOptions struct {
+	Disabled             bool
+	AcceptAllPermissions bool
+	RegistryAuth         string // RegistryAuth is the base64 encoded credentials for the registry
+	RemoteRef            string // RemoteRef is the plugin name on the registry
+
+	// PrivilegeFunc is a function that clients can supply to retry operations
+	// after getting an authorization error. This function returns the registry
+	// authentication header value in base64 encoded format, or an error if the
+	// privilege request fails.
+	//
+	// For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig].
+	PrivilegeFunc         func(context.Context) (string, error)
+	AcceptPermissionsFunc func(context.Context, plugin.Privileges) (bool, error)
+	Args                  []string
+}
+
+// PluginUpgradeResult holds the result of a plugin upgrade operation.
+type PluginUpgradeResult io.ReadCloser
+
+// PluginUpgrade upgrades a plugin
+func (cli *Client) PluginUpgrade(ctx context.Context, name string, options PluginUpgradeOptions) (PluginUpgradeResult, error) {
+	name, err := trimID("plugin", name)
+	if err != nil {
+		return nil, err
+	}
+
+	query := url.Values{}
+	if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
+		return nil, fmt.Errorf("invalid remote reference: %w", err)
+	}
+	query.Set("remote", options.RemoteRef)
+
+	privileges, err := cli.checkPluginPermissions(ctx, query, &options)
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := cli.tryPluginUpgrade(ctx, query, privileges, name, options.RegistryAuth)
+	if err != nil {
+		return nil, err
+	}
+	return resp.Body, nil
+}
+
+func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges plugin.Privileges, name, registryAuth string) (*http.Response, error) {
+	return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, http.Header{
+		registry.AuthHeader: {registryAuth},
+	})
+}
+
+func (o *PluginUpgradeOptions) getRegistryAuth() string {
+	return o.RegistryAuth
+}
+
+func (o *PluginUpgradeOptions) setRegistryAuth(auth string) {
+	o.RegistryAuth = auth
+}
+
+func (o *PluginUpgradeOptions) getPrivilegeFunc() func(context.Context) (string, error) {
+	return o.PrivilegeFunc
+}
+
+func (o *PluginUpgradeOptions) getAcceptAllPermissions() bool {
+	return o.AcceptAllPermissions
+}
+
+func (o *PluginUpgradeOptions) getAcceptPermissionsFunc() func(context.Context, plugin.Privileges) (bool, error) {
+	return o.AcceptPermissionsFunc
+}
+
+func (o *PluginUpgradeOptions) getRemoteRef() string {
+	return o.RemoteRef
+}
diff --git a/vendor/github.com/moby/moby/client/request.go b/vendor/github.com/moby/moby/client/request.go
new file mode 100644
index 000000000..10ed36dc6
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/request.go
@@ -0,0 +1,381 @@
+package client
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"net/http"
+	"net/url"
+	"os"
+	"reflect"
+	"strings"
+
+	"github.com/moby/moby/api/types/common"
+)
+
+// head sends an http request to the docker API using the method HEAD.
+func (cli *Client) head(ctx context.Context, path string, query url.Values, headers http.Header) (*http.Response, error) {
+	return cli.sendRequest(ctx, http.MethodHead, path, query, nil, headers)
+}
+
+// get sends an http request to the docker API using the method GET with a specific Go context.
+func (cli *Client) get(ctx context.Context, path string, query url.Values, headers http.Header) (*http.Response, error) {
+	return cli.sendRequest(ctx, http.MethodGet, path, query, nil, headers)
+}
+
+// post sends an http POST request to the API.
+func (cli *Client) post(ctx context.Context, path string, query url.Values, body any, headers http.Header) (*http.Response, error) {
+	jsonBody, headers, err := prepareJSONRequest(body, headers)
+	if err != nil {
+		return nil, err
+	}
+	return cli.sendRequest(ctx, http.MethodPost, path, query, jsonBody, headers)
+}
+
+func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers http.Header) (*http.Response, error) {
+	return cli.sendRequest(ctx, http.MethodPost, path, query, body, headers)
+}
+
+func (cli *Client) put(ctx context.Context, path string, query url.Values, body any, headers http.Header) (*http.Response, error) {
+	jsonBody, headers, err := prepareJSONRequest(body, headers)
+	if err != nil {
+		return nil, err
+	}
+	return cli.putRaw(ctx, path, query, jsonBody, headers)
+}
+
+// putRaw sends an http request to the docker API using the method PUT.
+func (cli *Client) putRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers http.Header) (*http.Response, error) {
+	// PUT requests are expected to always have a body (apparently)
+	// so explicitly pass an empty body to sendRequest to signal that
+	// it should set the Content-Type header if not already present.
+	if body == nil {
+		body = http.NoBody
+	}
+	return cli.sendRequest(ctx, http.MethodPut, path, query, body, headers)
+}
+
+// delete sends an http request to the docker API using the method DELETE.
+func (cli *Client) delete(ctx context.Context, path string, query url.Values, headers http.Header) (*http.Response, error) {
+	return cli.sendRequest(ctx, http.MethodDelete, path, query, nil, headers)
+}
+
+// prepareJSONRequest encodes the given body to JSON and returns it as an [io.Reader], and sets the Content-Type
+// header. If body is nil, or a nil-interface, a "nil" body is returned without
+// error.
+func prepareJSONRequest(body any, headers http.Header) (io.Reader, http.Header, error) {
+	jsonBody, err := jsonEncode(body)
+	if err != nil {
+		return nil, headers, err
+	}
+	if jsonBody == nil || jsonBody == http.NoBody {
+		// no content-type is set on empty requests.
+		return jsonBody, headers, nil
+	}
+
+	hdr := http.Header{}
+	if headers != nil {
+		hdr = headers.Clone()
+	}
+
+	// TODO(thaJeztah): should this return an error if a different Content-Type is already set?
+	hdr.Set("Content-Type", "application/json")
+	return jsonBody, hdr, nil
+}
+
+func (cli *Client) buildRequest(ctx context.Context, method, path string, body io.Reader, headers http.Header) (*http.Request, error) {
+	req, err := http.NewRequestWithContext(ctx, method, path, body)
+	if err != nil {
+		return nil, err
+	}
+	req = cli.addHeaders(req, headers)
+	req.URL.Scheme = cli.scheme
+	req.URL.Host = cli.addr
+
+	if cli.proto == "unix" || cli.proto == "npipe" {
+		// Override host header for non-tcp connections.
+		req.Host = DummyHost
+	}
+
+	return req, nil
+}
+
+func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers http.Header) (*http.Response, error) {
+	req, err := cli.buildRequest(ctx, method, cli.getAPIPath(ctx, path, query), body, headers)
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := cli.doRequest(req)
+	if err != nil {
+		// Failed to connect or context error.
+		return resp, err
+	}
+
+	// Successfully made a request; return the response and handle any
+	// API HTTP response errors.
+	return resp, checkResponseErr(resp)
+}
+
+// doRequest sends an HTTP request and returns an HTTP response. It is a
+// wrapper around [http.Client.Do] with extra handling to decorate errors.
+//
+// Otherwise, it behaves identical to [http.Client.Do]; an error is returned
+// when failing to make a connection, On error, any Response can be ignored.
+// A non-2xx status code doesn't cause an error.
+func (cli *Client) doRequest(req *http.Request) (*http.Response, error) {
+	resp, err := cli.client.Do(req) // #nosec G704 -- ignore "SSRF via taint analysis"; API client intentionally sends caller-provided requests/URLs.
+	if err == nil {
+		return resp, nil
+	}
+
+	if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") {
+		return nil, errConnectionFailed{fmt.Errorf("%w.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)}
+	}
+
+	const (
+		// Go 1.25 /  TLS 1.3 may produce a generic "handshake failure"
+		// whereas TLS 1.2 may produce a "bad certificate" TLS alert.
+		// See https://github.com/golang/go/issues/56371
+		//
+		// > https://tip.golang.org/doc/go1.12#tls_1_3
+		// >
+		// > In TLS 1.3 the client is the last one to speak in the handshake, so if
+		// > it causes an error to occur on the server, it will be returned on the
+		// > client by the first Read, not by Handshake. For example, that will be
+		// > the case if the server rejects the client certificate.
+		//
+		// https://github.com/golang/go/blob/go1.25.1/src/crypto/tls/alert.go#L71-L72
+		alertBadCertificate   = "bad certificate"   // go1.24 / TLS 1.2
+		alertHandshakeFailure = "handshake failure" // go1.25 / TLS 1.3
+	)
+
+	// TODO(thaJeztah): see if we can use errors.As for a [crypto/tls.AlertError] instead of bare string matching.
+	if cli.scheme == "https" && (strings.Contains(err.Error(), alertHandshakeFailure) || strings.Contains(err.Error(), alertBadCertificate)) {
+		return nil, errConnectionFailed{fmt.Errorf("the server probably has client authentication (--tlsverify) enabled; check your TLS client certification settings: %w", err)}
+	}
+
+	// Don't decorate context sentinel errors; users may be comparing to
+	// them directly.
+	if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
+		return nil, err
+	}
+
+	if errors.Is(err, os.ErrPermission) {
+		// Don't include request errors (Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.51/version"),
+		// which are irrelevant if we weren't able to connect.
+		return nil, errConnectionFailed{fmt.Errorf("permission denied while trying to connect to the docker API at %v", cli.host)}
+	}
+	if errors.Is(err, os.ErrNotExist) {
+		// Unwrap the error to remove request errors (Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.51/version"),
+		// which are irrelevant if we weren't able to connect.
+		err = errors.Unwrap(err)
+		return nil, errConnectionFailed{fmt.Errorf("failed to connect to the docker API at %v; check if the path is correct and if the daemon is running: %w", cli.host, err)}
+	}
+	var dnsErr *net.DNSError
+	if errors.As(err, &dnsErr) {
+		return nil, errConnectionFailed{fmt.Errorf("failed to connect to the docker API at %v: %w", cli.host, dnsErr)}
+	}
+
+	var nErr net.Error
+	if errors.As(err, &nErr) {
+		// FIXME(thaJeztah): any net.Error should be considered a connection error (but we should include the original error)?
+		if nErr.Timeout() {
+			return nil, connectionFailed(cli.host)
+		}
+		if strings.Contains(nErr.Error(), "connection refused") || strings.Contains(nErr.Error(), "dial unix") {
+			return nil, connectionFailed(cli.host)
+		}
+	}
+
+	// Although there's not a strongly typed error for this in go-winio,
+	// lots of people are using the default configuration for the docker
+	// daemon on Windows where the daemon is listening on a named pipe
+	// ("//./pipe/docker_engine"), and the client must be running elevated.
+	//
+	// Give users a clue rather than the not-overly useful message such as;
+	//
+	// 	open //./pipe/docker_engine: The system cannot find the file specified.
+	//
+	// Note we can't string compare "The system cannot find the file specified" as
+	// this is localized; for example. in French the error would be;
+	//
+	//	open //./pipe/docker_engine: Le fichier spécifié est introuvable.
+	if strings.Contains(err.Error(), `open //./pipe/docker_engine`) {
+		// Checks if client is running with elevated privileges
+		if f, elevatedErr := os.Open(`\\.\PHYSICALDRIVE0`); elevatedErr != nil {
+			err = fmt.Errorf("in the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect: %w", err)
+		} else {
+			_ = f.Close()
+			err = fmt.Errorf("this error may indicate that the docker daemon is not running: %w", err)
+		}
+	}
+
+	return nil, errConnectionFailed{fmt.Errorf("error during connect: %w", err)}
+}
+
+func checkResponseErr(serverResp *http.Response) (retErr error) {
+	if serverResp == nil {
+		return nil
+	}
+	if serverResp.StatusCode >= http.StatusOK && serverResp.StatusCode < http.StatusBadRequest {
+		return nil
+	}
+	defer func() {
+		retErr = httpErrorFromStatusCode(retErr, serverResp.StatusCode)
+	}()
+
+	var body []byte
+	var err error
+	var reqURL string
+	if serverResp.Request != nil {
+		reqURL = serverResp.Request.URL.String()
+	}
+	statusMsg := serverResp.Status
+	if statusMsg == "" {
+		statusMsg = http.StatusText(serverResp.StatusCode)
+	}
+	var reqMethod string
+	if serverResp.Request != nil {
+		reqMethod = serverResp.Request.Method
+	}
+	if serverResp.Body != nil && reqMethod != http.MethodHead {
+		bodyMax := 1 * 1024 * 1024 // 1 MiB
+		bodyR := &io.LimitedReader{
+			R: serverResp.Body,
+			N: int64(bodyMax),
+		}
+		body, err = io.ReadAll(bodyR)
+		if err != nil {
+			return err
+		}
+		if bodyR.N == 0 {
+			if reqURL != "" {
+				return fmt.Errorf("request returned %s with a message (> %d bytes) for API route and version %s, check if the server supports the requested API version", statusMsg, bodyMax, reqURL)
+			}
+			return fmt.Errorf("request returned %s with a message (> %d bytes); check if the server supports the requested API version", statusMsg, bodyMax)
+		}
+	}
+	if len(body) == 0 {
+		if reqURL != "" {
+			return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", statusMsg, reqURL)
+		}
+		return fmt.Errorf("request returned %s; check if the server supports the requested API version", statusMsg)
+	}
+
+	var daemonErr error
+	if serverResp.Header.Get("Content-Type") == "application/json" {
+		var errorResponse common.ErrorResponse
+		if err := json.Unmarshal(body, &errorResponse); err != nil {
+			return fmt.Errorf("error reading JSON: %w", err)
+		}
+		if errorResponse.Message == "" {
+			// Error-message is empty, which means that we successfully parsed the
+			// JSON-response (no error produced), but it didn't contain an error
+			// message. This could either be because the response was empty, or
+			// the response was valid JSON, but not with the expected schema
+			// ([common.ErrorResponse]).
+			//
+			// We cannot use "strict" JSON handling (json.NewDecoder with DisallowUnknownFields)
+			// due to the API using an open schema (we must anticipate fields
+			// being added to [common.ErrorResponse] in the future, and not
+			// reject those responses.
+			//
+			// For these cases, we construct an error with the status-code
+			// returned, but we could consider returning (a truncated version
+			// of) the actual response as-is.
+			//
+			// TODO(thaJeztah): consider adding a log.Debug to allow clients to debug the actual response when enabling debug logging.
+			daemonErr = fmt.Errorf(`API returned a %d (%s) but provided no error-message`,
+				serverResp.StatusCode,
+				http.StatusText(serverResp.StatusCode),
+			)
+		} else {
+			daemonErr = errors.New(strings.TrimSpace(errorResponse.Message))
+		}
+	} else {
+		// Fall back to returning the response as-is for situations where a
+		// plain text error is returned. This branch may also catch
+		// situations where a proxy is involved, returning an HTML response.
+		daemonErr = errors.New(strings.TrimSpace(string(body)))
+	}
+	return fmt.Errorf("Error response from daemon: %w", daemonErr)
+}
+
+func (cli *Client) addHeaders(req *http.Request, headers http.Header) *http.Request {
+	// Add CLI Config's HTTP Headers BEFORE we set the Docker headers
+	// then the user can't change OUR headers
+	for k, v := range cli.customHTTPHeaders {
+		req.Header.Set(k, v)
+	}
+
+	for k, v := range headers {
+		req.Header[http.CanonicalHeaderKey(k)] = v
+	}
+
+	if cli.userAgent == nil {
+		// No custom User-Agent set: use the default.
+		if req.Header.Get("User-Agent") == "" {
+			req.Header.Set("User-Agent", defaultUserAgent())
+		}
+	} else if *cli.userAgent == "" {
+		// User-Agent set to empty value; remove User-Agent.
+		req.Header.Del("User-Agent")
+	} else {
+		// Custom User-Agent set.
+		req.Header.Set("User-Agent", *cli.userAgent)
+	}
+	return req
+}
+
+func jsonEncode(data any) (io.Reader, error) {
+	switch x := data.(type) {
+	case nil:
+		return http.NoBody, nil
+	case io.Reader:
+		// http.NoBody or other readers
+		return x, nil
+	case json.RawMessage:
+		if len(x) == 0 {
+			return http.NoBody, nil
+		}
+		return bytes.NewReader(x), nil
+	}
+
+	// encoding/json encodes a nil pointer as the JSON document `null`,
+	// irrespective of whether the type implements json.Marshaler or encoding.TextMarshaler.
+	// That is almost certainly not what the caller intended as the request body.
+	if v := reflect.ValueOf(data); v.Kind() == reflect.Pointer && v.IsNil() {
+		return http.NoBody, nil
+	}
+
+	b, err := json.Marshal(data)
+	if err != nil {
+		return nil, err
+	}
+	return bytes.NewReader(b), nil
+}
+
+func ensureReaderClosed(response *http.Response) {
+	if response == nil || response.Body == nil {
+		return
+	}
+	if response.ContentLength == 0 || (response.Request != nil && response.Request.Method == http.MethodHead) {
+		// No need to drain head requests or zero-length responses.
+		_ = response.Body.Close()
+		return
+	}
+	// Drain up to 512 bytes and close the body to let the Transport reuse the connection
+	// see https://github.com/google/go-github/pull/317/files#r57536827
+	//
+	// TODO(thaJeztah): see if this optimization is still needed, or already implemented in stdlib,
+	//   and check if context-cancellation should handle this as well. If still needed, consider
+	//   wrapping response.Body, or returning a "closer()" from [Client.sendRequest] and related
+	//   methods.
+	_, _ = io.CopyN(io.Discard, response.Body, 512)
+	_ = response.Body.Close()
+}
diff --git a/vendor/github.com/moby/moby/client/secret_create.go b/vendor/github.com/moby/moby/client/secret_create.go
new file mode 100644
index 000000000..8e59a42ce
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/secret_create.go
@@ -0,0 +1,34 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SecretCreateOptions holds options for creating a secret.
+type SecretCreateOptions struct {
+	Spec swarm.SecretSpec
+}
+
+// SecretCreateResult holds the result from the [Client.SecretCreate] method.
+type SecretCreateResult struct {
+	ID string
+}
+
+// SecretCreate creates a new secret.
+func (cli *Client) SecretCreate(ctx context.Context, options SecretCreateOptions) (SecretCreateResult, error) {
+	resp, err := cli.post(ctx, "/secrets/create", nil, options.Spec, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return SecretCreateResult{}, err
+	}
+
+	var out swarm.ConfigCreateResponse
+	err = json.NewDecoder(resp.Body).Decode(&out)
+	if err != nil {
+		return SecretCreateResult{}, err
+	}
+	return SecretCreateResult{ID: out.ID}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/secret_inspect.go b/vendor/github.com/moby/moby/client/secret_inspect.go
new file mode 100644
index 000000000..fefd4cd23
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/secret_inspect.go
@@ -0,0 +1,35 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SecretInspectOptions holds options for inspecting a secret.
+type SecretInspectOptions struct {
+	// Add future optional parameters here
+}
+
+// SecretInspectResult holds the result from the [Client.SecretInspect]. method.
+type SecretInspectResult struct {
+	Secret swarm.Secret
+	Raw    json.RawMessage
+}
+
+// SecretInspect returns the secret information with raw data.
+func (cli *Client) SecretInspect(ctx context.Context, id string, options SecretInspectOptions) (SecretInspectResult, error) {
+	id, err := trimID("secret", id)
+	if err != nil {
+		return SecretInspectResult{}, err
+	}
+	resp, err := cli.get(ctx, "/secrets/"+id, nil, nil)
+	if err != nil {
+		return SecretInspectResult{}, err
+	}
+
+	var out SecretInspectResult
+	out.Raw, err = decodeWithRaw(resp, &out.Secret)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/secret_list.go b/vendor/github.com/moby/moby/client/secret_list.go
new file mode 100644
index 000000000..be3695575
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/secret_list.go
@@ -0,0 +1,38 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SecretListOptions holds parameters to list secrets
+type SecretListOptions struct {
+	Filters Filters
+}
+
+// SecretListResult holds the result from the [client.SecretList] method.
+type SecretListResult struct {
+	Items []swarm.Secret
+}
+
+// SecretList returns the list of secrets.
+func (cli *Client) SecretList(ctx context.Context, options SecretListOptions) (SecretListResult, error) {
+	query := url.Values{}
+	options.Filters.updateURLValues(query)
+
+	resp, err := cli.get(ctx, "/secrets", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return SecretListResult{}, err
+	}
+
+	var out SecretListResult
+	err = json.NewDecoder(resp.Body).Decode(&out.Items)
+	if err != nil {
+		return SecretListResult{}, err
+	}
+	return out, nil
+}
diff --git a/vendor/github.com/moby/moby/client/secret_remove.go b/vendor/github.com/moby/moby/client/secret_remove.go
new file mode 100644
index 000000000..42cbfec9e
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/secret_remove.go
@@ -0,0 +1,27 @@
+package client
+
+import "context"
+
+// SecretRemoveOptions holds options for [Client.SecretRemove].
+type SecretRemoveOptions struct {
+	// Add future optional parameters here
+}
+
+// SecretRemoveResult holds the result of [Client.SecretRemove].
+type SecretRemoveResult struct {
+	// Add future fields here
+}
+
+// SecretRemove removes a secret.
+func (cli *Client) SecretRemove(ctx context.Context, id string, options SecretRemoveOptions) (SecretRemoveResult, error) {
+	id, err := trimID("secret", id)
+	if err != nil {
+		return SecretRemoveResult{}, err
+	}
+	resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return SecretRemoveResult{}, err
+	}
+	return SecretRemoveResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/secret_update.go b/vendor/github.com/moby/moby/client/secret_update.go
new file mode 100644
index 000000000..d50fba4d4
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/secret_update.go
@@ -0,0 +1,33 @@
+package client
+
+import (
+	"context"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SecretUpdateOptions holds options for updating a secret.
+type SecretUpdateOptions struct {
+	Version swarm.Version
+	Spec    swarm.SecretSpec
+}
+
+// SecretUpdateResult holds the result of [Client.SecretUpdate].
+type SecretUpdateResult struct{}
+
+// SecretUpdate attempts to update a secret.
+func (cli *Client) SecretUpdate(ctx context.Context, id string, options SecretUpdateOptions) (SecretUpdateResult, error) {
+	id, err := trimID("secret", id)
+	if err != nil {
+		return SecretUpdateResult{}, err
+	}
+	query := url.Values{}
+	query.Set("version", options.Version.String())
+	resp, err := cli.post(ctx, "/secrets/"+id+"/update", query, options.Spec, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return SecretUpdateResult{}, err
+	}
+	return SecretUpdateResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/service_create.go b/vendor/github.com/moby/moby/client/service_create.go
new file mode 100644
index 000000000..319bca6f4
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/service_create.go
@@ -0,0 +1,206 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/distribution/reference"
+	"github.com/moby/moby/api/types/registry"
+	"github.com/moby/moby/api/types/swarm"
+	"github.com/opencontainers/go-digest"
+)
+
+// ServiceCreateOptions contains the options to use when creating a service.
+type ServiceCreateOptions struct {
+	Spec swarm.ServiceSpec
+
+	// EncodedRegistryAuth is the encoded registry authorization credentials to
+	// use when updating the service.
+	//
+	// This field follows the format of the X-Registry-Auth header.
+	EncodedRegistryAuth string
+
+	// QueryRegistry indicates whether the service update requires
+	// contacting a registry. A registry may be contacted to retrieve
+	// the image digest and manifest, which in turn can be used to update
+	// platform or other information about the service.
+	QueryRegistry bool
+}
+
+// ServiceCreateResult represents the result of creating a service.
+type ServiceCreateResult struct {
+	// ID is the ID of the created service.
+	ID string
+
+	// Warnings is a list of warnings that occurred during service creation.
+	Warnings []string
+}
+
+// ServiceCreate creates a new service.
+func (cli *Client) ServiceCreate(ctx context.Context, options ServiceCreateOptions) (ServiceCreateResult, error) {
+	// Make sure containerSpec is not nil when no runtime is set or the runtime is set to container
+	if options.Spec.TaskTemplate.ContainerSpec == nil && (options.Spec.TaskTemplate.Runtime == "" || options.Spec.TaskTemplate.Runtime == swarm.RuntimeContainer) {
+		options.Spec.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{}
+	}
+
+	if err := validateServiceSpec(options.Spec); err != nil {
+		return ServiceCreateResult{}, err
+	}
+
+	// ensure that the image is tagged
+	var warnings []string
+	switch {
+	case options.Spec.TaskTemplate.ContainerSpec != nil:
+		if taggedImg := imageWithTagString(options.Spec.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
+			options.Spec.TaskTemplate.ContainerSpec.Image = taggedImg
+		}
+		if options.QueryRegistry {
+			if warning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
+				warnings = append(warnings, warning)
+			}
+		}
+	case options.Spec.TaskTemplate.PluginSpec != nil:
+		if taggedImg := imageWithTagString(options.Spec.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
+			options.Spec.TaskTemplate.PluginSpec.Remote = taggedImg
+		}
+		if options.QueryRegistry {
+			if warning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
+				warnings = append(warnings, warning)
+			}
+		}
+	}
+
+	headers := http.Header{}
+	if options.EncodedRegistryAuth != "" {
+		headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
+	}
+	resp, err := cli.post(ctx, "/services/create", nil, options.Spec, headers)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ServiceCreateResult{}, err
+	}
+
+	var response swarm.ServiceCreateResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	warnings = append(warnings, response.Warnings...)
+
+	return ServiceCreateResult{
+		ID:       response.ID,
+		Warnings: warnings,
+	}, err
+}
+
+func resolveContainerSpecImage(ctx context.Context, cli DistributionAPIClient, taskSpec *swarm.TaskSpec, encodedAuth string) string {
+	img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.ContainerSpec.Image, encodedAuth)
+	if err != nil {
+		return digestWarning(taskSpec.ContainerSpec.Image)
+	}
+	taskSpec.ContainerSpec.Image = img
+	if len(imgPlatforms) > 0 {
+		if taskSpec.Placement == nil {
+			taskSpec.Placement = &swarm.Placement{}
+		}
+		taskSpec.Placement.Platforms = imgPlatforms
+	}
+	return ""
+}
+
+func resolvePluginSpecRemote(ctx context.Context, cli DistributionAPIClient, taskSpec *swarm.TaskSpec, encodedAuth string) string {
+	img, imgPlatforms, err := imageDigestAndPlatforms(ctx, cli, taskSpec.PluginSpec.Remote, encodedAuth)
+	if err != nil {
+		return digestWarning(taskSpec.PluginSpec.Remote)
+	}
+	taskSpec.PluginSpec.Remote = img
+	if len(imgPlatforms) > 0 {
+		if taskSpec.Placement == nil {
+			taskSpec.Placement = &swarm.Placement{}
+		}
+		taskSpec.Placement.Platforms = imgPlatforms
+	}
+	return ""
+}
+
+func imageDigestAndPlatforms(ctx context.Context, cli DistributionAPIClient, image, encodedAuth string) (string, []swarm.Platform, error) {
+	distributionInspect, err := cli.DistributionInspect(ctx, image, DistributionInspectOptions{
+		EncodedRegistryAuth: encodedAuth,
+	})
+	var platforms []swarm.Platform
+	if err != nil {
+		return "", nil, err
+	}
+
+	imageWithDigest := imageWithDigestString(image, distributionInspect.Descriptor.Digest)
+
+	if len(distributionInspect.Platforms) > 0 {
+		platforms = make([]swarm.Platform, 0, len(distributionInspect.Platforms))
+		for _, p := range distributionInspect.Platforms {
+			// clear architecture field for arm. This is a temporary patch to address
+			// https://github.com/docker/swarmkit/issues/2294. The issue is that while
+			// image manifests report "arm" as the architecture, the node reports
+			// something like "armv7l" (includes the variant), which causes arm images
+			// to stop working with swarm mode. This patch removes the architecture
+			// constraint for arm images to ensure tasks get scheduled.
+			arch := p.Architecture
+			if strings.ToLower(arch) == "arm" {
+				arch = ""
+			}
+			platforms = append(platforms, swarm.Platform{
+				Architecture: arch,
+				OS:           p.OS,
+			})
+		}
+	}
+	return imageWithDigest, platforms, err
+}
+
+// imageWithDigestString takes an image string and a digest, and updates
+// the image string if it didn't originally contain a digest. It returns
+// image unmodified in other situations.
+func imageWithDigestString(image string, dgst digest.Digest) string {
+	namedRef, err := reference.ParseNormalizedNamed(image)
+	if err == nil {
+		if _, hasDigest := namedRef.(reference.Digested); !hasDigest {
+			// ensure that image gets a default tag if none is provided
+			img, err := reference.WithDigest(namedRef, dgst)
+			if err == nil {
+				return reference.FamiliarString(img)
+			}
+		}
+	}
+	return image
+}
+
+// imageWithTagString takes an image string, and returns a tagged image
+// string, adding a 'latest' tag if one was not provided. It returns an
+// empty string if a canonical reference was provided
+func imageWithTagString(image string) string {
+	namedRef, err := reference.ParseNormalizedNamed(image)
+	if err == nil {
+		return reference.FamiliarString(reference.TagNameOnly(namedRef))
+	}
+	return ""
+}
+
+// digestWarning constructs a formatted warning string using the
+// image name that could not be pinned by digest. The formatting
+// is hardcoded, but could me made smarter in the future
+func digestWarning(image string) string {
+	return fmt.Sprintf("image %s could not be accessed on a registry to record\nits digest. Each node will access %s independently,\npossibly leading to different nodes running different\nversions of the image.\n", image, image)
+}
+
+func validateServiceSpec(s swarm.ServiceSpec) error {
+	if s.TaskTemplate.ContainerSpec != nil && s.TaskTemplate.PluginSpec != nil {
+		return errors.New("must not specify both a container spec and a plugin spec in the task template")
+	}
+	if s.TaskTemplate.PluginSpec != nil && s.TaskTemplate.Runtime != swarm.RuntimePlugin {
+		return errors.New("mismatched runtime with plugin spec")
+	}
+	if s.TaskTemplate.ContainerSpec != nil && (s.TaskTemplate.Runtime != "" && s.TaskTemplate.Runtime != swarm.RuntimeContainer) {
+		return errors.New("mismatched runtime with container spec")
+	}
+	return nil
+}
diff --git a/vendor/github.com/moby/moby/client/service_inspect.go b/vendor/github.com/moby/moby/client/service_inspect.go
new file mode 100644
index 000000000..9bda43f86
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/service_inspect.go
@@ -0,0 +1,40 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// ServiceInspectOptions holds parameters related to the service inspect operation.
+type ServiceInspectOptions struct {
+	InsertDefaults bool
+}
+
+// ServiceInspectResult represents the result of a service inspect operation.
+type ServiceInspectResult struct {
+	Service swarm.Service
+	Raw     json.RawMessage
+}
+
+// ServiceInspect retrieves detailed information about a specific service by its ID.
+func (cli *Client) ServiceInspect(ctx context.Context, serviceID string, options ServiceInspectOptions) (ServiceInspectResult, error) {
+	serviceID, err := trimID("service", serviceID)
+	if err != nil {
+		return ServiceInspectResult{}, err
+	}
+
+	query := url.Values{}
+	query.Set("insertDefaults", fmt.Sprintf("%v", options.InsertDefaults))
+	resp, err := cli.get(ctx, "/services/"+serviceID, query, nil)
+	if err != nil {
+		return ServiceInspectResult{}, err
+	}
+
+	var out ServiceInspectResult
+	out.Raw, err = decodeWithRaw(resp, &out.Service)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/service_list.go b/vendor/github.com/moby/moby/client/service_list.go
new file mode 100644
index 000000000..94b5204be
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/service_list.go
@@ -0,0 +1,44 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// ServiceListOptions holds parameters to list services with.
+type ServiceListOptions struct {
+	Filters Filters
+
+	// Status indicates whether the server should include the service task
+	// count of running and desired tasks.
+	Status bool
+}
+
+// ServiceListResult represents the result of a service list operation.
+type ServiceListResult struct {
+	Items []swarm.Service
+}
+
+// ServiceList returns the list of services.
+func (cli *Client) ServiceList(ctx context.Context, options ServiceListOptions) (ServiceListResult, error) {
+	query := url.Values{}
+
+	options.Filters.updateURLValues(query)
+
+	if options.Status {
+		query.Set("status", "true")
+	}
+
+	resp, err := cli.get(ctx, "/services", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ServiceListResult{}, err
+	}
+
+	var services []swarm.Service
+	err = json.NewDecoder(resp.Body).Decode(&services)
+	return ServiceListResult{Items: services}, err
+}
diff --git a/vendor/github.com/moby/moby/client/service_logs.go b/vendor/github.com/moby/moby/client/service_logs.go
new file mode 100644
index 000000000..911b63cb7
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/service_logs.go
@@ -0,0 +1,106 @@
+package client
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/url"
+	"time"
+
+	"github.com/moby/moby/client/internal/timestamp"
+)
+
+// ServiceLogsOptions holds parameters to filter logs with.
+type ServiceLogsOptions struct {
+	ShowStdout bool
+	ShowStderr bool
+	Since      string
+	Until      string
+	Timestamps bool
+	Follow     bool
+	Tail       string
+	Details    bool
+}
+
+// ServiceLogsResult holds the result of a service logs operation.
+// It implements [io.ReadCloser].
+// It's up to the caller to close the stream.
+type ServiceLogsResult interface {
+	io.ReadCloser
+}
+
+// ServiceLogs returns the logs generated by a service in a [ServiceLogsResult].
+// as an [io.ReadCloser]. Callers should close the stream.
+//
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
+func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options ServiceLogsOptions) (ServiceLogsResult, error) {
+	// TODO(thaJeztah): this function needs documentation about the format of the stream (similar to for container logs)
+	// TODO(thaJeztah): migrate CLI utilities to the client where suitable; https://github.com/docker/cli/blob/v29.0.0-rc.1/cli/command/service/logs.go#L73-L348
+
+	serviceID, err := trimID("service", serviceID)
+	if err != nil {
+		return nil, err
+	}
+
+	query := url.Values{}
+	if options.ShowStdout {
+		query.Set("stdout", "1")
+	}
+
+	if options.ShowStderr {
+		query.Set("stderr", "1")
+	}
+
+	if options.Since != "" {
+		ts, err := timestamp.GetTimestamp(options.Since, time.Now())
+		if err != nil {
+			return nil, fmt.Errorf(`invalid value for "since": %w`, err)
+		}
+		query.Set("since", ts)
+	}
+
+	if options.Timestamps {
+		query.Set("timestamps", "1")
+	}
+
+	if options.Details {
+		query.Set("details", "1")
+	}
+
+	if options.Follow {
+		query.Set("follow", "1")
+	}
+	switch options.Tail {
+	case "", "all":
+		// don't send option; default is to show all logs.
+		//
+		// The default on the daemon-side is to show all logs; account for
+		// some special values. The CLI may set a magic "all" value that's
+		// used as default.
+		//
+		// Given that the default is to show all logs, we can ignore these
+		// values, and don't send "tail".
+		//
+		// see https://github.com/moby/moby/blob/0df791cb72b568eeadba2267fe9a5040d12b0487/daemon/logs.go#L75-L78
+		// see https://github.com/moby/moby/blob/4d20b6fe56dfb2b06f4a5dd1f32913215a9c317b/daemon/cluster/services.go#L425-L449
+	default:
+		query.Set("tail", options.Tail)
+	}
+
+	resp, err := cli.get(ctx, "/services/"+serviceID+"/logs", query, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &serviceLogsResult{
+		ReadCloser: newCancelReadCloser(ctx, resp.Body),
+	}, nil
+}
+
+type serviceLogsResult struct {
+	io.ReadCloser
+}
+
+var (
+	_ io.ReadCloser     = (*serviceLogsResult)(nil)
+	_ ServiceLogsResult = (*serviceLogsResult)(nil)
+)
diff --git a/vendor/github.com/moby/moby/client/service_remove.go b/vendor/github.com/moby/moby/client/service_remove.go
new file mode 100644
index 000000000..163689b69
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/service_remove.go
@@ -0,0 +1,25 @@
+package client
+
+import "context"
+
+// ServiceRemoveOptions contains options for removing a service.
+type ServiceRemoveOptions struct {
+	// No options currently; placeholder for future use
+}
+
+// ServiceRemoveResult contains the result of removing a service.
+type ServiceRemoveResult struct {
+	// No fields currently; placeholder for future use
+}
+
+// ServiceRemove kills and removes a service.
+func (cli *Client) ServiceRemove(ctx context.Context, serviceID string, options ServiceRemoveOptions) (ServiceRemoveResult, error) {
+	serviceID, err := trimID("service", serviceID)
+	if err != nil {
+		return ServiceRemoveResult{}, err
+	}
+
+	resp, err := cli.delete(ctx, "/services/"+serviceID, nil, nil)
+	defer ensureReaderClosed(resp)
+	return ServiceRemoveResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/service_update.go b/vendor/github.com/moby/moby/client/service_update.go
new file mode 100644
index 000000000..2505fe4b8
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/service_update.go
@@ -0,0 +1,114 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"net/url"
+
+	"github.com/moby/moby/api/types/registry"
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// ServiceUpdateOptions contains the options to be used for updating services.
+type ServiceUpdateOptions struct {
+	Version swarm.Version
+	Spec    swarm.ServiceSpec
+
+	// EncodedRegistryAuth is the encoded registry authorization credentials to
+	// use when updating the service.
+	//
+	// This field follows the format of the X-Registry-Auth header.
+	EncodedRegistryAuth string
+
+	// TODO(stevvooe): Consider moving the version parameter of ServiceUpdate
+	// into this field. While it does open API users up to racy writes, most
+	// users may not need that level of consistency in practice.
+
+	// RegistryAuthFrom specifies where to find the registry authorization
+	// credentials if they are not given in EncodedRegistryAuth. Valid
+	// values are "spec" and "previous-spec".
+	RegistryAuthFrom swarm.RegistryAuthSource
+
+	// Rollback indicates whether a server-side rollback should be
+	// performed. When this is set, the provided spec will be ignored.
+	// The valid values are "previous" and "none". An empty value is the
+	// same as "none".
+	Rollback string
+
+	// QueryRegistry indicates whether the service update requires
+	// contacting a registry. A registry may be contacted to retrieve
+	// the image digest and manifest, which in turn can be used to update
+	// platform or other information about the service.
+	QueryRegistry bool
+}
+
+// ServiceUpdateResult represents the result of a service update.
+type ServiceUpdateResult struct {
+	// Warnings contains any warnings that occurred during the update.
+	Warnings []string
+}
+
+// ServiceUpdate updates a Service. The version number is required to avoid
+// conflicting writes. It must be the value as set *before* the update.
+// You can find this value in the [swarm.Service.Meta] field, which can
+// be found using [Client.ServiceInspectWithRaw].
+func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, options ServiceUpdateOptions) (ServiceUpdateResult, error) {
+	serviceID, err := trimID("service", serviceID)
+	if err != nil {
+		return ServiceUpdateResult{}, err
+	}
+
+	if err := validateServiceSpec(options.Spec); err != nil {
+		return ServiceUpdateResult{}, err
+	}
+
+	query := url.Values{}
+	if options.RegistryAuthFrom != "" {
+		query.Set("registryAuthFrom", string(options.RegistryAuthFrom))
+	}
+
+	if options.Rollback != "" {
+		query.Set("rollback", options.Rollback)
+	}
+
+	query.Set("version", options.Version.String())
+
+	// ensure that the image is tagged
+	var warnings []string
+	switch {
+	case options.Spec.TaskTemplate.ContainerSpec != nil:
+		if taggedImg := imageWithTagString(options.Spec.TaskTemplate.ContainerSpec.Image); taggedImg != "" {
+			options.Spec.TaskTemplate.ContainerSpec.Image = taggedImg
+		}
+		if options.QueryRegistry {
+			if warning := resolveContainerSpecImage(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
+				warnings = append(warnings, warning)
+			}
+		}
+	case options.Spec.TaskTemplate.PluginSpec != nil:
+		if taggedImg := imageWithTagString(options.Spec.TaskTemplate.PluginSpec.Remote); taggedImg != "" {
+			options.Spec.TaskTemplate.PluginSpec.Remote = taggedImg
+		}
+		if options.QueryRegistry {
+			if warning := resolvePluginSpecRemote(ctx, cli, &options.Spec.TaskTemplate, options.EncodedRegistryAuth); warning != "" {
+				warnings = append(warnings, warning)
+			}
+		}
+	}
+
+	headers := http.Header{}
+	if options.EncodedRegistryAuth != "" {
+		headers.Set(registry.AuthHeader, options.EncodedRegistryAuth)
+	}
+	resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, options.Spec, headers)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ServiceUpdateResult{}, err
+	}
+
+	var response swarm.ServiceUpdateResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	warnings = append(warnings, response.Warnings...)
+	return ServiceUpdateResult{Warnings: warnings}, err
+}
diff --git a/vendor/github.com/moby/moby/client/swarm_get_unlock_key.go b/vendor/github.com/moby/moby/client/swarm_get_unlock_key.go
new file mode 100644
index 000000000..03ecce409
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/swarm_get_unlock_key.go
@@ -0,0 +1,26 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SwarmGetUnlockKeyResult contains the swarm unlock key.
+type SwarmGetUnlockKeyResult struct {
+	Key string
+}
+
+// SwarmGetUnlockKey retrieves the swarm's unlock key.
+func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (SwarmGetUnlockKeyResult, error) {
+	resp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return SwarmGetUnlockKeyResult{}, err
+	}
+
+	var response swarm.UnlockKeyResponse
+	err = json.NewDecoder(resp.Body).Decode(&response)
+	return SwarmGetUnlockKeyResult{Key: response.UnlockKey}, err
+}
diff --git a/vendor/github.com/moby/moby/client/swarm_init.go b/vendor/github.com/moby/moby/client/swarm_init.go
new file mode 100644
index 000000000..caad56085
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/swarm_init.go
@@ -0,0 +1,54 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/netip"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SwarmInitOptions contains options for initializing a new swarm.
+type SwarmInitOptions struct {
+	ListenAddr       string
+	AdvertiseAddr    string
+	DataPathAddr     string
+	DataPathPort     uint32
+	ForceNewCluster  bool
+	Spec             swarm.Spec
+	AutoLockManagers bool
+	Availability     swarm.NodeAvailability
+	DefaultAddrPool  []netip.Prefix
+	SubnetSize       uint32
+}
+
+// SwarmInitResult contains the result of a SwarmInit operation.
+type SwarmInitResult struct {
+	NodeID string
+}
+
+// SwarmInit initializes the swarm.
+func (cli *Client) SwarmInit(ctx context.Context, options SwarmInitOptions) (SwarmInitResult, error) {
+	req := swarm.InitRequest{
+		ListenAddr:       options.ListenAddr,
+		AdvertiseAddr:    options.AdvertiseAddr,
+		DataPathAddr:     options.DataPathAddr,
+		DataPathPort:     options.DataPathPort,
+		ForceNewCluster:  options.ForceNewCluster,
+		Spec:             options.Spec,
+		AutoLockManagers: options.AutoLockManagers,
+		Availability:     options.Availability,
+		DefaultAddrPool:  options.DefaultAddrPool,
+		SubnetSize:       options.SubnetSize,
+	}
+
+	resp, err := cli.post(ctx, "/swarm/init", nil, req, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return SwarmInitResult{}, err
+	}
+
+	var nodeID string
+	err = json.NewDecoder(resp.Body).Decode(&nodeID)
+	return SwarmInitResult{NodeID: nodeID}, err
+}
diff --git a/vendor/github.com/moby/moby/client/swarm_inspect.go b/vendor/github.com/moby/moby/client/swarm_inspect.go
new file mode 100644
index 000000000..40e1d018a
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/swarm_inspect.go
@@ -0,0 +1,31 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SwarmInspectOptions holds options for inspecting a swarm.
+type SwarmInspectOptions struct {
+	// Add future optional parameters here
+}
+
+// SwarmInspectResult represents the result of a SwarmInspect operation.
+type SwarmInspectResult struct {
+	Swarm swarm.Swarm
+}
+
+// SwarmInspect inspects the swarm.
+func (cli *Client) SwarmInspect(ctx context.Context, options SwarmInspectOptions) (SwarmInspectResult, error) {
+	resp, err := cli.get(ctx, "/swarm", nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return SwarmInspectResult{}, err
+	}
+
+	var s swarm.Swarm
+	err = json.NewDecoder(resp.Body).Decode(&s)
+	return SwarmInspectResult{Swarm: s}, err
+}
diff --git a/vendor/github.com/moby/moby/client/swarm_join.go b/vendor/github.com/moby/moby/client/swarm_join.go
new file mode 100644
index 000000000..66a754482
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/swarm_join.go
@@ -0,0 +1,38 @@
+package client
+
+import (
+	"context"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SwarmJoinOptions specifies options for joining a swarm.
+type SwarmJoinOptions struct {
+	ListenAddr    string
+	AdvertiseAddr string
+	DataPathAddr  string
+	RemoteAddrs   []string
+	JoinToken     string // accept by secret
+	Availability  swarm.NodeAvailability
+}
+
+// SwarmJoinResult contains the result of joining a swarm.
+type SwarmJoinResult struct {
+	// No fields currently; placeholder for future use
+}
+
+// SwarmJoin joins the swarm.
+func (cli *Client) SwarmJoin(ctx context.Context, options SwarmJoinOptions) (SwarmJoinResult, error) {
+	req := swarm.JoinRequest{
+		ListenAddr:    options.ListenAddr,
+		AdvertiseAddr: options.AdvertiseAddr,
+		DataPathAddr:  options.DataPathAddr,
+		RemoteAddrs:   options.RemoteAddrs,
+		JoinToken:     options.JoinToken,
+		Availability:  options.Availability,
+	}
+
+	resp, err := cli.post(ctx, "/swarm/join", nil, req, nil)
+	defer ensureReaderClosed(resp)
+	return SwarmJoinResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/swarm_leave.go b/vendor/github.com/moby/moby/client/swarm_leave.go
new file mode 100644
index 000000000..a65a13de3
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/swarm_leave.go
@@ -0,0 +1,25 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// SwarmLeaveOptions contains options for leaving a swarm.
+type SwarmLeaveOptions struct {
+	Force bool
+}
+
+// SwarmLeaveResult represents the result of a SwarmLeave operation.
+type SwarmLeaveResult struct{}
+
+// SwarmLeave leaves the swarm.
+func (cli *Client) SwarmLeave(ctx context.Context, options SwarmLeaveOptions) (SwarmLeaveResult, error) {
+	query := url.Values{}
+	if options.Force {
+		query.Set("force", "1")
+	}
+	resp, err := cli.post(ctx, "/swarm/leave", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	return SwarmLeaveResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/swarm_unlock.go b/vendor/github.com/moby/moby/client/swarm_unlock.go
new file mode 100644
index 000000000..92335afb5
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/swarm_unlock.go
@@ -0,0 +1,25 @@
+package client
+
+import (
+	"context"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SwarmUnlockOptions specifies options for unlocking a swarm.
+type SwarmUnlockOptions struct {
+	Key string
+}
+
+// SwarmUnlockResult represents the result of unlocking a swarm.
+type SwarmUnlockResult struct{}
+
+// SwarmUnlock unlocks locked swarm.
+func (cli *Client) SwarmUnlock(ctx context.Context, options SwarmUnlockOptions) (SwarmUnlockResult, error) {
+	req := &swarm.UnlockRequest{
+		UnlockKey: options.Key,
+	}
+	resp, err := cli.post(ctx, "/swarm/unlock", nil, req, nil)
+	defer ensureReaderClosed(resp)
+	return SwarmUnlockResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/swarm_update.go b/vendor/github.com/moby/moby/client/swarm_update.go
new file mode 100644
index 000000000..81f62b2c0
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/swarm_update.go
@@ -0,0 +1,33 @@
+package client
+
+import (
+	"context"
+	"net/url"
+	"strconv"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// SwarmUpdateOptions contains options for updating a swarm.
+type SwarmUpdateOptions struct {
+	Version                swarm.Version
+	Spec                   swarm.Spec
+	RotateWorkerToken      bool
+	RotateManagerToken     bool
+	RotateManagerUnlockKey bool
+}
+
+// SwarmUpdateResult represents the result of a SwarmUpdate operation.
+type SwarmUpdateResult struct{}
+
+// SwarmUpdate updates the swarm.
+func (cli *Client) SwarmUpdate(ctx context.Context, options SwarmUpdateOptions) (SwarmUpdateResult, error) {
+	query := url.Values{}
+	query.Set("version", options.Version.String())
+	query.Set("rotateWorkerToken", strconv.FormatBool(options.RotateWorkerToken))
+	query.Set("rotateManagerToken", strconv.FormatBool(options.RotateManagerToken))
+	query.Set("rotateManagerUnlockKey", strconv.FormatBool(options.RotateManagerUnlockKey))
+	resp, err := cli.post(ctx, "/swarm/update", query, options.Spec, nil)
+	defer ensureReaderClosed(resp)
+	return SwarmUpdateResult{}, err
+}
diff --git a/vendor/github.com/moby/moby/client/system_disk_usage.go b/vendor/github.com/moby/moby/client/system_disk_usage.go
new file mode 100644
index 000000000..3f54bfd34
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/system_disk_usage.go
@@ -0,0 +1,330 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"slices"
+
+	"github.com/moby/moby/api/types/build"
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/image"
+	"github.com/moby/moby/api/types/system"
+	"github.com/moby/moby/api/types/volume"
+	"github.com/moby/moby/client/pkg/versions"
+)
+
+// DiskUsageOptions holds parameters for [Client.DiskUsage] operations.
+type DiskUsageOptions struct {
+	// Containers controls whether container disk usage should be computed.
+	Containers bool
+
+	// Images controls whether image disk usage should be computed.
+	Images bool
+
+	// BuildCache controls whether build cache disk usage should be computed.
+	BuildCache bool
+
+	// Volumes controls whether volume disk usage should be computed.
+	Volumes bool
+
+	// Verbose enables more detailed disk usage information.
+	Verbose bool
+}
+
+// DiskUsageResult is the result of [Client.DiskUsage] operations.
+type DiskUsageResult struct {
+	// Containers holds container disk usage information.
+	Containers ContainersDiskUsage
+
+	// Images holds image disk usage information.
+	Images ImagesDiskUsage
+
+	// BuildCache holds build cache disk usage information.
+	BuildCache BuildCacheDiskUsage
+
+	// Volumes holds volume disk usage information.
+	Volumes VolumesDiskUsage
+}
+
+// ContainersDiskUsage contains disk usage information for containers.
+type ContainersDiskUsage struct {
+	// ActiveCount is the number of active containers.
+	ActiveCount int64
+
+	// TotalCount is the total number of containers.
+	TotalCount int64
+
+	// Reclaimable is the amount of disk space that can be reclaimed.
+	Reclaimable int64
+
+	// TotalSize is the total disk space used by all containers.
+	TotalSize int64
+
+	// Items holds detailed information about each container.
+	Items []container.Summary
+}
+
+// ImagesDiskUsage contains disk usage information for images.
+type ImagesDiskUsage struct {
+	// ActiveCount is the number of active images.
+	ActiveCount int64
+
+	// TotalCount is the total number of images.
+	TotalCount int64
+
+	// Reclaimable is the amount of disk space that can be reclaimed.
+	Reclaimable int64
+
+	// TotalSize is the total disk space used by all images.
+	TotalSize int64
+
+	// Items holds detailed information about each image.
+	Items []image.Summary
+}
+
+// VolumesDiskUsage contains disk usage information for volumes.
+type VolumesDiskUsage struct {
+	// ActiveCount is the number of active volumes.
+	ActiveCount int64
+
+	// TotalCount is the total number of volumes.
+	TotalCount int64
+
+	// Reclaimable is the amount of disk space that can be reclaimed.
+	Reclaimable int64
+
+	// TotalSize is the total disk space used by all volumes.
+	TotalSize int64
+
+	// Items holds detailed information about each volume.
+	Items []volume.Volume
+}
+
+// BuildCacheDiskUsage contains disk usage information for build cache.
+type BuildCacheDiskUsage struct {
+	// ActiveCount is the number of active build cache records.
+	ActiveCount int64
+
+	// TotalCount is the total number of build cache records.
+	TotalCount int64
+
+	// Reclaimable is the amount of disk space that can be reclaimed.
+	Reclaimable int64
+
+	// TotalSize is the total disk space used by all build cache records.
+	TotalSize int64
+
+	// Items holds detailed information about each build cache record.
+	Items []build.CacheRecord
+}
+
+// DiskUsage requests the current data usage from the daemon.
+func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error) {
+	query := url.Values{}
+
+	for _, t := range []struct {
+		flag   bool
+		sysObj system.DiskUsageObject
+	}{
+		{options.Containers, system.ContainerObject},
+		{options.Images, system.ImageObject},
+		{options.Volumes, system.VolumeObject},
+		{options.BuildCache, system.BuildCacheObject},
+	} {
+		if t.flag {
+			query.Add("type", string(t.sysObj))
+		}
+	}
+
+	if options.Verbose {
+		query.Set("verbose", "1")
+	}
+
+	resp, err := cli.get(ctx, "/system/df", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return DiskUsageResult{}, err
+	}
+
+	if versions.LessThan(cli.version, "1.52") {
+		// Generate result from a legacy response.
+		var du legacyDiskUsage
+		if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
+			return DiskUsageResult{}, fmt.Errorf("retrieving disk usage: %v", err)
+		}
+
+		return diskUsageResultFromLegacyAPI(&du), nil
+	}
+
+	var du system.DiskUsage
+	if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
+		return DiskUsageResult{}, fmt.Errorf("retrieving disk usage: %v", err)
+	}
+
+	var r DiskUsageResult
+	if idu := du.ImageUsage; idu != nil {
+		r.Images = ImagesDiskUsage{
+			ActiveCount: idu.ActiveCount,
+			Reclaimable: idu.Reclaimable,
+			TotalCount:  idu.TotalCount,
+			TotalSize:   idu.TotalSize,
+		}
+
+		if options.Verbose {
+			r.Images.Items = slices.Clone(idu.Items)
+		}
+	}
+
+	if cdu := du.ContainerUsage; cdu != nil {
+		r.Containers = ContainersDiskUsage{
+			ActiveCount: cdu.ActiveCount,
+			Reclaimable: cdu.Reclaimable,
+			TotalCount:  cdu.TotalCount,
+			TotalSize:   cdu.TotalSize,
+		}
+
+		if options.Verbose {
+			r.Containers.Items = slices.Clone(cdu.Items)
+		}
+	}
+
+	if bdu := du.BuildCacheUsage; bdu != nil {
+		r.BuildCache = BuildCacheDiskUsage{
+			ActiveCount: bdu.ActiveCount,
+			Reclaimable: bdu.Reclaimable,
+			TotalCount:  bdu.TotalCount,
+			TotalSize:   bdu.TotalSize,
+		}
+
+		if options.Verbose {
+			r.BuildCache.Items = slices.Clone(bdu.Items)
+		}
+	}
+
+	if vdu := du.VolumeUsage; vdu != nil {
+		r.Volumes = VolumesDiskUsage{
+			ActiveCount: vdu.ActiveCount,
+			Reclaimable: vdu.Reclaimable,
+			TotalCount:  vdu.TotalCount,
+			TotalSize:   vdu.TotalSize,
+		}
+
+		if options.Verbose {
+			r.Volumes.Items = slices.Clone(vdu.Items)
+		}
+	}
+
+	return r, nil
+}
+
+// legacyDiskUsage is the response as was used by API < v1.52.
+type legacyDiskUsage struct {
+	LayersSize int64               `json:"LayersSize,omitempty"`
+	Images     []image.Summary     `json:"Images,omitzero"`
+	Containers []container.Summary `json:"Containers,omitzero"`
+	Volumes    []volume.Volume     `json:"Volumes,omitzero"`
+	BuildCache []build.CacheRecord `json:"BuildCache,omitzero"`
+}
+
+func diskUsageResultFromLegacyAPI(du *legacyDiskUsage) DiskUsageResult {
+	return DiskUsageResult{
+		Images:     imageDiskUsageFromLegacyAPI(du),
+		Containers: containerDiskUsageFromLegacyAPI(du),
+		BuildCache: buildCacheDiskUsageFromLegacyAPI(du),
+		Volumes:    volumeDiskUsageFromLegacyAPI(du),
+	}
+}
+
+func imageDiskUsageFromLegacyAPI(du *legacyDiskUsage) ImagesDiskUsage {
+	idu := ImagesDiskUsage{
+		TotalSize:  du.LayersSize,
+		TotalCount: int64(len(du.Images)),
+		Items:      du.Images,
+	}
+
+	for _, img := range idu.Items {
+		switch {
+		case img.Containers < 0:
+			// No container-count information available; skip (assume it's in use).
+		case img.Containers > 0:
+			idu.ActiveCount++
+		case img.Containers == 0 && img.Size != -1 && img.SharedSize != -1:
+			reclaimable := img.Size - img.SharedSize
+			idu.Reclaimable += reclaimable
+		}
+	}
+
+	return idu
+}
+
+func containerDiskUsageFromLegacyAPI(du *legacyDiskUsage) ContainersDiskUsage {
+	cdu := ContainersDiskUsage{
+		TotalCount: int64(len(du.Containers)),
+		Items:      du.Containers,
+	}
+
+	var used int64
+	for _, c := range cdu.Items {
+		cdu.TotalSize += c.SizeRw
+		switch c.State {
+		case container.StateRunning, container.StatePaused, container.StateRestarting:
+			cdu.ActiveCount++
+			used += c.SizeRw
+		case container.StateCreated, container.StateRemoving, container.StateExited, container.StateDead:
+			// not active
+		}
+	}
+
+	cdu.Reclaimable = cdu.TotalSize - used
+	return cdu
+}
+
+func buildCacheDiskUsageFromLegacyAPI(du *legacyDiskUsage) BuildCacheDiskUsage {
+	bdu := BuildCacheDiskUsage{
+		TotalCount: int64(len(du.BuildCache)),
+		Items:      du.BuildCache,
+	}
+
+	var used int64
+	for _, b := range du.BuildCache {
+		if !b.Shared {
+			bdu.TotalSize += b.Size
+		}
+
+		if b.InUse {
+			bdu.ActiveCount++
+			if !b.Shared {
+				used += b.Size
+			}
+		}
+	}
+
+	bdu.Reclaimable = bdu.TotalSize - used
+	return bdu
+}
+
+func volumeDiskUsageFromLegacyAPI(du *legacyDiskUsage) VolumesDiskUsage {
+	vdu := VolumesDiskUsage{
+		TotalCount: int64(len(du.Volumes)),
+		Items:      du.Volumes,
+	}
+
+	var used int64
+	for _, v := range vdu.Items {
+		// Ignore volumes with no usage data
+		if v.UsageData != nil {
+			if v.UsageData.RefCount > 0 {
+				vdu.ActiveCount++
+				used += v.UsageData.Size
+			}
+			if v.UsageData.Size > 0 {
+				vdu.TotalSize += v.UsageData.Size
+			}
+		}
+	}
+
+	vdu.Reclaimable = vdu.TotalSize - used
+	return vdu
+}
diff --git a/vendor/github.com/moby/moby/client/system_events.go b/vendor/github.com/moby/moby/client/system_events.go
new file mode 100644
index 000000000..b0ca71a19
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/system_events.go
@@ -0,0 +1,115 @@
+package client
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+	"time"
+
+	"github.com/moby/moby/api/types"
+	"github.com/moby/moby/api/types/events"
+	"github.com/moby/moby/client/internal"
+	"github.com/moby/moby/client/internal/timestamp"
+)
+
+// EventsListOptions holds parameters to filter events with.
+type EventsListOptions struct {
+	Since   string
+	Until   string
+	Filters Filters
+}
+
+// EventsResult holds the result of an Events query.
+type EventsResult struct {
+	Messages <-chan events.Message
+	Err      <-chan error
+}
+
+// Events returns a stream of events in the daemon. It's up to the caller to close the stream
+// by cancelling the context. Once the stream has been completely read an [io.EOF] error is
+// sent over the error channel. If an error is sent, all processing is stopped. It's up
+// to the caller to reopen the stream in the event of an error by reinvoking this method.
+func (cli *Client) Events(ctx context.Context, options EventsListOptions) EventsResult {
+	messages := make(chan events.Message)
+	errs := make(chan error, 1)
+
+	started := make(chan struct{})
+	go func() {
+		defer close(errs)
+
+		query, err := buildEventsQueryParams(options)
+		if err != nil {
+			close(started)
+			errs <- err
+			return
+		}
+
+		headers := http.Header{}
+		headers.Add("Accept", types.MediaTypeJSONLines) // Implicit q=1.0; in case server doesn't parse correctly.
+		headers.Add("Accept", types.MediaTypeNDJSON+";q=0.9")
+		headers.Add("Accept", types.MediaTypeJSONSequence+";q=0.5")
+		resp, err := cli.get(ctx, "/events", query, headers)
+		if err != nil {
+			close(started)
+			errs <- err
+			return
+		}
+		defer resp.Body.Close()
+
+		contentType := resp.Header.Get("Content-Type")
+		decoder := internal.NewJSONStreamDecoder(resp.Body, contentType)
+
+		close(started)
+		for {
+			select {
+			case <-ctx.Done():
+				errs <- ctx.Err()
+				return
+			default:
+				var event events.Message
+				if err := decoder(&event); err != nil {
+					errs <- err
+					return
+				}
+
+				select {
+				case messages <- event:
+				case <-ctx.Done():
+					errs <- ctx.Err()
+					return
+				}
+			}
+		}
+	}()
+	<-started
+
+	return EventsResult{
+		Messages: messages,
+		Err:      errs,
+	}
+}
+
+func buildEventsQueryParams(options EventsListOptions) (url.Values, error) {
+	query := url.Values{}
+	ref := time.Now()
+
+	if options.Since != "" {
+		ts, err := timestamp.GetTimestamp(options.Since, ref)
+		if err != nil {
+			return nil, err
+		}
+		query.Set("since", ts)
+	}
+
+	if options.Until != "" {
+		ts, err := timestamp.GetTimestamp(options.Until, ref)
+		if err != nil {
+			return nil, err
+		}
+		query.Set("until", ts)
+	}
+
+	options.Filters.updateURLValues(query)
+
+	return query, nil
+}
diff --git a/vendor/github.com/moby/moby/client/system_info.go b/vendor/github.com/moby/moby/client/system_info.go
new file mode 100644
index 000000000..b4241742d
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/system_info.go
@@ -0,0 +1,36 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	"github.com/moby/moby/api/types/system"
+)
+
+// InfoOptions holds options for [Client.Info].
+type InfoOptions struct {
+	// No options currently; placeholder for future use
+}
+
+// SystemInfoResult holds the result of [Client.Info].
+type SystemInfoResult struct {
+	Info system.Info
+}
+
+// Info returns information about the docker server.
+func (cli *Client) Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error) {
+	resp, err := cli.get(ctx, "/info", url.Values{}, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return SystemInfoResult{}, err
+	}
+
+	var info system.Info
+	if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
+		return SystemInfoResult{}, fmt.Errorf("Error reading remote info: %v", err)
+	}
+
+	return SystemInfoResult{Info: info}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/task_inspect.go b/vendor/github.com/moby/moby/client/task_inspect.go
new file mode 100644
index 000000000..96edcb09f
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/task_inspect.go
@@ -0,0 +1,36 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// TaskInspectOptions contains options for inspecting a task.
+type TaskInspectOptions struct {
+	// Currently no options are defined.
+}
+
+// TaskInspectResult contains the result of a task inspection.
+type TaskInspectResult struct {
+	Task swarm.Task
+	Raw  json.RawMessage
+}
+
+// TaskInspect returns the task information and its raw representation.
+func (cli *Client) TaskInspect(ctx context.Context, taskID string, options TaskInspectOptions) (TaskInspectResult, error) {
+	taskID, err := trimID("task", taskID)
+	if err != nil {
+		return TaskInspectResult{}, err
+	}
+
+	resp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil)
+	if err != nil {
+		return TaskInspectResult{}, err
+	}
+
+	var out TaskInspectResult
+	out.Raw, err = decodeWithRaw(resp, &out.Task)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/task_list.go b/vendor/github.com/moby/moby/client/task_list.go
new file mode 100644
index 000000000..5f7c41bb9
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/task_list.go
@@ -0,0 +1,36 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+)
+
+// TaskListOptions holds parameters to list tasks with.
+type TaskListOptions struct {
+	Filters Filters
+}
+
+// TaskListResult contains the result of a task list operation.
+type TaskListResult struct {
+	Items []swarm.Task
+}
+
+// TaskList returns the list of tasks.
+func (cli *Client) TaskList(ctx context.Context, options TaskListOptions) (TaskListResult, error) {
+	query := url.Values{}
+
+	options.Filters.updateURLValues(query)
+
+	resp, err := cli.get(ctx, "/tasks", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return TaskListResult{}, err
+	}
+
+	var tasks []swarm.Task
+	err = json.NewDecoder(resp.Body).Decode(&tasks)
+	return TaskListResult{Items: tasks}, err
+}
diff --git a/vendor/github.com/moby/moby/client/task_logs.go b/vendor/github.com/moby/moby/client/task_logs.go
new file mode 100644
index 000000000..0174ad465
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/task_logs.go
@@ -0,0 +1,84 @@
+package client
+
+import (
+	"context"
+	"io"
+	"net/url"
+	"time"
+
+	"github.com/moby/moby/client/internal/timestamp"
+)
+
+// TaskLogsOptions holds parameters to filter logs with.
+type TaskLogsOptions struct {
+	ShowStdout bool
+	ShowStderr bool
+	Since      string
+	Until      string
+	Timestamps bool
+	Follow     bool
+	Tail       string
+	Details    bool
+}
+
+// TaskLogsResult holds the result of a task logs operation.
+// It implements [io.ReadCloser].
+type TaskLogsResult interface {
+	io.ReadCloser
+}
+
+// TaskLogs returns the logs generated by a service in a [TaskLogsResult].
+// as an [io.ReadCloser]. Callers should close the stream.
+//
+// The underlying [io.ReadCloser] is automatically closed if the context is canceled,
+func (cli *Client) TaskLogs(ctx context.Context, taskID string, options TaskLogsOptions) (TaskLogsResult, error) {
+	// TODO(thaJeztah): this function needs documentation about the format of the stream (similar to for container logs)
+	// TODO(thaJeztah): migrate CLI utilities to the client where suitable; https://github.com/docker/cli/blob/v29.0.0-rc.1/cli/command/service/logs.go#L73-L348
+
+	query := url.Values{}
+	if options.ShowStdout {
+		query.Set("stdout", "1")
+	}
+
+	if options.ShowStderr {
+		query.Set("stderr", "1")
+	}
+
+	if options.Since != "" {
+		ts, err := timestamp.GetTimestamp(options.Since, time.Now())
+		if err != nil {
+			return nil, err
+		}
+		query.Set("since", ts)
+	}
+
+	if options.Timestamps {
+		query.Set("timestamps", "1")
+	}
+
+	if options.Details {
+		query.Set("details", "1")
+	}
+
+	if options.Follow {
+		query.Set("follow", "1")
+	}
+	query.Set("tail", options.Tail)
+
+	resp, err := cli.get(ctx, "/tasks/"+taskID+"/logs", query, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &taskLogsResult{
+		ReadCloser: newCancelReadCloser(ctx, resp.Body),
+	}, nil
+}
+
+type taskLogsResult struct {
+	io.ReadCloser
+}
+
+var (
+	_ io.ReadCloser       = (*taskLogsResult)(nil)
+	_ ContainerLogsResult = (*taskLogsResult)(nil)
+)
diff --git a/vendor/github.com/moby/moby/client/utils.go b/vendor/github.com/moby/moby/client/utils.go
new file mode 100644
index 000000000..1c0d09dfa
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/utils.go
@@ -0,0 +1,154 @@
+package client
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"sync"
+
+	cerrdefs "github.com/containerd/errdefs"
+	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+type emptyIDError string
+
+func (e emptyIDError) InvalidParameter() {}
+
+func (e emptyIDError) Error() string {
+	return "invalid " + string(e) + " name or ID: value is empty"
+}
+
+// trimID trims the given object-ID / name, returning an error if it's empty.
+func trimID(objType, id string) (string, error) {
+	id = strings.TrimSpace(id)
+	if id == "" {
+		return "", emptyIDError(objType)
+	}
+	return id, nil
+}
+
+// parseAPIVersion checks v to be a well-formed ("<major>.<minor>")
+// API version. It returns an error if the value is empty or does not
+// have the correct format, but does not validate if the API version is
+// within the supported range ([MinAPIVersion] <= v <= [MaxAPIVersion]).
+//
+// It returns version after normalizing, or an error if validation failed.
+func parseAPIVersion(version string) (string, error) {
+	if strings.TrimPrefix(strings.TrimSpace(version), "v") == "" {
+		return "", cerrdefs.ErrInvalidArgument.WithMessage("value is empty")
+	}
+	major, minor, err := parseMajorMinor(version)
+	if err != nil {
+		return "", err
+	}
+	return fmt.Sprintf("%d.%d", major, minor), nil
+}
+
+// parseMajorMinor is a helper for parseAPIVersion.
+func parseMajorMinor(v string) (major, minor int, _ error) {
+	if strings.HasPrefix(v, "v") {
+		return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("must be formatted <major>.<minor>")
+	}
+	if strings.TrimSpace(v) == "" {
+		return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("value is empty")
+	}
+
+	majVer, minVer, ok := strings.Cut(v, ".")
+	if !ok {
+		return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("must be formatted <major>.<minor>")
+	}
+	major, err := strconv.Atoi(majVer)
+	if err != nil {
+		return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("invalid major version: must be formatted <major>.<minor>")
+	}
+	minor, err = strconv.Atoi(minVer)
+	if err != nil {
+		return 0, 0, cerrdefs.ErrInvalidArgument.WithMessage("invalid minor version: must be formatted <major>.<minor>")
+	}
+	return major, minor, nil
+}
+
+// encodePlatforms marshals the given platform(s) to JSON format, to
+// be used for query-parameters for filtering / selecting platforms.
+func encodePlatforms(platform ...ocispec.Platform) ([]string, error) {
+	if len(platform) == 0 {
+		return []string{}, nil
+	}
+	if len(platform) == 1 {
+		p, err := encodePlatform(&platform[0])
+		if err != nil {
+			return nil, err
+		}
+		return []string{p}, nil
+	}
+
+	seen := make(map[string]struct{}, len(platform))
+	out := make([]string, 0, len(platform))
+	for i := range platform {
+		p, err := encodePlatform(&platform[i])
+		if err != nil {
+			return nil, err
+		}
+		if _, ok := seen[p]; !ok {
+			out = append(out, p)
+			seen[p] = struct{}{}
+		}
+	}
+	return out, nil
+}
+
+// encodePlatform marshals the given platform to JSON format, to
+// be used for query-parameters for filtering / selecting platforms. It
+// is used as a helper for encodePlatforms,
+func encodePlatform(platform *ocispec.Platform) (string, error) {
+	p, err := json.Marshal(platform)
+	if err != nil {
+		return "", fmt.Errorf("%w: invalid platform: %v", cerrdefs.ErrInvalidArgument, err)
+	}
+	return string(p), nil
+}
+
+func decodeWithRaw[T any](resp *http.Response, out *T) (raw json.RawMessage, _ error) {
+	if resp == nil || resp.Body == nil {
+		return nil, errors.New("empty response")
+	}
+	defer ensureReaderClosed(resp)
+
+	var buf bytes.Buffer
+	tr := io.TeeReader(resp.Body, &buf)
+	err := json.NewDecoder(tr).Decode(out)
+	if err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), nil
+}
+
+// newCancelReadCloser wraps rc so it's automatically closed when ctx is canceled.
+// Close is idempotent and returns the first error from rc.Close.
+func newCancelReadCloser(ctx context.Context, rc io.ReadCloser) io.ReadCloser {
+	crc := &cancelReadCloser{
+		rc:    rc,
+		close: sync.OnceValue(rc.Close),
+	}
+	crc.stop = context.AfterFunc(ctx, func() { _ = crc.close() })
+	return crc
+}
+
+type cancelReadCloser struct {
+	rc    io.ReadCloser
+	close func() error
+	stop  func() bool
+}
+
+func (c *cancelReadCloser) Read(p []byte) (int, error) { return c.rc.Read(p) }
+
+func (c *cancelReadCloser) Close() error {
+	c.stop() // unregister AfterFunc
+	return c.close()
+}
diff --git a/vendor/github.com/moby/moby/client/version.go b/vendor/github.com/moby/moby/client/version.go
new file mode 100644
index 000000000..7fa5a3fa0
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/version.go
@@ -0,0 +1,81 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/system"
+)
+
+// ServerVersionOptions specifies options for the server version request.
+type ServerVersionOptions struct {
+	// Currently no options are supported.
+}
+
+// ServerVersionResult contains information about the Docker server host.
+type ServerVersionResult struct {
+	// Platform is the platform (product name) the server is running on.
+	Platform PlatformInfo
+
+	// Version is the version of the daemon.
+	Version string
+
+	// APIVersion is the highest API version supported by the server.
+	APIVersion string
+
+	// MinAPIVersion is the minimum API version the server supports.
+	MinAPIVersion string
+
+	// Os is the operating system the server runs on.
+	Os string
+
+	// Arch is the hardware architecture the server runs on.
+	Arch string
+
+	// Experimental indicates that the daemon runs with experimental
+	// features enabled.
+	//
+	// Deprecated: this field will be removed in the next version.
+	Experimental bool
+
+	// Components contains version information for the components making
+	// up the server. Information in this field is for informational
+	// purposes, and not part of the API contract.
+	Components []system.ComponentVersion
+}
+
+// PlatformInfo holds information about the platform (product name) the
+// server is running on.
+type PlatformInfo struct {
+	// Name is the name of the platform (for example, "Docker Engine - Community",
+	// or "Docker Desktop 4.49.0 (208003)")
+	Name string
+}
+
+// ServerVersion returns information of the Docker server host.
+func (cli *Client) ServerVersion(ctx context.Context, _ ServerVersionOptions) (ServerVersionResult, error) {
+	resp, err := cli.get(ctx, "/version", nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return ServerVersionResult{}, err
+	}
+
+	var v system.VersionResponse
+	err = json.NewDecoder(resp.Body).Decode(&v)
+	if err != nil {
+		return ServerVersionResult{}, err
+	}
+
+	return ServerVersionResult{
+		Platform: PlatformInfo{
+			Name: v.Platform.Name,
+		},
+		Version:       v.Version,
+		APIVersion:    v.APIVersion,
+		MinAPIVersion: v.MinAPIVersion,
+		Os:            v.Os,
+		Arch:          v.Arch,
+		Experimental:  v.Experimental, //nolint:staticcheck // ignore deprecated field.
+		Components:    v.Components,
+	}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/volume_create.go b/vendor/github.com/moby/moby/client/volume_create.go
new file mode 100644
index 000000000..674e06335
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/volume_create.go
@@ -0,0 +1,42 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/volume"
+)
+
+// VolumeCreateOptions specifies the options to create a volume.
+type VolumeCreateOptions struct {
+	Name              string
+	Driver            string
+	DriverOpts        map[string]string
+	Labels            map[string]string
+	ClusterVolumeSpec *volume.ClusterVolumeSpec
+}
+
+// VolumeCreateResult is the result of a volume creation.
+type VolumeCreateResult struct {
+	Volume volume.Volume
+}
+
+// VolumeCreate creates a volume in the docker host.
+func (cli *Client) VolumeCreate(ctx context.Context, options VolumeCreateOptions) (VolumeCreateResult, error) {
+	createRequest := volume.CreateRequest{
+		Name:              options.Name,
+		Driver:            options.Driver,
+		DriverOpts:        options.DriverOpts,
+		Labels:            options.Labels,
+		ClusterVolumeSpec: options.ClusterVolumeSpec,
+	}
+	resp, err := cli.post(ctx, "/volumes/create", nil, createRequest, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return VolumeCreateResult{}, err
+	}
+
+	var v volume.Volume
+	err = json.NewDecoder(resp.Body).Decode(&v)
+	return VolumeCreateResult{Volume: v}, err
+}
diff --git a/vendor/github.com/moby/moby/client/volume_inspect.go b/vendor/github.com/moby/moby/client/volume_inspect.go
new file mode 100644
index 000000000..cf00236a2
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/volume_inspect.go
@@ -0,0 +1,36 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/moby/moby/api/types/volume"
+)
+
+// VolumeInspectOptions holds options for inspecting a volume.
+type VolumeInspectOptions struct {
+	// Add future optional parameters here
+}
+
+// VolumeInspectResult holds the result from the [Client.VolumeInspect] method.
+type VolumeInspectResult struct {
+	Volume volume.Volume
+	Raw    json.RawMessage
+}
+
+// VolumeInspect returns the information about a specific volume in the docker host.
+func (cli *Client) VolumeInspect(ctx context.Context, volumeID string, options VolumeInspectOptions) (VolumeInspectResult, error) {
+	volumeID, err := trimID("volume", volumeID)
+	if err != nil {
+		return VolumeInspectResult{}, err
+	}
+
+	resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil)
+	if err != nil {
+		return VolumeInspectResult{}, err
+	}
+
+	var out VolumeInspectResult
+	out.Raw, err = decodeWithRaw(resp, &out.Volume)
+	return out, err
+}
diff --git a/vendor/github.com/moby/moby/client/volume_list.go b/vendor/github.com/moby/moby/client/volume_list.go
new file mode 100644
index 000000000..989a0292e
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/volume_list.go
@@ -0,0 +1,46 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"net/url"
+
+	"github.com/moby/moby/api/types/volume"
+)
+
+// VolumeListOptions holds parameters to list volumes.
+type VolumeListOptions struct {
+	Filters Filters
+}
+
+// VolumeListResult holds the result from the [Client.VolumeList] method.
+type VolumeListResult struct {
+	// List of volumes.
+	Items []volume.Volume
+
+	// Warnings that occurred when fetching the list of volumes.
+	Warnings []string
+}
+
+// VolumeList returns the volumes configured in the docker host.
+func (cli *Client) VolumeList(ctx context.Context, options VolumeListOptions) (VolumeListResult, error) {
+	query := url.Values{}
+
+	options.Filters.updateURLValues(query)
+	resp, err := cli.get(ctx, "/volumes", query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return VolumeListResult{}, err
+	}
+
+	var apiResp volume.ListResponse
+	err = json.NewDecoder(resp.Body).Decode(&apiResp)
+	if err != nil {
+		return VolumeListResult{}, err
+	}
+
+	return VolumeListResult{
+		Items:    apiResp.Volumes,
+		Warnings: apiResp.Warnings,
+	}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/volume_prune.go b/vendor/github.com/moby/moby/client/volume_prune.go
new file mode 100644
index 000000000..eec0f482b
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/volume_prune.go
@@ -0,0 +1,55 @@
+package client
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/url"
+
+	cerrdefs "github.com/containerd/errdefs"
+	"github.com/moby/moby/api/types/volume"
+)
+
+// VolumePruneOptions holds parameters to prune volumes.
+type VolumePruneOptions struct {
+	// All controls whether named volumes should also be pruned. By
+	// default, only anonymous volumes are pruned.
+	All bool
+
+	// Filters to apply when pruning.
+	Filters Filters
+}
+
+// VolumePruneResult holds the result from the [Client.VolumePrune] method.
+type VolumePruneResult struct {
+	Report volume.PruneReport
+}
+
+// VolumePrune requests the daemon to delete unused data
+func (cli *Client) VolumePrune(ctx context.Context, options VolumePruneOptions) (VolumePruneResult, error) {
+	if options.All {
+		if _, ok := options.Filters["all"]; ok {
+			return VolumePruneResult{}, cerrdefs.ErrInvalidArgument.WithMessage(`conflicting options: cannot specify both "all" and "all" filter`)
+		}
+		if options.Filters == nil {
+			options.Filters = Filters{}
+		}
+		options.Filters.Add("all", "true")
+	}
+
+	query := url.Values{}
+	options.Filters.updateURLValues(query)
+
+	resp, err := cli.post(ctx, "/volumes/prune", query, nil, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return VolumePruneResult{}, err
+	}
+
+	var report volume.PruneReport
+	if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
+		return VolumePruneResult{}, fmt.Errorf("error retrieving volume prune report: %v", err)
+	}
+
+	return VolumePruneResult{Report: report}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/volume_remove.go b/vendor/github.com/moby/moby/client/volume_remove.go
new file mode 100644
index 000000000..0449e08d4
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/volume_remove.go
@@ -0,0 +1,36 @@
+package client
+
+import (
+	"context"
+	"net/url"
+)
+
+// VolumeRemoveOptions holds options for [Client.VolumeRemove].
+type VolumeRemoveOptions struct {
+	// Force the removal of the volume
+	Force bool
+}
+
+// VolumeRemoveResult holds the result of [Client.VolumeRemove],
+type VolumeRemoveResult struct {
+	// Add future fields here.
+}
+
+// VolumeRemove removes a volume from the docker host.
+func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, options VolumeRemoveOptions) (VolumeRemoveResult, error) {
+	volumeID, err := trimID("volume", volumeID)
+	if err != nil {
+		return VolumeRemoveResult{}, err
+	}
+
+	query := url.Values{}
+	if options.Force {
+		query.Set("force", "1")
+	}
+	resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return VolumeRemoveResult{}, err
+	}
+	return VolumeRemoveResult{}, nil
+}
diff --git a/vendor/github.com/moby/moby/client/volume_update.go b/vendor/github.com/moby/moby/client/volume_update.go
new file mode 100644
index 000000000..5aa2a0aa1
--- /dev/null
+++ b/vendor/github.com/moby/moby/client/volume_update.go
@@ -0,0 +1,40 @@
+package client
+
+import (
+	"context"
+	"net/url"
+
+	"github.com/moby/moby/api/types/swarm"
+	"github.com/moby/moby/api/types/volume"
+)
+
+// VolumeUpdateOptions holds options for [Client.VolumeUpdate].
+type VolumeUpdateOptions struct {
+	Version swarm.Version
+	// Spec is the ClusterVolumeSpec to update the volume to.
+	Spec *volume.ClusterVolumeSpec `json:"Spec,omitempty"`
+}
+
+// VolumeUpdateResult holds the result of [Client.VolumeUpdate],
+type VolumeUpdateResult struct {
+	// Add future fields here.
+}
+
+// VolumeUpdate updates a volume. This only works for Cluster Volumes, and
+// only some fields can be updated.
+func (cli *Client) VolumeUpdate(ctx context.Context, volumeID string, options VolumeUpdateOptions) (VolumeUpdateResult, error) {
+	volumeID, err := trimID("volume", volumeID)
+	if err != nil {
+		return VolumeUpdateResult{}, err
+	}
+
+	query := url.Values{}
+	query.Set("version", options.Version.String())
+
+	resp, err := cli.put(ctx, "/volumes/"+volumeID, query, options, nil)
+	defer ensureReaderClosed(resp)
+	if err != nil {
+		return VolumeUpdateResult{}, err
+	}
+	return VolumeUpdateResult{}, nil
+}
diff --git a/vendor/github.com/moby/patternmatcher/LICENSE b/vendor/github.com/moby/patternmatcher/LICENSE
new file mode 100644
index 000000000..6d8d58fb6
--- /dev/null
+++ b/vendor/github.com/moby/patternmatcher/LICENSE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2013-2018 Docker, 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
+
+       https://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.
diff --git a/vendor/github.com/moby/patternmatcher/NOTICE b/vendor/github.com/moby/patternmatcher/NOTICE
new file mode 100644
index 000000000..e5154640f
--- /dev/null
+++ b/vendor/github.com/moby/patternmatcher/NOTICE
@@ -0,0 +1,16 @@
+Docker
+Copyright 2012-2017 Docker, Inc.
+
+This product includes software developed at Docker, Inc. (https://www.docker.com).
+
+The following is courtesy of our legal counsel:
+
+
+Use and transfer of Docker may be subject to certain restrictions by the
+United States and other governments.
+It is your responsibility to ensure that your use and/or transfer does not
+violate applicable laws.
+
+For more information, please see https://www.bis.doc.gov
+
+See also https://www.apache.org/dev/crypto.html and/or seek legal counsel.
diff --git a/vendor/github.com/moby/patternmatcher/ignorefile/ignorefile.go b/vendor/github.com/moby/patternmatcher/ignorefile/ignorefile.go
new file mode 100644
index 000000000..94ea5a0ef
--- /dev/null
+++ b/vendor/github.com/moby/patternmatcher/ignorefile/ignorefile.go
@@ -0,0 +1,73 @@
+package ignorefile
+
+import (
+	"bufio"
+	"bytes"
+	"io"
+	"path/filepath"
+	"strings"
+)
+
+// ReadAll reads an ignore file from a reader and returns the list of file
+// patterns to ignore, applying the following rules:
+//
+//   - An UTF8 BOM header (if present) is stripped.
+//   - Lines starting with "#" are considered comments and are skipped.
+//
+// For remaining lines:
+//
+//   - Leading and trailing whitespace is removed from each ignore pattern.
+//   - It uses [filepath.Clean] to get the shortest/cleanest path for
+//     ignore patterns.
+//   - Leading forward-slashes ("/") are removed from ignore patterns,
+//     so "/some/path" and "some/path" are considered equivalent.
+func ReadAll(reader io.Reader) ([]string, error) {
+	if reader == nil {
+		return nil, nil
+	}
+
+	var excludes []string
+	currentLine := 0
+	utf8bom := []byte{0xEF, 0xBB, 0xBF}
+
+	scanner := bufio.NewScanner(reader)
+	for scanner.Scan() {
+		scannedBytes := scanner.Bytes()
+		// We trim UTF8 BOM
+		if currentLine == 0 {
+			scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
+		}
+		pattern := string(scannedBytes)
+		currentLine++
+		// Lines starting with # (comments) are ignored before processing
+		if strings.HasPrefix(pattern, "#") {
+			continue
+		}
+		pattern = strings.TrimSpace(pattern)
+		if pattern == "" {
+			continue
+		}
+		// normalize absolute paths to paths relative to the context
+		// (taking care of '!' prefix)
+		invert := pattern[0] == '!'
+		if invert {
+			pattern = strings.TrimSpace(pattern[1:])
+		}
+		if len(pattern) > 0 {
+			pattern = filepath.Clean(pattern)
+			pattern = filepath.ToSlash(pattern)
+			if len(pattern) > 1 && pattern[0] == '/' {
+				pattern = pattern[1:]
+			}
+		}
+		if invert {
+			pattern = "!" + pattern
+		}
+
+		excludes = append(excludes, pattern)
+	}
+	if err := scanner.Err(); err != nil {
+		return nil, err
+	}
+	return excludes, nil
+}
diff --git a/vendor/github.com/moby/patternmatcher/patternmatcher.go b/vendor/github.com/moby/patternmatcher/patternmatcher.go
new file mode 100644
index 000000000..216dea671
--- /dev/null
+++ b/vendor/github.com/moby/patternmatcher/patternmatcher.go
@@ -0,0 +1,477 @@
+package patternmatcher
+
+import (
+	"errors"
+	"os"
+	"path/filepath"
+	"regexp"
+	"strings"
+	"text/scanner"
+	"unicode/utf8"
+)
+
+// escapeBytes is a bitmap used to check whether a character should be escaped when creating the regex.
+var escapeBytes [8]byte
+
+// shouldEscape reports whether a rune should be escaped as part of the regex.
+//
+// This only includes characters that require escaping in regex but are also NOT valid filepath pattern characters.
+// Additionally, '\' is not excluded because there is specific logic to properly handle this, as it's a path separator
+// on Windows.
+//
+// Adapted from regexp::QuoteMeta in go stdlib.
+// See https://cs.opensource.google/go/go/+/refs/tags/go1.17.2:src/regexp/regexp.go;l=703-715;drc=refs%2Ftags%2Fgo1.17.2
+func shouldEscape(b rune) bool {
+	return b < utf8.RuneSelf && escapeBytes[b%8]&(1<<(b/8)) != 0
+}
+
+func init() {
+	for _, b := range []byte(`.+()|{}$`) {
+		escapeBytes[b%8] |= 1 << (b / 8)
+	}
+}
+
+// PatternMatcher allows checking paths against a list of patterns
+type PatternMatcher struct {
+	patterns   []*Pattern
+	exclusions bool
+}
+
+// New creates a new matcher object for specific patterns that can
+// be used later to match against patterns against paths
+func New(patterns []string) (*PatternMatcher, error) {
+	pm := &PatternMatcher{
+		patterns: make([]*Pattern, 0, len(patterns)),
+	}
+	for _, p := range patterns {
+		// Eliminate leading and trailing whitespace.
+		p = strings.TrimSpace(p)
+		if p == "" {
+			continue
+		}
+		p = filepath.Clean(p)
+		newp := &Pattern{}
+		if p[0] == '!' {
+			if len(p) == 1 {
+				return nil, errors.New("illegal exclusion pattern: \"!\"")
+			}
+			newp.exclusion = true
+			p = p[1:]
+			pm.exclusions = true
+		}
+		// Do some syntax checking on the pattern.
+		// filepath's Match() has some really weird rules that are inconsistent
+		// so instead of trying to dup their logic, just call Match() for its
+		// error state and if there is an error in the pattern return it.
+		// If this becomes an issue we can remove this since its really only
+		// needed in the error (syntax) case - which isn't really critical.
+		if _, err := filepath.Match(p, "."); err != nil {
+			return nil, err
+		}
+		newp.cleanedPattern = p
+		newp.dirs = strings.Split(p, string(os.PathSeparator))
+		pm.patterns = append(pm.patterns, newp)
+	}
+	return pm, nil
+}
+
+// Matches returns true if "file" matches any of the patterns
+// and isn't excluded by any of the subsequent patterns.
+//
+// The "file" argument should be a slash-delimited path.
+//
+// Matches is not safe to call concurrently.
+//
+// Deprecated: This implementation is buggy (it only checks a single parent dir
+// against the pattern) and will be removed soon. Use either
+// MatchesOrParentMatches or MatchesUsingParentResults instead.
+func (pm *PatternMatcher) Matches(file string) (bool, error) {
+	matched := false
+	file = filepath.FromSlash(file)
+	parentPath := filepath.Dir(file)
+	parentPathDirs := strings.Split(parentPath, string(os.PathSeparator))
+
+	for _, pattern := range pm.patterns {
+		// Skip evaluation if this is an inclusion and the filename
+		// already matched the pattern, or it's an exclusion and it has
+		// not matched the pattern yet.
+		if pattern.exclusion != matched {
+			continue
+		}
+
+		match, err := pattern.match(file)
+		if err != nil {
+			return false, err
+		}
+
+		if !match && parentPath != "." {
+			// Check to see if the pattern matches one of our parent dirs.
+			if len(pattern.dirs) <= len(parentPathDirs) {
+				match, _ = pattern.match(strings.Join(parentPathDirs[:len(pattern.dirs)], string(os.PathSeparator)))
+			}
+		}
+
+		if match {
+			matched = !pattern.exclusion
+		}
+	}
+
+	return matched, nil
+}
+
+// MatchesOrParentMatches returns true if "file" matches any of the patterns
+// and isn't excluded by any of the subsequent patterns.
+//
+// The "file" argument should be a slash-delimited path.
+//
+// Matches is not safe to call concurrently.
+func (pm *PatternMatcher) MatchesOrParentMatches(file string) (bool, error) {
+	matched := false
+	file = filepath.FromSlash(file)
+	parentPath := filepath.Dir(file)
+	parentPathDirs := strings.Split(parentPath, string(os.PathSeparator))
+
+	for _, pattern := range pm.patterns {
+		// Skip evaluation if this is an inclusion and the filename
+		// already matched the pattern, or it's an exclusion and it has
+		// not matched the pattern yet.
+		if pattern.exclusion != matched {
+			continue
+		}
+
+		match, err := pattern.match(file)
+		if err != nil {
+			return false, err
+		}
+
+		if !match && parentPath != "." {
+			// Check to see if the pattern matches one of our parent dirs.
+			for i := range parentPathDirs {
+				match, _ = pattern.match(strings.Join(parentPathDirs[:i+1], string(os.PathSeparator)))
+				if match {
+					break
+				}
+			}
+		}
+
+		if match {
+			matched = !pattern.exclusion
+		}
+	}
+
+	return matched, nil
+}
+
+// MatchesUsingParentResult returns true if "file" matches any of the patterns
+// and isn't excluded by any of the subsequent patterns. The functionality is
+// the same as Matches, but as an optimization, the caller keeps track of
+// whether the parent directory matched.
+//
+// The "file" argument should be a slash-delimited path.
+//
+// MatchesUsingParentResult is not safe to call concurrently.
+//
+// Deprecated: this function does behave correctly in some cases (see
+// https://github.com/docker/buildx/issues/850).
+//
+// Use MatchesUsingParentResults instead.
+func (pm *PatternMatcher) MatchesUsingParentResult(file string, parentMatched bool) (bool, error) {
+	matched := parentMatched
+	file = filepath.FromSlash(file)
+
+	for _, pattern := range pm.patterns {
+		// Skip evaluation if this is an inclusion and the filename
+		// already matched the pattern, or it's an exclusion and it has
+		// not matched the pattern yet.
+		if pattern.exclusion != matched {
+			continue
+		}
+
+		match, err := pattern.match(file)
+		if err != nil {
+			return false, err
+		}
+
+		if match {
+			matched = !pattern.exclusion
+		}
+	}
+	return matched, nil
+}
+
+// MatchInfo tracks information about parent dir matches while traversing a
+// filesystem.
+type MatchInfo struct {
+	parentMatched []bool
+}
+
+// MatchesUsingParentResults returns true if "file" matches any of the patterns
+// and isn't excluded by any of the subsequent patterns. The functionality is
+// the same as Matches, but as an optimization, the caller passes in
+// intermediate results from matching the parent directory.
+//
+// The "file" argument should be a slash-delimited path.
+//
+// MatchesUsingParentResults is not safe to call concurrently.
+func (pm *PatternMatcher) MatchesUsingParentResults(file string, parentMatchInfo MatchInfo) (bool, MatchInfo, error) {
+	parentMatched := parentMatchInfo.parentMatched
+	if len(parentMatched) != 0 && len(parentMatched) != len(pm.patterns) {
+		return false, MatchInfo{}, errors.New("wrong number of values in parentMatched")
+	}
+
+	file = filepath.FromSlash(file)
+	matched := false
+
+	matchInfo := MatchInfo{
+		parentMatched: make([]bool, len(pm.patterns)),
+	}
+	for i, pattern := range pm.patterns {
+		match := false
+		// If the parent matched this pattern, we don't need to recheck.
+		if len(parentMatched) != 0 {
+			match = parentMatched[i]
+		}
+
+		if !match {
+			// Skip evaluation if this is an inclusion and the filename
+			// already matched the pattern, or it's an exclusion and it has
+			// not matched the pattern yet.
+			if pattern.exclusion != matched {
+				continue
+			}
+
+			var err error
+			match, err = pattern.match(file)
+			if err != nil {
+				return false, matchInfo, err
+			}
+
+			// If the zero value of MatchInfo was passed in, we don't have
+			// any information about the parent dir's match results, and we
+			// apply the same logic as MatchesOrParentMatches.
+			if !match && len(parentMatched) == 0 {
+				if parentPath := filepath.Dir(file); parentPath != "." {
+					parentPathDirs := strings.Split(parentPath, string(os.PathSeparator))
+					// Check to see if the pattern matches one of our parent dirs.
+					for i := range parentPathDirs {
+						match, _ = pattern.match(strings.Join(parentPathDirs[:i+1], string(os.PathSeparator)))
+						if match {
+							break
+						}
+					}
+				}
+			}
+		}
+		matchInfo.parentMatched[i] = match
+
+		if match {
+			matched = !pattern.exclusion
+		}
+	}
+	return matched, matchInfo, nil
+}
+
+// Exclusions returns true if any of the patterns define exclusions
+func (pm *PatternMatcher) Exclusions() bool {
+	return pm.exclusions
+}
+
+// Patterns returns array of active patterns
+func (pm *PatternMatcher) Patterns() []*Pattern {
+	return pm.patterns
+}
+
+// Pattern defines a single regexp used to filter file paths.
+type Pattern struct {
+	matchType      matchType
+	cleanedPattern string
+	dirs           []string
+	regexp         *regexp.Regexp
+	exclusion      bool
+}
+
+type matchType int
+
+const (
+	unknownMatch matchType = iota
+	exactMatch
+	prefixMatch
+	suffixMatch
+	regexpMatch
+)
+
+func (p *Pattern) String() string {
+	return p.cleanedPattern
+}
+
+// Exclusion returns true if this pattern defines exclusion
+func (p *Pattern) Exclusion() bool {
+	return p.exclusion
+}
+
+func (p *Pattern) match(path string) (bool, error) {
+	if p.matchType == unknownMatch {
+		if err := p.compile(string(os.PathSeparator)); err != nil {
+			return false, filepath.ErrBadPattern
+		}
+	}
+
+	switch p.matchType {
+	case exactMatch:
+		return path == p.cleanedPattern, nil
+	case prefixMatch:
+		// strip trailing **
+		return strings.HasPrefix(path, p.cleanedPattern[:len(p.cleanedPattern)-2]), nil
+	case suffixMatch:
+		// strip leading **
+		suffix := p.cleanedPattern[2:]
+		if strings.HasSuffix(path, suffix) {
+			return true, nil
+		}
+		// **/foo matches "foo"
+		return suffix[0] == os.PathSeparator && path == suffix[1:], nil
+	case regexpMatch:
+		if p.regexp == nil {
+			return false, filepath.ErrBadPattern
+		}
+		return p.regexp.MatchString(path), nil
+	case unknownMatch:
+		return false, filepath.ErrBadPattern
+	default:
+		return false, nil
+	}
+}
+
+func (p *Pattern) compile(sl string) error {
+	regStr := "^"
+	detectedType := exactMatch // assume exact match
+	pattern := p.cleanedPattern
+	// Go through the pattern and convert it to a regexp.
+	// We use a scanner so we can support utf-8 chars.
+	var scan scanner.Scanner
+	scan.Init(strings.NewReader(pattern))
+
+	escSL := sl
+	if sl == `\` {
+		escSL += `\`
+	}
+
+	for i := 0; scan.Peek() != scanner.EOF; i++ {
+		ch := scan.Next()
+
+		if ch == '*' {
+			if scan.Peek() == '*' {
+				// is some flavor of "**"
+				scan.Next()
+
+				// Treat **/ as ** so eat the "/"
+				if string(scan.Peek()) == sl {
+					scan.Next()
+				}
+
+				if scan.Peek() == scanner.EOF {
+					// is "**EOF" - to align with .gitignore just accept all
+					if detectedType == exactMatch {
+						detectedType = prefixMatch
+					} else {
+						regStr += ".*"
+						detectedType = regexpMatch
+					}
+				} else {
+					// is "**"
+					// Note that this allows for any # of /'s (even 0) because
+					// the .* will eat everything, even /'s
+					regStr += "(.*" + escSL + ")?"
+					detectedType = regexpMatch
+				}
+
+				if i == 0 {
+					detectedType = suffixMatch
+				}
+			} else {
+				// is "*" so map it to anything but "/"
+				regStr += "[^" + escSL + "]*"
+				detectedType = regexpMatch
+			}
+		} else if ch == '?' {
+			// "?" is any char except "/"
+			regStr += "[^" + escSL + "]"
+			detectedType = regexpMatch
+		} else if shouldEscape(ch) {
+			// Escape some regexp special chars that have no meaning
+			// in golang's filepath.Match
+			regStr += `\` + string(ch)
+		} else if ch == '\\' {
+			// escape next char. Note that a trailing \ in the pattern
+			// will be left alone (but need to escape it)
+			if sl == `\` {
+				// On windows map "\" to "\\", meaning an escaped backslash,
+				// and then just continue because filepath.Match on
+				// Windows doesn't allow escaping at all
+				regStr += escSL
+				continue
+			}
+			if scan.Peek() != scanner.EOF {
+				regStr += `\` + string(scan.Next())
+				detectedType = regexpMatch
+			} else {
+				regStr += `\`
+			}
+		} else if ch == '[' || ch == ']' {
+			regStr += string(ch)
+			detectedType = regexpMatch
+		} else {
+			regStr += string(ch)
+		}
+	}
+
+	if detectedType == regexpMatch {
+		regStr += "$"
+
+		re, err := regexp.Compile(regStr)
+		if err != nil {
+			return err
+		}
+
+		p.regexp = re
+	}
+	p.matchType = detectedType
+	return nil
+}
+
+// Matches returns true if file matches any of the patterns
+// and isn't excluded by any of the subsequent patterns.
+//
+// This implementation is buggy (it only checks a single parent dir against the
+// pattern) and will be removed soon. Use MatchesOrParentMatches instead.
+func Matches(file string, patterns []string) (bool, error) {
+	pm, err := New(patterns)
+	if err != nil {
+		return false, err
+	}
+	file = filepath.Clean(file)
+
+	if file == "." {
+		// Don't let them exclude everything, kind of silly.
+		return false, nil
+	}
+
+	return pm.Matches(file)
+}
+
+// MatchesOrParentMatches returns true if file matches any of the patterns
+// and isn't excluded by any of the subsequent patterns.
+func MatchesOrParentMatches(file string, patterns []string) (bool, error) {
+	pm, err := New(patterns)
+	if err != nil {
+		return false, err
+	}
+	file = filepath.Clean(file)
+
+	if file == "." {
+		// Don't let them exclude everything, kind of silly.
+		return false, nil
+	}
+
+	return pm.MatchesOrParentMatches(file)
+}
diff --git a/vendor/github.com/moby/sys/sequential/LICENSE b/vendor/github.com/moby/sys/sequential/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/moby/sys/sequential/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/moby/sys/sequential/doc.go b/vendor/github.com/moby/sys/sequential/doc.go
new file mode 100644
index 000000000..af2817504
--- /dev/null
+++ b/vendor/github.com/moby/sys/sequential/doc.go
@@ -0,0 +1,15 @@
+// Package sequential provides a set of functions for managing sequential
+// files on Windows.
+//
+// The origin of these functions are the golang OS and windows packages,
+// slightly modified to only cope with files, not directories due to the
+// specific use case.
+//
+// The alteration is to allow a file on Windows to be opened with
+// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating
+// the standby list, particularly when accessing large files such as layer.tar.
+//
+// For non-Windows platforms, the package provides wrappers for the equivalents
+// in the os packages. They are passthrough on Unix platforms, and only relevant
+// on Windows.
+package sequential
diff --git a/vendor/github.com/moby/sys/sequential/sequential_unix.go b/vendor/github.com/moby/sys/sequential/sequential_unix.go
new file mode 100644
index 000000000..278cdfb07
--- /dev/null
+++ b/vendor/github.com/moby/sys/sequential/sequential_unix.go
@@ -0,0 +1,26 @@
+//go:build !windows
+// +build !windows
+
+package sequential
+
+import "os"
+
+// Create is an alias for [os.Create] on non-Windows platforms.
+func Create(name string) (*os.File, error) {
+	return os.Create(name)
+}
+
+// Open is an alias for [os.Open] on non-Windows platforms.
+func Open(name string) (*os.File, error) {
+	return os.Open(name)
+}
+
+// OpenFile is an alias for [os.OpenFile] on non-Windows platforms.
+func OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
+	return os.OpenFile(name, flag, perm)
+}
+
+// CreateTemp is an alias for [os.CreateTemp] on non-Windows platforms.
+func CreateTemp(dir, prefix string) (f *os.File, err error) {
+	return os.CreateTemp(dir, prefix)
+}
diff --git a/vendor/github.com/moby/sys/sequential/sequential_windows.go b/vendor/github.com/moby/sys/sequential/sequential_windows.go
new file mode 100644
index 000000000..3500ecc68
--- /dev/null
+++ b/vendor/github.com/moby/sys/sequential/sequential_windows.go
@@ -0,0 +1,162 @@
+package sequential
+
+import (
+	"os"
+	"path/filepath"
+	"strconv"
+	"sync"
+	"time"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+)
+
+// Create is a copy of [os.Create], modified to use sequential file access.
+//
+// It uses [windows.FILE_FLAG_SEQUENTIAL_SCAN] rather than [windows.FILE_ATTRIBUTE_NORMAL]
+// as implemented in golang. Refer to the [Win32 API documentation] for details
+// on sequential file access.
+//
+// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN
+func Create(name string) (*os.File, error) {
+	return openFileSequential(name, windows.O_RDWR|windows.O_CREAT|windows.O_TRUNC)
+}
+
+// Open is a copy of [os.Open], modified to use sequential file access.
+//
+// It uses [windows.FILE_FLAG_SEQUENTIAL_SCAN] rather than [windows.FILE_ATTRIBUTE_NORMAL]
+// as implemented in golang. Refer to the [Win32 API documentation] for details
+// on sequential file access.
+//
+// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN
+func Open(name string) (*os.File, error) {
+	return openFileSequential(name, windows.O_RDONLY)
+}
+
+// OpenFile is a copy of [os.OpenFile], modified to use sequential file access.
+//
+// It uses [windows.FILE_FLAG_SEQUENTIAL_SCAN] rather than [windows.FILE_ATTRIBUTE_NORMAL]
+// as implemented in golang. Refer to the [Win32 API documentation] for details
+// on sequential file access.
+//
+// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN
+func OpenFile(name string, flag int, _ os.FileMode) (*os.File, error) {
+	return openFileSequential(name, flag)
+}
+
+func openFileSequential(name string, flag int) (file *os.File, err error) {
+	if name == "" {
+		return nil, &os.PathError{Op: "open", Path: name, Err: windows.ERROR_FILE_NOT_FOUND}
+	}
+	r, e := openSequential(name, flag|windows.O_CLOEXEC)
+	if e != nil {
+		return nil, &os.PathError{Op: "open", Path: name, Err: e}
+	}
+	return os.NewFile(uintptr(r), name), nil
+}
+
+func makeInheritSa() *windows.SecurityAttributes {
+	var sa windows.SecurityAttributes
+	sa.Length = uint32(unsafe.Sizeof(sa))
+	sa.InheritHandle = 1
+	return &sa
+}
+
+func openSequential(path string, mode int) (fd windows.Handle, err error) {
+	if len(path) == 0 {
+		return windows.InvalidHandle, windows.ERROR_FILE_NOT_FOUND
+	}
+	pathp, err := windows.UTF16PtrFromString(path)
+	if err != nil {
+		return windows.InvalidHandle, err
+	}
+	var access uint32
+	switch mode & (windows.O_RDONLY | windows.O_WRONLY | windows.O_RDWR) {
+	case windows.O_RDONLY:
+		access = windows.GENERIC_READ
+	case windows.O_WRONLY:
+		access = windows.GENERIC_WRITE
+	case windows.O_RDWR:
+		access = windows.GENERIC_READ | windows.GENERIC_WRITE
+	}
+	if mode&windows.O_CREAT != 0 {
+		access |= windows.GENERIC_WRITE
+	}
+	if mode&windows.O_APPEND != 0 {
+		access &^= windows.GENERIC_WRITE
+		access |= windows.FILE_APPEND_DATA
+	}
+	sharemode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE)
+	var sa *windows.SecurityAttributes
+	if mode&windows.O_CLOEXEC == 0 {
+		sa = makeInheritSa()
+	}
+	var createmode uint32
+	switch {
+	case mode&(windows.O_CREAT|windows.O_EXCL) == (windows.O_CREAT | windows.O_EXCL):
+		createmode = windows.CREATE_NEW
+	case mode&(windows.O_CREAT|windows.O_TRUNC) == (windows.O_CREAT | windows.O_TRUNC):
+		createmode = windows.CREATE_ALWAYS
+	case mode&windows.O_CREAT == windows.O_CREAT:
+		createmode = windows.OPEN_ALWAYS
+	case mode&windows.O_TRUNC == windows.O_TRUNC:
+		createmode = windows.TRUNCATE_EXISTING
+	default:
+		createmode = windows.OPEN_EXISTING
+	}
+	// Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang.
+	// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN
+	h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, windows.FILE_FLAG_SEQUENTIAL_SCAN, 0)
+	return h, e
+}
+
+// Helpers for CreateTemp
+var (
+	rand   uint32
+	randmu sync.Mutex
+)
+
+func reseed() uint32 {
+	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
+}
+
+func nextSuffix() string {
+	randmu.Lock()
+	r := rand
+	if r == 0 {
+		r = reseed()
+	}
+	r = r*1664525 + 1013904223 // constants from Numerical Recipes
+	rand = r
+	randmu.Unlock()
+	return strconv.Itoa(int(1e9 + r%1e9))[1:]
+}
+
+// CreateTemp is a copy of [os.CreateTemp], modified to use sequential file access.
+//
+// It uses [windows.FILE_FLAG_SEQUENTIAL_SCAN] rather than [windows.FILE_ATTRIBUTE_NORMAL]
+// as implemented in golang. Refer to the [Win32 API documentation] for details
+// on sequential file access.
+//
+// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN
+func CreateTemp(dir, prefix string) (f *os.File, err error) {
+	if dir == "" {
+		dir = os.TempDir()
+	}
+
+	nconflict := 0
+	for i := 0; i < 10000; i++ {
+		name := filepath.Join(dir, prefix+nextSuffix())
+		f, err = openFileSequential(name, windows.O_RDWR|windows.O_CREAT|windows.O_EXCL)
+		if os.IsExist(err) {
+			if nconflict++; nconflict > 10 {
+				randmu.Lock()
+				rand = reseed()
+				randmu.Unlock()
+			}
+			continue
+		}
+		break
+	}
+	return
+}
diff --git a/vendor/github.com/moby/sys/user/LICENSE b/vendor/github.com/moby/sys/user/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/moby/sys/user/idtools.go b/vendor/github.com/moby/sys/user/idtools.go
new file mode 100644
index 000000000..595b7a927
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/idtools.go
@@ -0,0 +1,141 @@
+package user
+
+import (
+	"fmt"
+	"os"
+)
+
+// MkdirOpt is a type for options to pass to Mkdir calls
+type MkdirOpt func(*mkdirOptions)
+
+type mkdirOptions struct {
+	onlyNew bool
+}
+
+// WithOnlyNew is an option for MkdirAllAndChown that will only change ownership and permissions
+// on newly created directories.  If the directory already exists, it will not be modified
+func WithOnlyNew(o *mkdirOptions) {
+	o.onlyNew = true
+}
+
+// MkdirAllAndChown creates a directory (include any along the path) and then modifies
+// ownership to the requested uid/gid.  By default, if the directory already exists, this
+// function will still change ownership and permissions. If WithOnlyNew is passed as an
+// option, then only the newly created directories will have ownership and permissions changed.
+func MkdirAllAndChown(path string, mode os.FileMode, uid, gid int, opts ...MkdirOpt) error {
+	var options mkdirOptions
+	for _, opt := range opts {
+		opt(&options)
+	}
+
+	return mkdirAs(path, mode, uid, gid, true, options.onlyNew)
+}
+
+// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
+// By default, if the directory already exists, this function still changes ownership and permissions.
+// If WithOnlyNew is passed as an option, then only the newly created directory will have ownership
+// and permissions changed.
+// Note that unlike os.Mkdir(), this function does not return IsExist error
+// in case path already exists.
+func MkdirAndChown(path string, mode os.FileMode, uid, gid int, opts ...MkdirOpt) error {
+	var options mkdirOptions
+	for _, opt := range opts {
+		opt(&options)
+	}
+	return mkdirAs(path, mode, uid, gid, false, options.onlyNew)
+}
+
+// getRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
+// If the maps are empty, then the root uid/gid will default to "real" 0/0
+func getRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) {
+	uid, err := toHost(0, uidMap)
+	if err != nil {
+		return -1, -1, err
+	}
+	gid, err := toHost(0, gidMap)
+	if err != nil {
+		return -1, -1, err
+	}
+	return uid, gid, nil
+}
+
+// toContainer takes an id mapping, and uses it to translate a
+// host ID to the remapped ID. If no map is provided, then the translation
+// assumes a 1-to-1 mapping and returns the passed in id
+func toContainer(hostID int, idMap []IDMap) (int, error) {
+	if idMap == nil {
+		return hostID, nil
+	}
+	for _, m := range idMap {
+		if (int64(hostID) >= m.ParentID) && (int64(hostID) <= (m.ParentID + m.Count - 1)) {
+			contID := int(m.ID + (int64(hostID) - m.ParentID))
+			return contID, nil
+		}
+	}
+	return -1, fmt.Errorf("host ID %d cannot be mapped to a container ID", hostID)
+}
+
+// toHost takes an id mapping and a remapped ID, and translates the
+// ID to the mapped host ID. If no map is provided, then the translation
+// assumes a 1-to-1 mapping and returns the passed in id #
+func toHost(contID int, idMap []IDMap) (int, error) {
+	if idMap == nil {
+		return contID, nil
+	}
+	for _, m := range idMap {
+		if (int64(contID) >= m.ID) && (int64(contID) <= (m.ID + m.Count - 1)) {
+			hostID := int(m.ParentID + (int64(contID) - m.ID))
+			return hostID, nil
+		}
+	}
+	return -1, fmt.Errorf("container ID %d cannot be mapped to a host ID", contID)
+}
+
+// IdentityMapping contains a mappings of UIDs and GIDs.
+// The zero value represents an empty mapping.
+type IdentityMapping struct {
+	UIDMaps []IDMap `json:"UIDMaps"`
+	GIDMaps []IDMap `json:"GIDMaps"`
+}
+
+// RootPair returns a uid and gid pair for the root user. The error is ignored
+// because a root user always exists, and the defaults are correct when the uid
+// and gid maps are empty.
+func (i IdentityMapping) RootPair() (int, int) {
+	uid, gid, _ := getRootUIDGID(i.UIDMaps, i.GIDMaps)
+	return uid, gid
+}
+
+// ToHost returns the host UID and GID for the container uid, gid.
+// Remapping is only performed if the ids aren't already the remapped root ids
+func (i IdentityMapping) ToHost(uid, gid int) (int, int, error) {
+	var err error
+	ruid, rgid := i.RootPair()
+
+	if uid != ruid {
+		ruid, err = toHost(uid, i.UIDMaps)
+		if err != nil {
+			return ruid, rgid, err
+		}
+	}
+
+	if gid != rgid {
+		rgid, err = toHost(gid, i.GIDMaps)
+	}
+	return ruid, rgid, err
+}
+
+// ToContainer returns the container UID and GID for the host uid and gid
+func (i IdentityMapping) ToContainer(uid, gid int) (int, int, error) {
+	ruid, err := toContainer(uid, i.UIDMaps)
+	if err != nil {
+		return -1, -1, err
+	}
+	rgid, err := toContainer(gid, i.GIDMaps)
+	return ruid, rgid, err
+}
+
+// Empty returns true if there are no id mappings
+func (i IdentityMapping) Empty() bool {
+	return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0
+}
diff --git a/vendor/github.com/moby/sys/user/idtools_unix.go b/vendor/github.com/moby/sys/user/idtools_unix.go
new file mode 100644
index 000000000..4e39d2446
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/idtools_unix.go
@@ -0,0 +1,143 @@
+//go:build !windows
+
+package user
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strconv"
+	"syscall"
+)
+
+func mkdirAs(path string, mode os.FileMode, uid, gid int, mkAll, onlyNew bool) error {
+	path, err := filepath.Abs(path)
+	if err != nil {
+		return err
+	}
+
+	stat, err := os.Stat(path)
+	if err == nil {
+		if !stat.IsDir() {
+			return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
+		}
+		if onlyNew {
+			return nil
+		}
+
+		// short-circuit -- we were called with an existing directory and chown was requested
+		return setPermissions(path, mode, uid, gid, stat)
+	}
+
+	// make an array containing the original path asked for, plus (for mkAll == true)
+	// all path components leading up to the complete path that don't exist before we MkdirAll
+	// so that we can chown all of them properly at the end.  If onlyNew is true, we won't
+	// chown the full directory path if it exists
+	var paths []string
+	if os.IsNotExist(err) {
+		paths = append(paths, path)
+	}
+
+	if mkAll {
+		// walk back to "/" looking for directories which do not exist
+		// and add them to the paths array for chown after creation
+		dirPath := path
+		for {
+			dirPath = filepath.Dir(dirPath)
+			if dirPath == "/" {
+				break
+			}
+			if _, err = os.Stat(dirPath); os.IsNotExist(err) {
+				paths = append(paths, dirPath)
+			}
+		}
+		if err = os.MkdirAll(path, mode); err != nil {
+			return err
+		}
+	} else if err = os.Mkdir(path, mode); err != nil {
+		return err
+	}
+	// even if it existed, we will chown the requested path + any subpaths that
+	// didn't exist when we called MkdirAll
+	for _, pathComponent := range paths {
+		if err = setPermissions(pathComponent, mode, uid, gid, nil); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// setPermissions performs a chown/chmod only if the uid/gid don't match what's requested
+// Normally a Chown is a no-op if uid/gid match, but in some cases this can still cause an error, e.g. if the
+// dir is on an NFS share, so don't call chown unless we absolutely must.
+// Likewise for setting permissions.
+func setPermissions(p string, mode os.FileMode, uid, gid int, stat os.FileInfo) error {
+	if stat == nil {
+		var err error
+		stat, err = os.Stat(p)
+		if err != nil {
+			return err
+		}
+	}
+	if stat.Mode().Perm() != mode.Perm() {
+		if err := os.Chmod(p, mode.Perm()); err != nil {
+			return err
+		}
+	}
+	ssi := stat.Sys().(*syscall.Stat_t)
+	if ssi.Uid == uint32(uid) && ssi.Gid == uint32(gid) {
+		return nil
+	}
+	return os.Chown(p, uid, gid)
+}
+
+// LoadIdentityMapping takes a requested username and
+// using the data from /etc/sub{uid,gid} ranges, creates the
+// proper uid and gid remapping ranges for that user/group pair
+func LoadIdentityMapping(name string) (IdentityMapping, error) {
+	// TODO: Consider adding support for calling out to "getent"
+	usr, err := LookupUser(name)
+	if err != nil {
+		return IdentityMapping{}, fmt.Errorf("could not get user for username %s: %w", name, err)
+	}
+
+	subuidRanges, err := lookupSubRangesFile("/etc/subuid", usr)
+	if err != nil {
+		return IdentityMapping{}, err
+	}
+	subgidRanges, err := lookupSubRangesFile("/etc/subgid", usr)
+	if err != nil {
+		return IdentityMapping{}, err
+	}
+
+	return IdentityMapping{
+		UIDMaps: subuidRanges,
+		GIDMaps: subgidRanges,
+	}, nil
+}
+
+func lookupSubRangesFile(path string, usr User) ([]IDMap, error) {
+	uidstr := strconv.Itoa(usr.Uid)
+	rangeList, err := ParseSubIDFileFilter(path, func(sid SubID) bool {
+		return sid.Name == usr.Name || sid.Name == uidstr
+	})
+	if err != nil {
+		return nil, err
+	}
+	if len(rangeList) == 0 {
+		return nil, fmt.Errorf("no subuid ranges found for user %q", usr.Name)
+	}
+
+	idMap := []IDMap{}
+
+	var containerID int64
+	for _, idrange := range rangeList {
+		idMap = append(idMap, IDMap{
+			ID:       containerID,
+			ParentID: idrange.SubID,
+			Count:    idrange.Count,
+		})
+		containerID = containerID + idrange.Count
+	}
+	return idMap, nil
+}
diff --git a/vendor/github.com/moby/sys/user/idtools_windows.go b/vendor/github.com/moby/sys/user/idtools_windows.go
new file mode 100644
index 000000000..9de730caf
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/idtools_windows.go
@@ -0,0 +1,13 @@
+package user
+
+import (
+	"os"
+)
+
+// This is currently a wrapper around [os.MkdirAll] since currently
+// permissions aren't set through this path, the identity isn't utilized.
+// Ownership is handled elsewhere, but in the future could be support here
+// too.
+func mkdirAs(path string, _ os.FileMode, _, _ int, _, _ bool) error {
+	return os.MkdirAll(path, 0)
+}
diff --git a/vendor/github.com/moby/sys/user/lookup_unix.go b/vendor/github.com/moby/sys/user/lookup_unix.go
new file mode 100644
index 000000000..f95c1409f
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/lookup_unix.go
@@ -0,0 +1,157 @@
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package user
+
+import (
+	"io"
+	"os"
+	"strconv"
+
+	"golang.org/x/sys/unix"
+)
+
+// Unix-specific path to the passwd and group formatted files.
+const (
+	unixPasswdPath = "/etc/passwd"
+	unixGroupPath  = "/etc/group"
+)
+
+// LookupUser looks up a user by their username in /etc/passwd. If the user
+// cannot be found (or there is no /etc/passwd file on the filesystem), then
+// LookupUser returns an error.
+func LookupUser(username string) (User, error) {
+	return lookupUserFunc(func(u User) bool {
+		return u.Name == username
+	})
+}
+
+// LookupUid looks up a user by their user id in /etc/passwd. If the user cannot
+// be found (or there is no /etc/passwd file on the filesystem), then LookupId
+// returns an error.
+func LookupUid(uid int) (User, error) {
+	return lookupUserFunc(func(u User) bool {
+		return u.Uid == uid
+	})
+}
+
+func lookupUserFunc(filter func(u User) bool) (User, error) {
+	// Get operating system-specific passwd reader-closer.
+	passwd, err := GetPasswd()
+	if err != nil {
+		return User{}, err
+	}
+	defer passwd.Close()
+
+	// Get the users.
+	users, err := ParsePasswdFilter(passwd, filter)
+	if err != nil {
+		return User{}, err
+	}
+
+	// No user entries found.
+	if len(users) == 0 {
+		return User{}, ErrNoPasswdEntries
+	}
+
+	// Assume the first entry is the "correct" one.
+	return users[0], nil
+}
+
+// LookupGroup looks up a group by its name in /etc/group. If the group cannot
+// be found (or there is no /etc/group file on the filesystem), then LookupGroup
+// returns an error.
+func LookupGroup(groupname string) (Group, error) {
+	return lookupGroupFunc(func(g Group) bool {
+		return g.Name == groupname
+	})
+}
+
+// LookupGid looks up a group by its group id in /etc/group. If the group cannot
+// be found (or there is no /etc/group file on the filesystem), then LookupGid
+// returns an error.
+func LookupGid(gid int) (Group, error) {
+	return lookupGroupFunc(func(g Group) bool {
+		return g.Gid == gid
+	})
+}
+
+func lookupGroupFunc(filter func(g Group) bool) (Group, error) {
+	// Get operating system-specific group reader-closer.
+	group, err := GetGroup()
+	if err != nil {
+		return Group{}, err
+	}
+	defer group.Close()
+
+	// Get the users.
+	groups, err := ParseGroupFilter(group, filter)
+	if err != nil {
+		return Group{}, err
+	}
+
+	// No user entries found.
+	if len(groups) == 0 {
+		return Group{}, ErrNoGroupEntries
+	}
+
+	// Assume the first entry is the "correct" one.
+	return groups[0], nil
+}
+
+func GetPasswdPath() (string, error) {
+	return unixPasswdPath, nil
+}
+
+func GetPasswd() (io.ReadCloser, error) {
+	return os.Open(unixPasswdPath)
+}
+
+func GetGroupPath() (string, error) {
+	return unixGroupPath, nil
+}
+
+func GetGroup() (io.ReadCloser, error) {
+	return os.Open(unixGroupPath)
+}
+
+// CurrentUser looks up the current user by their user id in /etc/passwd. If the
+// user cannot be found (or there is no /etc/passwd file on the filesystem),
+// then CurrentUser returns an error.
+func CurrentUser() (User, error) {
+	return LookupUid(unix.Getuid())
+}
+
+// CurrentGroup looks up the current user's group by their primary group id's
+// entry in /etc/passwd. If the group cannot be found (or there is no
+// /etc/group file on the filesystem), then CurrentGroup returns an error.
+func CurrentGroup() (Group, error) {
+	return LookupGid(unix.Getgid())
+}
+
+func currentUserSubIDs(fileName string) ([]SubID, error) {
+	u, err := CurrentUser()
+	if err != nil {
+		return nil, err
+	}
+	filter := func(entry SubID) bool {
+		return entry.Name == u.Name || entry.Name == strconv.Itoa(u.Uid)
+	}
+	return ParseSubIDFileFilter(fileName, filter)
+}
+
+func CurrentUserSubUIDs() ([]SubID, error) {
+	return currentUserSubIDs("/etc/subuid")
+}
+
+func CurrentUserSubGIDs() ([]SubID, error) {
+	return currentUserSubIDs("/etc/subgid")
+}
+
+func CurrentProcessUIDMap() ([]IDMap, error) {
+	return ParseIDMapFile("/proc/self/uid_map")
+}
+
+func CurrentProcessGIDMap() ([]IDMap, error) {
+	return ParseIDMapFile("/proc/self/gid_map")
+}
diff --git a/vendor/github.com/moby/sys/user/user.go b/vendor/github.com/moby/sys/user/user.go
new file mode 100644
index 000000000..198c49367
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/user.go
@@ -0,0 +1,604 @@
+package user
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"strconv"
+	"strings"
+)
+
+const (
+	minID = 0
+	maxID = 1<<31 - 1 // for 32-bit systems compatibility
+)
+
+var (
+	// ErrNoPasswdEntries is returned if no matching entries were found in /etc/group.
+	ErrNoPasswdEntries = errors.New("no matching entries in passwd file")
+	// ErrNoGroupEntries is returned if no matching entries were found in /etc/passwd.
+	ErrNoGroupEntries = errors.New("no matching entries in group file")
+	// ErrRange is returned if a UID or GID is outside of the valid range.
+	ErrRange = fmt.Errorf("uids and gids must be in range %d-%d", minID, maxID)
+)
+
+type User struct {
+	Name  string
+	Pass  string
+	Uid   int
+	Gid   int
+	Gecos string
+	Home  string
+	Shell string
+}
+
+type Group struct {
+	Name string
+	Pass string
+	Gid  int
+	List []string
+}
+
+// SubID represents an entry in /etc/sub{u,g}id
+type SubID struct {
+	Name  string
+	SubID int64
+	Count int64
+}
+
+// IDMap represents an entry in /proc/PID/{u,g}id_map
+type IDMap struct {
+	ID       int64
+	ParentID int64
+	Count    int64
+}
+
+func parseLine(line []byte, v ...interface{}) {
+	parseParts(bytes.Split(line, []byte(":")), v...)
+}
+
+func parseParts(parts [][]byte, v ...interface{}) {
+	if len(parts) == 0 {
+		return
+	}
+
+	for i, p := range parts {
+		// Ignore cases where we don't have enough fields to populate the arguments.
+		// Some configuration files like to misbehave.
+		if len(v) <= i {
+			break
+		}
+
+		// Use the type of the argument to figure out how to parse it, scanf() style.
+		// This is legit.
+		switch e := v[i].(type) {
+		case *string:
+			*e = string(p)
+		case *int:
+			// "numbers", with conversion errors ignored because of some misbehaving configuration files.
+			*e, _ = strconv.Atoi(string(p))
+		case *int64:
+			*e, _ = strconv.ParseInt(string(p), 10, 64)
+		case *[]string:
+			// Comma-separated lists.
+			if len(p) != 0 {
+				*e = strings.Split(string(p), ",")
+			} else {
+				*e = []string{}
+			}
+		default:
+			// Someone goof'd when writing code using this function. Scream so they can hear us.
+			panic(fmt.Sprintf("parseLine only accepts {*string, *int, *int64, *[]string} as arguments! %#v is not a pointer!", e))
+		}
+	}
+}
+
+func ParsePasswdFile(path string) ([]User, error) {
+	passwd, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer passwd.Close()
+	return ParsePasswd(passwd)
+}
+
+func ParsePasswd(passwd io.Reader) ([]User, error) {
+	return ParsePasswdFilter(passwd, nil)
+}
+
+func ParsePasswdFileFilter(path string, filter func(User) bool) ([]User, error) {
+	passwd, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer passwd.Close()
+	return ParsePasswdFilter(passwd, filter)
+}
+
+func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) {
+	if r == nil {
+		return nil, errors.New("nil source for passwd-formatted data")
+	}
+
+	var (
+		s   = bufio.NewScanner(r)
+		out = []User{}
+	)
+
+	for s.Scan() {
+		line := bytes.TrimSpace(s.Bytes())
+		if len(line) == 0 {
+			continue
+		}
+
+		// see: man 5 passwd
+		//  name:password:UID:GID:GECOS:directory:shell
+		// Name:Pass:Uid:Gid:Gecos:Home:Shell
+		//  root:x:0:0:root:/root:/bin/bash
+		//  adm:x:3:4:adm:/var/adm:/bin/false
+		p := User{}
+		parseLine(line, &p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell)
+
+		if filter == nil || filter(p) {
+			out = append(out, p)
+		}
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+
+	return out, nil
+}
+
+func ParseGroupFile(path string) ([]Group, error) {
+	group, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+
+	defer group.Close()
+	return ParseGroup(group)
+}
+
+func ParseGroup(group io.Reader) ([]Group, error) {
+	return ParseGroupFilter(group, nil)
+}
+
+func ParseGroupFileFilter(path string, filter func(Group) bool) ([]Group, error) {
+	group, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer group.Close()
+	return ParseGroupFilter(group, filter)
+}
+
+func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) {
+	if r == nil {
+		return nil, errors.New("nil source for group-formatted data")
+	}
+	rd := bufio.NewReader(r)
+	out := []Group{}
+
+	// Read the file line-by-line.
+	for {
+		var (
+			isPrefix  bool
+			wholeLine []byte
+			err       error
+		)
+
+		// Read the next line. We do so in chunks (as much as reader's
+		// buffer is able to keep), check if we read enough columns
+		// already on each step and store final result in wholeLine.
+		for {
+			var line []byte
+			line, isPrefix, err = rd.ReadLine()
+			if err != nil {
+				// We should return no error if EOF is reached
+				// without a match.
+				if err == io.EOF {
+					err = nil
+				}
+				return out, err
+			}
+
+			// Simple common case: line is short enough to fit in a
+			// single reader's buffer.
+			if !isPrefix && len(wholeLine) == 0 {
+				wholeLine = line
+				break
+			}
+
+			wholeLine = append(wholeLine, line...)
+
+			// Check if we read the whole line already.
+			if !isPrefix {
+				break
+			}
+		}
+
+		// There's no spec for /etc/passwd or /etc/group, but we try to follow
+		// the same rules as the glibc parser, which allows comments and blank
+		// space at the beginning of a line.
+		wholeLine = bytes.TrimSpace(wholeLine)
+		if len(wholeLine) == 0 || wholeLine[0] == '#' {
+			continue
+		}
+
+		// see: man 5 group
+		//  group_name:password:GID:user_list
+		// Name:Pass:Gid:List
+		//  root:x:0:root
+		//  adm:x:4:root,adm,daemon
+		p := Group{}
+		parseLine(wholeLine, &p.Name, &p.Pass, &p.Gid, &p.List)
+
+		if filter == nil || filter(p) {
+			out = append(out, p)
+		}
+	}
+}
+
+type ExecUser struct {
+	Uid   int
+	Gid   int
+	Sgids []int
+	Home  string
+}
+
+// GetExecUserPath is a wrapper for GetExecUser. It reads data from each of the
+// given file paths and uses that data as the arguments to GetExecUser. If the
+// files cannot be opened for any reason, the error is ignored and a nil
+// io.Reader is passed instead.
+func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) {
+	var passwd, group io.Reader
+
+	if passwdFile, err := os.Open(passwdPath); err == nil {
+		passwd = passwdFile
+		defer passwdFile.Close()
+	}
+
+	if groupFile, err := os.Open(groupPath); err == nil {
+		group = groupFile
+		defer groupFile.Close()
+	}
+
+	return GetExecUser(userSpec, defaults, passwd, group)
+}
+
+// GetExecUser parses a user specification string (using the passwd and group
+// readers as sources for /etc/passwd and /etc/group data, respectively). In
+// the case of blank fields or missing data from the sources, the values in
+// defaults is used.
+//
+// GetExecUser will return an error if a user or group literal could not be
+// found in any entry in passwd and group respectively.
+//
+// Examples of valid user specifications are:
+//   - ""
+//   - "user"
+//   - "uid"
+//   - "user:group"
+//   - "uid:gid
+//   - "user:gid"
+//   - "uid:group"
+//
+// It should be noted that if you specify a numeric user or group id, they will
+// not be evaluated as usernames (only the metadata will be filled). So attempting
+// to parse a user with user.Name = "1337" will produce the user with a UID of
+// 1337.
+func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) (*ExecUser, error) {
+	if defaults == nil {
+		defaults = new(ExecUser)
+	}
+
+	// Copy over defaults.
+	user := &ExecUser{
+		Uid:   defaults.Uid,
+		Gid:   defaults.Gid,
+		Sgids: defaults.Sgids,
+		Home:  defaults.Home,
+	}
+
+	// Sgids slice *cannot* be nil.
+	if user.Sgids == nil {
+		user.Sgids = []int{}
+	}
+
+	// Allow for userArg to have either "user" syntax, or optionally "user:group" syntax
+	var userArg, groupArg string
+	parseLine([]byte(userSpec), &userArg, &groupArg)
+
+	// Convert userArg and groupArg to be numeric, so we don't have to execute
+	// Atoi *twice* for each iteration over lines.
+	uidArg, uidErr := strconv.Atoi(userArg)
+	gidArg, gidErr := strconv.Atoi(groupArg)
+
+	// Find the matching user.
+	users, err := ParsePasswdFilter(passwd, func(u User) bool {
+		if userArg == "" {
+			// Default to current state of the user.
+			return u.Uid == user.Uid
+		}
+
+		if uidErr == nil {
+			// If the userArg is numeric, always treat it as a UID.
+			return uidArg == u.Uid
+		}
+
+		return u.Name == userArg
+	})
+
+	// If we can't find the user, we have to bail.
+	if err != nil && passwd != nil {
+		if userArg == "" {
+			userArg = strconv.Itoa(user.Uid)
+		}
+		return nil, fmt.Errorf("unable to find user %s: %w", userArg, err)
+	}
+
+	var matchedUserName string
+	if len(users) > 0 {
+		// First match wins, even if there's more than one matching entry.
+		matchedUserName = users[0].Name
+		user.Uid = users[0].Uid
+		user.Gid = users[0].Gid
+		user.Home = users[0].Home
+	} else if userArg != "" {
+		// If we can't find a user with the given username, the only other valid
+		// option is if it's a numeric username with no associated entry in passwd.
+
+		if uidErr != nil {
+			// Not numeric.
+			return nil, fmt.Errorf("unable to find user %s: %w", userArg, ErrNoPasswdEntries)
+		}
+		user.Uid = uidArg
+
+		// Must be inside valid uid range.
+		if user.Uid < minID || user.Uid > maxID {
+			return nil, ErrRange
+		}
+
+		// Okay, so it's numeric. We can just roll with this.
+	}
+
+	// On to the groups. If we matched a username, we need to do this because of
+	// the supplementary group IDs.
+	if groupArg != "" || matchedUserName != "" {
+		groups, err := ParseGroupFilter(group, func(g Group) bool {
+			// If the group argument isn't explicit, we'll just search for it.
+			if groupArg == "" {
+				// Check if user is a member of this group.
+				for _, u := range g.List {
+					if u == matchedUserName {
+						return true
+					}
+				}
+				return false
+			}
+
+			if gidErr == nil {
+				// If the groupArg is numeric, always treat it as a GID.
+				return gidArg == g.Gid
+			}
+
+			return g.Name == groupArg
+		})
+		if err != nil && group != nil {
+			return nil, fmt.Errorf("unable to find groups for spec %v: %w", matchedUserName, err)
+		}
+
+		// Only start modifying user.Gid if it is in explicit form.
+		if groupArg != "" {
+			if len(groups) > 0 {
+				// First match wins, even if there's more than one matching entry.
+				user.Gid = groups[0].Gid
+			} else {
+				// If we can't find a group with the given name, the only other valid
+				// option is if it's a numeric group name with no associated entry in group.
+
+				if gidErr != nil {
+					// Not numeric.
+					return nil, fmt.Errorf("unable to find group %s: %w", groupArg, ErrNoGroupEntries)
+				}
+				user.Gid = gidArg
+
+				// Must be inside valid gid range.
+				if user.Gid < minID || user.Gid > maxID {
+					return nil, ErrRange
+				}
+
+				// Okay, so it's numeric. We can just roll with this.
+			}
+		} else if len(groups) > 0 {
+			// Supplementary group ids only make sense if in the implicit form.
+			user.Sgids = make([]int, len(groups))
+			for i, group := range groups {
+				user.Sgids[i] = group.Gid
+			}
+		}
+	}
+
+	return user, nil
+}
+
+// GetAdditionalGroups looks up a list of groups by name or group id
+// against the given /etc/group formatted data. If a group name cannot
+// be found, an error will be returned. If a group id cannot be found,
+// or the given group data is nil, the id will be returned as-is
+// provided it is in the legal range.
+func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, error) {
+	groups := []Group{}
+	if group != nil {
+		var err error
+		groups, err = ParseGroupFilter(group, func(g Group) bool {
+			for _, ag := range additionalGroups {
+				if g.Name == ag || strconv.Itoa(g.Gid) == ag {
+					return true
+				}
+			}
+			return false
+		})
+		if err != nil {
+			return nil, fmt.Errorf("Unable to find additional groups %v: %w", additionalGroups, err)
+		}
+	}
+
+	gidMap := make(map[int]struct{})
+	for _, ag := range additionalGroups {
+		var found bool
+		for _, g := range groups {
+			// if we found a matched group either by name or gid, take the
+			// first matched as correct
+			if g.Name == ag || strconv.Itoa(g.Gid) == ag {
+				if _, ok := gidMap[g.Gid]; !ok {
+					gidMap[g.Gid] = struct{}{}
+					found = true
+					break
+				}
+			}
+		}
+		// we asked for a group but didn't find it. let's check to see
+		// if we wanted a numeric group
+		if !found {
+			gid, err := strconv.ParseInt(ag, 10, 64)
+			if err != nil {
+				// Not a numeric ID either.
+				return nil, fmt.Errorf("Unable to find group %s: %w", ag, ErrNoGroupEntries)
+			}
+			// Ensure gid is inside gid range.
+			if gid < minID || gid > maxID {
+				return nil, ErrRange
+			}
+			gidMap[int(gid)] = struct{}{}
+		}
+	}
+	gids := []int{}
+	for gid := range gidMap {
+		gids = append(gids, gid)
+	}
+	return gids, nil
+}
+
+// GetAdditionalGroupsPath is a wrapper around GetAdditionalGroups
+// that opens the groupPath given and gives it as an argument to
+// GetAdditionalGroups.
+func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) {
+	var group io.Reader
+
+	if groupFile, err := os.Open(groupPath); err == nil {
+		group = groupFile
+		defer groupFile.Close()
+	}
+	return GetAdditionalGroups(additionalGroups, group)
+}
+
+func ParseSubIDFile(path string) ([]SubID, error) {
+	subid, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer subid.Close()
+	return ParseSubID(subid)
+}
+
+func ParseSubID(subid io.Reader) ([]SubID, error) {
+	return ParseSubIDFilter(subid, nil)
+}
+
+func ParseSubIDFileFilter(path string, filter func(SubID) bool) ([]SubID, error) {
+	subid, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer subid.Close()
+	return ParseSubIDFilter(subid, filter)
+}
+
+func ParseSubIDFilter(r io.Reader, filter func(SubID) bool) ([]SubID, error) {
+	if r == nil {
+		return nil, errors.New("nil source for subid-formatted data")
+	}
+
+	var (
+		s   = bufio.NewScanner(r)
+		out = []SubID{}
+	)
+
+	for s.Scan() {
+		line := bytes.TrimSpace(s.Bytes())
+		if len(line) == 0 {
+			continue
+		}
+
+		// see: man 5 subuid
+		p := SubID{}
+		parseLine(line, &p.Name, &p.SubID, &p.Count)
+
+		if filter == nil || filter(p) {
+			out = append(out, p)
+		}
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+
+	return out, nil
+}
+
+func ParseIDMapFile(path string) ([]IDMap, error) {
+	r, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer r.Close()
+	return ParseIDMap(r)
+}
+
+func ParseIDMap(r io.Reader) ([]IDMap, error) {
+	return ParseIDMapFilter(r, nil)
+}
+
+func ParseIDMapFileFilter(path string, filter func(IDMap) bool) ([]IDMap, error) {
+	r, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer r.Close()
+	return ParseIDMapFilter(r, filter)
+}
+
+func ParseIDMapFilter(r io.Reader, filter func(IDMap) bool) ([]IDMap, error) {
+	if r == nil {
+		return nil, errors.New("nil source for idmap-formatted data")
+	}
+
+	var (
+		s   = bufio.NewScanner(r)
+		out = []IDMap{}
+	)
+
+	for s.Scan() {
+		line := bytes.TrimSpace(s.Bytes())
+		if len(line) == 0 {
+			continue
+		}
+
+		// see: man 7 user_namespaces
+		p := IDMap{}
+		parseParts(bytes.Fields(line), &p.ID, &p.ParentID, &p.Count)
+
+		if filter == nil || filter(p) {
+			out = append(out, p)
+		}
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+
+	return out, nil
+}
diff --git a/vendor/github.com/moby/sys/user/user_fuzzer.go b/vendor/github.com/moby/sys/user/user_fuzzer.go
new file mode 100644
index 000000000..e018eae61
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/user_fuzzer.go
@@ -0,0 +1,43 @@
+//go:build gofuzz
+// +build gofuzz
+
+package user
+
+import (
+	"io"
+	"strings"
+)
+
+func IsDivisbleBy(n int, divisibleby int) bool {
+	return (n % divisibleby) == 0
+}
+
+func FuzzUser(data []byte) int {
+	if len(data) == 0 {
+		return -1
+	}
+	if !IsDivisbleBy(len(data), 5) {
+		return -1
+	}
+
+	var divided [][]byte
+
+	chunkSize := len(data) / 5
+
+	for i := 0; i < len(data); i += chunkSize {
+		end := i + chunkSize
+
+		divided = append(divided, data[i:end])
+	}
+
+	_, _ = ParsePasswdFilter(strings.NewReader(string(divided[0])), nil)
+
+	var passwd, group io.Reader
+
+	group = strings.NewReader(string(divided[1]))
+	_, _ = GetAdditionalGroups([]string{string(divided[2])}, group)
+
+	passwd = strings.NewReader(string(divided[3]))
+	_, _ = GetExecUser(string(divided[4]), nil, passwd, group)
+	return 1
+}
diff --git a/vendor/github.com/moby/sys/userns/LICENSE b/vendor/github.com/moby/sys/userns/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/moby/sys/userns/userns.go b/vendor/github.com/moby/sys/userns/userns.go
new file mode 100644
index 000000000..56b24c44a
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/userns.go
@@ -0,0 +1,16 @@
+// Package userns provides utilities to detect whether we are currently running
+// in a Linux user namespace.
+//
+// This code was migrated from [libcontainer/runc], which based its implementation
+// on code from [lcx/incus].
+//
+// [libcontainer/runc]: https://github.com/opencontainers/runc/blob/3778ae603c706494fd1e2c2faf83b406e38d687d/libcontainer/userns/userns_linux.go#L12-L49
+// [lcx/incus]: https://github.com/lxc/incus/blob/e45085dd42f826b3c8c3228e9733c0b6f998eafe/shared/util.go#L678-L700
+package userns
+
+// RunningInUserNS detects whether we are currently running in a Linux
+// user namespace and memoizes the result. It returns false on non-Linux
+// platforms.
+func RunningInUserNS() bool {
+	return inUserNS()
+}
diff --git a/vendor/github.com/moby/sys/userns/userns_linux.go b/vendor/github.com/moby/sys/userns/userns_linux.go
new file mode 100644
index 000000000..87c1c38ee
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/userns_linux.go
@@ -0,0 +1,53 @@
+package userns
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"sync"
+)
+
+var inUserNS = sync.OnceValue(runningInUserNS)
+
+// runningInUserNS detects whether we are currently running in a user namespace.
+//
+// This code was migrated from [libcontainer/runc] and based on an implementation
+// from [lcx/incus].
+//
+// [libcontainer/runc]: https://github.com/opencontainers/runc/blob/3778ae603c706494fd1e2c2faf83b406e38d687d/libcontainer/userns/userns_linux.go#L12-L49
+// [lcx/incus]: https://github.com/lxc/incus/blob/e45085dd42f826b3c8c3228e9733c0b6f998eafe/shared/util.go#L678-L700
+func runningInUserNS() bool {
+	file, err := os.Open("/proc/self/uid_map")
+	if err != nil {
+		// This kernel-provided file only exists if user namespaces are supported.
+		return false
+	}
+	defer file.Close()
+
+	buf := bufio.NewReader(file)
+	l, _, err := buf.ReadLine()
+	if err != nil {
+		return false
+	}
+
+	return uidMapInUserNS(string(l))
+}
+
+func uidMapInUserNS(uidMap string) bool {
+	if uidMap == "" {
+		// File exist but empty (the initial state when userns is created,
+		// see user_namespaces(7)).
+		return true
+	}
+
+	var a, b, c int64
+	if _, err := fmt.Sscanf(uidMap, "%d %d %d", &a, &b, &c); err != nil {
+		// Assume we are in a regular, non user namespace.
+		return false
+	}
+
+	// As per user_namespaces(7), /proc/self/uid_map of
+	// the initial user namespace shows 0 0 4294967295.
+	initNS := a == 0 && b == 0 && c == 4294967295
+	return !initNS
+}
diff --git a/vendor/github.com/moby/sys/userns/userns_linux_fuzzer.go b/vendor/github.com/moby/sys/userns/userns_linux_fuzzer.go
new file mode 100644
index 000000000..26ba2e16e
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/userns_linux_fuzzer.go
@@ -0,0 +1,8 @@
+//go:build linux && gofuzz
+
+package userns
+
+func FuzzUIDMap(uidmap []byte) int {
+	_ = uidMapInUserNS(string(uidmap))
+	return 1
+}
diff --git a/vendor/github.com/moby/sys/userns/userns_unsupported.go b/vendor/github.com/moby/sys/userns/userns_unsupported.go
new file mode 100644
index 000000000..8ed83072c
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/userns_unsupported.go
@@ -0,0 +1,6 @@
+//go:build !linux
+
+package userns
+
+// inUserNS is a stub for non-Linux systems. Always returns false.
+func inUserNS() bool { return false }
diff --git a/vendor/github.com/moby/term/.gitignore b/vendor/github.com/moby/term/.gitignore
new file mode 100644
index 000000000..b0747ff01
--- /dev/null
+++ b/vendor/github.com/moby/term/.gitignore
@@ -0,0 +1,8 @@
+# if you want to ignore files created by your editor/tools, consider using a
+# global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files
+.*
+!.github
+!.gitignore
+profile.out
+# support running go modules in vendor mode for local development
+vendor/
diff --git a/vendor/github.com/moby/term/LICENSE b/vendor/github.com/moby/term/LICENSE
new file mode 100644
index 000000000..6d8d58fb6
--- /dev/null
+++ b/vendor/github.com/moby/term/LICENSE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2013-2018 Docker, 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
+
+       https://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.
diff --git a/vendor/github.com/moby/term/README.md b/vendor/github.com/moby/term/README.md
new file mode 100644
index 000000000..0ce92cc33
--- /dev/null
+++ b/vendor/github.com/moby/term/README.md
@@ -0,0 +1,36 @@
+# term - utilities for dealing with terminals
+
+![Test](https://github.com/moby/term/workflows/Test/badge.svg) [![GoDoc](https://godoc.org/github.com/moby/term?status.svg)](https://godoc.org/github.com/moby/term) [![Go Report Card](https://goreportcard.com/badge/github.com/moby/term)](https://goreportcard.com/report/github.com/moby/term)
+
+term provides structures and helper functions to work with terminal (state, sizes).
+
+#### Using term
+
+```go
+package main
+
+import (
+	"log"
+	"os"
+
+	"github.com/moby/term"
+)
+
+func main() {
+	fd := os.Stdin.Fd()
+	if term.IsTerminal(fd) {
+		ws, err := term.GetWinsize(fd)
+		if err != nil {
+			log.Fatalf("term.GetWinsize: %s", err)
+		}
+		log.Printf("%d:%d\n", ws.Height, ws.Width)
+	}
+}
+```
+
+## Contributing
+
+Want to hack on term? [Docker's contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) apply.
+
+## Copyright and license
+Code and documentation copyright 2015 Docker, inc. Code released under the Apache 2.0 license. Docs released under Creative commons.
diff --git a/vendor/github.com/moby/term/ascii.go b/vendor/github.com/moby/term/ascii.go
new file mode 100644
index 000000000..55873c055
--- /dev/null
+++ b/vendor/github.com/moby/term/ascii.go
@@ -0,0 +1,66 @@
+package term
+
+import (
+	"fmt"
+	"strings"
+)
+
+// ASCII list the possible supported ASCII key sequence
+var ASCII = []string{
+	"ctrl-@",
+	"ctrl-a",
+	"ctrl-b",
+	"ctrl-c",
+	"ctrl-d",
+	"ctrl-e",
+	"ctrl-f",
+	"ctrl-g",
+	"ctrl-h",
+	"ctrl-i",
+	"ctrl-j",
+	"ctrl-k",
+	"ctrl-l",
+	"ctrl-m",
+	"ctrl-n",
+	"ctrl-o",
+	"ctrl-p",
+	"ctrl-q",
+	"ctrl-r",
+	"ctrl-s",
+	"ctrl-t",
+	"ctrl-u",
+	"ctrl-v",
+	"ctrl-w",
+	"ctrl-x",
+	"ctrl-y",
+	"ctrl-z",
+	"ctrl-[",
+	"ctrl-\\",
+	"ctrl-]",
+	"ctrl-^",
+	"ctrl-_",
+}
+
+// ToBytes converts a string representing a suite of key-sequence to the corresponding ASCII code.
+func ToBytes(keys string) ([]byte, error) {
+	codes := []byte{}
+next:
+	for _, key := range strings.Split(keys, ",") {
+		if len(key) != 1 {
+			for code, ctrl := range ASCII {
+				if ctrl == key {
+					codes = append(codes, byte(code))
+					continue next
+				}
+			}
+			if key == "DEL" {
+				codes = append(codes, 127)
+			} else {
+				return nil, fmt.Errorf("Unknown character: '%s'", key)
+			}
+		} else {
+			codes = append(codes, key[0])
+		}
+	}
+	return codes, nil
+}
diff --git a/vendor/github.com/moby/term/doc.go b/vendor/github.com/moby/term/doc.go
new file mode 100644
index 000000000..c9bc03244
--- /dev/null
+++ b/vendor/github.com/moby/term/doc.go
@@ -0,0 +1,3 @@
+// Package term provides structures and helper functions to work with
+// terminal (state, sizes).
+package term
diff --git a/vendor/github.com/moby/term/proxy.go b/vendor/github.com/moby/term/proxy.go
new file mode 100644
index 000000000..c47756b89
--- /dev/null
+++ b/vendor/github.com/moby/term/proxy.go
@@ -0,0 +1,88 @@
+package term
+
+import (
+	"io"
+)
+
+// EscapeError is special error which returned by a TTY proxy reader's Read()
+// method in case its detach escape sequence is read.
+type EscapeError struct{}
+
+func (EscapeError) Error() string {
+	return "read escape sequence"
+}
+
+// escapeProxy is used only for attaches with a TTY. It is used to proxy
+// stdin keypresses from the underlying reader and look for the passed in
+// escape key sequence to signal a detach.
+type escapeProxy struct {
+	escapeKeys   []byte
+	escapeKeyPos int
+	r            io.Reader
+	buf          []byte
+}
+
+// NewEscapeProxy returns a new TTY proxy reader which wraps the given reader
+// and detects when the specified escape keys are read, in which case the Read
+// method will return an error of type EscapeError.
+func NewEscapeProxy(r io.Reader, escapeKeys []byte) io.Reader {
+	return &escapeProxy{
+		escapeKeys: escapeKeys,
+		r:          r,
+	}
+}
+
+func (r *escapeProxy) Read(buf []byte) (n int, err error) {
+	if len(r.escapeKeys) > 0 && r.escapeKeyPos == len(r.escapeKeys) {
+		return 0, EscapeError{}
+	}
+
+	if len(r.buf) > 0 {
+		n = copy(buf, r.buf)
+		r.buf = r.buf[n:]
+	}
+
+	nr, err := r.r.Read(buf[n:])
+	n += nr
+	if len(r.escapeKeys) == 0 {
+		return n, err
+	}
+
+	for i := 0; i < n; i++ {
+		if buf[i] == r.escapeKeys[r.escapeKeyPos] {
+			r.escapeKeyPos++
+
+			// Check if the full escape sequence is matched.
+			if r.escapeKeyPos == len(r.escapeKeys) {
+				n = i + 1 - r.escapeKeyPos
+				if n < 0 {
+					n = 0
+				}
+				return n, EscapeError{}
+			}
+			continue
+		}
+
+		// If we need to prepend a partial escape sequence from the previous
+		// read, make sure the new buffer size doesn't exceed len(buf).
+		// Otherwise, preserve any extra data in a buffer for the next read.
+		if i < r.escapeKeyPos {
+			preserve := make([]byte, 0, r.escapeKeyPos+n)
+			preserve = append(preserve, r.escapeKeys[:r.escapeKeyPos]...)
+			preserve = append(preserve, buf[:n]...)
+			n = copy(buf, preserve)
+			i += r.escapeKeyPos
+			r.buf = append(r.buf, preserve[n:]...)
+		}
+		r.escapeKeyPos = 0
+	}
+
+	// If we're in the middle of reading an escape sequence, make sure we don't
+	// let the caller read it. If later on we find that this is not the escape
+	// sequence, we'll prepend it back to buf.
+	n -= r.escapeKeyPos
+	if n < 0 {
+		n = 0
+	}
+	return n, err
+}
diff --git a/vendor/github.com/moby/term/term.go b/vendor/github.com/moby/term/term.go
new file mode 100644
index 000000000..f9d8988ef
--- /dev/null
+++ b/vendor/github.com/moby/term/term.go
@@ -0,0 +1,85 @@
+package term
+
+import "io"
+
+// State holds the platform-specific state / console mode for the terminal.
+type State terminalState
+
+// Winsize represents the size of the terminal window.
+type Winsize struct {
+	Height uint16
+	Width  uint16
+
+	// Only used on Unix
+	x uint16
+	y uint16
+}
+
+// StdStreams returns the standard streams (stdin, stdout, stderr).
+//
+// On Windows, it attempts to turn on VT handling on all std handles if
+// supported, or falls back to terminal emulation. On Unix, this returns
+// the standard [os.Stdin], [os.Stdout] and [os.Stderr].
+func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
+	return stdStreams()
+}
+
+// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
+func GetFdInfo(in interface{}) (fd uintptr, isTerminal bool) {
+	return getFdInfo(in)
+}
+
+// GetWinsize returns the window size based on the specified file descriptor.
+func GetWinsize(fd uintptr) (*Winsize, error) {
+	return getWinsize(fd)
+}
+
+// SetWinsize tries to set the specified window size for the specified file
+// descriptor. It is only implemented on Unix, and returns an error on Windows.
+func SetWinsize(fd uintptr, ws *Winsize) error {
+	return setWinsize(fd, ws)
+}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(fd uintptr) bool {
+	return isTerminal(fd)
+}
+
+// RestoreTerminal restores the terminal connected to the given file descriptor
+// to a previous state.
+func RestoreTerminal(fd uintptr, state *State) error {
+	return restoreTerminal(fd, state)
+}
+
+// SaveState saves the state of the terminal connected to the given file descriptor.
+func SaveState(fd uintptr) (*State, error) {
+	return saveState(fd)
+}
+
+// DisableEcho applies the specified state to the terminal connected to the file
+// descriptor, with echo disabled.
+func DisableEcho(fd uintptr, state *State) error {
+	return disableEcho(fd, state)
+}
+
+// SetRawTerminal puts the terminal connected to the given file descriptor into
+// raw mode and returns the previous state. On UNIX, this is the equivalent of
+// [MakeRaw], and puts both the input and output into raw mode. On Windows, it
+// only puts the input into raw mode.
+func SetRawTerminal(fd uintptr) (previousState *State, err error) {
+	return setRawTerminal(fd)
+}
+
+// SetRawTerminalOutput puts the output of terminal connected to the given file
+// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
+// state. On Windows, it disables LF -> CRLF translation.
+func SetRawTerminalOutput(fd uintptr) (previousState *State, err error) {
+	return setRawTerminalOutput(fd)
+}
+
+// MakeRaw puts the terminal (Windows Console) connected to the
+// given file descriptor into raw mode and returns the previous state of
+// the terminal so that it can be restored.
+func MakeRaw(fd uintptr) (previousState *State, err error) {
+	return makeRaw(fd)
+}
diff --git a/vendor/github.com/moby/term/term_unix.go b/vendor/github.com/moby/term/term_unix.go
new file mode 100644
index 000000000..579ce5530
--- /dev/null
+++ b/vendor/github.com/moby/term/term_unix.go
@@ -0,0 +1,98 @@
+//go:build !windows
+// +build !windows
+
+package term
+
+import (
+	"errors"
+	"io"
+	"os"
+
+	"golang.org/x/sys/unix"
+)
+
+// ErrInvalidState is returned if the state of the terminal is invalid.
+//
+// Deprecated: ErrInvalidState is no longer used.
+var ErrInvalidState = errors.New("Invalid terminal state")
+
+// terminalState holds the platform-specific state / console mode for the terminal.
+type terminalState struct {
+	termios unix.Termios
+}
+
+func stdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
+	return os.Stdin, os.Stdout, os.Stderr
+}
+
+func getFdInfo(in interface{}) (uintptr, bool) {
+	var inFd uintptr
+	var isTerminalIn bool
+	if file, ok := in.(*os.File); ok {
+		inFd = file.Fd()
+		isTerminalIn = isTerminal(inFd)
+	}
+	return inFd, isTerminalIn
+}
+
+func getWinsize(fd uintptr) (*Winsize, error) {
+	uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
+	ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel}
+	return ws, err
+}
+
+func setWinsize(fd uintptr, ws *Winsize) error {
+	return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &unix.Winsize{
+		Row:    ws.Height,
+		Col:    ws.Width,
+		Xpixel: ws.x,
+		Ypixel: ws.y,
+	})
+}
+
+func isTerminal(fd uintptr) bool {
+	_, err := tcget(fd)
+	return err == nil
+}
+
+func restoreTerminal(fd uintptr, state *State) error {
+	if state == nil {
+		return errors.New("invalid terminal state")
+	}
+	return tcset(fd, &state.termios)
+}
+
+func saveState(fd uintptr) (*State, error) {
+	termios, err := tcget(fd)
+	if err != nil {
+		return nil, err
+	}
+	return &State{termios: *termios}, nil
+}
+
+func disableEcho(fd uintptr, state *State) error {
+	newState := state.termios
+	newState.Lflag &^= unix.ECHO
+
+	return tcset(fd, &newState)
+}
+
+func setRawTerminal(fd uintptr) (*State, error) {
+	return makeRaw(fd)
+}
+
+func setRawTerminalOutput(uintptr) (*State, error) {
+	return nil, nil
+}
+
+func tcget(fd uintptr) (*unix.Termios, error) {
+	p, err := unix.IoctlGetTermios(int(fd), getTermios)
+	if err != nil {
+		return nil, err
+	}
+	return p, nil
+}
+
+func tcset(fd uintptr, p *unix.Termios) error {
+	return unix.IoctlSetTermios(int(fd), setTermios, p)
+}
diff --git a/vendor/github.com/moby/term/term_windows.go b/vendor/github.com/moby/term/term_windows.go
new file mode 100644
index 000000000..81ccff042
--- /dev/null
+++ b/vendor/github.com/moby/term/term_windows.go
@@ -0,0 +1,176 @@
+package term
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"os/signal"
+
+	windowsconsole "github.com/moby/term/windows"
+	"golang.org/x/sys/windows"
+)
+
+// terminalState holds the platform-specific state / console mode for the terminal.
+type terminalState struct {
+	mode uint32
+}
+
+// vtInputSupported is true if winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported by the console
+var vtInputSupported bool
+
+func stdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
+	// Turn on VT handling on all std handles, if possible. This might
+	// fail, in which case we will fall back to terminal emulation.
+	var (
+		emulateStdin, emulateStdout, emulateStderr bool
+
+		mode uint32
+	)
+
+	fd := windows.Handle(os.Stdin.Fd())
+	if err := windows.GetConsoleMode(fd, &mode); err == nil {
+		// Validate that winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
+		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
+			emulateStdin = true
+		} else {
+			vtInputSupported = true
+		}
+		// Unconditionally set the console mode back even on failure because SetConsoleMode
+		// remembers invalid bits on input handles.
+		_ = windows.SetConsoleMode(fd, mode)
+	}
+
+	fd = windows.Handle(os.Stdout.Fd())
+	if err := windows.GetConsoleMode(fd, &mode); err == nil {
+		// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
+		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
+			emulateStdout = true
+		} else {
+			_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+		}
+	}
+
+	fd = windows.Handle(os.Stderr.Fd())
+	if err := windows.GetConsoleMode(fd, &mode); err == nil {
+		// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
+		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
+			emulateStderr = true
+		} else {
+			_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+		}
+	}
+
+	if emulateStdin {
+		h := uint32(windows.STD_INPUT_HANDLE)
+		stdIn = windowsconsole.NewAnsiReader(int(h))
+	} else {
+		stdIn = os.Stdin
+	}
+
+	if emulateStdout {
+		h := uint32(windows.STD_OUTPUT_HANDLE)
+		stdOut = windowsconsole.NewAnsiWriter(int(h))
+	} else {
+		stdOut = os.Stdout
+	}
+
+	if emulateStderr {
+		h := uint32(windows.STD_ERROR_HANDLE)
+		stdErr = windowsconsole.NewAnsiWriter(int(h))
+	} else {
+		stdErr = os.Stderr
+	}
+
+	return stdIn, stdOut, stdErr
+}
+
+func getFdInfo(in interface{}) (uintptr, bool) {
+	return windowsconsole.GetHandleInfo(in)
+}
+
+func getWinsize(fd uintptr) (*Winsize, error) {
+	var info windows.ConsoleScreenBufferInfo
+	if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
+		return nil, err
+	}
+
+	winsize := &Winsize{
+		Width:  uint16(info.Window.Right - info.Window.Left + 1),
+		Height: uint16(info.Window.Bottom - info.Window.Top + 1),
+	}
+
+	return winsize, nil
+}
+
+func setWinsize(fd uintptr, ws *Winsize) error {
+	return fmt.Errorf("not implemented on Windows")
+}
+
+func isTerminal(fd uintptr) bool {
+	var mode uint32
+	err := windows.GetConsoleMode(windows.Handle(fd), &mode)
+	return err == nil
+}
+
+func restoreTerminal(fd uintptr, state *State) error {
+	return windows.SetConsoleMode(windows.Handle(fd), state.mode)
+}
+
+func saveState(fd uintptr) (*State, error) {
+	var mode uint32
+
+	if err := windows.GetConsoleMode(windows.Handle(fd), &mode); err != nil {
+		return nil, err
+	}
+
+	return &State{mode: mode}, nil
+}
+
+func disableEcho(fd uintptr, state *State) error {
+	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
+	mode := state.mode
+	mode &^= windows.ENABLE_ECHO_INPUT
+	mode |= windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT
+	err := windows.SetConsoleMode(windows.Handle(fd), mode)
+	if err != nil {
+		return err
+	}
+
+	// Register an interrupt handler to catch and restore prior state
+	restoreAtInterrupt(fd, state)
+	return nil
+}
+
+func setRawTerminal(fd uintptr) (*State, error) {
+	oldState, err := MakeRaw(fd)
+	if err != nil {
+		return nil, err
+	}
+
+	// Register an interrupt handler to catch and restore prior state
+	restoreAtInterrupt(fd, oldState)
+	return oldState, err
+}
+
+func setRawTerminalOutput(fd uintptr) (*State, error) {
+	oldState, err := saveState(fd)
+	if err != nil {
+		return nil, err
+	}
+
+	// Ignore failures, since winterm.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this
+	// version of Windows.
+	_ = windows.SetConsoleMode(windows.Handle(fd), oldState.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
+	return oldState, err
+}
+
+func restoreAtInterrupt(fd uintptr, state *State) {
+	sigchan := make(chan os.Signal, 1)
+	signal.Notify(sigchan, os.Interrupt)
+
+	go func() {
+		_ = <-sigchan
+		_ = RestoreTerminal(fd, state)
+		os.Exit(0)
+	}()
+}
diff --git a/vendor/github.com/moby/term/termios_bsd.go b/vendor/github.com/moby/term/termios_bsd.go
new file mode 100644
index 000000000..45f77e03c
--- /dev/null
+++ b/vendor/github.com/moby/term/termios_bsd.go
@@ -0,0 +1,13 @@
+//go:build darwin || freebsd || openbsd || netbsd
+// +build darwin freebsd openbsd netbsd
+
+package term
+
+import (
+	"golang.org/x/sys/unix"
+)
+
+const (
+	getTermios = unix.TIOCGETA
+	setTermios = unix.TIOCSETA
+)
diff --git a/vendor/github.com/moby/term/termios_nonbsd.go b/vendor/github.com/moby/term/termios_nonbsd.go
new file mode 100644
index 000000000..88b7b2156
--- /dev/null
+++ b/vendor/github.com/moby/term/termios_nonbsd.go
@@ -0,0 +1,13 @@
+//go:build !darwin && !freebsd && !netbsd && !openbsd && !windows
+// +build !darwin,!freebsd,!netbsd,!openbsd,!windows
+
+package term
+
+import (
+	"golang.org/x/sys/unix"
+)
+
+const (
+	getTermios = unix.TCGETS
+	setTermios = unix.TCSETS
+)
diff --git a/vendor/github.com/moby/term/termios_unix.go b/vendor/github.com/moby/term/termios_unix.go
new file mode 100644
index 000000000..60c823783
--- /dev/null
+++ b/vendor/github.com/moby/term/termios_unix.go
@@ -0,0 +1,35 @@
+//go:build !windows
+// +build !windows
+
+package term
+
+import (
+	"golang.org/x/sys/unix"
+)
+
+// Termios is the Unix API for terminal I/O.
+//
+// Deprecated: use [unix.Termios].
+type Termios = unix.Termios
+
+func makeRaw(fd uintptr) (*State, error) {
+	termios, err := tcget(fd)
+	if err != nil {
+		return nil, err
+	}
+
+	oldState := State{termios: *termios}
+
+	termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
+	termios.Oflag &^= unix.OPOST
+	termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
+	termios.Cflag &^= unix.CSIZE | unix.PARENB
+	termios.Cflag |= unix.CS8
+	termios.Cc[unix.VMIN] = 1
+	termios.Cc[unix.VTIME] = 0
+
+	if err := tcset(fd, termios); err != nil {
+		return nil, err
+	}
+	return &oldState, nil
+}
diff --git a/vendor/github.com/moby/term/termios_windows.go b/vendor/github.com/moby/term/termios_windows.go
new file mode 100644
index 000000000..5be4e7601
--- /dev/null
+++ b/vendor/github.com/moby/term/termios_windows.go
@@ -0,0 +1,37 @@
+package term
+
+import "golang.org/x/sys/windows"
+
+func makeRaw(fd uintptr) (*State, error) {
+	state, err := SaveState(fd)
+	if err != nil {
+		return nil, err
+	}
+
+	mode := state.mode
+
+	// See
+	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
+	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
+
+	// Disable these modes
+	mode &^= windows.ENABLE_ECHO_INPUT
+	mode &^= windows.ENABLE_LINE_INPUT
+	mode &^= windows.ENABLE_MOUSE_INPUT
+	mode &^= windows.ENABLE_WINDOW_INPUT
+	mode &^= windows.ENABLE_PROCESSED_INPUT
+
+	// Enable these modes
+	mode |= windows.ENABLE_EXTENDED_FLAGS
+	mode |= windows.ENABLE_INSERT_MODE
+	mode |= windows.ENABLE_QUICK_EDIT_MODE
+	if vtInputSupported {
+		mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
+	}
+
+	err = windows.SetConsoleMode(windows.Handle(fd), mode)
+	if err != nil {
+		return nil, err
+	}
+	return state, nil
+}
diff --git a/vendor/github.com/moby/term/windows/ansi_reader.go b/vendor/github.com/moby/term/windows/ansi_reader.go
new file mode 100644
index 000000000..fb34c547a
--- /dev/null
+++ b/vendor/github.com/moby/term/windows/ansi_reader.go
@@ -0,0 +1,252 @@
+//go:build windows
+// +build windows
+
+package windowsconsole
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+	"unsafe"
+
+	ansiterm "github.com/Azure/go-ansiterm"
+	"github.com/Azure/go-ansiterm/winterm"
+)
+
+const (
+	escapeSequence = ansiterm.KEY_ESC_CSI
+)
+
+// ansiReader wraps a standard input file (e.g., os.Stdin) providing ANSI sequence translation.
+type ansiReader struct {
+	file     *os.File
+	fd       uintptr
+	buffer   []byte
+	cbBuffer int
+	command  []byte
+}
+
+// NewAnsiReader returns an io.ReadCloser that provides VT100 terminal emulation on top of a
+// Windows console input handle.
+func NewAnsiReader(nFile int) io.ReadCloser {
+	file, fd := winterm.GetStdFile(nFile)
+	return &ansiReader{
+		file:    file,
+		fd:      fd,
+		command: make([]byte, 0, ansiterm.ANSI_MAX_CMD_LENGTH),
+		buffer:  make([]byte, 0),
+	}
+}
+
+// Close closes the wrapped file.
+func (ar *ansiReader) Close() (err error) {
+	return ar.file.Close()
+}
+
+// Fd returns the file descriptor of the wrapped file.
+func (ar *ansiReader) Fd() uintptr {
+	return ar.fd
+}
+
+// Read reads up to len(p) bytes of translated input events into p.
+func (ar *ansiReader) Read(p []byte) (int, error) {
+	if len(p) == 0 {
+		return 0, nil
+	}
+
+	// Previously read bytes exist, read as much as we can and return
+	if len(ar.buffer) > 0 {
+		originalLength := len(ar.buffer)
+		copiedLength := copy(p, ar.buffer)
+
+		if copiedLength == originalLength {
+			ar.buffer = make([]byte, 0, len(p))
+		} else {
+			ar.buffer = ar.buffer[copiedLength:]
+		}
+
+		return copiedLength, nil
+	}
+
+	// Read and translate key events
+	events, err := readInputEvents(ar, len(p))
+	if err != nil {
+		return 0, err
+	} else if len(events) == 0 {
+		return 0, nil
+	}
+
+	keyBytes := translateKeyEvents(events, []byte(escapeSequence))
+
+	// Save excess bytes and right-size keyBytes
+	if len(keyBytes) > len(p) {
+		ar.buffer = keyBytes[len(p):]
+		keyBytes = keyBytes[:len(p)]
+	} else if len(keyBytes) == 0 {
+		return 0, nil
+	}
+
+	copiedLength := copy(p, keyBytes)
+	if copiedLength != len(keyBytes) {
+		return 0, errors.New("unexpected copy length encountered")
+	}
+
+	return copiedLength, nil
+}
+
+// readInputEvents polls until at least one event is available.
+func readInputEvents(ar *ansiReader, maxBytes int) ([]winterm.INPUT_RECORD, error) {
+	// Determine the maximum number of records to retrieve
+	// -- Cast around the type system to obtain the size of a single INPUT_RECORD.
+	//    unsafe.Sizeof requires an expression vs. a type-reference; the casting
+	//    tricks the type system into believing it has such an expression.
+	recordSize := int(unsafe.Sizeof(*((*winterm.INPUT_RECORD)(unsafe.Pointer(&maxBytes)))))
+	countRecords := maxBytes / recordSize
+	if countRecords > ansiterm.MAX_INPUT_EVENTS {
+		countRecords = ansiterm.MAX_INPUT_EVENTS
+	} else if countRecords == 0 {
+		countRecords = 1
+	}
+
+	// Wait for and read input events
+	events := make([]winterm.INPUT_RECORD, countRecords)
+	nEvents := uint32(0)
+	eventsExist, err := winterm.WaitForSingleObject(ar.fd, winterm.WAIT_INFINITE)
+	if err != nil {
+		return nil, err
+	}
+
+	if eventsExist {
+		err = winterm.ReadConsoleInput(ar.fd, events, &nEvents)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Return a slice restricted to the number of returned records
+	return events[:nEvents], nil
+}
+
+// KeyEvent Translation Helpers
+
+var arrowKeyMapPrefix = map[uint16]string{
+	winterm.VK_UP:    "%s%sA",
+	winterm.VK_DOWN:  "%s%sB",
+	winterm.VK_RIGHT: "%s%sC",
+	winterm.VK_LEFT:  "%s%sD",
+}
+
+var keyMapPrefix = map[uint16]string{
+	winterm.VK_UP:     "\x1B[%sA",
+	winterm.VK_DOWN:   "\x1B[%sB",
+	winterm.VK_RIGHT:  "\x1B[%sC",
+	winterm.VK_LEFT:   "\x1B[%sD",
+	winterm.VK_HOME:   "\x1B[1%s~", // showkey shows ^[[1
+	winterm.VK_END:    "\x1B[4%s~", // showkey shows ^[[4
+	winterm.VK_INSERT: "\x1B[2%s~",
+	winterm.VK_DELETE: "\x1B[3%s~",
+	winterm.VK_PRIOR:  "\x1B[5%s~",
+	winterm.VK_NEXT:   "\x1B[6%s~",
+	winterm.VK_F1:     "",
+	winterm.VK_F2:     "",
+	winterm.VK_F3:     "\x1B[13%s~",
+	winterm.VK_F4:     "\x1B[14%s~",
+	winterm.VK_F5:     "\x1B[15%s~",
+	winterm.VK_F6:     "\x1B[17%s~",
+	winterm.VK_F7:     "\x1B[18%s~",
+	winterm.VK_F8:     "\x1B[19%s~",
+	winterm.VK_F9:     "\x1B[20%s~",
+	winterm.VK_F10:    "\x1B[21%s~",
+	winterm.VK_F11:    "\x1B[23%s~",
+	winterm.VK_F12:    "\x1B[24%s~",
+}
+
+// translateKeyEvents converts the input events into the appropriate ANSI string.
+func translateKeyEvents(events []winterm.INPUT_RECORD, escapeSequence []byte) []byte {
+	var buffer bytes.Buffer
+	for _, event := range events {
+		if event.EventType == winterm.KEY_EVENT && event.KeyEvent.KeyDown != 0 {
+			buffer.WriteString(keyToString(&event.KeyEvent, escapeSequence))
+		}
+	}
+
+	return buffer.Bytes()
+}
+
+// keyToString maps the given input event record to the corresponding string.
+func keyToString(keyEvent *winterm.KEY_EVENT_RECORD, escapeSequence []byte) string {
+	if keyEvent.UnicodeChar == 0 {
+		return formatVirtualKey(keyEvent.VirtualKeyCode, keyEvent.ControlKeyState, escapeSequence)
+	}
+
+	_, alt, control := getControlKeys(keyEvent.ControlKeyState)
+	if control {
+		// TODO(azlinux): Implement following control sequences
+		// <Ctrl>-D  Signals the end of input from the keyboard; also exits current shell.
+		// <Ctrl>-H  Deletes the first character to the left of the cursor. Also called the ERASE key.
+		// <Ctrl>-Q  Restarts printing after it has been stopped with <Ctrl>-s.
+		// <Ctrl>-S  Suspends printing on the screen (does not stop the program).
+		// <Ctrl>-U  Deletes all characters on the current line. Also called the KILL key.
+		// <Ctrl>-E  Quits current command and creates a core
+	}
+
+	// <Alt>+Key generates ESC N Key
+	if !control && alt {
+		return ansiterm.KEY_ESC_N + strings.ToLower(string(rune(keyEvent.UnicodeChar)))
+	}
+
+	return string(rune(keyEvent.UnicodeChar))
+}
+
+// formatVirtualKey converts a virtual key (e.g., up arrow) into the appropriate ANSI string.
+func formatVirtualKey(key uint16, controlState uint32, escapeSequence []byte) string {
+	shift, alt, control := getControlKeys(controlState)
+	modifier := getControlKeysModifier(shift, alt, control)
+
+	if format, ok := arrowKeyMapPrefix[key]; ok {
+		return fmt.Sprintf(format, escapeSequence, modifier)
+	}
+
+	if format, ok := keyMapPrefix[key]; ok {
+		return fmt.Sprintf(format, modifier)
+	}
+
+	return ""
+}
+
+// getControlKeys extracts the shift, alt, and ctrl key states.
+func getControlKeys(controlState uint32) (shift, alt, control bool) {
+	shift = 0 != (controlState & winterm.SHIFT_PRESSED)
+	alt = 0 != (controlState & (winterm.LEFT_ALT_PRESSED | winterm.RIGHT_ALT_PRESSED))
+	control = 0 != (controlState & (winterm.LEFT_CTRL_PRESSED | winterm.RIGHT_CTRL_PRESSED))
+	return shift, alt, control
+}
+
+// getControlKeysModifier returns the ANSI modifier for the given combination of control keys.
+func getControlKeysModifier(shift, alt, control bool) string {
+	if shift && alt && control {
+		return ansiterm.KEY_CONTROL_PARAM_8
+	}
+	if alt && control {
+		return ansiterm.KEY_CONTROL_PARAM_7
+	}
+	if shift && control {
+		return ansiterm.KEY_CONTROL_PARAM_6
+	}
+	if control {
+		return ansiterm.KEY_CONTROL_PARAM_5
+	}
+	if shift && alt {
+		return ansiterm.KEY_CONTROL_PARAM_4
+	}
+	if alt {
+		return ansiterm.KEY_CONTROL_PARAM_3
+	}
+	if shift {
+		return ansiterm.KEY_CONTROL_PARAM_2
+	}
+	return ""
+}
diff --git a/vendor/github.com/moby/term/windows/ansi_writer.go b/vendor/github.com/moby/term/windows/ansi_writer.go
new file mode 100644
index 000000000..4243307fd
--- /dev/null
+++ b/vendor/github.com/moby/term/windows/ansi_writer.go
@@ -0,0 +1,57 @@
+//go:build windows
+// +build windows
+
+package windowsconsole
+
+import (
+	"io"
+	"os"
+
+	ansiterm "github.com/Azure/go-ansiterm"
+	"github.com/Azure/go-ansiterm/winterm"
+)
+
+// ansiWriter wraps a standard output file (e.g., os.Stdout) providing ANSI sequence translation.
+type ansiWriter struct {
+	file           *os.File
+	fd             uintptr
+	infoReset      *winterm.CONSOLE_SCREEN_BUFFER_INFO
+	command        []byte
+	escapeSequence []byte
+	inAnsiSequence bool
+	parser         *ansiterm.AnsiParser
+}
+
+// NewAnsiWriter returns an io.Writer that provides VT100 terminal emulation on top of a
+// Windows console output handle.
+func NewAnsiWriter(nFile int) io.Writer {
+	file, fd := winterm.GetStdFile(nFile)
+	info, err := winterm.GetConsoleScreenBufferInfo(fd)
+	if err != nil {
+		return nil
+	}
+
+	parser := ansiterm.CreateParser("Ground", winterm.CreateWinEventHandler(fd, file))
+
+	return &ansiWriter{
+		file:           file,
+		fd:             fd,
+		infoReset:      info,
+		command:        make([]byte, 0, ansiterm.ANSI_MAX_CMD_LENGTH),
+		escapeSequence: []byte(ansiterm.KEY_ESC_CSI),
+		parser:         parser,
+	}
+}
+
+func (aw *ansiWriter) Fd() uintptr {
+	return aw.fd
+}
+
+// Write writes len(p) bytes from p to the underlying data stream.
+func (aw *ansiWriter) Write(p []byte) (total int, err error) {
+	if len(p) == 0 {
+		return 0, nil
+	}
+
+	return aw.parser.Parse(p)
+}
diff --git a/vendor/github.com/moby/term/windows/console.go b/vendor/github.com/moby/term/windows/console.go
new file mode 100644
index 000000000..21e57bd52
--- /dev/null
+++ b/vendor/github.com/moby/term/windows/console.go
@@ -0,0 +1,43 @@
+//go:build windows
+// +build windows
+
+package windowsconsole
+
+import (
+	"os"
+
+	"golang.org/x/sys/windows"
+)
+
+// GetHandleInfo returns file descriptor and bool indicating whether the file is a console.
+func GetHandleInfo(in interface{}) (uintptr, bool) {
+	switch t := in.(type) {
+	case *ansiReader:
+		return t.Fd(), true
+	case *ansiWriter:
+		return t.Fd(), true
+	}
+
+	var inFd uintptr
+	var isTerminal bool
+
+	if file, ok := in.(*os.File); ok {
+		inFd = file.Fd()
+		isTerminal = isConsole(inFd)
+	}
+	return inFd, isTerminal
+}
+
+// IsConsole returns true if the given file descriptor is a Windows Console.
+// The code assumes that GetConsoleMode will return an error for file descriptors that are not a console.
+//
+// Deprecated: use [windows.GetConsoleMode] or [golang.org/x/term.IsTerminal].
+func IsConsole(fd uintptr) bool {
+	return isConsole(fd)
+}
+
+func isConsole(fd uintptr) bool {
+	var mode uint32
+	err := windows.GetConsoleMode(windows.Handle(fd), &mode)
+	return err == nil
+}
diff --git a/vendor/github.com/moby/term/windows/doc.go b/vendor/github.com/moby/term/windows/doc.go
new file mode 100644
index 000000000..54265fffa
--- /dev/null
+++ b/vendor/github.com/moby/term/windows/doc.go
@@ -0,0 +1,5 @@
+// These files implement ANSI-aware input and output streams for use by the Docker Windows client.
+// When asked for the set of standard streams (e.g., stdin, stdout, stderr), the code will create
+// and return pseudo-streams that convert ANSI sequences to / from Windows Console API calls.
+
+package windowsconsole
diff --git a/vendor/github.com/power-devops/perfstat/LICENSE b/vendor/github.com/power-devops/perfstat/LICENSE
new file mode 100644
index 000000000..ec4e5d39d
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/LICENSE
@@ -0,0 +1,23 @@
+MIT License
+
+Copyright (c) 2020 Power DevOps
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
diff --git a/vendor/github.com/power-devops/perfstat/c_helpers.c b/vendor/github.com/power-devops/perfstat/c_helpers.c
new file mode 100644
index 000000000..49ba1ad7e
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/c_helpers.c
@@ -0,0 +1,159 @@
+#include "c_helpers.h"
+
+GETFUNC(cpu)
+GETFUNC(disk)
+GETFUNC(diskadapter)
+GETFUNC(diskpath)
+GETFUNC(fcstat)
+GETFUNC(logicalvolume)
+GETFUNC(memory_page)
+GETFUNC(netadapter)
+GETFUNC(netbuffer)
+GETFUNC(netinterface)
+GETFUNC(pagingspace)
+GETFUNC(process)
+GETFUNC(thread)
+GETFUNC(volumegroup)
+
+double get_partition_mhz(perfstat_partition_config_t pinfo) {
+	return pinfo.processorMHz;
+}
+
+char *get_ps_hostname(perfstat_pagingspace_t *ps) {
+	return ps->u.nfs_paging.hostname;
+}
+
+char *get_ps_filename(perfstat_pagingspace_t *ps) {
+	return ps->u.nfs_paging.filename;
+}
+
+char *get_ps_vgname(perfstat_pagingspace_t *ps) {
+	return ps->u.lv_paging.vgname;
+}
+
+time_t boottime()
+{
+        register struct utmpx *utmp;
+
+	setutxent();
+        while ( (utmp = getutxent()) != NULL ) {
+                if (utmp->ut_type == BOOT_TIME) {
+                        return utmp->ut_tv.tv_sec;
+                }
+        }
+	endutxent();
+        return -1;
+}
+
+struct fsinfo *get_filesystem_stat(struct fsinfo *fs_all, int n) {
+	if (!fs_all) return NULL;
+	return &(fs_all[n]);
+}
+
+int get_mounts(struct vmount **vmountpp) {
+        int size;
+        struct vmount *vm;
+        int nmounts;
+
+        size = BUFSIZ;
+
+        while (1) {
+                if ((vm = (struct vmount *)malloc((size_t)size)) == NULL) {
+                        perror("malloc failed");
+                        exit(-1);
+                }
+                if ((nmounts = mntctl(MCTL_QUERY, size, (caddr_t)vm)) > 0) {
+                        *vmountpp = vm;
+                        return nmounts;
+                } else if (nmounts == 0) {
+                        size = *(int *)vm;
+                        free((void *)vm);
+                } else {
+                        free((void *)vm);
+                        return -1;
+                }
+        }
+}
+
+void fill_fsinfo(struct statfs statbuf, struct fsinfo *fs) {
+        fsblkcnt_t freeblks, totblks, usedblks;
+        fsblkcnt_t tinodes, ninodes, ifree;
+        uint    cfactor;
+
+        if (statbuf.f_blocks == -1) {
+                fs->totalblks = 0;
+                fs->freeblks = 0;
+                fs->totalinodes = 0;
+                fs->freeinodes = 0;
+                return;
+        }
+
+        cfactor = statbuf.f_bsize / 512;
+        fs->freeblks = statbuf.f_bavail * cfactor;
+        fs->totalblks = statbuf.f_blocks * cfactor;
+
+        fs->freeinodes = statbuf.f_ffree;
+        fs->totalinodes = statbuf.f_files;
+
+        if (fs->freeblks < 0)
+                fs->freeblks = 0;
+}
+
+int getfsinfo(char *fsname, char *devname, char *host, char *options, int flags, int fstype, struct fsinfo *fs) {
+        struct statfs statbuf;
+	int devname_size = strlen(devname);
+	int fsname_size = strlen(fsname);
+        char buf[BUFSIZ];
+        char *p;
+
+        if (fs == NULL) {
+                return 1;
+        }
+
+        for (p = strtok(options, ","); p != NULL; p = strtok(NULL, ","))
+                if (strcmp(p, "ignore") == 0)
+                        return 0;
+
+        if (*host != 0 && strcmp(host, "-") != 0) {
+                sprintf(buf, "%s:%s", host, devname);
+                devname = buf;
+        }
+        fs->devname = (char *)calloc(devname_size+1, 1);
+        fs->fsname = (char *)calloc(fsname_size+1, 1);
+        strncpy(fs->devname, devname, devname_size);
+        strncpy(fs->fsname, fsname, fsname_size);
+	fs->flags = flags;
+	fs->fstype = fstype;
+
+        if (statfs(fsname,&statbuf) < 0) {
+                return 1;
+        }
+
+        fill_fsinfo(statbuf, fs);
+        return 0;
+}
+
+struct fsinfo *get_all_fs(int *rc) {
+        struct vmount *mnt;
+        struct fsinfo *fs_all;
+        int nmounts;
+
+        *rc = -1;
+        if ((nmounts = get_mounts(&mnt)) <= 0) {
+                perror("Can't get mount table info");
+                return NULL;
+        }
+
+        fs_all = (struct fsinfo *)calloc(sizeof(struct fsinfo), nmounts);
+        while ((*rc)++, nmounts--) {
+                getfsinfo(vmt2dataptr(mnt, VMT_STUB),
+                          vmt2dataptr(mnt, VMT_OBJECT),
+                          vmt2dataptr(mnt, VMT_HOST),
+                          vmt2dataptr(mnt, VMT_ARGS),
+			  mnt->vmt_flags,
+			  mnt->vmt_gfstype,
+                          &fs_all[*rc]);
+                mnt = (struct vmount *)((char *)mnt + mnt->vmt_length);
+        }
+        return fs_all;
+}
diff --git a/vendor/github.com/power-devops/perfstat/c_helpers.h b/vendor/github.com/power-devops/perfstat/c_helpers.h
new file mode 100644
index 000000000..b66bc53c3
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/c_helpers.h
@@ -0,0 +1,58 @@
+#ifndef C_HELPERS_H
+#define C_HELPERS_H
+
+#include <sys/types.h>
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <sys/statfs.h>
+#include <libperfstat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmpx.h>
+
+#define GETFUNC(TYPE) perfstat_##TYPE##_t *get_##TYPE##_stat(perfstat_##TYPE##_t *b, int n) { \
+        if (!b) return NULL; \
+        return &(b[n]); \
+}
+
+#define GETFUNC_EXT(TYPE) extern perfstat_##TYPE##_t *get_##TYPE##_stat(perfstat_##TYPE##_t *, int);
+
+GETFUNC_EXT(cpu)
+GETFUNC_EXT(disk)
+GETFUNC_EXT(diskadapter)
+GETFUNC_EXT(diskpath)
+GETFUNC_EXT(fcstat)
+GETFUNC_EXT(logicalvolume)
+GETFUNC_EXT(memory_page)
+GETFUNC_EXT(netadapter)
+GETFUNC_EXT(netbuffer)
+GETFUNC_EXT(netinterface)
+GETFUNC_EXT(pagingspace)
+GETFUNC_EXT(process)
+GETFUNC_EXT(thread)
+GETFUNC_EXT(volumegroup)
+
+struct fsinfo {
+        char *devname;
+        char *fsname;
+	int flags;
+	int fstype;
+        unsigned long totalblks;
+        unsigned long freeblks;
+        unsigned long totalinodes;
+        unsigned long freeinodes;
+};
+
+extern double get_partition_mhz(perfstat_partition_config_t);
+extern char *get_ps_hostname(perfstat_pagingspace_t *);
+extern char *get_ps_filename(perfstat_pagingspace_t *);
+extern char *get_ps_vgname(perfstat_pagingspace_t *);
+extern time_t boottime();
+struct fsinfo *get_filesystem_stat(struct fsinfo *, int);
+int get_mounts(struct vmount **);
+void fill_statfs(struct statfs, struct fsinfo *);
+int getfsinfo(char *, char *, char *, char *, int, int, struct fsinfo *);
+struct fsinfo *get_all_fs(int *);
+
+#endif
diff --git a/vendor/github.com/power-devops/perfstat/config.go b/vendor/github.com/power-devops/perfstat/config.go
new file mode 100644
index 000000000..a6df39c67
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/config.go
@@ -0,0 +1,19 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+*/
+import "C"
+
+func EnableLVMStat() {
+	C.perfstat_config(C.PERFSTAT_ENABLE|C.PERFSTAT_LV|C.PERFSTAT_VG, nil)
+}
+
+func DisableLVMStat() {
+	C.perfstat_config(C.PERFSTAT_DISABLE|C.PERFSTAT_LV|C.PERFSTAT_VG, nil)
+}
diff --git a/vendor/github.com/power-devops/perfstat/cpustat.go b/vendor/github.com/power-devops/perfstat/cpustat.go
new file mode 100644
index 000000000..10f543fa4
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/cpustat.go
@@ -0,0 +1,138 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "c_helpers.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"runtime"
+	"time"
+	"unsafe"
+)
+
+var old_cpu_total_stat *C.perfstat_cpu_total_t
+
+func init() {
+	old_cpu_total_stat = (*C.perfstat_cpu_total_t)(C.malloc(C.sizeof_perfstat_cpu_total_t))
+	C.perfstat_cpu_total(nil, old_cpu_total_stat, C.sizeof_perfstat_cpu_total_t, 1)
+}
+
+func CpuStat() ([]CPU, error) {
+	var cpustat *C.perfstat_cpu_t
+	var cpu C.perfstat_id_t
+
+	ncpu := runtime.NumCPU()
+
+	cpustat_len := C.sizeof_perfstat_cpu_t * C.ulong(ncpu)
+	cpustat = (*C.perfstat_cpu_t)(C.malloc(cpustat_len))
+	defer C.free(unsafe.Pointer(cpustat))
+	C.strcpy(&cpu.name[0], C.CString(C.FIRST_CPU))
+	r := C.perfstat_cpu(&cpu, cpustat, C.sizeof_perfstat_cpu_t, C.int(ncpu))
+	if r <= 0 {
+		return nil, fmt.Errorf("error perfstat_cpu()")
+	}
+	c := make([]CPU, r)
+	for i := 0; i < int(r); i++ {
+		n := C.get_cpu_stat(cpustat, C.int(i))
+		if n != nil {
+			c[i] = perfstatcpu2cpu(n)
+		}
+	}
+	return c, nil
+}
+
+func CpuTotalStat() (*CPUTotal, error) {
+	var cpustat *C.perfstat_cpu_total_t
+
+	cpustat = (*C.perfstat_cpu_total_t)(C.malloc(C.sizeof_perfstat_cpu_total_t))
+	defer C.free(unsafe.Pointer(cpustat))
+	r := C.perfstat_cpu_total(nil, cpustat, C.sizeof_perfstat_cpu_total_t, 1)
+	if r <= 0 {
+		return nil, fmt.Errorf("error perfstat_cpu_total()")
+	}
+	c := perfstatcputotal2cputotal(cpustat)
+	return &c, nil
+}
+
+func CpuUtilStat(intvl time.Duration) (*CPUUtil, error) {
+	var cpuutil *C.perfstat_cpu_util_t
+	var newt *C.perfstat_cpu_total_t
+	var oldt *C.perfstat_cpu_total_t
+	var data C.perfstat_rawdata_t
+
+	oldt = (*C.perfstat_cpu_total_t)(C.malloc(C.sizeof_perfstat_cpu_total_t))
+	newt = (*C.perfstat_cpu_total_t)(C.malloc(C.sizeof_perfstat_cpu_total_t))
+	cpuutil = (*C.perfstat_cpu_util_t)(C.malloc(C.sizeof_perfstat_cpu_util_t))
+	defer C.free(unsafe.Pointer(oldt))
+	defer C.free(unsafe.Pointer(newt))
+	defer C.free(unsafe.Pointer(cpuutil))
+
+	r := C.perfstat_cpu_total(nil, oldt, C.sizeof_perfstat_cpu_total_t, 1)
+	if r <= 0 {
+		return nil, fmt.Errorf("error perfstat_cpu_total()")
+	}
+
+	time.Sleep(intvl)
+
+	r = C.perfstat_cpu_total(nil, newt, C.sizeof_perfstat_cpu_total_t, 1)
+	if r <= 0 {
+		return nil, fmt.Errorf("error perfstat_cpu_total()")
+	}
+
+	data._type = C.UTIL_CPU_TOTAL
+	data.curstat = unsafe.Pointer(newt)
+	data.prevstat = unsafe.Pointer(oldt)
+	data.sizeof_data = C.sizeof_perfstat_cpu_total_t
+	data.cur_elems = 1
+	data.prev_elems = 1
+
+	r = C.perfstat_cpu_util(&data, cpuutil, C.sizeof_perfstat_cpu_util_t, 1)
+	if r <= 0 {
+		return nil, fmt.Errorf("error perfstat_cpu_util()")
+	}
+	u := perfstatcpuutil2cpuutil(cpuutil)
+	return &u, nil
+}
+
+func CpuUtilTotalStat() (*CPUUtil, error) {
+	var cpuutil *C.perfstat_cpu_util_t
+	var new_cpu_total_stat *C.perfstat_cpu_total_t
+	var data C.perfstat_rawdata_t
+
+	new_cpu_total_stat = (*C.perfstat_cpu_total_t)(C.malloc(C.sizeof_perfstat_cpu_total_t))
+	cpuutil = (*C.perfstat_cpu_util_t)(C.malloc(C.sizeof_perfstat_cpu_util_t))
+	defer C.free(unsafe.Pointer(cpuutil))
+
+	r := C.perfstat_cpu_total(nil, new_cpu_total_stat, C.sizeof_perfstat_cpu_total_t, 1)
+	if r <= 0 {
+		C.free(unsafe.Pointer(new_cpu_total_stat))
+		return nil, fmt.Errorf("error perfstat_cpu_total()")
+	}
+
+	data._type = C.UTIL_CPU_TOTAL
+	data.curstat = unsafe.Pointer(new_cpu_total_stat)
+	data.prevstat = unsafe.Pointer(old_cpu_total_stat)
+	data.sizeof_data = C.sizeof_perfstat_cpu_total_t
+	data.cur_elems = 1
+	data.prev_elems = 1
+
+	r = C.perfstat_cpu_util(&data, cpuutil, C.sizeof_perfstat_cpu_util_t, 1)
+	C.free(unsafe.Pointer(old_cpu_total_stat))
+	old_cpu_total_stat = new_cpu_total_stat
+	if r <= 0 {
+		return nil, fmt.Errorf("error perfstat_cpu_util()")
+	}
+	u := perfstatcpuutil2cpuutil(cpuutil)
+	return &u, nil
+}
diff --git a/vendor/github.com/power-devops/perfstat/diskstat.go b/vendor/github.com/power-devops/perfstat/diskstat.go
new file mode 100644
index 000000000..06763b4bc
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/diskstat.go
@@ -0,0 +1,138 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+#include <string.h>
+#include <stdlib.h>
+#include "c_helpers.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+func DiskTotalStat() (*DiskTotal, error) {
+	var disk C.perfstat_disk_total_t
+
+	rc := C.perfstat_disk_total(nil, &disk, C.sizeof_perfstat_disk_total_t, 1)
+	if rc != 1 {
+		return nil, fmt.Errorf("perfstat_disk_total() error")
+	}
+	d := perfstatdisktotal2disktotal(disk)
+	return &d, nil
+}
+
+func DiskAdapterStat() ([]DiskAdapter, error) {
+	var adapter *C.perfstat_diskadapter_t
+	var adptname C.perfstat_id_t
+
+	numadpt := C.perfstat_diskadapter(nil, nil, C.sizeof_perfstat_diskadapter_t, 0)
+	if numadpt <= 0 {
+		return nil, fmt.Errorf("perfstat_diskadapter() error")
+	}
+
+	adapter_len := C.sizeof_perfstat_diskadapter_t * C.ulong(numadpt)
+	adapter = (*C.perfstat_diskadapter_t)(C.malloc(adapter_len))
+	defer C.free(unsafe.Pointer(adapter))
+	C.strcpy(&adptname.name[0], C.CString(C.FIRST_DISKADAPTER))
+	r := C.perfstat_diskadapter(&adptname, adapter, C.sizeof_perfstat_diskadapter_t, numadpt)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_diskadapter() error")
+	}
+	da := make([]DiskAdapter, r)
+	for i := 0; i < int(r); i++ {
+		d := C.get_diskadapter_stat(adapter, C.int(i))
+		if d != nil {
+			da[i] = perfstatdiskadapter2diskadapter(d)
+		}
+	}
+	return da, nil
+}
+
+func DiskStat() ([]Disk, error) {
+	var disk *C.perfstat_disk_t
+	var diskname C.perfstat_id_t
+
+	numdisk := C.perfstat_disk(nil, nil, C.sizeof_perfstat_disk_t, 0)
+	if numdisk <= 0 {
+		return nil, fmt.Errorf("perfstat_disk() error")
+	}
+
+	disk_len := C.sizeof_perfstat_disk_t * C.ulong(numdisk)
+	disk = (*C.perfstat_disk_t)(C.malloc(disk_len))
+	defer C.free(unsafe.Pointer(disk))
+	C.strcpy(&diskname.name[0], C.CString(C.FIRST_DISK))
+	r := C.perfstat_disk(&diskname, disk, C.sizeof_perfstat_disk_t, numdisk)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_disk() error")
+	}
+	d := make([]Disk, r)
+	for i := 0; i < int(r); i++ {
+		ds := C.get_disk_stat(disk, C.int(i))
+		if ds != nil {
+			d[i] = perfstatdisk2disk(ds)
+		}
+	}
+	return d, nil
+}
+
+func DiskPathStat() ([]DiskPath, error) {
+	var diskpath *C.perfstat_diskpath_t
+	var pathname C.perfstat_id_t
+
+	numpaths := C.perfstat_diskpath(nil, nil, C.sizeof_perfstat_diskpath_t, 0)
+	if numpaths <= 0 {
+		return nil, fmt.Errorf("perfstat_diskpath() error")
+	}
+
+	path_len := C.sizeof_perfstat_diskpath_t * C.ulong(numpaths)
+	diskpath = (*C.perfstat_diskpath_t)(C.malloc(path_len))
+	defer C.free(unsafe.Pointer(diskpath))
+	C.strcpy(&pathname.name[0], C.CString(C.FIRST_DISKPATH))
+	r := C.perfstat_diskpath(&pathname, diskpath, C.sizeof_perfstat_diskpath_t, numpaths)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_diskpath() error")
+	}
+	d := make([]DiskPath, r)
+	for i := 0; i < int(r); i++ {
+		p := C.get_diskpath_stat(diskpath, C.int(i))
+		if p != nil {
+			d[i] = perfstatdiskpath2diskpath(p)
+		}
+	}
+	return d, nil
+}
+
+func FCAdapterStat() ([]FCAdapter, error) {
+	var fcstat *C.perfstat_fcstat_t
+	var fcname C.perfstat_id_t
+
+	numadpt := C.perfstat_fcstat(nil, nil, C.sizeof_perfstat_fcstat_t, 0)
+	if numadpt <= 0 {
+		return nil, fmt.Errorf("perfstat_fcstat() error")
+	}
+
+	fcstat_len := C.sizeof_perfstat_fcstat_t * C.ulong(numadpt)
+	fcstat = (*C.perfstat_fcstat_t)(C.malloc(fcstat_len))
+	defer C.free(unsafe.Pointer(fcstat))
+	C.strcpy(&fcname.name[0], C.CString(C.FIRST_NETINTERFACE))
+	r := C.perfstat_fcstat(&fcname, fcstat, C.sizeof_perfstat_fcstat_t, numadpt)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_fcstat() error")
+	}
+	fca := make([]FCAdapter, r)
+	for i := 0; i < int(r); i++ {
+		f := C.get_fcstat_stat(fcstat, C.int(i))
+		if f != nil {
+			fca[i] = perfstatfcstat2fcadapter(f)
+		}
+	}
+	return fca, nil
+}
diff --git a/vendor/github.com/power-devops/perfstat/doc.go b/vendor/github.com/power-devops/perfstat/doc.go
new file mode 100644
index 000000000..9730a61c2
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/doc.go
@@ -0,0 +1,316 @@
+//go:build !aix
+// +build !aix
+
+// Copyright 2020 Power-Devops.com. All rights reserved.
+// Use of this source code is governed by the license
+// that can be found in the LICENSE file.
+/*
+Package perfstat is Go interface to IBM AIX libperfstat.
+To use it you need AIX with installed bos.perf.libperfstat. You can check, if is installed using the following command:
+
+	$ lslpp -L bos.perf.perfstat
+
+The package is written using Go 1.14.7 and AIX 7.2 TL5. It should work with earlier TLs of AIX 7.2, but I
+can't guarantee that perfstat structures in the TLs have all the same fields as the structures in AIX 7.2 TL5.
+
+For documentation of perfstat on AIX and using it in programs refer to the official IBM documentation:
+https://www.ibm.com/support/knowledgecenter/ssw_aix_72/performancetools/idprftools_perfstat.html
+*/
+package perfstat
+
+import (
+	"fmt"
+	"time"
+)
+
+// EnableLVMStat() switches on LVM (logical volumes and volume groups) performance statistics.
+// With this enabled you can use fields KBReads, KBWrites, and IOCnt
+// in LogicalVolume and VolumeGroup data types.
+func EnableLVMStat() {}
+
+// DisableLVMStat() switchess of LVM (logical volumes and volume groups) performance statistics.
+// This is the default state. In this case LogicalVolume and VolumeGroup data types are
+// populated with informations about LVM structures, but performance statistics fields
+// (KBReads, KBWrites, IOCnt) are empty.
+func DisableLVMStat() {}
+
+// CpuStat() returns array of CPU structures with information about
+// logical CPUs on the system.
+// IBM documentation:
+//   - https://www.ibm.com/support/knowledgecenter/ssw_aix_72/performancetools/idprftools_perfstat_int_cpu.html
+//   - https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/p_bostechref/perfstat_cpu.html
+func CpuStat() ([]CPU, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+// CpuTotalStat() returns general information about CPUs on the system.
+// IBM documentation:
+//   - https://www.ibm.com/support/knowledgecenter/ssw_aix_72/performancetools/idprftools_perfstat_glob_cpu.html
+//   - https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/p_bostechref/perfstat_cputot.html
+func CpuTotalStat() (*CPUTotal, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+// CpuUtilStat() calculates CPU utilization.
+// IBM documentation:
+//   - https://www.ibm.com/support/knowledgecenter/ssw_aix_72/performancetools/idprftools_perfstat_cpu_util.html
+//   - https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/p_bostechref/perfstat_cpu_util.html
+func CpuUtilStat(intvl time.Duration) (*CPUUtil, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func DiskTotalStat() (*DiskTotal, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func DiskAdapterStat() ([]DiskAdapter, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func DiskStat() ([]Disk, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func DiskPathStat() ([]DiskPath, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func FCAdapterStat() ([]FCAdapter, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func PartitionStat() (*PartitionConfig, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func LogicalVolumeStat() ([]LogicalVolume, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func VolumeGroupStat() ([]VolumeGroup, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func MemoryTotalStat() (*MemoryTotal, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func MemoryPageStat() ([]MemoryPage, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func PagingSpaceStat() ([]PagingSpace, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func NetIfaceTotalStat() (*NetIfaceTotal, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func NetBufferStat() ([]NetBuffer, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func NetIfaceStat() ([]NetIface, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func NetAdapterStat() ([]NetAdapter, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func ProcessStat() ([]Process, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func ThreadStat() ([]Thread, error) {
+	return nil, fmt.Errorf("not implemented")
+}
+
+func Sysconf(name int32) (int64, error) {
+	return 0, fmt.Errorf("not implemented")
+}
+
+func GetCPUImplementation() string {
+	return ""
+}
+
+func POWER9OrNewer() bool {
+	return false
+}
+
+func POWER9() bool {
+	return false
+}
+
+func POWER8OrNewer() bool {
+	return false
+}
+
+func POWER8() bool {
+	return false
+}
+
+func POWER7OrNewer() bool {
+	return false
+}
+
+func POWER7() bool {
+	return false
+}
+
+func HasTransactionalMemory() bool {
+	return false
+}
+
+func Is64Bit() bool {
+	return false
+}
+
+func IsSMP() bool {
+	return false
+}
+
+func HasVMX() bool {
+	return false
+}
+
+func HasVSX() bool {
+	return false
+}
+
+func HasDFP() bool {
+	return false
+}
+
+func HasNxGzip() bool {
+	return false
+}
+
+func PksCapable() bool {
+	return false
+}
+
+func PksEnabled() bool {
+	return false
+}
+
+func CPUMode() string {
+	return ""
+}
+
+func KernelBits() int {
+	return 0
+}
+
+func IsLPAR() bool {
+	return false
+}
+
+func CpuAddCapable() bool {
+	return false
+}
+
+func CpuRemoveCapable() bool {
+	return false
+}
+
+func MemoryAddCapable() bool {
+	return false
+}
+
+func MemoryRemoveCapable() bool {
+	return false
+}
+
+func DLparCapable() bool {
+	return false
+}
+
+func IsNUMA() bool {
+	return false
+}
+
+func KernelKeys() bool {
+	return false
+}
+
+func RecoveryMode() bool {
+	return false
+}
+
+func EnhancedAffinity() bool {
+	return false
+}
+
+func VTpmEnabled() bool {
+	return false
+}
+
+func IsVIOS() bool {
+	return false
+}
+
+func MLSEnabled() bool {
+	return false
+}
+
+func SPLparCapable() bool {
+	return false
+}
+
+func SPLparEnabled() bool {
+	return false
+}
+
+func DedicatedLpar() bool {
+	return false
+}
+
+func SPLparCapped() bool {
+	return false
+}
+
+func SPLparDonating() bool {
+	return false
+}
+
+func SmtCapable() bool {
+	return false
+}
+
+func SmtEnabled() bool {
+	return false
+}
+
+func VrmCapable() bool {
+	return false
+}
+
+func VrmEnabled() bool {
+	return false
+}
+
+func AmeEnabled() bool {
+	return false
+}
+
+func EcoCapable() bool {
+	return false
+}
+
+func EcoEnabled() bool {
+	return false
+}
+
+func BootTime() (uint64, error) {
+	return 0, fmt.Errorf("Not implemented")
+}
+
+func UptimeSeconds() (uint64, error) {
+	return 0, fmt.Errorf("Not implemented")
+}
+
+func FileSystemStat() ([]FileSystem, error) {
+	return nil, fmt.Errorf("Not implemented")
+}
diff --git a/vendor/github.com/power-devops/perfstat/fsstat.go b/vendor/github.com/power-devops/perfstat/fsstat.go
new file mode 100644
index 000000000..d3913197a
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/fsstat.go
@@ -0,0 +1,32 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#include "c_helpers.h"
+*/
+import "C"
+
+import (
+	"fmt"
+)
+
+func FileSystemStat() ([]FileSystem, error) {
+	var fsinfo *C.struct_fsinfo
+	var nmounts C.int
+
+	fsinfo = C.get_all_fs(&nmounts)
+	if nmounts <= 0 {
+		return nil, fmt.Errorf("No mounts found")
+	}
+
+	fs := make([]FileSystem, nmounts)
+	for i := 0; i < int(nmounts); i++ {
+		f := C.get_filesystem_stat(fsinfo, C.int(i))
+		if f != nil {
+			fs[i] = fsinfo2filesystem(f)
+		}
+	}
+	return fs, nil
+}
diff --git a/vendor/github.com/power-devops/perfstat/helpers.go b/vendor/github.com/power-devops/perfstat/helpers.go
new file mode 100644
index 000000000..d5268ab53
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/helpers.go
@@ -0,0 +1,819 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+#include <sys/proc.h>
+#include <sys/dr.h>
+
+#include "c_helpers.h"
+*/
+import "C"
+
+func perfstatcpu2cpu(n *C.perfstat_cpu_t) CPU {
+	var c CPU
+	c.Name = C.GoString(&n.name[0])
+	c.User = int64(n.user)
+	c.Sys = int64(n.sys)
+	c.Idle = int64(n.idle)
+	c.Wait = int64(n.wait)
+	c.PSwitch = int64(n.pswitch)
+	c.Syscall = int64(n.syscall)
+	c.Sysread = int64(n.sysread)
+	c.Syswrite = int64(n.syswrite)
+	c.Sysfork = int64(n.sysfork)
+	c.Sysexec = int64(n.sysexec)
+	c.Readch = int64(n.readch)
+	c.Writech = int64(n.writech)
+	c.Bread = int64(n.bread)
+	c.Bwrite = int64(n.bwrite)
+	c.Lread = int64(n.lread)
+	c.Lwrite = int64(n.lwrite)
+	c.Phread = int64(n.phread)
+	c.Phwrite = int64(n.phwrite)
+	c.Iget = int64(n.iget)
+	c.Namei = int64(n.namei)
+	c.Dirblk = int64(n.dirblk)
+	c.Msg = int64(n.msg)
+	c.Sema = int64(n.sema)
+	c.MinFaults = int64(n.minfaults)
+	c.MajFaults = int64(n.majfaults)
+	c.PUser = int64(n.puser)
+	c.PSys = int64(n.psys)
+	c.PIdle = int64(n.pidle)
+	c.PWait = int64(n.pwait)
+	c.RedispSD0 = int64(n.redisp_sd0)
+	c.RedispSD1 = int64(n.redisp_sd1)
+	c.RedispSD2 = int64(n.redisp_sd2)
+	c.RedispSD3 = int64(n.redisp_sd3)
+	c.RedispSD4 = int64(n.redisp_sd4)
+	c.RedispSD5 = int64(n.redisp_sd5)
+	c.MigrationPush = int64(n.migration_push)
+	c.MigrationS3grq = int64(n.migration_S3grq)
+	c.MigrationS3pul = int64(n.migration_S3pul)
+	c.InvolCSwitch = int64(n.invol_cswitch)
+	c.VolCSwitch = int64(n.vol_cswitch)
+	c.RunQueue = int64(n.runque)
+	c.Bound = int64(n.bound)
+	c.DecrIntrs = int64(n.decrintrs)
+	c.MpcRIntrs = int64(n.mpcrintrs)
+	c.MpcSIntrs = int64(n.mpcsintrs)
+	c.SoftIntrs = int64(n.softintrs)
+	c.DevIntrs = int64(n.devintrs)
+	c.PhantIntrs = int64(n.phantintrs)
+	c.IdleDonatedPurr = int64(n.idle_donated_purr)
+	c.IdleDonatedSpurr = int64(n.idle_donated_spurr)
+	c.BusyDonatedPurr = int64(n.busy_donated_purr)
+	c.BusyDonatedSpurr = int64(n.busy_donated_spurr)
+	c.IdleStolenPurr = int64(n.idle_stolen_purr)
+	c.IdleStolenSpurr = int64(n.idle_stolen_spurr)
+	c.BusyStolenPurr = int64(n.busy_stolen_purr)
+	c.BusyStolenSpurr = int64(n.busy_stolen_spurr)
+	c.Hpi = int64(n.hpi)
+	c.Hpit = int64(n.hpit)
+	c.PUserSpurr = int64(n.puser_spurr)
+	c.PSysSpurr = int64(n.psys_spurr)
+	c.PIdleSpurr = int64(n.pidle_spurr)
+	c.PWaitSpurr = int64(n.pwait_spurr)
+	c.SpurrFlag = int32(n.spurrflag)
+	c.LocalDispatch = int64(n.localdispatch)
+	c.NearDispatch = int64(n.neardispatch)
+	c.FarDispatch = int64(n.fardispatch)
+	c.CSwitches = int64(n.cswitches)
+	c.Version = int64(n.version)
+	c.TbLast = int64(n.tb_last)
+	c.State = int(n.state)
+	c.VtbLast = int64(n.vtb_last)
+	c.ICountLast = int64(n.icount_last)
+	return c
+}
+
+func perfstatcputotal2cputotal(n *C.perfstat_cpu_total_t) CPUTotal {
+	var c CPUTotal
+	c.NCpus = int(n.ncpus)
+	c.NCpusCfg = int(n.ncpus_cfg)
+	c.Description = C.GoString(&n.description[0])
+	c.ProcessorHz = int64(n.processorHZ)
+	c.User = int64(n.user)
+	c.Sys = int64(n.sys)
+	c.Idle = int64(n.idle)
+	c.Wait = int64(n.wait)
+	c.PSwitch = int64(n.pswitch)
+	c.Syscall = int64(n.syscall)
+	c.Sysread = int64(n.sysread)
+	c.Syswrite = int64(n.syswrite)
+	c.Sysfork = int64(n.sysfork)
+	c.Sysexec = int64(n.sysexec)
+	c.Readch = int64(n.readch)
+	c.Writech = int64(n.writech)
+	c.DevIntrs = int64(n.devintrs)
+	c.SoftIntrs = int64(n.softintrs)
+	c.Lbolt = int64(n.lbolt)
+	c.LoadAvg1 = (float32(n.loadavg[0]) / (1 << C.SBITS))
+	c.LoadAvg5 = (float32(n.loadavg[1]) / (1 << C.SBITS))
+	c.LoadAvg15 = (float32(n.loadavg[2]) / (1 << C.SBITS))
+	c.RunQueue = int64(n.runque)
+	c.SwpQueue = int64(n.swpque)
+	c.Bread = int64(n.bread)
+	c.Bwrite = int64(n.bwrite)
+	c.Lread = int64(n.lread)
+	c.Lwrite = int64(n.lwrite)
+	c.Phread = int64(n.phread)
+	c.Phwrite = int64(n.phwrite)
+	c.RunOcc = int64(n.runocc)
+	c.SwpOcc = int64(n.swpocc)
+	c.Iget = int64(n.iget)
+	c.Namei = int64(n.namei)
+	c.Dirblk = int64(n.dirblk)
+	c.Msg = int64(n.msg)
+	c.Sema = int64(n.sema)
+	c.RcvInt = int64(n.rcvint)
+	c.XmtInt = int64(n.xmtint)
+	c.MdmInt = int64(n.mdmint)
+	c.TtyRawInch = int64(n.tty_rawinch)
+	c.TtyCanInch = int64(n.tty_caninch)
+	c.TtyRawOutch = int64(n.tty_rawoutch)
+	c.Ksched = int64(n.ksched)
+	c.Koverf = int64(n.koverf)
+	c.Kexit = int64(n.kexit)
+	c.Rbread = int64(n.rbread)
+	c.Rcread = int64(n.rcread)
+	c.Rbwrt = int64(n.rbwrt)
+	c.Rcwrt = int64(n.rcwrt)
+	c.Traps = int64(n.traps)
+	c.NCpusHigh = int64(n.ncpus_high)
+	c.PUser = int64(n.puser)
+	c.PSys = int64(n.psys)
+	c.PIdle = int64(n.pidle)
+	c.PWait = int64(n.pwait)
+	c.DecrIntrs = int64(n.decrintrs)
+	c.MpcRIntrs = int64(n.mpcrintrs)
+	c.MpcSIntrs = int64(n.mpcsintrs)
+	c.PhantIntrs = int64(n.phantintrs)
+	c.IdleDonatedPurr = int64(n.idle_donated_purr)
+	c.IdleDonatedSpurr = int64(n.idle_donated_spurr)
+	c.BusyDonatedPurr = int64(n.busy_donated_purr)
+	c.BusyDonatedSpurr = int64(n.busy_donated_spurr)
+	c.IdleStolenPurr = int64(n.idle_stolen_purr)
+	c.IdleStolenSpurr = int64(n.idle_stolen_spurr)
+	c.BusyStolenPurr = int64(n.busy_stolen_purr)
+	c.BusyStolenSpurr = int64(n.busy_stolen_spurr)
+	c.IOWait = int32(n.iowait)
+	c.PhysIO = int32(n.physio)
+	c.TWait = int64(n.twait)
+	c.Hpi = int64(n.hpi)
+	c.Hpit = int64(n.hpit)
+	c.PUserSpurr = int64(n.puser_spurr)
+	c.PSysSpurr = int64(n.psys_spurr)
+	c.PIdleSpurr = int64(n.pidle_spurr)
+	c.PWaitSpurr = int64(n.pwait_spurr)
+	c.SpurrFlag = int(n.spurrflag)
+	c.Version = int64(n.version)
+	c.TbLast = int64(n.tb_last)
+	c.PurrCoalescing = int64(n.purr_coalescing)
+	c.SpurrCoalescing = int64(n.spurr_coalescing)
+	return c
+}
+
+func perfstatcpuutil2cpuutil(n *C.perfstat_cpu_util_t) CPUUtil {
+	var c CPUUtil
+
+	c.Version = int64(n.version)
+	c.CpuID = C.GoString(&n.cpu_id[0])
+	c.Entitlement = float32(n.entitlement)
+	c.UserPct = float32(n.user_pct)
+	c.KernPct = float32(n.kern_pct)
+	c.IdlePct = float32(n.idle_pct)
+	c.WaitPct = float32(n.wait_pct)
+	c.PhysicalBusy = float32(n.physical_busy)
+	c.PhysicalConsumed = float32(n.physical_consumed)
+	c.FreqPct = float32(n.freq_pct)
+	c.EntitlementPct = float32(n.entitlement_pct)
+	c.BusyPct = float32(n.busy_pct)
+	c.IdleDonatedPct = float32(n.idle_donated_pct)
+	c.BusyDonatedPct = float32(n.busy_donated_pct)
+	c.IdleStolenPct = float32(n.idle_stolen_pct)
+	c.BusyStolenPct = float32(n.busy_stolen_pct)
+	c.LUserPct = float32(n.l_user_pct)
+	c.LKernPct = float32(n.l_kern_pct)
+	c.LIdlePct = float32(n.l_idle_pct)
+	c.LWaitPct = float32(n.l_wait_pct)
+	c.DeltaTime = int64(n.delta_time)
+
+	return c
+}
+
+func perfstatdisktotal2disktotal(n C.perfstat_disk_total_t) DiskTotal {
+	var d DiskTotal
+
+	d.Number = int32(n.number)
+	d.Size = int64(n.size)
+	d.Free = int64(n.free)
+	d.XRate = int64(n.xrate)
+	d.Xfers = int64(n.xfers)
+	d.Wblks = int64(n.wblks)
+	d.Rblks = int64(n.rblks)
+	d.Time = int64(n.time)
+	d.Version = int64(n.version)
+	d.Rserv = int64(n.rserv)
+	d.MinRserv = int64(n.min_rserv)
+	d.MaxRserv = int64(n.max_rserv)
+	d.RTimeOut = int64(n.rtimeout)
+	d.RFailed = int64(n.rfailed)
+	d.Wserv = int64(n.wserv)
+	d.MinWserv = int64(n.min_wserv)
+	d.MaxWserv = int64(n.max_wserv)
+	d.WTimeOut = int64(n.wtimeout)
+	d.WFailed = int64(n.wfailed)
+	d.WqDepth = int64(n.wq_depth)
+	d.WqTime = int64(n.wq_time)
+	d.WqMinTime = int64(n.wq_min_time)
+	d.WqMaxTime = int64(n.wq_max_time)
+
+	return d
+}
+
+func perfstatdiskadapter2diskadapter(n *C.perfstat_diskadapter_t) DiskAdapter {
+	var d DiskAdapter
+
+	d.Name = C.GoString(&n.name[0])
+	d.Description = C.GoString(&n.description[0])
+	d.Number = int32(n.number)
+	d.Size = int64(n.size)
+	d.Free = int64(n.free)
+	d.XRate = int64(n.xrate)
+	d.Xfers = int64(n.xfers)
+	d.Rblks = int64(n.rblks)
+	d.Wblks = int64(n.wblks)
+	d.Time = int64(n.time)
+	d.Version = int64(n.version)
+	d.AdapterType = int64(n.adapter_type)
+	d.DkBSize = int64(n.dk_bsize)
+	d.DkRserv = int64(n.dk_rserv)
+	d.DkWserv = int64(n.dk_wserv)
+	d.MinRserv = int64(n.min_rserv)
+	d.MaxRserv = int64(n.max_rserv)
+	d.MinWserv = int64(n.min_wserv)
+	d.MaxWserv = int64(n.max_wserv)
+	d.WqDepth = int64(n.wq_depth)
+	d.WqSampled = int64(n.wq_sampled)
+	d.WqTime = int64(n.wq_time)
+	d.WqMinTime = int64(n.wq_min_time)
+	d.WqMaxTime = int64(n.wq_max_time)
+	d.QFull = int64(n.q_full)
+	d.QSampled = int64(n.q_sampled)
+
+	return d
+}
+
+func perfstatpartitionconfig2partitionconfig(n C.perfstat_partition_config_t) PartitionConfig {
+	var p PartitionConfig
+	p.Version = int64(n.version)
+	p.Name = C.GoString(&n.partitionname[0])
+	p.Node = C.GoString(&n.nodename[0])
+	p.Conf.SmtCapable = (n.conf[0] & (1 << 7)) > 0
+	p.Conf.SmtEnabled = (n.conf[0] & (1 << 6)) > 0
+	p.Conf.LparCapable = (n.conf[0] & (1 << 5)) > 0
+	p.Conf.LparEnabled = (n.conf[0] & (1 << 4)) > 0
+	p.Conf.SharedCapable = (n.conf[0] & (1 << 3)) > 0
+	p.Conf.SharedEnabled = (n.conf[0] & (1 << 2)) > 0
+	p.Conf.DLparCapable = (n.conf[0] & (1 << 1)) > 0
+	p.Conf.Capped = (n.conf[0] & (1 << 0)) > 0
+	p.Conf.Kernel64bit = (n.conf[1] & (1 << 7)) > 0
+	p.Conf.PoolUtilAuthority = (n.conf[1] & (1 << 6)) > 0
+	p.Conf.DonateCapable = (n.conf[1] & (1 << 5)) > 0
+	p.Conf.DonateEnabled = (n.conf[1] & (1 << 4)) > 0
+	p.Conf.AmsCapable = (n.conf[1] & (1 << 3)) > 0
+	p.Conf.AmsEnabled = (n.conf[1] & (1 << 2)) > 0
+	p.Conf.PowerSave = (n.conf[1] & (1 << 1)) > 0
+	p.Conf.AmeEnabled = (n.conf[1] & (1 << 0)) > 0
+	p.Conf.SharedExtended = (n.conf[2] & (1 << 7)) > 0
+	p.Number = int32(n.partitionnum)
+	p.GroupID = int32(n.groupid)
+	p.ProcessorFamily = C.GoString(&n.processorFamily[0])
+	p.ProcessorModel = C.GoString(&n.processorModel[0])
+	p.MachineID = C.GoString(&n.machineID[0])
+	p.ProcessorMhz = float64(C.get_partition_mhz(n))
+	p.NumProcessors.Online = int64(n.numProcessors.online)
+	p.NumProcessors.Max = int64(n.numProcessors.max)
+	p.NumProcessors.Min = int64(n.numProcessors.min)
+	p.NumProcessors.Desired = int64(n.numProcessors.desired)
+	p.OSName = C.GoString(&n.OSName[0])
+	p.OSVersion = C.GoString(&n.OSVersion[0])
+	p.OSBuild = C.GoString(&n.OSBuild[0])
+	p.LCpus = int32(n.lcpus)
+	p.SmtThreads = int32(n.smtthreads)
+	p.Drives = int32(n.drives)
+	p.NetworkAdapters = int32(n.nw_adapters)
+	p.CpuCap.Online = int64(n.cpucap.online)
+	p.CpuCap.Max = int64(n.cpucap.max)
+	p.CpuCap.Min = int64(n.cpucap.min)
+	p.CpuCap.Desired = int64(n.cpucap.desired)
+	p.Weightage = int32(n.cpucap_weightage)
+	p.EntCapacity = int32(n.entitled_proc_capacity)
+	p.VCpus.Online = int64(n.vcpus.online)
+	p.VCpus.Max = int64(n.vcpus.max)
+	p.VCpus.Min = int64(n.vcpus.min)
+	p.VCpus.Desired = int64(n.vcpus.desired)
+	p.PoolID = int32(n.processor_poolid)
+	p.ActiveCpusInPool = int32(n.activecpusinpool)
+	p.PoolWeightage = int32(n.cpupool_weightage)
+	p.SharedPCpu = int32(n.sharedpcpu)
+	p.MaxPoolCap = int32(n.maxpoolcap)
+	p.EntPoolCap = int32(n.entpoolcap)
+	p.Mem.Online = int64(n.mem.online)
+	p.Mem.Max = int64(n.mem.max)
+	p.Mem.Min = int64(n.mem.min)
+	p.Mem.Desired = int64(n.mem.desired)
+	p.MemWeightage = int32(n.mem_weightage)
+	p.TotalIOMemoryEntitlement = int64(n.totiomement)
+	p.MemPoolID = int32(n.mempoolid)
+	p.HyperPgSize = int64(n.hyperpgsize)
+	p.ExpMem.Online = int64(n.exp_mem.online)
+	p.ExpMem.Max = int64(n.exp_mem.max)
+	p.ExpMem.Min = int64(n.exp_mem.min)
+	p.ExpMem.Desired = int64(n.exp_mem.desired)
+	p.TargetMemExpFactor = int64(n.targetmemexpfactor)
+	p.TargetMemExpSize = int64(n.targetmemexpsize)
+	p.SubProcessorMode = int32(n.subprocessor_mode)
+	return p
+}
+
+func perfstatmemorytotal2memorytotal(n C.perfstat_memory_total_t) MemoryTotal {
+	var m MemoryTotal
+	m.VirtualTotal = int64(n.virt_total)
+	m.RealTotal = int64(n.real_total)
+	m.RealFree = int64(n.real_free)
+	m.RealPinned = int64(n.real_pinned)
+	m.RealInUse = int64(n.real_inuse)
+	m.BadPages = int64(n.pgbad)
+	m.PageFaults = int64(n.pgexct)
+	m.PageIn = int64(n.pgins)
+	m.PageOut = int64(n.pgouts)
+	m.PgSpIn = int64(n.pgspins)
+	m.PgSpOut = int64(n.pgspouts)
+	m.Scans = int64(n.scans)
+	m.Cycles = int64(n.cycles)
+	m.PgSteals = int64(n.pgsteals)
+	m.NumPerm = int64(n.numperm)
+	m.PgSpTotal = int64(n.pgsp_total)
+	m.PgSpFree = int64(n.pgsp_free)
+	m.PgSpRsvd = int64(n.pgsp_rsvd)
+	m.RealSystem = int64(n.real_system)
+	m.RealUser = int64(n.real_user)
+	m.RealProcess = int64(n.real_process)
+	m.VirtualActive = int64(n.virt_active)
+	m.IOME = int64(n.iome)
+	m.IOMU = int64(n.iomu)
+	m.IOHWM = int64(n.iohwm)
+	m.PMem = int64(n.pmem)
+	m.CompressedTotal = int64(n.comprsd_total)
+	m.CompressedWSegPg = int64(n.comprsd_wseg_pgs)
+	m.CPgIn = int64(n.cpgins)
+	m.CPgOut = int64(n.cpgouts)
+	m.TrueSize = int64(n.true_size)
+	m.ExpandedMemory = int64(n.expanded_memory)
+	m.CompressedWSegSize = int64(n.comprsd_wseg_size)
+	m.TargetCPoolSize = int64(n.target_cpool_size)
+	m.MaxCPoolSize = int64(n.max_cpool_size)
+	m.MinUCPoolSize = int64(n.min_ucpool_size)
+	m.CPoolSize = int64(n.cpool_size)
+	m.UCPoolSize = int64(n.ucpool_size)
+	m.CPoolInUse = int64(n.cpool_inuse)
+	m.UCPoolInUse = int64(n.ucpool_inuse)
+	m.Version = int64(n.version)
+	m.RealAvailable = int64(n.real_avail)
+	m.BytesCoalesced = int64(n.bytes_coalesced)
+	m.BytesCoalescedMemPool = int64(n.bytes_coalesced_mempool)
+
+	return m
+}
+
+func perfstatnetinterfacetotal2netifacetotal(n C.perfstat_netinterface_total_t) NetIfaceTotal {
+	var i NetIfaceTotal
+
+	i.Number = int32(n.number)
+	i.IPackets = int64(n.ipackets)
+	i.IBytes = int64(n.ibytes)
+	i.IErrors = int64(n.ierrors)
+	i.OPackets = int64(n.opackets)
+	i.OBytes = int64(n.obytes)
+	i.OErrors = int64(n.oerrors)
+	i.Collisions = int64(n.collisions)
+	i.XmitDrops = int64(n.xmitdrops)
+	i.Version = int64(n.version)
+
+	return i
+}
+
+func perfstatdisk2disk(n *C.perfstat_disk_t) Disk {
+	var d Disk
+
+	d.Name = C.GoString(&n.name[0])
+	d.Description = C.GoString(&n.description[0])
+	d.VGName = C.GoString(&n.vgname[0])
+	d.Size = int64(n.size)
+	d.Free = int64(n.free)
+	d.BSize = int64(n.bsize)
+	d.XRate = int64(n.xrate)
+	d.Xfers = int64(n.xfers)
+	d.Wblks = int64(n.wblks)
+	d.Rblks = int64(n.rblks)
+	d.QDepth = int64(n.qdepth)
+	d.Time = int64(n.time)
+	d.Adapter = C.GoString(&n.adapter[0])
+	d.PathsCount = int32(n.paths_count)
+	d.QFull = int64(n.q_full)
+	d.Rserv = int64(n.rserv)
+	d.RTimeOut = int64(n.rtimeout)
+	d.Rfailed = int64(n.rfailed)
+	d.MinRserv = int64(n.min_rserv)
+	d.MaxRserv = int64(n.max_rserv)
+	d.Wserv = int64(n.wserv)
+	d.WTimeOut = int64(n.wtimeout)
+	d.Wfailed = int64(n.wfailed)
+	d.MinWserv = int64(n.min_wserv)
+	d.MaxWserv = int64(n.max_wserv)
+	d.WqDepth = int64(n.wq_depth)
+	d.WqSampled = int64(n.wq_sampled)
+	d.WqTime = int64(n.wq_time)
+	d.WqMinTime = int64(n.wq_min_time)
+	d.WqMaxTime = int64(n.wq_max_time)
+	d.QSampled = int64(n.q_sampled)
+	d.Version = int64(n.version)
+	d.PseudoDisk = (n.dk_type[0] & (1 << 7)) > 0
+	d.VTDisk = (n.dk_type[0] & (1 << 6)) > 0
+
+	return d
+}
+
+func perfstatdiskpath2diskpath(n *C.perfstat_diskpath_t) DiskPath {
+	var d DiskPath
+
+	d.Name = C.GoString(&n.name[0])
+	d.XRate = int64(n.xrate)
+	d.Xfers = int64(n.xfers)
+	d.Rblks = int64(n.rblks)
+	d.Wblks = int64(n.wblks)
+	d.Time = int64(n.time)
+	d.Adapter = C.GoString(&n.adapter[0])
+	d.QFull = int64(n.q_full)
+	d.Rserv = int64(n.rserv)
+	d.RTimeOut = int64(n.rtimeout)
+	d.Rfailed = int64(n.rfailed)
+	d.MinRserv = int64(n.min_rserv)
+	d.MaxRserv = int64(n.max_rserv)
+	d.Wserv = int64(n.wserv)
+	d.WTimeOut = int64(n.wtimeout)
+	d.Wfailed = int64(n.wfailed)
+	d.MinWserv = int64(n.min_wserv)
+	d.MaxWserv = int64(n.max_wserv)
+	d.WqDepth = int64(n.wq_depth)
+	d.WqSampled = int64(n.wq_sampled)
+	d.WqTime = int64(n.wq_time)
+	d.WqMinTime = int64(n.wq_min_time)
+	d.WqMaxTime = int64(n.wq_max_time)
+	d.QSampled = int64(n.q_sampled)
+	d.Version = int64(n.version)
+
+	return d
+}
+
+func perfstatfcstat2fcadapter(n *C.perfstat_fcstat_t) FCAdapter {
+	var f FCAdapter
+
+	f.Version = int64(n.version)
+	f.Name = C.GoString(&n.name[0])
+	f.State = int32(n.state)
+	f.InputRequests = int64(n.InputRequests)
+	f.OutputRequests = int64(n.OutputRequests)
+	f.InputBytes = int64(n.InputBytes)
+	f.OutputBytes = int64(n.OutputBytes)
+	f.EffMaxTransfer = int64(n.EffMaxTransfer)
+	f.NoDMAResourceCnt = int64(n.NoDMAResourceCnt)
+	f.NoCmdResourceCnt = int64(n.NoCmdResourceCnt)
+	f.AttentionType = int32(n.AttentionType)
+	f.SecondsSinceLastReset = int64(n.SecondsSinceLastReset)
+	f.TxFrames = int64(n.TxFrames)
+	f.TxWords = int64(n.TxWords)
+	f.RxFrames = int64(n.RxFrames)
+	f.RxWords = int64(n.RxWords)
+	f.LIPCount = int64(n.LIPCount)
+	f.NOSCount = int64(n.NOSCount)
+	f.ErrorFrames = int64(n.ErrorFrames)
+	f.DumpedFrames = int64(n.DumpedFrames)
+	f.LinkFailureCount = int64(n.LinkFailureCount)
+	f.LossofSyncCount = int64(n.LossofSyncCount)
+	f.LossofSignal = int64(n.LossofSignal)
+	f.PrimitiveSeqProtocolErrCount = int64(n.PrimitiveSeqProtocolErrCount)
+	f.InvalidTxWordCount = int64(n.InvalidTxWordCount)
+	f.InvalidCRCCount = int64(n.InvalidCRCCount)
+	f.PortFcId = int64(n.PortFcId)
+	f.PortSpeed = int64(n.PortSpeed)
+	f.PortType = C.GoString(&n.PortType[0])
+	f.PortWWN = int64(n.PortWWN)
+	f.PortSupportedSpeed = int64(n.PortSupportedSpeed)
+	f.AdapterType = int(n.adapter_type)
+	f.VfcName = C.GoString(&n.vfc_name[0])
+	f.ClientPartName = C.GoString(&n.client_part_name[0])
+
+	return f
+}
+
+func perfstatlogicalvolume2logicalvolume(n *C.perfstat_logicalvolume_t) LogicalVolume {
+	var l LogicalVolume
+
+	l.Name = C.GoString(&n.name[0])
+	l.VGName = C.GoString(&n.vgname[0])
+	l.OpenClose = int64(n.open_close)
+	l.State = int64(n.state)
+	l.MirrorPolicy = int64(n.mirror_policy)
+	l.MirrorWriteConsistency = int64(n.mirror_write_consistency)
+	l.WriteVerify = int64(n.write_verify)
+	l.PPsize = int64(n.ppsize)
+	l.LogicalPartitions = int64(n.logical_partitions)
+	l.Mirrors = int32(n.mirrors)
+	l.IOCnt = int64(n.iocnt)
+	l.KBReads = int64(n.kbreads)
+	l.KBWrites = int64(n.kbwrites)
+	l.Version = int64(n.version)
+
+	return l
+}
+
+func perfstatvolumegroup2volumegroup(n *C.perfstat_volumegroup_t) VolumeGroup {
+	var v VolumeGroup
+
+	v.Name = C.GoString(&n.name[0])
+	v.TotalDisks = int64(n.total_disks)
+	v.ActiveDisks = int64(n.active_disks)
+	v.TotalLogicalVolumes = int64(n.total_logical_volumes)
+	v.OpenedLogicalVolumes = int64(n.opened_logical_volumes)
+	v.IOCnt = int64(n.iocnt)
+	v.KBReads = int64(n.kbreads)
+	v.KBWrites = int64(n.kbwrites)
+	v.Version = int64(n.version)
+	v.VariedState = int(n.variedState)
+
+	return v
+}
+
+func perfstatmemorypage2memorypage(n *C.perfstat_memory_page_t) MemoryPage {
+	var m MemoryPage
+
+	m.PSize = int64(n.psize)
+	m.RealTotal = int64(n.real_total)
+	m.RealFree = int64(n.real_free)
+	m.RealPinned = int64(n.real_pinned)
+	m.RealInUse = int64(n.real_inuse)
+	m.PgExct = int64(n.pgexct)
+	m.PgIns = int64(n.pgins)
+	m.PgOuts = int64(n.pgouts)
+	m.PgSpIns = int64(n.pgspins)
+	m.PgSpOuts = int64(n.pgspouts)
+	m.Scans = int64(n.scans)
+	m.Cycles = int64(n.cycles)
+	m.PgSteals = int64(n.pgsteals)
+	m.NumPerm = int64(n.numperm)
+	m.NumPgSp = int64(n.numpgsp)
+	m.RealSystem = int64(n.real_system)
+	m.RealUser = int64(n.real_user)
+	m.RealProcess = int64(n.real_process)
+	m.VirtActive = int64(n.virt_active)
+	m.ComprsdTotal = int64(n.comprsd_total)
+	m.ComprsdWsegPgs = int64(n.comprsd_wseg_pgs)
+	m.CPgIns = int64(n.cpgins)
+	m.CPgOuts = int64(n.cpgouts)
+	m.CPoolInUse = int64(n.cpool_inuse)
+	m.UCPoolSize = int64(n.ucpool_size)
+	m.ComprsdWsegSize = int64(n.comprsd_wseg_size)
+	m.Version = int64(n.version)
+	m.RealAvail = int64(n.real_avail)
+
+	return m
+}
+
+func perfstatnetbuffer2netbuffer(n *C.perfstat_netbuffer_t) NetBuffer {
+	var b NetBuffer
+
+	b.Name = C.GoString(&n.name[0])
+	b.InUse = int64(n.inuse)
+	b.Calls = int64(n.calls)
+	b.Delayed = int64(n.delayed)
+	b.Free = int64(n.free)
+	b.Failed = int64(n.failed)
+	b.HighWatermark = int64(n.highwatermark)
+	b.Freed = int64(n.freed)
+	b.Version = int64(n.version)
+
+	return b
+}
+
+func perfstatnetinterface2netiface(n *C.perfstat_netinterface_t) NetIface {
+	var i NetIface
+
+	i.Name = C.GoString(&n.name[0])
+	i.Description = C.GoString(&n.description[0])
+	i.Type = uint8(n._type)
+	i.MTU = int64(n.mtu)
+	i.IPackets = int64(n.ipackets)
+	i.IBytes = int64(n.ibytes)
+	i.IErrors = int64(n.ierrors)
+	i.OPackets = int64(n.opackets)
+	i.OBytes = int64(n.obytes)
+	i.OErrors = int64(n.oerrors)
+	i.Collisions = int64(n.collisions)
+	i.Bitrate = int64(n.bitrate)
+	i.XmitDrops = int64(n.xmitdrops)
+	i.Version = int64(n.version)
+	i.IfIqDrops = int64(n.if_iqdrops)
+	i.IfArpDrops = int64(n.if_arpdrops)
+
+	return i
+}
+
+func perfstatnetadapter2netadapter(n *C.perfstat_netadapter_t) NetAdapter {
+	var i NetAdapter
+
+	i.Version = int64(n.version)
+	i.Name = C.GoString(&n.name[0])
+	i.TxPackets = int64(n.tx_packets)
+	i.TxBytes = int64(n.tx_bytes)
+	i.TxInterrupts = int64(n.tx_interrupts)
+	i.TxErrors = int64(n.tx_errors)
+	i.TxPacketsDropped = int64(n.tx_packets_dropped)
+	i.TxQueueSize = int64(n.tx_queue_size)
+	i.TxQueueLen = int64(n.tx_queue_len)
+	i.TxQueueOverflow = int64(n.tx_queue_overflow)
+	i.TxBroadcastPackets = int64(n.tx_broadcast_packets)
+	i.TxMulticastPackets = int64(n.tx_multicast_packets)
+	i.TxCarrierSense = int64(n.tx_carrier_sense)
+	i.TxDMAUnderrun = int64(n.tx_DMA_underrun)
+	i.TxLostCTSErrors = int64(n.tx_lost_CTS_errors)
+	i.TxMaxCollisionErrors = int64(n.tx_max_collision_errors)
+	i.TxLateCollisionErrors = int64(n.tx_late_collision_errors)
+	i.TxDeferred = int64(n.tx_deferred)
+	i.TxTimeoutErrors = int64(n.tx_timeout_errors)
+	i.TxSingleCollisionCount = int64(n.tx_single_collision_count)
+	i.TxMultipleCollisionCount = int64(n.tx_multiple_collision_count)
+	i.RxPackets = int64(n.rx_packets)
+	i.RxBytes = int64(n.rx_bytes)
+	i.RxInterrupts = int64(n.rx_interrupts)
+	i.RxErrors = int64(n.rx_errors)
+	i.RxPacketsDropped = int64(n.rx_packets_dropped)
+	i.RxBadPackets = int64(n.rx_bad_packets)
+	i.RxMulticastPackets = int64(n.rx_multicast_packets)
+	i.RxBroadcastPackets = int64(n.rx_broadcast_packets)
+	i.RxCRCErrors = int64(n.rx_CRC_errors)
+	i.RxDMAOverrun = int64(n.rx_DMA_overrun)
+	i.RxAlignmentErrors = int64(n.rx_alignment_errors)
+	i.RxNoResourceErrors = int64(n.rx_noresource_errors)
+	i.RxCollisionErrors = int64(n.rx_collision_errors)
+	i.RxPacketTooShortErrors = int64(n.rx_packet_tooshort_errors)
+	i.RxPacketTooLongErrors = int64(n.rx_packet_toolong_errors)
+	i.RxPacketDiscardedByAdapter = int64(n.rx_packets_discardedbyadapter)
+	i.AdapterType = int32(n.adapter_type)
+
+	return i
+}
+
+func perfstatpagingspace2pagingspace(n *C.perfstat_pagingspace_t) PagingSpace {
+	var i PagingSpace
+
+	i.Name = C.GoString(&n.name[0])
+	i.Type = uint8(n._type)
+	i.VGName = C.GoString(C.get_ps_vgname(n))
+	i.Hostname = C.GoString(C.get_ps_hostname(n))
+	i.Filename = C.GoString(C.get_ps_filename(n))
+	i.LPSize = int64(n.lp_size)
+	i.MBSize = int64(n.mb_size)
+	i.MBUsed = int64(n.mb_used)
+	i.IOPending = int64(n.io_pending)
+	i.Active = uint8(n.active)
+	i.Automatic = uint8(n.automatic)
+	i.Version = int64(n.version)
+
+	return i
+}
+
+func perfstatprocess2process(n *C.perfstat_process_t) Process {
+	var i Process
+
+	i.Version = int64(n.version)
+	i.PID = int64(n.pid)
+	i.ProcessName = C.GoString(&n.proc_name[0])
+	i.Priority = int32(n.proc_priority)
+	i.NumThreads = int64(n.num_threads)
+	i.UID = int64(n.proc_uid)
+	i.ClassID = int64(n.proc_classid)
+	i.Size = int64(n.proc_size)
+	i.RealMemData = int64(n.proc_real_mem_data)
+	i.RealMemText = int64(n.proc_real_mem_text)
+	i.VirtMemData = int64(n.proc_virt_mem_data)
+	i.VirtMemText = int64(n.proc_virt_mem_text)
+	i.SharedLibDataSize = int64(n.shared_lib_data_size)
+	i.HeapSize = int64(n.heap_size)
+	i.RealInUse = int64(n.real_inuse)
+	i.VirtInUse = int64(n.virt_inuse)
+	i.Pinned = int64(n.pinned)
+	i.PgSpInUse = int64(n.pgsp_inuse)
+	i.FilePages = int64(n.filepages)
+	i.RealInUseMap = int64(n.real_inuse_map)
+	i.VirtInUseMap = int64(n.virt_inuse_map)
+	i.PinnedInUseMap = int64(n.pinned_inuse_map)
+	i.UCpuTime = float64(n.ucpu_time)
+	i.SCpuTime = float64(n.scpu_time)
+	i.LastTimeBase = int64(n.last_timebase)
+	i.InBytes = int64(n.inBytes)
+	i.OutBytes = int64(n.outBytes)
+	i.InOps = int64(n.inOps)
+	i.OutOps = int64(n.outOps)
+
+	return i
+}
+
+func perfstatthread2thread(n *C.perfstat_thread_t) Thread {
+	var i Thread
+
+	i.TID = int64(n.tid)
+	i.PID = int64(n.pid)
+	i.CpuID = int64(n.cpuid)
+	i.UCpuTime = float64(n.ucpu_time)
+	i.SCpuTime = float64(n.scpu_time)
+	i.LastTimeBase = int64(n.last_timebase)
+	i.Version = int64(n.version)
+
+	return i
+}
+
+func fsinfo2filesystem(n *C.struct_fsinfo) FileSystem {
+	var i FileSystem
+
+	i.Device = C.GoString(n.devname)
+	i.MountPoint = C.GoString(n.fsname)
+	i.FSType = int(n.fstype)
+	i.Flags = uint(n.flags)
+	i.TotalBlocks = int64(n.totalblks)
+	i.FreeBlocks = int64(n.freeblks)
+	i.TotalInodes = int64(n.totalinodes)
+	i.FreeInodes = int64(n.freeinodes)
+
+	return i
+}
+
+func lparinfo2partinfo(n C.lpar_info_format2_t) PartitionInfo {
+	var i PartitionInfo
+
+	i.Version = int(n.version)
+	i.OnlineMemory = uint64(n.online_memory)
+	i.TotalDispatchTime = uint64(n.tot_dispatch_time)
+	i.PoolIdleTime = uint64(n.pool_idle_time)
+	i.DispatchLatency = uint64(n.dispatch_latency)
+	i.LparFlags = uint(n.lpar_flags)
+	i.PCpusInSys = uint(n.pcpus_in_sys)
+	i.OnlineVCpus = uint(n.online_vcpus)
+	i.OnlineLCpus = uint(n.online_lcpus)
+	i.PCpusInPool = uint(n.pcpus_in_pool)
+	i.UnallocCapacity = uint(n.unalloc_capacity)
+	i.EntitledCapacity = uint(n.entitled_capacity)
+	i.VariableWeight = uint(n.variable_weight)
+	i.UnallocWeight = uint(n.unalloc_weight)
+	i.MinReqVCpuCapacity = uint(n.min_req_vcpu_capacity)
+	i.GroupId = uint8(n.group_id)
+	i.PoolId = uint8(n.pool_id)
+	i.ShCpusInSys = uint(n.shcpus_in_sys)
+	i.MaxPoolCapacity = uint(n.max_pool_capacity)
+	i.EntitledPoolCapacity = uint(n.entitled_pool_capacity)
+	i.PoolMaxTime = uint64(n.pool_max_time)
+	i.PoolBusyTime = uint64(n.pool_busy_time)
+	i.PoolScaledBusyTime = uint64(n.pool_scaled_busy_time)
+	i.ShCpuTotalTime = uint64(n.shcpu_tot_time)
+	i.ShCpuBusyTime = uint64(n.shcpu_busy_time)
+	i.ShCpuScaledBusyTime = uint64(n.shcpu_scaled_busy_time)
+	i.EntMemCapacity = uint64(n.ent_mem_capacity)
+	i.PhysMem = uint64(n.phys_mem)
+	i.VrmPoolPhysMem = uint64(n.vrm_pool_physmem)
+	i.HypPageSize = uint(n.hyp_pagesize)
+	i.VrmPoolId = int(n.vrm_pool_id)
+	i.VrmGroupId = int(n.vrm_group_id)
+	i.VarMemWeight = int(n.var_mem_weight)
+	i.UnallocVarMemWeight = int(n.unalloc_var_mem_weight)
+	i.UnallocEntMemCapacity = uint64(n.unalloc_ent_mem_capacity)
+	i.TrueOnlineMemory = uint64(n.true_online_memory)
+	i.AmeOnlineMemory = uint64(n.ame_online_memory)
+	i.AmeType = uint8(n.ame_type)
+	i.SpecExecMode = uint8(n.spec_exec_mode)
+	i.AmeFactor = uint(n.ame_factor)
+	i.EmPartMajorCode = uint(n.em_part_major_code)
+	i.EmPartMinorCode = uint(n.em_part_minor_code)
+	i.BytesCoalesced = uint64(n.bytes_coalesced)
+	i.BytesCoalescedMemPool = uint64(n.bytes_coalesced_mempool)
+	i.PurrCoalescing = uint64(n.purr_coalescing)
+	i.SpurrCoalescing = uint64(n.spurr_coalescing)
+
+	return i
+}
diff --git a/vendor/github.com/power-devops/perfstat/lparstat.go b/vendor/github.com/power-devops/perfstat/lparstat.go
new file mode 100644
index 000000000..470a1af2f
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/lparstat.go
@@ -0,0 +1,40 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+#include <sys/dr.h>
+*/
+import "C"
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+func PartitionStat() (*PartitionConfig, error) {
+	var part C.perfstat_partition_config_t
+
+	rc := C.perfstat_partition_config(nil, &part, C.sizeof_perfstat_partition_config_t, 1)
+	if rc != 1 {
+		return nil, fmt.Errorf("perfstat_partition_config() error")
+	}
+	p := perfstatpartitionconfig2partitionconfig(part)
+	return &p, nil
+
+}
+
+func LparInfo() (*PartitionInfo, error) {
+	var pinfo C.lpar_info_format2_t
+
+	rc := C.lpar_get_info(C.LPAR_INFO_FORMAT2, unsafe.Pointer(&pinfo), C.sizeof_lpar_info_format2_t)
+	if rc != 0 {
+		return nil, fmt.Errorf("lpar_get_info() error")
+	}
+	p := lparinfo2partinfo(pinfo)
+	return &p, nil
+}
diff --git a/vendor/github.com/power-devops/perfstat/lvmstat.go b/vendor/github.com/power-devops/perfstat/lvmstat.go
new file mode 100644
index 000000000..2ce99086a
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/lvmstat.go
@@ -0,0 +1,73 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+#include <string.h>
+#include <stdlib.h>
+#include "c_helpers.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+func LogicalVolumeStat() ([]LogicalVolume, error) {
+	var lv *C.perfstat_logicalvolume_t
+	var lvname C.perfstat_id_t
+
+	numlvs := C.perfstat_logicalvolume(nil, nil, C.sizeof_perfstat_logicalvolume_t, 0)
+	if numlvs <= 0 {
+		return nil, fmt.Errorf("perfstat_logicalvolume() error")
+	}
+
+	lv_len := C.sizeof_perfstat_logicalvolume_t * C.ulong(numlvs)
+	lv = (*C.perfstat_logicalvolume_t)(C.malloc(lv_len))
+	defer C.free(unsafe.Pointer(lv))
+	C.strcpy(&lvname.name[0], C.CString(""))
+	r := C.perfstat_logicalvolume(&lvname, lv, C.sizeof_perfstat_logicalvolume_t, numlvs)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_logicalvolume() error")
+	}
+	lvs := make([]LogicalVolume, r)
+	for i := 0; i < int(r); i++ {
+		l := C.get_logicalvolume_stat(lv, C.int(i))
+		if l != nil {
+			lvs[i] = perfstatlogicalvolume2logicalvolume(l)
+		}
+	}
+	return lvs, nil
+}
+
+func VolumeGroupStat() ([]VolumeGroup, error) {
+	var vg *C.perfstat_volumegroup_t
+	var vgname C.perfstat_id_t
+
+	numvgs := C.perfstat_volumegroup(nil, nil, C.sizeof_perfstat_volumegroup_t, 0)
+	if numvgs <= 0 {
+		return nil, fmt.Errorf("perfstat_volumegroup() error")
+	}
+
+	vg_len := C.sizeof_perfstat_volumegroup_t * C.ulong(numvgs)
+	vg = (*C.perfstat_volumegroup_t)(C.malloc(vg_len))
+	defer C.free(unsafe.Pointer(vg))
+	C.strcpy(&vgname.name[0], C.CString(""))
+	r := C.perfstat_volumegroup(&vgname, vg, C.sizeof_perfstat_volumegroup_t, numvgs)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_volumegroup() error")
+	}
+	vgs := make([]VolumeGroup, r)
+	for i := 0; i < int(r); i++ {
+		v := C.get_volumegroup_stat(vg, C.int(i))
+		if v != nil {
+			vgs[i] = perfstatvolumegroup2volumegroup(v)
+		}
+	}
+	return vgs, nil
+}
diff --git a/vendor/github.com/power-devops/perfstat/memstat.go b/vendor/github.com/power-devops/perfstat/memstat.go
new file mode 100644
index 000000000..52133f0a8
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/memstat.go
@@ -0,0 +1,85 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "c_helpers.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+func MemoryTotalStat() (*MemoryTotal, error) {
+	var memory C.perfstat_memory_total_t
+
+	rc := C.perfstat_memory_total(nil, &memory, C.sizeof_perfstat_memory_total_t, 1)
+	if rc != 1 {
+		return nil, fmt.Errorf("perfstat_memory_total() error")
+	}
+	m := perfstatmemorytotal2memorytotal(memory)
+	return &m, nil
+}
+
+func MemoryPageStat() ([]MemoryPage, error) {
+	var mempage *C.perfstat_memory_page_t
+	var fps C.perfstat_psize_t
+
+	numps := C.perfstat_memory_page(nil, nil, C.sizeof_perfstat_memory_page_t, 0)
+	if numps < 1 {
+		return nil, fmt.Errorf("perfstat_memory_page() error")
+	}
+
+	mp_len := C.sizeof_perfstat_memory_page_t * C.ulong(numps)
+	mempage = (*C.perfstat_memory_page_t)(C.malloc(mp_len))
+	defer C.free(unsafe.Pointer(mempage))
+	fps.psize = C.FIRST_PSIZE
+	r := C.perfstat_memory_page(&fps, mempage, C.sizeof_perfstat_memory_page_t, numps)
+	if r < 1 {
+		return nil, fmt.Errorf("perfstat_memory_page() error")
+	}
+	ps := make([]MemoryPage, r)
+	for i := 0; i < int(r); i++ {
+		p := C.get_memory_page_stat(mempage, C.int(i))
+		if p != nil {
+			ps[i] = perfstatmemorypage2memorypage(p)
+		}
+	}
+	return ps, nil
+}
+
+func PagingSpaceStat() ([]PagingSpace, error) {
+	var pspace *C.perfstat_pagingspace_t
+	var fps C.perfstat_id_t
+
+	numps := C.perfstat_pagingspace(nil, nil, C.sizeof_perfstat_pagingspace_t, 0)
+	if numps <= 0 {
+		return nil, fmt.Errorf("perfstat_pagingspace() error")
+	}
+
+	ps_len := C.sizeof_perfstat_pagingspace_t * C.ulong(numps)
+	pspace = (*C.perfstat_pagingspace_t)(C.malloc(ps_len))
+	defer C.free(unsafe.Pointer(pspace))
+	C.strcpy(&fps.name[0], C.CString(C.FIRST_PAGINGSPACE))
+	r := C.perfstat_pagingspace(&fps, pspace, C.sizeof_perfstat_pagingspace_t, numps)
+	if r < 1 {
+		return nil, fmt.Errorf("perfstat_pagingspace() error")
+	}
+	ps := make([]PagingSpace, r)
+	for i := 0; i < int(r); i++ {
+		p := C.get_pagingspace_stat(pspace, C.int(i))
+		if p != nil {
+			ps[i] = perfstatpagingspace2pagingspace(p)
+		}
+	}
+	return ps, nil
+}
diff --git a/vendor/github.com/power-devops/perfstat/netstat.go b/vendor/github.com/power-devops/perfstat/netstat.go
new file mode 100644
index 000000000..847d2946e
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/netstat.go
@@ -0,0 +1,118 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "c_helpers.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+func NetIfaceTotalStat() (*NetIfaceTotal, error) {
+	var nif C.perfstat_netinterface_total_t
+
+	rc := C.perfstat_netinterface_total(nil, &nif, C.sizeof_perfstat_netinterface_total_t, 1)
+	if rc != 1 {
+		return nil, fmt.Errorf("perfstat_netinterface_total() error")
+	}
+	n := perfstatnetinterfacetotal2netifacetotal(nif)
+	return &n, nil
+}
+
+func NetBufferStat() ([]NetBuffer, error) {
+	var nbuf *C.perfstat_netbuffer_t
+	var first C.perfstat_id_t
+
+	numbuf := C.perfstat_netbuffer(nil, nil, C.sizeof_perfstat_netbuffer_t, 0)
+	if numbuf < 1 {
+		return nil, fmt.Errorf("perfstat_netbuffer() error")
+	}
+
+	nblen := C.sizeof_perfstat_netbuffer_t * C.ulong(numbuf)
+	nbuf = (*C.perfstat_netbuffer_t)(C.malloc(nblen))
+	defer C.free(unsafe.Pointer(nbuf))
+	C.strcpy(&first.name[0], C.CString(C.FIRST_NETBUFFER))
+	r := C.perfstat_netbuffer(&first, nbuf, C.sizeof_perfstat_netbuffer_t, numbuf)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_netbuffer() error")
+	}
+	nb := make([]NetBuffer, r)
+	for i := 0; i < int(r); i++ {
+		b := C.get_netbuffer_stat(nbuf, C.int(i))
+		if b != nil {
+			nb[i] = perfstatnetbuffer2netbuffer(b)
+		}
+	}
+	return nb, nil
+}
+
+func NetIfaceStat() ([]NetIface, error) {
+	var nif *C.perfstat_netinterface_t
+	var first C.perfstat_id_t
+
+	numif := C.perfstat_netinterface(nil, nil, C.sizeof_perfstat_netinterface_t, 0)
+	if numif < 0 {
+		return nil, fmt.Errorf("perfstat_netinterface() error")
+	}
+	if numif == 0 {
+		return []NetIface{}, fmt.Errorf("no network interfaces found")
+	}
+
+	iflen := C.sizeof_perfstat_netinterface_t * C.ulong(numif)
+	nif = (*C.perfstat_netinterface_t)(C.malloc(iflen))
+	defer C.free(unsafe.Pointer(nif))
+	C.strcpy(&first.name[0], C.CString(C.FIRST_NETINTERFACE))
+	r := C.perfstat_netinterface(&first, nif, C.sizeof_perfstat_netinterface_t, numif)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_netinterface() error")
+	}
+	ifs := make([]NetIface, r)
+	for i := 0; i < int(r); i++ {
+		b := C.get_netinterface_stat(nif, C.int(i))
+		if b != nil {
+			ifs[i] = perfstatnetinterface2netiface(b)
+		}
+	}
+	return ifs, nil
+}
+
+func NetAdapterStat() ([]NetAdapter, error) {
+	var adapters *C.perfstat_netadapter_t
+	var first C.perfstat_id_t
+
+	numad := C.perfstat_netadapter(nil, nil, C.sizeof_perfstat_netadapter_t, 0)
+	if numad < 0 {
+		return nil, fmt.Errorf("perfstat_netadater() error")
+	}
+	if numad == 0 {
+		return []NetAdapter{}, fmt.Errorf("no network adapters found")
+	}
+
+	adplen := C.sizeof_perfstat_netadapter_t * C.ulong(numad)
+	adapters = (*C.perfstat_netadapter_t)(C.malloc(adplen))
+	defer C.free(unsafe.Pointer(adapters))
+	C.strcpy(&first.name[0], C.CString(C.FIRST_NETINTERFACE))
+	r := C.perfstat_netadapter(&first, adapters, C.sizeof_perfstat_netadapter_t, numad)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_netadapter() error")
+	}
+	ads := make([]NetAdapter, r)
+	for i := 0; i < int(r); i++ {
+		b := C.get_netadapter_stat(adapters, C.int(i))
+		if b != nil {
+			ads[i] = perfstatnetadapter2netadapter(b)
+		}
+	}
+	return ads, nil
+}
diff --git a/vendor/github.com/power-devops/perfstat/procstat.go b/vendor/github.com/power-devops/perfstat/procstat.go
new file mode 100644
index 000000000..957ec2b33
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/procstat.go
@@ -0,0 +1,76 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#cgo LDFLAGS: -lperfstat
+
+#include <libperfstat.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "c_helpers.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+func ProcessStat() ([]Process, error) {
+	var proc *C.perfstat_process_t
+	var first C.perfstat_id_t
+
+	numproc := C.perfstat_process(nil, nil, C.sizeof_perfstat_process_t, 0)
+	if numproc < 1 {
+		return nil, fmt.Errorf("perfstat_process() error")
+	}
+
+	plen := C.sizeof_perfstat_process_t * C.ulong(numproc)
+	proc = (*C.perfstat_process_t)(C.malloc(plen))
+	defer C.free(unsafe.Pointer(proc))
+	C.strcpy(&first.name[0], C.CString(""))
+	r := C.perfstat_process(&first, proc, C.sizeof_perfstat_process_t, numproc)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_process() error")
+	}
+
+	ps := make([]Process, r)
+	for i := 0; i < int(r); i++ {
+		p := C.get_process_stat(proc, C.int(i))
+		if p != nil {
+			ps[i] = perfstatprocess2process(p)
+		}
+	}
+	return ps, nil
+}
+
+func ThreadStat() ([]Thread, error) {
+	var thread *C.perfstat_thread_t
+	var first C.perfstat_id_t
+
+	numthr := C.perfstat_thread(nil, nil, C.sizeof_perfstat_thread_t, 0)
+	if numthr < 1 {
+		return nil, fmt.Errorf("perfstat_thread() error")
+	}
+
+	thlen := C.sizeof_perfstat_thread_t * C.ulong(numthr)
+	thread = (*C.perfstat_thread_t)(C.malloc(thlen))
+	defer C.free(unsafe.Pointer(thread))
+	C.strcpy(&first.name[0], C.CString(""))
+	r := C.perfstat_thread(&first, thread, C.sizeof_perfstat_thread_t, numthr)
+	if r < 0 {
+		return nil, fmt.Errorf("perfstat_thread() error")
+	}
+
+	th := make([]Thread, r)
+	for i := 0; i < int(r); i++ {
+		t := C.get_thread_stat(thread, C.int(i))
+		if t != nil {
+			th[i] = perfstatthread2thread(t)
+		}
+	}
+	return th, nil
+}
diff --git a/vendor/github.com/power-devops/perfstat/sysconf.go b/vendor/github.com/power-devops/perfstat/sysconf.go
new file mode 100644
index 000000000..b557da0de
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/sysconf.go
@@ -0,0 +1,196 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#include <unistd.h>
+*/
+import "C"
+
+import "fmt"
+
+const (
+	SC_ARG_MAX                      = 0
+	SC_CHILD_MAX                    = 1
+	SC_CLK_TCK                      = 2
+	SC_NGROUPS_MAX                  = 3
+	SC_OPEN_MAX                     = 4
+	SC_STREAM_MAX                   = 5
+	SC_TZNAME_MAX                   = 6
+	SC_JOB_CONTROL                  = 7
+	SC_SAVED_IDS                    = 8
+	SC_VERSION                      = 9
+	SC_POSIX_ARG_MAX                = 10
+	SC_POSIX_CHILD_MAX              = 11
+	SC_POSIX_LINK_MAX               = 12
+	SC_POSIX_MAX_CANON              = 13
+	SC_POSIX_MAX_INPUT              = 14
+	SC_POSIX_NAME_MAX               = 15
+	SC_POSIX_NGROUPS_MAX            = 16
+	SC_POSIX_OPEN_MAX               = 17
+	SC_POSIX_PATH_MAX               = 18
+	SC_POSIX_PIPE_BUF               = 19
+	SC_POSIX_SSIZE_MAX              = 20
+	SC_POSIX_STREAM_MAX             = 21
+	SC_POSIX_TZNAME_MAX             = 22
+	SC_BC_BASE_MAX                  = 23
+	SC_BC_DIM_MAX                   = 24
+	SC_BC_SCALE_MAX                 = 25
+	SC_BC_STRING_MAX                = 26
+	SC_EQUIV_CLASS_MAX              = 27
+	SC_EXPR_NEST_MAX                = 28
+	SC_LINE_MAX                     = 29
+	SC_RE_DUP_MAX                   = 30
+	SC_2_VERSION                    = 31
+	SC_2_C_DEV                      = 32
+	SC_2_FORT_DEV                   = 33
+	SC_2_FORT_RUN                   = 34
+	SC_2_LOCALEDEF                  = 35
+	SC_2_SW_DEV                     = 36
+	SC_POSIX2_BC_BASE_MAX           = 37
+	SC_POSIX2_BC_DIM_MAX            = 38
+	SC_POSIX2_BC_SCALE_MAX          = 39
+	SC_POSIX2_BC_STRING_MAX         = 40
+	SC_POSIX2_BC_EQUIV_CLASS_MAX    = 41
+	SC_POSIX2_BC_EXPR_NEST_MAX      = 42
+	SC_POSIX2_BC_LINE_MAX           = 43
+	SC_POSIX2_BC_RE_DUP_MAX         = 44
+	SC_PASS_MAX                     = 45
+	SC_XOPEN_VERSION                = 46
+	SC_ATEXIT_MAX                   = 47
+	SC_PAGE_SIZE                    = 48
+	SC_PAGESIZE                     = SC_PAGE_SIZE
+	SC_AES_OS_VERSION               = 49
+	SC_COLL_WEIGHTS_MAX             = 50
+	SC_2_C_WIND                     = 51
+	SC_2_C_VERSION                  = 52
+	SC_2_UPE                        = 53
+	SC_2_CHAR_TERM                  = 54
+	SC_XOPEN_SHM                    = 55
+	SC_XOPEN_CRYPT                  = 56
+	SC_XOPEN_ENH_I18N               = 57
+	SC_IOV_MAX                      = 58
+	SC_THREAD_SAFE_FUNCTIONS        = 59
+	SC_THREADS                      = 60
+	SC_THREAD_ATTR_STACKADDR        = 61
+	SC_THREAD_ATTR_STACKSIZE        = 62
+	SC_THREAD_FORKALL               = 63
+	SC_THREAD_PRIORITY_SCHEDULING   = 64
+	SC_THREAD_PRIO_INHERIT          = 65
+	SC_THREAD_PRIO_PROTECT          = 66
+	SC_THREAD_PROCESS_SHARED        = 67
+	SC_THREAD_KEYS_MAX              = 68
+	SC_THREAD_DATAKEYS_MAX          = SC_THREAD_KEYS_MAX
+	SC_THREAD_STACK_MIN             = 69
+	SC_THREAD_THREADS_MAX           = 70
+	SC_NPROCESSORS_CONF             = 71
+	SC_NPROCESSORS_ONLN             = 72
+	SC_XOPEN_UNIX                   = 73
+	SC_AIO_LISTIO_MAX               = 75
+	SC_AIO_MAX                      = 76
+	SC_AIO_PRIO_DELTA_MAX           = 77
+	SC_ASYNCHRONOUS_IO              = 78
+	SC_DELAYTIMER_MAX               = 79
+	SC_FSYNC                        = 80
+	SC_GETGR_R_SIZE_MAX             = 81
+	SC_GETPW_R_SIZE_MAX             = 82
+	SC_LOGIN_NAME_MAX               = 83
+	SC_MAPPED_FILES                 = 84
+	SC_MEMLOCK                      = 85
+	SC_MEMLOCK_RANGE                = 86
+	SC_MEMORY_PROTECTION            = 87
+	SC_MESSAGE_PASSING              = 88
+	SC_MQ_OPEN_MAX                  = 89
+	SC_MQ_PRIO_MAX                  = 90
+	SC_PRIORITIZED_IO               = 91
+	SC_PRIORITY_SCHEDULING          = 92
+	SC_REALTIME_SIGNALS             = 93
+	SC_RTSIG_MAX                    = 94
+	SC_SEMAPHORES                   = 95
+	SC_SEM_NSEMS_MAX                = 96
+	SC_SEM_VALUE_MAX                = 97
+	SC_SHARED_MEMORY_OBJECTS        = 98
+	SC_SIGQUEUE_MAX                 = 99
+	SC_SYNCHRONIZED_IO              = 100
+	SC_THREAD_DESTRUCTOR_ITERATIONS = 101
+	SC_TIMERS                       = 102
+	SC_TIMER_MAX                    = 103
+	SC_TTY_NAME_MAX                 = 104
+	SC_XBS5_ILP32_OFF32             = 105
+	SC_XBS5_ILP32_OFFBIG            = 106
+	SC_XBS5_LP64_OFF64              = 107
+	SC_XBS5_LPBIG_OFFBIG            = 108
+	SC_XOPEN_XCU_VERSION            = 109
+	SC_XOPEN_REALTIME               = 110
+	SC_XOPEN_REALTIME_THREADS       = 111
+	SC_XOPEN_LEGACY                 = 112
+	SC_REENTRANT_FUNCTIONS          = SC_THREAD_SAFE_FUNCTIONS
+	SC_PHYS_PAGES                   = 113
+	SC_AVPHYS_PAGES                 = 114
+	SC_LPAR_ENABLED                 = 115
+	SC_LARGE_PAGESIZE               = 116
+	SC_AIX_KERNEL_BITMODE           = 117
+	SC_AIX_REALMEM                  = 118
+	SC_AIX_HARDWARE_BITMODE         = 119
+	SC_AIX_MP_CAPABLE               = 120
+	SC_V6_ILP32_OFF32               = 121
+	SC_V6_ILP32_OFFBIG              = 122
+	SC_V6_LP64_OFF64                = 123
+	SC_V6_LPBIG_OFFBIG              = 124
+	SC_XOPEN_STREAMS                = 125
+	SC_HOST_NAME_MAX                = 126
+	SC_REGEXP                       = 127
+	SC_SHELL                        = 128
+	SC_SYMLOOP_MAX                  = 129
+	SC_ADVISORY_INFO                = 130
+	SC_FILE_LOCKING                 = 131
+	SC_2_PBS                        = 132
+	SC_2_PBS_ACCOUNTING             = 133
+	SC_2_PBS_CHECKPOINT             = 134
+	SC_2_PBS_LOCATE                 = 135
+	SC_2_PBS_MESSAGE                = 136
+	SC_2_PBS_TRACK                  = 137
+	SC_BARRIERS                     = 138
+	SC_CLOCK_SELECTION              = 139
+	SC_CPUTIME                      = 140
+	SC_MONOTONIC_CLOCK              = 141
+	SC_READER_WRITER_LOCKS          = 142
+	SC_SPAWN                        = 143
+	SC_SPIN_LOCKS                   = 144
+	SC_SPORADIC_SERVER              = 145
+	SC_THREAD_CPUTIME               = 146
+	SC_THREAD_SPORADIC_SERVER       = 147
+	SC_TIMEOUTS                     = 148
+	SC_TRACE                        = 149
+	SC_TRACE_EVENT_FILTER           = 150
+	SC_TRACE_INHERIT                = 151
+	SC_TRACE_LOG                    = 152
+	SC_TYPED_MEMORY_OBJECTS         = 153
+	SC_IPV6                         = 154
+	SC_RAW_SOCKETS                  = 155
+	SC_SS_REPL_MAX                  = 156
+	SC_TRACE_EVENT_NAME_MAX         = 157
+	SC_TRACE_NAME_MAX               = 158
+	SC_TRACE_SYS_MAX                = 159
+	SC_TRACE_USER_EVENT_MAX         = 160
+	SC_AIX_UKEYS                    = 161
+	SC_AIX_ENHANCED_AFFINITY        = 162
+	SC_V7_ILP32_OFF32               = 163
+	SC_V7_ILP32_OFFBIG              = 164
+	SC_V7_LP64_OFF64                = 165
+	SC_V7_LPBIG_OFFBIG              = 166
+	SC_THREAD_ROBUST_PRIO_INHERIT   = 167
+	SC_THREAD_ROBUST_PRIO_PROTECT   = 168
+	SC_XOPEN_UUCP                   = 169
+	SC_XOPEN_ARMOR                  = 170
+)
+
+func Sysconf(name int32) (int64, error) {
+	r := C.sysconf(C.int(name))
+	if r == -1 {
+		return 0, fmt.Errorf("sysconf error")
+	} else {
+		return int64(r), nil
+	}
+}
diff --git a/vendor/github.com/power-devops/perfstat/systemcfg.go b/vendor/github.com/power-devops/perfstat/systemcfg.go
new file mode 100644
index 000000000..b7c7b7259
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/systemcfg.go
@@ -0,0 +1,662 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+import "golang.org/x/sys/unix"
+
+// function Getsystemcfg() is defined in golang.org/x/sys/unix
+// we define here just missing constants for the function and some helpers
+
+// Calls to getsystemcfg()
+const (
+	SC_ARCH         = 1  /* processor architecture */
+	SC_IMPL         = 2  /* processor implementation */
+	SC_VERS         = 3  /* processor version */
+	SC_WIDTH        = 4  /* width (32 || 64) */
+	SC_NCPUS        = 5  /* 1 = UP, n = n-way MP */
+	SC_L1C_ATTR     = 6  /* L1 cache attributes (bit flags) */
+	SC_L1C_ISZ      = 7  /* size of L1 instruction cache */
+	SC_L1C_DSZ      = 8  /* size of L1 data cache */
+	SC_L1C_ICA      = 9  /* L1 instruction cache associativity */
+	SC_L1C_DCA      = 10 /* L1 data cache associativity */
+	SC_L1C_IBS      = 11 /* L1 instruction cache block size */
+	SC_L1C_DBS      = 12 /* L1 data cache block size */
+	SC_L1C_ILS      = 13 /* L1 instruction cache line size */
+	SC_L1C_DLS      = 14 /* L1 data cache line size */
+	SC_L2C_SZ       = 15 /* size of L2 cache, 0 = No L2 cache */
+	SC_L2C_AS       = 16 /* L2 cache associativity */
+	SC_TLB_ATTR     = 17 /* TLB attributes (bit flags) */
+	SC_ITLB_SZ      = 18 /* entries in instruction TLB */
+	SC_DTLB_SZ      = 19 /* entries in data TLB */
+	SC_ITLB_ATT     = 20 /* instruction tlb associativity */
+	SC_DTLB_ATT     = 21 /* data tlb associativity */
+	SC_RESRV_SZ     = 22 /* size of reservation */
+	SC_PRI_LC       = 23 /* spin lock count in supevisor mode */
+	SC_PRO_LC       = 24 /* spin lock count in problem state */
+	SC_RTC_TYPE     = 25 /* RTC type */
+	SC_VIRT_AL      = 26 /* 1 if hardware aliasing is supported */
+	SC_CAC_CONG     = 27 /* number of page bits for cache synonym */
+	SC_MOD_ARCH     = 28 /* used by system for model determination */
+	SC_MOD_IMPL     = 29 /* used by system for model determination */
+	SC_XINT         = 30 /* used by system for time base conversion */
+	SC_XFRAC        = 31 /* used by system for time base conversion */
+	SC_KRN_ATTR     = 32 /* kernel attributes, see below */
+	SC_PHYSMEM      = 33 /* bytes of OS available memory */
+	SC_SLB_ATTR     = 34 /* SLB attributes */
+	SC_SLB_SZ       = 35 /* size of slb (0 = no slb) */
+	SC_ORIG_NCPUS   = 36 /* original number of CPUs */
+	SC_MAX_NCPUS    = 37 /* max cpus supported by this AIX image */
+	SC_MAX_REALADDR = 38 /* max supported real memory address +1 */
+	SC_ORIG_ENT_CAP = 39 /* configured entitled processor capacity at boot required by cross-partition LPAR tools. */
+	SC_ENT_CAP      = 40 /* entitled processor capacity */
+	SC_DISP_WHE     = 41 /* Dispatch wheel time period (TB units) */
+	SC_CAPINC       = 42 /* delta by which capacity can change */
+	SC_VCAPW        = 43 /* priority weight for idle capacity distribution */
+	SC_SPLP_STAT    = 44 /* State of SPLPAR enablement: 0x1 => 1=SPLPAR capable; 0=not, 0x2 => SPLPAR enabled 0=dedicated, 1=shared */
+	SC_SMT_STAT     = 45 /* State of SMT enablement: 0x1 = SMT Capable  0=no/1=yes, 0x2 = SMT Enabled  0=no/1=yes, 0x4 = SMT threads bound true 0=no/1=yes */
+	SC_SMT_TC       = 46 /* Number of SMT Threads per Physical CPU */
+	SC_VMX_VER      = 47 /* RPA defined VMX version: 0 = VMX not available or disabled, 1 = VMX capable, 2 = VMX and VSX capable */
+	SC_LMB_SZ       = 48 /* Size of an LMB on this system. */
+	SC_MAX_XCPU     = 49 /* Number of exclusive cpus on line */
+	SC_EC_LVL       = 50 /* Kernel error checking level */
+	SC_AME_STAT     = 51 /* AME status */
+	SC_ECO_STAT     = 52 /* extended cache options */
+	SC_DFP_STAT     = 53 /* RPA defined DFP version, 0=none/disabled */
+	SC_VRM_STAT     = 54 /* VRM Capable/enabled */
+	SC_PHYS_IMP     = 55 /* physical processor implementation */
+	SC_PHYS_VER     = 56 /* physical processor version */
+	SC_SPCM_STATUS  = 57
+	SC_SPCM_MAX     = 58
+	SC_TM_VER       = 59 /* Transaction Memory version, 0 - not capable */
+	SC_NX_CAP       = 60 /* NX GZIP capable */
+	SC_PKS_STATE    = 61 /* Platform KeyStore */
+	SC_MMA_VER      = 62
+)
+
+/* kernel attributes                        */
+/* bit          0/1 meaning                 */
+/* -----------------------------------------*/
+/* 31   32-bit kernel / 64-bit kernel       */
+/* 30   non-LPAR      / LPAR                */
+/* 29   old 64bit ABI / 64bit Large ABI     */
+/* 28   non-NUMA      / NUMA                */
+/* 27   UP            / MP                  */
+/* 26   no DR CPU add / DR CPU add support  */
+/* 25   no DR CPU rm  / DR CPU rm  support  */
+/* 24   no DR MEM add / DR MEM add support  */
+/* 23   no DR MEM rm  / DR MEM rm  support  */
+/* 22   kernel keys disabled / enabled      */
+/* 21   no recovery   / recovery enabled    */
+/* 20   non-MLS    / MLS enabled            */
+/* 19   enhanced affinity indicator         */
+/* 18   non-vTPM    / vTPM enabled          */
+/* 17   non-VIOS    / VIOS                  */
+
+// Values for architecture field
+const (
+	ARCH_POWER_RS = 0x0001 /* Power Classic architecture */
+	ARCH_POWER_PC = 0x0002 /* Power PC architecture */
+	ARCH_IA64     = 0x0003 /* Intel IA64 architecture */
+)
+
+// Values for implementation field for POWER_PC Architectures
+const (
+	IMPL_POWER_RS1     = 0x00001     /* RS1 class CPU */
+	IMPL_POWER_RSC     = 0x00002     /* RSC class CPU */
+	IMPL_POWER_RS2     = 0x00004     /* RS2 class CPU */
+	IMPL_POWER_601     = 0x00008     /* 601 class CPU */
+	IMPL_POWER_603     = 0x00020     /* 603 class CPU */
+	IMPL_POWER_604     = 0x00010     /* 604 class CPU */
+	IMPL_POWER_620     = 0x00040     /* 620 class CPU */
+	IMPL_POWER_630     = 0x00080     /* 630 class CPU */
+	IMPL_POWER_A35     = 0x00100     /* A35 class CPU */
+	IMPL_POWER_RS64II  = 0x0200      /* RS64-II class CPU */
+	IMPL_POWER_RS64III = 0x0400      /* RS64-III class CPU */
+	IMPL_POWER4        = 0x0800      /* 4 class CPU */
+	IMPL_POWER_RS64IV  = IMPL_POWER4 /* 4 class CPU */
+	IMPL_POWER_MPC7450 = 0x1000      /* MPC7450 class CPU */
+	IMPL_POWER5        = 0x2000      /* 5 class CPU */
+	IMPL_POWER6        = 0x4000      /* 6 class CPU */
+	IMPL_POWER7        = 0x8000      /* 7 class CPU */
+	IMPL_POWER8        = 0x10000     /* 8 class CPU */
+	IMPL_POWER9        = 0x20000     /* 9 class CPU */
+	IMPL_POWER10       = 0x20000     /* 10 class CPU */
+)
+
+// Values for implementation field for IA64 Architectures
+const (
+	IMPL_IA64_M1 = 0x0001 /* IA64 M1 class CPU (Itanium) */
+	IMPL_IA64_M2 = 0x0002 /* IA64 M2 class CPU */
+)
+
+// Values for the version field
+const (
+	PV_601        = 0x010001 /* Power PC 601 */
+	PV_601A       = 0x010002 /* Power PC 601 */
+	PV_603        = 0x060000 /* Power PC 603 */
+	PV_604        = 0x050000 /* Power PC 604 */
+	PV_620        = 0x070000 /* Power PC 620 */
+	PV_630        = 0x080000 /* Power PC 630 */
+	PV_A35        = 0x090000 /* Power PC A35 */
+	PV_RS64II     = 0x0A0000 /* Power PC RS64II */
+	PV_RS64III    = 0x0B0000 /* Power PC RS64III */
+	PV_4          = 0x0C0000 /* Power PC 4 */
+	PV_RS64IV     = PV_4     /* Power PC 4 */
+	PV_MPC7450    = 0x0D0000 /* Power PC MPC7450 */
+	PV_4_2        = 0x0E0000 /* Power PC 4 */
+	PV_4_3        = 0x0E0001 /* Power PC 4 */
+	PV_5          = 0x0F0000 /* Power PC 5 */
+	PV_5_2        = 0x0F0001 /* Power PC 5 */
+	PV_5_3        = 0x0F0002 /* Power PC 5 */
+	PV_6          = 0x100000 /* Power PC 6 */
+	PV_6_1        = 0x100001 /* Power PC 6 DD1.x */
+	PV_7          = 0x200000 /* Power PC 7 */
+	PV_8          = 0x300000 /* Power PC 8 */
+	PV_9          = 0x400000 /* Power PC 9 */
+	PV_10         = 0x500000 /* Power PC 10 */
+	PV_5_Compat   = 0x0F8000 /* Power PC 5 */
+	PV_6_Compat   = 0x108000 /* Power PC 6 */
+	PV_7_Compat   = 0x208000 /* Power PC 7 */
+	PV_8_Compat   = 0x308000 /* Power PC 8 */
+	PV_9_Compat   = 0x408000 /* Power PC 9 */
+	PV_10_Compat  = 0x508000 /* Power PC 10 */
+	PV_RESERVED_2 = 0x0A0000 /* source compatability */
+	PV_RESERVED_3 = 0x0B0000 /* source compatability */
+	PV_RS2        = 0x040000 /* Power RS2 */
+	PV_RS1        = 0x020000 /* Power RS1 */
+	PV_RSC        = 0x030000 /* Power RSC */
+	PV_M1         = 0x008000 /* Intel IA64 M1 */
+	PV_M2         = 0x008001 /* Intel IA64 M2 */
+)
+
+// Values for rtc_type
+const (
+	RTC_POWER    = 1 /* rtc as defined by Power Arch. */
+	RTC_POWER_PC = 2 /* rtc as defined by Power PC Arch. */
+	RTC_IA64     = 3 /* rtc as defined by IA64 Arch. */
+)
+
+const NX_GZIP_PRESENT = 0x00000001
+
+const (
+	PKS_STATE_CAPABLE = 1
+	PKS_STATE_ENABLED = 2
+)
+
+// Macros for identifying physical processor
+const (
+	PPI4_1  = 0x35
+	PPI4_2  = 0x38
+	PPI4_3  = 0x39
+	PPI4_4  = 0x3C
+	PPI4_5  = 0x44
+	PPI5_1  = 0x3A
+	PPI5_2  = 0x3B
+	PPI6_1  = 0x3E
+	PPI7_1  = 0x3F
+	PPI7_2  = 0x4A
+	PPI8_1  = 0x4B
+	PPI8_2  = 0x4D
+	PPI9    = 0x4E
+	PPI9_1  = 0x4E
+	PPI10_1 = 0x80
+)
+
+// Macros for kernel attributes
+const (
+	KERN_TYPE            = 0x1
+	KERN_LPAR            = 0x2
+	KERN_64BIT_LARGE_ABI = 0x4
+	KERN_NUMA            = 0x8
+	KERN_UPMP            = 0x10
+	KERN_DR_CPU_ADD      = 0x20
+	KERN_DR_CPU_RM       = 0x40
+	KERN_DR_MEM_ADD      = 0x80
+	KERN_DR_MEM_RM       = 0x100
+	KERN_KKEY_ENABLED    = 0x200
+	KERN_RECOVERY        = 0x400
+	KERN_MLS             = 0x800
+	KERN_ENH_AFFINITY    = 0x1000
+	KERN_VTPM            = 0x2000
+	KERN_VIOS            = 0x4000
+)
+
+// macros for SPLPAR environment.
+const (
+	SPLPAR_CAPABLE        = 0x1
+	SPLPAR_ENABLED        = 0x2
+	SPLPAR_DONATE_CAPABLE = 0x4
+)
+
+// Macros for SMT status determination
+const (
+	SMT_CAPABLE = 0x1
+	SMT_ENABLE  = 0x2
+	SMT_BOUND   = 0x4
+	SMT_ORDER   = 0x8
+)
+
+// Macros for VRM status determination
+const (
+	VRM_CAPABLE  = 0x1
+	VRM_ENABLE   = 0x2
+	CMOX_CAPABLE = 0x4
+)
+
+// Macros for AME status determination
+const AME_ENABLE = 0x1
+
+// Macros for extended cache options
+const (
+	ECO_CAPABLE = 0x1
+	ECO_ENABLE  = 0x2
+)
+
+// These define blocks of values for model_arch and model_impl that are reserved for OEM use.
+const (
+	MODEL_ARCH_RSPC         = 2
+	MODEL_ARCH_CHRP         = 3
+	MODEL_ARCH_IA64         = 4
+	MODEL_ARCH_OEM_START    = 1024
+	MODEL_ARCH_OEM_END      = 2047
+	MODEL_IMPL_RS6K_UP_MCA  = 1
+	MODEL_IMPL_RS6K_SMP_MCA = 2
+	MODEL_IMPL_RSPC_UP_PCI  = 3
+	MODEL_IMPL_RSPC_SMP_PCI = 4
+	MODEL_IMPL_CHRP_UP_PCI  = 5
+	MODEL_IMPL_CHRP_SMP_PCI = 6
+	MODEL_IMPL_IA64_COM     = 7
+	MODEL_IMPL_IA64_SOFTSDV = 8
+	MODEL_IMPL_MAMBO_SIM    = 9
+	MODEL_IMPL_POWER_KVM    = 10
+	MODEL_IMPL_OEM_START    = 1024
+	MODEL_IMPL_OEM_END      = 2047
+)
+
+// example determining processor compatibilty mode on AIX:
+// impl := unix.Getsystemcfg(SC_IMPL)
+// if impl&IMPL_POWER8 != 0 {
+//     // we are running on POWER8
+// }
+// if impl&IMPL_POWER9 != 0 {
+//     // we are running on POWER9
+// }
+
+func GetCPUImplementation() string {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	switch {
+	case impl&IMPL_POWER4 != 0:
+		return "POWER4"
+	case impl&IMPL_POWER5 != 0:
+		return "POWER5"
+	case impl&IMPL_POWER6 != 0:
+		return "POWER6"
+	case impl&IMPL_POWER7 != 0:
+		return "POWER7"
+	case impl&IMPL_POWER8 != 0:
+		return "POWER8"
+	case impl&IMPL_POWER9 != 0:
+		return "POWER9"
+	case impl&IMPL_POWER10 != 0:
+		return "Power10"
+	default:
+		return "Unknown"
+	}
+}
+
+func POWER10OrNewer() bool {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	if impl&IMPL_POWER10 != 0 {
+		return true
+	}
+	return false
+}
+
+func POWER10() bool {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	if impl&IMPL_POWER10 != 0 {
+		return true
+	}
+	return false
+}
+
+func POWER9OrNewer() bool {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	if impl&IMPL_POWER10 != 0 || impl&IMPL_POWER9 != 0 {
+		return true
+	}
+	return false
+}
+
+func POWER9() bool {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	if impl&IMPL_POWER9 != 0 {
+		return true
+	}
+	return false
+}
+
+func POWER8OrNewer() bool {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	if impl&IMPL_POWER10 != 0 || impl&IMPL_POWER9 != 0 || impl&IMPL_POWER8 != 0 {
+		return true
+	}
+	return false
+}
+
+func POWER8() bool {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	if impl&IMPL_POWER8 != 0 {
+		return true
+	}
+	return false
+}
+
+func POWER7OrNewer() bool {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	if impl&IMPL_POWER10 != 0 || impl&IMPL_POWER9 != 0 || impl&IMPL_POWER8 != 0 || impl&IMPL_POWER7 != 0 {
+		return true
+	}
+	return false
+}
+
+func POWER7() bool {
+	impl := unix.Getsystemcfg(SC_IMPL)
+	if impl&IMPL_POWER7 != 0 {
+		return true
+	}
+	return false
+}
+
+func HasTransactionalMemory() bool {
+	impl := unix.Getsystemcfg(SC_TM_VER)
+	if impl > 0 {
+		return true
+	}
+	return false
+}
+
+func Is64Bit() bool {
+	impl := unix.Getsystemcfg(SC_WIDTH)
+	if impl == 64 {
+		return true
+	}
+	return false
+}
+
+func IsSMP() bool {
+	impl := unix.Getsystemcfg(SC_NCPUS)
+	if impl > 1 {
+		return true
+	}
+	return false
+}
+
+func HasVMX() bool {
+	impl := unix.Getsystemcfg(SC_VMX_VER)
+	if impl > 0 {
+		return true
+	}
+	return false
+}
+
+func HasVSX() bool {
+	impl := unix.Getsystemcfg(SC_VMX_VER)
+	if impl > 1 {
+		return true
+	}
+	return false
+}
+
+func HasDFP() bool {
+	impl := unix.Getsystemcfg(SC_DFP_STAT)
+	if impl > 1 {
+		return true
+	}
+	return false
+}
+
+func HasNxGzip() bool {
+	impl := unix.Getsystemcfg(SC_NX_CAP)
+	if impl&NX_GZIP_PRESENT > 0 {
+		return true
+	}
+	return false
+}
+
+func PksCapable() bool {
+	impl := unix.Getsystemcfg(SC_PKS_STATE)
+	if impl&PKS_STATE_CAPABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func PksEnabled() bool {
+	impl := unix.Getsystemcfg(SC_PKS_STATE)
+	if impl&PKS_STATE_ENABLED > 0 {
+		return true
+	}
+	return false
+}
+
+func CPUMode() string {
+	impl := unix.Getsystemcfg(SC_VERS)
+	switch impl {
+	case PV_10, PV_10_Compat:
+		return "Power10"
+	case PV_9, PV_9_Compat:
+		return "POWER9"
+	case PV_8, PV_8_Compat:
+		return "POWER8"
+	case PV_7, PV_7_Compat:
+		return "POWER7"
+	default:
+		return "Unknown"
+	}
+}
+
+func KernelBits() int {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_TYPE == KERN_TYPE {
+		return 64
+	}
+	return 32
+}
+
+func IsLPAR() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_LPAR == KERN_LPAR {
+		return true
+	}
+	return false
+}
+
+func CpuAddCapable() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_DR_CPU_ADD == KERN_DR_CPU_ADD {
+		return true
+	}
+	return false
+}
+
+func CpuRemoveCapable() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_DR_CPU_RM == KERN_DR_CPU_RM {
+		return true
+	}
+	return false
+}
+
+func MemoryAddCapable() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_DR_MEM_ADD == KERN_DR_MEM_ADD {
+		return true
+	}
+	return false
+}
+
+func MemoryRemoveCapable() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_DR_MEM_RM == KERN_DR_MEM_RM {
+		return true
+	}
+	return false
+}
+
+func DLparCapable() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&(KERN_DR_CPU_ADD|KERN_DR_CPU_RM|KERN_DR_MEM_ADD|KERN_DR_MEM_RM) > 0 {
+		return true
+	}
+	return false
+}
+
+func IsNUMA() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_NUMA > 0 {
+		return true
+	}
+	return false
+}
+
+func KernelKeys() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_KKEY_ENABLED > 0 {
+		return true
+	}
+	return false
+}
+
+func RecoveryMode() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_RECOVERY > 0 {
+		return true
+	}
+	return false
+}
+
+func EnhancedAffinity() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_ENH_AFFINITY > 0 {
+		return true
+	}
+	return false
+}
+
+func VTpmEnabled() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_VTPM > 0 {
+		return true
+	}
+	return false
+}
+
+func IsVIOS() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_VIOS > 0 {
+		return true
+	}
+	return false
+}
+
+func MLSEnabled() bool {
+	impl := unix.Getsystemcfg(SC_KRN_ATTR)
+	if impl&KERN_MLS > 0 {
+		return true
+	}
+	return false
+}
+
+func SPLparCapable() bool {
+	impl := unix.Getsystemcfg(SC_SPLP_STAT)
+	if impl&SPLPAR_CAPABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func SPLparEnabled() bool {
+	impl := unix.Getsystemcfg(SC_SPLP_STAT)
+	if impl&SPLPAR_ENABLED > 0 {
+		return true
+	}
+	return false
+}
+
+func DedicatedLpar() bool {
+	return !SPLparEnabled()
+}
+
+func SPLparCapped() bool {
+	impl := unix.Getsystemcfg(SC_VCAPW)
+	if impl == 0 {
+		return true
+	}
+	return false
+}
+
+func SPLparDonating() bool {
+	impl := unix.Getsystemcfg(SC_SPLP_STAT)
+	if impl&SPLPAR_DONATE_CAPABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func SmtCapable() bool {
+	impl := unix.Getsystemcfg(SC_SMT_STAT)
+	if impl&SMT_CAPABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func SmtEnabled() bool {
+	impl := unix.Getsystemcfg(SC_SMT_STAT)
+	if impl&SMT_ENABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func VrmCapable() bool {
+	impl := unix.Getsystemcfg(SC_VRM_STAT)
+	if impl&VRM_CAPABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func VrmEnabled() bool {
+	impl := unix.Getsystemcfg(SC_VRM_STAT)
+	if impl&VRM_ENABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func AmeEnabled() bool {
+	impl := unix.Getsystemcfg(SC_AME_STAT)
+	if impl&AME_ENABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func EcoCapable() bool {
+	impl := unix.Getsystemcfg(SC_ECO_STAT)
+	if impl&ECO_CAPABLE > 0 {
+		return true
+	}
+	return false
+}
+
+func EcoEnabled() bool {
+	impl := unix.Getsystemcfg(SC_ECO_STAT)
+	if impl&ECO_ENABLE > 0 {
+		return true
+	}
+	return false
+}
diff --git a/vendor/github.com/power-devops/perfstat/types_cpu.go b/vendor/github.com/power-devops/perfstat/types_cpu.go
new file mode 100644
index 000000000..84425e92f
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/types_cpu.go
@@ -0,0 +1,186 @@
+package perfstat
+
+type CPU struct {
+	Name             string /* logical processor name (cpu0, cpu1, ..) */
+	User             int64  /* raw number of clock ticks spent in user mode */
+	Sys              int64  /* raw number of clock ticks spent in system mode */
+	Idle             int64  /* raw number of clock ticks spent idle */
+	Wait             int64  /* raw number of clock ticks spent waiting for I/O */
+	PSwitch          int64  /* number of context switches (changes of currently running process) */
+	Syscall          int64  /* number of system calls executed */
+	Sysread          int64  /* number of read system calls executed */
+	Syswrite         int64  /* number of write system calls executed */
+	Sysfork          int64  /* number of fork system call executed */
+	Sysexec          int64  /* number of exec system call executed */
+	Readch           int64  /* number of characters tranferred with read system call */
+	Writech          int64  /* number of characters tranferred with write system call */
+	Bread            int64  /* number of block reads */
+	Bwrite           int64  /* number of block writes */
+	Lread            int64  /* number of logical read requests */
+	Lwrite           int64  /* number of logical write requests */
+	Phread           int64  /* number of physical reads (reads on raw device) */
+	Phwrite          int64  /* number of physical writes (writes on raw device) */
+	Iget             int64  /* number of inode lookups */
+	Namei            int64  /* number of vnode lookup from a path name */
+	Dirblk           int64  /* number of 512-byte block reads by the directory search routine to locate an entry for a file */
+	Msg              int64  /* number of IPC message operations */
+	Sema             int64  /* number of IPC semaphore operations  */
+	MinFaults        int64  /* number of page faults with no I/O */
+	MajFaults        int64  /* number of page faults with disk I/O */
+	PUser            int64  /* raw number of physical processor tics in user mode */
+	PSys             int64  /* raw number of physical processor tics in system mode */
+	PIdle            int64  /* raw number of physical processor tics idle */
+	PWait            int64  /* raw number of physical processor tics waiting for I/O */
+	RedispSD0        int64  /* number of thread redispatches within the scheduler affinity domain 0 */
+	RedispSD1        int64  /* number of thread redispatches within the scheduler affinity domain 1 */
+	RedispSD2        int64  /* number of thread redispatches within the scheduler affinity domain 2 */
+	RedispSD3        int64  /* number of thread redispatches within the scheduler affinity domain 3 */
+	RedispSD4        int64  /* number of thread redispatches within the scheduler affinity domain 4 */
+	RedispSD5        int64  /* number of thread redispatches within the scheduler affinity domain 5 */
+	MigrationPush    int64  /* number of thread migrations from the local runque to another queue due to starvation load balancing */
+	MigrationS3grq   int64  /* number of  thread migrations from the global runque to the local runque resulting in a move accross scheduling domain 3 */
+	MigrationS3pul   int64  /* number of  thread migrations from another processor's runque resulting in a move accross scheduling domain 3 */
+	InvolCSwitch     int64  /* number of  involuntary thread context switches */
+	VolCSwitch       int64  /* number of  voluntary thread context switches */
+	RunQueue         int64  /* number of  threads on the runque */
+	Bound            int64  /* number of  bound threads */
+	DecrIntrs        int64  /* number of decrementer tics interrupts */
+	MpcRIntrs        int64  /* number of mpc's received interrupts */
+	MpcSIntrs        int64  /* number of mpc's sent interrupts */
+	DevIntrs         int64  /* number of device interrupts */
+	SoftIntrs        int64  /* number of offlevel handlers called */
+	PhantIntrs       int64  /* number of phantom interrupts */
+	IdleDonatedPurr  int64  /* number of idle cycles donated by a dedicated partition enabled for donation */
+	IdleDonatedSpurr int64  /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+	BusyDonatedPurr  int64  /* number of busy cycles donated by a dedicated partition enabled for donation */
+	BusyDonatedSpurr int64  /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+	IdleStolenPurr   int64  /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+	IdleStolenSpurr  int64  /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+	BusyStolenPurr   int64  /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+	BusyStolenSpurr  int64  /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+	Hpi              int64  /* number of hypervisor page-ins */
+	Hpit             int64  /* Time spent in hypervisor page-ins (in nanoseconds)*/
+	PUserSpurr       int64  /* number of spurr cycles spent in user mode */
+	PSysSpurr        int64  /* number of spurr cycles spent in kernel mode */
+	PIdleSpurr       int64  /* number of spurr cycles spent in idle mode */
+	PWaitSpurr       int64  /* number of spurr cycles spent in wait mode */
+	SpurrFlag        int32  /* set if running in spurr mode */
+	LocalDispatch    int64  /* number of local thread dispatches on this logical CPU */
+	NearDispatch     int64  /* number of near thread dispatches on this logical CPU */
+	FarDispatch      int64  /* number of far thread dispatches on this logical CPU */
+	CSwitches        int64  /* Context switches */
+	Version          int64  /* version number (1, 2, etc.,) */
+	TbLast           int64  /* timebase counter */
+	State            int    /* Show whether the CPU is offline or online */
+	VtbLast          int64  /* Last virtual timebase read */
+	ICountLast       int64  /* Last instruction count read */
+}
+
+type CPUTotal struct {
+	NCpus            int     /* number of active logical processors */
+	NCpusCfg         int     /* number of configured processors */
+	Description      string  /* processor description (type/official name) */
+	ProcessorHz      int64   /* processor speed in Hz */
+	User             int64   /*  raw total number of clock ticks spent in user mode */
+	Sys              int64   /* raw total number of clock ticks spent in system mode */
+	Idle             int64   /* raw total number of clock ticks spent idle */
+	Wait             int64   /* raw total number of clock ticks spent waiting for I/O */
+	PSwitch          int64   /* number of process switches (change in currently running process) */
+	Syscall          int64   /* number of system calls executed */
+	Sysread          int64   /* number of read system calls executed */
+	Syswrite         int64   /* number of write system calls executed */
+	Sysfork          int64   /* number of forks system calls executed */
+	Sysexec          int64   /* number of execs system calls executed */
+	Readch           int64   /* number of characters tranferred with read system call */
+	Writech          int64   /* number of characters tranferred with write system call */
+	DevIntrs         int64   /* number of device interrupts */
+	SoftIntrs        int64   /* number of software interrupts */
+	Lbolt            int64   /* number of ticks since last reboot */
+	LoadAvg1         float32 /* times the average number of runnables processes during the last 1, 5 and 15 minutes.    */
+	LoadAvg5         float32 /* times the average number of runnables processes during the last 1, 5 and 15 minutes.    */
+	LoadAvg15        float32 /* times the average number of runnables processes during the last 1, 5 and 15 minutes.    */
+	RunQueue         int64   /* length of the run queue (processes ready) */
+	SwpQueue         int64   /* length of the swap queue (processes waiting to be paged in) */
+	Bread            int64   /* number of blocks read */
+	Bwrite           int64   /* number of blocks written */
+	Lread            int64   /* number of logical read requests */
+	Lwrite           int64   /* number of logical write requests */
+	Phread           int64   /* number of physical reads (reads on raw devices) */
+	Phwrite          int64   /* number of physical writes (writes on raw devices) */
+	RunOcc           int64   /* updated whenever runque is updated, i.e. the runqueue is occupied. This can be used to compute the simple average of ready processes  */
+	SwpOcc           int64   /* updated whenever swpque is updated. i.e. the swpqueue is occupied. This can be used to compute the simple average processes waiting to be paged in */
+	Iget             int64   /* number of inode lookups */
+	Namei            int64   /* number of vnode lookup from a path name */
+	Dirblk           int64   /* number of 512-byte block reads by the directory search routine to locate an entry for a file */
+	Msg              int64   /* number of IPC message operations */
+	Sema             int64   /* number of IPC semaphore operations */
+	RcvInt           int64   /* number of tty receive interrupts */
+	XmtInt           int64   /* number of tyy transmit interrupts */
+	MdmInt           int64   /* number of modem interrupts */
+	TtyRawInch       int64   /* number of raw input characters  */
+	TtyCanInch       int64   /* number of canonical input characters (always zero) */
+	TtyRawOutch      int64   /* number of raw output characters */
+	Ksched           int64   /* number of kernel processes created */
+	Koverf           int64   /* kernel process creation attempts where: -the user has forked to their maximum limit -the configuration limit of processes has been reached */
+	Kexit            int64   /* number of kernel processes that became zombies */
+	Rbread           int64   /* number of remote read requests */
+	Rcread           int64   /* number of cached remote reads */
+	Rbwrt            int64   /* number of remote writes */
+	Rcwrt            int64   /* number of cached remote writes */
+	Traps            int64   /* number of traps */
+	NCpusHigh        int64   /* index of highest processor online */
+	PUser            int64   /* raw number of physical processor tics in user mode */
+	PSys             int64   /* raw number of physical processor tics in system mode */
+	PIdle            int64   /* raw number of physical processor tics idle */
+	PWait            int64   /* raw number of physical processor tics waiting for I/O */
+	DecrIntrs        int64   /* number of decrementer tics interrupts */
+	MpcRIntrs        int64   /* number of mpc's received interrupts */
+	MpcSIntrs        int64   /* number of mpc's sent interrupts */
+	PhantIntrs       int64   /* number of phantom interrupts */
+	IdleDonatedPurr  int64   /* number of idle cycles donated by a dedicated partition enabled for donation */
+	IdleDonatedSpurr int64   /* number of idle spurr cycles donated by a dedicated partition enabled for donation */
+	BusyDonatedPurr  int64   /* number of busy cycles donated by a dedicated partition enabled for donation */
+	BusyDonatedSpurr int64   /* number of busy spurr cycles donated by a dedicated partition enabled for donation */
+	IdleStolenPurr   int64   /* number of idle cycles stolen by the hypervisor from a dedicated partition */
+	IdleStolenSpurr  int64   /* number of idle spurr cycles stolen by the hypervisor from a dedicated partition */
+	BusyStolenPurr   int64   /* number of busy cycles stolen by the hypervisor from a dedicated partition */
+	BusyStolenSpurr  int64   /* number of busy spurr cycles stolen by the hypervisor from a dedicated partition */
+	IOWait           int32   /* number of processes that are asleep waiting for buffered I/O */
+	PhysIO           int32   /* number of processes waiting for raw I/O */
+	TWait            int64   /* number of threads that are waiting for filesystem direct(cio) */
+	Hpi              int64   /* number of hypervisor page-ins */
+	Hpit             int64   /* Time spent in hypervisor page-ins (in nanoseconds) */
+	PUserSpurr       int64   /* number of spurr cycles spent in user mode */
+	PSysSpurr        int64   /* number of spurr cycles spent in kernel mode */
+	PIdleSpurr       int64   /* number of spurr cycles spent in idle mode */
+	PWaitSpurr       int64   /* number of spurr cycles spent in wait mode */
+	SpurrFlag        int     /* set if running in spurr mode */
+	Version          int64   /* version number (1, 2, etc.,) */
+	TbLast           int64   /*time base counter */
+	PurrCoalescing   int64   /* If the calling partition is authorized to see pool wide statistics then PURR cycles consumed to coalesce data else set to zero.*/
+	SpurrCoalescing  int64   /* If the calling partition is authorized to see pool wide statistics then SPURR cycles consumed to coalesce data else set to zero.  */
+}
+
+type CPUUtil struct {
+	Version          int64
+	CpuID            string  /* holds the id of the cpu */
+	Entitlement      float32 /* Partition's entitlement */
+	UserPct          float32 /* % of utilization in user mode */
+	KernPct          float32 /* % of utilization in kernel mode */
+	IdlePct          float32 /* % of utilization in idle mode */
+	WaitPct          float32 /* % of utilization in wait mode */
+	PhysicalBusy     float32 /* physical cpus busy */
+	PhysicalConsumed float32 /* total cpus consumed by the partition */
+	FreqPct          float32 /* Average freq% over the last interval */
+	EntitlementPct   float32 /* % of entitlement used */
+	BusyPct          float32 /* % of entitlement busy */
+	IdleDonatedPct   float32 /* % idle cycles donated */
+	BusyDonatedPct   float32 /* % of busy cycles donated */
+	IdleStolenPct    float32 /* % idle cycles stolen */
+	BusyStolenPct    float32 /* % busy cycles stolen */
+	LUserPct         float32 /* % of utilization in user mode, in terms of logical processor ticks */
+	LKernPct         float32 /* % of utilization in kernel mode, in terms of logical processor ticks*/
+	LIdlePct         float32 /* % of utilization in idle mode, in terms of logical processor ticks */
+	LWaitPct         float32 /* % of utilization in wait mode, in terms of logical processor ticks */
+	DeltaTime        int64   /*   delta time in milliseconds, for which utilization is evaluated */
+}
diff --git a/vendor/github.com/power-devops/perfstat/types_disk.go b/vendor/github.com/power-devops/perfstat/types_disk.go
new file mode 100644
index 000000000..50e323dbe
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/types_disk.go
@@ -0,0 +1,176 @@
+package perfstat
+
+type DiskTotal struct {
+	Number    int32 /* total number of disks */
+	Size      int64 /* total size of all disks (in MB) */
+	Free      int64 /* free portion of all disks (in MB) */
+	XRate     int64 /* __rxfers: total number of transfers from disk */
+	Xfers     int64 /* total number of transfers to/from disk */
+	Wblks     int64 /* 512 bytes blocks written to all disks */
+	Rblks     int64 /* 512 bytes blocks read from all disks */
+	Time      int64 /* amount of time disks are active */
+	Version   int64 /* version number (1, 2, etc.,) */
+	Rserv     int64 /* Average read or receive service time */
+	MinRserv  int64 /* min read or receive service time */
+	MaxRserv  int64 /* max read or receive service time */
+	RTimeOut  int64 /* number of read request timeouts */
+	RFailed   int64 /* number of failed read requests */
+	Wserv     int64 /* Average write or send service time */
+	MinWserv  int64 /* min write or send service time */
+	MaxWserv  int64 /* max write or send service time */
+	WTimeOut  int64 /* number of write request timeouts */
+	WFailed   int64 /* number of failed write requests */
+	WqDepth   int64 /* instantaneous wait queue depth (number of requests waiting to be sent to disk) */
+	WqTime    int64 /* accumulated wait queueing time */
+	WqMinTime int64 /* min wait queueing time */
+	WqMaxTime int64 /* max wait queueing time */
+}
+
+// Disk Adapter Types
+const (
+	DA_SCSI  = 0 /* 0 ==> SCSI, SAS, other legacy adapter types */
+	DA_VSCSI = 1 /* 1 ==> Virtual SCSI/SAS Adapter */
+	DA_FCA   = 2 /* 2 ==> Fiber Channel Adapter */
+)
+
+type DiskAdapter struct {
+	Name        string /* name of the adapter (from ODM) */
+	Description string /* adapter description (from ODM) */
+	Number      int32  /* number of disks connected to adapter */
+	Size        int64  /* total size of all disks (in MB)  */
+	Free        int64  /* free portion of all disks (in MB)  */
+	XRate       int64  /* __rxfers: total number of reads via adapter */
+	Xfers       int64  /* total number of transfers via adapter */
+	Rblks       int64  /* 512 bytes blocks written via adapter */
+	Wblks       int64  /* 512 bytes blocks read via adapter  */
+	Time        int64  /* amount of time disks are active */
+	Version     int64  /* version number (1, 2, etc.,) */
+	AdapterType int64  /* 0 ==> SCSI, SAS, other legacy adapter types, 1 ==> Virtual SCSI/SAS Adapter, 2 ==> Fiber Channel Adapter */
+	DkBSize     int64  /* Number of Bytes in a block for this disk*/
+	DkRxfers    int64  /* Number of transfers from disk */
+	DkRserv     int64  /* read or receive service time */
+	DkWserv     int64  /* write or send service time */
+	MinRserv    int64  /* Minimum read service time */
+	MaxRserv    int64  /* Maximum read service time */
+	MinWserv    int64  /* Minimum Write service time */
+	MaxWserv    int64  /* Maximum write service time */
+	WqDepth     int64  /* driver wait queue depth */
+	WqSampled   int64  /* accumulated sampled dk_wq_depth */
+	WqTime      int64  /* accumulated wait queueing time */
+	WqMinTime   int64  /* minimum wait queueing time */
+	WqMaxTime   int64  /* maximum wait queueing time */
+	QFull       int64  /* "Service" queue full occurrence count (number of times the adapter/devices connected to the adapter is not accepting any more request) */
+	QSampled    int64  /* accumulated sampled */
+}
+
+type Disk struct {
+	Name        string /* name of the disk */
+	Description string /* disk description (from ODM) */
+	VGName      string /* volume group name (from ODM) */
+	Size        int64  /* size of the disk (in MB) */
+	Free        int64  /* free portion of the disk (in MB) */
+	BSize       int64  /* disk block size (in bytes) */
+	XRate       int64  /* number of transfers from disk */
+	Xfers       int64  /* number of transfers to/from disk */
+	Wblks       int64  /* number of blocks written to disk */
+	Rblks       int64  /* number of blocks read from disk */
+	QDepth      int64  /* instantaneous "service" queue depth (number of requests sent to disk and not completed yet) */
+	Time        int64  /* amount of time disk is active */
+	Adapter     string /* disk adapter name */
+	PathsCount  int32  /* number of paths to this disk */
+	QFull       int64  /* "service" queue full occurrence count (number of times the disk is not accepting any more request) */
+	Rserv       int64  /* read or receive service time */
+	RTimeOut    int64  /* number of read request timeouts */
+	Rfailed     int64  /* number of failed read requests */
+	MinRserv    int64  /* min read or receive service time */
+	MaxRserv    int64  /* max read or receive service time */
+	Wserv       int64  /* write or send service time */
+	WTimeOut    int64  /* number of write request timeouts */
+	Wfailed     int64  /* number of failed write requests */
+	MinWserv    int64  /* min write or send service time */
+	MaxWserv    int64  /* max write or send service time */
+	WqDepth     int64  /* instantaneous wait queue depth (number of requests waiting to be sent to disk) */
+	WqSampled   int64  /* accumulated sampled dk_wq_depth */
+	WqTime      int64  /* accumulated wait queueing time */
+	WqMinTime   int64  /* min wait queueing time */
+	WqMaxTime   int64  /* max wait queueing time */
+	QSampled    int64  /* accumulated sampled dk_q_depth */
+	Version     int64  /* version number (1, 2, etc.,) */
+	PseudoDisk  bool   /*Indicates whether pseudo or physical disk */
+	VTDisk      bool   /* 1- Virtual Target Disk, 0 - Others */
+}
+
+type DiskPath struct {
+	Name      string /* name of the path */
+	XRate     int64  /* __rxfers: number of reads via the path */
+	Xfers     int64  /* number of transfers via the path */
+	Rblks     int64  /* 512 bytes blocks written via the path */
+	Wblks     int64  /* 512 bytes blocks read via the path  */
+	Time      int64  /* amount of time disks are active */
+	Adapter   string /* disk adapter name (from ODM) */
+	QFull     int64  /* "service" queue full occurrence count (number of times the disk is not accepting any more request) */
+	Rserv     int64  /* read or receive service time */
+	RTimeOut  int64  /* number of read request timeouts */
+	Rfailed   int64  /* number of failed read requests */
+	MinRserv  int64  /* min read or receive service time */
+	MaxRserv  int64  /* max read or receive service time */
+	Wserv     int64  /* write or send service time */
+	WTimeOut  int64  /* number of write request timeouts */
+	Wfailed   int64  /* number of failed write requests */
+	MinWserv  int64  /* min write or send service time */
+	MaxWserv  int64  /* max write or send service time */
+	WqDepth   int64  /* instantaneous wait queue depth (number of requests waiting to be sent to disk) */
+	WqSampled int64  /* accumulated sampled dk_wq_depth */
+	WqTime    int64  /* accumulated wait queueing time */
+	WqMinTime int64  /* min wait queueing time */
+	WqMaxTime int64  /* max wait queueing time */
+	QSampled  int64  /* accumulated sampled dk_q_depth */
+	Version   int64  /* version number (1, 2, etc.,)   */
+}
+
+const (
+	FC_DOWN = 0 // FC Adapter state is DOWN
+	FC_UP   = 1 // FC Adapter state is UP
+)
+
+const (
+	FCT_FCHBA = 0 // FC type - real Fiber Channel Adapter
+	FCT_VFC   = 1 // FC type - virtual Fiber Channel
+)
+
+type FCAdapter struct {
+	Version                      int64  /* version number (1, 2, etc.,) */
+	Name                         string /* name of the adapter */
+	State                        int32  /* FC Adapter state  UP or DOWN */
+	InputRequests                int64  /* Number of Input Requests*/
+	OutputRequests               int64  /* Number of Output Requests */
+	InputBytes                   int64  /* Number of Input Bytes */
+	OutputBytes                  int64  /* Number of Output Bytes */
+	EffMaxTransfer               int64  /* Adapter's Effective Maximum  Transfer Value */
+	NoDMAResourceCnt             int64  /* Count of DMA failures due to no DMA Resource available */
+	NoCmdResourceCnt             int64  /* Count of failures to allocate a command due to no command resource available */
+	AttentionType                int32  /* Link up or down Indicator */
+	SecondsSinceLastReset        int64  /* Displays the seconds since last reset of the statistics on the adapter */
+	TxFrames                     int64  /* Number of frames transmitted */
+	TxWords                      int64  /* Fiber Channel Kbytes transmitted */
+	RxFrames                     int64  /* Number of Frames Received */
+	RxWords                      int64  /* Fiber Channel Kbytes Received */
+	LIPCount                     int64  /* Count of LIP (Loop Initialization Protocol) Events received in case we have FC-AL */
+	NOSCount                     int64  /* Count of NOS (Not_Operational) Events. This indicates a link failure state. */
+	ErrorFrames                  int64  /* Number of frames received with the CRC Error */
+	DumpedFrames                 int64  /* Number of lost frames */
+	LinkFailureCount             int64  /* Count of Link failures */
+	LossofSyncCount              int64  /* Count of loss of sync */
+	LossofSignal                 int64  /* Count of loss of Signal */
+	PrimitiveSeqProtocolErrCount int64  /* number of times a primitive sequence was in error */
+	InvalidTxWordCount           int64  /* Count of Invalid Transmission words received */
+	InvalidCRCCount              int64  /* Count of CRC Errors in a Received Frame */
+	PortFcId                     int64  /* SCSI Id of the adapter */
+	PortSpeed                    int64  /* Speed of Adapter in GBIT */
+	PortType                     string /* Type of connection. The Possible Values are Fabric, Private Loop, Point-to-Point, unknown */
+	PortWWN                      int64  /* World Wide Port name */
+	PortSupportedSpeed           int64  /* Supported Port Speed in GBIT */
+	AdapterType                  int    /* 0 - Fiber Chanel, 1 - Virtual Fiber Chanel Adapter */
+	VfcName                      string /* name of the Virtual Fiber Chanel(VFC) adapter */
+	ClientPartName               string /* name of the client partition */
+}
diff --git a/vendor/github.com/power-devops/perfstat/types_fs.go b/vendor/github.com/power-devops/perfstat/types_fs.go
new file mode 100644
index 000000000..b4b43ac61
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/types_fs.go
@@ -0,0 +1,195 @@
+package perfstat
+
+import (
+	"strings"
+)
+
+type FileSystem struct {
+	Device      string /* name of the mounted device */
+	MountPoint  string /* where the device is mounted */
+	FSType      int    /* File system type, see the constants below */
+	Flags       uint   /* Flags of the file system */
+	TotalBlocks int64  /* number of 512 bytes blocks in the filesystem */
+	FreeBlocks  int64  /* number of free 512 bytes block in the filesystem */
+	TotalInodes int64  /* total number of inodes in the filesystem */
+	FreeInodes  int64  /* number of free inodes in the filesystem */
+}
+
+func (f *FileSystem) TypeString() string {
+	switch f.FSType {
+	case FS_JFS2:
+		return "jfs2"
+	case FS_NAMEFS:
+		return "namefs"
+	case FS_NFS:
+		return "nfs"
+	case FS_JFS:
+		return "jfs"
+	case FS_CDROM:
+		return "cdrfs"
+	case FS_PROCFS:
+		return "procfs"
+	case FS_SFS:
+		return "sfs"
+	case FS_CACHEFS:
+		return "cachefs"
+	case FS_NFS3:
+		return "nfs3"
+	case FS_AUTOFS:
+		return "autofs"
+	case FS_POOLFS:
+		return "poolfs"
+	case FS_VXFS:
+		return "vxfs"
+	case FS_VXODM:
+		return "vxodm"
+	case FS_UDF:
+		return "udfs"
+	case FS_NFS4:
+		return "nfs4"
+	case FS_RFS4:
+		return "rfs4"
+	case FS_CIFS:
+		return "cifs"
+	case FS_PMEMFS:
+		return "pmemfs"
+	case FS_AHAFS:
+		return "ahafs"
+	case FS_STNFS:
+		return "stnfs"
+	case FS_ASMFS:
+		return "asmfs"
+	}
+	return "unknown"
+}
+
+func (f *FileSystem) FlagsString() string {
+	var flags []string
+
+	switch {
+	case f.Flags&VFS_READONLY != 0:
+		flags = append(flags, "ro")
+	case f.Flags&VFS_REMOVABLE != 0:
+		flags = append(flags, "removable")
+	case f.Flags&VFS_DEVMOUNT != 0:
+		flags = append(flags, "local")
+	case f.Flags&VFS_REMOTE != 0:
+		flags = append(flags, "remote")
+	case f.Flags&VFS_SYSV_MOUNT != 0:
+		flags = append(flags, "sysv")
+	case f.Flags&VFS_UNMOUNTING != 0:
+		flags = append(flags, "unmounting")
+	case f.Flags&VFS_NOSUID != 0:
+		flags = append(flags, "nosuid")
+	case f.Flags&VFS_NODEV != 0:
+		flags = append(flags, "nodev")
+	case f.Flags&VFS_NOINTEG != 0:
+		flags = append(flags, "nointeg")
+	case f.Flags&VFS_NOMANAGER != 0:
+		flags = append(flags, "nomanager")
+	case f.Flags&VFS_NOCASE != 0:
+		flags = append(flags, "nocase")
+	case f.Flags&VFS_UPCASE != 0:
+		flags = append(flags, "upcase")
+	case f.Flags&VFS_NBC != 0:
+		flags = append(flags, "nbc")
+	case f.Flags&VFS_MIND != 0:
+		flags = append(flags, "mind")
+	case f.Flags&VFS_RBR != 0:
+		flags = append(flags, "rbr")
+	case f.Flags&VFS_RBW != 0:
+		flags = append(flags, "rbw")
+	case f.Flags&VFS_DISCONNECTED != 0:
+		flags = append(flags, "disconnected")
+	case f.Flags&VFS_SHUTDOWN != 0:
+		flags = append(flags, "shutdown")
+	case f.Flags&VFS_VMOUNTOK != 0:
+		flags = append(flags, "vmountok")
+	case f.Flags&VFS_SUSER != 0:
+		flags = append(flags, "suser")
+	case f.Flags&VFS_SOFT_MOUNT != 0:
+		flags = append(flags, "soft")
+	case f.Flags&VFS_UNMOUNTED != 0:
+		flags = append(flags, "unmounted")
+	case f.Flags&VFS_DEADMOUNT != 0:
+		flags = append(flags, "deadmount")
+	case f.Flags&VFS_SNAPSHOT != 0:
+		flags = append(flags, "snapshot")
+	case f.Flags&VFS_VCM_ON != 0:
+		flags = append(flags, "vcm_on")
+	case f.Flags&VFS_VCM_MONITOR != 0:
+		flags = append(flags, "vcm_monitor")
+	case f.Flags&VFS_ATIMEOFF != 0:
+		flags = append(flags, "noatime")
+	case f.Flags&VFS_READMOSTLY != 0:
+		flags = append(flags, "readmostly")
+	case f.Flags&VFS_CIOR != 0:
+		flags = append(flags, "cior")
+	case f.Flags&VFS_CIO != 0:
+		flags = append(flags, "cio")
+	case f.Flags&VFS_DIO != 0:
+		flags = append(flags, "dio")
+	}
+
+	return strings.Join(flags, ",")
+}
+
+// Filesystem types
+const (
+	FS_JFS2    = 0  /* AIX physical fs "jfs2" */
+	FS_NAMEFS  = 1  /* AIX pseudo fs "namefs" */
+	FS_NFS     = 2  /* SUN Network File System "nfs" */
+	FS_JFS     = 3  /* AIX R3 physical fs "jfs" */
+	FS_CDROM   = 5  /* CDROM File System "cdrom" */
+	FS_PROCFS  = 6  /* PROCFS File System "proc" */
+	FS_SFS     = 16 /* AIX Special FS (STREAM mounts) */
+	FS_CACHEFS = 17 /* Cachefs file system */
+	FS_NFS3    = 18 /* NFSv3 file system */
+	FS_AUTOFS  = 19 /* Automount file system */
+	FS_POOLFS  = 20 /* Pool file system */
+	FS_VXFS    = 32 /* THRPGIO File System "vxfs" */
+	FS_VXODM   = 33 /* For Veritas File System */
+	FS_UDF     = 34 /* UDFS file system */
+	FS_NFS4    = 35 /* NFSv4 file system */
+	FS_RFS4    = 36 /* NFSv4 Pseudo file system */
+	FS_CIFS    = 37 /* AIX SMBFS (CIFS client) */
+	FS_PMEMFS  = 38 /* MCR Async Mobility pseudo file system */
+	FS_AHAFS   = 39 /* AHAFS File System "aha" */
+	FS_STNFS   = 40 /* Short-Term NFS */
+	FS_ASMFS   = 41 /* Oracle ASM FS */
+)
+
+// Filesystem flags
+const (
+	VFS_READONLY     = 0x00000001 /* rdonly access to vfs */
+	VFS_REMOVABLE    = 0x00000002 /* removable (diskette) media */
+	VFS_DEVMOUNT     = 0x00000004 /* physical device mount */
+	VFS_REMOTE       = 0x00000008 /* file system is on network */
+	VFS_SYSV_MOUNT   = 0x00000010 /* System V style mount */
+	VFS_UNMOUNTING   = 0x00000020 /* originated by unmount() */
+	VFS_NOSUID       = 0x00000040 /* don't maintain suid-ness across this mount */
+	VFS_NODEV        = 0x00000080 /* don't allow device access across this mount */
+	VFS_NOINTEG      = 0x00000100 /* no integrity mount option */
+	VFS_NOMANAGER    = 0x00000200 /* mount managed fs w/o manager */
+	VFS_NOCASE       = 0x00000400 /* do not map dir names */
+	VFS_UPCASE       = 0x00000800 /* map dir names to uppercase */
+	VFS_NBC          = 0x00001000 /* NBC cached file in this vfs */
+	VFS_MIND         = 0x00002000 /* multi-segment .indirect */
+	VFS_RBR          = 0x00004000 /* Release-behind when reading */
+	VFS_RBW          = 0x00008000 /* Release-behind when writing */
+	VFS_DISCONNECTED = 0x00010000 /* file mount not in use */
+	VFS_SHUTDOWN     = 0x00020000 /* forced unmount for shutdown */
+	VFS_VMOUNTOK     = 0x00040000 /* dir/file mnt permission flag */
+	VFS_SUSER        = 0x00080000 /* client-side suser perm. flag */
+	VFS_SOFT_MOUNT   = 0x00100000 /* file-over-file or directory over directory "soft" mount */
+	VFS_UNMOUNTED    = 0x00200000 /* unmount completed, stale vnodes are left in the vfs */
+	VFS_DEADMOUNT    = 0x00400000 /* softmount vfs should be disconnected at last vnode free */
+	VFS_SNAPSHOT     = 0x00800000 /* snapshot mount */
+	VFS_VCM_ON       = 0x01000000 /* VCM is currently active */
+	VFS_VCM_MONITOR  = 0x02000000 /* VCM monitoring is active */
+	VFS_ATIMEOFF     = 0x04000000 /* no atime updates during i/o */
+	VFS_READMOSTLY   = 0x10000000 /* ROFS allows open for write */
+	VFS_CIOR         = 0x20000000 /* O_CIOR mount */
+	VFS_CIO          = 0x40000000 /* O_CIO mount */
+	VFS_DIO          = 0x80000000 /* O_DIRECT mount */
+)
diff --git a/vendor/github.com/power-devops/perfstat/types_lpar.go b/vendor/github.com/power-devops/perfstat/types_lpar.go
new file mode 100644
index 000000000..f95f8c300
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/types_lpar.go
@@ -0,0 +1,129 @@
+package perfstat
+
+type PartitionType struct {
+	SmtCapable        bool /* OS supports SMT mode */
+	SmtEnabled        bool /* SMT mode is on */
+	LparCapable       bool /* OS supports logical partitioning */
+	LparEnabled       bool /* logical partitioning is on */
+	SharedCapable     bool /* OS supports shared processor LPAR */
+	SharedEnabled     bool /* partition runs in shared mode */
+	DLparCapable      bool /* OS supports dynamic LPAR */
+	Capped            bool /* partition is capped */
+	Kernel64bit       bool /* kernel is 64 bit */
+	PoolUtilAuthority bool /* pool utilization available */
+	DonateCapable     bool /* capable of donating cycles */
+	DonateEnabled     bool /* enabled for donating cycles */
+	AmsCapable        bool /* 1 = AMS(Active Memory Sharing) capable, 0 = Not AMS capable */
+	AmsEnabled        bool /* 1 = AMS(Active Memory Sharing) enabled, 0 = Not AMS enabled */
+	PowerSave         bool /*1= Power saving mode is enabled*/
+	AmeEnabled        bool /* Active Memory Expansion is enabled */
+	SharedExtended    bool
+}
+
+type PartitionValue struct {
+	Online  int64
+	Max     int64
+	Min     int64
+	Desired int64
+}
+
+type PartitionConfig struct {
+	Version                  int64          /* Version number */
+	Name                     string         /* Partition Name */
+	Node                     string         /* Node Name */
+	Conf                     PartitionType  /* Partition Properties */
+	Number                   int32          /* Partition Number */
+	GroupID                  int32          /* Group ID */
+	ProcessorFamily          string         /* Processor Type */
+	ProcessorModel           string         /* Processor Model */
+	MachineID                string         /* Machine ID */
+	ProcessorMhz             float64        /* Processor Clock Speed in MHz */
+	NumProcessors            PartitionValue /* Number of Configured Physical Processors in frame*/
+	OSName                   string         /* Name of Operating System */
+	OSVersion                string         /* Version of operating System */
+	OSBuild                  string         /* Build of Operating System */
+	LCpus                    int32          /* Number of Logical CPUs */
+	SmtThreads               int32          /* Number of SMT Threads */
+	Drives                   int32          /* Total Number of Drives */
+	NetworkAdapters          int32          /* Total Number of Network Adapters */
+	CpuCap                   PartitionValue /* Min, Max and Online CPU Capacity */
+	Weightage                int32          /* Variable Processor Capacity Weightage */
+	EntCapacity              int32          /* number of processor units this partition is entitled to receive */
+	VCpus                    PartitionValue /* Min, Max and Online Virtual CPUs */
+	PoolID                   int32          /* Shared Pool ID of physical processors, to which this partition belongs*/
+	ActiveCpusInPool         int32          /* Count of physical CPUs in the shared processor pool, to which this partition belongs */
+	PoolWeightage            int32          /* Pool Weightage */
+	SharedPCpu               int32          /* Number of physical processors allocated for shared processor use */
+	MaxPoolCap               int32          /* Maximum processor capacity of partition's pool */
+	EntPoolCap               int32          /* Entitled processor capacity of partition's pool */
+	Mem                      PartitionValue /* Min, Max and Online Memory */
+	MemWeightage             int32          /* Variable Memory Capacity Weightage */
+	TotalIOMemoryEntitlement int64          /* I/O Memory Entitlement of the partition in bytes */
+	MemPoolID                int32          /* AMS pool id of the pool the LPAR belongs to */
+	HyperPgSize              int64          /* Hypervisor page size in KB*/
+	ExpMem                   PartitionValue /* Min, Max and Online Expanded Memory */
+	TargetMemExpFactor       int64          /* Target Memory Expansion Factor scaled by 100 */
+	TargetMemExpSize         int64          /* Expanded Memory Size in MB */
+	SubProcessorMode         int32          /* Split core mode, its value can be 0,1,2 or 4. 0 for unsupported, 1 for capable but not enabled, 2 or 4 for enabled*/
+}
+
+const (
+	AME_TYPE_V1           = 0x1
+	AME_TYPE_V2           = 0x2
+	LPAR_INFO_CAPPED      = 0x01 /* Parition Capped */
+	LPAR_INFO_AUTH_PIC    = 0x02 /* Authority granted for poolidle*/
+	LPAR_INFO_SMT_ENABLED = 0x04 /* SMT Enabled */
+	LPAR_INFO_WPAR_ACTIVE = 0x08 /* Process Running Within a WPAR */
+	LPAR_INFO_EXTENDED    = 0x10 /* Extended shared processor pool information */
+	LPAR_INFO_AME_ENABLED = 0x20 /* Active Mem. Expansion (AME) enabled*/
+	LPAR_INFO_SEM_ENABLED = 0x40 /* Speculative Execution Mode enabled */
+)
+
+type PartitionInfo struct {
+	Version               int    /* version for this structure */
+	OnlineMemory          uint64 /* MB of currently online memory */
+	TotalDispatchTime     uint64 /* Total lpar dispatch time in nsecs */
+	PoolIdleTime          uint64 /* Idle time of shared CPU pool nsecs*/
+	DispatchLatency       uint64 /* Max latency inbetween dispatches of this LPAR on physCPUS in nsecs */
+	LparFlags             uint   /* LPAR flags */
+	PCpusInSys            uint   /* # of active licensed physical CPUs in system */
+	OnlineVCpus           uint   /* # of current online virtual CPUs */
+	OnlineLCpus           uint   /* # of current online logical CPUs */
+	PCpusInPool           uint   /* # physical CPUs in shared pool */
+	UnallocCapacity       uint   /* Unallocated Capacity available in shared pool */
+	EntitledCapacity      uint   /* Entitled Processor Capacity for this partition */
+	VariableWeight        uint   /* Variable Processor Capacity Weight */
+	UnallocWeight         uint   /* Unallocated Variable Weight available for this partition */
+	MinReqVCpuCapacity    uint   /* OS minimum required virtual processor capacity. */
+	GroupId               uint8  /* ID of a LPAR group/aggregation */
+	PoolId                uint8  /* ID of a shared pool */
+	ShCpusInSys           uint   /* # of physical processors allocated for shared processor use */
+	MaxPoolCapacity       uint   /* Maximum processor capacity of partition's pool */
+	EntitledPoolCapacity  uint   /* Entitled processor capacity of partition's pool */
+	PoolMaxTime           uint64 /* Summation of maximum time that could be consumed by the pool, in nanoseconds */
+	PoolBusyTime          uint64 /* Summation of busy time accumulated across all partitions in the pool, in nanoseconds */
+	PoolScaledBusyTime    uint64 /* Scaled summation of busy time accumulated across all partitions in the pool, in nanoseconds */
+	ShCpuTotalTime        uint64 /* Summation of total time across all physical processors allocated for shared processor use, in nanoseconds */
+	ShCpuBusyTime         uint64 /* Summation of busy time accumulated across all shared processor partitions, in nanoseconds */
+	ShCpuScaledBusyTime   uint64 /* Scaled summation of busy time accumulated across all shared processor partitions, in nanoseconds */
+	EntMemCapacity        uint64 /* Partition's current entitlement memory capacity setting */
+	PhysMem               uint64 /* Amount of physical memory, in bytes, currently backing the partition's logical memory */
+	VrmPoolPhysMem        uint64 /* Total amount of physical memory in the VRM pool */
+	HypPageSize           uint   /* Page size hypervisor is using to virtualize partition's memory */
+	VrmPoolId             int    /* ID of VRM pool */
+	VrmGroupId            int    /* eWLM VRM group to which partition belongs */
+	VarMemWeight          int    /* Partition's current variable memory capacity weighting setting */
+	UnallocVarMemWeight   int    /* Amount of unallocated variable memory capacity weight available to LPAR's group */
+	UnallocEntMemCapacity uint64 /* Amount of unallocated I/O memory entitlement available to LPAR's group */
+	TrueOnlineMemory      uint64 /* true MB of currently online memory */
+	AmeOnlineMemory       uint64 /* AME MB of currently online memory  */
+	AmeType               uint8
+	SpecExecMode          uint8  /* Speculative Execution Mode */
+	AmeFactor             uint   /* memory expansion factor for LPAR */
+	EmPartMajorCode       uint   /* Major and minor codes for our    */
+	EmPartMinorCode       uint   /*   current energy management mode */
+	BytesCoalesced        uint64 /* The number of bytes of the calling partition.s logical real memory  coalesced because they contained duplicated data */
+	BytesCoalescedMemPool uint64 /* If the calling partition is authorized to see pool wide statistics then the number of bytes of logical real memory coalesced because they contained duplicated data in the calling partition.s memory pool else set to zero.*/
+	PurrCoalescing        uint64 /* If the calling partition is authorized to see pool wide statistics then  PURR cycles consumed to coalesce data else set to zero.*/
+	SpurrCoalescing       uint64 /* If the calling partition is authorized to see pool wide statistics then SPURR cycles consumed to coalesce data else set to zero.*/
+}
diff --git a/vendor/github.com/power-devops/perfstat/types_lvm.go b/vendor/github.com/power-devops/perfstat/types_lvm.go
new file mode 100644
index 000000000..8f7176a61
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/types_lvm.go
@@ -0,0 +1,31 @@
+package perfstat
+
+type LogicalVolume struct {
+	Name                   string /* logical volume name */
+	VGName                 string /* volume group name  */
+	OpenClose              int64  /* LVM_QLVOPEN, etc. (see lvm.h) */
+	State                  int64  /* LVM_UNDEF, etc. (see lvm.h) */
+	MirrorPolicy           int64  /* LVM_PARALLEL, etc. (see lvm.h) */
+	MirrorWriteConsistency int64  /* LVM_CONSIST, etc. (see lvm.h) */
+	WriteVerify            int64  /* LVM_VERIFY, etc. (see lvm.h) */
+	PPsize                 int64  /* physical partition size in MB */
+	LogicalPartitions      int64  /* total number of logical paritions configured for this logical volume */
+	Mirrors                int32  /* number of physical mirrors for each logical partition */
+	IOCnt                  int64  /* Number of read and write requests */
+	KBReads                int64  /* Number of Kilobytes read */
+	KBWrites               int64  /* Number of Kilobytes written */
+	Version                int64  /* version number (1, 2, etc.,) */
+}
+
+type VolumeGroup struct {
+	Name                 string /* volume group name */
+	TotalDisks           int64  /* number of physical volumes in the volume group */
+	ActiveDisks          int64  /* number of active physical volumes in the volume group */
+	TotalLogicalVolumes  int64  /* number of logical volumes in the volume group */
+	OpenedLogicalVolumes int64  /* number of logical volumes opened in the volume group */
+	IOCnt                int64  /* Number of read and write requests */
+	KBReads              int64  /* Number of Kilobytes read */
+	KBWrites             int64  /* Number of Kilobytes written */
+	Version              int64  /* version number (1, 2, etc.,) */
+	VariedState          int    /* Indicates volume group available or not */
+}
diff --git a/vendor/github.com/power-devops/perfstat/types_memory.go b/vendor/github.com/power-devops/perfstat/types_memory.go
new file mode 100644
index 000000000..096d29ad2
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/types_memory.go
@@ -0,0 +1,101 @@
+package perfstat
+
+type MemoryTotal struct {
+	VirtualTotal          int64 /* total virtual memory (in 4KB pages) */
+	RealTotal             int64 /* total real memory (in 4KB pages) */
+	RealFree              int64 /* free real memory (in 4KB pages) */
+	RealPinned            int64 /* real memory which is pinned (in 4KB pages) */
+	RealInUse             int64 /* real memory which is in use (in 4KB pages) */
+	BadPages              int64 /* number of bad pages */
+	PageFaults            int64 /* number of page faults */
+	PageIn                int64 /* number of pages paged in */
+	PageOut               int64 /* number of pages paged out */
+	PgSpIn                int64 /* number of page ins from paging space */
+	PgSpOut               int64 /* number of page outs from paging space */
+	Scans                 int64 /* number of page scans by clock */
+	Cycles                int64 /* number of page replacement cycles */
+	PgSteals              int64 /* number of page steals */
+	NumPerm               int64 /* number of frames used for files (in 4KB pages) */
+	PgSpTotal             int64 /* total paging space (in 4KB pages) */
+	PgSpFree              int64 /* free paging space (in 4KB pages) */
+	PgSpRsvd              int64 /* reserved paging space (in 4KB pages) */
+	RealSystem            int64 /* real memory used by system segments (in 4KB pages). */
+	RealUser              int64 /* real memory used by non-system segments (in 4KB pages). */
+	RealProcess           int64 /* real memory used by process segments (in 4KB pages). */
+	VirtualActive         int64 /* Active virtual pages. Virtual pages are considered active if they have been accessed */
+	IOME                  int64 /* I/O memory entitlement of the partition in bytes*/
+	IOMU                  int64 /* I/O memory entitlement of the partition in use in bytes*/
+	IOHWM                 int64 /* High water mark of I/O memory entitlement used in bytes*/
+	PMem                  int64 /* Amount of physical mmeory currently backing partition's logical memory in bytes*/
+	CompressedTotal       int64 /* Total numbers of pages in compressed pool (in 4KB pages) */
+	CompressedWSegPg      int64 /* Number of compressed working storage pages */
+	CPgIn                 int64 /* number of page ins to compressed pool */
+	CPgOut                int64 /* number of page outs from compressed pool */
+	TrueSize              int64 /* True Memory Size in 4KB pages */
+	ExpandedMemory        int64 /* Expanded Memory Size in 4KB pages */
+	CompressedWSegSize    int64 /* Total size of the compressed working storage pages in the pool */
+	TargetCPoolSize       int64 /* Target Compressed Pool Size in bytes */
+	MaxCPoolSize          int64 /* Max Size of Compressed Pool in bytes */
+	MinUCPoolSize         int64 /* Min Size of Uncompressed Pool in bytes */
+	CPoolSize             int64 /* Compressed Pool size in bytes */
+	UCPoolSize            int64 /* Uncompressed Pool size in bytes */
+	CPoolInUse            int64 /* Compressed Pool Used in bytes */
+	UCPoolInUse           int64 /* Uncompressed Pool Used in bytes */
+	Version               int64 /* version number (1, 2, etc.,) */
+	RealAvailable         int64 /* number of pages (in 4KB pages) of memory available without paging out working segments */
+	BytesCoalesced        int64 /* The number of bytes of the calling partition.s logical real memory  coalesced because they contained duplicated data */
+	BytesCoalescedMemPool int64 /* number of bytes of logical real memory coalesced because they contained duplicated data in the calling partition.s memory */
+}
+
+type MemoryPage struct {
+	PSize           int64 /* page size in bytes */
+	RealTotal       int64 /* number of real memory frames of this page size */
+	RealFree        int64 /* number of pages on free list */
+	RealPinned      int64 /* number of pages pinned */
+	RealInUse       int64 /* number of pages in use */
+	PgExct          int64 /* number of page faults  */
+	PgIns           int64 /* number of pages paged in */
+	PgOuts          int64 /* number of pages paged out */
+	PgSpIns         int64 /* number of page ins from paging space */
+	PgSpOuts        int64 /* number of page outs from paging space */
+	Scans           int64 /* number of page scans by clock */
+	Cycles          int64 /* number of page replacement cycles */
+	PgSteals        int64 /* number of page steals */
+	NumPerm         int64 /* number of frames used for files */
+	NumPgSp         int64 /* number of pages with allocated paging space */
+	RealSystem      int64 /* number of pages used by system segments. */
+	RealUser        int64 /* number of pages used by non-system segments. */
+	RealProcess     int64 /* number of pages used by process segments. */
+	VirtActive      int64 /* Active virtual pages. */
+	ComprsdTotal    int64 /* Number of pages of this size compressed */
+	ComprsdWsegPgs  int64 /* Number of compressed working storage pages */
+	CPgIns          int64 /* number of page ins of this page size to compressed pool */
+	CPgOuts         int64 /* number of page outs of this page size from compressed pool */
+	CPoolInUse      int64 /* Compressed Size of this page size in Compressed Pool */
+	UCPoolSize      int64 /* Uncompressed Pool size in bytes of this page size */
+	ComprsdWsegSize int64 /* Total size of the compressed working storage pages in the pool */
+	Version         int64 /* version number (1, 2, etc.,) */
+	RealAvail       int64 /* number of pages (in 4KB pages) of memory available without paging out working segments */
+}
+
+// paging space types
+const (
+	LV_PAGING      = 1
+	NFS_PAGING     = 2
+	UNKNOWN_PAGING = 3
+)
+
+type PagingSpace struct {
+	Name      string /* Paging space name */
+	Type      uint8  /* type of paging device (LV_PAGING or NFS_PAGING) */
+	VGName    string /* volume group name */
+	Hostname  string /* host name of paging server */
+	Filename  string /* swap file name on server */
+	LPSize    int64  /* size in number of logical partitions  */
+	MBSize    int64  /* size in megabytes  */
+	MBUsed    int64  /* portion used in megabytes  */
+	IOPending int64  /* number of pending I/O */
+	Active    uint8  /* indicates if active (1 if so, 0 if not) */
+	Automatic uint8  /* indicates if automatic (1 if so, 0 if not) */
+	Version   int64  /* version number (1, 2, etc.,) */
+}
diff --git a/vendor/github.com/power-devops/perfstat/types_network.go b/vendor/github.com/power-devops/perfstat/types_network.go
new file mode 100644
index 000000000..e69d0041d
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/types_network.go
@@ -0,0 +1,163 @@
+package perfstat
+
+// Network Interface types
+const (
+	IFT_OTHER       = 0x1
+	IFT_1822        = 0x2 /* old-style arpanet imp */
+	IFT_HDH1822     = 0x3 /* HDH arpanet imp */
+	IFT_X25DDN      = 0x4 /* x25 to imp */
+	IFT_X25         = 0x5 /* PDN X25 interface (RFC877) */
+	IFT_ETHER       = 0x6 /* Ethernet CSMACD */
+	IFT_ISO88023    = 0x7 /* CMSA CD */
+	IFT_ISO88024    = 0x8 /* Token Bus */
+	IFT_ISO88025    = 0x9 /* Token Ring */
+	IFT_ISO88026    = 0xa /* MAN */
+	IFT_STARLAN     = 0xb
+	IFT_P10         = 0xc /* Proteon 10MBit ring */
+	IFT_P80         = 0xd /* Proteon 10MBit ring */
+	IFT_HY          = 0xe /* Hyperchannel */
+	IFT_FDDI        = 0xf
+	IFT_LAPB        = 0x10
+	IFT_SDLC        = 0x11
+	IFT_T1          = 0x12
+	IFT_CEPT        = 0x13 /* E1 - european T1 */
+	IFT_ISDNBASIC   = 0x14
+	IFT_ISDNPRIMARY = 0x15
+	IFT_PTPSERIAL   = 0x16 /* Proprietary PTP serial */
+	IFT_PPP         = 0x17 /* RFC 1331 */
+	IFT_LOOP        = 0x18 /* loopback */
+	IFT_EON         = 0x19 /* ISO over IP */
+	IFT_XETHER      = 0x1a /* obsolete 3MB experimental ethernet */
+	IFT_NSIP        = 0x1b /* XNS over IP */
+	IFT_SLIP        = 0x1c /* IP over generic TTY */
+	IFT_ULTRA       = 0x1d /* Ultra Technologies */
+	IFT_DS3         = 0x1e /* Generic T3 */
+	IFT_SIP         = 0x1f /* SMDS */
+	IFT_FRELAY      = 0x20 /* Frame Relay DTE only */
+	IFT_RS232       = 0x21
+	IFT_PARA        = 0x22 /* parallel-port */
+	IFT_ARCNET      = 0x23
+	IFT_ARCNETPLUS  = 0x24
+	IFT_ATM         = 0x25 /* ATM cells */
+	IFT_MIOX25      = 0x26
+	IFT_SONET       = 0x27 /* SONET or SDH */
+	IFT_X25PLE      = 0x28
+	IFT_ISO88022LLC = 0x29
+	IFT_LOCALTALK   = 0x2a
+	IFT_SMDSDXI     = 0x2b
+	IFT_FRELAYDCE   = 0x2c /* Frame Relay DCE */
+	IFT_V35         = 0x2d
+	IFT_HSSI        = 0x2e
+	IFT_HIPPI       = 0x2f
+	IFT_MODEM       = 0x30 /* Generic Modem */
+	IFT_AAL5        = 0x31 /* AAL5 over ATM */
+	IFT_SONETPATH   = 0x32
+	IFT_SONETVT     = 0x33
+	IFT_SMDSICIP    = 0x34 /* SMDS InterCarrier Interface */
+	IFT_PROPVIRTUAL = 0x35 /* Proprietary Virtual/internal */
+	IFT_PROPMUX     = 0x36 /* Proprietary Multiplexing */
+	IFT_VIPA        = 0x37 /* Virtual Interface */
+	IFT_SN          = 0x38 /* Federation Switch */
+	IFT_SP          = 0x39 /* SP switch */
+	IFT_FCS         = 0x3a /* IP over Fiber Channel */
+	IFT_TUNNEL      = 0x3b
+	IFT_GIFTUNNEL   = 0x3c /* IPv4 over IPv6 tunnel */
+	IFT_HF          = 0x3d /* Support for PERCS HFI*/
+	IFT_CLUSTER     = 0x3e /* cluster pseudo network interface */
+	IFT_FB          = 0xc7 /* IP over Infiniband. Number by IANA */
+)
+
+type NetIfaceTotal struct {
+	Number     int32 /* number of network interfaces  */
+	IPackets   int64 /* number of packets received on interface */
+	IBytes     int64 /* number of bytes received on interface */
+	IErrors    int64 /* number of input errors on interface */
+	OPackets   int64 /* number of packets sent on interface */
+	OBytes     int64 /* number of bytes sent on interface */
+	OErrors    int64 /* number of output errors on interface */
+	Collisions int64 /* number of collisions on csma interface */
+	XmitDrops  int64 /* number of packets not transmitted */
+	Version    int64 /* version number (1, 2, etc.,) */
+}
+
+type NetIface struct {
+	Name        string /* name of the interface */
+	Description string /* interface description (from ODM, similar to lscfg output) */
+	Type        uint8  /* ethernet, tokenring, etc. interpretation can be done using /usr/include/net/if_types.h */
+	MTU         int64  /* network frame size */
+	IPackets    int64  /* number of packets received on interface */
+	IBytes      int64  /* number of bytes received on interface */
+	IErrors     int64  /* number of input errors on interface */
+	OPackets    int64  /* number of packets sent on interface */
+	OBytes      int64  /* number of bytes sent on interface */
+	OErrors     int64  /* number of output errors on interface */
+	Collisions  int64  /* number of collisions on csma interface */
+	Bitrate     int64  /* adapter rating in bit per second */
+	XmitDrops   int64  /* number of packets not transmitted */
+	Version     int64  /* version number (1, 2, etc.,) */
+	IfIqDrops   int64  /* Dropped on input, this interface */
+	IfArpDrops  int64  /* Dropped because no arp response */
+}
+
+type NetBuffer struct {
+	Name          string /* size in ascii, always power of 2 (ex: "32", "64", "128") */
+	InUse         int64  /* number of buffer currently allocated */
+	Calls         int64  /* number of buffer allocations since last reset */
+	Delayed       int64  /* number of delayed allocations */
+	Free          int64  /* number of free calls */
+	Failed        int64  /* number of failed allocations */
+	HighWatermark int64  /* high threshold for number of buffer allocated */
+	Freed         int64  /* number of buffers freed */
+	Version       int64  /* version number (1, 2, etc.,) */
+}
+
+// Network adapter types
+const (
+	NET_PHY  = 0 /* physical device */
+	NET_SEA  = 1 /* shared ethernet adapter */
+	NET_VIR  = 2 /* virtual device */
+	NET_HEA  = 3 /* host ethernet adapter */
+	NET_EC   = 4 /* etherchannel */
+	NET_VLAN = 5 /* vlan pseudo device */
+)
+
+type NetAdapter struct {
+	Version                    int64  /* version number (1,2, etc) */
+	Name                       string /* name of the adapter */
+	TxPackets                  int64  /* Transmit Packets on interface */
+	TxBytes                    int64  /* Transmit Bytes on interface */
+	TxInterrupts               int64  /* Transfer Interrupts */
+	TxErrors                   int64  /* Transmit Errors */
+	TxPacketsDropped           int64  /* Packets Dropped at the time of Data Transmission */
+	TxQueueSize                int64  /* Maximum Packets on Software Transmit Queue */
+	TxQueueLen                 int64  /* Transmission Queue Length */
+	TxQueueOverflow            int64  /* Transmission Queue Overflow */
+	TxBroadcastPackets         int64  /* Number of Broadcast Packets Transmitted */
+	TxMulticastPackets         int64  /* Number of Multicast packets Transmitted */
+	TxCarrierSense             int64  /* Lost Carrier Sense signal count */
+	TxDMAUnderrun              int64  /* Count of DMA Under-runs for Transmission */
+	TxLostCTSErrors            int64  /* The number of unsuccessful transmissions due to the loss of the Clear-to-Send signal error */
+	TxMaxCollisionErrors       int64  /* Maximum Collision Errors at Transmission */
+	TxLateCollisionErrors      int64  /* Late Collision Errors at Transmission */
+	TxDeferred                 int64  /* The number of packets deferred for Transmission. */
+	TxTimeoutErrors            int64  /* Time Out Errors for Transmission */
+	TxSingleCollisionCount     int64  /* Count of Single Collision error at Transmission */
+	TxMultipleCollisionCount   int64  /* Count of Multiple Collision error at Transmission */
+	RxPackets                  int64  /* Receive Packets on interface */
+	RxBytes                    int64  /* Receive Bytes on interface */
+	RxInterrupts               int64  /* Receive Interrupts */
+	RxErrors                   int64  /* Input errors on interface */
+	RxPacketsDropped           int64  /* The number of packets accepted by the device driver for transmission which were not (for any reason) given to the device. */
+	RxBadPackets               int64  /* Count of Bad Packets Received. */
+	RxMulticastPackets         int64  /* Number of MultiCast Packets Received */
+	RxBroadcastPackets         int64  /* Number of Broadcast Packets Received */
+	RxCRCErrors                int64  /* Count of Packets Received with CRC errors  */
+	RxDMAOverrun               int64  /* Count of DMA over-runs for Data Receival. */
+	RxAlignmentErrors          int64  /* Packets Received with Alignment Error  */
+	RxNoResourceErrors         int64  /* Packets Received with No Resource Errors */
+	RxCollisionErrors          int64  /* Packets Received with Collision errors */
+	RxPacketTooShortErrors     int64  /* Count of Short Packets Received. */
+	RxPacketTooLongErrors      int64  /* Count of Too Long Packets Received. */
+	RxPacketDiscardedByAdapter int64  /* Count of Received Packets discarded by Adapter. */
+	AdapterType                int32  /* 0 - Physical, 1 - SEA, 2 - Virtual, 3 -HEA */
+}
diff --git a/vendor/github.com/power-devops/perfstat/types_process.go b/vendor/github.com/power-devops/perfstat/types_process.go
new file mode 100644
index 000000000..325c70b07
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/types_process.go
@@ -0,0 +1,43 @@
+package perfstat
+
+type Process struct {
+	Version           int64   /* version number (1, 2, etc.,) */
+	PID               int64   /* Process ID */
+	ProcessName       string  /* Name of The Process */
+	Priority          int32   /* Process Priority */
+	NumThreads        int64   /* Thread Count */
+	UID               int64   /* Owner Info */
+	ClassID           int64   /* WLM Class Name */
+	Size              int64   /* Virtual Size of the Process in KB(Exclusive Usage, Leaving all Shared Library Text & Shared File Pages, Shared Memory, Memory Mapped) */
+	RealMemData       int64   /* Real Memory used for Data in KB */
+	RealMemText       int64   /* Real Memory used for Text in KB */
+	VirtMemData       int64   /* Virtual Memory used to Data in KB */
+	VirtMemText       int64   /* Virtual Memory used for Text in KB */
+	SharedLibDataSize int64   /* Data Size from Shared Library in KB */
+	HeapSize          int64   /* Heap Size in KB */
+	RealInUse         int64   /* The Real memory in use(in KB) by the process including all kind of segments (excluding system segments). This includes Text, Data, Shared Library Text, Shared Library Data, File Pages, Shared Memory & Memory Mapped */
+	VirtInUse         int64   /* The Virtual memory in use(in KB) by the process including all kind of segments (excluding system segments). This includes Text, Data, Shared Library Text, Shared Library Data, File Pages, Shared Memory & Memory Mapped */
+	Pinned            int64   /* Pinned Memory(in KB) for this process inclusive of all segments */
+	PgSpInUse         int64   /* Paging Space used(in KB) inclusive of all segments */
+	FilePages         int64   /* File Pages used(in KB) including shared pages */
+	RealInUseMap      int64   /* Real memory used(in KB) for Shared Memory and Memory Mapped regions */
+	VirtInUseMap      int64   /* Virtual Memory used(in KB) for Shared Memory and Memory Mapped regions */
+	PinnedInUseMap    int64   /* Pinned memory(in KB) for Shared Memory and Memory Mapped regions */
+	UCpuTime          float64 /* User Mode CPU time will be in percentage or milliseconds based on, whether it is filled by perfstat_process_util or perfstat_process respectively. */
+	SCpuTime          float64 /* System Mode CPU time will be in percentage or milliseconds based on, whether it is filled by perfstat_process_util or perfstat_process respectively. */
+	LastTimeBase      int64   /* Timebase Counter */
+	InBytes           int64   /* Bytes Read from Disk */
+	OutBytes          int64   /* Bytes Written to Disk */
+	InOps             int64   /* In Operations from Disk */
+	OutOps            int64   /* Out Operations from Disk */
+}
+
+type Thread struct {
+	TID          int64   /* thread identifier */
+	PID          int64   /* process identifier */
+	CpuID        int64   /* processor on which I'm bound */
+	UCpuTime     float64 /* User Mode CPU time will be in percentage or milliseconds based on, whether it is filled by perfstat_thread_util or perfstat_thread respectively. */
+	SCpuTime     float64 /* System Mode CPU time will be in percentage or milliseconds based on, whether it is filled by perfstat_thread_util or perfstat_thread respectively. */
+	LastTimeBase int64   /* Timebase Counter */
+	Version      int64
+}
diff --git a/vendor/github.com/power-devops/perfstat/uptime.go b/vendor/github.com/power-devops/perfstat/uptime.go
new file mode 100644
index 000000000..860878747
--- /dev/null
+++ b/vendor/github.com/power-devops/perfstat/uptime.go
@@ -0,0 +1,36 @@
+//go:build aix
+// +build aix
+
+package perfstat
+
+/*
+#include "c_helpers.h"
+*/
+import "C"
+
+import (
+	"fmt"
+	"time"
+)
+
+func timeSince(ts uint64) uint64 {
+	return uint64(time.Now().Unix()) - ts
+}
+
+// BootTime() returns the time of the last boot in UNIX seconds
+func BootTime() (uint64, error) {
+	sec := C.boottime()
+	if sec == -1 {
+		return 0, fmt.Errorf("Can't determine boot time")
+	}
+	return uint64(sec), nil
+}
+
+// UptimeSeconds() calculates uptime in seconds
+func UptimeSeconds() (uint64, error) {
+	boot, err := BootTime()
+	if err != nil {
+		return 0, err
+	}
+	return timeSince(boot), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/LICENSE b/vendor/github.com/shirou/gopsutil/v4/LICENSE
new file mode 100644
index 000000000..6f06adcbf
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/LICENSE
@@ -0,0 +1,61 @@
+gopsutil is distributed under BSD license reproduced below.
+
+Copyright (c) 2014, WAKAYAMA Shirou
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+ * Neither the name of the gopsutil authors nor the names of its contributors
+   may be used to endorse or promote products derived from this software without
+   specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+-------
+internal/common/binary.go in the gopsutil is copied and modified from golang/encoding/binary.go.
+
+
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/vendor/github.com/shirou/gopsutil/v4/common/env.go b/vendor/github.com/shirou/gopsutil/v4/common/env.go
new file mode 100644
index 000000000..47e471c40
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/common/env.go
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+type EnvKeyType string
+
+// EnvKey is a context key that can be used to set programmatically the environment
+// gopsutil relies on to perform calls against the OS.
+// Example of use:
+//
+//	ctx := context.WithValue(context.Background(), common.EnvKey, EnvMap{common.HostProcEnvKey: "/myproc"})
+//	avg, err := load.AvgWithContext(ctx)
+var EnvKey = EnvKeyType("env")
+
+const (
+	HostProcEnvKey    EnvKeyType = "HOST_PROC"
+	HostSysEnvKey     EnvKeyType = "HOST_SYS"
+	HostEtcEnvKey     EnvKeyType = "HOST_ETC"
+	HostVarEnvKey     EnvKeyType = "HOST_VAR"
+	HostRunEnvKey     EnvKeyType = "HOST_RUN"
+	HostDevEnvKey     EnvKeyType = "HOST_DEV"
+	HostRootEnvKey    EnvKeyType = "HOST_ROOT"
+	HostProcMountinfo EnvKeyType = "HOST_PROC_MOUNTINFO"
+)
+
+type EnvMap map[EnvKeyType]string
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu.go
new file mode 100644
index 000000000..9bc3dfb51
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu.go
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"math"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// TimesStat contains the amounts of time the CPU has spent performing different
+// kinds of work. Time units are in seconds. It is based on linux /proc/stat file.
+type TimesStat struct {
+	CPU       string  `json:"cpu"`
+	User      float64 `json:"user"`
+	System    float64 `json:"system"`
+	Idle      float64 `json:"idle"`
+	Nice      float64 `json:"nice"`
+	Iowait    float64 `json:"iowait"`
+	Irq       float64 `json:"irq"`
+	Softirq   float64 `json:"softirq"`
+	Steal     float64 `json:"steal"`
+	Guest     float64 `json:"guest"`
+	GuestNice float64 `json:"guestNice"`
+}
+
+type InfoStat struct {
+	CPU        int32    `json:"cpu"`
+	VendorID   string   `json:"vendorId"`
+	Family     string   `json:"family"`
+	Model      string   `json:"model"`
+	Stepping   int32    `json:"stepping"`
+	PhysicalID string   `json:"physicalId"`
+	CoreID     string   `json:"coreId"`
+	Cores      int32    `json:"cores"`
+	ModelName  string   `json:"modelName"`
+	Mhz        float64  `json:"mhz"`
+	CacheSize  int32    `json:"cacheSize"`
+	Flags      []string `json:"flags"`
+	Microcode  string   `json:"microcode"`
+}
+
+type lastPercent struct {
+	sync.Mutex
+	lastCPUTimes    []TimesStat
+	lastPerCPUTimes []TimesStat
+}
+
+var (
+	lastCPUPercent lastPercent
+	invoke         common.Invoker = common.Invoke{}
+)
+
+func init() {
+	lastCPUPercent.Lock()
+	lastCPUPercent.lastCPUTimes, _ = Times(false)
+	lastCPUPercent.lastPerCPUTimes, _ = Times(true)
+	lastCPUPercent.Unlock()
+}
+
+// Counts returns the number of physical or logical cores in the system
+func Counts(logical bool) (int, error) {
+	return CountsWithContext(context.Background(), logical)
+}
+
+func (c TimesStat) String() string {
+	v := []string{
+		`"cpu":"` + c.CPU + `"`,
+		`"user":` + strconv.FormatFloat(c.User, 'f', 1, 64),
+		`"system":` + strconv.FormatFloat(c.System, 'f', 1, 64),
+		`"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64),
+		`"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64),
+		`"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64),
+		`"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64),
+		`"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),
+		`"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),
+		`"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),
+		`"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
+	}
+
+	return `{` + strings.Join(v, ",") + `}`
+}
+
+// Deprecated: Total returns the total number of seconds in a CPUTimesStat
+// Please do not use this internal function.
+func (c TimesStat) Total() float64 {
+	total := c.User + c.System + c.Idle + c.Nice + c.Iowait + c.Irq +
+		c.Softirq + c.Steal + c.Guest + c.GuestNice
+
+	return total
+}
+
+func (c InfoStat) String() string {
+	s, _ := json.Marshal(c)
+	return string(s)
+}
+
+func getAllBusy(t TimesStat) (float64, float64) {
+	tot := t.Total()
+	if runtime.GOOS == "linux" {
+		tot -= t.Guest     // Linux 2.6.24+
+		tot -= t.GuestNice // Linux 3.2.0+
+	}
+
+	busy := tot - t.Idle - t.Iowait
+
+	return tot, busy
+}
+
+func calculateBusy(t1, t2 TimesStat) float64 {
+	t1All, t1Busy := getAllBusy(t1)
+	t2All, t2Busy := getAllBusy(t2)
+
+	if t2Busy <= t1Busy {
+		return 0
+	}
+	if t2All <= t1All {
+		return 100
+	}
+	return math.Min(100, math.Max(0, (t2Busy-t1Busy)/(t2All-t1All)*100))
+}
+
+func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
+	// Make sure the CPU measurements have the same length.
+	if len(t1) != len(t2) {
+		return nil, fmt.Errorf(
+			"received two CPU counts: %d != %d",
+			len(t1), len(t2),
+		)
+	}
+
+	ret := make([]float64, len(t1))
+	for i, t := range t2 {
+		ret[i] = calculateBusy(t1[i], t)
+	}
+	return ret, nil
+}
+
+// Percent calculates the percentage of cpu used either per CPU or combined.
+// If an interval of 0 is given it will compare the current cpu times against the last call.
+// Returns one value per cpu, or a single value if percpu is set to false.
+func Percent(interval time.Duration, percpu bool) ([]float64, error) {
+	return PercentWithContext(context.Background(), interval, percpu)
+}
+
+func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {
+	if interval <= 0 {
+		return percentUsedFromLastCallWithContext(ctx, percpu)
+	}
+
+	// Get CPU usage at the start of the interval.
+	cpuTimes1, err := TimesWithContext(ctx, percpu)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := common.Sleep(ctx, interval); err != nil {
+		return nil, err
+	}
+
+	// And at the end of the interval.
+	cpuTimes2, err := TimesWithContext(ctx, percpu)
+	if err != nil {
+		return nil, err
+	}
+
+	return calculateAllBusy(cpuTimes1, cpuTimes2)
+}
+
+func percentUsedFromLastCall(percpu bool) ([]float64, error) {
+	return percentUsedFromLastCallWithContext(context.Background(), percpu)
+}
+
+func percentUsedFromLastCallWithContext(ctx context.Context, percpu bool) ([]float64, error) {
+	cpuTimes, err := TimesWithContext(ctx, percpu)
+	if err != nil {
+		return nil, err
+	}
+	lastCPUPercent.Lock()
+	defer lastCPUPercent.Unlock()
+	var lastTimes []TimesStat
+	if percpu {
+		lastTimes = lastCPUPercent.lastPerCPUTimes
+		lastCPUPercent.lastPerCPUTimes = cpuTimes
+	} else {
+		lastTimes = lastCPUPercent.lastCPUTimes
+		lastCPUPercent.lastCPUTimes = cpuTimes
+	}
+
+	if lastTimes == nil {
+		return nil, errors.New("error getting times for cpu percent. lastTimes was nil")
+	}
+	return calculateAllBusy(lastTimes, cpuTimes)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix.go
new file mode 100644
index 000000000..bc766bd4f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix.go
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix
+
+package cpu
+
+import (
+	"context"
+)
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_cgo.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_cgo.go
new file mode 100644
index 000000000..8bd84de6c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_cgo.go
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && cgo
+
+package cpu
+
+import (
+	"context"
+
+	"github.com/power-devops/perfstat"
+)
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+	var ret []TimesStat
+	if percpu {
+		cpus, err := perfstat.CpuStat()
+		if err != nil {
+			return nil, err
+		}
+		for _, c := range cpus {
+			ct := &TimesStat{
+				CPU:    c.Name,
+				Idle:   float64(c.Idle),
+				User:   float64(c.User),
+				System: float64(c.Sys),
+				Iowait: float64(c.Wait),
+			}
+			ret = append(ret, *ct)
+		}
+	} else {
+		c, err := perfstat.CpuTotalStat()
+		if err != nil {
+			return nil, err
+		}
+		ct := &TimesStat{
+			CPU:    "cpu-total",
+			Idle:   float64(c.Idle),
+			User:   float64(c.User),
+			System: float64(c.Sys),
+			Iowait: float64(c.Wait),
+		}
+		ret = append(ret, *ct)
+	}
+	return ret, nil
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+	c, err := perfstat.CpuTotalStat()
+	if err != nil {
+		return nil, err
+	}
+	p, err := perfstat.LparInfo()
+	if err != nil {
+		return nil, err
+	}
+	info := InfoStat{
+		CPU:       0,
+		ModelName: c.Description,
+		Mhz:       float64(c.ProcessorHz / 1000000),
+		Cores:     int32(p.OnlineVCpus),
+	}
+	result := []InfoStat{info}
+	return result, nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+	if logical {
+		c, err := perfstat.CpuTotalStat()
+		if err != nil {
+			return 0, err
+		}
+		return c.NCpusCfg, nil
+	}
+	// For physical count, use the number of online virtual CPUs (before SMT multiplications).
+	p, err := perfstat.LparInfo()
+	if err != nil {
+		return 0, err
+	}
+	return int(p.OnlineVCpus), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_nocgo.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_nocgo.go
new file mode 100644
index 000000000..981e32e51
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_aix_nocgo.go
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && !cgo
+
+package cpu
+
+import (
+	"context"
+	"strconv"
+	"strings"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+	var ret []TimesStat
+	if percpu {
+		perOut, err := invoke.CommandWithContext(ctx, "sar", "-u", "-P", "ALL", "10", "1")
+		if err != nil {
+			return nil, err
+		}
+		lines := strings.Split(string(perOut), "\n")
+		if len(lines) < 6 {
+			return []TimesStat{}, common.ErrNotImplementedError
+		}
+
+		hp := strings.Fields(lines[5]) // headers
+		for l := 6; l < len(lines)-1; l++ {
+			ct := &TimesStat{}
+			v := strings.Fields(lines[l]) // values
+			for i, header := range hp {
+				// We're done in any of these use cases
+				if i >= len(v) || v[0] == "-" {
+					break
+				}
+
+				// Position variable for v
+				pos := i
+				// There is a missing field at the beginning of all but the first line
+				// so adjust the position
+				if l > 6 {
+					pos = i - 1
+				}
+				// We don't want invalid positions
+				if pos < 0 {
+					continue
+				}
+
+				if t, err := strconv.ParseFloat(v[pos], 64); err == nil {
+					switch header {
+					case `cpu`:
+						ct.CPU = strconv.FormatFloat(t, 'f', -1, 64)
+					case `%usr`:
+						ct.User = t
+					case `%sys`:
+						ct.System = t
+					case `%wio`:
+						ct.Iowait = t
+					case `%idle`:
+						ct.Idle = t
+					}
+				}
+			}
+			// Valid CPU data, so append it
+			ret = append(ret, *ct)
+		}
+	} else {
+		out, err := invoke.CommandWithContext(ctx, "sar", "-u", "10", "1")
+		if err != nil {
+			return nil, err
+		}
+		lines := strings.Split(string(out), "\n")
+		if len(lines) < 5 {
+			return []TimesStat{}, common.ErrNotImplementedError
+		}
+
+		ct := &TimesStat{CPU: "cpu-total"}
+		h := strings.Fields(lines[len(lines)-3]) // headers
+		v := strings.Fields(lines[len(lines)-2]) // values
+		for i, header := range h {
+			if t, err := strconv.ParseFloat(v[i], 64); err == nil {
+				switch header {
+				case `%usr`:
+					ct.User = t
+				case `%sys`:
+					ct.System = t
+				case `%wio`:
+					ct.Iowait = t
+				case `%idle`:
+					ct.Idle = t
+				}
+			}
+		}
+
+		ret = append(ret, *ct)
+	}
+
+	return ret, nil
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+	out, err := invoke.CommandWithContext(ctx, "prtconf")
+	if err != nil {
+		return nil, err
+	}
+
+	ret := InfoStat{}
+	for _, line := range strings.Split(string(out), "\n") {
+		switch {
+		case strings.HasPrefix(line, "Number Of Processors:"):
+			p := strings.Fields(line)
+			if len(p) > 3 {
+				if t, err := strconv.ParseUint(p[3], 10, 64); err == nil {
+					ret.Cores = int32(t)
+				}
+			}
+		case strings.HasPrefix(line, "Processor Clock Speed:"):
+			p := strings.Fields(line)
+			if len(p) > 4 {
+				if t, err := strconv.ParseFloat(p[3], 64); err == nil {
+					switch strings.ToUpper(p[4]) {
+					case "MHZ":
+						ret.Mhz = t
+					case "GHZ":
+						ret.Mhz = t * 1000.0
+					case "KHZ":
+						ret.Mhz = t / 1000.0
+					default:
+						ret.Mhz = t
+					}
+				}
+			}
+		case strings.HasPrefix(line, "System Model:"):
+			p := strings.Split(string(line), ":")
+			if p != nil {
+				ret.VendorID = strings.TrimSpace(p[1])
+			}
+		case strings.HasPrefix(line, "Processor Type:"):
+			p := strings.Split(string(line), ":")
+			if p != nil {
+				c := strings.Split(string(p[1]), "_")
+				if c != nil {
+					ret.Family = strings.TrimSpace(c[0])
+					ret.Model = strings.TrimSpace(c[1])
+				}
+			}
+		}
+	}
+	return []InfoStat{ret}, nil
+}
+
+func CountsWithContext(ctx context.Context, _ bool) (int, error) {
+	info, err := InfoWithContext(ctx)
+	if err == nil {
+		return int(info[0].Cores), nil
+	}
+	return 0, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go
new file mode 100644
index 000000000..d3b6dbc53
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin.go
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package cpu
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"unsafe"
+
+	"github.com/tklauser/go-sysconf"
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// sys/resource.h
+const (
+	CPUser    = 0
+	cpNice    = 1
+	cpSys     = 2
+	cpIntr    = 3
+	cpIdle    = 4
+	cpUStates = 5
+)
+
+// mach/machine.h
+const (
+	cpuStateUser   = 0
+	cpuStateSystem = 1
+	cpuStateIdle   = 2
+	cpuStateNice   = 3
+	cpuStateMax    = 4
+)
+
+// mach/processor_info.h
+const (
+	processorCpuLoadInfo = 2 //nolint:revive //FIXME
+)
+
+type hostCpuLoadInfoData struct { //nolint:revive //FIXME
+	cpuTicks [cpuStateMax]uint32
+}
+
+// default value. from time.h
+var ClocksPerSec = float64(128)
+
+func init() {
+	clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+	// ignore errors
+	if err == nil {
+		ClocksPerSec = float64(clkTck)
+	}
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {
+	sys, err := common.NewSystemLib()
+	if err != nil {
+		return nil, err
+	}
+	defer sys.Close()
+
+	if percpu {
+		return perCPUTimes(sys)
+	}
+
+	return allCPUTimes(sys)
+}
+
+// Returns only one CPUInfoStat on FreeBSD
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(_ context.Context) ([]InfoStat, error) {
+	var ret []InfoStat
+
+	c := InfoStat{}
+	c.ModelName, _ = unix.Sysctl("machdep.cpu.brand_string")
+	family, _ := unix.SysctlUint32("machdep.cpu.family")
+	c.Family = strconv.FormatUint(uint64(family), 10)
+	model, _ := unix.SysctlUint32("machdep.cpu.model")
+	c.Model = strconv.FormatUint(uint64(model), 10)
+	stepping, _ := unix.SysctlUint32("machdep.cpu.stepping")
+	c.Stepping = int32(stepping)
+	features, err := unix.Sysctl("machdep.cpu.features")
+	if err == nil {
+		for _, v := range strings.Fields(features) {
+			c.Flags = append(c.Flags, strings.ToLower(v))
+		}
+	}
+	leaf7Features, err := unix.Sysctl("machdep.cpu.leaf7_features")
+	if err == nil {
+		for _, v := range strings.Fields(leaf7Features) {
+			c.Flags = append(c.Flags, strings.ToLower(v))
+		}
+	}
+	extfeatures, err := unix.Sysctl("machdep.cpu.extfeatures")
+	if err == nil {
+		for _, v := range strings.Fields(extfeatures) {
+			c.Flags = append(c.Flags, strings.ToLower(v))
+		}
+	}
+	cores, _ := unix.SysctlUint32("machdep.cpu.core_count")
+	c.Cores = int32(cores)
+	cacheSize, _ := unix.SysctlUint32("machdep.cpu.cache.size")
+	c.CacheSize = int32(cacheSize)
+	c.VendorID, _ = unix.Sysctl("machdep.cpu.vendor")
+
+	v, err := getFrequency()
+	if err == nil {
+		c.Mhz = v
+	}
+
+	return append(ret, c), nil
+}
+
+func CountsWithContext(_ context.Context, logical bool) (int, error) {
+	var cpuArgument string
+	if logical {
+		cpuArgument = "hw.logicalcpu"
+	} else {
+		cpuArgument = "hw.physicalcpu"
+	}
+
+	count, err := unix.SysctlUint32(cpuArgument)
+	if err != nil {
+		return 0, err
+	}
+
+	return int(count), nil
+}
+
+func perCPUTimes(sys *common.SystemLib) ([]TimesStat, error) {
+	var count, ncpu uint32
+	var cpuload *hostCpuLoadInfoData
+
+	status := sys.HostProcessorInfo(sys.MachHostSelf(), processorCpuLoadInfo,
+		&ncpu, uintptr(unsafe.Pointer(&cpuload)), &count)
+
+	if status != common.KERN_SUCCESS {
+		return nil, fmt.Errorf("host_processor_info error=%d", status)
+	}
+
+	if cpuload == nil {
+		return nil, errors.New("host_processor_info returned nil cpuload")
+	}
+
+	defer sys.VMDeallocate(sys.MachTaskSelf(), uintptr(unsafe.Pointer(cpuload)), uintptr(ncpu))
+
+	ret := []TimesStat{}
+	loads := unsafe.Slice(cpuload, ncpu)
+
+	for i := 0; i < int(ncpu); i++ {
+		c := TimesStat{
+			CPU:    fmt.Sprintf("cpu%d", i),
+			User:   float64(loads[i].cpuTicks[cpuStateUser]) / ClocksPerSec,
+			System: float64(loads[i].cpuTicks[cpuStateSystem]) / ClocksPerSec,
+			Nice:   float64(loads[i].cpuTicks[cpuStateNice]) / ClocksPerSec,
+			Idle:   float64(loads[i].cpuTicks[cpuStateIdle]) / ClocksPerSec,
+		}
+		ret = append(ret, c)
+	}
+
+	return ret, nil
+}
+
+func allCPUTimes(sys *common.SystemLib) ([]TimesStat, error) {
+	var cpuload hostCpuLoadInfoData
+	count := uint32(cpuStateMax)
+
+	status := sys.HostStatistics(sys.MachHostSelf(), common.HOST_CPU_LOAD_INFO,
+		uintptr(unsafe.Pointer(&cpuload)), &count)
+
+	if status != common.KERN_SUCCESS {
+		return nil, fmt.Errorf("host_statistics error=%d", status)
+	}
+
+	c := TimesStat{
+		CPU:    "cpu-total",
+		User:   float64(cpuload.cpuTicks[cpuStateUser]) / ClocksPerSec,
+		System: float64(cpuload.cpuTicks[cpuStateSystem]) / ClocksPerSec,
+		Nice:   float64(cpuload.cpuTicks[cpuStateNice]) / ClocksPerSec,
+		Idle:   float64(cpuload.cpuTicks[cpuStateIdle]) / ClocksPerSec,
+	}
+
+	return []TimesStat{c}, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go
new file mode 100644
index 000000000..c9628a6d7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_arm64.go
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin && arm64
+
+package cpu
+
+import (
+	"encoding/binary"
+	"fmt"
+	"sync"
+	"unsafe"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// Keep IOKit and CoreFoundation libraries open for the process lifetime.
+// See: https://github.com/shirou/gopsutil/issues/1832
+var (
+	cpuLibOnce sync.Once
+	cpuIOKit   *common.IOKitLib
+	cpuCF      *common.CoreFoundationLib
+	cpuLibErr  error
+)
+
+func initCPULibraries() {
+	cpuIOKit, cpuLibErr = common.NewIOKitLib()
+	if cpuLibErr != nil {
+		return
+	}
+	cpuCF, cpuLibErr = common.NewCoreFoundationLib()
+}
+
+// https://github.com/shoenig/go-m1cpu/blob/v0.1.6/cpu.go
+func getFrequency() (float64, error) {
+	cpuLibOnce.Do(initCPULibraries)
+	if cpuLibErr != nil {
+		return 0, cpuLibErr
+	}
+
+	iokit := cpuIOKit
+	corefoundation := cpuCF
+
+	matching := iokit.IOServiceMatching("AppleARMIODevice")
+
+	var iterator uint32
+	if status := iokit.IOServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(matching), &iterator); status != common.KERN_SUCCESS {
+		return 0.0, fmt.Errorf("IOServiceGetMatchingServices error=%d", status)
+	}
+	defer iokit.IOObjectRelease(iterator)
+
+	pCorekey := corefoundation.CFStringCreateWithCString(common.KCFAllocatorDefault, "voltage-states5-sram", common.KCFStringEncodingUTF8)
+	defer corefoundation.CFRelease(uintptr(pCorekey))
+
+	var pCoreHz uint32
+	for {
+		service := iokit.IOIteratorNext(iterator)
+		if service <= 0 {
+			break
+		}
+
+		buf := common.NewCStr(512)
+		iokit.IORegistryEntryGetName(service, buf)
+
+		if buf.GoString() == "pmgr" {
+			pCoreRef := iokit.IORegistryEntryCreateCFProperty(service, uintptr(pCorekey), common.KCFAllocatorDefault, common.KNilOptions)
+			length := corefoundation.CFDataGetLength(uintptr(pCoreRef))
+			data := corefoundation.CFDataGetBytePtr(uintptr(pCoreRef))
+
+			// composite uint32 from the byte array
+			buf := unsafe.Slice((*byte)(data), length)
+
+			// combine the bytes into a uint32 value
+			b := buf[length-8 : length-4]
+			pCoreHz = binary.LittleEndian.Uint32(b)
+			corefoundation.CFRelease(uintptr(pCoreRef))
+			iokit.IOObjectRelease(service)
+			break
+		}
+
+		iokit.IOObjectRelease(service)
+	}
+
+	return float64(pCoreHz / 1_000_000), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_fallback.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_fallback.go
new file mode 100644
index 000000000..b9e52aba1
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_darwin_fallback.go
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin && !arm64
+
+package cpu
+
+import "golang.org/x/sys/unix"
+
+func getFrequency() (float64, error) {
+	// Use the rated frequency of the CPU. This is a static value and does not
+	// account for low power or Turbo Boost modes.
+	cpuFrequency, err := unix.SysctlUint64("hw.cpufrequency")
+	return float64(cpuFrequency) / 1000000.0, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly.go
new file mode 100644
index 000000000..48f2804d9
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly.go
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"unsafe"
+
+	"github.com/tklauser/go-sysconf"
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var (
+	ClocksPerSec   = float64(128)
+	cpuMatch       = regexp.MustCompile(`^CPU:`)
+	originMatch    = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`)
+	featuresMatch  = regexp.MustCompile(`Features=.+<(.+)>`)
+	featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`)
+	cpuEnd         = regexp.MustCompile(`^Trying to mount root`)
+	cpuTimesSize   int
+	emptyTimes     cpuTimes
+)
+
+func init() {
+	clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+	// ignore errors
+	if err == nil {
+		ClocksPerSec = float64(clkTck)
+	}
+}
+
+func timeStat(name string, t *cpuTimes) *TimesStat {
+	return &TimesStat{
+		User:   float64(t.User) / ClocksPerSec,
+		Nice:   float64(t.Nice) / ClocksPerSec,
+		System: float64(t.Sys) / ClocksPerSec,
+		Idle:   float64(t.Idle) / ClocksPerSec,
+		Irq:    float64(t.Intr) / ClocksPerSec,
+		CPU:    name,
+	}
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {
+	if percpu {
+		buf, err := unix.SysctlRaw("kern.cp_times")
+		if err != nil {
+			return nil, err
+		}
+
+		// We can't do this in init due to the conflict with cpu.init()
+		if cpuTimesSize == 0 {
+			cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())
+		}
+
+		ncpus := len(buf) / cpuTimesSize
+		ret := make([]TimesStat, 0, ncpus)
+		for i := 0; i < ncpus; i++ {
+			times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))
+			if *times == emptyTimes {
+				// CPU not present
+				continue
+			}
+			ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times))
+		}
+		return ret, nil
+	}
+
+	buf, err := unix.SysctlRaw("kern.cp_time")
+	if err != nil {
+		return nil, err
+	}
+
+	times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+	return []TimesStat{*timeStat("cpu-total", times)}, nil
+}
+
+// Returns only one InfoStat on DragonflyBSD.  The information regarding core
+// count, however is accurate and it is assumed that all InfoStat attributes
+// are the same across CPUs.
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(_ context.Context) ([]InfoStat, error) {
+	const dmesgBoot = "/var/run/dmesg.boot"
+
+	c, err := parseDmesgBoot(dmesgBoot)
+	if err != nil {
+		return nil, err
+	}
+
+	var u32 uint32
+	if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil {
+		return nil, err
+	}
+	c.Mhz = float64(u32)
+
+	var num int
+	var buf string
+	if buf, err = unix.Sysctl("hw.cpu_topology.tree"); err != nil {
+		return nil, err
+	}
+	num = strings.Count(buf, "CHIP")
+	c.Cores = int32(strings.Count(string(buf), "CORE") / num)
+
+	if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
+		return nil, err
+	}
+
+	ret := make([]InfoStat, num)
+	for i := 0; i < num; i++ {
+		ret[i] = c
+	}
+
+	return ret, nil
+}
+
+func parseDmesgBoot(fileName string) (InfoStat, error) {
+	c := InfoStat{}
+	lines, err := common.ReadLines(fileName)
+	if err != nil {
+		return c, fmt.Errorf("could not read %s: %w", fileName, err)
+	}
+
+	for _, line := range lines {
+		if matches := cpuEnd.FindStringSubmatch(line); matches != nil {
+			break
+		} else if matches := originMatch.FindStringSubmatch(line); matches != nil {
+			c.VendorID = matches[1]
+			t, err := strconv.ParseInt(matches[2], 10, 32)
+			if err != nil {
+				return c, fmt.Errorf("unable to parse DragonflyBSD CPU stepping information from %q: %w", line, err)
+			}
+			c.Stepping = int32(t)
+		} else if matches := featuresMatch.FindStringSubmatch(line); matches != nil {
+			for _, v := range strings.Split(matches[1], ",") {
+				c.Flags = append(c.Flags, strings.ToLower(v))
+			}
+		} else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil {
+			for _, v := range strings.Split(matches[1], ",") {
+				c.Flags = append(c.Flags, strings.ToLower(v))
+			}
+		}
+	}
+
+	return c, nil
+}
+
+func CountsWithContext(_ context.Context, _ bool) (int, error) {
+	return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly_amd64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly_amd64.go
new file mode 100644
index 000000000..25ececa68
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_dragonfly_amd64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Intr uint64
+	Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_fallback.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_fallback.go
new file mode 100644
index 000000000..245c1ec98
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_fallback.go
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build !darwin && !linux && !freebsd && !openbsd && !netbsd && !solaris && !windows && !dragonfly && !plan9 && !aix
+
+package cpu
+
+import (
+	"context"
+	"runtime"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+	return []TimesStat{}, common.ErrNotImplementedError
+}
+
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+	return []InfoStat{}, common.ErrNotImplementedError
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+	return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd.go
new file mode 100644
index 000000000..3e0aeb26a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd.go
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"unsafe"
+
+	"github.com/tklauser/go-sysconf"
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var (
+	ClocksPerSec   = float64(128)
+	cpuMatch       = regexp.MustCompile(`^CPU:`)
+	originMatch    = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Family\s*=\s*(.+)\s+Model\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`)
+	featuresMatch  = regexp.MustCompile(`Features=.+<(.+)>`)
+	featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`)
+	cpuEnd         = regexp.MustCompile(`^Trying to mount root`)
+	cpuCores       = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`)
+	cpuTimesSize   int
+	emptyTimes     cpuTimes
+)
+
+func init() {
+	clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+	// ignore errors
+	if err == nil {
+		ClocksPerSec = float64(clkTck)
+	}
+}
+
+func timeStat(name string, t *cpuTimes) *TimesStat {
+	return &TimesStat{
+		User:   float64(t.User) / ClocksPerSec,
+		Nice:   float64(t.Nice) / ClocksPerSec,
+		System: float64(t.Sys) / ClocksPerSec,
+		Idle:   float64(t.Idle) / ClocksPerSec,
+		Irq:    float64(t.Intr) / ClocksPerSec,
+		CPU:    name,
+	}
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {
+	if percpu {
+		buf, err := unix.SysctlRaw("kern.cp_times")
+		if err != nil {
+			return nil, err
+		}
+
+		// We can't do this in init due to the conflict with cpu.init()
+		if cpuTimesSize == 0 {
+			cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())
+		}
+
+		ncpus := len(buf) / cpuTimesSize
+		ret := make([]TimesStat, 0, ncpus)
+		for i := 0; i < ncpus; i++ {
+			times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))
+			if *times == emptyTimes {
+				// CPU not present
+				continue
+			}
+			ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times))
+		}
+		return ret, nil
+	}
+
+	buf, err := unix.SysctlRaw("kern.cp_time")
+	if err != nil {
+		return nil, err
+	}
+
+	times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+	return []TimesStat{*timeStat("cpu-total", times)}, nil
+}
+
+// Returns only one InfoStat on FreeBSD.  The information regarding core
+// count, however is accurate and it is assumed that all InfoStat attributes
+// are the same across CPUs.
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(_ context.Context) ([]InfoStat, error) {
+	const dmesgBoot = "/var/run/dmesg.boot"
+
+	c, num, err := parseDmesgBoot(dmesgBoot)
+	if err != nil {
+		return nil, err
+	}
+
+	var u32 uint32
+	if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil {
+		return nil, err
+	}
+	c.Mhz = float64(u32)
+
+	if u32, err = unix.SysctlUint32("hw.ncpu"); err != nil {
+		return nil, err
+	}
+	c.Cores = int32(u32)
+
+	if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
+		return nil, err
+	}
+
+	ret := make([]InfoStat, num)
+	for i := 0; i < num; i++ {
+		ret[i] = c
+	}
+
+	return ret, nil
+}
+
+func parseDmesgBoot(fileName string) (InfoStat, int, error) {
+	c := InfoStat{}
+	lines, err := common.ReadLines(fileName)
+	if err != nil {
+		return c, 0, fmt.Errorf("could not read %s: %w", fileName, err)
+	}
+
+	cpuNum := 1 // default cpu num is 1
+	for _, line := range lines {
+		if matches := cpuEnd.FindStringSubmatch(line); matches != nil {
+			break
+		} else if matches := originMatch.FindStringSubmatch(line); matches != nil {
+			c.VendorID = matches[1]
+			c.Family = matches[3]
+			c.Model = matches[4]
+			t, err := strconv.ParseInt(matches[5], 10, 32)
+			if err != nil {
+				return c, 0, fmt.Errorf("unable to parse FreeBSD CPU stepping information from %q: %w", line, err)
+			}
+			c.Stepping = int32(t)
+		} else if matches := featuresMatch.FindStringSubmatch(line); matches != nil {
+			for _, v := range strings.Split(matches[1], ",") {
+				c.Flags = append(c.Flags, strings.ToLower(v))
+			}
+		} else if matches := featuresMatch2.FindStringSubmatch(line); matches != nil {
+			for _, v := range strings.Split(matches[1], ",") {
+				c.Flags = append(c.Flags, strings.ToLower(v))
+			}
+		} else if matches := cpuCores.FindStringSubmatch(line); matches != nil {
+			t, err := strconv.ParseInt(matches[1], 10, 32)
+			if err != nil {
+				return c, 0, fmt.Errorf("unable to parse FreeBSD CPU Nums from %q: %w", line, err)
+			}
+			cpuNum = int(t)
+			t2, err := strconv.ParseInt(matches[2], 10, 32)
+			if err != nil {
+				return c, 0, fmt.Errorf("unable to parse FreeBSD CPU cores from %q: %w", line, err)
+			}
+			c.Cores = int32(t2)
+		}
+	}
+
+	return c, cpuNum, nil
+}
+
+func CountsWithContext(_ context.Context, _ bool) (int, error) {
+	return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_386.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_386.go
new file mode 100644
index 000000000..e4799bcf5
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_386.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint32
+	Nice uint32
+	Sys  uint32
+	Intr uint32
+	Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_amd64.go
new file mode 100644
index 000000000..25ececa68
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_amd64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Intr uint64
+	Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm.go
new file mode 100644
index 000000000..e4799bcf5
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint32
+	Nice uint32
+	Sys  uint32
+	Intr uint32
+	Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm64.go
new file mode 100644
index 000000000..25ececa68
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_freebsd_arm64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Intr uint64
+	Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go
new file mode 100644
index 000000000..4072f19cf
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_linux.go
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package cpu
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"path/filepath"
+	"strconv"
+	"strings"
+
+	"github.com/tklauser/go-sysconf"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var ClocksPerSec = float64(100)
+
+var armModelToModelName = map[uint64]string{
+	0x810: "ARM810",
+	0x920: "ARM920",
+	0x922: "ARM922",
+	0x926: "ARM926",
+	0x940: "ARM940",
+	0x946: "ARM946",
+	0x966: "ARM966",
+	0xa20: "ARM1020",
+	0xa22: "ARM1022",
+	0xa26: "ARM1026",
+	0xb02: "ARM11 MPCore",
+	0xb36: "ARM1136",
+	0xb56: "ARM1156",
+	0xb76: "ARM1176",
+	0xc05: "Cortex-A5",
+	0xc07: "Cortex-A7",
+	0xc08: "Cortex-A8",
+	0xc09: "Cortex-A9",
+	0xc0d: "Cortex-A17",
+	0xc0f: "Cortex-A15",
+	0xc0e: "Cortex-A17",
+	0xc14: "Cortex-R4",
+	0xc15: "Cortex-R5",
+	0xc17: "Cortex-R7",
+	0xc18: "Cortex-R8",
+	0xc20: "Cortex-M0",
+	0xc21: "Cortex-M1",
+	0xc23: "Cortex-M3",
+	0xc24: "Cortex-M4",
+	0xc27: "Cortex-M7",
+	0xc60: "Cortex-M0+",
+	0xd01: "Cortex-A32",
+	0xd02: "Cortex-A34",
+	0xd03: "Cortex-A53",
+	0xd04: "Cortex-A35",
+	0xd05: "Cortex-A55",
+	0xd06: "Cortex-A65",
+	0xd07: "Cortex-A57",
+	0xd08: "Cortex-A72",
+	0xd09: "Cortex-A73",
+	0xd0a: "Cortex-A75",
+	0xd0b: "Cortex-A76",
+	0xd0c: "Neoverse-N1",
+	0xd0d: "Cortex-A77",
+	0xd0e: "Cortex-A76AE",
+	0xd13: "Cortex-R52",
+	0xd20: "Cortex-M23",
+	0xd21: "Cortex-M33",
+	0xd40: "Neoverse-V1",
+	0xd41: "Cortex-A78",
+	0xd42: "Cortex-A78AE",
+	0xd43: "Cortex-A65AE",
+	0xd44: "Cortex-X1",
+	0xd46: "Cortex-A510",
+	0xd47: "Cortex-A710",
+	0xd48: "Cortex-X2",
+	0xd49: "Neoverse-N2",
+	0xd4a: "Neoverse-E1",
+	0xd4b: "Cortex-A78C",
+	0xd4c: "Cortex-X1C",
+	0xd4d: "Cortex-A715",
+	0xd4e: "Cortex-X3",
+	0xd4f: "Neoverse-V2",
+	0xd81: "Cortex-A720",
+	0xd82: "Cortex-X4",
+	0xd84: "Neoverse-V3",
+	0xd85: "Cortex-X925",
+	0xd87: "Cortex-A725",
+	0xd8e: "Neoverse-N3",
+}
+
+func init() {
+	clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+	// ignore errors
+	if err == nil {
+		ClocksPerSec = float64(clkTck)
+	}
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+	filename := common.HostProcWithContext(ctx, "stat")
+	lines := []string{}
+	var err error
+	if percpu {
+		statlines, err := common.ReadLines(filename)
+		if err != nil || len(statlines) < 2 {
+			return []TimesStat{}, nil
+		}
+		for _, line := range statlines[1:] {
+			if !strings.HasPrefix(line, "cpu") {
+				break
+			}
+			lines = append(lines, line)
+		}
+	} else {
+		lines, err = common.ReadLinesOffsetN(filename, 0, 1)
+		if err != nil || len(lines) == 0 {
+			return []TimesStat{}, nil
+		}
+	}
+
+	ret := make([]TimesStat, 0, len(lines))
+
+	for _, line := range lines {
+		ct, err := parseStatLine(line)
+		if err != nil {
+			continue
+		}
+		ret = append(ret, *ct)
+
+	}
+	return ret, nil
+}
+
+func sysCPUPath(ctx context.Context, cpu int32, relPath string) string {
+	return common.HostSysWithContext(ctx, fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath)
+}
+
+func finishCPUInfo(ctx context.Context, c *InfoStat) {
+	var lines []string
+	var err error
+	var value float64
+
+	if c.CoreID == "" {
+		lines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, "topology/core_id"))
+		if err == nil {
+			c.CoreID = lines[0]
+		}
+	}
+
+	// override the value of c.Mhz with cpufreq/cpuinfo_max_freq regardless
+	// of the value from /proc/cpuinfo because we want to report the maximum
+	// clock-speed of the CPU for c.Mhz, matching the behaviour of Windows
+	lines, err = common.ReadLines(sysCPUPath(ctx, c.CPU, "cpufreq/cpuinfo_max_freq"))
+	// if we encounter errors below such as there are no cpuinfo_max_freq file,
+	// we just ignore. so let Mhz is 0.
+	if err != nil || len(lines) == 0 {
+		return
+	}
+	value, err = strconv.ParseFloat(lines[0], 64)
+	if err != nil {
+		return
+	}
+	c.Mhz = value / 1000.0 // value is in kHz
+	if c.Mhz > 9999 {
+		c.Mhz /= 1000.0 // value in Hz
+	}
+}
+
+// CPUInfo on linux will return 1 item per physical thread.
+//
+// CPUs have three levels of counting: sockets, cores, threads.
+// Cores with HyperThreading count as having 2 threads per core.
+// Sockets often come with many physical CPU cores.
+// For example a single socket board with two cores each with HT will
+// return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1.
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+	filename := common.HostProcWithContext(ctx, "cpuinfo")
+	lines, err := common.ReadLines(filename)
+	if err != nil {
+		return nil, fmt.Errorf("could not read %s: %w", filename, err)
+	}
+
+	var ret []InfoStat
+	var processorName string
+
+	c := InfoStat{CPU: -1, Cores: 1}
+	for _, line := range lines {
+		fields := strings.SplitN(line, ":", 2)
+		if len(fields) < 2 {
+			continue
+		}
+		key := strings.TrimSpace(fields[0])
+		value := strings.TrimSpace(fields[1])
+
+		switch key {
+		case "Processor":
+			processorName = value
+		case "processor", "cpu number":
+			if c.CPU >= 0 {
+				finishCPUInfo(ctx, &c)
+				ret = append(ret, c)
+			}
+			c = InfoStat{Cores: 1, ModelName: processorName}
+			t, err := strconv.ParseInt(value, 10, 64)
+			if err != nil {
+				return ret, err
+			}
+			c.CPU = int32(t)
+		case "vendorId", "vendor_id":
+			c.VendorID = value
+			if strings.Contains(value, "S390") {
+				processorName = "S390"
+			}
+		case "mvendorid":
+			if !strings.HasPrefix(value, "0x") {
+				continue
+			}
+
+			if v, err := strconv.ParseUint(value[2:], 16, 32); err == nil {
+				switch v {
+				case 0x31e:
+					c.VendorID = "Andes"
+				case 0x029:
+					c.VendorID = "Microchip"
+				case 0x127:
+					c.VendorID = "MIPS"
+				case 0x489:
+					c.VendorID = "SiFive"
+				case 0x5b7:
+					c.VendorID = "T-Head"
+				}
+			}
+		case "CPU implementer":
+			if v, err := strconv.ParseUint(value, 0, 8); err == nil {
+				switch v {
+				case 0x41:
+					c.VendorID = "ARM"
+				case 0x42:
+					c.VendorID = "Broadcom"
+				case 0x43:
+					c.VendorID = "Cavium"
+				case 0x44:
+					c.VendorID = "DEC"
+				case 0x46:
+					c.VendorID = "Fujitsu"
+				case 0x48:
+					c.VendorID = "HiSilicon"
+				case 0x49:
+					c.VendorID = "Infineon"
+				case 0x4d:
+					c.VendorID = "Motorola/Freescale"
+				case 0x4e:
+					c.VendorID = "NVIDIA"
+				case 0x50:
+					c.VendorID = "APM"
+				case 0x51:
+					c.VendorID = "Qualcomm"
+				case 0x56:
+					c.VendorID = "Marvell"
+				case 0x61:
+					c.VendorID = "Apple"
+				case 0x69:
+					c.VendorID = "Intel"
+				case 0xc0:
+					c.VendorID = "Ampere"
+				}
+			}
+		case "cpu family", "marchid":
+			c.Family = value
+		case "model", "CPU part", "mimpid":
+			c.Model = value
+			// if CPU is arm based, model name is found via model number. refer to: arch/arm64/kernel/cpuinfo.c
+			if c.VendorID == "ARM" {
+				if v, err := strconv.ParseUint(c.Model, 0, 16); err == nil {
+					modelName, exist := armModelToModelName[v]
+					if exist {
+						c.ModelName = modelName
+					} else {
+						c.ModelName = "Undefined"
+					}
+				}
+			}
+		case "Model Name", "model name", "cpu", "uarch":
+			c.ModelName = value
+			if strings.Contains(value, "POWER") {
+				c.Model = strings.Split(value, " ")[0]
+				c.Family = "POWER"
+				c.VendorID = "IBM"
+			}
+		case "stepping", "revision", "CPU revision":
+			val := value
+
+			if key == "revision" {
+				val = strings.Split(value, ".")[0]
+			}
+
+			if strings.EqualFold(val, "unknown") {
+				continue
+			}
+
+			t, err := strconv.ParseInt(val, 10, 64)
+			if err != nil {
+				return ret, err
+			}
+			c.Stepping = int32(t)
+		case "cpu MHz", "clock", "cpu MHz dynamic":
+			// treat this as the fallback value, thus we ignore error
+			if t, err := strconv.ParseFloat(strings.Replace(value, "MHz", "", 1), 64); err == nil {
+				c.Mhz = t
+			}
+		case "cache size":
+			t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64)
+			if err != nil {
+				return ret, err
+			}
+			c.CacheSize = int32(t)
+		case "physical id", "hart":
+			c.PhysicalID = value
+		case "core id":
+			c.CoreID = value
+		case "flags", "Features":
+			c.Flags = strings.FieldsFunc(value, func(r rune) bool {
+				return r == ',' || r == ' '
+			})
+		case "isa", "hart isa":
+			if len(c.Flags) != 0 || !strings.HasPrefix(value, "rv64") {
+				continue
+			}
+			c.Flags = riscvISAParse(value)
+		case "microcode":
+			c.Microcode = value
+		}
+	}
+	if c.CPU >= 0 {
+		finishCPUInfo(ctx, &c)
+		ret = append(ret, c)
+	}
+	return ret, nil
+}
+
+func parseStatLine(line string) (*TimesStat, error) {
+	fields := strings.Fields(line)
+
+	if len(fields) < 8 {
+		return nil, errors.New("stat does not contain cpu info")
+	}
+
+	if !strings.HasPrefix(fields[0], "cpu") {
+		return nil, errors.New("not contain cpu")
+	}
+
+	cpu := fields[0]
+	if cpu == "cpu" {
+		cpu = "cpu-total"
+	}
+	user, err := strconv.ParseFloat(fields[1], 64)
+	if err != nil {
+		return nil, err
+	}
+	nice, err := strconv.ParseFloat(fields[2], 64)
+	if err != nil {
+		return nil, err
+	}
+	system, err := strconv.ParseFloat(fields[3], 64)
+	if err != nil {
+		return nil, err
+	}
+	idle, err := strconv.ParseFloat(fields[4], 64)
+	if err != nil {
+		return nil, err
+	}
+	iowait, err := strconv.ParseFloat(fields[5], 64)
+	if err != nil {
+		return nil, err
+	}
+	irq, err := strconv.ParseFloat(fields[6], 64)
+	if err != nil {
+		return nil, err
+	}
+	softirq, err := strconv.ParseFloat(fields[7], 64)
+	if err != nil {
+		return nil, err
+	}
+
+	ct := &TimesStat{
+		CPU:     cpu,
+		User:    user / ClocksPerSec,
+		Nice:    nice / ClocksPerSec,
+		System:  system / ClocksPerSec,
+		Idle:    idle / ClocksPerSec,
+		Iowait:  iowait / ClocksPerSec,
+		Irq:     irq / ClocksPerSec,
+		Softirq: softirq / ClocksPerSec,
+	}
+	if len(fields) > 8 { // Linux >= 2.6.11
+		steal, err := strconv.ParseFloat(fields[8], 64)
+		if err != nil {
+			return nil, err
+		}
+		ct.Steal = steal / ClocksPerSec
+	}
+	if len(fields) > 9 { // Linux >= 2.6.24
+		guest, err := strconv.ParseFloat(fields[9], 64)
+		if err != nil {
+			return nil, err
+		}
+		ct.Guest = guest / ClocksPerSec
+	}
+	if len(fields) > 10 { // Linux >= 3.2.0
+		guestNice, err := strconv.ParseFloat(fields[10], 64)
+		if err != nil {
+			return nil, err
+		}
+		ct.GuestNice = guestNice / ClocksPerSec
+	}
+
+	return ct, nil
+}
+
+func CountsWithContext(ctx context.Context, logical bool) (int, error) {
+	if logical {
+		ret := 0
+		// https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_pslinux.py#L599
+		procCpuinfo := common.HostProcWithContext(ctx, "cpuinfo")
+		lines, err := common.ReadLines(procCpuinfo)
+		if err == nil {
+			for _, line := range lines {
+				line = strings.ToLower(line)
+				if strings.HasPrefix(line, "processor") {
+					_, err = strconv.ParseInt(strings.TrimSpace(line[strings.IndexByte(line, ':')+1:]), 10, 32)
+					if err == nil {
+						ret++
+					}
+				}
+			}
+		}
+		if ret == 0 {
+			procStat := common.HostProcWithContext(ctx, "stat")
+			lines, err = common.ReadLines(procStat)
+			if err != nil {
+				return 0, err
+			}
+			for _, line := range lines {
+				if len(line) >= 4 && strings.HasPrefix(line, "cpu") && '0' <= line[3] && line[3] <= '9' { // `^cpu\d` regexp matching
+					ret++
+				}
+			}
+		}
+		return ret, nil
+	}
+	// physical cores
+	// https://github.com/giampaolo/psutil/blob/8415355c8badc9c94418b19bdf26e622f06f0cce/psutil/_pslinux.py#L615-L628
+	threadSiblingsLists := make(map[string]bool)
+	// These 2 files are the same but */core_cpus_list is newer while */thread_siblings_list is deprecated and may disappear in the future.
+	// https://www.kernel.org/doc/Documentation/admin-guide/cputopology.rst
+	// https://github.com/giampaolo/psutil/pull/1727#issuecomment-707624964
+	// https://lkml.org/lkml/2019/2/26/41
+	for _, glob := range []string{"devices/system/cpu/cpu[0-9]*/topology/core_cpus_list", "devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list"} {
+		if files, err := filepath.Glob(common.HostSysWithContext(ctx, glob)); err == nil {
+			for _, file := range files {
+				lines, err := common.ReadLines(file)
+				if err != nil || len(lines) != 1 {
+					continue
+				}
+				threadSiblingsLists[lines[0]] = true
+			}
+			ret := len(threadSiblingsLists)
+			if ret != 0 {
+				return ret, nil
+			}
+		}
+	}
+	// https://github.com/giampaolo/psutil/blob/122174a10b75c9beebe15f6c07dcf3afbe3b120d/psutil/_pslinux.py#L631-L652
+	filename := common.HostProcWithContext(ctx, "cpuinfo")
+	lines, err := common.ReadLines(filename)
+	if err != nil {
+		return 0, err
+	}
+	mapping := make(map[int]int)
+	currentInfo := make(map[string]int)
+	for _, line := range lines {
+		line = strings.ToLower(strings.TrimSpace(line))
+		if line == "" {
+			// new section
+			id, okID := currentInfo["physical id"]
+			cores, okCores := currentInfo["cpu cores"]
+			if okID && okCores {
+				mapping[id] = cores
+			}
+			currentInfo = make(map[string]int)
+			continue
+		}
+		fields := strings.SplitN(line, ":", 2)
+		if len(fields) < 2 {
+			continue
+		}
+		fields[0] = strings.TrimSpace(fields[0])
+		if fields[0] == "physical id" || fields[0] == "cpu cores" {
+			val, err := strconv.ParseInt(strings.TrimSpace(fields[1]), 10, 32)
+			if err != nil {
+				continue
+			}
+			currentInfo[fields[0]] = int(val)
+		}
+	}
+	ret := 0
+	for _, v := range mapping {
+		ret += v
+	}
+	return ret, nil
+}
+
+func riscvISAParse(s string) []string {
+	ext := strings.Split(s, "_")
+	if len(ext[0]) <= 4 {
+		return nil
+	}
+	// the base extensions must "rv64" prefix
+	base := strings.Split(ext[0][4:], "")
+	return append(base, ext[1:]...)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd.go
new file mode 100644
index 000000000..9e23edb6e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd.go
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build netbsd
+
+package cpu
+
+import (
+	"context"
+	"fmt"
+	"runtime"
+	"unsafe"
+
+	"github.com/tklauser/go-sysconf"
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+const (
+	// sys/sysctl.h
+	ctlKern    = 1  // "high kernel": proc, limits
+	ctlHw      = 6  // CTL_HW
+	kernCpTime = 51 // KERN_CPTIME
+)
+
+var ClocksPerSec = float64(100)
+
+func init() {
+	clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+	// ignore errors
+	if err == nil {
+		ClocksPerSec = float64(clkTck)
+	}
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {
+	ret := make([]TimesStat, 0)
+	if !percpu {
+		mib := []int32{ctlKern, kernCpTime}
+		buf, _, err := common.CallSyscall(mib)
+		if err != nil {
+			return ret, err
+		}
+		times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+		ret = append(ret, TimesStat{
+			CPU:    "cpu-total",
+			User:   float64(times.User),
+			Nice:   float64(times.Nice),
+			System: float64(times.Sys),
+			Idle:   float64(times.Idle),
+			Irq:    float64(times.Intr),
+		})
+		return ret, nil
+	}
+
+	ncpu, err := unix.SysctlUint32("hw.ncpu")
+	if err != nil {
+		return ret, err
+	}
+
+	var i uint32
+	for i = 0; i < ncpu; i++ {
+		mib := []int32{ctlKern, kernCpTime, int32(i)}
+		buf, _, err := common.CallSyscall(mib)
+		if err != nil {
+			return ret, err
+		}
+
+		stats := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+		ret = append(ret, TimesStat{
+			CPU:    fmt.Sprintf("cpu%d", i),
+			User:   float64(stats.User),
+			Nice:   float64(stats.Nice),
+			System: float64(stats.Sys),
+			Idle:   float64(stats.Idle),
+			Irq:    float64(stats.Intr),
+		})
+	}
+
+	return ret, nil
+}
+
+// Returns only one (minimal) CPUInfoStat on NetBSD
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(_ context.Context) ([]InfoStat, error) {
+	var ret []InfoStat
+	var err error
+
+	c := InfoStat{}
+
+	mhz, err := unix.Sysctl("machdep.dmi.processor-frequency")
+	if err != nil {
+		return nil, err
+	}
+	_, err = fmt.Sscanf(mhz, "%f", &c.Mhz)
+	if err != nil {
+		return nil, err
+	}
+
+	ncpu, err := unix.SysctlUint32("hw.ncpuonline")
+	if err != nil {
+		return nil, err
+	}
+	c.Cores = int32(ncpu)
+
+	if c.ModelName, err = unix.Sysctl("machdep.dmi.processor-version"); err != nil {
+		return nil, err
+	}
+
+	return append(ret, c), nil
+}
+
+func CountsWithContext(_ context.Context, _ bool) (int, error) {
+	return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_amd64.go
new file mode 100644
index 000000000..25ececa68
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_amd64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Intr uint64
+	Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm.go
new file mode 100644
index 000000000..e4799bcf5
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint32
+	Nice uint32
+	Sys  uint32
+	Intr uint32
+	Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm64.go
new file mode 100644
index 000000000..25ececa68
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_netbsd_arm64.go
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Intr uint64
+	Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd.go
new file mode 100644
index 000000000..9b37d296a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd.go
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package cpu
+
+import (
+	"context"
+	"fmt"
+	"runtime"
+	"unsafe"
+
+	"github.com/tklauser/go-sysconf"
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+const (
+	// sys/sched.h
+	cpuOnline = 0x0001 // CPUSTATS_ONLINE
+
+	// sys/sysctl.h
+	ctlKern      = 1  // "high kernel": proc, limits
+	ctlHw        = 6  // CTL_HW
+	smt          = 24 // HW_SMT
+	kernCpTime   = 40 // KERN_CPTIME
+	kernCPUStats = 85 // KERN_CPUSTATS
+)
+
+var ClocksPerSec = float64(128)
+
+type cpuStats struct {
+	// cs_time[CPUSTATES]
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Spin uint64
+	Intr uint64
+	Idle uint64
+
+	// cs_flags
+	Flags uint64
+}
+
+func init() {
+	clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+	// ignore errors
+	if err == nil {
+		ClocksPerSec = float64(clkTck)
+	}
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {
+	ret := make([]TimesStat, 0)
+	if !percpu {
+		mib := []int32{ctlKern, kernCpTime}
+		buf, _, err := common.CallSyscall(mib)
+		if err != nil {
+			return ret, err
+		}
+		times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
+		ret = append(ret, TimesStat{
+			CPU:    "cpu-total",
+			User:   float64(times.User) / ClocksPerSec,
+			Nice:   float64(times.Nice) / ClocksPerSec,
+			System: float64(times.Sys) / ClocksPerSec,
+			Idle:   float64(times.Idle) / ClocksPerSec,
+			Irq:    float64(times.Intr) / ClocksPerSec,
+		})
+		return ret, nil
+	}
+
+	ncpu, err := unix.SysctlUint32("hw.ncpu")
+	if err != nil {
+		return ret, err
+	}
+
+	var i uint32
+	for i = 0; i < ncpu; i++ {
+		mib := []int32{ctlKern, kernCPUStats, int32(i)}
+		buf, _, err := common.CallSyscall(mib)
+		if err != nil {
+			return ret, err
+		}
+
+		stats := (*cpuStats)(unsafe.Pointer(&buf[0]))
+		if (stats.Flags & cpuOnline) == 0 {
+			continue
+		}
+		ret = append(ret, TimesStat{
+			CPU:    fmt.Sprintf("cpu%d", i),
+			User:   float64(stats.User) / ClocksPerSec,
+			Nice:   float64(stats.Nice) / ClocksPerSec,
+			System: float64(stats.Sys) / ClocksPerSec,
+			Idle:   float64(stats.Idle) / ClocksPerSec,
+			Irq:    float64(stats.Intr) / ClocksPerSec,
+		})
+	}
+
+	return ret, nil
+}
+
+// Returns only one (minimal) CPUInfoStat on OpenBSD
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(_ context.Context) ([]InfoStat, error) {
+	var ret []InfoStat
+	var err error
+
+	c := InfoStat{}
+
+	mhz, err := unix.SysctlUint32("hw.cpuspeed")
+	if err != nil {
+		return nil, err
+	}
+	c.Mhz = float64(mhz)
+
+	ncpu, err := unix.SysctlUint32("hw.ncpuonline")
+	if err != nil {
+		return nil, err
+	}
+	c.Cores = int32(ncpu)
+
+	if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
+		return nil, err
+	}
+
+	return append(ret, c), nil
+}
+
+func CountsWithContext(_ context.Context, _ bool) (int, error) {
+	return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_386.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_386.go
new file mode 100644
index 000000000..40a6f43e4
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_386.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint32
+	Nice uint32
+	Sys  uint32
+	Spin uint32
+	Intr uint32
+	Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_amd64.go
new file mode 100644
index 000000000..464156d54
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_amd64.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Spin uint64
+	Intr uint64
+	Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm.go
new file mode 100644
index 000000000..40a6f43e4
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint32
+	Nice uint32
+	Sys  uint32
+	Spin uint32
+	Intr uint32
+	Idle uint32
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm64.go
new file mode 100644
index 000000000..464156d54
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_arm64.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Spin uint64
+	Intr uint64
+	Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_riscv64.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_riscv64.go
new file mode 100644
index 000000000..464156d54
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_openbsd_riscv64.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+type cpuTimes struct {
+	User uint64
+	Nice uint64
+	Sys  uint64
+	Spin uint64
+	Intr uint64
+	Idle uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_plan9.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_plan9.go
new file mode 100644
index 000000000..02ad3f747
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_plan9.go
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build plan9
+
+package cpu
+
+import (
+	"context"
+	"os"
+	"runtime"
+
+	stats "github.com/lufia/plan9stats"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(ctx context.Context, _ bool) ([]TimesStat, error) {
+	// BUG: percpu flag is not supported yet.
+	root := os.Getenv("HOST_ROOT")
+	c, err := stats.ReadCPUType(ctx, stats.WithRootDir(root))
+	if err != nil {
+		return nil, err
+	}
+	s, err := stats.ReadCPUStats(ctx, stats.WithRootDir(root))
+	if err != nil {
+		return nil, err
+	}
+	return []TimesStat{
+		{
+			CPU:    c.Name,
+			User:   s.User.Seconds(),
+			System: s.Sys.Seconds(),
+			Idle:   s.Idle.Seconds(),
+		},
+	}, nil
+}
+
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(_ context.Context) ([]InfoStat, error) {
+	return []InfoStat{}, common.ErrNotImplementedError
+}
+
+func CountsWithContext(_ context.Context, _ bool) (int, error) {
+	return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_solaris.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_solaris.go
new file mode 100644
index 000000000..9494e3c3f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_solaris.go
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package cpu
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"regexp"
+	"runtime"
+	"sort"
+	"strconv"
+	"strings"
+
+	"github.com/tklauser/go-sysconf"
+)
+
+var ClocksPerSec = float64(128)
+
+func init() {
+	clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+	// ignore errors
+	if err == nil {
+		ClocksPerSec = float64(clkTck)
+	}
+}
+
+// sum all values in a float64 map with float64 keys
+func msum(x map[float64]float64) float64 {
+	total := 0.0
+	for _, y := range x {
+		total += y
+	}
+	return total
+}
+
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+var kstatSplit = regexp.MustCompile(`[:\s]+`)
+
+func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
+	kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-p", "cpu_stat:*:*:/^idle$|^user$|^kernel$|^iowait$|^swap$/")
+	if err != nil {
+		return nil, fmt.Errorf("cannot execute kstat: %w", err)
+	}
+	cpu := make(map[float64]float64)
+	idle := make(map[float64]float64)
+	user := make(map[float64]float64)
+	kern := make(map[float64]float64)
+	iowt := make(map[float64]float64)
+	// swap := make(map[float64]float64)
+	for _, line := range strings.Split(string(kstatSysOut), "\n") {
+		fields := kstatSplit.Split(line, -1)
+		if fields[0] != "cpu_stat" {
+			continue
+		}
+		cpuNumber, err := strconv.ParseFloat(fields[1], 64)
+		if err != nil {
+			return nil, fmt.Errorf("cannot parse cpu number: %w", err)
+		}
+		cpu[cpuNumber] = cpuNumber
+		switch fields[3] {
+		case "idle":
+			idle[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse idle: %w", err)
+			}
+		case "user":
+			user[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse user: %w", err)
+			}
+		case "kernel":
+			kern[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse kernel: %w", err)
+			}
+		case "iowait":
+			iowt[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse iowait: %w", err)
+			}
+			// not sure how this translates, don't report, add to kernel, something else?
+			/*case "swap":
+			swap[cpuNumber], err = strconv.ParseFloat(fields[4], 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse swap: %s", err)
+			} */
+		}
+	}
+	ret := make([]TimesStat, 0, len(cpu))
+	if percpu {
+		for _, c := range cpu {
+			ct := &TimesStat{
+				CPU:    fmt.Sprintf("cpu%d", int(cpu[c])),
+				Idle:   idle[c] / ClocksPerSec,
+				User:   user[c] / ClocksPerSec,
+				System: kern[c] / ClocksPerSec,
+				Iowait: iowt[c] / ClocksPerSec,
+			}
+			ret = append(ret, *ct)
+		}
+	} else {
+		ct := &TimesStat{
+			CPU:    "cpu-total",
+			Idle:   msum(idle) / ClocksPerSec,
+			User:   msum(user) / ClocksPerSec,
+			System: msum(kern) / ClocksPerSec,
+			Iowait: msum(iowt) / ClocksPerSec,
+		}
+		ret = append(ret, *ct)
+	}
+	return ret, nil
+}
+
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+	psrInfoOut, err := invoke.CommandWithContext(ctx, "psrinfo", "-p", "-v")
+	if err != nil {
+		return nil, fmt.Errorf("cannot execute psrinfo: %w", err)
+	}
+
+	procs, err := parseProcessorInfo(string(psrInfoOut))
+	if err != nil {
+		return nil, fmt.Errorf("error parsing psrinfo output: %w", err)
+	}
+
+	isaInfoOut, err := invoke.CommandWithContext(ctx, "isainfo", "-b", "-v")
+	if err != nil {
+		return nil, fmt.Errorf("cannot execute isainfo: %w", err)
+	}
+
+	flags, err := parseISAInfo(string(isaInfoOut))
+	if err != nil {
+		return nil, fmt.Errorf("error parsing isainfo output: %w", err)
+	}
+
+	result := make([]InfoStat, 0, len(flags))
+	for i := range procs {
+		procWithFlags := procs[i]
+		procWithFlags.Flags = flags
+		result = append(result, procWithFlags)
+	}
+
+	return result, nil
+}
+
+var flagsMatch = regexp.MustCompile(`[\w.]+`)
+
+func parseISAInfo(cmdOutput string) ([]string, error) {
+	words := flagsMatch.FindAllString(cmdOutput, -1)
+
+	// Sanity check the output
+	if len(words) < 4 || words[1] != "bit" || words[3] != "applications" {
+		return nil, errors.New("attempted to parse invalid isainfo output")
+	}
+
+	flags := words[4:]
+	sort.Strings(flags)
+
+	return flags, nil
+}
+
+var psrInfoMatch = regexp.MustCompile(`The physical processor has (?:([\d]+) virtual processors? \(([\d-]+)\)|([\d]+) cores and ([\d]+) virtual processors[^\n]+)\n(?:\s+ The core has.+\n)*\s+.+ \((\w+) ([\S]+) family (.+) model (.+) step (.+) clock (.+) MHz\)\n[\s]*(.*)`)
+
+const (
+	psrNumCoresOffset   = 1
+	psrNumCoresHTOffset = 3
+	psrNumHTOffset      = 4
+	psrVendorIDOffset   = 5
+	psrFamilyOffset     = 7
+	psrModelOffset      = 8
+	psrStepOffset       = 9
+	psrClockOffset      = 10
+	psrModelNameOffset  = 11
+)
+
+func parseProcessorInfo(cmdOutput string) ([]InfoStat, error) {
+	matches := psrInfoMatch.FindAllStringSubmatch(cmdOutput, -1)
+
+	var infoStatCount int32
+	result := make([]InfoStat, 0, len(matches))
+	for physicalIndex, physicalCPU := range matches {
+		var step int32
+		var clock float64
+
+		if physicalCPU[psrStepOffset] != "" {
+			stepParsed, err := strconv.ParseInt(physicalCPU[psrStepOffset], 10, 32)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse value %q for step as 32-bit integer: %w", physicalCPU[9], err)
+			}
+			step = int32(stepParsed)
+		}
+
+		if physicalCPU[psrClockOffset] != "" {
+			clockParsed, err := strconv.ParseInt(physicalCPU[psrClockOffset], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse value %q for clock as 32-bit integer: %w", physicalCPU[10], err)
+			}
+			clock = float64(clockParsed)
+		}
+
+		var err error
+		var numCores int64
+		var numHT int64
+		switch {
+		case physicalCPU[psrNumCoresOffset] != "":
+			numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresOffset], 10, 32)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %w", physicalCPU[1], err)
+			}
+
+			for i := 0; i < int(numCores); i++ {
+				result = append(result, InfoStat{
+					CPU:        infoStatCount,
+					PhysicalID: strconv.Itoa(physicalIndex),
+					CoreID:     strconv.Itoa(i),
+					Cores:      1,
+					VendorID:   physicalCPU[psrVendorIDOffset],
+					ModelName:  physicalCPU[psrModelNameOffset],
+					Family:     physicalCPU[psrFamilyOffset],
+					Model:      physicalCPU[psrModelOffset],
+					Stepping:   step,
+					Mhz:        clock,
+				})
+				infoStatCount++
+			}
+		case physicalCPU[psrNumCoresHTOffset] != "":
+			numCores, err = strconv.ParseInt(physicalCPU[psrNumCoresHTOffset], 10, 32)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse value %q for core count as 32-bit integer: %w", physicalCPU[3], err)
+			}
+
+			numHT, err = strconv.ParseInt(physicalCPU[psrNumHTOffset], 10, 32)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse value %q for hyperthread count as 32-bit integer: %w", physicalCPU[4], err)
+			}
+
+			for i := 0; i < int(numCores); i++ {
+				result = append(result, InfoStat{
+					CPU:        infoStatCount,
+					PhysicalID: strconv.Itoa(physicalIndex),
+					CoreID:     strconv.Itoa(i),
+					Cores:      int32(numHT) / int32(numCores),
+					VendorID:   physicalCPU[psrVendorIDOffset],
+					ModelName:  physicalCPU[psrModelNameOffset],
+					Family:     physicalCPU[psrFamilyOffset],
+					Model:      physicalCPU[psrModelOffset],
+					Stepping:   step,
+					Mhz:        clock,
+				})
+				infoStatCount++
+			}
+		default:
+			return nil, errors.New("values for cores with and without hyperthreading are both set")
+		}
+	}
+	return result, nil
+}
+
+func CountsWithContext(_ context.Context, _ bool) (int, error) {
+	return runtime.NumCPU(), nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_windows.go b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_windows.go
new file mode 100644
index 000000000..c15a085b7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/cpu/cpu_windows.go
@@ -0,0 +1,538 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package cpu
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"math/bits"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+	"golang.org/x/sys/windows/registry"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var (
+	procGetNativeSystemInfo              = common.Modkernel32.NewProc("GetNativeSystemInfo")
+	procGetLogicalProcessorInformationEx = common.Modkernel32.NewProc("GetLogicalProcessorInformationEx")
+	procGetSystemFirmwareTable           = common.Modkernel32.NewProc("GetSystemFirmwareTable")
+	procCallNtPowerInformation           = common.ModPowrProf.NewProc("CallNtPowerInformation")
+	procGetActiveProcessorGroupCount     = common.Modkernel32.NewProc("GetActiveProcessorGroupCount")
+)
+
+type win32_Processor struct { //nolint:revive //FIXME
+	Family                    uint16
+	Manufacturer              string
+	Name                      string
+	NumberOfLogicalProcessors uint32
+	NumberOfCores             uint32
+	ProcessorID               *string
+	Stepping                  *string
+	MaxClockSpeed             uint32
+}
+
+// SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
+// defined in windows api doc with the following
+// https://docs.microsoft.com/en-us/windows/desktop/api/winternl/nf-winternl-ntquerysysteminformation#system_processor_performance_information
+// additional fields documented here
+// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/processor_performance.htm
+type win32_SystemProcessorPerformanceInformation struct { //nolint:revive //FIXME
+	IdleTime       int64  // idle time in 100ns (this is not a filetime).
+	KernelTime     int64  // kernel time in 100ns.  kernel time includes idle time. (this is not a filetime).
+	UserTime       int64  // usertime in 100ns (this is not a filetime).
+	DpcTime        int64  // dpc time in 100ns (this is not a filetime).
+	InterruptTime  int64  // interrupt time in 100ns
+	InterruptCount uint64 // ULONG needs to be uint64
+}
+
+// https://learn.microsoft.com/en-us/windows/win32/power/processor-power-information-str
+type processorPowerInformation struct {
+	number           uint32 // http://download.microsoft.com/download/a/d/f/adf1347d-08dc-41a4-9084-623b1194d4b2/MoreThan64proc.docx
+	maxMhz           uint32
+	currentMhz       uint32
+	mhzLimit         uint32
+	maxIdleState     uint32
+	currentIdleState uint32
+}
+
+const (
+	ClocksPerSec = 10000000.0
+
+	// systemProcessorPerformanceInformationClass information class to query with NTQuerySystemInformation
+	// https://processhacker.sourceforge.io/doc/ntexapi_8h.html#ad5d815b48e8f4da1ef2eb7a2f18a54e0
+	win32_SystemProcessorPerformanceInformationClass = 8 //nolint:revive //FIXME
+
+	// size of systemProcessorPerformanceInfoSize in memory
+	win32_SystemProcessorPerformanceInfoSize = uint32(unsafe.Sizeof(win32_SystemProcessorPerformanceInformation{})) //nolint:revive //FIXME
+
+	firmwareTableProviderSignatureRSMB = 0x52534d42 // "RSMB"  https://gitlab.winehq.org/dreamer/wine/-/blame/wine-7.0-rc6/dlls/ntdll/unix/system.c#L230
+	smBiosHeaderSize                   = 8          // SMBIOS header size
+	smbiosEndOfTable                   = 127        // Minimum length for processor structure
+	smbiosTypeProcessor                = 4          // SMBIOS Type 4: Processor Information
+	smbiosProcessorMinLength           = 0x18       // Minimum length for processor structure
+
+	centralProcessorRegistryKey = `HARDWARE\DESCRIPTION\System\CentralProcessor`
+)
+
+type relationship uint32
+
+// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
+const (
+	relationProcessorCore    = relationship(0)
+	relationProcessorPackage = relationship(3)
+)
+
+const (
+	kAffinitySize = unsafe.Sizeof(int(0))
+	// https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/interrupt-affinity-and-priority
+	maxLogicalProcessorsPerGroup = uint32(unsafe.Sizeof(kAffinitySize * 8))
+	// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-power_information_level
+	processorInformation = 11
+)
+
+// Times returns times stat per cpu and combined for all CPUs
+func Times(percpu bool) ([]TimesStat, error) {
+	return TimesWithContext(context.Background(), percpu)
+}
+
+func TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) {
+	if percpu {
+		return perCPUTimes()
+	}
+
+	var ret []TimesStat
+	var lpIdleTime common.FILETIME
+	var lpKernelTime common.FILETIME
+	var lpUserTime common.FILETIME
+	// GetSystemTimes returns 0 for error, in which case we check err,
+	// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call
+	r, _, err := common.ProcGetSystemTimes.Call(
+		uintptr(unsafe.Pointer(&lpIdleTime)),
+		uintptr(unsafe.Pointer(&lpKernelTime)),
+		uintptr(unsafe.Pointer(&lpUserTime)))
+	if r == 0 {
+		return nil, err
+	}
+
+	LOT := float64(0.0000001)
+	HIT := (LOT * 4294967296.0)
+	idle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime)))
+	user := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime)))
+	kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime)))
+	system := (kernel - idle)
+
+	ret = append(ret, TimesStat{
+		CPU:    "cpu-total",
+		Idle:   float64(idle),
+		User:   float64(user),
+		System: float64(system),
+	})
+	return ret, nil
+}
+
+func Info() ([]InfoStat, error) {
+	return InfoWithContext(context.Background())
+}
+
+// this function iterates over each set bit in the package affinity mask, each bit represent a logical processor in a group (assuming you are iteriang over a package mask)
+// the function is used also to compute the global logical processor number
+// https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups
+// see https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_affinity
+// and https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship
+// and https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
+func forEachSetBit64(mask uint64, fn func(bit int)) {
+	m := mask
+	for m != 0 {
+		b := bits.TrailingZeros64(m)
+		fn(b)
+		m &= m - 1
+	}
+}
+
+func getProcessorPowerInformation(ctx context.Context) ([]processorPowerInformation, error) {
+	numLP, countErr := CountsWithContext(ctx, true)
+	if countErr != nil {
+		return nil, fmt.Errorf("failed to get logical processor count: %w", countErr)
+	}
+	if numLP <= 0 {
+		return nil, fmt.Errorf("invalid logical processor count: %d", numLP)
+	}
+
+	ppiSize := uintptr(numLP) * unsafe.Sizeof(processorPowerInformation{})
+	buf := make([]byte, ppiSize)
+	ppi, _, err := procCallNtPowerInformation.Call(
+		uintptr(processorInformation),
+		0,
+		0,
+		uintptr(unsafe.Pointer(&buf[0])),
+		uintptr(ppiSize),
+	)
+	if ppi != 0 {
+		return nil, fmt.Errorf("CallNtPowerInformation failed with code %d: %w", ppi, err)
+	}
+	ppis := unsafe.Slice((*processorPowerInformation)(unsafe.Pointer(&buf[0])), numLP)
+	return ppis, nil
+}
+
+func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
+	var ret []InfoStat
+	processorPackages, err := getSystemLogicalProcessorInformationEx(relationProcessorPackage)
+	if err != nil {
+		return ret, fmt.Errorf("failed to get processor package information: %w", err)
+	}
+
+	ppis, powerInformationErr := getProcessorPowerInformation(ctx)
+	if powerInformationErr != nil {
+		return ret, fmt.Errorf("failed to get processor power information: %w", powerInformationErr)
+	}
+
+	family, processorId, smBIOSErr := getSMBIOSProcessorInfo()
+	if smBIOSErr != nil {
+		return ret, smBIOSErr
+	}
+
+	for i, pkg := range processorPackages {
+		logicalCount := 0
+		maxMhz := 0
+		model := ""
+		vendorId := ""
+		// iterate over each set bit in the package affinity mask
+		for _, ga := range pkg.processor.groupMask {
+			g := int(ga.group)
+			forEachSetBit64(uint64(ga.mask), func(bit int) {
+				// the global logical processor label
+				globalLpl := g*int(maxLogicalProcessorsPerGroup) + bit
+				if globalLpl >= 0 && globalLpl < len(ppis) {
+					logicalCount++
+					m := int(ppis[globalLpl].maxMhz)
+					if m > maxMhz {
+						maxMhz = m
+					}
+				}
+
+				registryKeyPath := filepath.Join(centralProcessorRegistryKey, strconv.Itoa(globalLpl))
+				key, err := registry.OpenKey(registry.LOCAL_MACHINE, registryKeyPath, registry.QUERY_VALUE|registry.READ)
+				if err == nil {
+					model = getRegistryStringValueIfUnset(key, "ProcessorNameString", model)
+					vendorId = getRegistryStringValueIfUnset(key, "VendorIdentifier", vendorId)
+					_ = key.Close()
+				}
+			})
+		}
+		ret = append(ret, InfoStat{
+			CPU:        int32(i),
+			Family:     strconv.FormatUint(uint64(family), 10),
+			VendorID:   vendorId,
+			ModelName:  model,
+			Cores:      int32(logicalCount),
+			PhysicalID: processorId,
+			Mhz:        float64(maxMhz),
+			Flags:      []string{},
+		})
+	}
+
+	return ret, nil
+}
+
+// perCPUTimes returns times stat per cpu, per core and overall for all CPUs
+func perCPUTimes() ([]TimesStat, error) {
+	var ret []TimesStat
+	stats, err := perfInfo()
+	if err != nil {
+		return nil, err
+	}
+	for core, v := range stats {
+		c := TimesStat{
+			CPU:    fmt.Sprintf("cpu%d", core),
+			User:   float64(v.UserTime) / ClocksPerSec,
+			System: float64(v.KernelTime-v.IdleTime) / ClocksPerSec,
+			Idle:   float64(v.IdleTime) / ClocksPerSec,
+			Irq:    float64(v.InterruptTime) / ClocksPerSec,
+		}
+		ret = append(ret, c)
+	}
+	return ret, nil
+}
+
+// makes call to Windows API function to retrieve performance information for each core
+func perfInfo() ([]win32_SystemProcessorPerformanceInformation, error) {
+	// On hosts with more than 64 logical CPUs Windows splits CPUs into Processor Groups
+	// (up to 64 logical CPUs per group). The non-Ex NtQuerySystemInformation only returns
+	// data for the calling thread's group, so whenever the Ex variant is available we
+	// iterate every active group and concatenate the results. See issue #887.
+	if common.ProcNtQuerySystemInformationEx.Find() == nil {
+		return perfInfoAllGroups()
+	}
+	return perfInfoSingleGroup()
+}
+
+// perfInfoSingleGroup queries SystemProcessorPerformanceInformation via the non-Ex
+// NtQuerySystemInformation call. This is the legacy fallback for environments where
+// NtQuerySystemInformationEx cannot be resolved; it only returns data for the calling
+// thread's processor group.
+func perfInfoSingleGroup() ([]win32_SystemProcessorPerformanceInformation, error) {
+	// Make maxResults large for safety.
+	// We can't invoke the api call with a results array that's too small.
+	// If we have more than 2056 cores on a single host, then it's probably the future.
+	maxBuffer := 2056
+	// buffer for results from the windows proc
+	resultBuffer := make([]win32_SystemProcessorPerformanceInformation, maxBuffer)
+	// size of the buffer in memory
+	bufferSize := uintptr(win32_SystemProcessorPerformanceInfoSize) * uintptr(maxBuffer)
+	// size of the returned response
+	var retSize uint32
+
+	// Invoke windows api proc.
+	// The returned err from the windows dll proc will always be non-nil even when successful.
+	// See https://godoc.org/golang.org/x/sys/windows#LazyProc.Call for more information
+	retCode, _, err := common.ProcNtQuerySystemInformation.Call(
+		win32_SystemProcessorPerformanceInformationClass, // System Information Class -> SystemProcessorPerformanceInformation
+		uintptr(unsafe.Pointer(&resultBuffer[0])),        // pointer to first element in result buffer
+		bufferSize,                        // size of the buffer in memory
+		uintptr(unsafe.Pointer(&retSize)), // pointer to the size of the returned results the windows proc will set this
+	)
+
+	// check return code for errors
+	if retCode != 0 {
+		return nil, fmt.Errorf("call to NtQuerySystemInformation returned 0x%x: %w", retCode, err)
+	}
+
+	// calculate the number of returned elements based on the returned size
+	numReturnedElements := retSize / win32_SystemProcessorPerformanceInfoSize
+
+	// trim results to the number of returned elements
+	return resultBuffer[:numReturnedElements], nil
+}
+
+// perfInfoAllGroups queries SystemProcessorPerformanceInformation for every active
+// processor group via NtQuerySystemInformationEx and concatenates the results. The
+// group index is passed as the InputBuffer per the Ex calling convention documented at
+// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/queryex.htm
+func perfInfoAllGroups() ([]win32_SystemProcessorPerformanceInformation, error) {
+	// GetActiveProcessorGroupCount returns 0 only on failure; propagate the error
+	// rather than silently defaulting to a single group and returning partial data.
+	r, _, callErr := procGetActiveProcessorGroupCount.Call()
+	if r == 0 {
+		return nil, fmt.Errorf("GetActiveProcessorGroupCount returned 0: %w", callErr)
+	}
+	groupCount := uint16(r)
+
+	var result []win32_SystemProcessorPerformanceInformation
+	for g := uint16(0); g < groupCount; g++ {
+		numLP := windows.GetActiveProcessorCount(g)
+		if numLP == 0 {
+			return nil, fmt.Errorf("GetActiveProcessorCount returned 0 for processor group %d", g)
+		}
+		// buffer sized exactly for this group's logical CPU count
+		buf := make([]win32_SystemProcessorPerformanceInformation, numLP)
+		bufSize := uintptr(win32_SystemProcessorPerformanceInfoSize) * uintptr(numLP)
+		var retSize uint32
+		// InputBuffer is a USHORT (2 bytes) holding the target processor group index.
+		group := g
+		retCode, _, err := common.ProcNtQuerySystemInformationEx.Call(
+			win32_SystemProcessorPerformanceInformationClass, // System Information Class -> SystemProcessorPerformanceInformation
+			uintptr(unsafe.Pointer(&group)),                  // InputBuffer: pointer to USHORT group index
+			unsafe.Sizeof(group),                             // InputBufferLength: sizeof(USHORT) = 2
+			uintptr(unsafe.Pointer(&buf[0])),                 // pointer to first element in result buffer
+			bufSize,                                          // size of the buffer in memory
+			uintptr(unsafe.Pointer(&retSize)),                // pointer to the size of the returned results the windows proc will set this
+		)
+		if retCode != 0 {
+			return nil, fmt.Errorf("call to NtQuerySystemInformationEx(group=%d) returned 0x%x: %w", g, retCode, err)
+		}
+		// Guard against a retSize that is not a whole number of entries or exceeds
+		// the allocated buffer (e.g. CPU hot-add racing with GetActiveProcessorCount).
+		if retSize%win32_SystemProcessorPerformanceInfoSize != 0 || uintptr(retSize) > bufSize {
+			return nil, fmt.Errorf("NtQuerySystemInformationEx(group=%d) returned unexpected retSize=%d (bufSize=%d)", g, retSize, bufSize)
+		}
+		n := retSize / win32_SystemProcessorPerformanceInfoSize
+		result = append(result, buf[:n]...)
+	}
+	return result, nil
+}
+
+// SystemInfo is an equivalent representation of SYSTEM_INFO in the Windows API.
+// https://msdn.microsoft.com/en-us/library/ms724958%28VS.85%29.aspx?f=255&MSPPError=-2147217396
+// https://github.com/elastic/go-windows/blob/bb1581babc04d5cb29a2bfa7a9ac6781c730c8dd/kernel32.go#L43
+type systemInfo struct {
+	wProcessorArchitecture      uint16
+	wReserved                   uint16
+	dwPageSize                  uint32
+	lpMinimumApplicationAddress uintptr
+	lpMaximumApplicationAddress uintptr
+	dwActiveProcessorMask       uintptr
+	dwNumberOfProcessors        uint32
+	dwProcessorType             uint32
+	dwAllocationGranularity     uint32
+	wProcessorLevel             uint16
+	wProcessorRevision          uint16
+}
+
+type groupAffinity struct {
+	mask     uintptr // https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/interrupt-affinity-and-priority#about-kaffinity
+	group    uint16
+	reserved [3]uint16
+}
+
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship
+type processorRelationship struct {
+	flags          byte
+	efficientClass byte
+	reserved       [20]byte
+	groupCount     uint16
+	groupMask      [1]groupAffinity
+}
+
+// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
+type systemLogicalProcessorInformationEx struct {
+	relationship uint32
+	size         uint32
+	processor    processorRelationship
+}
+
+// getSMBIOSProcessorInfo reads the SMBIOS Type 4 (Processor Information) structure and returns the Processor Family and ProcessorId fields.
+// If not found, returns 0 and an empty string.
+func getSMBIOSProcessorInfo() (family uint8, processorId string, err error) {
+	// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable
+	size, _, err := procGetSystemFirmwareTable.Call(
+		uintptr(firmwareTableProviderSignatureRSMB),
+		0,
+		0,
+		0,
+	)
+	if size == 0 {
+		return 0, "", fmt.Errorf("failed to get SMBIOS table size: %w", err)
+	}
+	buf := make([]byte, size)
+	ret, _, err := procGetSystemFirmwareTable.Call(
+		uintptr(firmwareTableProviderSignatureRSMB),
+		0,
+		uintptr(unsafe.Pointer(&buf[0])),
+		uintptr(size),
+	)
+	if ret == 0 {
+		return 0, "", fmt.Errorf("failed to read SMBIOS table: %w", err)
+	}
+	// https://wiki.osdev.org/System_Management_BIOS
+	i := smBiosHeaderSize // skip SMBIOS header (first 8 bytes)
+	maxIterations := len(buf) * 2
+	iterations := 0
+	for i < len(buf) && iterations < maxIterations {
+		iterations++
+		if i+4 > len(buf) {
+			break
+		}
+		typ := buf[i]
+		length := buf[i+1]
+		if typ == smbiosEndOfTable {
+			break
+		}
+		if typ == smbiosTypeProcessor && length >= smbiosProcessorMinLength && i+int(length) <= len(buf) {
+			// Ensure we have enough bytes for procIdBytes
+			if i+16 > len(buf) {
+				break
+			}
+			// Get the processor family from byte at offset 6
+			family = buf[i+6]
+			// Extract processor ID bytes (8 bytes total) from offsets 8-15
+			procIdBytes := buf[i+8 : i+16]
+			// Convert first 4 bytes to 32-bit EAX register value (little endian)
+			eax := uint32(procIdBytes[0]) | uint32(procIdBytes[1])<<8 | uint32(procIdBytes[2])<<16 | uint32(procIdBytes[3])<<24
+			// Convert last 4 bytes to 32-bit EDX register value (little endian)
+			edx := uint32(procIdBytes[4]) | uint32(procIdBytes[5])<<8 | uint32(procIdBytes[6])<<16 | uint32(procIdBytes[7])<<24
+			// Format processor ID as 16 character hex string (EDX+EAX)
+			procId := fmt.Sprintf("%08X%08X", edx, eax)
+			return family, procId, nil
+		}
+		// skip to next structure
+		j := i + int(length)
+		innerIterations := 0
+		maxInner := len(buf) // failsafe for inner loop
+		for j+1 < len(buf) && innerIterations < maxInner {
+			innerIterations++
+			if buf[j] == 0 && buf[j+1] == 0 {
+				j += 2
+				break
+			}
+			j++
+		}
+		if innerIterations >= maxInner {
+			break // malformed buffer, avoid infinite loop
+		}
+		i = j
+	}
+	return 0, "", fmt.Errorf("SMBIOS processor information not found: %w", syscall.ERROR_NOT_FOUND)
+}
+
+func getSystemLogicalProcessorInformationEx(relationship relationship) ([]systemLogicalProcessorInformationEx, error) {
+	var length uint32
+	// First call to determine the required buffer size
+	_, _, err := procGetLogicalProcessorInformationEx.Call(uintptr(relationship), 0, uintptr(unsafe.Pointer(&length)))
+	if err != nil && !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {
+		return nil, fmt.Errorf("failed to get buffer size: %w", err)
+	}
+
+	// Allocate the buffer
+	buffer := make([]byte, length)
+
+	// Second call to retrieve the processor information
+	_, _, err = procGetLogicalProcessorInformationEx.Call(uintptr(relationship), uintptr(unsafe.Pointer(&buffer[0])), uintptr(unsafe.Pointer(&length)))
+	if err != nil && !errors.Is(err, windows.NTE_OP_OK) {
+		return nil, fmt.Errorf("failed to get logical processor information: %w", err)
+	}
+
+	// Convert the byte slice into a slice of systemLogicalProcessorInformationEx structs
+	offset := uintptr(0)
+	var infos []systemLogicalProcessorInformationEx
+	for offset < uintptr(length) {
+		info := (*systemLogicalProcessorInformationEx)(unsafe.Pointer(uintptr(unsafe.Pointer(&buffer[0])) + offset))
+		infos = append(infos, *info)
+		offset += uintptr(info.size)
+	}
+
+	return infos, nil
+}
+
+func getPhysicalCoreCount() (int, error) {
+	infos, err := getSystemLogicalProcessorInformationEx(relationProcessorCore)
+	return len(infos), err
+}
+
+func getRegistryStringValueIfUnset(key registry.Key, keyName, value string) string {
+	if value != "" {
+		return value
+	}
+	val, _, err := key.GetStringValue(keyName)
+	if err == nil {
+		return strings.TrimSpace(val)
+	}
+	return ""
+}
+
+func CountsWithContext(_ context.Context, logical bool) (int, error) {
+	if logical {
+		// Get logical processor count https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L97
+		ret := windows.GetActiveProcessorCount(windows.ALL_PROCESSOR_GROUPS)
+		if ret != 0 {
+			return int(ret), nil
+		}
+
+		var sInfo systemInfo
+		_, _, err := procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sInfo)))
+		if sInfo.dwNumberOfProcessors == 0 {
+			return 0, err
+		}
+		return int(sInfo.dwNumberOfProcessors), nil
+	}
+
+	// Get physical core count https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L499
+	return getPhysicalCoreCount()
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common.go
new file mode 100644
index 000000000..dce15b3b4
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common.go
@@ -0,0 +1,475 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+//
+// gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
+// This covers these architectures.
+//  - linux (amd64, arm)
+//  - freebsd (amd64)
+//  - windows (amd64)
+//  - aix (ppc64)
+
+import (
+	"bufio"
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"math"
+	"net/url"
+	"os"
+	"os/exec"
+	"path"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"slices"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/shirou/gopsutil/v4/common"
+)
+
+var (
+	Timeout                = 3 * time.Second
+	ErrNotImplementedError = errors.New("not implemented yet")
+	ErrTimeout             = errors.New("command timed out")
+)
+
+type Invoker interface {
+	Command(string, ...string) ([]byte, error)
+	CommandWithContext(context.Context, string, ...string) ([]byte, error)
+}
+
+type Invoke struct{}
+
+func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), Timeout)
+	defer cancel()
+	return i.CommandWithContext(ctx, name, arg...)
+}
+
+func (Invoke) CommandWithContext(ctx context.Context, name string, arg ...string) ([]byte, error) {
+	cmd := exec.CommandContext(ctx, name, arg...)
+
+	var buf bytes.Buffer
+	cmd.Stdout = &buf
+	cmd.Stderr = &buf
+
+	if err := cmd.Start(); err != nil {
+		return buf.Bytes(), err
+	}
+
+	if err := cmd.Wait(); err != nil {
+		return buf.Bytes(), err
+	}
+
+	return buf.Bytes(), nil
+}
+
+type FakeInvoke struct {
+	Suffix string // Suffix species expected file name suffix such as "fail"
+	Error  error  // If Error specified, return the error.
+}
+
+// Command in FakeInvoke returns from expected file if exists.
+func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
+	if i.Error != nil {
+		return []byte{}, i.Error
+	}
+
+	arch := runtime.GOOS
+
+	commandName := filepath.Base(name)
+
+	fname := strings.Join(append([]string{commandName}, arg...), "")
+	fname = url.QueryEscape(fname)
+	fpath := path.Join("testdata", arch, fname)
+	if i.Suffix != "" {
+		fpath += "_" + i.Suffix
+	}
+	if PathExists(fpath) {
+		return os.ReadFile(fpath)
+	}
+	return []byte{}, fmt.Errorf("could not find testdata: %s", fpath)
+}
+
+func (i FakeInvoke) CommandWithContext(_ context.Context, name string, arg ...string) ([]byte, error) {
+	return i.Command(name, arg...)
+}
+
+// ReadFile reads contents from a file
+func ReadFile(filename string) (string, error) {
+	content, err := os.ReadFile(filename)
+	if err != nil {
+		return "", err
+	}
+
+	return string(content), nil
+}
+
+// ReadLines reads contents from a file and splits them by new lines.
+// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
+func ReadLines(filename string) ([]string, error) {
+	return ReadLinesOffsetN(filename, 0, -1)
+}
+
+// ReadLine reads a file and returns the first occurrence of a line that is prefixed with prefix.
+func ReadLine(filename, prefix string) (string, error) {
+	f, err := os.Open(filename)
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+	r := bufio.NewReader(f)
+	for {
+		line, err := r.ReadString('\n')
+		if err != nil {
+			if err == io.EOF {
+				break
+			}
+			return "", err
+		}
+		if strings.HasPrefix(line, prefix) {
+			return line, nil
+		}
+	}
+
+	return "", nil
+}
+
+// ReadLinesOffsetN reads contents from file and splits them by new line.
+// The offset tells at which line number to start.
+// The count determines the number of lines to read (starting from offset):
+// n >= 0: at most n lines
+// n < 0: whole file
+func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
+	f, err := os.Open(filename)
+	if err != nil {
+		return []string{""}, err
+	}
+	defer f.Close()
+
+	var ret []string
+
+	r := bufio.NewReader(f)
+	for i := uint(0); i < uint(n)+offset || n < 0; i++ {
+		line, err := r.ReadString('\n')
+		if err != nil {
+			if err == io.EOF && line != "" {
+				ret = append(ret, strings.Trim(line, "\n"))
+			}
+			break
+		}
+		if i < offset {
+			continue
+		}
+		ret = append(ret, strings.Trim(line, "\n"))
+	}
+
+	return ret, nil
+}
+
+func IntToString(orig []int8) string {
+	ret := make([]byte, len(orig))
+	size := -1
+	for i, o := range orig {
+		if o == 0 {
+			size = i
+			break
+		}
+		ret[i] = byte(o)
+	}
+	if size == -1 {
+		size = len(orig)
+	}
+
+	return string(ret[0:size])
+}
+
+func UintToString(orig []uint8) string {
+	ret := make([]byte, len(orig))
+	size := -1
+	for i, o := range orig {
+		if o == 0 {
+			size = i
+			break
+		}
+		ret[i] = byte(o)
+	}
+	if size == -1 {
+		size = len(orig)
+	}
+
+	return string(ret[0:size])
+}
+
+func ByteToString(orig []byte) string {
+	n := -1
+	l := -1
+	for i, b := range orig {
+		// skip left side null
+		if l == -1 && b == 0 {
+			continue
+		}
+		if l == -1 {
+			l = i
+		}
+
+		if b == 0 {
+			break
+		}
+		n = i + 1
+	}
+	if n == -1 {
+		return string(orig)
+	}
+	return string(orig[l:n])
+}
+
+// ReadInts reads contents from single line file and returns them as []int32.
+func ReadInts(filename string) ([]int64, error) {
+	f, err := os.Open(filename)
+	if err != nil {
+		return []int64{}, err
+	}
+	defer f.Close()
+
+	var ret []int64
+
+	r := bufio.NewReader(f)
+
+	// The int files that this is concerned with should only be one liners.
+	line, err := r.ReadString('\n')
+	if err != nil {
+		return []int64{}, err
+	}
+
+	i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32)
+	if err != nil {
+		return []int64{}, err
+	}
+	ret = append(ret, i)
+
+	return ret, nil
+}
+
+// Parse Hex to uint32 without error
+func HexToUint32(hex string) uint32 {
+	vv, _ := strconv.ParseUint(hex, 16, 32)
+	return uint32(vv)
+}
+
+// Parse to int32 without error
+func mustParseInt32(val string) int32 {
+	vv, _ := strconv.ParseInt(val, 10, 32)
+	return int32(vv)
+}
+
+// Parse to uint64 without error
+func mustParseUint64(val string) uint64 {
+	vv, _ := strconv.ParseInt(val, 10, 64)
+	return uint64(vv)
+}
+
+// Parse to Float64 without error
+func mustParseFloat64(val string) float64 {
+	vv, _ := strconv.ParseFloat(val, 64)
+	return vv
+}
+
+// StringsHas checks the target string slice contains src or not
+func StringsHas(target []string, src string) bool {
+	for _, t := range target {
+		if strings.TrimSpace(t) == src {
+			return true
+		}
+	}
+	return false
+}
+
+// StringsContains checks the src in any string of the target string slice
+func StringsContains(target []string, src string) bool {
+	return slices.ContainsFunc(target, func(s string) bool {
+		return strings.Contains(s, src)
+	})
+}
+
+// IntContains checks the src in any int of the target int slice.
+func IntContains(target []int, src int) bool {
+	return slices.Contains(target, src)
+}
+
+// get struct attributes.
+// This method is used only for debugging platform dependent code.
+func attributes(m any) map[string]reflect.Type {
+	typ := reflect.TypeOf(m)
+	if typ.Kind() == reflect.Ptr {
+		typ = typ.Elem()
+	}
+
+	attrs := make(map[string]reflect.Type)
+	if typ.Kind() != reflect.Struct {
+		return nil
+	}
+
+	for i := 0; i < typ.NumField(); i++ {
+		p := typ.Field(i)
+		if !p.Anonymous {
+			attrs[p.Name] = p.Type
+		}
+	}
+
+	return attrs
+}
+
+func PathExists(filename string) bool {
+	if _, err := os.Stat(filename); err == nil {
+		return true
+	}
+	return false
+}
+
+// PathExistsWithContents returns the filename exists and it is not empty
+func PathExistsWithContents(filename string) bool {
+	info, err := os.Stat(filename)
+	if err != nil {
+		return false
+	}
+	return info.Size() > 4 && !info.IsDir() // at least 4 bytes
+}
+
+// GetEnvWithContext retrieves the environment variable key. If it does not exist it returns the default.
+// The context may optionally contain a map superseding os.EnvKey.
+func GetEnvWithContext(ctx context.Context, key, dfault string, combineWith ...string) string {
+	var value string
+	if env, ok := ctx.Value(common.EnvKey).(common.EnvMap); ok {
+		value = env[common.EnvKeyType(key)]
+	}
+	if value == "" {
+		value = os.Getenv(key)
+	}
+	if value == "" {
+		value = dfault
+	}
+
+	return combine(value, combineWith)
+}
+
+// GetEnv retrieves the environment variable key. If it does not exist it returns the default.
+func GetEnv(key, dfault string, combineWith ...string) string {
+	value := os.Getenv(key)
+	if value == "" {
+		value = dfault
+	}
+
+	return combine(value, combineWith)
+}
+
+func combine(value string, combineWith []string) string {
+	switch len(combineWith) {
+	case 0:
+		return value
+	case 1:
+		return filepath.Join(value, combineWith[0])
+	default:
+		all := make([]string, len(combineWith)+1)
+		all[0] = value
+		copy(all[1:], combineWith)
+		return filepath.Join(all...)
+	}
+}
+
+func HostProc(combineWith ...string) string {
+	return GetEnv("HOST_PROC", "/proc", combineWith...)
+}
+
+func HostSys(combineWith ...string) string {
+	return GetEnv("HOST_SYS", "/sys", combineWith...)
+}
+
+func HostEtc(combineWith ...string) string {
+	return GetEnv("HOST_ETC", "/etc", combineWith...)
+}
+
+func HostVar(combineWith ...string) string {
+	return GetEnv("HOST_VAR", "/var", combineWith...)
+}
+
+func HostRun(combineWith ...string) string {
+	return GetEnv("HOST_RUN", "/run", combineWith...)
+}
+
+func HostDev(combineWith ...string) string {
+	return GetEnv("HOST_DEV", "/dev", combineWith...)
+}
+
+func HostRoot(combineWith ...string) string {
+	return GetEnv("HOST_ROOT", "/", combineWith...)
+}
+
+func HostProcWithContext(ctx context.Context, combineWith ...string) string {
+	return GetEnvWithContext(ctx, "HOST_PROC", "/proc", combineWith...)
+}
+
+func HostProcMountInfoWithContext(ctx context.Context, combineWith ...string) string {
+	return GetEnvWithContext(ctx, "HOST_PROC_MOUNTINFO", "", combineWith...)
+}
+
+func HostSysWithContext(ctx context.Context, combineWith ...string) string {
+	return GetEnvWithContext(ctx, "HOST_SYS", "/sys", combineWith...)
+}
+
+func HostEtcWithContext(ctx context.Context, combineWith ...string) string {
+	return GetEnvWithContext(ctx, "HOST_ETC", "/etc", combineWith...)
+}
+
+func HostVarWithContext(ctx context.Context, combineWith ...string) string {
+	return GetEnvWithContext(ctx, "HOST_VAR", "/var", combineWith...)
+}
+
+func HostRunWithContext(ctx context.Context, combineWith ...string) string {
+	return GetEnvWithContext(ctx, "HOST_RUN", "/run", combineWith...)
+}
+
+func HostDevWithContext(ctx context.Context, combineWith ...string) string {
+	return GetEnvWithContext(ctx, "HOST_DEV", "/dev", combineWith...)
+}
+
+func HostRootWithContext(ctx context.Context, combineWith ...string) string {
+	return GetEnvWithContext(ctx, "HOST_ROOT", "/", combineWith...)
+}
+
+// getSysctrlEnv sets LC_ALL=C in a list of env vars for use when running
+// sysctl commands.
+func getSysctrlEnv(env []string) []string {
+	foundLC := false
+	for i, line := range env {
+		if strings.HasPrefix(line, "LC_ALL") {
+			env[i] = "LC_ALL=C"
+			foundLC = true
+		}
+	}
+	if !foundLC {
+		env = append(env, "LC_ALL=C")
+	}
+	return env
+}
+
+// Round places rounds the number 'val' to 'n' decimal places
+func Round(val float64, n int) float64 {
+	// Calculate the power of 10 to the n
+	pow10 := math.Pow(10, float64(n))
+	// Multiply the value by pow10, round it, then divide it by pow10
+	return math.Round(val*pow10) / pow10
+}
+
+func TimeSince(ts uint64) uint64 {
+	return uint64(time.Now().Unix()) - ts
+}
+
+func TimeSinceMillis(ts uint64) uint64 {
+	return uint64(time.Now().UnixMilli()) - ts
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_aix.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_aix.go
new file mode 100644
index 000000000..5579c3bcc
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_aix.go
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix
+
+package common
+
+import (
+	"context"
+	"errors"
+	"strconv"
+	"strings"
+)
+
+func BootTimeWithContext(ctx context.Context, invoke Invoker) (btime uint64, err error) {
+	ut, err := UptimeWithContext(ctx, invoke)
+	if err != nil {
+		return 0, err
+	}
+
+	if ut <= 0 {
+		return 0, errors.New("uptime was not set, so cannot calculate boot time from it")
+	}
+
+	return TimeSince(ut), nil
+}
+
+// Uses ps to get the elapsed time for PID 1 in DAYS-HOURS:MINUTES:SECONDS format.
+// Examples of ps -o etimes -p 1 output:
+// 124-01:40:39 (with days)
+// 15:03:02 (without days, hours only)
+// 01:02 (just-rebooted systems, minutes and seconds)
+func UptimeWithContext(ctx context.Context, invoke Invoker) (uint64, error) {
+	out, err := invoke.CommandWithContext(ctx, "ps", "-o", "etimes", "-p", "1")
+	if err != nil {
+		return 0, err
+	}
+
+	lines := strings.Split(strings.TrimSpace(string(out)), "\n")
+	if len(lines) < 2 {
+		return 0, errors.New("ps output has fewer than 2 rows")
+	}
+
+	// Extract the etimes value from the second row, trimming whitespace
+	etimes := strings.TrimSpace(lines[1])
+	return ParseUptime(etimes), nil
+}
+
+// Parses etimes output from ps command into total seconds.
+// Handles formats like:
+// - "124-01:40:39" (DAYS-HOURS:MINUTES:SECONDS)
+// - "15:03:02" (HOURS:MINUTES:SECONDS)
+// - "01:02" (MINUTES:SECONDS, from just-rebooted systems)
+func ParseUptime(etimes string) uint64 {
+	var days, hours, mins, secs uint64
+
+	// Check if days component is present (contains a dash)
+	if strings.Contains(etimes, "-") {
+		parts := strings.Split(etimes, "-")
+		if len(parts) != 2 {
+			return 0
+		}
+
+		var err error
+		days, err = strconv.ParseUint(parts[0], 10, 64)
+		if err != nil {
+			return 0
+		}
+
+		// Parse the HH:MM:SS portion (after days, must have 3 parts)
+		etimes = parts[1]
+		timeParts := strings.Split(etimes, ":")
+		if len(timeParts) != 3 {
+			return 0
+		}
+
+		var err2 error
+		hours, err2 = strconv.ParseUint(timeParts[0], 10, 64)
+		if err2 != nil {
+			return 0
+		}
+
+		mins, err2 = strconv.ParseUint(timeParts[1], 10, 64)
+		if err2 != nil {
+			return 0
+		}
+
+		secs, err2 = strconv.ParseUint(timeParts[2], 10, 64)
+		if err2 != nil {
+			return 0
+		}
+	} else {
+		// Parse time portions (either HH:MM:SS or MM:SS) when no days present
+		timeParts := strings.Split(etimes, ":")
+		switch len(timeParts) {
+		case 3:
+			// HH:MM:SS format
+			var err error
+			hours, err = strconv.ParseUint(timeParts[0], 10, 64)
+			if err != nil {
+				return 0
+			}
+
+			mins, err = strconv.ParseUint(timeParts[1], 10, 64)
+			if err != nil {
+				return 0
+			}
+
+			secs, err = strconv.ParseUint(timeParts[2], 10, 64)
+			if err != nil {
+				return 0
+			}
+		case 2:
+			// MM:SS format (just-rebooted systems)
+			var err error
+			mins, err = strconv.ParseUint(timeParts[0], 10, 64)
+			if err != nil {
+				return 0
+			}
+
+			secs, err = strconv.ParseUint(timeParts[1], 10, 64)
+			if err != nil {
+				return 0
+			}
+		default:
+			return 0
+		}
+	}
+
+	// Convert to total seconds
+	totalSeconds := (days * 24 * 60 * 60) + (hours * 60 * 60) + (mins * 60) + secs
+	return totalSeconds
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go
new file mode 100644
index 000000000..caa1b8d98
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_darwin.go
@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package common
+
+import (
+	"errors"
+	"fmt"
+	"math"
+	"sync"
+	"unsafe"
+
+	"github.com/ebitengine/purego"
+)
+
+// Library represents a dynamic library loaded by purego.
+type library struct {
+	handle uintptr
+	fnMap  map[string]any
+	mu     sync.RWMutex
+}
+
+// library paths
+const (
+	IOKitLibPath          = "/System/Library/Frameworks/IOKit.framework/IOKit"
+	CoreFoundationLibPath = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"
+	SystemLibPath         = "/usr/lib/libSystem.B.dylib"
+)
+
+func newLibrary(path string) (*library, error) {
+	lib, err := purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL)
+	if err != nil {
+		return nil, err
+	}
+
+	return &library{
+		handle: lib,
+		fnMap:  make(map[string]any),
+	}, nil
+}
+
+func (lib *library) Dlsym(symbol string) (uintptr, error) {
+	return purego.Dlsym(lib.handle, symbol)
+}
+
+// getFunc resolves a function pointer from the library, caching it in fnMap.
+// Thread-safe via double-checked locking to support shared library handles.
+func getFunc[T any](lib *library, symbol string) T {
+	// Fast path: read lock only
+	lib.mu.RLock()
+	if f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok {
+		lib.mu.RUnlock()
+		return f.fn
+	}
+	lib.mu.RUnlock()
+
+	// Slow path: write lock for first-time resolution
+	lib.mu.Lock()
+	defer lib.mu.Unlock()
+
+	// Double-check after acquiring write lock
+	if f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok {
+		return f.fn
+	}
+
+	dlfun := newDlfunc[T](symbol)
+	dlfun.init(lib.handle)
+	lib.fnMap[symbol] = dlfun
+	return dlfun.fn
+}
+
+func (lib *library) Close() {
+	purego.Dlclose(lib.handle)
+}
+
+type dlFunc[T any] struct {
+	sym string
+	fn  T
+}
+
+func (d *dlFunc[T]) init(handle uintptr) {
+	purego.RegisterLibFunc(&d.fn, handle, d.sym)
+}
+
+func newDlfunc[T any](sym string) *dlFunc[T] {
+	return &dlFunc[T]{sym: sym}
+}
+
+type CoreFoundationLib struct {
+	*library
+}
+
+func NewCoreFoundationLib() (*CoreFoundationLib, error) {
+	library, err := newLibrary(CoreFoundationLibPath)
+	if err != nil {
+		return nil, err
+	}
+	return &CoreFoundationLib{library}, nil
+}
+
+func (c *CoreFoundationLib) CFGetTypeID(cf uintptr) int64 {
+	fn := getFunc[CFGetTypeIDFunc](c.library, "CFGetTypeID")
+	return fn(cf)
+}
+
+func (c *CoreFoundationLib) CFNumberCreate(allocator uintptr, theType int64, valuePtr uintptr) unsafe.Pointer {
+	fn := getFunc[CFNumberCreateFunc](c.library, "CFNumberCreate")
+	return fn(allocator, theType, valuePtr)
+}
+
+func (c *CoreFoundationLib) CFNumberGetValue(num uintptr, theType int64, valuePtr uintptr) bool {
+	fn := getFunc[CFNumberGetValueFunc](c.library, "CFNumberGetValue")
+	return fn(num, theType, valuePtr)
+}
+
+func (c *CoreFoundationLib) CFDictionaryCreate(allocator uintptr, keys, values *unsafe.Pointer, numValues int64,
+	keyCallBacks, valueCallBacks uintptr,
+) unsafe.Pointer {
+	fn := getFunc[CFDictionaryCreateFunc](c.library, "CFDictionaryCreate")
+	return fn(allocator, keys, values, numValues, keyCallBacks, valueCallBacks)
+}
+
+func (c *CoreFoundationLib) CFDictionaryAddValue(theDict, key, value uintptr) {
+	fn := getFunc[CFDictionaryAddValueFunc](c.library, "CFDictionaryAddValue")
+	fn(theDict, key, value)
+}
+
+func (c *CoreFoundationLib) CFDictionaryGetValue(theDict, key uintptr) unsafe.Pointer {
+	fn := getFunc[CFDictionaryGetValueFunc](c.library, "CFDictionaryGetValue")
+	return fn(theDict, key)
+}
+
+func (c *CoreFoundationLib) CFArrayGetCount(theArray uintptr) int64 {
+	fn := getFunc[CFArrayGetCountFunc](c.library, "CFArrayGetCount")
+	return fn(theArray)
+}
+
+func (c *CoreFoundationLib) CFArrayGetValueAtIndex(theArray uintptr, index int64) unsafe.Pointer {
+	fn := getFunc[CFArrayGetValueAtIndexFunc](c.library, "CFArrayGetValueAtIndex")
+	return fn(theArray, index)
+}
+
+func (c *CoreFoundationLib) CFStringCreateMutable(alloc uintptr, maxLength int64) unsafe.Pointer {
+	fn := getFunc[CFStringCreateMutableFunc](c.library, "CFStringCreateMutable")
+	return fn(alloc, maxLength)
+}
+
+func (c *CoreFoundationLib) CFStringGetLength(theString uintptr) int64 {
+	fn := getFunc[CFStringGetLengthFunc](c.library, "CFStringGetLength")
+	return fn(theString)
+}
+
+func (c *CoreFoundationLib) CFStringGetCString(theString uintptr, buffer CStr, bufferSize int64, encoding uint32) {
+	fn := getFunc[CFStringGetCStringFunc](c.library, "CFStringGetCString")
+	fn(theString, buffer, bufferSize, encoding)
+}
+
+func (c *CoreFoundationLib) CFStringCreateWithCString(alloc uintptr, cStr string, encoding uint32) unsafe.Pointer {
+	fn := getFunc[CFStringCreateWithCStringFunc](c.library, "CFStringCreateWithCString")
+	return fn(alloc, cStr, encoding)
+}
+
+func (c *CoreFoundationLib) CFDataGetLength(theData uintptr) int64 {
+	fn := getFunc[CFDataGetLengthFunc](c.library, "CFDataGetLength")
+	return fn(theData)
+}
+
+func (c *CoreFoundationLib) CFDataGetBytePtr(theData uintptr) unsafe.Pointer {
+	fn := getFunc[CFDataGetBytePtrFunc](c.library, "CFDataGetBytePtr")
+	return fn(theData)
+}
+
+func (c *CoreFoundationLib) CFRelease(cf uintptr) {
+	fn := getFunc[CFReleaseFunc](c.library, "CFRelease")
+	fn(cf)
+}
+
+type IOKitLib struct {
+	*library
+}
+
+func NewIOKitLib() (*IOKitLib, error) {
+	library, err := newLibrary(IOKitLibPath)
+	if err != nil {
+		return nil, err
+	}
+	return &IOKitLib{library}, nil
+}
+
+func (l *IOKitLib) IOServiceGetMatchingService(mainPort uint32, matching uintptr) uint32 {
+	fn := getFunc[IOServiceGetMatchingServiceFunc](l.library, "IOServiceGetMatchingService")
+	return fn(mainPort, matching)
+}
+
+func (l *IOKitLib) IOServiceGetMatchingServices(mainPort uint32, matching uintptr, existing *uint32) int32 {
+	fn := getFunc[IOServiceGetMatchingServicesFunc](l.library, "IOServiceGetMatchingServices")
+	return fn(mainPort, matching, existing)
+}
+
+func (l *IOKitLib) IOServiceMatching(name string) unsafe.Pointer {
+	fn := getFunc[IOServiceMatchingFunc](l.library, "IOServiceMatching")
+	return fn(name)
+}
+
+func (l *IOKitLib) IOServiceOpen(service, owningTask, connType uint32, connect *uint32) int32 {
+	fn := getFunc[IOServiceOpenFunc](l.library, "IOServiceOpen")
+	return fn(service, owningTask, connType, connect)
+}
+
+func (l *IOKitLib) IOServiceClose(connect uint32) int32 {
+	fn := getFunc[IOServiceCloseFunc](l.library, "IOServiceClose")
+	return fn(connect)
+}
+
+func (l *IOKitLib) IOIteratorNext(iterator uint32) uint32 {
+	fn := getFunc[IOIteratorNextFunc](l.library, "IOIteratorNext")
+	return fn(iterator)
+}
+
+func (l *IOKitLib) IORegistryEntryGetName(entry uint32, name CStr) int32 {
+	fn := getFunc[IORegistryEntryGetNameFunc](l.library, "IORegistryEntryGetName")
+	return fn(entry, name)
+}
+
+func (l *IOKitLib) IORegistryEntryGetParentEntry(entry uint32, plane string, parent *uint32) int32 {
+	fn := getFunc[IORegistryEntryGetParentEntryFunc](l.library, "IORegistryEntryGetParentEntry")
+	return fn(entry, plane, parent)
+}
+
+func (l *IOKitLib) IORegistryEntryCreateCFProperty(entry uint32, key, allocator uintptr, options uint32) unsafe.Pointer {
+	fn := getFunc[IORegistryEntryCreateCFPropertyFunc](l.library, "IORegistryEntryCreateCFProperty")
+	return fn(entry, key, allocator, options)
+}
+
+func (l *IOKitLib) IORegistryEntryCreateCFProperties(entry uint32, properties unsafe.Pointer, allocator uintptr, options uint32) int32 {
+	fn := getFunc[IORegistryEntryCreateCFPropertiesFunc](l.library, "IORegistryEntryCreateCFProperties")
+	return fn(entry, properties, allocator, options)
+}
+
+func (l *IOKitLib) IOObjectConformsTo(object uint32, className string) bool {
+	fn := getFunc[IOObjectConformsToFunc](l.library, "IOObjectConformsTo")
+	return fn(object, className)
+}
+
+func (l *IOKitLib) IOObjectRelease(object uint32) int32 {
+	fn := getFunc[IOObjectReleaseFunc](l.library, "IOObjectRelease")
+	return fn(object)
+}
+
+func (l *IOKitLib) IOConnectCallStructMethod(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int32 {
+	fn := getFunc[IOConnectCallStructMethodFunc](l.library, "IOConnectCallStructMethod")
+	return fn(connection, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt)
+}
+
+func (l *IOKitLib) IOHIDEventSystemClientCreate(allocator uintptr) unsafe.Pointer {
+	fn := getFunc[IOHIDEventSystemClientCreateFunc](l.library, "IOHIDEventSystemClientCreate")
+	return fn(allocator)
+}
+
+func (l *IOKitLib) IOHIDEventSystemClientSetMatching(client, match uintptr) int32 {
+	fn := getFunc[IOHIDEventSystemClientSetMatchingFunc](l.library, "IOHIDEventSystemClientSetMatching")
+	return fn(client, match)
+}
+
+func (l *IOKitLib) IOHIDServiceClientCopyEvent(service uintptr, eventType int64, options int32, timeout int64) unsafe.Pointer {
+	fn := getFunc[IOHIDServiceClientCopyEventFunc](l.library, "IOHIDServiceClientCopyEvent")
+	return fn(service, eventType, options, timeout)
+}
+
+func (l *IOKitLib) IOHIDServiceClientCopyProperty(service, property uintptr) unsafe.Pointer {
+	fn := getFunc[IOHIDServiceClientCopyPropertyFunc](l.library, "IOHIDServiceClientCopyProperty")
+	return fn(service, property)
+}
+
+func (l *IOKitLib) IOHIDEventGetFloatValue(event uintptr, field int32) float64 {
+	fn := getFunc[IOHIDEventGetFloatValueFunc](l.library, "IOHIDEventGetFloatValue")
+	return fn(event, field)
+}
+
+func (l *IOKitLib) IOHIDEventSystemClientCopyServices(client uintptr) unsafe.Pointer {
+	fn := getFunc[IOHIDEventSystemClientCopyServicesFunc](l.library, "IOHIDEventSystemClientCopyServices")
+	return fn(client)
+}
+
+type SystemLib struct {
+	*library
+}
+
+func NewSystemLib() (*SystemLib, error) {
+	library, err := newLibrary(SystemLibPath)
+	if err != nil {
+		return nil, err
+	}
+	return &SystemLib{library}, nil
+}
+
+func (s *SystemLib) HostProcessorInfo(host uint32, flavor int32, outProcessorCount *uint32, outProcessorInfo uintptr,
+	outProcessorInfoCnt *uint32,
+) int32 {
+	fn := getFunc[HostProcessorInfoFunc](s.library, "host_processor_info")
+	return fn(host, flavor, outProcessorCount, outProcessorInfo, outProcessorInfoCnt)
+}
+
+func (s *SystemLib) HostStatistics(host uint32, flavor int32, hostInfoOut uintptr, hostInfoOutCnt *uint32) int32 {
+	fn := getFunc[HostStatisticsFunc](s.library, "host_statistics")
+	return fn(host, flavor, hostInfoOut, hostInfoOutCnt)
+}
+
+func (s *SystemLib) MachHostSelf() uint32 {
+	fn := getFunc[MachHostSelfFunc](s.library, "mach_host_self")
+	return fn()
+}
+
+func (s *SystemLib) MachTaskSelf() uint32 {
+	fn := getFunc[MachTaskSelfFunc](s.library, "mach_task_self")
+	return fn()
+}
+
+func (s *SystemLib) MachTimeBaseInfo(info uintptr) int32 {
+	fn := getFunc[MachTimeBaseInfoFunc](s.library, "mach_timebase_info")
+	return fn(info)
+}
+
+func (s *SystemLib) VMDeallocate(targetTask uint32, vmAddress, vmSize uintptr) int32 {
+	fn := getFunc[VMDeallocateFunc](s.library, "vm_deallocate")
+	return fn(targetTask, vmAddress, vmSize)
+}
+
+func (s *SystemLib) ProcPidPath(pid int32, buffer uintptr, bufferSize uint32) int32 {
+	fn := getFunc[ProcPidPathFunc](s.library, "proc_pidpath")
+	return fn(pid, buffer, bufferSize)
+}
+
+func (s *SystemLib) ProcPidInfo(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32 {
+	fn := getFunc[ProcPidInfoFunc](s.library, "proc_pidinfo")
+	return fn(pid, flavor, arg, buffer, bufferSize)
+}
+
+// status codes
+const (
+	KERN_SUCCESS = 0
+)
+
+// IOKit types and constants.
+type (
+	IOServiceGetMatchingServiceFunc       func(mainPort uint32, matching uintptr) uint32
+	IOServiceGetMatchingServicesFunc      func(mainPort uint32, matching uintptr, existing *uint32) int32
+	IOServiceMatchingFunc                 func(name string) unsafe.Pointer
+	IOServiceOpenFunc                     func(service, owningTask, connType uint32, connect *uint32) int32
+	IOServiceCloseFunc                    func(connect uint32) int32
+	IOIteratorNextFunc                    func(iterator uint32) uint32
+	IORegistryEntryGetNameFunc            func(entry uint32, name CStr) int32
+	IORegistryEntryGetParentEntryFunc     func(entry uint32, plane string, parent *uint32) int32
+	IORegistryEntryCreateCFPropertyFunc   func(entry uint32, key, allocator uintptr, options uint32) unsafe.Pointer
+	IORegistryEntryCreateCFPropertiesFunc func(entry uint32, properties unsafe.Pointer, allocator uintptr, options uint32) int32
+	IOObjectConformsToFunc                func(object uint32, className string) bool
+	IOObjectReleaseFunc                   func(object uint32) int32
+	IOConnectCallStructMethodFunc         func(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int32
+
+	IOHIDEventSystemClientCreateFunc      func(allocator uintptr) unsafe.Pointer
+	IOHIDEventSystemClientSetMatchingFunc func(client, match uintptr) int32
+	IOHIDServiceClientCopyEventFunc       func(service uintptr, eventType int64,
+		options int32, timeout int64) unsafe.Pointer
+	IOHIDServiceClientCopyPropertyFunc     func(service, property uintptr) unsafe.Pointer
+	IOHIDEventGetFloatValueFunc            func(event uintptr, field int32) float64
+	IOHIDEventSystemClientCopyServicesFunc func(client uintptr) unsafe.Pointer
+)
+
+const (
+	KIOMainPortDefault = 0
+
+	KIOHIDEventTypeTemperature = 15
+
+	KNilOptions = 0
+)
+
+const (
+	KIOMediaWholeKey = "Media"
+	KIOServicePlane  = "IOService"
+)
+
+// CoreFoundation types and constants.
+type (
+	CFGetTypeIDFunc        func(cf uintptr) int64
+	CFNumberCreateFunc     func(allocator uintptr, theType int64, valuePtr uintptr) unsafe.Pointer
+	CFNumberGetValueFunc   func(num uintptr, theType int64, valuePtr uintptr) bool
+	CFDictionaryCreateFunc func(allocator uintptr, keys, values *unsafe.Pointer, numValues int64,
+		keyCallBacks, valueCallBacks uintptr) unsafe.Pointer
+	CFDictionaryAddValueFunc      func(theDict, key, value uintptr)
+	CFDictionaryGetValueFunc      func(theDict, key uintptr) unsafe.Pointer
+	CFArrayGetCountFunc           func(theArray uintptr) int64
+	CFArrayGetValueAtIndexFunc    func(theArray uintptr, index int64) unsafe.Pointer
+	CFStringCreateMutableFunc     func(alloc uintptr, maxLength int64) unsafe.Pointer
+	CFStringGetLengthFunc         func(theString uintptr) int64
+	CFStringGetCStringFunc        func(theString uintptr, buffer CStr, bufferSize int64, encoding uint32)
+	CFStringCreateWithCStringFunc func(alloc uintptr, cStr string, encoding uint32) unsafe.Pointer
+	CFDataGetLengthFunc           func(theData uintptr) int64
+	CFDataGetBytePtrFunc          func(theData uintptr) unsafe.Pointer
+	CFReleaseFunc                 func(cf uintptr)
+)
+
+const (
+	KCFStringEncodingUTF8 = 0x08000100
+	KCFNumberSInt64Type   = 4
+	KCFNumberIntType      = 9
+	KCFAllocatorDefault   = 0
+	KCFNotFound           = -1
+)
+
+// libSystem types and constants.
+type MachTimeBaseInfo struct {
+	Numer uint32
+	Denom uint32
+}
+
+type (
+	HostProcessorInfoFunc func(host uint32, flavor int32, outProcessorCount *uint32, outProcessorInfo uintptr,
+		outProcessorInfoCnt *uint32) int32
+	HostStatisticsFunc   func(host uint32, flavor int32, hostInfoOut uintptr, hostInfoOutCnt *uint32) int32
+	MachHostSelfFunc     func() uint32
+	MachTaskSelfFunc     func() uint32
+	MachTimeBaseInfoFunc func(info uintptr) int32
+	VMDeallocateFunc     func(targetTask uint32, vmAddress, vmSize uintptr) int32
+)
+
+const (
+	HostProcessorInfoSym = "host_processor_info"
+	HostStatisticsSym    = "host_statistics"
+	MachHostSelfSym      = "mach_host_self"
+	MachTaskSelfSym      = "mach_task_self"
+	MachTimeBaseInfoSym  = "mach_timebase_info"
+	VMDeallocateSym      = "vm_deallocate"
+)
+
+const (
+	HOST_VM_INFO       = 2
+	HOST_CPU_LOAD_INFO = 3
+
+	HOST_VM_INFO_COUNT = 0xf
+)
+
+type (
+	ProcPidPathFunc func(pid int32, buffer uintptr, bufferSize uint32) int32
+	ProcPidInfoFunc func(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32
+)
+
+const (
+	SysctlSym      = "sysctl"
+	ProcPidPathSym = "proc_pidpath"
+	ProcPidInfoSym = "proc_pidinfo"
+)
+
+const (
+	MAXPATHLEN               = 1024
+	PROC_PIDLISTFDS          = 1
+	PROC_PIDPATHINFO_MAXSIZE = 4 * MAXPATHLEN
+	PROC_PIDTASKINFO         = 4
+	PROC_PIDVNODEPATHINFO    = 9
+)
+
+// SMC represents a SMC instance.
+type SMC struct {
+	lib  *IOKitLib
+	conn uint32
+}
+
+const ioServiceSMC = "AppleSMC"
+
+const (
+	KSMCUserClientOpen  = 0
+	KSMCUserClientClose = 1
+	KSMCHandleYPCEvent  = 2
+	KSMCReadKey         = 5
+	KSMCWriteKey        = 6
+	KSMCGetKeyCount     = 7
+	KSMCGetKeyFromIndex = 8
+	KSMCGetKeyInfo      = 9
+)
+
+const (
+	KSMCSuccess     = 0
+	KSMCError       = 1
+	KSMCKeyNotFound = 132
+)
+
+func NewSMC() (*SMC, error) {
+	iokit, err := NewIOKitLib()
+	if err != nil {
+		return nil, err
+	}
+
+	service := iokit.IOServiceGetMatchingService(0, uintptr(iokit.IOServiceMatching(ioServiceSMC)))
+	if service == 0 {
+		return nil, fmt.Errorf("ERROR: %s NOT FOUND", ioServiceSMC)
+	}
+
+	var conn uint32
+	machTaskSelf := getFunc[MachTaskSelfFunc](iokit.library, "mach_task_self")
+	if result := iokit.IOServiceOpen(service, machTaskSelf(), 0, &conn); result != 0 {
+		return nil, errors.New("ERROR: IOServiceOpen failed")
+	}
+
+	iokit.IOObjectRelease(service)
+	return &SMC{
+		lib:  iokit,
+		conn: conn,
+	}, nil
+}
+
+func (s *SMC) CallStruct(selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int32 {
+	return s.lib.IOConnectCallStructMethod(s.conn, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt)
+}
+
+func (s *SMC) Close() error {
+	if result := s.lib.IOServiceClose(s.conn); result != 0 {
+		return errors.New("ERROR: IOServiceClose failed")
+	}
+	s.lib.Close()
+	return nil
+}
+
+type CStr []byte
+
+func NewCStr(length int64) CStr {
+	return make(CStr, length)
+}
+
+func (s CStr) Length() int64 {
+	return int64(len(s))
+}
+
+func (s CStr) Ptr() *byte {
+	if len(s) < 1 {
+		return nil
+	}
+
+	return &s[0]
+}
+
+func (s CStr) Addr() uintptr {
+	return uintptr(unsafe.Pointer(s.Ptr()))
+}
+
+func (s CStr) GoString() string {
+	if s == nil {
+		return ""
+	}
+
+	var length int
+	for _, char := range s {
+		if char == '\x00' {
+			break
+		}
+		length++
+	}
+	return string(s[:length])
+}
+
+// https://github.com/ebitengine/purego/blob/main/internal/strings/strings.go#L26
+func GoString(cStr *byte) string {
+	if cStr == nil {
+		return ""
+	}
+	var length int
+	for *(*byte)(unsafe.Add(unsafe.Pointer(cStr), uintptr(length))) != '\x00' {
+		length++
+	}
+	return string(unsafe.Slice(cStr, length))
+}
+
+// https://github.com/apple-oss-distributions/CF/blob/dc54c6bb1c1e5e0b9486c1d26dd5bef110b20bf3/CFString.c#L463
+func GetCFStringBufLengthForUTF8(length int64) int64 {
+	if length > (math.MaxInt64 / 3) {
+		return KCFNotFound
+	}
+	return length*3 + 1 // includes null terminator
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_freebsd.go
new file mode 100644
index 000000000..7a40a40c2
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_freebsd.go
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd || openbsd
+
+package common
+
+import (
+	"fmt"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+)
+
+func SysctlUint(mib string) (uint64, error) {
+	buf, err := unix.SysctlRaw(mib)
+	if err != nil {
+		return 0, err
+	}
+	if len(buf) == 8 { // 64 bit
+		return *(*uint64)(unsafe.Pointer(&buf[0])), nil
+	}
+	if len(buf) == 4 { // 32bit
+		t := *(*uint32)(unsafe.Pointer(&buf[0]))
+		return uint64(t), nil
+	}
+	return 0, fmt.Errorf("unexpected size: %s, %d", mib, len(buf))
+}
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+	mibptr := unsafe.Pointer(&mib[0])
+	miblen := uint64(len(mib))
+
+	// get required buffer size
+	length := uint64(0)
+	_, _, err := unix.Syscall6(
+		unix.SYS___SYSCTL,
+		uintptr(mibptr),
+		uintptr(miblen),
+		0,
+		uintptr(unsafe.Pointer(&length)),
+		0,
+		0)
+	if err != 0 {
+		var b []byte
+		return b, length, err
+	}
+	if length == 0 {
+		var b []byte
+		return b, length, err
+	}
+	// get proc info itself
+	buf := make([]byte, length)
+	_, _, err = unix.Syscall6(
+		unix.SYS___SYSCTL,
+		uintptr(mibptr),
+		uintptr(miblen),
+		uintptr(unsafe.Pointer(&buf[0])),
+		uintptr(unsafe.Pointer(&length)),
+		0,
+		0)
+	if err != 0 {
+		return buf, length, err
+	}
+
+	return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_linux.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_linux.go
new file mode 100644
index 000000000..a2473f41d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_linux.go
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package common
+
+import (
+	"context"
+	"errors"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"syscall"
+	"time"
+)
+
+// cachedBootTime must be accessed via atomic.Load/StoreUint64
+var cachedBootTime uint64
+
+func NumProcs() (uint64, error) {
+	return NumProcsWithContext(context.Background())
+}
+
+func NumProcsWithContext(ctx context.Context) (uint64, error) {
+	f, err := os.Open(HostProcWithContext(ctx))
+	if err != nil {
+		return 0, err
+	}
+	defer f.Close()
+
+	list, err := f.Readdirnames(-1)
+	if err != nil {
+		return 0, err
+	}
+	var cnt uint64
+
+	for _, v := range list {
+		if _, err = strconv.ParseUint(v, 10, 64); err == nil {
+			cnt++
+		}
+	}
+
+	return cnt, nil
+}
+
+func BootTimeWithContext(ctx context.Context, enableCache bool) (uint64, error) {
+	if enableCache {
+		t := atomic.LoadUint64(&cachedBootTime)
+		if t != 0 {
+			return t, nil
+		}
+	}
+
+	system, role, err := VirtualizationWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+
+	useStatFile := true
+	if system == "lxc" && role == "guest" {
+		// if lxc, /proc/uptime is used.
+		useStatFile = false
+	} else if system == "docker" && role == "guest" {
+		// also docker, guest
+		useStatFile = false
+	}
+
+	if useStatFile {
+		t, err := readBootTimeStat(ctx)
+		if err != nil {
+			return 0, err
+		}
+		if enableCache {
+			atomic.StoreUint64(&cachedBootTime, t)
+		}
+
+		return t, nil
+	}
+
+	filename := HostProcWithContext(ctx, "uptime")
+	lines, err := ReadLines(filename)
+	if err != nil {
+		return handleBootTimeFileReadErr(err)
+	}
+	currentTime := float64(time.Now().UnixNano()) / float64(time.Second)
+
+	if len(lines) != 1 {
+		return 0, errors.New("wrong uptime format")
+	}
+	f := strings.Fields(lines[0])
+	b, err := strconv.ParseFloat(f[0], 64)
+	if err != nil {
+		return 0, err
+	}
+	t := currentTime - b
+
+	if enableCache {
+		atomic.StoreUint64(&cachedBootTime, uint64(t))
+	}
+
+	return uint64(t), nil
+}
+
+func handleBootTimeFileReadErr(err error) (uint64, error) {
+	if !os.IsPermission(err) {
+		return 0, err
+	}
+	var info syscall.Sysinfo_t
+	err = syscall.Sysinfo(&info)
+	if err != nil {
+		return 0, err
+	}
+
+	currentTime := time.Now().UnixNano() / int64(time.Second)
+	t := currentTime - int64(info.Uptime)
+	return uint64(t), nil
+}
+
+func readBootTimeStat(ctx context.Context) (uint64, error) {
+	filename := HostProcWithContext(ctx, "stat")
+	line, err := ReadLine(filename, "btime")
+	if err != nil {
+		return handleBootTimeFileReadErr(err)
+	}
+	if strings.HasPrefix(line, "btime") {
+		f := strings.Fields(line)
+		if len(f) != 2 {
+			return 0, errors.New("wrong btime format")
+		}
+		b, err := strconv.ParseInt(f[1], 10, 64)
+		if err != nil {
+			return 0, err
+		}
+		t := uint64(b)
+		return t, nil
+	}
+	return 0, errors.New("could not find btime")
+}
+
+func Virtualization() (string, string, error) {
+	return VirtualizationWithContext(context.Background())
+}
+
+// required variables for concurrency safe virtualization caching
+var (
+	cachedVirtMap   map[string]string
+	cachedVirtMutex sync.RWMutex
+	cachedVirtOnce  sync.Once
+)
+
+func VirtualizationWithContext(ctx context.Context) (string, string, error) {
+	var system, role string
+
+	// if cached already, return from cache
+	cachedVirtMutex.RLock() // unlock won't be deferred so concurrent reads don't wait for long
+	if cachedVirtMap != nil {
+		cachedSystem, cachedRole := cachedVirtMap["system"], cachedVirtMap["role"]
+		cachedVirtMutex.RUnlock()
+		return cachedSystem, cachedRole, nil
+	}
+	cachedVirtMutex.RUnlock()
+
+	filename := HostProcWithContext(ctx, "xen")
+	if PathExists(filename) {
+		system = "xen"
+		role = "guest" // assume guest
+
+		if PathExists(filepath.Join(filename, "capabilities")) {
+			contents, err := ReadLines(filepath.Join(filename, "capabilities"))
+			if err == nil {
+				if StringsContains(contents, "control_d") {
+					role = "host"
+				}
+			}
+		}
+	}
+
+	filename = HostProcWithContext(ctx, "modules")
+	if PathExists(filename) {
+		contents, err := ReadLines(filename)
+		if err == nil {
+			switch {
+			case StringsContains(contents, "kvm"):
+				system = "kvm"
+				role = "host"
+			case StringsContains(contents, "hv_util"):
+				system = "hyperv"
+				role = "guest"
+			case StringsContains(contents, "vboxdrv"):
+				system = "vbox"
+				role = "host"
+			case StringsContains(contents, "vboxguest"):
+				system = "vbox"
+				role = "guest"
+			case StringsContains(contents, "vmware"):
+				system = "vmware"
+				role = "guest"
+			}
+		}
+	}
+
+	filename = HostProcWithContext(ctx, "cpuinfo")
+	if PathExists(filename) {
+		contents, err := ReadLines(filename)
+		if err == nil {
+			if StringsContains(contents, "QEMU Virtual CPU") ||
+				StringsContains(contents, "Common KVM processor") ||
+				StringsContains(contents, "Common 32-bit KVM processor") {
+				system = "kvm"
+				role = "guest"
+			}
+		}
+	}
+
+	filename = HostProcWithContext(ctx, "bus/pci/devices")
+	if PathExists(filename) {
+		contents, err := ReadLines(filename)
+		if err == nil {
+			if StringsContains(contents, "virtio-pci") {
+				role = "guest"
+			}
+		}
+	}
+
+	filename = HostProcWithContext(ctx)
+	if PathExists(filepath.Join(filename, "bc", "0")) {
+		system = "openvz"
+		role = "host"
+	} else if PathExists(filepath.Join(filename, "vz")) {
+		system = "openvz"
+		role = "guest"
+	}
+
+	// not use dmidecode because it requires root
+	if PathExists(filepath.Join(filename, "self", "status")) {
+		contents, err := ReadLines(filepath.Join(filename, "self", "status"))
+		if err == nil {
+			if StringsContains(contents, "s_context:") ||
+				StringsContains(contents, "VxID:") {
+				system = "linux-vserver"
+			}
+			// TODO: guest or host
+		}
+	}
+
+	if PathExists(filepath.Join(filename, "1", "environ")) {
+		contents, err := ReadFile(filepath.Join(filename, "1", "environ"))
+
+		if err == nil {
+			if strings.Contains(contents, "container=lxc") {
+				system = "lxc"
+				role = "guest"
+			}
+		}
+	}
+
+	if PathExists(filepath.Join(filename, "self", "cgroup")) {
+		contents, err := ReadLines(filepath.Join(filename, "self", "cgroup"))
+		if err == nil {
+			switch {
+			case StringsContains(contents, "lxc"):
+				system = "lxc"
+				role = "guest"
+			case StringsContains(contents, "docker"):
+				system = "docker"
+				role = "guest"
+			case StringsContains(contents, "machine-rkt"):
+				system = "rkt"
+				role = "guest"
+			case PathExists("/usr/bin/lxc-version"):
+				system = "lxc"
+				role = "host"
+			}
+		}
+	}
+
+	if PathExists(HostEtcWithContext(ctx, "os-release")) {
+		p, _, err := GetOSReleaseWithContext(ctx)
+		if err == nil && p == "coreos" {
+			system = "rkt" // Is it true?
+			role = "host"
+		}
+	}
+
+	if PathExists(HostRootWithContext(ctx, ".dockerenv")) {
+		system = "docker"
+		role = "guest"
+	}
+
+	// before returning for the first time, cache the system and role
+	cachedVirtOnce.Do(func() {
+		cachedVirtMutex.Lock()
+		defer cachedVirtMutex.Unlock()
+		cachedVirtMap = map[string]string{
+			"system": system,
+			"role":   role,
+		}
+	})
+
+	return system, role, nil
+}
+
+func GetOSRelease() (platform, version string, err error) {
+	return GetOSReleaseWithContext(context.Background())
+}
+
+func GetOSReleaseWithContext(ctx context.Context) (platform, version string, err error) {
+	contents, err := ReadLines(HostEtcWithContext(ctx, "os-release"))
+	if err != nil {
+		return "", "", nil // return empty
+	}
+	for _, line := range contents {
+		field := strings.Split(line, "=")
+		if len(field) < 2 {
+			continue
+		}
+		switch field[0] {
+		case "ID": // use ID for lowercase
+			platform = trimQuotes(field[1])
+		case "VERSION_ID":
+			version = trimQuotes(field[1])
+		}
+	}
+
+	// cleanup amazon ID
+	if platform == "amzn" {
+		platform = "amazon"
+	}
+
+	return platform, version, nil
+}
+
+// Remove quotes of the source string
+func trimQuotes(s string) string {
+	if len(s) >= 2 {
+		if s[0] == '"' && s[len(s)-1] == '"' {
+			return s[1 : len(s)-1]
+		}
+	}
+	return s
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_netbsd.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_netbsd.go
new file mode 100644
index 000000000..52796ddbf
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_netbsd.go
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build netbsd
+
+package common
+
+import (
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+)
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+	mibptr := unsafe.Pointer(&mib[0])
+	miblen := uint64(len(mib))
+
+	// get required buffer size
+	length := uint64(0)
+	_, _, err := unix.Syscall6(
+		unix.SYS___SYSCTL,
+		uintptr(mibptr),
+		uintptr(miblen),
+		0,
+		uintptr(unsafe.Pointer(&length)),
+		0,
+		0)
+	if err != 0 {
+		var b []byte
+		return b, length, err
+	}
+	if length == 0 {
+		var b []byte
+		return b, length, err
+	}
+	// get proc info itself
+	buf := make([]byte, length)
+	_, _, err = unix.Syscall6(
+		unix.SYS___SYSCTL,
+		uintptr(mibptr),
+		uintptr(miblen),
+		uintptr(unsafe.Pointer(&buf[0])),
+		uintptr(unsafe.Pointer(&length)),
+		0,
+		0)
+	if err != 0 {
+		return buf, length, err
+	}
+
+	return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_openbsd.go
new file mode 100644
index 000000000..df44ac042
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_openbsd.go
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package common
+
+import (
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+)
+
+func CallSyscall(mib []int32) ([]byte, uint64, error) {
+	mibptr := unsafe.Pointer(&mib[0])
+	miblen := uint64(len(mib))
+
+	// get required buffer size
+	length := uint64(0)
+	_, _, err := unix.Syscall6(
+		unix.SYS___SYSCTL,
+		uintptr(mibptr),
+		uintptr(miblen),
+		0,
+		uintptr(unsafe.Pointer(&length)),
+		0,
+		0)
+	if err != 0 {
+		var b []byte
+		return b, length, err
+	}
+	if length == 0 {
+		var b []byte
+		return b, length, err
+	}
+	// get proc info itself
+	buf := make([]byte, length)
+	_, _, err = unix.Syscall6(
+		unix.SYS___SYSCTL,
+		uintptr(mibptr),
+		uintptr(miblen),
+		uintptr(unsafe.Pointer(&buf[0])),
+		uintptr(unsafe.Pointer(&length)),
+		0,
+		0)
+	if err != 0 {
+		return buf, length, err
+	}
+
+	return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_unix.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_unix.go
new file mode 100644
index 000000000..2ccb37608
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_unix.go
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux || freebsd || darwin || openbsd
+
+package common
+
+import (
+	"context"
+	"errors"
+	"os/exec"
+	"strconv"
+	"strings"
+)
+
+func CallLsofWithContext(ctx context.Context, invoke Invoker, pid int32, args ...string) ([]string, error) {
+	var cmd []string
+	if pid == 0 { // will get from all processes.
+		cmd = []string{"-a", "-n", "-P"}
+	} else {
+		cmd = []string{"-a", "-n", "-P", "-p", strconv.Itoa(int(pid))}
+	}
+	cmd = append(cmd, args...)
+	out, err := invoke.CommandWithContext(ctx, "lsof", cmd...)
+	if err != nil {
+		if errors.Is(err, exec.ErrNotFound) {
+			return []string{}, err
+		}
+		// if no pid found, lsof returns code 1.
+		if err.Error() == "exit status 1" && len(out) == 0 {
+			return []string{}, nil
+		}
+	}
+	lines := strings.Split(string(out), "\n")
+
+	var ret []string
+	for _, l := range lines[1:] {
+		if l == "" {
+			continue
+		}
+		ret = append(ret, l)
+	}
+	return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/common_windows.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_windows.go
new file mode 100644
index 000000000..3778e4d95
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/common_windows.go
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package common
+
+import (
+	"context"
+	"fmt"
+	"path/filepath"
+	"reflect"
+	"strings"
+	"syscall"
+	"unsafe"
+
+	"github.com/yusufpapurcu/wmi"
+	"golang.org/x/sys/windows"
+)
+
+// for double values
+type PDH_FMT_COUNTERVALUE_DOUBLE struct { //nolint:revive //FIXME
+	CStatus     uint32
+	DoubleValue float64
+}
+
+// for 64 bit integer values
+type PDH_FMT_COUNTERVALUE_LARGE struct { //nolint:revive //FIXME
+	CStatus    uint32
+	LargeValue int64
+}
+
+// for long values
+type PDH_FMT_COUNTERVALUE_LONG struct { //nolint:revive //FIXME
+	CStatus   uint32
+	LongValue int32
+	padding   [4]byte
+}
+
+// windows system const
+const (
+	ERROR_SUCCESS        = 0
+	ERROR_FILE_NOT_FOUND = 2
+	DRIVE_REMOVABLE      = 2
+	DRIVE_FIXED          = 3
+	HKEY_LOCAL_MACHINE   = 0x80000002
+	RRF_RT_REG_SZ        = 0x00000002
+	RRF_RT_REG_DWORD     = 0x00000010
+	PDH_FMT_LONG         = 0x00000100
+	PDH_FMT_DOUBLE       = 0x00000200
+	PDH_FMT_LARGE        = 0x00000400
+	PDH_INVALID_DATA     = 0xc0000bc6
+	PDH_INVALID_HANDLE   = 0xC0000bbc
+	PDH_NO_DATA          = 0x800007d5
+
+	STATUS_BUFFER_OVERFLOW      = 0x80000005
+	STATUS_BUFFER_TOO_SMALL     = 0xC0000023
+	STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
+)
+
+const (
+	ProcessBasicInformation = 0
+	ProcessWow64Information = 26
+	ProcessQueryInformation = windows.PROCESS_DUP_HANDLE | windows.PROCESS_QUERY_INFORMATION
+
+	SystemExtendedHandleInformationClass = 64
+)
+
+var (
+	Modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+	ModNt       = windows.NewLazySystemDLL("ntdll.dll")
+	ModPdh      = windows.NewLazySystemDLL("pdh.dll")
+	ModPsapi    = windows.NewLazySystemDLL("psapi.dll")
+	ModPowrProf = windows.NewLazySystemDLL("powrprof.dll")
+
+	ProcGetSystemTimes                   = Modkernel32.NewProc("GetSystemTimes")
+	ProcNtQuerySystemInformation         = ModNt.NewProc("NtQuerySystemInformation")
+	ProcNtQuerySystemInformationEx       = ModNt.NewProc("NtQuerySystemInformationEx")
+	ProcRtlGetNativeSystemInformation    = ModNt.NewProc("RtlGetNativeSystemInformation")
+	ProcRtlNtStatusToDosError            = ModNt.NewProc("RtlNtStatusToDosError")
+	ProcNtQueryInformationProcess        = ModNt.NewProc("NtQueryInformationProcess")
+	ProcNtReadVirtualMemory              = ModNt.NewProc("NtReadVirtualMemory")
+	ProcNtWow64QueryInformationProcess64 = ModNt.NewProc("NtWow64QueryInformationProcess64")
+	ProcNtWow64ReadVirtualMemory64       = ModNt.NewProc("NtWow64ReadVirtualMemory64")
+
+	PdhOpenQuery                = ModPdh.NewProc("PdhOpenQuery")
+	PdhAddEnglishCounterW       = ModPdh.NewProc("PdhAddEnglishCounterW")
+	PdhCollectQueryData         = ModPdh.NewProc("PdhCollectQueryData")
+	PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue")
+	PdhCloseQuery               = ModPdh.NewProc("PdhCloseQuery")
+
+	procQueryDosDeviceW = Modkernel32.NewProc("QueryDosDeviceW")
+)
+
+type FILETIME struct {
+	DwLowDateTime  uint32
+	DwHighDateTime uint32
+}
+
+// borrowed from net/interface_windows.go
+func BytePtrToString(p *uint8) string {
+	a := (*[10000]uint8)(unsafe.Pointer(p))
+	i := 0
+	for a[i] != 0 {
+		i++
+	}
+	return string(a[:i])
+}
+
+// CounterInfo struct is used to track a windows performance counter
+// copied from https://github.com/mackerelio/mackerel-agent/
+type CounterInfo struct {
+	PostName    string
+	CounterName string
+	Counter     windows.Handle
+}
+
+// CreateQuery with a PdhOpenQuery call
+// copied from https://github.com/mackerelio/mackerel-agent/
+func CreateQuery() (windows.Handle, error) {
+	var query windows.Handle
+	r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query)))
+	if r != 0 {
+		return 0, err
+	}
+	return query, nil
+}
+
+// CreateCounter with a PdhAddEnglishCounterW call
+func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) {
+	var counter windows.Handle
+	r, _, err := PdhAddEnglishCounterW.Call(
+		uintptr(query),
+		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cname))),
+		0,
+		uintptr(unsafe.Pointer(&counter)))
+	if r != 0 {
+		return nil, err
+	}
+	return &CounterInfo{
+		PostName:    pname,
+		CounterName: cname,
+		Counter:     counter,
+	}, nil
+}
+
+// GetCounterValue get counter value from handle
+// adapted from https://github.com/mackerelio/mackerel-agent/
+func GetCounterValue(counter windows.Handle) (float64, error) {
+	var value PDH_FMT_COUNTERVALUE_DOUBLE
+	r, _, err := PdhGetFormattedCounterValue.Call(uintptr(counter), PDH_FMT_DOUBLE, uintptr(0), uintptr(unsafe.Pointer(&value)))
+	if r != 0 && r != PDH_INVALID_DATA {
+		return 0.0, err
+	}
+	return value.DoubleValue, nil
+}
+
+type Win32PerformanceCounter struct {
+	PostName    string
+	CounterName string
+	Query       windows.Handle
+	Counter     windows.Handle
+}
+
+func NewWin32PerformanceCounter(postName, counterName string) (*Win32PerformanceCounter, error) {
+	query, err := CreateQuery()
+	if err != nil {
+		return nil, err
+	}
+	counter := Win32PerformanceCounter{
+		Query:       query,
+		PostName:    postName,
+		CounterName: counterName,
+	}
+	r, _, err := PdhAddEnglishCounterW.Call(
+		uintptr(counter.Query),
+		uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(counter.CounterName))),
+		0,
+		uintptr(unsafe.Pointer(&counter.Counter)),
+	)
+	if r != 0 {
+		return nil, err
+	}
+	return &counter, nil
+}
+
+func (w *Win32PerformanceCounter) GetValue() (float64, error) {
+	r, _, err := PdhCollectQueryData.Call(uintptr(w.Query))
+	if r != 0 && err != nil {
+		if r == PDH_NO_DATA {
+			return 0.0, fmt.Errorf("%w: this counter has not data", err)
+		}
+		return 0.0, err
+	}
+
+	return GetCounterValue(w.Counter)
+}
+
+func ProcessorQueueLengthCounter() (*Win32PerformanceCounter, error) {
+	return NewWin32PerformanceCounter("processor_queue_length", `\System\Processor Queue Length`)
+}
+
+// WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
+func WMIQueryWithContext(ctx context.Context, query string, dst any, connectServerArgs ...any) error {
+	if _, ok := ctx.Deadline(); !ok {
+		ctxTimeout, cancel := context.WithTimeout(ctx, Timeout)
+		defer cancel()
+		ctx = ctxTimeout
+	}
+
+	errChan := make(chan error, 1)
+	go func() {
+		errChan <- wmi.Query(query, dst, connectServerArgs...)
+	}()
+
+	select {
+	case <-ctx.Done():
+		return ctx.Err()
+	case err := <-errChan:
+		return err
+	}
+}
+
+// Convert paths using native DOS format like:
+//
+//	"\Device\HarddiskVolume1\Windows\systemew\file.txt"
+//
+// into:
+//
+//	"C:\Windows\systemew\file.txt"
+func ConvertDOSPath(p string) string {
+	rawDrive := strings.Join(strings.Split(p, `\`)[:3], `\`)
+
+	for d := 'A'; d <= 'Z'; d++ {
+		szDeviceName := string(d) + ":"
+		szTarget := make([]uint16, 512)
+		ret, _, _ := procQueryDosDeviceW.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(szDeviceName))),
+			uintptr(unsafe.Pointer(&szTarget[0])),
+			uintptr(len(szTarget)))
+		if ret != 0 && windows.UTF16ToString(szTarget) == rawDrive {
+			return filepath.Join(szDeviceName, p[len(rawDrive):])
+		}
+	}
+	return p
+}
+
+type NtStatus uint32
+
+func (s NtStatus) Error() error {
+	if s == 0 {
+		return nil
+	}
+	return fmt.Errorf("NtStatus 0x%08x", uint32(s))
+}
+
+func (s NtStatus) IsError() bool {
+	return s>>30 == 3
+}
+
+type SystemExtendedHandleTableEntryInformation struct {
+	Object                uintptr
+	UniqueProcessId       uintptr
+	HandleValue           uintptr
+	GrantedAccess         uint32
+	CreatorBackTraceIndex uint16
+	ObjectTypeIndex       uint16
+	HandleAttributes      uint32
+	Reserved              uint32
+}
+
+type SystemExtendedHandleInformation struct {
+	NumberOfHandles uintptr
+	Reserved        uintptr
+	Handles         [1]SystemExtendedHandleTableEntryInformation
+}
+
+// CallWithExpandingBuffer https://github.com/hillu/go-ntdll
+func CallWithExpandingBuffer(fn func() NtStatus, buf *[]byte, resultLength *uint32) NtStatus {
+	for {
+		st := fn()
+		if st == STATUS_BUFFER_OVERFLOW || st == STATUS_BUFFER_TOO_SMALL || st == STATUS_INFO_LENGTH_MISMATCH {
+			if int(*resultLength) <= cap(*buf) {
+				(*reflect.SliceHeader)(unsafe.Pointer(buf)).Len = int(*resultLength)
+			} else {
+				*buf = make([]byte, int(*resultLength))
+			}
+			continue
+		}
+		if !st.IsError() {
+			*buf = (*buf)[:int(*resultLength)]
+		}
+		return st
+	}
+}
+
+func NtQuerySystemInformation(
+	SystemInformationClass uint32,
+	SystemInformation *byte,
+	SystemInformationLength uint32,
+	ReturnLength *uint32,
+) NtStatus {
+	r0, _, _ := ProcNtQuerySystemInformation.Call(
+		uintptr(SystemInformationClass),
+		uintptr(unsafe.Pointer(SystemInformation)),
+		uintptr(SystemInformationLength),
+		uintptr(unsafe.Pointer(ReturnLength)))
+	return NtStatus(r0)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/endian.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/endian.go
new file mode 100644
index 000000000..113ff2e9f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/endian.go
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+import "unsafe"
+
+// IsLittleEndian checks if the current platform uses little-endian.
+// copied from https://github.com/ntrrg/ntgo/blob/v0.8.0/runtime/infrastructure.go#L16 (MIT License)
+func IsLittleEndian() bool {
+	var x int16 = 0x0011
+	return *(*byte)(unsafe.Pointer(&x)) == 0x11
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/readlink_linux.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/readlink_linux.go
new file mode 100644
index 000000000..ea2d4677b
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/readlink_linux.go
@@ -0,0 +1,53 @@
+package common
+
+import (
+	"errors"
+	"os"
+	"sync"
+	"syscall"
+)
+
+var bufferPool = sync.Pool{
+	New: func() any {
+		b := make([]byte, syscall.PathMax)
+		return &b
+	},
+}
+
+// The following three functions are copied from stdlib.
+
+// ignoringEINTR2 is ignoringEINTR, but returning an additional value.
+func ignoringEINTR2[T any](fn func() (T, error)) (T, error) {
+	for {
+		v, err := fn()
+		if !errors.Is(err, syscall.EINTR) {
+			return v, err
+		}
+	}
+}
+
+// Many functions in package syscall return a count of -1 instead of 0.
+// Using fixCount(call()) instead of call() corrects the count.
+func fixCount(n int, err error) (int, error) {
+	if n < 0 {
+		n = 0
+	}
+	return n, err
+}
+
+// Readlink behaves like os.Readlink but caches the buffer passed to syscall.Readlink.
+func Readlink(name string) (string, error) {
+	b := bufferPool.Get().(*[]byte)
+
+	n, err := ignoringEINTR2(func() (int, error) {
+		return fixCount(syscall.Readlink(name, *b))
+	})
+	if err != nil {
+		bufferPool.Put(b)
+		return "", &os.PathError{Op: "readlink", Path: name, Err: err}
+	}
+
+	result := string((*b)[:n])
+	bufferPool.Put(b)
+	return result, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/sleep.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/sleep.go
new file mode 100644
index 000000000..504f13ffd
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/sleep.go
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+import (
+	"context"
+	"time"
+)
+
+// Sleep awaits for provided interval.
+// Can be interrupted by context cancellation.
+func Sleep(ctx context.Context, interval time.Duration) error {
+	timer := time.NewTimer(interval)
+	select {
+	case <-ctx.Done():
+		if !timer.Stop() {
+			<-timer.C
+		}
+		return ctx.Err()
+	case <-timer.C:
+		return nil
+	}
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/internal/common/warnings.go b/vendor/github.com/shirou/gopsutil/v4/internal/common/warnings.go
new file mode 100644
index 000000000..6bbfc2d72
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/internal/common/warnings.go
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package common
+
+import (
+	"fmt"
+	"strings"
+)
+
+const (
+	maxWarnings             = 100 // An arbitrary limit to avoid excessive memory usage, it has no sense to store hundreds of errors
+	tooManyErrorsMessage    = "too many errors reported, next errors were discarded"
+	numberOfWarningsMessage = "Number of warnings:"
+)
+
+type Warnings struct {
+	List          []error
+	tooManyErrors bool
+	Verbose       bool
+}
+
+func (w *Warnings) Add(err error) {
+	if len(w.List) >= maxWarnings {
+		w.tooManyErrors = true
+		return
+	}
+	w.List = append(w.List, err)
+}
+
+func (w *Warnings) Reference() error {
+	if len(w.List) > 0 {
+		return w
+	}
+	return nil
+}
+
+func (w *Warnings) Error() string {
+	if w.Verbose {
+		str := ""
+		var sb strings.Builder
+		for i, e := range w.List {
+			fmt.Fprintf(&sb, "\tError %d: %s\n", i, e.Error())
+		}
+		str += sb.String()
+		if w.tooManyErrors {
+			str += fmt.Sprintf("\t%s\n", tooManyErrorsMessage)
+		}
+		return str
+	}
+	if w.tooManyErrors {
+		return fmt.Sprintf("%s > %v - %s", numberOfWarningsMessage, maxWarnings, tooManyErrorsMessage)
+	}
+	return fmt.Sprintf("%s %v", numberOfWarningsMessage, len(w.List))
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go b/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go
new file mode 100644
index 000000000..b69dfb605
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/ex_linux.go
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package mem
+
+import (
+	"context"
+	"encoding/json"
+)
+
+type ExVirtualMemory struct {
+	ActiveFile   uint64 `json:"activefile"`
+	InactiveFile uint64 `json:"inactivefile"`
+	ActiveAnon   uint64 `json:"activeanon"`
+	InactiveAnon uint64 `json:"inactiveanon"`
+	Unevictable  uint64 `json:"unevictable"`
+	Percpu       uint64 `json:"percpu"`
+	KernelStack  uint64 `json:"kernelstack"`
+}
+
+func (v ExVirtualMemory) String() string {
+	s, _ := json.Marshal(v)
+	return string(s)
+}
+
+type ExLinux struct{}
+
+func NewExLinux() *ExLinux {
+	return &ExLinux{}
+}
+
+func (ex *ExLinux) VirtualMemory() (*ExVirtualMemory, error) {
+	return ex.VirtualMemoryWithContext(context.Background())
+}
+
+func (*ExLinux) VirtualMemoryWithContext(ctx context.Context) (*ExVirtualMemory, error) {
+	_, vmEx, err := fillFromMeminfoWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return vmEx, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/ex_windows.go b/vendor/github.com/shirou/gopsutil/v4/mem/ex_windows.go
new file mode 100644
index 000000000..907143d3e
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/ex_windows.go
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package mem
+
+import (
+	"unsafe"
+)
+
+// ExVirtualMemory represents Windows specific information
+// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
+// https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-performance_information
+type ExVirtualMemory struct {
+	CommitLimit   uint64 `json:"commitLimit"`
+	CommitTotal   uint64 `json:"commitTotal"`
+	VirtualTotal  uint64 `json:"virtualTotal"`
+	VirtualAvail  uint64 `json:"virtualAvail"`
+	PhysTotal     uint64 `json:"physTotal"`
+	PhysAvail     uint64 `json:"physAvail"`
+	PageFileTotal uint64 `json:"pageFileTotal"`
+	PageFileAvail uint64 `json:"pageFileAvail"`
+}
+
+type ExWindows struct{}
+
+func NewExWindows() *ExWindows {
+	return &ExWindows{}
+}
+
+func (*ExWindows) VirtualMemory() (*ExVirtualMemory, error) {
+	var memInfo memoryStatusEx
+	memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
+	// If mem == 0 since this is an error according to GlobalMemoryStatusEx documentation
+	// In that case, use err which is constructed from GetLastError(),
+	// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call
+	mem, _, err := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
+	if mem == 0 {
+		return nil, err
+	}
+
+	var perfInfo performanceInformation
+	perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
+	// Analogous to above: perf == 0 is an error according to the GetPerformanceInfo documentation,
+	// use err in that case
+	perf, _, err := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
+	if perf == 0 {
+		return nil, err
+	}
+
+	ret := &ExVirtualMemory{
+		CommitLimit:   perfInfo.commitLimit * perfInfo.pageSize,
+		CommitTotal:   perfInfo.commitTotal * perfInfo.pageSize,
+		VirtualTotal:  memInfo.ullTotalVirtual,
+		VirtualAvail:  memInfo.ullAvailVirtual,
+		PhysTotal:     memInfo.ullTotalPhys,
+		PhysAvail:     memInfo.ullAvailPhys,
+		PageFileTotal: memInfo.ullTotalPageFile,
+		PageFileAvail: memInfo.ullAvailPageFile,
+	}
+
+	return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem.go
new file mode 100644
index 000000000..f4f46f0d2
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem.go
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package mem
+
+import (
+	"encoding/json"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var invoke common.Invoker = common.Invoke{}
+
+// Memory usage statistics. Total, Available and Used contain numbers of bytes
+// for human consumption.
+//
+// The other fields in this struct contain kernel specific values.
+type VirtualMemoryStat struct {
+	// Total amount of RAM on this system
+	Total uint64 `json:"total"`
+
+	// RAM available for programs to allocate
+	//
+	// This value is computed from the kernel specific values.
+	Available uint64 `json:"available"`
+
+	// RAM used by programs
+	//
+	// This value is computed from the kernel specific values.
+	Used uint64 `json:"used"`
+
+	// Percentage of RAM used by programs
+	//
+	// This value is computed from the kernel specific values.
+	UsedPercent float64 `json:"usedPercent"`
+
+	// This is the kernel's notion of free memory; RAM chips whose bits nobody
+	// cares about the value of right now. For a human consumable number,
+	// Available is what you really want.
+	Free uint64 `json:"free"`
+
+	// OS X / BSD specific numbers:
+	// http://www.macyourself.com/2010/02/17/what-is-free-wired-active-and-inactive-system-memory-ram/
+	Active   uint64 `json:"active"`
+	Inactive uint64 `json:"inactive"`
+	Wired    uint64 `json:"wired"`
+
+	// FreeBSD specific numbers:
+	// https://reviews.freebsd.org/D8467
+	Laundry uint64 `json:"laundry"`
+
+	// Linux specific numbers
+	// https://blogs.oracle.com/linux/understanding-linux-kernel-memory-statistics
+	// https://www.kernel.org/doc/Documentation/filesystems/proc.txt
+	// https://www.kernel.org/doc/Documentation/vm/overcommit-accounting
+	// https://www.kernel.org/doc/Documentation/vm/transhuge.txt
+	//
+	Buffers        uint64 `json:"buffers"`
+	Cached         uint64 `json:"cached"`
+	WriteBack      uint64 `json:"writeBack"`
+	Dirty          uint64 `json:"dirty"`
+	WriteBackTmp   uint64 `json:"writeBackTmp"`
+	Shared         uint64 `json:"shared"`
+	Slab           uint64 `json:"slab"`
+	Sreclaimable   uint64 `json:"sreclaimable"`
+	Sunreclaim     uint64 `json:"sunreclaim"`
+	PageTables     uint64 `json:"pageTables"`
+	SwapCached     uint64 `json:"swapCached"`
+	CommitLimit    uint64 `json:"commitLimit"`
+	CommittedAS    uint64 `json:"committedAS"`
+	HighTotal      uint64 `json:"highTotal"`
+	HighFree       uint64 `json:"highFree"`
+	LowTotal       uint64 `json:"lowTotal"`
+	LowFree        uint64 `json:"lowFree"`
+	SwapTotal      uint64 `json:"swapTotal"`
+	SwapFree       uint64 `json:"swapFree"`
+	Mapped         uint64 `json:"mapped"`
+	VmallocTotal   uint64 `json:"vmallocTotal"`
+	VmallocUsed    uint64 `json:"vmallocUsed"`
+	VmallocChunk   uint64 `json:"vmallocChunk"`
+	HugePagesTotal uint64 `json:"hugePagesTotal"`
+	HugePagesFree  uint64 `json:"hugePagesFree"`
+	HugePagesRsvd  uint64 `json:"hugePagesRsvd"`
+	HugePagesSurp  uint64 `json:"hugePagesSurp"`
+	HugePageSize   uint64 `json:"hugePageSize"`
+	AnonHugePages  uint64 `json:"anonHugePages"`
+}
+
+type SwapMemoryStat struct {
+	Total       uint64  `json:"total"`
+	Used        uint64  `json:"used"`
+	Free        uint64  `json:"free"`
+	UsedPercent float64 `json:"usedPercent"`
+	Sin         uint64  `json:"sin"`
+	Sout        uint64  `json:"sout"`
+	PgIn        uint64  `json:"pgIn"`
+	PgOut       uint64  `json:"pgOut"`
+	PgFault     uint64  `json:"pgFault"`
+
+	// Linux specific numbers
+	// https://www.kernel.org/doc/Documentation/cgroup-v2.txt
+	PgMajFault uint64 `json:"pgMajFault"`
+}
+
+func (m VirtualMemoryStat) String() string {
+	s, _ := json.Marshal(m)
+	return string(s)
+}
+
+func (m SwapMemoryStat) String() string {
+	s, _ := json.Marshal(m)
+	return string(s)
+}
+
+type SwapDevice struct {
+	Name      string `json:"name"`
+	UsedBytes uint64 `json:"usedBytes"`
+	FreeBytes uint64 `json:"freeBytes"`
+}
+
+func (m SwapDevice) String() string {
+	s, _ := json.Marshal(m)
+	return string(s)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix.go
new file mode 100644
index 000000000..ac2c39dd3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix.go
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix
+
+package mem
+
+import (
+	"context"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_cgo.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_cgo.go
new file mode 100644
index 000000000..2d03dd0c3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_cgo.go
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && cgo
+
+package mem
+
+import (
+	"context"
+
+	"github.com/power-devops/perfstat"
+)
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+	m, err := perfstat.MemoryTotalStat()
+	if err != nil {
+		return nil, err
+	}
+	pagesize := uint64(4096)
+	ret := VirtualMemoryStat{
+		Total:       uint64(m.RealTotal) * pagesize,
+		Available:   uint64(m.RealAvailable) * pagesize,
+		Free:        uint64(m.RealFree) * pagesize,
+		Used:        uint64(m.RealInUse) * pagesize,
+		UsedPercent: 100 * float64(m.RealInUse) / float64(m.RealTotal),
+		Active:      uint64(m.VirtualActive) * pagesize,
+		SwapTotal:   uint64(m.PgSpTotal) * pagesize,
+		SwapFree:    uint64(m.PgSpFree) * pagesize,
+	}
+	return &ret, nil
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+	m, err := perfstat.MemoryTotalStat()
+	if err != nil {
+		return nil, err
+	}
+	pagesize := uint64(4096)
+	swapUsed := uint64(m.PgSpTotal-m.PgSpFree-m.PgSpRsvd) * pagesize
+	swapTotal := uint64(m.PgSpTotal) * pagesize
+	ret := SwapMemoryStat{
+		Total:       swapTotal,
+		Free:        uint64(m.PgSpFree) * pagesize,
+		Used:        swapUsed,
+		UsedPercent: float64(100*swapUsed) / float64(swapTotal),
+		Sin:         uint64(m.PgSpIn),
+		Sout:        uint64(m.PgSpOut),
+		PgIn:        uint64(m.PageIn),
+		PgOut:       uint64(m.PageOut),
+		PgFault:     uint64(m.PageFaults),
+	}
+	return &ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_nocgo.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_nocgo.go
new file mode 100644
index 000000000..bc3c0ed3b
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_aix_nocgo.go
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && !cgo
+
+package mem
+
+import (
+	"context"
+	"strconv"
+	"strings"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+	vmem, swap, err := callSVMon(ctx, true)
+	if err != nil {
+		return nil, err
+	}
+	if vmem.Total == 0 {
+		return nil, common.ErrNotImplementedError
+	}
+	vmem.SwapTotal = swap.Total
+	vmem.SwapFree = swap.Free
+	return vmem, nil
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+	_, swap, err := callSVMon(ctx, false)
+	if err != nil {
+		return nil, err
+	}
+	if swap.Total == 0 {
+		return nil, common.ErrNotImplementedError
+	}
+	return swap, nil
+}
+
+func callSVMon(ctx context.Context, virt bool) (*VirtualMemoryStat, *SwapMemoryStat, error) {
+	out, err := invoke.CommandWithContext(ctx, "svmon", "-G")
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pagesize := uint64(4096)
+	vmem := &VirtualMemoryStat{}
+	swap := &SwapMemoryStat{}
+	for _, line := range strings.Split(string(out), "\n") {
+		if virt && strings.HasPrefix(line, "memory") {
+			p := strings.Fields(line)
+			if len(p) > 2 {
+				if t, err := strconv.ParseUint(p[1], 10, 64); err == nil {
+					vmem.Total = t * pagesize
+				}
+				if t, err := strconv.ParseUint(p[2], 10, 64); err == nil {
+					vmem.Used = t * pagesize
+					if vmem.Total > 0 {
+						vmem.UsedPercent = 100 * float64(vmem.Used) / float64(vmem.Total)
+					}
+				}
+				if t, err := strconv.ParseUint(p[3], 10, 64); err == nil {
+					vmem.Free = t * pagesize
+				}
+			}
+		} else if strings.HasPrefix(line, "pg space") {
+			p := strings.Fields(line)
+			if len(p) > 3 {
+				if t, err := strconv.ParseUint(p[2], 10, 64); err == nil {
+					swap.Total = t * pagesize
+				}
+				if t, err := strconv.ParseUint(p[3], 10, 64); err == nil {
+					swap.Free = swap.Total - t*pagesize
+				}
+			}
+			break
+		}
+	}
+	return vmem, swap, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_bsd.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_bsd.go
new file mode 100644
index 000000000..4f3e57c03
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_bsd.go
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd || openbsd || netbsd
+
+package mem
+
+import (
+	"context"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+const swapCommand = "swapctl"
+
+// swapctl column indexes
+const (
+	nameCol     = 0
+	totalKiBCol = 1
+	usedKiBCol  = 2
+)
+
+func SwapDevices() ([]*SwapDevice, error) {
+	return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+	output, err := invoke.CommandWithContext(ctx, swapCommand, "-lk")
+	if err != nil {
+		return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err)
+	}
+
+	return parseSwapctlOutput(string(output))
+}
+
+func parseSwapctlOutput(output string) ([]*SwapDevice, error) {
+	lines := strings.Split(output, "\n")
+	if len(lines) == 0 {
+		return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output)
+	}
+
+	// Check header headerFields are as expected.
+	header := lines[0]
+	header = strings.ToLower(header)
+	header = strings.ReplaceAll(header, ":", "")
+	headerFields := strings.Fields(header)
+	if len(headerFields) < usedKiBCol {
+		return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, header)
+	}
+	if headerFields[nameCol] != "device" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "device")
+	}
+	if headerFields[totalKiBCol] != "1kb-blocks" && headerFields[totalKiBCol] != "1k-blocks" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalKiBCol], "1kb-blocks")
+	}
+	if headerFields[usedKiBCol] != "used" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[usedKiBCol], "used")
+	}
+
+	var swapDevices []*SwapDevice
+	for _, line := range lines[1:] {
+		if line == "" {
+			continue // the terminal line is typically empty
+		}
+		fields := strings.Fields(line)
+		if len(fields) < usedKiBCol {
+			return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand)
+		}
+
+		totalKiB, err := strconv.ParseUint(fields[totalKiBCol], 10, 64)
+		if err != nil {
+			return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err)
+		}
+
+		usedKiB, err := strconv.ParseUint(fields[usedKiBCol], 10, 64)
+		if err != nil {
+			return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err)
+		}
+
+		swapDevices = append(swapDevices, &SwapDevice{
+			Name:      fields[nameCol],
+			UsedBytes: usedKiB * 1024,
+			FreeBytes: (totalKiB - usedKiB) * 1024,
+		})
+	}
+
+	return swapDevices, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go
new file mode 100644
index 000000000..1b3e9f21b
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_darwin.go
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package mem
+
+import (
+	"context"
+	"fmt"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func getHwMemsize() (uint64, error) {
+	total, err := unix.SysctlUint64("hw.memsize")
+	if err != nil {
+		return 0, err
+	}
+	return total, nil
+}
+
+// xsw_usage in sys/sysctl.h
+type swapUsage struct {
+	Total     uint64
+	Avail     uint64
+	Used      uint64
+	Pagesize  int32
+	Encrypted bool
+}
+
+// SwapMemory returns swapinfo.
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {
+	// https://github.com/yanllearnn/go-osstat/blob/ae8a279d26f52ec946a03698c7f50a26cfb427e3/memory/memory_darwin.go
+	var ret *SwapMemoryStat
+
+	value, err := unix.SysctlRaw("vm.swapusage")
+	if err != nil {
+		return ret, err
+	}
+	if len(value) != 32 {
+		return ret, fmt.Errorf("unexpected output of sysctl vm.swapusage: %v (len: %d)", value, len(value))
+	}
+	swap := (*swapUsage)(unsafe.Pointer(&value[0]))
+
+	u := float64(0)
+	if swap.Total != 0 {
+		u = ((float64(swap.Total) - float64(swap.Avail)) / float64(swap.Total)) * 100.0
+	}
+
+	ret = &SwapMemoryStat{
+		Total:       swap.Total,
+		Used:        swap.Used,
+		Free:        swap.Avail,
+		UsedPercent: u,
+	}
+
+	return ret, nil
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+	return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(_ context.Context) ([]*SwapDevice, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+type vmStatisticsData struct {
+	freeCount     uint32
+	activeCount   uint32
+	inactiveCount uint32
+	wireCount     uint32
+	_             [44]byte // Not used here
+}
+
+// VirtualMemory returns VirtualmemoryStat.
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {
+	sys, err := common.NewSystemLib()
+	if err != nil {
+		return nil, err
+	}
+	defer sys.Close()
+
+	count := uint32(common.HOST_VM_INFO_COUNT)
+	var vmstat vmStatisticsData
+
+	status := sys.HostStatistics(sys.MachHostSelf(), common.HOST_VM_INFO,
+		uintptr(unsafe.Pointer(&vmstat)), &count)
+
+	if status != common.KERN_SUCCESS {
+		return nil, fmt.Errorf("host_statistics error=%d", status)
+	}
+
+	pageSizeAddr, _ := sys.Dlsym("vm_kernel_page_size")
+	pageSize := **(**uint64)(unsafe.Pointer(&pageSizeAddr))
+	total, err := getHwMemsize()
+	if err != nil {
+		return nil, err
+	}
+	totalCount := uint32(total / pageSize)
+
+	availableCount := vmstat.inactiveCount + vmstat.freeCount
+	usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount)
+
+	usedCount := totalCount - availableCount
+
+	return &VirtualMemoryStat{
+		Total:       total,
+		Available:   pageSize * uint64(availableCount),
+		Used:        pageSize * uint64(usedCount),
+		UsedPercent: usedPercent,
+		Free:        pageSize * uint64(vmstat.freeCount),
+		Active:      pageSize * uint64(vmstat.activeCount),
+		Inactive:    pageSize * uint64(vmstat.inactiveCount),
+		Wired:       pageSize * uint64(vmstat.wireCount),
+	}, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_fallback.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_fallback.go
new file mode 100644
index 000000000..74283a2b5
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_fallback.go
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !plan9 && !aix && !netbsd
+
+package mem
+
+import (
+	"context"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+	return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(_ context.Context) ([]*SwapDevice, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_freebsd.go
new file mode 100644
index 000000000..dbe6d9199
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_freebsd.go
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd
+
+package mem
+
+import (
+	"context"
+	"errors"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {
+	pageSize, err := common.SysctlUint("vm.stats.vm.v_page_size")
+	if err != nil {
+		return nil, err
+	}
+	physmem, err := common.SysctlUint("hw.physmem")
+	if err != nil {
+		return nil, err
+	}
+
+	free, err := common.SysctlUint("vm.stats.vm.v_free_count")
+	if err != nil {
+		return nil, err
+	}
+	active, err := common.SysctlUint("vm.stats.vm.v_active_count")
+	if err != nil {
+		return nil, err
+	}
+	inactive, err := common.SysctlUint("vm.stats.vm.v_inactive_count")
+	if err != nil {
+		return nil, err
+	}
+	buffers, err := common.SysctlUint("vfs.bufspace")
+	if err != nil {
+		return nil, err
+	}
+	wired, err := common.SysctlUint("vm.stats.vm.v_wire_count")
+	if err != nil {
+		return nil, err
+	}
+	var cached, laundry uint64
+	osreldate, _ := common.SysctlUint("kern.osreldate")
+	if osreldate < 1102000 {
+		cached, err = common.SysctlUint("vm.stats.vm.v_cache_count")
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		laundry, err = common.SysctlUint("vm.stats.vm.v_laundry_count")
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	p := pageSize
+	ret := &VirtualMemoryStat{
+		Total:    physmem,
+		Free:     free * p,
+		Active:   active * p,
+		Inactive: inactive * p,
+		Cached:   cached * p,
+		Buffers:  buffers,
+		Wired:    wired * p,
+		Laundry:  laundry * p,
+	}
+
+	ret.Available = ret.Inactive + ret.Cached + ret.Free + ret.Laundry
+	ret.Used = ret.Total - ret.Available
+	ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+	return ret, nil
+}
+
+// Return swapinfo
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+// Constants from vm/vm_param.h
+const (
+	XSWDEV_VERSION11 = 1
+	XSWDEV_VERSION   = 2
+)
+
+// Types from vm/vm_param.h
+type xswdev struct {
+	Version uint32 // Version is the version
+	Dev     uint64 // Dev is the device identifier
+	Flags   int32  // Flags is the swap flags applied to the device
+	NBlks   int32  // NBlks is the total number of blocks
+	Used    int32  // Used is the number of blocks used
+}
+
+// xswdev11 is a compatibility for under FreeBSD 11
+// sys/vm/swap_pager.c
+type xswdev11 struct {
+	Version uint32 // Version is the version
+	Dev     uint32 // Dev is the device identifier
+	Flags   int32  // Flags is the swap flags applied to the device
+	NBlks   int32  // NBlks is the total number of blocks
+	Used    int32  // Used is the number of blocks used
+}
+
+func SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {
+	// FreeBSD can have multiple swap devices so we total them up
+	i, err := common.SysctlUint("vm.nswapdev")
+	if err != nil {
+		return nil, err
+	}
+
+	if i == 0 {
+		return nil, errors.New("no swap devices found")
+	}
+
+	c := int(i)
+
+	i, err = common.SysctlUint("vm.stats.vm.v_page_size")
+	if err != nil {
+		return nil, err
+	}
+	pageSize := i
+
+	var buf []byte
+	s := &SwapMemoryStat{}
+	for n := 0; n < c; n++ {
+		buf, err = unix.SysctlRaw("vm.swap_info", n)
+		if err != nil {
+			return nil, err
+		}
+
+		// first, try to parse with version 2
+		xsw := (*xswdev)(unsafe.Pointer(&buf[0]))
+		switch {
+		case xsw.Version == XSWDEV_VERSION11:
+			// this is version 1, so try to parse again
+			xsw := (*xswdev11)(unsafe.Pointer(&buf[0]))
+			if xsw.Version != XSWDEV_VERSION11 {
+				return nil, errors.New("xswdev version mismatch(11)")
+			}
+			s.Total += uint64(xsw.NBlks)
+			s.Used += uint64(xsw.Used)
+		case xsw.Version != XSWDEV_VERSION:
+			return nil, errors.New("xswdev version mismatch")
+		default:
+			s.Total += uint64(xsw.NBlks)
+			s.Used += uint64(xsw.Used)
+		}
+
+	}
+
+	if s.Total != 0 {
+		s.UsedPercent = float64(s.Used) / float64(s.Total) * 100
+	}
+	s.Total *= pageSize
+	s.Used *= pageSize
+	s.Free = s.Total - s.Used
+
+	return s, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go
new file mode 100644
index 000000000..a888c5bad
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_linux.go
@@ -0,0 +1,524 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package mem
+
+import (
+	"bufio"
+	"context"
+	"fmt"
+	"io"
+	"math"
+	"os"
+	"strconv"
+	"strings"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+	vm, _, err := fillFromMeminfoWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return vm, nil
+}
+
+func fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *ExVirtualMemory, error) {
+	filename := common.HostProcWithContext(ctx, "meminfo")
+	lines, err := common.ReadLines(filename)
+	if err != nil {
+		return nil, nil, fmt.Errorf("couldn't read %s: %w", filename, err)
+	}
+
+	// flag if MemAvailable is in /proc/meminfo (kernel 3.14+)
+	memavail := false
+	activeFile := false   // "Active(file)" not available: 2.6.28 / Dec 2008
+	inactiveFile := false // "Inactive(file)" not available: 2.6.28 / Dec 2008
+	sReclaimable := false // "Sreclaimable:" not available: 2.6.19 / Nov 2006
+
+	ret := &VirtualMemoryStat{}
+	retEx := &ExVirtualMemory{}
+
+	for _, line := range lines {
+		fields := strings.Split(line, ":")
+		if len(fields) != 2 {
+			continue
+		}
+		key := strings.TrimSpace(fields[0])
+		value := strings.TrimSpace(fields[1])
+		value = strings.ReplaceAll(value, " kB", "")
+
+		switch key {
+		case "MemTotal":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Total = t * 1024
+		case "MemFree":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Free = t * 1024
+		case "MemAvailable":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			memavail = true
+			ret.Available = t * 1024
+		case "Buffers":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Buffers = t * 1024
+		case "Cached":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Cached = t * 1024
+		case "Active":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Active = t * 1024
+		case "Inactive":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Inactive = t * 1024
+		case "Active(anon)":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			retEx.ActiveAnon = t * 1024
+		case "Inactive(anon)":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			retEx.InactiveAnon = t * 1024
+		case "Active(file)":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			activeFile = true
+			retEx.ActiveFile = t * 1024
+		case "Inactive(file)":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			inactiveFile = true
+			retEx.InactiveFile = t * 1024
+		case "Unevictable":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			retEx.Unevictable = t * 1024
+		case "Percpu":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			retEx.Percpu = t * 1024
+		case "Writeback":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.WriteBack = t * 1024
+		case "WritebackTmp":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.WriteBackTmp = t * 1024
+		case "Dirty":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Dirty = t * 1024
+		case "Shmem":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Shared = t * 1024
+		case "Slab":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Slab = t * 1024
+		case "SReclaimable":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			sReclaimable = true
+			ret.Sreclaimable = t * 1024
+		case "SUnreclaim":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Sunreclaim = t * 1024
+		case "KernelStack":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			retEx.KernelStack = t * 1024
+		case "PageTables":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.PageTables = t * 1024
+		case "SwapCached":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.SwapCached = t * 1024
+		case "CommitLimit":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.CommitLimit = t * 1024
+		case "Committed_AS":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.CommittedAS = t * 1024
+		case "HighTotal":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.HighTotal = t * 1024
+		case "HighFree":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.HighFree = t * 1024
+		case "LowTotal":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.LowTotal = t * 1024
+		case "LowFree":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.LowFree = t * 1024
+		case "SwapTotal":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.SwapTotal = t * 1024
+		case "SwapFree":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.SwapFree = t * 1024
+		case "Mapped":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.Mapped = t * 1024
+		case "VmallocTotal":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.VmallocTotal = t * 1024
+		case "VmallocUsed":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.VmallocUsed = t * 1024
+		case "VmallocChunk":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.VmallocChunk = t * 1024
+		case "HugePages_Total":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.HugePagesTotal = t
+		case "HugePages_Free":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.HugePagesFree = t
+		case "HugePages_Rsvd":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.HugePagesRsvd = t
+		case "HugePages_Surp":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.HugePagesSurp = t
+		case "Hugepagesize":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.HugePageSize = t * 1024
+		case "AnonHugePages":
+			t, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return ret, retEx, err
+			}
+			ret.AnonHugePages = t * 1024
+		}
+	}
+
+	ret.Cached += ret.Sreclaimable
+
+	if !memavail {
+		if activeFile && inactiveFile && sReclaimable {
+			ret.Available = calculateAvailVmem(ctx, ret, retEx)
+		} else {
+			ret.Available = ret.Cached + ret.Free
+		}
+	}
+	ret.Used = ret.Total - ret.Available
+
+	ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+	return ret, retEx, nil
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+	sysinfo := &unix.Sysinfo_t{}
+
+	if err := unix.Sysinfo(sysinfo); err != nil {
+		return nil, err
+	}
+	ret := &SwapMemoryStat{
+		Total: uint64(sysinfo.Totalswap) * uint64(sysinfo.Unit),
+		Free:  uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit),
+	}
+	ret.Used = ret.Total - ret.Free
+	// check Infinity
+	if ret.Total != 0 {
+		ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0
+	} else {
+		ret.UsedPercent = 0
+	}
+	filename := common.HostProcWithContext(ctx, "vmstat")
+	lines, err := common.ReadLines(filename)
+	if err != nil {
+		return nil, fmt.Errorf("couldn't read %s: %w", filename, err)
+	}
+	for _, l := range lines {
+		fields := strings.Fields(l)
+		if len(fields) < 2 {
+			continue
+		}
+		switch fields[0] {
+		case "pswpin":
+			value, err := strconv.ParseUint(fields[1], 10, 64)
+			if err != nil {
+				continue
+			}
+			ret.Sin = value * 4 * 1024
+		case "pswpout":
+			value, err := strconv.ParseUint(fields[1], 10, 64)
+			if err != nil {
+				continue
+			}
+			ret.Sout = value * 4 * 1024
+		case "pgpgin":
+			value, err := strconv.ParseUint(fields[1], 10, 64)
+			if err != nil {
+				continue
+			}
+			ret.PgIn = value * 4 * 1024
+		case "pgpgout":
+			value, err := strconv.ParseUint(fields[1], 10, 64)
+			if err != nil {
+				continue
+			}
+			ret.PgOut = value * 4 * 1024
+		case "pgfault":
+			value, err := strconv.ParseUint(fields[1], 10, 64)
+			if err != nil {
+				continue
+			}
+			ret.PgFault = value * 4 * 1024
+		case "pgmajfault":
+			value, err := strconv.ParseUint(fields[1], 10, 64)
+			if err != nil {
+				continue
+			}
+			ret.PgMajFault = value * 4 * 1024
+		}
+	}
+	return ret, nil
+}
+
+// calculateAvailVmem is a fallback under kernel 3.14 where /proc/meminfo does not provide
+// "MemAvailable:" column. It reimplements an algorithm from the link below
+// https://github.com/giampaolo/psutil/pull/890
+func calculateAvailVmem(ctx context.Context, ret *VirtualMemoryStat, retEx *ExVirtualMemory) uint64 {
+	var watermarkLow uint64
+
+	fn := common.HostProcWithContext(ctx, "zoneinfo")
+	lines, err := common.ReadLines(fn)
+	if err != nil {
+		return ret.Free + ret.Cached // fallback under kernel 2.6.13
+	}
+
+	pagesize := uint64(os.Getpagesize())
+	watermarkLow = 0
+
+	for _, line := range lines {
+		fields := strings.Fields(line)
+
+		if strings.HasPrefix(fields[0], "low") {
+			lowValue, err := strconv.ParseUint(fields[1], 10, 64)
+			if err != nil {
+				lowValue = 0
+			}
+			watermarkLow += lowValue
+		}
+	}
+
+	watermarkLow *= pagesize
+
+	availMemory := ret.Free - watermarkLow
+	pageCache := retEx.ActiveFile + retEx.InactiveFile
+	pageCache -= uint64(math.Min(float64(pageCache/2), float64(watermarkLow)))
+	availMemory += pageCache
+	availMemory += ret.Sreclaimable - uint64(math.Min(float64(ret.Sreclaimable/2.0), float64(watermarkLow)))
+
+	if availMemory < 0 {
+		availMemory = 0
+	}
+
+	return availMemory
+}
+
+const swapsFilename = "swaps"
+
+// swaps file column indexes
+const (
+	nameCol = 0
+	// typeCol     = 1
+	totalCol = 2
+	usedCol  = 3
+	// priorityCol = 4
+)
+
+func SwapDevices() ([]*SwapDevice, error) {
+	return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+	swapsFilePath := common.HostProcWithContext(ctx, swapsFilename)
+	f, err := os.Open(swapsFilePath)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	return parseSwapsFile(ctx, f)
+}
+
+func parseSwapsFile(ctx context.Context, r io.Reader) ([]*SwapDevice, error) {
+	swapsFilePath := common.HostProcWithContext(ctx, swapsFilename)
+	scanner := bufio.NewScanner(r)
+	if !scanner.Scan() {
+		if err := scanner.Err(); err != nil {
+			return nil, fmt.Errorf("couldn't read file %q: %w", swapsFilePath, err)
+		}
+		return nil, fmt.Errorf("unexpected end-of-file in %q", swapsFilePath)
+
+	}
+
+	// Check header headerFields are as expected
+	headerFields := strings.Fields(scanner.Text())
+	if len(headerFields) < usedCol {
+		return nil, fmt.Errorf("couldn't parse %q: too few fields in header", swapsFilePath)
+	}
+	if headerFields[nameCol] != "Filename" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[nameCol], "Filename")
+	}
+	if headerFields[totalCol] != "Size" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[totalCol], "Size")
+	}
+	if headerFields[usedCol] != "Used" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapsFilePath, headerFields[usedCol], "Used")
+	}
+
+	var swapDevices []*SwapDevice
+	for scanner.Scan() {
+		fields := strings.Fields(scanner.Text())
+		if len(fields) < usedCol {
+			return nil, fmt.Errorf("couldn't parse %q: too few fields", swapsFilePath)
+		}
+
+		totalKiB, err := strconv.ParseUint(fields[totalCol], 10, 64)
+		if err != nil {
+			return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapsFilePath, err)
+		}
+
+		usedKiB, err := strconv.ParseUint(fields[usedCol], 10, 64)
+		if err != nil {
+			return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapsFilePath, err)
+		}
+
+		swapDevices = append(swapDevices, &SwapDevice{
+			Name:      fields[nameCol],
+			UsedBytes: usedKiB * 1024,
+			FreeBytes: (totalKiB - usedKiB) * 1024,
+		})
+	}
+
+	if err := scanner.Err(); err != nil {
+		return nil, fmt.Errorf("couldn't read file %q: %w", swapsFilePath, err)
+	}
+
+	return swapDevices, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_netbsd.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_netbsd.go
new file mode 100644
index 000000000..2efa1199c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_netbsd.go
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build netbsd
+
+package mem
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	"golang.org/x/sys/unix"
+)
+
+func GetPageSize() (uint64, error) {
+	return GetPageSizeWithContext(context.Background())
+}
+
+func GetPageSizeWithContext(_ context.Context) (uint64, error) {
+	uvmexp, err := unix.SysctlUvmexp("vm.uvmexp2")
+	if err != nil {
+		return 0, err
+	}
+	return uint64(uvmexp.Pagesize), nil
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {
+	uvmexp, err := unix.SysctlUvmexp("vm.uvmexp2")
+	if err != nil {
+		return nil, err
+	}
+	p := uint64(uvmexp.Pagesize)
+
+	ret := &VirtualMemoryStat{
+		Total:    uint64(uvmexp.Npages) * p,
+		Free:     uint64(uvmexp.Free) * p,
+		Active:   uint64(uvmexp.Active) * p,
+		Inactive: uint64(uvmexp.Inactive) * p,
+		Cached:   0, // not available
+		Wired:    uint64(uvmexp.Wired) * p,
+	}
+
+	ret.Available = ret.Inactive + ret.Cached + ret.Free
+	ret.Used = ret.Total - ret.Available
+	ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+	// Get buffers from vm.bufmem sysctl
+	ret.Buffers, err = unix.SysctlUint64("vm.bufmem")
+	if err != nil {
+		return nil, err
+	}
+
+	return ret, nil
+}
+
+// Return swapctl summary info
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+// Reference: https://man.netbsd.org/swapctl.8
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+	out, err := invoke.CommandWithContext(ctx, "swapctl", "-sk")
+	if err != nil {
+		return &SwapMemoryStat{}, nil
+	}
+
+	line := string(out)
+	var total, used, free uint64
+
+	_, err = fmt.Sscanf(line,
+		"total: %d KBytes allocated, %d KBytes used, %d KBytes available",
+		&total, &used, &free)
+	if err != nil {
+		return nil, errors.New("failed to parse swapctl output")
+	}
+
+	percent := float64(used) / float64(total) * 100
+	return &SwapMemoryStat{
+		Total:       total * 1024,
+		Used:        used * 1024,
+		Free:        free * 1024,
+		UsedPercent: percent,
+	}, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd.go
new file mode 100644
index 000000000..69d8a8116
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd.go
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package mem
+
+import (
+	"bytes"
+	"context"
+	"encoding/binary"
+	"errors"
+	"fmt"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func GetPageSize() (uint64, error) {
+	return GetPageSizeWithContext(context.Background())
+}
+
+func GetPageSizeWithContext(_ context.Context) (uint64, error) {
+	uvmexp, err := unix.SysctlUvmexp("vm.uvmexp")
+	if err != nil {
+		return 0, err
+	}
+	return uint64(uvmexp.Pagesize), nil
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {
+	uvmexp, err := unix.SysctlUvmexp("vm.uvmexp")
+	if err != nil {
+		return nil, err
+	}
+	p := uint64(uvmexp.Pagesize)
+
+	mib := []int32{CTLVfs, VfsGeneric, VfsBcacheStat}
+	buf, length, err := common.CallSyscall(mib)
+	if err != nil {
+		return nil, err
+	}
+	if length < sizeOfBcachestats {
+		return nil, fmt.Errorf("short syscall ret %d bytes", length)
+	}
+	var bcs Bcachestats
+	br := bytes.NewReader(buf)
+	if err := binary.Read(br, binary.LittleEndian, &bcs); err != nil {
+		return nil, err
+	}
+	// On OpenBSD, the buffer cache is the closest equivalent to both
+	// Linux's Buffers and Cached memory.
+	bcache := uint64(bcs.Numbufpages) * p
+
+	ret := &VirtualMemoryStat{
+		Total:    uint64(uvmexp.Npages) * p,
+		Free:     uint64(uvmexp.Free) * p,
+		Active:   uint64(uvmexp.Active) * p,
+		Inactive: uint64(uvmexp.Inactive) * p,
+		Cached:   bcache,
+		Buffers:  bcache,
+		Wired:    uint64(uvmexp.Wired) * p,
+	}
+
+	ret.Available = ret.Inactive + ret.Cached + ret.Free
+	ret.Used = ret.Total - ret.Available
+	ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
+
+	return ret, nil
+}
+
+// Return swapctl summary info
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+	out, err := invoke.CommandWithContext(ctx, "swapctl", "-sk")
+	if err != nil {
+		return &SwapMemoryStat{}, nil
+	}
+
+	line := string(out)
+	var total, used, free uint64
+
+	_, err = fmt.Sscanf(line,
+		"total: %d 1K-blocks allocated, %d used, %d available",
+		&total, &used, &free)
+	if err != nil {
+		return nil, errors.New("failed to parse swapctl output")
+	}
+
+	percent := float64(used) / float64(total) * 100
+	return &SwapMemoryStat{
+		Total:       total * 1024,
+		Used:        used * 1024,
+		Free:        free * 1024,
+		UsedPercent: percent,
+	}, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_386.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_386.go
new file mode 100644
index 000000000..552e93f4a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_386.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && 386
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs mem/types_openbsd.go
+
+package mem
+
+const (
+	CTLVfs        = 10
+	VfsGeneric    = 0
+	VfsBcacheStat = 3
+)
+
+const (
+	sizeOfBcachestats = 0x90
+)
+
+type Bcachestats struct {
+	Numbufs       int64
+	Numbufpages   int64
+	Numdirtypages int64
+	Numcleanpages int64
+	Pendingwrites int64
+	Pendingreads  int64
+	Numwrites     int64
+	Numreads      int64
+	Cachehits     int64
+	Busymapped    int64
+	Dmapages      int64
+	Highpages     int64
+	Delwribufs    int64
+	Kvaslots      int64
+	Avail         int64
+	Highflips     int64
+	Highflops     int64
+	Dmaflips      int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_amd64.go
new file mode 100644
index 000000000..73e5b72aa
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_amd64.go
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package mem
+
+const (
+	CTLVfs        = 10
+	VfsGeneric    = 0
+	VfsBcacheStat = 3
+)
+
+const (
+	sizeOfBcachestats = 0x78
+)
+
+type Bcachestats struct {
+	Numbufs       int64
+	Numbufpages   int64
+	Numdirtypages int64
+	Numcleanpages int64
+	Pendingwrites int64
+	Pendingreads  int64
+	Numwrites     int64
+	Numreads      int64
+	Cachehits     int64
+	Busymapped    int64
+	Dmapages      int64
+	Highpages     int64
+	Delwribufs    int64
+	Kvaslots      int64
+	Avail         int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm.go
new file mode 100644
index 000000000..57b5861de
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && arm
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs mem/types_openbsd.go
+
+package mem
+
+const (
+	CTLVfs        = 10
+	VfsGeneric    = 0
+	VfsBcacheStat = 3
+)
+
+const (
+	sizeOfBcachestats = 0x90
+)
+
+type Bcachestats struct {
+	Numbufs       int64
+	Numbufpages   int64
+	Numdirtypages int64
+	Numcleanpages int64
+	Pendingwrites int64
+	Pendingreads  int64
+	Numwrites     int64
+	Numreads      int64
+	Cachehits     int64
+	Busymapped    int64
+	Dmapages      int64
+	Highpages     int64
+	Delwribufs    int64
+	Kvaslots      int64
+	Avail         int64
+	Highflips     int64
+	Highflops     int64
+	Dmaflips      int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm64.go
new file mode 100644
index 000000000..f39a6456b
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_arm64.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && arm64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs mem/types_openbsd.go
+
+package mem
+
+const (
+	CTLVfs        = 10
+	VfsGeneric    = 0
+	VfsBcacheStat = 3
+)
+
+const (
+	sizeOfBcachestats = 0x90
+)
+
+type Bcachestats struct {
+	Numbufs       int64
+	Numbufpages   int64
+	Numdirtypages int64
+	Numcleanpages int64
+	Pendingwrites int64
+	Pendingreads  int64
+	Numwrites     int64
+	Numreads      int64
+	Cachehits     int64
+	Busymapped    int64
+	Dmapages      int64
+	Highpages     int64
+	Delwribufs    int64
+	Kvaslots      int64
+	Avail         int64
+	Highflips     int64
+	Highflops     int64
+	Dmaflips      int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_riscv64.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_riscv64.go
new file mode 100644
index 000000000..f9f838f54
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_openbsd_riscv64.go
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && riscv64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs mem/types_openbsd.go
+
+package mem
+
+const (
+	CTLVfs        = 10
+	VfsGeneric    = 0
+	VfsBcacheStat = 3
+)
+
+const (
+	sizeOfBcachestats = 0x90
+)
+
+type Bcachestats struct {
+	Numbufs       int64
+	Numbufpages   int64
+	Numdirtypages int64
+	Numcleanpages int64
+	Pendingwrites int64
+	Pendingreads  int64
+	Numwrites     int64
+	Numreads      int64
+	Cachehits     int64
+	Busymapped    int64
+	Dmapages      int64
+	Highpages     int64
+	Delwribufs    int64
+	Kvaslots      int64
+	Avail         int64
+	Highflips     int64
+	Highflops     int64
+	Dmaflips      int64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_plan9.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_plan9.go
new file mode 100644
index 000000000..0df0745c7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_plan9.go
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build plan9
+
+package mem
+
+import (
+	"context"
+	"os"
+
+	stats "github.com/lufia/plan9stats"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
+	root := os.Getenv("HOST_ROOT")
+	m, err := stats.ReadMemStats(ctx, stats.WithRootDir(root))
+	if err != nil {
+		return nil, err
+	}
+	u := 0.0
+	if m.SwapPages.Avail != 0 {
+		u = float64(m.SwapPages.Used) / float64(m.SwapPages.Avail) * 100.0
+	}
+	return &SwapMemoryStat{
+		Total:       uint64(m.SwapPages.Avail * m.PageSize),
+		Used:        uint64(m.SwapPages.Used * m.PageSize),
+		Free:        uint64(m.SwapPages.Free() * m.PageSize),
+		UsedPercent: u,
+	}, nil
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+	root := os.Getenv("HOST_ROOT")
+	m, err := stats.ReadMemStats(ctx, stats.WithRootDir(root))
+	if err != nil {
+		return nil, err
+	}
+	u := 0.0
+	if m.UserPages.Avail != 0 {
+		u = float64(m.UserPages.Used) / float64(m.UserPages.Avail) * 100.0
+	}
+	return &VirtualMemoryStat{
+		Total:       uint64(m.Total),
+		Available:   uint64(m.UserPages.Free() * m.PageSize),
+		Used:        uint64(m.UserPages.Used * m.PageSize),
+		UsedPercent: u,
+		Free:        uint64(m.UserPages.Free() * m.PageSize),
+
+		SwapTotal: uint64(m.SwapPages.Avail * m.PageSize),
+		SwapFree:  uint64(m.SwapPages.Free() * m.PageSize),
+	}, nil
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+	return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(_ context.Context) ([]*SwapDevice, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_solaris.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_solaris.go
new file mode 100644
index 000000000..1a391dc4b
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_solaris.go
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build solaris
+
+package mem
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/tklauser/go-sysconf"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// VirtualMemory for Solaris is a minimal implementation which only returns
+// what Nomad needs. It does take into account global vs zone, however.
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
+	result := &VirtualMemoryStat{}
+
+	zoneName, err := zoneName(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	if zoneName == "global" {
+		capacity, err := globalZoneMemoryCapacity(ctx)
+		if err != nil {
+			return nil, err
+		}
+		result.Total = capacity
+		freemem, err := globalZoneFreeMemory(ctx)
+		if err != nil {
+			return nil, err
+		}
+		result.Available = freemem
+		result.Free = freemem
+		result.Used = result.Total - result.Free
+	} else {
+		capacity, err := nonGlobalZoneMemoryCapacity(ctx)
+		if err != nil {
+			return nil, err
+		}
+		result.Total = capacity
+	}
+
+	return result, nil
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func zoneName(ctx context.Context) (string, error) {
+	out, err := invoke.CommandWithContext(ctx, "zonename")
+	if err != nil {
+		return "", err
+	}
+
+	return strings.TrimSpace(string(out)), nil
+}
+
+var globalZoneMemoryCapacityMatch = regexp.MustCompile(`[Mm]emory size: (\d+) Megabytes`)
+
+func globalZoneMemoryCapacity(ctx context.Context) (uint64, error) {
+	out, err := invoke.CommandWithContext(ctx, "prtconf")
+	if err != nil {
+		return 0, err
+	}
+
+	match := globalZoneMemoryCapacityMatch.FindAllStringSubmatch(string(out), -1)
+	if len(match) != 1 {
+		return 0, errors.New("memory size not contained in output of prtconf")
+	}
+
+	totalMB, err := strconv.ParseUint(match[0][1], 10, 64)
+	if err != nil {
+		return 0, err
+	}
+
+	return totalMB * 1024 * 1024, nil
+}
+
+func globalZoneFreeMemory(ctx context.Context) (uint64, error) {
+	output, err := invoke.CommandWithContext(ctx, "pagesize")
+	if err != nil {
+		return 0, err
+	}
+
+	pagesize, err := strconv.ParseUint(strings.TrimSpace(string(output)), 10, 64)
+	if err != nil {
+		return 0, err
+	}
+
+	free, err := sysconf.Sysconf(sysconf.SC_AVPHYS_PAGES)
+	if err != nil {
+		return 0, err
+	}
+
+	return uint64(free) * pagesize, nil
+}
+
+var kstatMatch = regexp.MustCompile(`(\S+)\s+(\S*)`)
+
+func nonGlobalZoneMemoryCapacity(ctx context.Context) (uint64, error) {
+	out, err := invoke.CommandWithContext(ctx, "kstat", "-p", "-c", "zone_memory_cap", "memory_cap:*:*:physcap")
+	if err != nil {
+		return 0, err
+	}
+
+	kstats := kstatMatch.FindAllStringSubmatch(string(out), -1)
+	if len(kstats) != 1 {
+		return 0, fmt.Errorf("expected 1 kstat, found %d", len(kstats))
+	}
+
+	memSizeBytes, err := strconv.ParseUint(kstats[0][2], 10, 64)
+	if err != nil {
+		return 0, err
+	}
+
+	return memSizeBytes, nil
+}
+
+const swapCommand = "swap"
+
+// The blockSize as reported by `swap -l`. See https://docs.oracle.com/cd/E23824_01/html/821-1459/fsswap-52195.html
+const blockSize = 512
+
+// swapctl column indexes
+const (
+	nameCol = 0
+	// devCol = 1
+	// swaploCol = 2
+	totalBlocksCol = 3
+	freeBlocksCol  = 4
+)
+
+func SwapDevices() ([]*SwapDevice, error) {
+	return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
+	output, err := invoke.CommandWithContext(ctx, swapCommand, "-l")
+	if err != nil {
+		return nil, fmt.Errorf("could not execute %q: %w", swapCommand, err)
+	}
+
+	return parseSwapsCommandOutput(string(output))
+}
+
+func parseSwapsCommandOutput(output string) ([]*SwapDevice, error) {
+	lines := strings.Split(output, "\n")
+	if len(lines) == 0 {
+		return nil, fmt.Errorf("could not parse output of %q: no lines in %q", swapCommand, output)
+	}
+
+	// Check header headerFields are as expected.
+	headerFields := strings.Fields(lines[0])
+	if len(headerFields) < freeBlocksCol {
+		return nil, fmt.Errorf("couldn't parse %q: too few fields in header %q", swapCommand, lines[0])
+	}
+	if headerFields[nameCol] != "swapfile" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[nameCol], "swapfile")
+	}
+	if headerFields[totalBlocksCol] != "blocks" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[totalBlocksCol], "blocks")
+	}
+	if headerFields[freeBlocksCol] != "free" {
+		return nil, fmt.Errorf("couldn't parse %q: expected %q to be %q", swapCommand, headerFields[freeBlocksCol], "free")
+	}
+
+	var swapDevices []*SwapDevice
+	for _, line := range lines[1:] {
+		if line == "" {
+			continue // the terminal line is typically empty
+		}
+		fields := strings.Fields(line)
+		if len(fields) < freeBlocksCol {
+			return nil, fmt.Errorf("couldn't parse %q: too few fields", swapCommand)
+		}
+
+		totalBlocks, err := strconv.ParseUint(fields[totalBlocksCol], 10, 64)
+		if err != nil {
+			return nil, fmt.Errorf("couldn't parse 'Size' column in %q: %w", swapCommand, err)
+		}
+
+		freeBlocks, err := strconv.ParseUint(fields[freeBlocksCol], 10, 64)
+		if err != nil {
+			return nil, fmt.Errorf("couldn't parse 'Used' column in %q: %w", swapCommand, err)
+		}
+
+		swapDevices = append(swapDevices, &SwapDevice{
+			Name:      fields[nameCol],
+			UsedBytes: (totalBlocks - freeBlocks) * blockSize,
+			FreeBytes: freeBlocks * blockSize,
+		})
+	}
+
+	return swapDevices, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/mem/mem_windows.go b/vendor/github.com/shirou/gopsutil/v4/mem/mem_windows.go
new file mode 100644
index 000000000..f7421f647
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/mem/mem_windows.go
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package mem
+
+import (
+	"context"
+	"sync"
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var (
+	procEnumPageFilesW       = common.ModPsapi.NewProc("EnumPageFilesW")
+	procGetNativeSystemInfo  = common.Modkernel32.NewProc("GetNativeSystemInfo")
+	procGetPerformanceInfo   = common.ModPsapi.NewProc("GetPerformanceInfo")
+	procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
+)
+
+type memoryStatusEx struct {
+	cbSize                  uint32
+	dwMemoryLoad            uint32
+	ullTotalPhys            uint64 // in bytes
+	ullAvailPhys            uint64
+	ullTotalPageFile        uint64
+	ullAvailPageFile        uint64
+	ullTotalVirtual         uint64
+	ullAvailVirtual         uint64
+	ullAvailExtendedVirtual uint64
+}
+
+func VirtualMemory() (*VirtualMemoryStat, error) {
+	return VirtualMemoryWithContext(context.Background())
+}
+
+func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) {
+	var memInfo memoryStatusEx
+	memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
+	// GlobalMemoryStatusEx returns 0 for error, in which case we check err,
+	// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call
+	mem, _, err := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
+	if mem == 0 {
+		return nil, err
+	}
+
+	ret := &VirtualMemoryStat{
+		Total:       memInfo.ullTotalPhys,
+		Available:   memInfo.ullAvailPhys,
+		Free:        memInfo.ullAvailPhys,
+		UsedPercent: float64(memInfo.dwMemoryLoad),
+	}
+
+	ret.Used = ret.Total - ret.Available
+	return ret, nil
+}
+
+type performanceInformation struct {
+	cb                uint32
+	commitTotal       uint64
+	commitLimit       uint64
+	commitPeak        uint64
+	physicalTotal     uint64
+	physicalAvailable uint64
+	systemCache       uint64
+	kernelTotal       uint64
+	kernelPaged       uint64
+	kernelNonpaged    uint64
+	pageSize          uint64
+	handleCount       uint32
+	processCount      uint32
+	threadCount       uint32
+}
+
+func SwapMemory() (*SwapMemoryStat, error) {
+	return SwapMemoryWithContext(context.Background())
+}
+
+func SwapMemoryWithContext(_ context.Context) (*SwapMemoryStat, error) {
+	// Use the performance counter to get the swap usage percentage
+	counter, err := common.NewWin32PerformanceCounter("swap_percentage", `\Paging File(_Total)\% Usage`)
+	if err != nil {
+		return nil, err
+	}
+	defer common.PdhCloseQuery.Call(uintptr(counter.Query))
+
+	usedPercent, err := counter.GetValue()
+	if err != nil {
+		return nil, err
+	}
+
+	// Get total memory from performance information
+	var perfInfo performanceInformation
+	perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
+	// GetPerformanceInfo returns 0 for error, in which case we check err,
+	// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call
+	mem, _, err := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
+	if mem == 0 {
+		return nil, err
+	}
+	totalPhys := perfInfo.physicalTotal * perfInfo.pageSize
+	totalSys := perfInfo.commitLimit * perfInfo.pageSize
+	total := totalSys - totalPhys
+
+	var used uint64
+	if total > 0 {
+		used = uint64(0.01 * usedPercent * float64(total))
+	} else {
+		usedPercent = 0.0
+		used = 0
+	}
+
+	ret := &SwapMemoryStat{
+		Total:       total,
+		Used:        used,
+		Free:        total - used,
+		UsedPercent: common.Round(usedPercent, 1),
+	}
+
+	return ret, nil
+}
+
+var (
+	pageSize     uint64
+	pageSizeOnce sync.Once
+)
+
+type systemInfo struct {
+	wProcessorArchitecture      uint16
+	wReserved                   uint16
+	dwPageSize                  uint32
+	lpMinimumApplicationAddress uintptr
+	lpMaximumApplicationAddress uintptr
+	dwActiveProcessorMask       uintptr
+	dwNumberOfProcessors        uint32
+	dwProcessorType             uint32
+	dwAllocationGranularity     uint32
+	wProcessorLevel             uint16
+	wProcessorRevision          uint16
+}
+
+// system type as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-enum_page_file_information
+type enumPageFileInformation struct {
+	cb         uint32
+	reserved   uint32
+	totalSize  uint64
+	totalInUse uint64
+	peakUsage  uint64
+}
+
+func SwapDevices() ([]*SwapDevice, error) {
+	return SwapDevicesWithContext(context.Background())
+}
+
+func SwapDevicesWithContext(_ context.Context) ([]*SwapDevice, error) {
+	pageSizeOnce.Do(func() {
+		var sysInfo systemInfo
+		procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sysInfo)))
+		pageSize = uint64(sysInfo.dwPageSize)
+	})
+
+	// the following system call invokes the supplied callback function once for each page file before returning
+	// see https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumpagefilesw
+	var swapDevices []*SwapDevice
+	// EnumPageFilesW returns 0 for error, in which case we check err,
+	// see https://pkg.go.dev/golang.org/x/sys/windows#LazyProc.Call
+	result, _, err := procEnumPageFilesW.Call(windows.NewCallback(pEnumPageFileCallbackW), uintptr(unsafe.Pointer(&swapDevices)))
+	if result == 0 {
+		return nil, err
+	}
+
+	return swapDevices, nil
+}
+
+// system callback as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/nc-psapi-penum_page_file_callbackw
+func pEnumPageFileCallbackW(swapDevices *[]*SwapDevice, enumPageFileInfo *enumPageFileInformation, lpFilenamePtr *[syscall.MAX_LONG_PATH]uint16) *bool {
+	*swapDevices = append(*swapDevices, &SwapDevice{
+		Name:      syscall.UTF16ToString((*lpFilenamePtr)[:]),
+		UsedBytes: enumPageFileInfo.totalInUse * pageSize,
+		FreeBytes: (enumPageFileInfo.totalSize - enumPageFileInfo.totalInUse) * pageSize,
+	})
+
+	// return true to continue enumerating page files
+	ret := true
+	return &ret
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net.go b/vendor/github.com/shirou/gopsutil/v4/net/net.go
new file mode 100644
index 000000000..384e5673a
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net.go
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package net
+
+import (
+	"context"
+	"encoding/json"
+	"net"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var invoke common.Invoker = common.Invoke{}
+
+type IOCountersStat struct {
+	Name        string `json:"name"`        // interface name
+	BytesSent   uint64 `json:"bytesSent"`   // number of bytes sent
+	BytesRecv   uint64 `json:"bytesRecv"`   // number of bytes received
+	PacketsSent uint64 `json:"packetsSent"` // number of packets sent
+	PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
+	Errin       uint64 `json:"errin"`       // total number of errors while receiving
+	Errout      uint64 `json:"errout"`      // total number of errors while sending
+	Dropin      uint64 `json:"dropin"`      // total number of incoming packets which were dropped
+	Dropout     uint64 `json:"dropout"`     // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
+	Fifoin      uint64 `json:"fifoin"`      // total number of FIFO buffers errors while receiving
+	Fifoout     uint64 `json:"fifoout"`     // total number of FIFO buffers errors while sending
+}
+
+// Addr is implemented compatibility to psutil
+type Addr struct {
+	IP   string `json:"ip"`
+	Port uint32 `json:"port"`
+}
+
+type ConnectionStat struct {
+	Fd     uint32  `json:"fd"`
+	Family uint32  `json:"family"`
+	Type   uint32  `json:"type"`
+	Laddr  Addr    `json:"localaddr"`
+	Raddr  Addr    `json:"remoteaddr"`
+	Status string  `json:"status"`
+	Uids   []int32 `json:"uids"`
+	Pid    int32   `json:"pid"`
+}
+
+// System wide stats about different network protocols
+type ProtoCountersStat struct {
+	Protocol string           `json:"protocol"`
+	Stats    map[string]int64 `json:"stats"`
+}
+
+// NetInterfaceAddr is designed for represent interface addresses
+type InterfaceAddr struct {
+	Addr string `json:"addr"`
+}
+
+// InterfaceAddrList is a list of InterfaceAddr
+type InterfaceAddrList []InterfaceAddr
+
+type InterfaceStat struct {
+	Index        int               `json:"index"`
+	MTU          int               `json:"mtu"`          // maximum transmission unit
+	Name         string            `json:"name"`         // e.g., "en0", "lo0", "eth0.100"
+	HardwareAddr string            `json:"hardwareAddr"` // IEEE MAC-48, EUI-48 and EUI-64 form
+	Flags        []string          `json:"flags"`        // e.g., FlagUp, FlagLoopback, FlagMulticast
+	Addrs        InterfaceAddrList `json:"addrs"`
+}
+
+// InterfaceStatList is a list of InterfaceStat
+type InterfaceStatList []InterfaceStat
+
+type FilterStat struct {
+	ConnTrackCount int64 `json:"connTrackCount"`
+	ConnTrackMax   int64 `json:"connTrackMax"`
+}
+
+// ConntrackStat has conntrack summary info
+type ConntrackStat struct {
+	Entries       uint32 `json:"entries"`       // Number of entries in the conntrack table
+	Searched      uint32 `json:"searched"`      // Number of conntrack table lookups performed
+	Found         uint32 `json:"found"`         // Number of searched entries which were successful
+	New           uint32 `json:"new"`           // Number of entries added which were not expected before
+	Invalid       uint32 `json:"invalid"`       // Number of packets seen which can not be tracked
+	Ignore        uint32 `json:"ignore"`        // Packets seen which are already connected to an entry
+	Delete        uint32 `json:"delete"`        // Number of entries which were removed
+	DeleteList    uint32 `json:"deleteList"`    // Number of entries which were put to dying list
+	Insert        uint32 `json:"insert"`        // Number of entries inserted into the list
+	InsertFailed  uint32 `json:"insertFailed"`  // # insertion attempted but failed (same entry exists)
+	Drop          uint32 `json:"drop"`          // Number of packets dropped due to conntrack failure.
+	EarlyDrop     uint32 `json:"earlyDrop"`     // Dropped entries to make room for new ones, if maxsize reached
+	IcmpError     uint32 `json:"icmpError"`     // Subset of invalid. Packets that can't be tracked d/t error
+	ExpectNew     uint32 `json:"expectNew"`     // Entries added after an expectation was already present
+	ExpectCreate  uint32 `json:"expectCreate"`  // Expectations added
+	ExpectDelete  uint32 `json:"expectDelete"`  // Expectations deleted
+	SearchRestart uint32 `json:"searchRestart"` // Conntrack table lookups restarted due to hashtable resizes
+}
+
+func NewConntrackStat(e, s, f, n, inv, ign, del, dlst, ins, insfail, drop, edrop, ie, en, ec, ed, sr uint32) *ConntrackStat {
+	return &ConntrackStat{
+		Entries:       e,
+		Searched:      s,
+		Found:         f,
+		New:           n,
+		Invalid:       inv,
+		Ignore:        ign,
+		Delete:        del,
+		DeleteList:    dlst,
+		Insert:        ins,
+		InsertFailed:  insfail,
+		Drop:          drop,
+		EarlyDrop:     edrop,
+		IcmpError:     ie,
+		ExpectNew:     en,
+		ExpectCreate:  ec,
+		ExpectDelete:  ed,
+		SearchRestart: sr,
+	}
+}
+
+type ConntrackStatList struct {
+	items []*ConntrackStat
+}
+
+func NewConntrackStatList() *ConntrackStatList {
+	return &ConntrackStatList{
+		items: []*ConntrackStat{},
+	}
+}
+
+func (l *ConntrackStatList) Append(c *ConntrackStat) {
+	l.items = append(l.items, c)
+}
+
+func (l *ConntrackStatList) Items() []ConntrackStat {
+	items := make([]ConntrackStat, len(l.items))
+	for i, el := range l.items {
+		items[i] = *el
+	}
+	return items
+}
+
+// Summary returns a single-element list with totals from all list items.
+func (l *ConntrackStatList) Summary() []ConntrackStat {
+	summary := NewConntrackStat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+	for _, cs := range l.items {
+		summary.Entries += cs.Entries
+		summary.Searched += cs.Searched
+		summary.Found += cs.Found
+		summary.New += cs.New
+		summary.Invalid += cs.Invalid
+		summary.Ignore += cs.Ignore
+		summary.Delete += cs.Delete
+		summary.DeleteList += cs.DeleteList
+		summary.Insert += cs.Insert
+		summary.InsertFailed += cs.InsertFailed
+		summary.Drop += cs.Drop
+		summary.EarlyDrop += cs.EarlyDrop
+		summary.IcmpError += cs.IcmpError
+		summary.ExpectNew += cs.ExpectNew
+		summary.ExpectCreate += cs.ExpectCreate
+		summary.ExpectDelete += cs.ExpectDelete
+		summary.SearchRestart += cs.SearchRestart
+	}
+	return []ConntrackStat{*summary}
+}
+
+func (n IOCountersStat) String() string {
+	s, _ := json.Marshal(n)
+	return string(s)
+}
+
+func (n ConnectionStat) String() string {
+	s, _ := json.Marshal(n)
+	return string(s)
+}
+
+func (n ProtoCountersStat) String() string {
+	s, _ := json.Marshal(n)
+	return string(s)
+}
+
+func (a Addr) String() string {
+	s, _ := json.Marshal(a)
+	return string(s)
+}
+
+func (n InterfaceStat) String() string {
+	s, _ := json.Marshal(n)
+	return string(s)
+}
+
+func (l InterfaceStatList) String() string {
+	s, _ := json.Marshal(l)
+	return string(s)
+}
+
+func (n InterfaceAddr) String() string {
+	s, _ := json.Marshal(n)
+	return string(s)
+}
+
+func (n ConntrackStat) String() string {
+	s, _ := json.Marshal(n)
+	return string(s)
+}
+
+func Interfaces() (InterfaceStatList, error) {
+	return InterfacesWithContext(context.Background())
+}
+
+func InterfacesWithContext(_ context.Context) (InterfaceStatList, error) {
+	is, err := net.Interfaces()
+	if err != nil {
+		return nil, err
+	}
+	ret := make(InterfaceStatList, 0, len(is))
+	for _, ifi := range is {
+
+		var flags []string
+		if ifi.Flags&net.FlagUp != 0 {
+			flags = append(flags, "up")
+		}
+		if ifi.Flags&net.FlagBroadcast != 0 {
+			flags = append(flags, "broadcast")
+		}
+		if ifi.Flags&net.FlagLoopback != 0 {
+			flags = append(flags, "loopback")
+		}
+		if ifi.Flags&net.FlagPointToPoint != 0 {
+			flags = append(flags, "pointtopoint")
+		}
+		if ifi.Flags&net.FlagMulticast != 0 {
+			flags = append(flags, "multicast")
+		}
+
+		r := InterfaceStat{
+			Index:        ifi.Index,
+			Name:         ifi.Name,
+			MTU:          ifi.MTU,
+			HardwareAddr: ifi.HardwareAddr.String(),
+			Flags:        flags,
+		}
+		addrs, err := ifi.Addrs()
+		if err == nil {
+			r.Addrs = make(InterfaceAddrList, 0, len(addrs))
+			for _, addr := range addrs {
+				r.Addrs = append(r.Addrs, InterfaceAddr{
+					Addr: addr.String(),
+				})
+			}
+
+		}
+		ret = append(ret, r)
+	}
+
+	return ret, nil
+}
+
+func getIOCountersAll(n []IOCountersStat) []IOCountersStat {
+	r := IOCountersStat{
+		Name: "all",
+	}
+	for _, nic := range n {
+		r.BytesRecv += nic.BytesRecv
+		r.PacketsRecv += nic.PacketsRecv
+		r.Errin += nic.Errin
+		r.Dropin += nic.Dropin
+		r.BytesSent += nic.BytesSent
+		r.PacketsSent += nic.PacketsSent
+		r.Errout += nic.Errout
+		r.Dropout += nic.Dropout
+	}
+
+	return []IOCountersStat{r}
+}
+
+// IOCounters returns network I/O statistics for every network
+// interface installed on the system.  If pernic argument is false,
+// return only sum of all information (which name is 'all'). If true,
+// every network interface installed on the system is returned
+// separately.
+func IOCounters(pernic bool) ([]IOCountersStat, error) {
+	return IOCountersWithContext(context.Background(), pernic)
+}
+
+func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
+	return IOCountersByFileWithContext(context.Background(), pernic, filename)
+}
+
+// ProtoCounters returns network statistics for the entire system.
+// If protocols is empty then all protocols are returned, otherwise
+// just the protocols in the list are returned.
+//
+// Available protocols:
+// [ip,icmp,icmpmsg,tcp,udp,udplite]
+//
+// Key naming contract:
+// The keys of the returned Stats map use MIB-II (RFC 1213) identifier
+// names — e.g. "InSegs", "OutSegs", "RetransSegs", "ActiveOpens",
+// "InDatagrams", "NoPorts". This contract was established by the
+// original Linux implementation, which sources its keys from
+// /proc/net/snmp (whose headers are MIB-II names). Per-platform
+// implementations are expected to map their native counter sources
+// (e.g. AIX `netstat -s`, BSD sysctl) to these MIB-II names.
+// Native counters that have no MIB-II equivalent are not exposed
+// through this API.
+//
+// Not Implemented for FreeBSD, Windows, OpenBSD, Darwin, Solaris.
+func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
+	return ProtoCountersWithContext(context.Background(), protocols)
+}
+
+// FilterCounters returns iptables conntrack statistics
+// the currently in use conntrack count and the max.
+// If the file does not exist or is invalid it will return nil.
+func FilterCounters() ([]FilterStat, error) {
+	return FilterCountersWithContext(context.Background())
+}
+
+// ConntrackStats returns more detailed info about the conntrack table
+func ConntrackStats(percpu bool) ([]ConntrackStat, error) {
+	return ConntrackStatsWithContext(context.Background(), percpu)
+}
+
+// Return a list of network connections opened.
+func Connections(kind string) ([]ConnectionStat, error) {
+	return ConnectionsWithContext(context.Background(), kind)
+}
+
+// Return a list of network connections opened returning at most `max`
+// connections for each running process.
+func ConnectionsMax(kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithContext(context.Background(), kind, maxConn)
+}
+
+// Return a list of network connections opened, omitting `Uids`.
+// WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be
+// removed from the API in the future.
+func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) {
+	return ConnectionsWithoutUidsWithContext(context.Background(), kind)
+}
+
+// Return a list of network connections opened by a process.
+func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidWithContext(context.Background(), kind, pid)
+}
+
+// Return a list of network connections opened, omitting `Uids`.
+// WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be
+// removed from the API in the future.
+func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid)
+}
+
+func ConnectionsPidMaxWithoutUids(kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, maxConn)
+}
+
+// Return up to `max` network connections opened by a process.
+func ConnectionsPidMax(kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(context.Background(), kind, pid, maxConn)
+}
+
+// Pids retunres all pids.
+// Note: this is a copy of process_linux.Pids()
+// FIXME: Import process occurs import cycle.
+// move to common made other platform breaking. Need consider.
+func Pids() ([]int32, error) {
+	return PidsWithContext(context.Background())
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_aix.go b/vendor/github.com/shirou/gopsutil/v4/net/net_aix.go
new file mode 100644
index 000000000..9f2e145f0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_aix.go
@@ -0,0 +1,532 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix
+
+package net
+
+import (
+	"context"
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
+	return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+	out, err := invoke.CommandWithContext(ctx, "netstat", "-s")
+	if err != nil {
+		return nil, err
+	}
+	return parseNetstatS(string(out), protocols)
+}
+
+// parseNetstatS parses "netstat -s" output on AIX.
+//
+// Format:
+//
+//	<proto>:
+//	\t<count> <description>
+//	\t\t<count> <sub-description>
+//
+// Descriptions containing parenthetical sub-counts (e.g. "(6302116893 bytes)")
+// are normalised by stripping the parenthetical before matching.
+func parseNetstatS(output string, protocols []string) ([]ProtoCountersStat, error) {
+	var stats []ProtoCountersStat
+	var currentProto string
+	var currentStats map[string]int64
+
+	for _, line := range strings.Split(output, "\n") {
+		// Protocol header: no leading whitespace, ends with ":"
+		if line != "" && line[0] != '\t' {
+			if currentProto != "" && len(currentStats) > 0 {
+				if len(protocols) == 0 || common.StringsHas(protocols, currentProto) {
+					stats = append(stats, ProtoCountersStat{
+						Protocol: currentProto,
+						Stats:    currentStats,
+					})
+				}
+			}
+			currentProto = strings.TrimSuffix(strings.TrimSpace(line), ":")
+			currentStats = make(map[string]int64)
+			continue
+		}
+
+		if currentProto == "" {
+			continue
+		}
+
+		// Count leading tabs to track indentation depth (1 = top-level metric).
+		depth := 0
+		rest := line
+		for rest != "" && rest[0] == '\t' {
+			depth++
+			rest = rest[1:]
+		}
+		if depth == 0 || rest == "" {
+			continue
+		}
+
+		// Split "<number> <description>".
+		spaceIdx := strings.IndexByte(rest, ' ')
+		if spaceIdx <= 0 {
+			continue
+		}
+		val, err := strconv.ParseInt(rest[:spaceIdx], 10, 64)
+		if err != nil {
+			continue
+		}
+		// Normalise: remove parenthetical sub-counts like "(6302116893 bytes)".
+		desc := normaliseNetstatDesc(strings.TrimSpace(rest[spaceIdx+1:]))
+
+		if key := aixProtoKey(currentProto, depth, desc); key != "" {
+			currentStats[key] += val
+		}
+	}
+
+	if currentProto != "" && len(currentStats) > 0 {
+		if len(protocols) == 0 || common.StringsHas(protocols, currentProto) {
+			stats = append(stats, ProtoCountersStat{
+				Protocol: currentProto,
+				Stats:    currentStats,
+			})
+		}
+	}
+
+	return stats, nil
+}
+
+// normaliseNetstatDesc strips a single parenthetical from a netstat -s description,
+// e.g. "data packets (6302116893 bytes) retransmitted" → "data packets retransmitted".
+func normaliseNetstatDesc(s string) string {
+	start := strings.Index(s, "(")
+	if start == -1 {
+		return s
+	}
+	end := strings.LastIndex(s, ")")
+	if end < start {
+		return s
+	}
+	return strings.Join(strings.Fields(s[:start]+s[end+1:]), " ")
+}
+
+// aixProtoKey maps a normalised AIX netstat -s description to a ProtoCountersStat key.
+// depth is the tab-indentation level (1 = top-level line under the protocol header).
+// Returns "" for lines that should be ignored.
+func aixProtoKey(proto string, depth int, desc string) string {
+	switch proto {
+	case "tcp":
+		return aixTCPKey(depth, desc)
+	case "udp":
+		return aixUDPKey(desc)
+	case "ip":
+		return aixIPKey(depth, desc)
+	case "ipv6":
+		return aixIPv6Key(depth, desc)
+	}
+	return ""
+}
+
+func aixTCPKey(depth int, desc string) string {
+	switch {
+	// Top-level totals — depth check avoids matching sub-lines like "N data packets sent".
+	case depth == 1 && desc == "packets sent":
+		return "OutSegs"
+	case depth == 1 && desc == "packets received":
+		return "InSegs"
+	// Sub-line: "data packets NNN bytes retransmitted" → normalised "data packets retransmitted"
+	case strings.Contains(desc, "retransmitted"):
+		return "RetransSegs"
+	case desc == "connection requests":
+		return "ActiveOpens"
+	case desc == "connection accepts":
+		return "PassiveOpens"
+	case desc == "embryonic connections dropped":
+		return "AttemptFails"
+	case strings.HasPrefix(desc, "discarded for bad checksums"):
+		return "InCsumErrors"
+	// Other input errors accumulate into InErrs.
+	case strings.HasPrefix(desc, "discarded for bad header") ||
+		strings.HasPrefix(desc, "discarded because packet too short"):
+		return "InErrs"
+	}
+	return ""
+}
+
+func aixUDPKey(desc string) string {
+	switch {
+	case desc == "delivered":
+		return "InDatagrams"
+	// Both unicast and broadcast "dropped due to no socket" map to NoPorts.
+	case strings.Contains(desc, "dropped due to no socket"):
+		return "NoPorts"
+	case desc == "bad checksums":
+		return "InCsumErrors"
+	case desc == "socket buffer overflows":
+		return "RcvbufErrors"
+	case desc == "datagrams output":
+		return "OutDatagrams"
+	case desc == "incomplete headers" || desc == "bad data length fields":
+		return "InErrors"
+	}
+	return ""
+}
+
+func aixIPKey(depth int, desc string) string {
+	switch {
+	case desc == "total packets received":
+		return "InReceives"
+	// All header-error variants accumulate into InHdrErrors.
+	case desc == "bad header checksums" ||
+		desc == "with size smaller than minimum" ||
+		desc == "with data size < data length" ||
+		desc == "with header length < data size" ||
+		desc == "with data length < header length" ||
+		desc == "with bad options" ||
+		desc == "with incorrect version number":
+		return "InHdrErrors"
+	case strings.Contains(desc, "unknown/unsupported protocol"):
+		return "InUnknownProtos"
+	case desc == "packets for this host":
+		return "InDelivers"
+	case depth == 1 && desc == "packets forwarded":
+		return "ForwDatagrams"
+	case desc == "packets sent from this host":
+		return "OutRequests"
+	case desc == "packets reassembled ok":
+		return "ReasmOKs"
+	case strings.HasPrefix(desc, "fragments dropped after timeout"):
+		return "ReasmFails"
+	case desc == "fragments received":
+		return "ReasmReqds"
+	case strings.HasPrefix(desc, "fragments dropped"):
+		return "InDiscards"
+	case desc == "fragments created":
+		return "FragCreates"
+	case desc == "output packets discarded due to no route":
+		return "OutNoRoutes"
+	case strings.HasPrefix(desc, "output packets dropped due to no bufs"):
+		return "OutDiscards"
+	}
+	return ""
+}
+
+func aixIPv6Key(depth int, desc string) string {
+	switch {
+	case desc == "total packets received":
+		return "InReceives"
+	case desc == "with size smaller than minimum" ||
+		desc == "with data size < data length" ||
+		desc == "with incorrect version number" ||
+		desc == "with illegal source":
+		return "InHdrErrors"
+	case strings.Contains(desc, "unknown/unsupported protocol"):
+		return "InUnknownProtos"
+	case desc == "input packets without enough memory":
+		return "InDiscards"
+	case desc == "packets for this host":
+		return "InDelivers"
+	case depth == 1 && desc == "packets forwarded":
+		return "ForwDatagrams"
+	case desc == "packets sent from this host":
+		return "OutRequests"
+	case desc == "packets reassembled ok":
+		return "ReasmOKs"
+	case strings.HasPrefix(desc, "fragments dropped after timeout"):
+		return "ReasmFails"
+	case desc == "fragments received":
+		return "ReasmReqds"
+	case strings.HasPrefix(desc, "fragments dropped"):
+		return "InDiscards"
+	case desc == "fragments created":
+		return "FragCreates"
+	case desc == "output packets discarded due to no route":
+		return "OutNoRoutes"
+	case strings.HasPrefix(desc, "output packets dropped due to no bufs") ||
+		desc == "output packets without enough memory":
+		return "OutDiscards"
+	}
+	return ""
+}
+
+func parseNetstatNetLine(line string) (ConnectionStat, error) {
+	f := strings.Fields(line)
+	if len(f) < 5 {
+		return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+	}
+
+	var netType, netFamily uint32
+	switch f[0] {
+	case "tcp", "tcp4":
+		netType = syscall.SOCK_STREAM
+		netFamily = syscall.AF_INET
+	case "udp", "udp4":
+		netType = syscall.SOCK_DGRAM
+		netFamily = syscall.AF_INET
+	case "tcp6":
+		netType = syscall.SOCK_STREAM
+		netFamily = syscall.AF_INET6
+	case "udp6":
+		netType = syscall.SOCK_DGRAM
+		netFamily = syscall.AF_INET6
+	default:
+		return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
+	}
+
+	laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
+	if err != nil {
+		return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
+	}
+
+	n := ConnectionStat{
+		Fd:     uint32(0), // not supported
+		Family: uint32(netFamily),
+		Type:   uint32(netType),
+		Laddr:  laddr,
+		Raddr:  raddr,
+		Pid:    int32(0), // not supported
+	}
+	if len(f) == 6 {
+		n.Status = f[5]
+	}
+
+	return n, nil
+}
+
+var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
+
+func parseAddr(l string, family uint32) (Addr, error) {
+	matches := portMatch.FindStringSubmatch(l)
+	if matches == nil {
+		return Addr{}, fmt.Errorf("wrong addr, %s", l)
+	}
+	host := matches[1]
+	port := matches[2]
+	if host == "*" {
+		switch family {
+		case syscall.AF_INET:
+			host = "0.0.0.0"
+		case syscall.AF_INET6:
+			host = "::"
+		default:
+			return Addr{}, fmt.Errorf("unknown family, %d", family)
+		}
+	}
+	lport, err := strconv.ParseInt(port, 10, 32)
+	if err != nil {
+		return Addr{}, err
+	}
+	return Addr{IP: host, Port: uint32(lport)}, nil
+}
+
+// This function only works for netstat returning addresses with a "."
+// before the port (0.0.0.0.22 instead of 0.0.0.0:22).
+func parseNetstatAddr(local, remote string, family uint32) (laddr, raddr Addr, err error) {
+	laddr, err = parseAddr(local, family)
+	if remote != "*.*" { // remote addr exists
+		raddr, err = parseAddr(remote, family)
+		if err != nil {
+			return laddr, raddr, err
+		}
+	}
+
+	return laddr, raddr, err
+}
+
+func parseNetstatUnixLine(f []string) (ConnectionStat, error) {
+	if len(f) < 8 {
+		return ConnectionStat{}, fmt.Errorf("wrong number of fields: expected >=8 got %d", len(f))
+	}
+
+	var netType uint32
+
+	switch f[1] {
+	case "dgram":
+		netType = syscall.SOCK_DGRAM
+	case "stream":
+		netType = syscall.SOCK_STREAM
+	default:
+		return ConnectionStat{}, fmt.Errorf("unknown type: %s", f[1])
+	}
+
+	// Some Unix Socket don't have any address associated
+	addr := ""
+	if len(f) == 9 {
+		addr = f[8]
+	}
+
+	c := ConnectionStat{
+		Fd:     uint32(0), // not supported
+		Family: uint32(syscall.AF_UNIX),
+		Type:   uint32(netType),
+		Laddr: Addr{
+			IP: addr,
+		},
+		Status: "NONE",
+		Pid:    int32(0), // not supported
+	}
+
+	return c, nil
+}
+
+// Return true if proto is the corresponding to the kind parameter
+// Only for Inet lines
+func hasCorrectInetProto(kind, proto string) bool {
+	switch kind {
+	case "all", "inet":
+		return true
+	case "unix":
+		return false
+	case "inet4":
+		return !strings.HasSuffix(proto, "6")
+	case "inet6":
+		return strings.HasSuffix(proto, "6")
+	case "tcp":
+		return proto == "tcp" || proto == "tcp4" || proto == "tcp6"
+	case "tcp4":
+		return proto == "tcp" || proto == "tcp4"
+	case "tcp6":
+		return proto == "tcp6"
+	case "udp":
+		return proto == "udp" || proto == "udp4" || proto == "udp6"
+	case "udp4":
+		return proto == "udp" || proto == "udp4"
+	case "udp6":
+		return proto == "udp6"
+	}
+	return false
+}
+
+func parseNetstatA(output, kind string) ([]ConnectionStat, error) {
+	var ret []ConnectionStat
+	lines := strings.Split(string(output), "\n")
+
+	for _, line := range lines {
+		fields := strings.Fields(line)
+		if len(fields) < 1 {
+			continue
+		}
+
+		switch {
+		case strings.HasPrefix(fields[0], "f1"):
+			// Unix lines
+			if len(fields) < 2 {
+				// every unix connections have two lines
+				continue
+			}
+
+			c, err := parseNetstatUnixLine(fields)
+			if err != nil {
+				return nil, fmt.Errorf("failed to parse Unix Address (%s): %w", line, err)
+			}
+
+			ret = append(ret, c)
+
+		case strings.HasPrefix(fields[0], "tcp") || strings.HasPrefix(fields[0], "udp"):
+			// Inet lines
+			if !hasCorrectInetProto(kind, fields[0]) {
+				continue
+			}
+
+			// On AIX, netstat display some connections with "*.*" as local addresses
+			// Skip them as they aren't real connections.
+			if fields[3] == "*.*" {
+				continue
+			}
+
+			c, err := parseNetstatNetLine(line)
+			if err != nil {
+				return nil, fmt.Errorf("failed to parse Inet Address (%s): %w", line, err)
+			}
+
+			ret = append(ret, c)
+		default:
+			// Header lines
+			continue
+		}
+	}
+
+	return ret, nil
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	args := []string{"-na"}
+	switch strings.ToLower(kind) {
+	default:
+		fallthrough
+	case "":
+		kind = "all"
+	case "all":
+		// nothing to add
+	case "inet", "inet4", "inet6":
+		args = append(args, "-finet")
+	case "tcp", "tcp4", "tcp6":
+		args = append(args, "-finet")
+	case "udp", "udp4", "udp6":
+		args = append(args, "-finet")
+	case "unix":
+		args = append(args, "-funix")
+	}
+
+	out, err := invoke.CommandWithContext(ctx, "netstat", args...)
+	if err != nil {
+		return nil, err
+	}
+
+	ret, err := parseNetstatA(string(out), kind)
+	if err != nil {
+		return nil, err
+	}
+
+	return ret, nil
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_aix_cgo.go b/vendor/github.com/shirou/gopsutil/v4/net/net_aix_cgo.go
new file mode 100644
index 000000000..717863692
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_aix_cgo.go
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && cgo
+
+package net
+
+import (
+	"context"
+
+	"github.com/power-devops/perfstat"
+)
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+	ifs, err := perfstat.NetIfaceStat()
+	if err != nil {
+		return nil, err
+	}
+
+	iocounters := make([]IOCountersStat, 0, len(ifs))
+	for _, netif := range ifs {
+		n := IOCountersStat{
+			Name:        netif.Name,
+			BytesSent:   uint64(netif.OBytes),
+			BytesRecv:   uint64(netif.IBytes),
+			PacketsSent: uint64(netif.OPackets),
+			PacketsRecv: uint64(netif.IPackets),
+			Errin:       uint64(netif.IErrors),
+			Errout:      uint64(netif.OErrors),
+			Dropin:      uint64(netif.IfIqDrops),
+			Dropout:     uint64(netif.XmitDrops),
+		}
+		iocounters = append(iocounters, n)
+	}
+	if !pernic {
+		return getIOCountersAll(iocounters), nil
+	}
+	return iocounters, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_aix_nocgo.go b/vendor/github.com/shirou/gopsutil/v4/net/net_aix_nocgo.go
new file mode 100644
index 000000000..27d37a99c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_aix_nocgo.go
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build aix && !cgo
+
+package net
+
+import (
+	"context"
+	"errors"
+	"strconv"
+	"strings"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func parseNetstatI(output string) ([]IOCountersStat, error) {
+	lines := strings.Split(string(output), "\n")
+	ret := make([]IOCountersStat, 0, len(lines)-1)
+	exists := make([]string, 0, len(ret))
+
+	// Check first line is header
+	if len(lines) > 0 && strings.Fields(lines[0])[0] != "Name" {
+		return nil, errors.New("not a 'netstat -i' output")
+	}
+
+	for _, line := range lines[1:] {
+		values := strings.Fields(line)
+		if len(values) < 1 || values[0] == "Name" {
+			continue
+		}
+		if common.StringsHas(exists, values[0]) {
+			// skip if already get
+			continue
+		}
+		exists = append(exists, values[0])
+
+		if len(values) < 9 {
+			continue
+		}
+
+		base := 1
+		// sometimes Address is omitted
+		if len(values) < 10 {
+			base = 0
+		}
+
+		parsed := make([]uint64, 0, 5)
+		vv := []string{
+			values[base+3], // Ipkts == PacketsRecv
+			values[base+4], // Ierrs == Errin
+			values[base+5], // Opkts == PacketsSent
+			values[base+6], // Oerrs == Errout
+			values[base+8], // Drops == Dropout
+		}
+
+		for _, target := range vv {
+			if target == "-" {
+				parsed = append(parsed, 0)
+				continue
+			}
+
+			t, err := strconv.ParseUint(target, 10, 64)
+			if err != nil {
+				return nil, err
+			}
+			parsed = append(parsed, t)
+		}
+
+		n := IOCountersStat{
+			Name:        values[0],
+			PacketsRecv: parsed[0],
+			Errin:       parsed[1],
+			PacketsSent: parsed[2],
+			Errout:      parsed[3],
+			Dropout:     parsed[4],
+		}
+		ret = append(ret, n)
+	}
+	return ret, nil
+}
+
+// parseEntstat extracts BytesSent and BytesRecv from entstat output.
+// The entstat two-column Transmit/Receive format (including the "Bytes:"
+// line) has been stable across AIX 4.3 through 7.3 (over 25 years).
+// The output has a two-column layout with Transmit on the left and Receive
+// on the right, e.g.:
+//
+//	Bytes: 3509236040                             Bytes: 4547812126
+func parseEntstat(output string) (bytesSent, bytesRecv uint64) {
+	for _, line := range strings.Split(output, "\n") {
+		if !strings.Contains(line, "Bytes:") {
+			continue
+		}
+		// Split on "Bytes:" to get: ["", " 3509236040                             ", " 4547812126"]
+		parts := strings.Split(line, "Bytes:")
+		if len(parts) >= 2 {
+			if v, err := strconv.ParseUint(strings.TrimSpace(parts[1]), 10, 64); err == nil {
+				bytesSent = v
+			}
+		}
+		if len(parts) >= 3 {
+			if v, err := strconv.ParseUint(strings.TrimSpace(parts[2]), 10, 64); err == nil {
+				bytesRecv = v
+			}
+		}
+		return
+	}
+	return
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+	out, err := invoke.CommandWithContext(ctx, "netstat", "-idn")
+	if err != nil {
+		return nil, err
+	}
+
+	iocounters, err := parseNetstatI(string(out))
+	if err != nil {
+		return nil, err
+	}
+
+	// Populate BytesSent/BytesRecv via entstat for each interface.
+	// entstat only works on hardware/virtual ethernet adapters; it fails
+	// on loopback (lo0) with errno 19, which is silently skipped. Errors
+	// on other interfaces are propagated since they indicate a real problem.
+	for i := range iocounters {
+		entOut, err := invoke.CommandWithContext(ctx, "entstat", iocounters[i].Name)
+		if err != nil {
+			// entstat fails on loopback (lo0) with errno 19 — this is expected.
+			// For other interfaces, propagate the error.
+			if iocounters[i].Name == "lo0" {
+				continue
+			}
+			return nil, err
+		}
+		iocounters[i].BytesSent, iocounters[i].BytesRecv = parseEntstat(string(entOut))
+	}
+
+	if !pernic {
+		return getIOCountersAll(iocounters), nil
+	}
+	return iocounters, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_darwin.go b/vendor/github.com/shirou/gopsutil/v4/net/net_darwin.go
new file mode 100644
index 000000000..9531ad5b1
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_darwin.go
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package net
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"os/exec"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var (
+	errNetstatHeader  = errors.New("can't parse header of netstat output")
+	netstatLinkRegexp = regexp.MustCompile(`^<Link#(\d+)>$`)
+)
+
+const endOfLine = "\n"
+
+func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err error) {
+	var (
+		numericValue uint64
+		columns      = strings.Fields(line)
+	)
+
+	if columns[0] == "Name" {
+		return nil, nil, errNetstatHeader
+	}
+
+	// try to extract the numeric value from <Link#123>
+	if subMatch := netstatLinkRegexp.FindStringSubmatch(columns[2]); len(subMatch) == 2 {
+		numericValue, err = strconv.ParseUint(subMatch[1], 10, 64)
+		if err != nil {
+			return nil, nil, err
+		}
+		linkIDUint := uint(numericValue)
+		linkID = &linkIDUint
+	}
+
+	base := 1
+	numberColumns := len(columns)
+	// sometimes Address is omitted
+	if numberColumns < 12 {
+		base = 0
+	}
+	if numberColumns < 11 || numberColumns > 13 {
+		return nil, nil, fmt.Errorf("line %q do have an invalid number of columns %d", line, numberColumns)
+	}
+
+	parsed := make([]uint64, 0, 7)
+	vv := []string{
+		columns[base+3],  // Ipkts == PacketsRecv
+		columns[base+4],  // Ierrs == Errin
+		columns[base+5],  // Ibytes == BytesRecv
+		columns[base+6],  // Opkts == PacketsSent
+		columns[base+7],  // Oerrs == Errout
+		columns[base+8],  // Obytes == BytesSent
+		columns[base+10], // Drop == Dropout
+	}
+
+	for _, target := range vv {
+		if target == "-" {
+			parsed = append(parsed, 0)
+			continue
+		}
+
+		if numericValue, err = strconv.ParseUint(target, 10, 64); err != nil {
+			return nil, nil, err
+		}
+		parsed = append(parsed, numericValue)
+	}
+
+	stat = &IOCountersStat{
+		Name:        strings.Trim(columns[0], "*"), // remove the * that sometimes is on right on interface
+		PacketsRecv: parsed[0],
+		Errin:       parsed[1],
+		BytesRecv:   parsed[2],
+		PacketsSent: parsed[3],
+		Errout:      parsed[4],
+		BytesSent:   parsed[5],
+		Dropout:     parsed[6],
+	}
+	return stat, linkID, nil
+}
+
+type netstatInterface struct {
+	linkID *uint
+	stat   *IOCountersStat
+}
+
+func parseNetstatOutput(output string) ([]netstatInterface, error) {
+	var (
+		err   error
+		lines = strings.Split(strings.Trim(output, endOfLine), endOfLine)
+	)
+
+	// number of interfaces is number of lines less one for the header
+	numberInterfaces := len(lines) - 1
+
+	interfaces := make([]netstatInterface, numberInterfaces)
+	// no output beside header
+	if numberInterfaces == 0 {
+		return interfaces, nil
+	}
+
+	for index := 0; index < numberInterfaces; index++ {
+		nsIface := netstatInterface{}
+		if nsIface.stat, nsIface.linkID, err = parseNetstatLine(lines[index+1]); err != nil {
+			return nil, err
+		}
+		interfaces[index] = nsIface
+	}
+	return interfaces, nil
+}
+
+// map that hold the name of a network interface and the number of usage
+type mapInterfaceNameUsage map[string]uint
+
+func newMapInterfaceNameUsage(ifaces []netstatInterface) mapInterfaceNameUsage {
+	output := make(mapInterfaceNameUsage)
+	for index := range ifaces {
+		if ifaces[index].linkID != nil {
+			ifaceName := ifaces[index].stat.Name
+			usage, ok := output[ifaceName]
+			if ok {
+				output[ifaceName] = usage + 1
+			} else {
+				output[ifaceName] = 1
+			}
+		}
+	}
+	return output
+}
+
+func (mapi mapInterfaceNameUsage) isTruncated() bool {
+	for _, usage := range mapi {
+		if usage > 1 {
+			return true
+		}
+	}
+	return false
+}
+
+func (mapi mapInterfaceNameUsage) notTruncated() []string {
+	output := make([]string, 0)
+	for ifaceName, usage := range mapi {
+		if usage == 1 {
+			output = append(output, ifaceName)
+		}
+	}
+	return output
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+// example of `netstat -ibdnW` output on yosemite
+// Name  Mtu   Network       Address            Ipkts Ierrs     Ibytes    Opkts Oerrs     Obytes  Coll Drop
+// lo0   16384 <Link#1>                        869107     0  169411755   869107     0  169411755     0   0
+// lo0   16384 ::1/128     ::1                 869107     -  169411755   869107     -  169411755     -   -
+// lo0   16384 127           127.0.0.1         869107     -  169411755   869107     -  169411755     -   -
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+	var (
+		ret      []IOCountersStat
+		retIndex int
+	)
+
+	netstat, err := exec.LookPath("netstat")
+	if err != nil {
+		return nil, err
+	}
+
+	// try to get all interface metrics, and hope there won't be any truncated
+	out, err := invoke.CommandWithContext(ctx, netstat, "-ibdnW")
+	if err != nil {
+		return nil, err
+	}
+
+	nsInterfaces, err := parseNetstatOutput(string(out))
+	if err != nil {
+		return nil, err
+	}
+
+	ifaceUsage := newMapInterfaceNameUsage(nsInterfaces)
+	notTruncated := ifaceUsage.notTruncated()
+	ret = make([]IOCountersStat, len(notTruncated))
+
+	if !ifaceUsage.isTruncated() {
+		// no truncated interface name, return stats of all interface with <Link#...>
+		for index := range nsInterfaces {
+			if nsInterfaces[index].linkID != nil {
+				ret[retIndex] = *nsInterfaces[index].stat
+				retIndex++
+			}
+		}
+	} else {
+		// duplicated interface, list all interfaces
+		if out, err = invoke.CommandWithContext(ctx, "ifconfig", "-l"); err != nil {
+			return nil, err
+		}
+		interfaceNames := strings.Fields(strings.TrimRight(string(out), endOfLine))
+
+		// for each of the interface name, run netstat if we don't have any stats yet
+		for _, interfaceName := range interfaceNames {
+			truncated := true
+			for index := range nsInterfaces {
+				if nsInterfaces[index].linkID != nil && nsInterfaces[index].stat.Name == interfaceName {
+					// handle the non truncated name to avoid execute netstat for them again
+					ret[retIndex] = *nsInterfaces[index].stat
+					retIndex++
+					truncated = false
+					break
+				}
+			}
+			if truncated {
+				// run netstat with -I$ifacename
+				if out, err = invoke.CommandWithContext(ctx, netstat, "-ibdnWI"+interfaceName); err != nil {
+					return nil, err
+				}
+				parsedIfaces, err := parseNetstatOutput(string(out))
+				if err != nil {
+					return nil, err
+				}
+				if len(parsedIfaces) == 0 {
+					// interface had been removed since `ifconfig -l` had been executed
+					continue
+				}
+				for index := range parsedIfaces {
+					if parsedIfaces[index].linkID != nil {
+						ret = append(ret, *parsedIfaces[index].stat)
+						break
+					}
+				}
+			}
+		}
+	}
+
+	if !pernic {
+		return getIOCountersAll(ret), nil
+	}
+	return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
+	return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_fallback.go b/vendor/github.com/shirou/gopsutil/v4/net/net_fallback.go
new file mode 100644
index 000000000..0c0e57da3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_fallback.go
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build !aix && !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !netbsd
+
+package net
+
+import (
+	"context"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func IOCountersWithContext(_ context.Context, _ bool) ([]IOCountersStat, error) {
+	return []IOCountersStat{}, common.ErrNotImplementedError
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
+	return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsWithContext(_ context.Context, _ string) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/net/net_freebsd.go
new file mode 100644
index 000000000..a72aa00a6
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_freebsd.go
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd
+
+package net
+
+import (
+	"context"
+	"strconv"
+	"strings"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+	out, err := invoke.CommandWithContext(ctx, "netstat", "-ibdnW")
+	if err != nil {
+		return nil, err
+	}
+
+	lines := strings.Split(string(out), "\n")
+	ret := make([]IOCountersStat, 0, len(lines)-1)
+	exists := make([]string, 0, len(ret))
+
+	for _, line := range lines {
+		values := strings.Fields(line)
+		if len(values) < 1 || values[0] == "Name" {
+			continue
+		}
+		if common.StringsHas(exists, values[0]) {
+			// skip if already get
+			continue
+		}
+		exists = append(exists, values[0])
+
+		if len(values) < 12 {
+			continue
+		}
+		base := 1
+		// sometimes Address is omitted
+		if len(values) < 13 {
+			base = 0
+		}
+
+		parsed := make([]uint64, 0, 8)
+		vv := []string{
+			values[base+3],  // PacketsRecv
+			values[base+4],  // Errin
+			values[base+5],  // Dropin
+			values[base+6],  // BytesRecvn
+			values[base+7],  // PacketSent
+			values[base+8],  // Errout
+			values[base+9],  // BytesSent
+			values[base+11], // Dropout
+		}
+		for _, target := range vv {
+			if target == "-" {
+				parsed = append(parsed, 0)
+				continue
+			}
+
+			t, err := strconv.ParseUint(target, 10, 64)
+			if err != nil {
+				return nil, err
+			}
+			parsed = append(parsed, t)
+		}
+
+		n := IOCountersStat{
+			Name:        values[0],
+			PacketsRecv: parsed[0],
+			Errin:       parsed[1],
+			Dropin:      parsed[2],
+			BytesRecv:   parsed[3],
+			PacketsSent: parsed[4],
+			Errout:      parsed[5],
+			BytesSent:   parsed[6],
+			Dropout:     parsed[7],
+		}
+		ret = append(ret, n)
+	}
+
+	if !pernic {
+		return getIOCountersAll(ret), nil
+	}
+
+	return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
+	return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_linux.go b/vendor/github.com/shirou/gopsutil/v4/net/net_linux.go
new file mode 100644
index 000000000..96a78ff80
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_linux.go
@@ -0,0 +1,820 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package net
+
+import (
+	"bytes"
+	"context"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+const ( // Conntrack Column numbers
+	ctENTRIES = iota
+	ctSEARCHED
+	ctFOUND
+	ctNEW
+	ctINVALID
+	ctIGNORE
+	ctDELETE
+	ctDELETE_LIST //nolint:revive //FIXME
+	ctINSERT
+	ctINSERT_FAILED //nolint:revive //FIXME
+	ctDROP
+	ctEARLY_DROP     //nolint:revive //FIXME
+	ctICMP_ERROR     //nolint:revive //FIXME
+	CT_EXPEctNEW     //nolint:revive //FIXME
+	ctEXPECT_CREATE  //nolint:revive //FIXME
+	CT_EXPEctDELETE  //nolint:revive //FIXME
+	ctSEARCH_RESTART //nolint:revive //FIXME
+)
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+	filename := common.HostProcWithContext(ctx, "net/dev")
+	return IOCountersByFileWithContext(ctx, pernic, filename)
+}
+
+func IOCountersByFileWithContext(_ context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
+	lines, err := common.ReadLines(filename)
+	if err != nil {
+		return nil, err
+	}
+
+	statlen := len(lines) - 1
+
+	ret := make([]IOCountersStat, 0, statlen)
+
+	for _, line := range lines[2:] {
+		// Split interface name and stats data at the last ":"
+		separatorPos := strings.LastIndex(line, ":")
+		if separatorPos == -1 {
+			continue
+		}
+		interfacePart := line[0:separatorPos]
+		statsPart := line[separatorPos+1:]
+
+		interfaceName := strings.TrimSpace(interfacePart)
+		if interfaceName == "" {
+			continue
+		}
+
+		fields := strings.Fields(strings.TrimSpace(statsPart))
+		if len(fields) < 13 {
+			continue
+		}
+		bytesRecv, err := strconv.ParseUint(fields[0], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		packetsRecv, err := strconv.ParseUint(fields[1], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		errIn, err := strconv.ParseUint(fields[2], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		dropIn, err := strconv.ParseUint(fields[3], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		fifoIn, err := strconv.ParseUint(fields[4], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		bytesSent, err := strconv.ParseUint(fields[8], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		packetsSent, err := strconv.ParseUint(fields[9], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		errOut, err := strconv.ParseUint(fields[10], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		dropOut, err := strconv.ParseUint(fields[11], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+		fifoOut, err := strconv.ParseUint(fields[12], 10, 64)
+		if err != nil {
+			return ret, err
+		}
+
+		nic := IOCountersStat{
+			Name:        interfaceName,
+			BytesRecv:   bytesRecv,
+			PacketsRecv: packetsRecv,
+			Errin:       errIn,
+			Dropin:      dropIn,
+			Fifoin:      fifoIn,
+			BytesSent:   bytesSent,
+			PacketsSent: packetsSent,
+			Errout:      errOut,
+			Dropout:     dropOut,
+			Fifoout:     fifoOut,
+		}
+		ret = append(ret, nic)
+	}
+
+	if !pernic {
+		return getIOCountersAll(ret), nil
+	}
+
+	return ret, nil
+}
+
+var netProtocols = []string{
+	"ip",
+	"icmp",
+	"icmpmsg",
+	"tcp",
+	"udp",
+	"udplite",
+}
+
+func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
+	if len(protocols) == 0 {
+		protocols = netProtocols
+	}
+
+	stats := make([]ProtoCountersStat, 0, len(protocols))
+	protos := make(map[string]bool, len(protocols))
+	for _, p := range protocols {
+		protos[p] = true
+	}
+
+	filename := common.HostProcWithContext(ctx, "net/snmp")
+	lines, err := common.ReadLines(filename)
+	if err != nil {
+		return nil, err
+	}
+
+	linecount := len(lines)
+	for i := 0; i < linecount; i++ {
+		line := lines[i]
+		r := strings.IndexRune(line, ':')
+		if r == -1 {
+			return nil, errors.New(filename + " is not formatted correctly, expected ':'.")
+		}
+		proto := strings.ToLower(line[:r])
+		if !protos[proto] {
+			// skip protocol and data line
+			i++
+			continue
+		}
+
+		// Read header line
+		statNames := strings.Split(line[r+2:], " ")
+
+		// Read data line
+		i++
+		statValues := strings.Split(lines[i][r+2:], " ")
+		if len(statNames) != len(statValues) {
+			return nil, errors.New(filename + " is not formatted correctly, expected same number of columns.")
+		}
+		stat := ProtoCountersStat{
+			Protocol: proto,
+			Stats:    make(map[string]int64, len(statNames)),
+		}
+		for j := range statNames {
+			value, err := strconv.ParseInt(statValues[j], 10, 64)
+			if err != nil {
+				return nil, err
+			}
+			stat.Stats[statNames[j]] = value
+		}
+		stats = append(stats, stat)
+	}
+	return stats, nil
+}
+
+func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
+	countfile := common.HostProcWithContext(ctx, "sys/net/netfilter/nf_conntrack_count")
+	maxfile := common.HostProcWithContext(ctx, "sys/net/netfilter/nf_conntrack_max")
+
+	count, err := common.ReadInts(countfile)
+	if err != nil {
+		return nil, err
+	}
+	stats := make([]FilterStat, 0, 1)
+
+	maxConn, err := common.ReadInts(maxfile)
+	if err != nil {
+		return nil, err
+	}
+
+	payload := FilterStat{
+		ConnTrackCount: count[0],
+		ConnTrackMax:   maxConn[0],
+	}
+
+	stats = append(stats, payload)
+	return stats, nil
+}
+
+// ConntrackStatsWithContext returns more detailed info about the conntrack table
+func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
+	return conntrackStatsFromFile(common.HostProcWithContext(ctx, "net/stat/nf_conntrack"), percpu)
+}
+
+// conntrackStatsFromFile returns more detailed info about the conntrack table
+// from `filename`
+// If 'percpu' is false, the result will contain exactly one item with totals/summary
+func conntrackStatsFromFile(filename string, percpu bool) ([]ConntrackStat, error) {
+	lines, err := common.ReadLines(filename)
+	if err != nil {
+		return nil, err
+	}
+
+	statlist := NewConntrackStatList()
+
+	for _, line := range lines {
+		fields := strings.Fields(line)
+		if len(fields) == 17 && fields[0] != "entries" {
+			statlist.Append(NewConntrackStat(
+				common.HexToUint32(fields[ctENTRIES]),
+				common.HexToUint32(fields[ctSEARCHED]),
+				common.HexToUint32(fields[ctFOUND]),
+				common.HexToUint32(fields[ctNEW]),
+				common.HexToUint32(fields[ctINVALID]),
+				common.HexToUint32(fields[ctIGNORE]),
+				common.HexToUint32(fields[ctDELETE]),
+				common.HexToUint32(fields[ctDELETE_LIST]),
+				common.HexToUint32(fields[ctINSERT]),
+				common.HexToUint32(fields[ctINSERT_FAILED]),
+				common.HexToUint32(fields[ctDROP]),
+				common.HexToUint32(fields[ctEARLY_DROP]),
+				common.HexToUint32(fields[ctICMP_ERROR]),
+				common.HexToUint32(fields[CT_EXPEctNEW]),
+				common.HexToUint32(fields[ctEXPECT_CREATE]),
+				common.HexToUint32(fields[CT_EXPEctDELETE]),
+				common.HexToUint32(fields[ctSEARCH_RESTART]),
+			))
+		}
+	}
+
+	if percpu {
+		return statlist.Items(), nil
+	}
+	return statlist.Summary(), nil
+}
+
+// http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
+var tcpStatuses = map[string]string{
+	"01": "ESTABLISHED",
+	"02": "SYN_SENT",
+	"03": "SYN_RECV",
+	"04": "FIN_WAIT1",
+	"05": "FIN_WAIT2",
+	"06": "TIME_WAIT",
+	"07": "CLOSE",
+	"08": "CLOSE_WAIT",
+	"09": "LAST_ACK",
+	"0A": "LISTEN",
+	"0B": "CLOSING",
+}
+
+type netConnectionKindType struct {
+	family   uint32
+	sockType uint32
+	filename string
+}
+
+var kindTCP4 = netConnectionKindType{
+	family:   syscall.AF_INET,
+	sockType: syscall.SOCK_STREAM,
+	filename: "tcp",
+}
+
+var kindTCP6 = netConnectionKindType{
+	family:   syscall.AF_INET6,
+	sockType: syscall.SOCK_STREAM,
+	filename: "tcp6",
+}
+
+var kindUDP4 = netConnectionKindType{
+	family:   syscall.AF_INET,
+	sockType: syscall.SOCK_DGRAM,
+	filename: "udp",
+}
+
+var kindUDP6 = netConnectionKindType{
+	family:   syscall.AF_INET6,
+	sockType: syscall.SOCK_DGRAM,
+	filename: "udp6",
+}
+
+var kindUNIX = netConnectionKindType{
+	family:   syscall.AF_UNIX,
+	filename: "unix",
+}
+
+var netConnectionKindMap = map[string][]netConnectionKindType{
+	"all":   {kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},
+	"tcp":   {kindTCP4, kindTCP6},
+	"tcp4":  {kindTCP4},
+	"tcp6":  {kindTCP6},
+	"udp":   {kindUDP4, kindUDP6},
+	"udp4":  {kindUDP4},
+	"udp6":  {kindUDP6},
+	"unix":  {kindUNIX},
+	"inet":  {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+	"inet4": {kindTCP4, kindUDP4},
+	"inet6": {kindTCP6, kindUDP6},
+}
+
+type inodeMap struct {
+	pid int32
+	fd  uint32
+}
+
+type connTmp struct {
+	fd       uint32
+	family   uint32
+	sockType uint32
+	laddr    Addr
+	raddr    Addr
+	status   string
+	pid      int32
+	boundPid int32
+	path     string
+	inode    string
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsPidWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int, skipUids bool) ([]ConnectionStat, error) {
+	tmap, ok := netConnectionKindMap[kind]
+	if !ok {
+		return nil, fmt.Errorf("invalid kind, %s", kind)
+	}
+	root := common.HostProcWithContext(ctx)
+	var err error
+	var inodes map[string][]inodeMap
+	if pid == 0 {
+		inodes, err = getProcInodesAllWithContext(ctx, root, maxConn)
+	} else {
+		inodes, err = getProcInodes(root, pid, maxConn)
+		if len(inodes) == 0 {
+			// no connection for the pid
+			return []ConnectionStat{}, nil
+		}
+	}
+	if err != nil {
+		return nil, fmt.Errorf("could not get pid(s), %d: %w", pid, err)
+	}
+	return statsFromInodesWithContext(ctx, root, pid, tmap, inodes, skipUids)
+}
+
+// connectionDedupKey builds a key to deduplicate connections.
+// For inet sockets, the tuple (type, src, dst, status) is sufficient.
+// For unix sockets, unnamed sockets share the same empty address,
+// so pid, fd, and inode must be included to avoid incorrect deduplication.
+// The inode is especially important when pid/fd are unavailable (e.g.,
+// unprivileged queries where inode-to-pid mapping fails).
+func connectionDedupKey(family uint32, c connTmp) string {
+	if family == syscall.AF_UNIX {
+		return fmt.Sprintf("%d-%d-%s-%d-%s:%d-%s:%d-%s", c.pid, c.fd, c.inode, c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)
+	}
+	return fmt.Sprintf("%d-%s:%d-%s:%d-%s", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)
+}
+
+func statsFromInodesWithContext(ctx context.Context, root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap, skipUids bool) ([]ConnectionStat, error) {
+	dupCheckMap := make(map[string]struct{})
+	var ret []ConnectionStat
+
+	var err error
+	for _, t := range tmap {
+		var path string
+		var ls []connTmp
+		if pid == 0 {
+			path = fmt.Sprintf("%s/net/%s", root, t.filename)
+		} else {
+			path = fmt.Sprintf("%s/%d/net/%s", root, pid, t.filename)
+		}
+		switch t.family {
+		case syscall.AF_INET, syscall.AF_INET6:
+			ls, err = processInet(path, t, inodes, pid)
+		case syscall.AF_UNIX:
+			ls, err = processUnix(path, t, inodes, pid)
+		}
+		if err != nil {
+			return nil, err
+		}
+		for _, c := range ls {
+			connKey := connectionDedupKey(t.family, c)
+			if _, ok := dupCheckMap[connKey]; ok {
+				continue
+			}
+
+			conn := ConnectionStat{
+				Fd:     c.fd,
+				Family: c.family,
+				Type:   c.sockType,
+				Laddr:  c.laddr,
+				Raddr:  c.raddr,
+				Status: c.status,
+				Pid:    c.pid,
+			}
+			if c.pid == 0 {
+				conn.Pid = c.boundPid
+			} else {
+				conn.Pid = c.pid
+			}
+
+			if !skipUids {
+				// fetch process owner Real, effective, saved set, and filesystem UIDs
+				proc := process{Pid: conn.Pid}
+				conn.Uids, _ = proc.getUids(ctx)
+			}
+
+			ret = append(ret, conn)
+			dupCheckMap[connKey] = struct{}{}
+		}
+
+	}
+
+	return ret, nil
+}
+
+// getProcInodes returns fd of the pid.
+func getProcInodes(root string, pid int32, maxConn int) (map[string][]inodeMap, error) {
+	ret := make(map[string][]inodeMap)
+
+	dir := fmt.Sprintf("%s/%d/fd", root, pid)
+	f, err := os.Open(dir)
+	if err != nil {
+		return ret, err
+	}
+	defer f.Close()
+	dirEntries, err := f.ReadDir(maxConn)
+	if err != nil {
+		return ret, err
+	}
+	for _, dirEntry := range dirEntries {
+		inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, dirEntry.Name())
+
+		inode, err := os.Readlink(inodePath)
+		if err != nil {
+			continue
+		}
+		if !strings.HasPrefix(inode, "socket:[") {
+			continue
+		}
+		// the process is using a socket
+		l := len(inode)
+		inode = inode[8 : l-1]
+		_, ok := ret[inode]
+		if !ok {
+			ret[inode] = make([]inodeMap, 0)
+		}
+		fd, err := strconv.ParseInt(dirEntry.Name(), 10, 32)
+		if err != nil {
+			continue
+		}
+
+		i := inodeMap{
+			pid: pid,
+			fd:  uint32(fd),
+		}
+		ret[inode] = append(ret[inode], i)
+	}
+	return ret, nil
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+	var ret []int32
+
+	d, err := os.Open(common.HostProcWithContext(ctx))
+	if err != nil {
+		return nil, err
+	}
+	defer d.Close()
+
+	fnames, err := d.Readdirnames(-1)
+	if err != nil {
+		return nil, err
+	}
+	for _, fname := range fnames {
+		pid, err := strconv.ParseInt(fname, 10, 32)
+		if err != nil {
+			// if not numeric name, just skip
+			continue
+		}
+		ret = append(ret, int32(pid))
+	}
+
+	return ret, nil
+}
+
+// Note: the following is based off process_linux structs and methods
+// we need these to fetch the owner of a process ID
+// FIXME: Import process occurs import cycle.
+// see remarks on pids()
+type process struct {
+	Pid  int32 `json:"pid"`
+	uids []int32
+}
+
+// Uids returns user ids of the process as a slice of the int
+func (p *process) getUids(ctx context.Context) ([]int32, error) {
+	err := p.fillFromStatus(ctx)
+	if err != nil {
+		return []int32{}, err
+	}
+	return p.uids, nil
+}
+
+// Get status from /proc/(pid)/status
+func (p *process) fillFromStatus(ctx context.Context) error {
+	pid := p.Pid
+	statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status")
+	contents, err := os.ReadFile(statPath)
+	if err != nil {
+		return err
+	}
+	lines := strings.Split(string(contents), "\n")
+	for _, line := range lines {
+		tabParts := strings.SplitN(line, "\t", 2)
+		if len(tabParts) < 2 {
+			continue
+		}
+		value := tabParts[1]
+		if strings.TrimRight(tabParts[0], ":") == "Uid" {
+			p.uids = make([]int32, 0, 4)
+			for _, i := range strings.Split(value, "\t") {
+				v, err := strconv.ParseInt(i, 10, 32)
+				if err != nil {
+					return err
+				}
+				p.uids = append(p.uids, int32(v))
+			}
+		}
+	}
+	return nil
+}
+
+func getProcInodesAllWithContext(ctx context.Context, root string, maxConn int) (map[string][]inodeMap, error) {
+	pids, err := PidsWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	ret := make(map[string][]inodeMap)
+
+	for _, pid := range pids {
+		t, err := getProcInodes(root, pid, maxConn)
+		if err != nil {
+			// skip if permission error or no longer exists
+			if os.IsPermission(err) || os.IsNotExist(err) || errors.Is(err, io.EOF) {
+				continue
+			}
+			return ret, err
+		}
+		if len(t) == 0 {
+			continue
+		}
+		// TODO: update ret.
+		ret = updateMap(ret, t)
+	}
+	return ret, nil
+}
+
+// decodeAddress decode address represents addr in proc/net/*
+// ex:
+// "0500000A:0016" -> "10.0.0.5", 22
+// "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53
+func decodeAddress(family uint32, src string) (Addr, error) {
+	t := strings.Split(src, ":")
+	if len(t) != 2 {
+		return Addr{}, fmt.Errorf("does not contain port, %s", src)
+	}
+	addr := t[0]
+	port, err := strconv.ParseUint(t[1], 16, 16)
+	if err != nil {
+		return Addr{}, fmt.Errorf("invalid port, %s", src)
+	}
+	decoded, err := hex.DecodeString(addr)
+	if err != nil {
+		return Addr{}, fmt.Errorf("decode error, %w", err)
+	}
+	var ip net.IP
+
+	if family == syscall.AF_INET {
+		if common.IsLittleEndian() {
+			ip = net.IP(Reverse(decoded))
+		} else {
+			ip = net.IP(decoded)
+		}
+	} else { // IPv6
+		ip, err = parseIPv6HexString(decoded)
+		if err != nil {
+			return Addr{}, err
+		}
+	}
+	return Addr{
+		IP:   ip.String(),
+		Port: uint32(port),
+	}, nil
+}
+
+func Reverse(s []byte) []byte {
+	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
+		s[i], s[j] = s[j], s[i]
+	}
+	return s
+}
+
+// parseIPv6HexString parse array of bytes to IPv6 string
+func parseIPv6HexString(src []byte) (net.IP, error) {
+	if len(src) != 16 {
+		return nil, errors.New("invalid IPv6 string")
+	}
+
+	buf := make([]byte, 0, 16)
+	for i := 0; i < len(src); i += 4 {
+		r := Reverse(src[i : i+4])
+		buf = append(buf, r...)
+	}
+	return net.IP(buf), nil
+}
+
+func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
+	if strings.HasSuffix(file, "6") && !common.PathExists(file) {
+		// IPv6 not supported, return empty.
+		return []connTmp{}, nil
+	}
+
+	// Read the contents of the /proc file with a single read sys call.
+	// This minimizes duplicates in the returned connections
+	// For more info:
+	// https://github.com/shirou/gopsutil/pull/361
+	contents, err := os.ReadFile(file)
+	if err != nil {
+		return nil, err
+	}
+
+	lines := bytes.Split(contents, []byte("\n"))
+
+	var ret []connTmp
+	// skip first line
+	for _, line := range lines[1:] {
+		l := strings.Fields(string(line))
+		if len(l) < 10 {
+			continue
+		}
+		laddr := l[1]
+		raddr := l[2]
+		status := l[3]
+		inode := l[9]
+		pid := int32(0)
+		fd := uint32(0)
+		i, exists := inodes[inode]
+		if exists {
+			pid = i[0].pid
+			fd = i[0].fd
+		}
+		if filterPid > 0 && filterPid != pid {
+			continue
+		}
+		if kind.sockType == syscall.SOCK_STREAM {
+			status = tcpStatuses[status]
+		} else {
+			status = "NONE"
+		}
+		la, err := decodeAddress(kind.family, laddr)
+		if err != nil {
+			continue
+		}
+		ra, err := decodeAddress(kind.family, raddr)
+		if err != nil {
+			continue
+		}
+
+		ret = append(ret, connTmp{
+			fd:       fd,
+			family:   kind.family,
+			sockType: kind.sockType,
+			laddr:    la,
+			raddr:    ra,
+			status:   status,
+			pid:      pid,
+			inode:    inode,
+		})
+	}
+
+	return ret, nil
+}
+
+func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
+	// Read the contents of the /proc file with a single read sys call.
+	// This minimizes duplicates in the returned connections
+	// For more info:
+	// https://github.com/shirou/gopsutil/pull/361
+	contents, err := os.ReadFile(file)
+	if err != nil {
+		return nil, err
+	}
+
+	lines := bytes.Split(contents, []byte("\n"))
+
+	var ret []connTmp
+	// skip first line
+	for _, line := range lines[1:] {
+		tokens := strings.Fields(string(line))
+		if len(tokens) < 6 {
+			continue
+		}
+		st, err := strconv.ParseInt(tokens[4], 10, 32)
+		if err != nil {
+			return nil, err
+		}
+
+		inode := tokens[6]
+
+		var pairs []inodeMap
+		pairs, exists := inodes[inode]
+		if !exists {
+			pairs = []inodeMap{
+				{},
+			}
+		}
+		for _, pair := range pairs {
+			if filterPid > 0 && filterPid != pair.pid {
+				continue
+			}
+			var path string
+			if len(tokens) == 8 {
+				path = tokens[len(tokens)-1]
+			}
+			ret = append(ret, connTmp{
+				fd:       pair.fd,
+				family:   kind.family,
+				sockType: uint32(st),
+				laddr: Addr{
+					IP: path,
+				},
+				pid:    pair.pid,
+				status: "NONE",
+				path:   path,
+				inode:  inode,
+			})
+		}
+	}
+
+	return ret, nil
+}
+
+func updateMap(src, add map[string][]inodeMap) map[string][]inodeMap {
+	for key, value := range add {
+		a, exists := src[key]
+		if !exists {
+			src[key] = value
+			continue
+		}
+		src[key] = append(a, value...)
+	}
+	return src
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_netbsd.go b/vendor/github.com/shirou/gopsutil/v4/net/net_netbsd.go
new file mode 100644
index 000000000..d0e44fbf2
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_netbsd.go
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build netbsd
+
+package net
+
+import (
+	"context"
+	"fmt"
+	"os/exec"
+	"regexp"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
+
+// parseNetstat parses the output of "netstat -inb" (mode "inb") or
+// "netstat -ind" (mode "ind") and merges results into iocs.
+//
+// NetBSD netstat column layout (0-indexed fields after strings.Fields):
+//
+//	-inb with Address    (6 fields):  Name Mtu Network Address   Ibytes  Obytes
+//	-inb without Address (5 fields):  Name Mtu Network          Ibytes  Obytes
+//
+//	-ind with Address    (11 fields): Name Mtu Network Address   Ipkts Ierrs Idrops Opkts Oerrs Colls Odrops
+//	-ind without Address (10 fields): Name Mtu Network          Ipkts Ierrs Idrops Opkts Oerrs Colls Odrops
+//
+// The Address field is present for non-loopback interfaces and absent for
+// loopback (lo0). We detect this via field count and set base accordingly.
+//
+// Reference: https://man.netbsd.org/netstat.1
+func parseNetstat(output, mode string, iocs map[string]IOCountersStat) error {
+	// Minimum field counts when Address is absent.
+	minFields := map[string]int{
+		"inb": 5,
+		"ind": 10,
+	}
+	// Field count when Address is present (base = 1).
+	addrFields := map[string]int{
+		"inb": 6,
+		"ind": 11,
+	}
+
+	seen := make([]string, 0)
+
+	for _, line := range strings.Split(output, "\n") {
+		values := strings.Fields(line)
+		if len(values) < 1 || values[0] == "Name" {
+			continue
+		}
+		if common.StringsHas(seen, values[0]) {
+			continue
+		}
+		if len(values) < minFields[mode] {
+			continue
+		}
+
+		base := 0
+		if len(values) >= addrFields[mode] {
+			base = 1
+		}
+
+		seen = append(seen, values[0])
+
+		n, present := iocs[values[0]]
+		if !present {
+			n = IOCountersStat{Name: values[0]}
+		}
+
+		switch mode {
+		case "inb":
+			recv, err := parseUint(values[base+3])
+			if err != nil {
+				return err
+			}
+			sent, err := parseUint(values[base+4])
+			if err != nil {
+				return err
+			}
+			n.BytesRecv = recv
+			n.BytesSent = sent
+
+		case "ind":
+			// Ipkts Ierrs Idrops Opkts Oerrs Colls Odrops
+			pktsRecv, err := parseUint(values[base+3])
+			if err != nil {
+				return err
+			}
+			errin, err := parseUint(values[base+4])
+			if err != nil {
+				return err
+			}
+			dropin, err := parseUint(values[base+5])
+			if err != nil {
+				return err
+			}
+			pktsSent, err := parseUint(values[base+6])
+			if err != nil {
+				return err
+			}
+			errout, err := parseUint(values[base+7])
+			if err != nil {
+				return err
+			}
+			// values[base+8] = Colls (not mapped to IOCountersStat)
+			dropout, err := parseUint(values[base+9])
+			if err != nil {
+				return err
+			}
+			n.PacketsRecv = pktsRecv
+			n.Errin = errin
+			n.Dropin = dropin
+			n.PacketsSent = pktsSent
+			n.Errout = errout
+			n.Dropout = dropout
+		}
+
+		iocs[n.Name] = n
+	}
+	return nil
+}
+
+func parseUint(s string) (uint64, error) {
+	if s == "-" {
+		return 0, nil
+	}
+	return strconv.ParseUint(s, 10, 64)
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+	netstat, err := exec.LookPath("netstat")
+	if err != nil {
+		return nil, err
+	}
+
+	outBytes, err := invoke.CommandWithContext(ctx, netstat, "-inb")
+	if err != nil {
+		return nil, err
+	}
+	outPackets, err := invoke.CommandWithContext(ctx, netstat, "-ind")
+	if err != nil {
+		return nil, err
+	}
+
+	iocs := make(map[string]IOCountersStat)
+
+	if err := parseNetstat(string(outBytes), "inb", iocs); err != nil {
+		return nil, err
+	}
+	if err := parseNetstat(string(outPackets), "ind", iocs); err != nil {
+		return nil, err
+	}
+
+	ret := make([]IOCountersStat, 0, len(iocs))
+	for _, ioc := range iocs {
+		ret = append(ret, ioc)
+	}
+
+	if !pernic {
+		return getIOCountersAll(ret), nil
+	}
+
+	return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
+	return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func parseNetstatLine(line string) (ConnectionStat, error) {
+	f := strings.Fields(line)
+	if len(f) < 5 {
+		return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+	}
+
+	var netType, netFamily uint32
+	switch f[0] {
+	case "tcp":
+		netType = syscall.SOCK_STREAM
+		netFamily = syscall.AF_INET
+	case "udp":
+		netType = syscall.SOCK_DGRAM
+		netFamily = syscall.AF_INET
+	case "tcp6":
+		netType = syscall.SOCK_STREAM
+		netFamily = syscall.AF_INET6
+	case "udp6":
+		netType = syscall.SOCK_DGRAM
+		netFamily = syscall.AF_INET6
+	default:
+		return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
+	}
+
+	laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
+	if err != nil {
+		return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
+	}
+
+	n := ConnectionStat{
+		Fd:     uint32(0), // not supported
+		Family: uint32(netFamily),
+		Type:   uint32(netType),
+		Laddr:  laddr,
+		Raddr:  raddr,
+		Pid:    int32(0), // not supported
+	}
+	if len(f) == 6 {
+		n.Status = f[5]
+	}
+
+	return n, nil
+}
+
+func parseAddr(l string, family uint32) (Addr, error) {
+	matches := portMatch.FindStringSubmatch(l)
+	if matches == nil {
+		return Addr{}, fmt.Errorf("wrong addr, %s", l)
+	}
+	host := matches[1]
+	port := matches[2]
+	if host == "*" {
+		switch family {
+		case syscall.AF_INET:
+			host = "0.0.0.0"
+		case syscall.AF_INET6:
+			host = "::"
+		default:
+			return Addr{}, fmt.Errorf("unknown family, %d", family)
+		}
+	}
+	lport, err := strconv.ParseInt(port, 10, 32)
+	if err != nil {
+		return Addr{}, err
+	}
+	return Addr{IP: host, Port: uint32(lport)}, nil
+}
+
+func parseNetstatAddr(local, remote string, family uint32) (laddr, raddr Addr, err error) {
+	laddr, err = parseAddr(local, family)
+	if err != nil {
+		return laddr, raddr, err
+	}
+	if remote != "*.*" {
+		raddr, err = parseAddr(remote, family)
+		if err != nil {
+			return laddr, raddr, err
+		}
+	}
+	return laddr, raddr, err
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	var ret []ConnectionStat
+
+	args := []string{"-na"}
+	switch strings.ToLower(kind) {
+	default:
+		fallthrough
+	case "", "all", "inet":
+		// nothing to add
+	case "inet4":
+		args = append(args, "-finet")
+	case "inet6":
+		args = append(args, "-finet6")
+	case "tcp":
+		args = append(args, "-ptcp")
+	case "tcp4":
+		args = append(args, "-ptcp", "-finet")
+	case "tcp6":
+		args = append(args, "-ptcp", "-finet6")
+	case "udp":
+		args = append(args, "-pudp")
+	case "udp4":
+		args = append(args, "-pudp", "-finet")
+	case "udp6":
+		args = append(args, "-pudp", "-finet6")
+	case "unix":
+		return ret, common.ErrNotImplementedError
+	}
+
+	netstat, err := exec.LookPath("netstat")
+	if err != nil {
+		return nil, err
+	}
+	out, err := invoke.CommandWithContext(ctx, netstat, args...)
+	if err != nil {
+		return nil, err
+	}
+	for _, line := range strings.Split(string(out), "\n") {
+		if !strings.HasPrefix(line, "tcp") && !strings.HasPrefix(line, "udp") {
+			continue
+		}
+		n, err := parseNetstatLine(line)
+		if err != nil {
+			continue
+		}
+		ret = append(ret, n)
+	}
+
+	return ret, nil
+}
+
+func ConnectionsPidWithContext(_ context.Context, _ string, _ int32) ([]ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(_ context.Context, _ string, _ int) ([]ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsPidMaxWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/net/net_openbsd.go
new file mode 100644
index 000000000..ec4cfb957
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_openbsd.go
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package net
+
+import (
+	"context"
+	"fmt"
+	"os/exec"
+	"regexp"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
+
+func ParseNetstat(output string, mode string,
+	iocs map[string]IOCountersStat,
+) error {
+	lines := strings.Split(output, "\n")
+
+	exists := make([]string, 0, len(lines)-1)
+
+	columns := 9
+	if mode == "inb" {
+		columns = 6
+	}
+	for _, line := range lines {
+		values := strings.Fields(line)
+		if len(values) < 1 || values[0] == "Name" {
+			continue
+		}
+		if common.StringsHas(exists, values[0]) {
+			// skip if already get
+			continue
+		}
+
+		if len(values) < columns {
+			continue
+		}
+		base := 1
+		// sometimes Address is omitted
+		if len(values) < columns {
+			base = 0
+		}
+
+		parsed := make([]uint64, 0, 8)
+		var vv []string
+		switch mode {
+		case "inb":
+			vv = []string{
+				values[base+3], // BytesRecv
+				values[base+4], // BytesSent
+			}
+		case "ind":
+			vv = []string{
+				values[base+3], // Ipkts
+				values[base+4], // Idrop
+				values[base+5], // Opkts
+				values[base+6], // Odrops
+			}
+		case "ine":
+			vv = []string{
+				values[base+4], // Ierrs
+				values[base+6], // Oerrs
+			}
+		}
+		for _, target := range vv {
+			if target == "-" {
+				parsed = append(parsed, 0)
+				continue
+			}
+
+			t, err := strconv.ParseUint(target, 10, 64)
+			if err != nil {
+				return err
+			}
+			parsed = append(parsed, t)
+		}
+		exists = append(exists, values[0])
+
+		n, present := iocs[values[0]]
+		if !present {
+			n = IOCountersStat{Name: values[0]}
+		}
+
+		switch mode {
+		case "inb":
+			n.BytesRecv = parsed[0]
+			n.BytesSent = parsed[1]
+		case "ind":
+			n.PacketsRecv = parsed[0]
+			n.Dropin = parsed[1]
+			n.PacketsSent = parsed[2]
+			n.Dropout = parsed[3]
+		case "ine":
+			n.Errin = parsed[0]
+			n.Errout = parsed[1]
+		}
+
+		iocs[n.Name] = n
+	}
+	return nil
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+	netstat, err := exec.LookPath("netstat")
+	if err != nil {
+		return nil, err
+	}
+	out, err := invoke.CommandWithContext(ctx, netstat, "-inb")
+	if err != nil {
+		return nil, err
+	}
+	out2, err := invoke.CommandWithContext(ctx, netstat, "-ind")
+	if err != nil {
+		return nil, err
+	}
+	out3, err := invoke.CommandWithContext(ctx, netstat, "-ine")
+	if err != nil {
+		return nil, err
+	}
+	iocs := make(map[string]IOCountersStat)
+
+	lines := strings.Split(string(out), "\n")
+	ret := make([]IOCountersStat, 0, len(lines)-1)
+
+	err = ParseNetstat(string(out), "inb", iocs)
+	if err != nil {
+		return nil, err
+	}
+	err = ParseNetstat(string(out2), "ind", iocs)
+	if err != nil {
+		return nil, err
+	}
+	err = ParseNetstat(string(out3), "ine", iocs)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, ioc := range iocs {
+		ret = append(ret, ioc)
+	}
+
+	if !pernic {
+		return getIOCountersAll(ret), nil
+	}
+
+	return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
+	return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func parseNetstatLine(line string) (ConnectionStat, error) {
+	f := strings.Fields(line)
+	if len(f) < 5 {
+		return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+	}
+
+	var netType, netFamily uint32
+	switch f[0] {
+	case "tcp":
+		netType = syscall.SOCK_STREAM
+		netFamily = syscall.AF_INET
+	case "udp":
+		netType = syscall.SOCK_DGRAM
+		netFamily = syscall.AF_INET
+	case "tcp6":
+		netType = syscall.SOCK_STREAM
+		netFamily = syscall.AF_INET6
+	case "udp6":
+		netType = syscall.SOCK_DGRAM
+		netFamily = syscall.AF_INET6
+	default:
+		return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
+	}
+
+	laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
+	if err != nil {
+		return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
+	}
+
+	n := ConnectionStat{
+		Fd:     uint32(0), // not supported
+		Family: uint32(netFamily),
+		Type:   uint32(netType),
+		Laddr:  laddr,
+		Raddr:  raddr,
+		Pid:    int32(0), // not supported
+	}
+	if len(f) == 6 {
+		n.Status = f[5]
+	}
+
+	return n, nil
+}
+
+func parseAddr(l string, family uint32) (Addr, error) {
+	matches := portMatch.FindStringSubmatch(l)
+	if matches == nil {
+		return Addr{}, fmt.Errorf("wrong addr, %s", l)
+	}
+	host := matches[1]
+	port := matches[2]
+	if host == "*" {
+		switch family {
+		case syscall.AF_INET:
+			host = "0.0.0.0"
+		case syscall.AF_INET6:
+			host = "::"
+		default:
+			return Addr{}, fmt.Errorf("unknown family, %d", family)
+		}
+	}
+	lport, err := strconv.ParseInt(port, 10, 32)
+	if err != nil {
+		return Addr{}, err
+	}
+	return Addr{IP: host, Port: uint32(lport)}, nil
+}
+
+func parseNetstatAddr(local, remote string, family uint32) (laddr, raddr Addr, err error) {
+	laddr, err = parseAddr(local, family)
+	if remote != "*.*" { // remote addr exists
+		raddr, err = parseAddr(remote, family)
+		if err != nil {
+			return laddr, raddr, err
+		}
+	}
+
+	return laddr, raddr, err
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	var ret []ConnectionStat
+
+	args := []string{"-na"}
+	switch strings.ToLower(kind) {
+	default:
+		fallthrough
+	case "", "all", "inet":
+		// nothing to add
+	case "inet4":
+		args = append(args, "-finet")
+	case "inet6":
+		args = append(args, "-finet6")
+	case "tcp":
+		args = append(args, "-ptcp")
+	case "tcp4":
+		args = append(args, "-ptcp", "-finet")
+	case "tcp6":
+		args = append(args, "-ptcp", "-finet6")
+	case "udp":
+		args = append(args, "-pudp")
+	case "udp4":
+		args = append(args, "-pudp", "-finet")
+	case "udp6":
+		args = append(args, "-pudp", "-finet6")
+	case "unix":
+		return ret, common.ErrNotImplementedError
+	}
+
+	netstat, err := exec.LookPath("netstat")
+	if err != nil {
+		return nil, err
+	}
+	out, err := invoke.CommandWithContext(ctx, netstat, args...)
+	if err != nil {
+		return nil, err
+	}
+	lines := strings.Split(string(out), "\n")
+	for _, line := range lines {
+		if !strings.HasPrefix(line, "tcp") && !strings.HasPrefix(line, "udp") {
+			continue
+		}
+		n, err := parseNetstatLine(line)
+		if err != nil {
+			continue
+		}
+
+		ret = append(ret, n)
+	}
+
+	return ret, nil
+}
+
+func ConnectionsPidWithContext(_ context.Context, _ string, _ int32) ([]ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(_ context.Context, _ string, _ int) ([]ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsPidMaxWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_solaris.go b/vendor/github.com/shirou/gopsutil/v4/net/net_solaris.go
new file mode 100644
index 000000000..df067806c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_solaris.go
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build solaris
+
+package net
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var kstatSplit = regexp.MustCompile(`[:\s]+`)
+
+func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
+	// collect all the net class's links with below statistics
+	filterstr := "/^(?!vnic)/::phys:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/"
+	if runtime.GOOS == "illumos" {
+		filterstr = "/[^vnic]/::mac:/^rbytes64$|^ipackets64$|^idrops64$|^ierrors$|^obytes64$|^opackets64$|^odrops64$|^oerrors$/"
+	}
+	kstatSysOut, err := invoke.CommandWithContext(ctx, "kstat", "-c", "net", "-p", filterstr)
+	if err != nil {
+		return nil, fmt.Errorf("cannot execute kstat: %w", err)
+	}
+
+	lines := strings.Split(strings.TrimSpace(string(kstatSysOut)), "\n")
+	if len(lines) == 0 {
+		return nil, errors.New("no interface found")
+	}
+	rbytes64arr := make(map[string]uint64)
+	ipackets64arr := make(map[string]uint64)
+	idrops64arr := make(map[string]uint64)
+	ierrorsarr := make(map[string]uint64)
+	obytes64arr := make(map[string]uint64)
+	opackets64arr := make(map[string]uint64)
+	odrops64arr := make(map[string]uint64)
+	oerrorsarr := make(map[string]uint64)
+
+	for _, line := range lines {
+		fields := kstatSplit.Split(line, -1)
+		interfaceName := fields[0]
+		instance := fields[1]
+		switch fields[3] {
+		case "rbytes64":
+			rbytes64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse rbytes64: %w", err)
+			}
+		case "ipackets64":
+			ipackets64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse ipackets64: %w", err)
+			}
+		case "idrops64":
+			idrops64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse idrops64: %w", err)
+			}
+		case "ierrors":
+			ierrorsarr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse ierrors: %w", err)
+			}
+		case "obytes64":
+			obytes64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse obytes64: %w", err)
+			}
+		case "opackets64":
+			opackets64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse opackets64: %w", err)
+			}
+		case "odrops64":
+			odrops64arr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse odrops64: %w", err)
+			}
+		case "oerrors":
+			oerrorsarr[interfaceName+instance], err = strconv.ParseUint(fields[4], 10, 64)
+			if err != nil {
+				return nil, fmt.Errorf("cannot parse oerrors: %w", err)
+			}
+		}
+	}
+	ret := make([]IOCountersStat, 0)
+	for k := range rbytes64arr {
+		nic := IOCountersStat{
+			Name:        k,
+			BytesRecv:   rbytes64arr[k],
+			PacketsRecv: ipackets64arr[k],
+			Errin:       ierrorsarr[k],
+			Dropin:      idrops64arr[k],
+			BytesSent:   obytes64arr[k],
+			PacketsSent: opackets64arr[k],
+			Errout:      oerrorsarr[k],
+			Dropout:     odrops64arr[k],
+		}
+		ret = append(ret, nic)
+	}
+
+	if !pernic {
+		return getIOCountersAll(ret), nil
+	}
+
+	return ret, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
+	return IOCountersWithContext(ctx, pernic)
+}
+
+func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsWithContext(_ context.Context, _ string) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_unix.go b/vendor/github.com/shirou/gopsutil/v4/net/net_unix.go
new file mode 100644
index 000000000..c491a2911
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_unix.go
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd || darwin
+
+package net
+
+import (
+	"context"
+	"fmt"
+	"net"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsPidWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithContext(_ context.Context, _ string, _ int) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	var ret []ConnectionStat
+
+	args := []string{"-i"}
+	switch strings.ToLower(kind) {
+	default:
+		fallthrough
+	case "", "all", "inet":
+		args = append(args, "tcp", "-i", "udp")
+	case "inet4":
+		args = append(args, "4")
+	case "inet6":
+		args = append(args, "6")
+	case "tcp":
+		args = append(args, "tcp")
+	case "tcp4":
+		args = append(args, "4tcp")
+	case "tcp6":
+		args = append(args, "6tcp")
+	case "udp":
+		args = append(args, "udp")
+	case "udp4":
+		args = append(args, "4udp")
+	case "udp6":
+		args = append(args, "6udp")
+	case "unix":
+		args = []string{"-U"}
+	}
+
+	r, err := common.CallLsofWithContext(ctx, invoke, pid, args...)
+	if err != nil {
+		return nil, err
+	}
+	for _, rr := range r {
+		if strings.HasPrefix(rr, "COMMAND") {
+			continue
+		}
+		n, err := parseNetLine(rr)
+		if err != nil {
+			continue
+		}
+
+		ret = append(ret, n)
+	}
+
+	return ret, nil
+}
+
+var constMap = map[string]int{
+	"unix": syscall.AF_UNIX,
+	"TCP":  syscall.SOCK_STREAM,
+	"UDP":  syscall.SOCK_DGRAM,
+	"IPv4": syscall.AF_INET,
+	"IPv6": syscall.AF_INET6,
+}
+
+func parseNetLine(line string) (ConnectionStat, error) {
+	f := strings.Fields(line)
+	if len(f) < 8 {
+		return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
+	}
+
+	if len(f) == 8 {
+		f = append(f, f[7])
+		f[7] = "unix"
+	}
+
+	pid, err := strconv.ParseInt(f[1], 10, 32)
+	if err != nil {
+		return ConnectionStat{}, err
+	}
+	fd, err := strconv.ParseInt(strings.Trim(f[3], "u"), 10, 32)
+	if err != nil {
+		return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3])
+	}
+	netFamily, ok := constMap[f[4]]
+	if !ok {
+		return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4])
+	}
+	netType, ok := constMap[f[7]]
+	if !ok {
+		return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7])
+	}
+
+	var laddr, raddr Addr
+	if f[7] == "unix" {
+		laddr.IP = f[8]
+	} else {
+		laddr, raddr, err = parseNetAddr(f[8])
+		if err != nil {
+			return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8])
+		}
+	}
+
+	n := ConnectionStat{
+		Fd:     uint32(fd),
+		Family: uint32(netFamily),
+		Type:   uint32(netType),
+		Laddr:  laddr,
+		Raddr:  raddr,
+		Pid:    int32(pid),
+	}
+	if len(f) == 10 {
+		n.Status = strings.Trim(f[9], "()")
+	}
+
+	return n, nil
+}
+
+func parseAddr(l string) (Addr, error) {
+	host, port, err := net.SplitHostPort(l)
+	if err != nil {
+		return Addr{}, fmt.Errorf("wrong addr, %s", l)
+	}
+	lport, err := strconv.ParseInt(port, 10, 32)
+	if err != nil {
+		return Addr{}, err
+	}
+	return Addr{IP: host, Port: uint32(lport)}, nil
+}
+
+func parseNetAddr(line string) (laddr, raddr Addr, err error) {
+	addrs := strings.Split(line, "->")
+	if len(addrs) == 0 {
+		return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line)
+	}
+	laddr, err = parseAddr(addrs[0])
+	if len(addrs) == 2 { // remote addr exists
+		raddr, err = parseAddr(addrs[1])
+		if err != nil {
+			return laddr, raddr, err
+		}
+	}
+
+	return laddr, raddr, err
+}
+
+func ConnectionsPidMaxWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/net/net_windows.go b/vendor/github.com/shirou/gopsutil/v4/net/net_windows.go
new file mode 100644
index 000000000..f530e4e57
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/net/net_windows.go
@@ -0,0 +1,731 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package net
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net"
+	"os"
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+var (
+	modiphlpapi             = windows.NewLazySystemDLL("iphlpapi.dll")
+	procGetExtendedTCPTable = modiphlpapi.NewProc("GetExtendedTcpTable")
+	procGetExtendedUDPTable = modiphlpapi.NewProc("GetExtendedUdpTable")
+	procGetIfEntry2         = modiphlpapi.NewProc("GetIfEntry2")
+)
+
+const (
+	TCPTableBasicListener = iota
+	TCPTableBasicConnections
+	TCPTableBasicAll
+	TCPTableOwnerPIDListener
+	TCPTableOwnerPIDConnections
+	TCPTableOwnerPIDAll
+	TCPTableOwnerModuleListener
+	TCPTableOwnerModuleConnections
+	TCPTableOwnerModuleAll
+)
+
+type netConnectionKindType struct {
+	family   uint32
+	sockType uint32
+	filename string
+}
+
+var kindTCP4 = netConnectionKindType{
+	family:   syscall.AF_INET,
+	sockType: syscall.SOCK_STREAM,
+	filename: "tcp",
+}
+
+var kindTCP6 = netConnectionKindType{
+	family:   syscall.AF_INET6,
+	sockType: syscall.SOCK_STREAM,
+	filename: "tcp6",
+}
+
+var kindUDP4 = netConnectionKindType{
+	family:   syscall.AF_INET,
+	sockType: syscall.SOCK_DGRAM,
+	filename: "udp",
+}
+
+var kindUDP6 = netConnectionKindType{
+	family:   syscall.AF_INET6,
+	sockType: syscall.SOCK_DGRAM,
+	filename: "udp6",
+}
+
+var netConnectionKindMap = map[string][]netConnectionKindType{
+	"all":   {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+	"tcp":   {kindTCP4, kindTCP6},
+	"tcp4":  {kindTCP4},
+	"tcp6":  {kindTCP6},
+	"udp":   {kindUDP4, kindUDP6},
+	"udp4":  {kindUDP4},
+	"udp6":  {kindUDP6},
+	"inet":  {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
+	"inet4": {kindTCP4, kindUDP4},
+	"inet6": {kindTCP6, kindUDP6},
+}
+
+// https://github.com/microsoft/ethr/blob/aecdaf923970e5a9b4c461b4e2e3963d781ad2cc/plt_windows.go#L114-L170
+type guid struct {
+	Data1 uint32
+	Data2 uint16
+	Data3 uint16
+	Data4 [8]byte
+}
+
+const (
+	maxStringSize        = 256
+	maxPhysAddressLength = 32
+	pad0for64_4for32     = 0
+)
+
+type mibIfRow2 struct {
+	InterfaceLuid               uint64
+	InterfaceIndex              uint32
+	InterfaceGuid               guid //nolint:revive //FIXME
+	Alias                       [maxStringSize + 1]uint16
+	Description                 [maxStringSize + 1]uint16
+	PhysicalAddressLength       uint32
+	PhysicalAddress             [maxPhysAddressLength]uint8
+	PermanentPhysicalAddress    [maxPhysAddressLength]uint8
+	Mtu                         uint32
+	Type                        uint32
+	TunnelType                  uint32
+	MediaType                   uint32
+	PhysicalMediumType          uint32
+	AccessType                  uint32
+	DirectionType               uint32
+	InterfaceAndOperStatusFlags uint32
+	OperStatus                  uint32
+	AdminStatus                 uint32
+	MediaConnectState           uint32
+	NetworkGuid                 guid //nolint:revive //FIXME
+	ConnectionType              uint32
+	padding1                    [pad0for64_4for32]byte
+	TransmitLinkSpeed           uint64
+	ReceiveLinkSpeed            uint64
+	InOctets                    uint64
+	InUcastPkts                 uint64
+	InNUcastPkts                uint64
+	InDiscards                  uint64
+	InErrors                    uint64
+	InUnknownProtos             uint64
+	InUcastOctets               uint64
+	InMulticastOctets           uint64
+	InBroadcastOctets           uint64
+	OutOctets                   uint64
+	OutUcastPkts                uint64
+	OutNUcastPkts               uint64
+	OutDiscards                 uint64
+	OutErrors                   uint64
+	OutUcastOctets              uint64
+	OutMulticastOctets          uint64
+	OutBroadcastOctets          uint64
+	OutQLen                     uint64
+}
+
+func IOCountersWithContext(_ context.Context, pernic bool) ([]IOCountersStat, error) {
+	ifs, err := net.Interfaces()
+	if err != nil {
+		return nil, err
+	}
+	var counters []IOCountersStat
+
+	err = procGetIfEntry2.Find()
+	if err == nil { // Vista+, uint64 values (issue#693)
+		for _, ifi := range ifs {
+			c := IOCountersStat{
+				Name: ifi.Name,
+			}
+
+			row := mibIfRow2{InterfaceIndex: uint32(ifi.Index)}
+			ret, _, err := procGetIfEntry2.Call(uintptr(unsafe.Pointer(&row)))
+			if ret != 0 {
+				return nil, os.NewSyscallError("GetIfEntry2", err)
+			}
+			c.BytesSent = uint64(row.OutOctets)
+			c.BytesRecv = uint64(row.InOctets)
+			c.PacketsSent = uint64(row.OutUcastPkts)
+			c.PacketsRecv = uint64(row.InUcastPkts)
+			c.Errin = uint64(row.InErrors)
+			c.Errout = uint64(row.OutErrors)
+			c.Dropin = uint64(row.InDiscards)
+			c.Dropout = uint64(row.OutDiscards)
+
+			counters = append(counters, c)
+		}
+	} else { // WinXP fallback, uint32 values
+		for _, ifi := range ifs {
+			c := IOCountersStat{
+				Name: ifi.Name,
+			}
+
+			row := windows.MibIfRow{Index: uint32(ifi.Index)}
+			err = windows.GetIfEntry(&row)
+			if err != nil {
+				return nil, os.NewSyscallError("GetIfEntry", err)
+			}
+			c.BytesSent = uint64(row.OutOctets)
+			c.BytesRecv = uint64(row.InOctets)
+			c.PacketsSent = uint64(row.OutUcastPkts)
+			c.PacketsRecv = uint64(row.InUcastPkts)
+			c.Errin = uint64(row.InErrors)
+			c.Errout = uint64(row.OutErrors)
+			c.Dropin = uint64(row.InDiscards)
+			c.Dropout = uint64(row.OutDiscards)
+
+			counters = append(counters, c)
+		}
+	}
+
+	if !pernic {
+		return getIOCountersAll(counters), nil
+	}
+	return counters, nil
+}
+
+func IOCountersByFileWithContext(ctx context.Context, pernic bool, _ string) ([]IOCountersStat, error) {
+	return IOCountersWithContext(ctx, pernic)
+}
+
+func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsPidWithContext(ctx, kind, 0)
+}
+
+func ConnectionsPidWithContext(_ context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	tmap, ok := netConnectionKindMap[kind]
+	if !ok {
+		return nil, fmt.Errorf("invalid kind, %s", kind)
+	}
+	return getProcInet(tmap, pid)
+}
+
+func getProcInet(kinds []netConnectionKindType, pid int32) ([]ConnectionStat, error) {
+	stats := make([]ConnectionStat, 0)
+
+	for _, kind := range kinds {
+		s, err := getNetStatWithKind(kind)
+		if err != nil {
+			continue
+		}
+
+		if pid == 0 {
+			stats = append(stats, s...)
+		} else {
+			for _, ns := range s {
+				if ns.Pid != pid {
+					continue
+				}
+				stats = append(stats, ns)
+			}
+		}
+	}
+
+	return stats, nil
+}
+
+func getNetStatWithKind(kindType netConnectionKindType) ([]ConnectionStat, error) {
+	if kindType.filename == "" {
+		return nil, errors.New("kind filename must be required")
+	}
+
+	switch kindType.filename {
+	case kindTCP4.filename:
+		return getTCPConnections(kindTCP4.family)
+	case kindTCP6.filename:
+		return getTCPConnections(kindTCP6.family)
+	case kindUDP4.filename:
+		return getUDPConnections(kindUDP4.family)
+	case kindUDP6.filename:
+		return getUDPConnections(kindUDP6.family)
+	}
+
+	return nil, fmt.Errorf("invalid kind filename, %s", kindType.filename)
+}
+
+// Deprecated: use process.PidsWithContext instead
+func PidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConnectionsMaxWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
+	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
+}
+
+func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, maxConn int) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, maxConn)
+}
+
+func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
+	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
+}
+
+func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, false)
+}
+
+func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, maxConn int) ([]ConnectionStat, error) {
+	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, maxConn, true)
+}
+
+func connectionsPidMaxWithoutUidsWithContext(_ context.Context, _ string, _ int32, _ int, _ bool) ([]ConnectionStat, error) {
+	return []ConnectionStat{}, common.ErrNotImplementedError
+}
+
+func FilterCountersWithContext(_ context.Context) ([]FilterStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ConntrackStatsWithContext(_ context.Context, _ bool) ([]ConntrackStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProtoCountersWithContext(_ context.Context, _ []string) ([]ProtoCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func getTableUintptr(family uint32, buf []byte) uintptr {
+	var (
+		pmibTCPTable  pmibTCPTableOwnerPidAll
+		pmibTCP6Table pmibTCP6TableOwnerPidAll
+
+		p uintptr
+	)
+	switch family {
+	case kindTCP4.family:
+		if len(buf) > 0 {
+			pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+			p = uintptr(unsafe.Pointer(pmibTCPTable))
+		} else {
+			p = uintptr(unsafe.Pointer(pmibTCPTable))
+		}
+	case kindTCP6.family:
+		if len(buf) > 0 {
+			pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+			p = uintptr(unsafe.Pointer(pmibTCP6Table))
+		} else {
+			p = uintptr(unsafe.Pointer(pmibTCP6Table))
+		}
+	}
+	return p
+}
+
+func getTableInfo(filename string, table any) (index, step, length int) {
+	switch filename {
+	case kindTCP4.filename:
+		index = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).DwNumEntries))
+		step = int(unsafe.Sizeof(table.(pmibTCPTableOwnerPidAll).Table))
+		length = int(table.(pmibTCPTableOwnerPidAll).DwNumEntries)
+	case kindTCP6.filename:
+		index = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).DwNumEntries))
+		step = int(unsafe.Sizeof(table.(pmibTCP6TableOwnerPidAll).Table))
+		length = int(table.(pmibTCP6TableOwnerPidAll).DwNumEntries)
+	case kindUDP4.filename:
+		index = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).DwNumEntries))
+		step = int(unsafe.Sizeof(table.(pmibUDPTableOwnerPid).Table))
+		length = int(table.(pmibUDPTableOwnerPid).DwNumEntries)
+	case kindUDP6.filename:
+		index = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).DwNumEntries))
+		step = int(unsafe.Sizeof(table.(pmibUDP6TableOwnerPid).Table))
+		length = int(table.(pmibUDP6TableOwnerPid).DwNumEntries)
+	}
+
+	return index, step, length
+}
+
+func getTCPConnections(family uint32) ([]ConnectionStat, error) {
+	var (
+		p    uintptr
+		buf  []byte
+		size uint32
+
+		pmibTCPTable  pmibTCPTableOwnerPidAll
+		pmibTCP6Table pmibTCP6TableOwnerPidAll
+	)
+
+	if family == 0 {
+		return nil, errors.New("faimly must be required")
+	}
+
+	for {
+		switch family {
+		case kindTCP4.family:
+			if len(buf) > 0 {
+				pmibTCPTable = (*mibTCPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+				p = uintptr(unsafe.Pointer(pmibTCPTable))
+			} else {
+				p = uintptr(unsafe.Pointer(pmibTCPTable))
+			}
+		case kindTCP6.family:
+			if len(buf) > 0 {
+				pmibTCP6Table = (*mibTCP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+				p = uintptr(unsafe.Pointer(pmibTCP6Table))
+			} else {
+				p = uintptr(unsafe.Pointer(pmibTCP6Table))
+			}
+		}
+
+		err := getExtendedTCPTable(p,
+			&size,
+			true,
+			family,
+			tcpTableOwnerPidAll,
+			0)
+		if err == nil {
+			break
+		}
+		if !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {
+			return nil, err
+		}
+		buf = make([]byte, size)
+	}
+
+	var (
+		index, step int
+		length      int
+	)
+
+	stats := make([]ConnectionStat, 0)
+	switch family {
+	case kindTCP4.family:
+		index, step, length = getTableInfo(kindTCP4.filename, pmibTCPTable)
+	case kindTCP6.family:
+		index, step, length = getTableInfo(kindTCP6.filename, pmibTCP6Table)
+	}
+
+	if length == 0 {
+		return nil, nil
+	}
+
+	for i := 0; i < length; i++ {
+		switch family {
+		case kindTCP4.family:
+			mibs := (*mibTCPRowOwnerPid)(unsafe.Pointer(&buf[index]))
+			ns := mibs.convertToConnectionStat()
+			stats = append(stats, ns)
+		case kindTCP6.family:
+			mibs := (*mibTCP6RowOwnerPid)(unsafe.Pointer(&buf[index]))
+			ns := mibs.convertToConnectionStat()
+			stats = append(stats, ns)
+		}
+
+		index += step
+	}
+	return stats, nil
+}
+
+func getUDPConnections(family uint32) ([]ConnectionStat, error) {
+	var (
+		p    uintptr
+		buf  []byte
+		size uint32
+
+		pmibUDPTable  pmibUDPTableOwnerPid
+		pmibUDP6Table pmibUDP6TableOwnerPid
+	)
+
+	if family == 0 {
+		return nil, errors.New("faimly must be required")
+	}
+
+	for {
+		switch family {
+		case kindUDP4.family:
+			if len(buf) > 0 {
+				pmibUDPTable = (*mibUDPTableOwnerPid)(unsafe.Pointer(&buf[0]))
+				p = uintptr(unsafe.Pointer(pmibUDPTable))
+			} else {
+				p = uintptr(unsafe.Pointer(pmibUDPTable))
+			}
+		case kindUDP6.family:
+			if len(buf) > 0 {
+				pmibUDP6Table = (*mibUDP6TableOwnerPid)(unsafe.Pointer(&buf[0]))
+				p = uintptr(unsafe.Pointer(pmibUDP6Table))
+			} else {
+				p = uintptr(unsafe.Pointer(pmibUDP6Table))
+			}
+		}
+
+		err := getExtendedUDPTable(
+			p,
+			&size,
+			true,
+			family,
+			udpTableOwnerPid,
+			0,
+		)
+		if err == nil {
+			break
+		}
+		if !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {
+			return nil, err
+		}
+		buf = make([]byte, size)
+	}
+
+	var index, step, length int
+
+	stats := make([]ConnectionStat, 0)
+	switch family {
+	case kindUDP4.family:
+		index, step, length = getTableInfo(kindUDP4.filename, pmibUDPTable)
+	case kindUDP6.family:
+		index, step, length = getTableInfo(kindUDP6.filename, pmibUDP6Table)
+	}
+
+	if length == 0 {
+		return nil, nil
+	}
+
+	for i := 0; i < length; i++ {
+		switch family {
+		case kindUDP4.family:
+			mibs := (*mibUDPRowOwnerPid)(unsafe.Pointer(&buf[index]))
+			ns := mibs.convertToConnectionStat()
+			stats = append(stats, ns)
+		case kindUDP6.family:
+			mibs := (*mibUDP6RowOwnerPid)(unsafe.Pointer(&buf[index]))
+			ns := mibs.convertToConnectionStat()
+			stats = append(stats, ns)
+		}
+
+		index += step
+	}
+	return stats, nil
+}
+
+// tcpStatuses https://msdn.microsoft.com/en-us/library/windows/desktop/bb485761(v=vs.85).aspx
+var tcpStatuses = map[mibTCPState]string{
+	1:  "CLOSED",
+	2:  "LISTEN",
+	3:  "SYN_SENT",
+	4:  "SYN_RECEIVED",
+	5:  "ESTABLISHED",
+	6:  "FIN_WAIT_1",
+	7:  "FIN_WAIT_2",
+	8:  "CLOSE_WAIT",
+	9:  "CLOSING",
+	10: "LAST_ACK",
+	11: "TIME_WAIT",
+	12: "DELETE",
+}
+
+func getExtendedTCPTable(pTCPTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass tcpTableClass, reserved uint32) (errcode error) {
+	r1, _, _ := syscall.Syscall6(procGetExtendedTCPTable.Addr(), 6, pTCPTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved))
+	if r1 != 0 {
+		errcode = syscall.Errno(r1)
+	}
+	return errcode
+}
+
+func getExtendedUDPTable(pUDPTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass udpTableClass, reserved uint32) (errcode error) {
+	r1, _, _ := syscall.Syscall6(procGetExtendedUDPTable.Addr(), 6, pUDPTable, uintptr(unsafe.Pointer(pdwSize)), getUintptrFromBool(bOrder), uintptr(ulAf), uintptr(tableClass), uintptr(reserved))
+	if r1 != 0 {
+		errcode = syscall.Errno(r1)
+	}
+	return errcode
+}
+
+func getUintptrFromBool(b bool) uintptr {
+	if b {
+		return 1
+	}
+	return 0
+}
+
+const anySize = 1
+
+// type MIB_TCP_STATE int32
+type mibTCPState int32
+
+type tcpTableClass int32
+
+const (
+	tcpTableBasicListener tcpTableClass = iota
+	tcpTableBasicConnections
+	tcpTableBasicAll
+	tcpTableOwnerPidListener
+	tcpTableOwnerPidConnections
+	tcpTableOwnerPidAll
+	tcpTableOwnerModuleListener
+	tcpTableOwnerModuleConnections
+	tcpTableOwnerModuleAll
+)
+
+type udpTableClass int32
+
+const (
+	udpTableBasic udpTableClass = iota
+	udpTableOwnerPid
+	udpTableOwnerModule
+)
+
+// TCP
+
+type mibTCPRowOwnerPid struct {
+	DwState      uint32
+	DwLocalAddr  uint32
+	DwLocalPort  uint32
+	DwRemoteAddr uint32
+	DwRemotePort uint32
+	DwOwningPid  uint32
+}
+
+func (m *mibTCPRowOwnerPid) convertToConnectionStat() ConnectionStat {
+	ns := ConnectionStat{
+		Family: kindTCP4.family,
+		Type:   kindTCP4.sockType,
+		Laddr: Addr{
+			IP:   parseIPv4HexString(m.DwLocalAddr),
+			Port: uint32(decodePort(m.DwLocalPort)),
+		},
+		Raddr: Addr{
+			IP:   parseIPv4HexString(m.DwRemoteAddr),
+			Port: uint32(decodePort(m.DwRemotePort)),
+		},
+		Pid:    int32(m.DwOwningPid),
+		Status: tcpStatuses[mibTCPState(m.DwState)],
+	}
+
+	return ns
+}
+
+type mibTCPTableOwnerPid struct {
+	DwNumEntries uint32
+	Table        [anySize]mibTCPRowOwnerPid
+}
+
+type mibTCP6RowOwnerPid struct {
+	UcLocalAddr     [16]byte
+	DwLocalScopeId  uint32
+	DwLocalPort     uint32
+	UcRemoteAddr    [16]byte
+	DwRemoteScopeId uint32
+	DwRemotePort    uint32
+	DwState         uint32
+	DwOwningPid     uint32
+}
+
+func (m *mibTCP6RowOwnerPid) convertToConnectionStat() ConnectionStat {
+	ns := ConnectionStat{
+		Family: kindTCP6.family,
+		Type:   kindTCP6.sockType,
+		Laddr: Addr{
+			IP:   parseIPv6HexString(m.UcLocalAddr),
+			Port: uint32(decodePort(m.DwLocalPort)),
+		},
+		Raddr: Addr{
+			IP:   parseIPv6HexString(m.UcRemoteAddr),
+			Port: uint32(decodePort(m.DwRemotePort)),
+		},
+		Pid:    int32(m.DwOwningPid),
+		Status: tcpStatuses[mibTCPState(m.DwState)],
+	}
+
+	return ns
+}
+
+type mibTCP6TableOwnerPid struct {
+	DwNumEntries uint32
+	Table        [anySize]mibTCP6RowOwnerPid
+}
+
+type (
+	pmibTCPTableOwnerPidAll  *mibTCPTableOwnerPid
+	pmibTCP6TableOwnerPidAll *mibTCP6TableOwnerPid
+)
+
+// UDP
+
+type mibUDPRowOwnerPid struct {
+	DwLocalAddr uint32
+	DwLocalPort uint32
+	DwOwningPid uint32
+}
+
+func (m *mibUDPRowOwnerPid) convertToConnectionStat() ConnectionStat {
+	ns := ConnectionStat{
+		Family: kindUDP4.family,
+		Type:   kindUDP4.sockType,
+		Laddr: Addr{
+			IP:   parseIPv4HexString(m.DwLocalAddr),
+			Port: uint32(decodePort(m.DwLocalPort)),
+		},
+		Pid: int32(m.DwOwningPid),
+	}
+
+	return ns
+}
+
+type mibUDPTableOwnerPid struct {
+	DwNumEntries uint32
+	Table        [anySize]mibUDPRowOwnerPid
+}
+
+type mibUDP6RowOwnerPid struct {
+	UcLocalAddr    [16]byte
+	DwLocalScopeId uint32
+	DwLocalPort    uint32
+	DwOwningPid    uint32
+}
+
+func (m *mibUDP6RowOwnerPid) convertToConnectionStat() ConnectionStat {
+	ns := ConnectionStat{
+		Family: kindUDP6.family,
+		Type:   kindUDP6.sockType,
+		Laddr: Addr{
+			IP:   parseIPv6HexString(m.UcLocalAddr),
+			Port: uint32(decodePort(m.DwLocalPort)),
+		},
+		Pid: int32(m.DwOwningPid),
+	}
+
+	return ns
+}
+
+type mibUDP6TableOwnerPid struct {
+	DwNumEntries uint32
+	Table        [anySize]mibUDP6RowOwnerPid
+}
+
+type (
+	pmibUDPTableOwnerPid  *mibUDPTableOwnerPid
+	pmibUDP6TableOwnerPid *mibUDP6TableOwnerPid
+)
+
+func decodePort(port uint32) uint16 {
+	return syscall.Ntohs(uint16(port))
+}
+
+func parseIPv4HexString(addr uint32) string {
+	return fmt.Sprintf("%d.%d.%d.%d", addr&255, addr>>8&255, addr>>16&255, addr>>24&255)
+}
+
+func parseIPv6HexString(addr [16]byte) string {
+	var ret [16]byte
+	for i := 0; i < 16; i++ {
+		ret[i] = uint8(addr[i])
+	}
+
+	// convert []byte to net.IP
+	ip := net.IP(ret[:])
+	return ip.String()
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process.go b/vendor/github.com/shirou/gopsutil/v4/process/process.go
new file mode 100644
index 000000000..5db5ff481
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process.go
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package process
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"regexp"
+	"runtime"
+	"sort"
+	"sync"
+	"time"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/mem"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+var (
+	invoke                 common.Invoker = common.Invoke{}
+	strictIntPtrn                         = regexp.MustCompile(`^\d+$`)
+	ErrorNoChildren                       = errors.New("process does not have children") // Deprecated: ErrorNoChildren is never returned by process.Children(), check its returned []*Process slice length instead
+	ErrorProcessNotRunning                = errors.New("process does not exist")
+	ErrorNotPermitted                     = errors.New("operation not permitted")
+)
+
+type Process struct {
+	Pid            int32 `json:"pid"`
+	name           string
+	status         string
+	parent         int32
+	parentMutex    sync.RWMutex // for windows ppid cache
+	numCtxSwitches *NumCtxSwitchesStat
+	uids           []uint32
+	gids           []uint32
+	groups         []uint32
+	numThreads     int32
+	memInfo        *MemoryInfoStat
+	sigInfo        *SignalInfoStat
+	createTime     int64
+
+	lastCPUTimes *cpu.TimesStat
+	lastCPUTime  time.Time
+
+	tgid int32
+}
+
+// Process status
+const (
+	// Running marks a task a running or runnable (on the run queue)
+	Running = "running"
+	// Blocked marks a task waiting on a short, uninterruptible operation (usually I/O)
+	Blocked = "blocked"
+	// Idle marks a task sleeping for more than about 20 seconds
+	Idle = "idle"
+	// Lock marks a task waiting to acquire a lock
+	Lock = "lock"
+	// Sleep marks task waiting for short, interruptible operation
+	Sleep = "sleep"
+	// Stop marks a stopped process
+	Stop = "stop"
+	// Wait marks an idle interrupt thread (or paging in pre 2.6.xx Linux)
+	Wait = "wait"
+	// Zombie marks a defunct process, terminated but not reaped by its parent
+	Zombie = "zombie"
+
+	// Solaris states. See https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115
+	Daemon   = "daemon"
+	Detached = "detached"
+	System   = "system"
+	Orphan   = "orphan"
+
+	UnknownState = ""
+)
+
+type OpenFilesStat struct {
+	Path string `json:"path"`
+	Fd   uint64 `json:"fd"`
+}
+
+type MemoryInfoStat struct {
+	RSS    uint64 `json:"rss"`    // bytes
+	VMS    uint64 `json:"vms"`    // bytes
+	HWM    uint64 `json:"hwm"`    // bytes
+	Data   uint64 `json:"data"`   // bytes
+	Stack  uint64 `json:"stack"`  // bytes
+	Locked uint64 `json:"locked"` // bytes
+	Swap   uint64 `json:"swap"`   // bytes
+}
+
+type SignalInfoStat struct {
+	PendingProcess uint64 `json:"pending_process"`
+	PendingThread  uint64 `json:"pending_thread"`
+	Blocked        uint64 `json:"blocked"`
+	Ignored        uint64 `json:"ignored"`
+	Caught         uint64 `json:"caught"`
+}
+
+type RlimitStat struct {
+	Resource int32  `json:"resource"`
+	Soft     uint64 `json:"soft"`
+	Hard     uint64 `json:"hard"`
+	Used     uint64 `json:"used"`
+}
+
+type IOCountersStat struct {
+	// ReadCount is a number of read I/O operations such as syscalls.
+	ReadCount uint64 `json:"readCount"`
+	// WriteCount is a number of read I/O operations such as syscalls.
+	WriteCount uint64 `json:"writeCount"`
+	// ReadBytes is a number of all I/O read in bytes. This includes disk I/O on Linux and Windows.
+	ReadBytes uint64 `json:"readBytes"`
+	// WriteBytes is a number of all I/O write in bytes. This includes disk I/O on Linux and Windows.
+	WriteBytes uint64 `json:"writeBytes"`
+	// DiskReadBytes is a number of disk I/O write in bytes. Currently only Linux has this value.
+	DiskReadBytes uint64 `json:"diskReadBytes"`
+	// DiskWriteBytes is a number of disk I/O read in bytes.  Currently only Linux has this value.
+	DiskWriteBytes uint64 `json:"diskWriteBytes"`
+}
+
+type NumCtxSwitchesStat struct {
+	Voluntary   int64 `json:"voluntary"`
+	Involuntary int64 `json:"involuntary"`
+}
+
+type PageFaultsStat struct {
+	MinorFaults      uint64 `json:"minorFaults"`
+	MajorFaults      uint64 `json:"majorFaults"`
+	ChildMinorFaults uint64 `json:"childMinorFaults"`
+	ChildMajorFaults uint64 `json:"childMajorFaults"`
+}
+
+// Resource limit constants are from /usr/include/x86_64-linux-gnu/bits/resource.h
+// from libc6-dev package in Ubuntu 16.10
+const (
+	RLIMIT_CPU        int32 = 0
+	RLIMIT_FSIZE      int32 = 1
+	RLIMIT_DATA       int32 = 2
+	RLIMIT_STACK      int32 = 3
+	RLIMIT_CORE       int32 = 4
+	RLIMIT_RSS        int32 = 5
+	RLIMIT_NPROC      int32 = 6
+	RLIMIT_NOFILE     int32 = 7
+	RLIMIT_MEMLOCK    int32 = 8
+	RLIMIT_AS         int32 = 9
+	RLIMIT_LOCKS      int32 = 10
+	RLIMIT_SIGPENDING int32 = 11
+	RLIMIT_MSGQUEUE   int32 = 12
+	RLIMIT_NICE       int32 = 13
+	RLIMIT_RTPRIO     int32 = 14
+	RLIMIT_RTTIME     int32 = 15
+)
+
+func (p Process) String() string {
+	s, _ := json.Marshal(p)
+	return string(s)
+}
+
+func (o OpenFilesStat) String() string {
+	s, _ := json.Marshal(o)
+	return string(s)
+}
+
+func (m MemoryInfoStat) String() string {
+	s, _ := json.Marshal(m)
+	return string(s)
+}
+
+func (r RlimitStat) String() string {
+	s, _ := json.Marshal(r)
+	return string(s)
+}
+
+func (i IOCountersStat) String() string {
+	s, _ := json.Marshal(i)
+	return string(s)
+}
+
+func (p NumCtxSwitchesStat) String() string {
+	s, _ := json.Marshal(p)
+	return string(s)
+}
+
+var enableBootTimeCache bool
+
+// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.
+func EnableBootTimeCache(enable bool) {
+	enableBootTimeCache = enable
+}
+
+// Pids returns a slice of process ID list which are running now.
+func Pids() ([]int32, error) {
+	return PidsWithContext(context.Background())
+}
+
+func PidsWithContext(ctx context.Context) ([]int32, error) {
+	pids, err := pidsWithContext(ctx)
+	sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] })
+	return pids, err
+}
+
+// Processes returns a slice of pointers to Process structs for all
+// currently running processes.
+func Processes() ([]*Process, error) {
+	return ProcessesWithContext(context.Background())
+}
+
+// NewProcess creates a new Process instance, it only stores the pid and
+// checks that the process exists. Other method on Process can be used
+// to get more information about the process. An error will be returned
+// if the process does not exist.
+func NewProcess(pid int32) (*Process, error) {
+	return NewProcessWithContext(context.Background(), pid)
+}
+
+func NewProcessWithContext(ctx context.Context, pid int32) (*Process, error) {
+	p := &Process{
+		Pid: pid,
+	}
+
+	exists, err := PidExistsWithContext(ctx, pid)
+	if err != nil {
+		return p, err
+	}
+	if !exists {
+		return p, ErrorProcessNotRunning
+	}
+	p.CreateTimeWithContext(ctx)
+	return p, nil
+}
+
+func PidExists(pid int32) (bool, error) {
+	return PidExistsWithContext(context.Background(), pid)
+}
+
+// Background returns true if the process is in background, false otherwise.
+func (p *Process) Background() (bool, error) {
+	return p.BackgroundWithContext(context.Background())
+}
+
+func (p *Process) BackgroundWithContext(ctx context.Context) (bool, error) {
+	fg, err := p.ForegroundWithContext(ctx)
+	if err != nil {
+		return false, err
+	}
+	return !fg, err
+}
+
+// If interval is 0, return difference from last call(non-blocking).
+// If interval > 0, wait interval sec and return difference between start and end.
+func (p *Process) Percent(interval time.Duration) (float64, error) {
+	return p.PercentWithContext(context.Background(), interval)
+}
+
+func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration) (float64, error) {
+	cpuTimes, err := p.TimesWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+	now := time.Now()
+
+	if interval > 0 {
+		p.lastCPUTimes = cpuTimes
+		p.lastCPUTime = now
+		if err := common.Sleep(ctx, interval); err != nil {
+			return 0, err
+		}
+		cpuTimes, err = p.TimesWithContext(ctx)
+		now = time.Now()
+		if err != nil {
+			return 0, err
+		}
+	} else if p.lastCPUTimes == nil {
+		// invoked first time
+		p.lastCPUTimes = cpuTimes
+		p.lastCPUTime = now
+		return 0, nil
+	}
+
+	numcpu := runtime.NumCPU()
+	delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
+	ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
+	p.lastCPUTimes = cpuTimes
+	p.lastCPUTime = now
+	return ret, nil
+}
+
+// IsRunning returns whether the process is still running or not.
+func (p *Process) IsRunning() (bool, error) {
+	return p.IsRunningWithContext(context.Background())
+}
+
+func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
+	createTime, err := p.CreateTimeWithContext(ctx)
+	if err != nil {
+		return false, err
+	}
+	p2, err := NewProcessWithContext(ctx, p.Pid)
+	if errors.Is(err, ErrorProcessNotRunning) {
+		return false, nil
+	}
+	createTime2, err := p2.CreateTimeWithContext(ctx)
+	if err != nil {
+		return false, err
+	}
+	return createTime == createTime2, nil
+}
+
+// CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
+func (p *Process) CreateTime() (int64, error) {
+	return p.CreateTimeWithContext(context.Background())
+}
+
+func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
+	if p.createTime != 0 {
+		return p.createTime, nil
+	}
+	createTime, err := p.createTimeWithContext(ctx)
+	p.createTime = createTime
+	return p.createTime, err
+}
+
+func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
+	if delta == 0 {
+		return 0
+	}
+	// https://github.com/giampaolo/psutil/blob/c034e6692cf736b5e87d14418a8153bb03f6cf42/psutil/__init__.py#L1064
+	deltaProc := (t2.User - t1.User) + (t2.System - t1.System)
+	if deltaProc <= 0 {
+		return 0
+	}
+	overallPercent := ((deltaProc / delta) * 100) * float64(numcpu)
+	return overallPercent
+}
+
+// MemoryPercent returns how many percent of the total RAM this process uses
+func (p *Process) MemoryPercent() (float32, error) {
+	return p.MemoryPercentWithContext(context.Background())
+}
+
+func (p *Process) MemoryPercentWithContext(ctx context.Context) (float32, error) {
+	machineMemory, err := mem.VirtualMemoryWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+	total := machineMemory.Total
+
+	processMemory, err := p.MemoryInfoWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+	used := processMemory.RSS
+
+	return (100 * float32(used) / float32(total)), nil
+}
+
+// CPUPercent returns how many percent of the CPU time this process uses
+func (p *Process) CPUPercent() (float64, error) {
+	return p.CPUPercentWithContext(context.Background())
+}
+
+func (p *Process) CPUPercentWithContext(ctx context.Context) (float64, error) {
+	createTime, err := p.createTimeWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+
+	cput, err := p.TimesWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+
+	created := time.Unix(0, createTime*int64(time.Millisecond))
+	totalTime := time.Since(created).Seconds()
+	if totalTime <= 0 {
+		return 0, nil
+	}
+
+	return 100 * cput.Total() / totalTime, nil
+}
+
+// Groups returns all group IDs(include supplementary groups) of the process as a slice of the int
+func (p *Process) Groups() ([]uint32, error) {
+	return p.GroupsWithContext(context.Background())
+}
+
+// Ppid returns Parent Process ID of the process.
+func (p *Process) Ppid() (int32, error) {
+	return p.PpidWithContext(context.Background())
+}
+
+// Name returns name of the process.
+func (p *Process) Name() (string, error) {
+	return p.NameWithContext(context.Background())
+}
+
+// Exe returns executable path of the process.
+func (p *Process) Exe() (string, error) {
+	return p.ExeWithContext(context.Background())
+}
+
+// Cmdline returns the command line arguments of the process as a string with
+// each argument separated by 0x20 ascii character.
+func (p *Process) Cmdline() (string, error) {
+	return p.CmdlineWithContext(context.Background())
+}
+
+// CmdlineSlice returns the command line arguments of the process as a slice with each
+// element being an argument.
+//
+// On Windows, this assumes the command line is encoded according to the convention accepted by
+// [golang.org/x/sys/windows.CmdlineToArgv] (the most common convention). If this is not suitable,
+// you should instead use [Process.Cmdline] and parse the command line according to your specific
+// requirements.
+func (p *Process) CmdlineSlice() ([]string, error) {
+	return p.CmdlineSliceWithContext(context.Background())
+}
+
+// Cwd returns current working directory of the process.
+func (p *Process) Cwd() (string, error) {
+	return p.CwdWithContext(context.Background())
+}
+
+// Parent returns parent Process of the process.
+func (p *Process) Parent() (*Process, error) {
+	return p.ParentWithContext(context.Background())
+}
+
+// ParentWithContext returns parent Process of the process.
+func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
+	ppid, err := p.PpidWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return NewProcessWithContext(ctx, ppid)
+}
+
+// Status returns the process status.
+// Return value could be one of these.
+// R: Running S: Sleep T: Stop I: Idle
+// Z: Zombie W: Wait L: Lock
+// The character is same within all supported platforms.
+func (p *Process) Status() ([]string, error) {
+	return p.StatusWithContext(context.Background())
+}
+
+// Foreground returns true if the process is in foreground, false otherwise.
+func (p *Process) Foreground() (bool, error) {
+	return p.ForegroundWithContext(context.Background())
+}
+
+// Uids returns user ids of the process as a slice of the int
+func (p *Process) Uids() ([]uint32, error) {
+	return p.UidsWithContext(context.Background())
+}
+
+// Gids returns group ids of the process as a slice of the int
+func (p *Process) Gids() ([]uint32, error) {
+	return p.GidsWithContext(context.Background())
+}
+
+// Terminal returns a terminal which is associated with the process.
+func (p *Process) Terminal() (string, error) {
+	return p.TerminalWithContext(context.Background())
+}
+
+// Nice returns a nice value (priority).
+func (p *Process) Nice() (int32, error) {
+	return p.NiceWithContext(context.Background())
+}
+
+// IOnice returns process I/O nice value (priority).
+func (p *Process) IOnice() (int32, error) {
+	return p.IOniceWithContext(context.Background())
+}
+
+// Rlimit returns Resource Limits.
+func (p *Process) Rlimit() ([]RlimitStat, error) {
+	return p.RlimitWithContext(context.Background())
+}
+
+// RlimitUsage returns Resource Limits.
+// If gatherUsed is true, the currently used value will be gathered and added
+// to the resulting RlimitStat.
+func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
+	return p.RlimitUsageWithContext(context.Background(), gatherUsed)
+}
+
+// IOCounters returns IO Counters.
+func (p *Process) IOCounters() (*IOCountersStat, error) {
+	return p.IOCountersWithContext(context.Background())
+}
+
+// NumCtxSwitches returns the number of the context switches of the process.
+func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
+	return p.NumCtxSwitchesWithContext(context.Background())
+}
+
+// NumFDs returns the number of File Descriptors used by the process.
+func (p *Process) NumFDs() (int32, error) {
+	return p.NumFDsWithContext(context.Background())
+}
+
+// NumThreads returns the number of threads used by the process.
+func (p *Process) NumThreads() (int32, error) {
+	return p.NumThreadsWithContext(context.Background())
+}
+
+func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
+	return p.ThreadsWithContext(context.Background())
+}
+
+// Times returns CPU times of the process.
+func (p *Process) Times() (*cpu.TimesStat, error) {
+	return p.TimesWithContext(context.Background())
+}
+
+// CPUAffinity returns CPU affinity of the process.
+func (p *Process) CPUAffinity() ([]int32, error) {
+	return p.CPUAffinityWithContext(context.Background())
+}
+
+// MemoryInfo returns generic process memory information,
+// such as RSS and VMS.
+func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
+	return p.MemoryInfoWithContext(context.Background())
+}
+
+// MemoryInfoEx returns platform-specific process memory information.
+func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
+	return p.MemoryInfoExWithContext(context.Background())
+}
+
+// PageFaults returns the process's page fault counters.
+func (p *Process) PageFaults() (*PageFaultsStat, error) {
+	return p.PageFaultsWithContext(context.Background())
+}
+
+// Children returns the children of the process represented as a slice
+// of pointers to Process type.
+func (p *Process) Children() ([]*Process, error) {
+	return p.ChildrenWithContext(context.Background())
+}
+
+// OpenFiles returns a slice of OpenFilesStat opend by the process.
+// OpenFilesStat includes a file path and file descriptor.
+func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
+	return p.OpenFilesWithContext(context.Background())
+}
+
+// Connections returns a slice of net.ConnectionStat used by the process.
+// This returns all kind of the connection. This means TCP, UDP or UNIX.
+func (p *Process) Connections() ([]net.ConnectionStat, error) {
+	return p.ConnectionsWithContext(context.Background())
+}
+
+// ConnectionsMax returns a slice of net.ConnectionStat used by the process at most `max`.
+func (p *Process) ConnectionsMax(maxConn int) ([]net.ConnectionStat, error) {
+	return p.ConnectionsMaxWithContext(context.Background(), maxConn)
+}
+
+// MemoryMaps get memory maps from /proc/(pid)/smaps
+func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
+	return p.MemoryMapsWithContext(context.Background(), grouped)
+}
+
+// Tgid returns thread group id of the process.
+func (p *Process) Tgid() (int32, error) {
+	return p.TgidWithContext(context.Background())
+}
+
+// SendSignal sends a unix.Signal to the process.
+func (p *Process) SendSignal(sig Signal) error {
+	return p.SendSignalWithContext(context.Background(), sig)
+}
+
+// Suspend sends SIGSTOP to the process.
+func (p *Process) Suspend() error {
+	return p.SuspendWithContext(context.Background())
+}
+
+// Resume sends SIGCONT to the process.
+func (p *Process) Resume() error {
+	return p.ResumeWithContext(context.Background())
+}
+
+// Terminate sends SIGTERM to the process.
+func (p *Process) Terminate() error {
+	return p.TerminateWithContext(context.Background())
+}
+
+// Kill sends SIGKILL to the process.
+func (p *Process) Kill() error {
+	return p.KillWithContext(context.Background())
+}
+
+// Username returns a username of the process.
+func (p *Process) Username() (string, error) {
+	return p.UsernameWithContext(context.Background())
+}
+
+// Environ returns the environment variables of the process.
+func (p *Process) Environ() ([]string, error) {
+	return p.EnvironWithContext(context.Background())
+}
+
+// convertStatusChar as reported by the ps command across different platforms.
+func convertStatusChar(letter string) string {
+	// Sources
+	// Darwin: http://www.mywebuniversity.com/Man_Pages/Darwin/man_ps.html
+	// FreeBSD: https://www.freebsd.org/cgi/man.cgi?ps
+	// Linux https://man7.org/linux/man-pages/man1/ps.1.html
+	// OpenBSD: https://man.openbsd.org/ps.1#state
+	// Solaris: https://github.com/collectd/collectd/blob/1da3305c10c8ff9a63081284cf3d4bb0f6daffd8/src/processes.c#L2115
+	switch letter {
+	case "A":
+		return Daemon
+	case "D", "U":
+		return Blocked
+	case "E":
+		return Detached
+	case "I":
+		return Idle
+	case "L":
+		return Lock
+	case "O":
+		return Orphan
+	case "R":
+		return Running
+	case "S":
+		return Sleep
+	case "T", "t":
+		// "t" is used by Linux to signal stopped by the debugger during tracing
+		return Stop
+	case "W":
+		return Wait
+	case "Y":
+		return System
+	case "Z":
+		return Zombie
+	default:
+		return UnknownState
+	}
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go
new file mode 100644
index 000000000..d094d389d
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_bsd.go
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin || freebsd || openbsd
+
+package process
+
+import (
+	"bytes"
+	"context"
+	"encoding/binary"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+type MemoryInfoExStat struct{}
+
+type MemoryMapsStat struct{}
+
+func (*Process) TgidWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) EnvironWithContext(_ context.Context) ([]string, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func parseKinfoProc(buf []byte) (KinfoProc, error) {
+	var k KinfoProc
+	br := bytes.NewReader(buf)
+	err := binary.Read(br, binary.LittleEndian, &k)
+	return k, err
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go
new file mode 100644
index 000000000..6e1d0ce37
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin.go
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin
+
+package process
+
+import (
+	"bytes"
+	"context"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strconv"
+	"strings"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+// copied from sys/sysctl.h
+const (
+	CTLKern          = 1  // "high kernel": proc, limits
+	KernProc         = 14 // struct: process entries
+	KernProcPID      = 1  // by process id
+	KernProcProc     = 8  // only return procs
+	KernProcAll      = 0  // everything
+	KernProcPathname = 12 // path to executable
+)
+
+type _Ctype_struct___0 struct { //nolint:revive //FIXME
+	Pad uint64
+}
+
+func pidsWithContext(_ context.Context) ([]int32, error) {
+	var ret []int32
+
+	kprocs, err := unix.SysctlKinfoProcSlice("kern.proc.all")
+	if err != nil {
+		return ret, err
+	}
+
+	for i := range kprocs {
+		proc := &kprocs[i]
+		ret = append(ret, int32(proc.Proc.P_pid))
+	}
+
+	return ret, nil
+}
+
+func (p *Process) PpidWithContext(_ context.Context) (int32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+
+	return k.Eproc.Ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return "", err
+	}
+
+	name := common.ByteToString(k.Proc.P_comm[:])
+
+	if len(name) >= 15 {
+		cmdName, err := p.cmdNameWithContext(ctx)
+		if err != nil {
+			return "", err
+		}
+		if cmdName != "" {
+			extendedName := filepath.Base(cmdName)
+			if strings.HasPrefix(extendedName, p.name) {
+				name = extendedName
+			}
+		}
+	}
+
+	return name, nil
+}
+
+func (p *Process) createTimeWithContext(_ context.Context) (int64, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+
+	return k.Proc.P_starttime.Sec*1000 + int64(k.Proc.P_starttime.Usec)/1000, nil
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+	r, err := callPsWithContext(ctx, "state", p.Pid, false, false)
+	if err != nil {
+		return []string{""}, err
+	}
+	status := convertStatusChar(r[0][0][0:1])
+	return []string{status}, err
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+	// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+	pid := p.Pid
+	out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+	if err != nil {
+		return false, err
+	}
+	return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) UidsWithContext(_ context.Context) ([]uint32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+
+	// See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html
+	userEffectiveUID := uint32(k.Eproc.Ucred.Uid)
+
+	return []uint32{userEffectiveUID}, nil
+}
+
+func (p *Process) GidsWithContext(_ context.Context) ([]uint32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+
+	gids := make([]uint32, 0, 3)
+	gids = append(gids, uint32(k.Eproc.Pcred.P_rgid), uint32(k.Eproc.Ucred.Groups[0]), uint32(k.Eproc.Pcred.P_svgid))
+
+	return gids, nil
+}
+
+func (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+	// k, err := p.getKProc()
+	// if err != nil {
+	// 	return nil, err
+	// }
+
+	// groups := make([]int32, k.Eproc.Ucred.Ngroups)
+	// for i := int16(0); i < k.Eproc.Ucred.Ngroups; i++ {
+	// 	groups[i] = int32(k.Eproc.Ucred.Groups[i])
+	// }
+
+	// return groups, nil
+}
+
+func (*Process) TerminalWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+	/*
+		k, err := p.getKProc()
+		if err != nil {
+			return "", err
+		}
+
+		ttyNr := uint64(k.Eproc.Tdev)
+		termmap, err := getTerminalMap()
+		if err != nil {
+			return "", err
+		}
+
+		return termmap[ttyNr], nil
+	*/
+}
+
+func (p *Process) NiceWithContext(_ context.Context) (int32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+	return int32(k.Proc.P_nice), nil
+}
+
+func (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+	procs, err := ProcessesWithContext(ctx)
+	if err != nil {
+		return nil, nil
+	}
+	ret := make([]*Process, 0, len(procs))
+	for _, proc := range procs {
+		ppid, err := proc.PpidWithContext(ctx)
+		if err != nil {
+			continue
+		}
+		if ppid == p.Pid {
+			ret = append(ret, proc)
+		}
+	}
+	sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+	return ret, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+	return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+	return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, maxConn)
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+	out := []*Process{}
+
+	pids, err := PidsWithContext(ctx)
+	if err != nil {
+		return out, err
+	}
+
+	for _, pid := range pids {
+		p, err := NewProcessWithContext(ctx, pid)
+		if err != nil {
+			continue
+		}
+		out = append(out, p)
+	}
+
+	return out, nil
+}
+
+// Returns a proc as defined here:
+// http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html
+func (p *Process) getKProc() (*unix.KinfoProc, error) {
+	return unix.SysctlKinfoProc("kern.proc.pid", int(p.Pid))
+}
+
+// call ps command.
+// Return value deletes Header line(you must not input wrong arg).
+// And split by Space. Caller have responsibility to manage.
+// If passed arg pid is 0, get information from all process.
+func callPsWithContext(ctx context.Context, arg string, pid int32, threadOption, nameOption bool) ([][]string, error) {
+	var cmd []string
+	switch {
+	case pid == 0: // will get from all processes.
+		cmd = []string{"-ax", "-o", arg}
+	case threadOption:
+		cmd = []string{"-x", "-o", arg, "-M", "-p", strconv.Itoa(int(pid))}
+	default:
+		cmd = []string{"-x", "-o", arg, "-p", strconv.Itoa(int(pid))}
+	}
+	if nameOption {
+		cmd = append(cmd, "-c")
+	}
+	out, err := invoke.CommandWithContext(ctx, "ps", cmd...)
+	if err != nil {
+		return [][]string{}, err
+	}
+	lines := strings.Split(string(out), "\n")
+
+	var ret [][]string
+	for _, l := range lines[1:] {
+		var lr []string
+		if nameOption {
+			lr = append(lr, l)
+		} else {
+			for _, r := range strings.Split(l, " ") {
+				if r == "" {
+					continue
+				}
+				lr = append(lr, strings.TrimSpace(r))
+			}
+		}
+		if len(lr) != 0 {
+			ret = append(ret, lr)
+		}
+	}
+
+	return ret, nil
+}
+
+type dlFuncs struct {
+	lib *common.SystemLib
+}
+
+func loadProcFuncs() (*dlFuncs, error) {
+	lib, err := common.NewSystemLib()
+	if err != nil {
+		return nil, err
+	}
+	return &dlFuncs{lib}, err
+}
+
+func (f *dlFuncs) getTimeScaleToNanoSeconds() float64 {
+	var timeBaseInfo common.MachTimeBaseInfo
+
+	f.lib.MachTimeBaseInfo(uintptr(unsafe.Pointer(&timeBaseInfo)))
+
+	return float64(timeBaseInfo.Numer) / float64(timeBaseInfo.Denom)
+}
+
+func (f *dlFuncs) Close() {
+	f.lib.Close()
+}
+
+func (p *Process) ExeWithContext(_ context.Context) (string, error) {
+	funcs, err := loadProcFuncs()
+	if err != nil {
+		return "", err
+	}
+	defer funcs.Close()
+
+	buf := common.NewCStr(common.PROC_PIDPATHINFO_MAXSIZE)
+	ret := funcs.lib.ProcPidPath(p.Pid, buf.Addr(), common.PROC_PIDPATHINFO_MAXSIZE)
+
+	if ret <= 0 {
+		return "", fmt.Errorf("unknown error: proc_pidpath returned %d", ret)
+	}
+
+	return buf.GoString(), nil
+}
+
+// CwdWithContext retrieves the Current Working Directory for the given process.
+// It uses the proc_pidinfo from libproc and will only work for processes the
+// EUID can access.  Otherwise "operation not permitted" will be returned as the
+// error.
+// Note: This might also work for other *BSD OSs.
+func (p *Process) CwdWithContext(_ context.Context) (string, error) {
+	funcs, err := loadProcFuncs()
+	if err != nil {
+		return "", err
+	}
+	defer funcs.Close()
+
+	// Lock OS thread to ensure the errno does not change
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	var vpi vnodePathInfo
+	const vpiSize = int32(unsafe.Sizeof(vpi))
+	ret := funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize)
+	errno, _ := funcs.lib.Dlsym("errno")
+	err = *(**unix.Errno)(unsafe.Pointer(&errno))
+	if errors.Is(err, unix.EPERM) {
+		return "", ErrorNotPermitted
+	}
+
+	if ret <= 0 {
+		return "", fmt.Errorf("unknown error: proc_pidinfo returned %d", ret)
+	}
+
+	if ret != vpiSize {
+		return "", fmt.Errorf("too few bytes; expected %d, got %d", vpiSize, ret)
+	}
+	return common.GoString((*byte)(unsafe.Pointer(&vpi.Cdir.Path[0]))), nil
+}
+
+func procArgs(pid int32) ([]byte, int, error) {
+	procargs, err := unix.SysctlRaw("kern.procargs2", int(pid))
+	if err != nil {
+		return nil, 0, err
+	}
+
+	// The first 4 bytes indicate the number of arguments.
+	nargs := procargs[:4]
+	return procargs, int(binary.LittleEndian.Uint32(nargs)), nil
+}
+
+func (p *Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {
+	return p.cmdlineSlice()
+}
+
+func (p *Process) cmdlineSlice() ([]string, error) {
+	pargs, nargs, err := procArgs(p.Pid)
+	if err != nil {
+		return nil, err
+	}
+	// procArgs reads nargs as a 4-byte uint32; skip exactly those 4 bytes
+	// (matches Apple's ps using sizeof(nargs)). The previous code used
+	// unsafe.Sizeof(int(0)) which is 8 on 64-bit and would discard the
+	// first 4 bytes of exec_path — harmless only because chunks[0] is
+	// dropped, but logically wrong.
+	return parseCmdline(pargs[4:], nargs), nil
+}
+
+// parseCmdline extracts argv from the kern.procargs2 buffer with the leading
+// nargs int already stripped. Layout:
+//
+//	exec_path \0 [padding \0...] argv[0] \0 ... argv[nargs-1] \0 envp[0] \0 ...
+//
+// Empty argv elements within the nargs count are preserved — skipping them
+// would advance past argv[nargs-1] into envp, leaking environment values
+// (potentially secrets) into Cmdline output.
+//
+// Known limitation: a process whose argv[0] is itself an empty string is
+// indistinguishable from padding by this parser, since XNU does not expose
+// the exec/argv alignment boundary. Such a process will still see one envp
+// entry leak. Fixing it requires libgetargv-style alignment math against
+// the XNU exec layout, which is out of scope for this change.
+func parseCmdline(args []byte, nargs int) []string {
+	chunks := bytes.Split(args, []byte{0})
+	if len(chunks) <= 1 {
+		return nil
+	}
+	// Skip exec_path (chunks[0]) and any padding NULs before argv[0].
+	i := 1
+	for ; i < len(chunks) && len(chunks[i]) == 0; i++ {
+	}
+	if nargs > len(chunks)-i {
+		nargs = len(chunks) - i
+	}
+	if nargs < 0 {
+		nargs = 0
+	}
+	argSlice := make([]string, 0, nargs)
+	for ; nargs > 0; nargs-- {
+		argSlice = append(argSlice, string(chunks[i]))
+		i++
+	}
+	return argSlice
+}
+
+// cmdNameWithContext returns the command name (including spaces) without any arguments
+func (p *Process) cmdNameWithContext(_ context.Context) (string, error) {
+	r, err := p.cmdlineSlice()
+	if err != nil {
+		return "", err
+	}
+
+	if len(r) == 0 {
+		return "", nil
+	}
+
+	return r[0], err
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+	r, err := p.CmdlineSliceWithContext(ctx)
+	if err != nil {
+		return "", err
+	}
+	return strings.Join(r, " "), err
+}
+
+func (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) {
+	funcs, err := loadProcFuncs()
+	if err != nil {
+		return 0, err
+	}
+	defer funcs.Close()
+
+	var ti ProcTaskInfo
+	funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
+
+	return int32(ti.Threadnum), nil
+}
+
+func (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
+	funcs, err := loadProcFuncs()
+	if err != nil {
+		return nil, err
+	}
+	defer funcs.Close()
+
+	var ti ProcTaskInfo
+	funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
+
+	timescaleToNanoSeconds := funcs.getTimeScaleToNanoSeconds()
+	ret := &cpu.TimesStat{
+		CPU:    "cpu",
+		User:   float64(ti.Total_user) * timescaleToNanoSeconds / 1e9,
+		System: float64(ti.Total_system) * timescaleToNanoSeconds / 1e9,
+	}
+	return ret, nil
+}
+
+func (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
+	funcs, err := loadProcFuncs()
+	if err != nil {
+		return nil, err
+	}
+	defer funcs.Close()
+
+	var ti ProcTaskInfo
+	funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti)))
+
+	ret := &MemoryInfoStat{
+		RSS: uint64(ti.Resident_size),
+		VMS: uint64(ti.Virtual_size),
+	}
+	return ret, nil
+}
+
+// procFDInfo represents a file descriptor entry from sys/proc_info.h
+type procFDInfo struct {
+	ProcFd     int32
+	ProcFdtype uint32
+}
+
+// NumFDsWithContext returns the number of file descriptors used by the process.
+// It uses proc_pidinfo with PROC_PIDLISTFDS to query the kernel for the count
+// of open file descriptors. The method makes a single syscall and calculates
+// the count from the buffer size returned by the kernel.
+func (p *Process) NumFDsWithContext(_ context.Context) (int32, error) {
+	funcs, err := loadProcFuncs()
+	if err != nil {
+		return 0, err
+	}
+	defer funcs.Close()
+
+	// First call: get required buffer size
+	bufferSize := funcs.lib.ProcPidInfo(
+		p.Pid,
+		common.PROC_PIDLISTFDS,
+		0,
+		0, // NULL buffer
+		0, // 0 size
+	)
+	if bufferSize <= 0 {
+		return 0, fmt.Errorf("unknown error: proc_pidinfo returned %d", bufferSize)
+	}
+
+	// Allocate buffer of the required size
+	const sizeofProcFDInfo = int32(unsafe.Sizeof(procFDInfo{}))
+	numEntries := bufferSize / sizeofProcFDInfo
+	buf := make([]procFDInfo, numEntries)
+
+	// Second call: get actual data
+	ret := funcs.lib.ProcPidInfo(
+		p.Pid,
+		common.PROC_PIDLISTFDS,
+		0,
+		uintptr(unsafe.Pointer(&buf[0])), // Real buffer
+		bufferSize,                       // Size from first call
+	)
+	if ret <= 0 {
+		return 0, fmt.Errorf("unknown error: proc_pidinfo returned %d", ret)
+	}
+
+	// Calculate actual number of FDs returned
+	numFDs := ret / sizeofProcFDInfo
+	return numFDs, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go
new file mode 100644
index 000000000..a40f96195
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_amd64.go
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+package process
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec       int64
+	Usec      int32
+	Pad_cgo_0 [4]byte
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type UGid_t uint32
+
+type KinfoProc struct {
+	Proc  ExternProc
+	Eproc Eproc
+}
+
+type Eproc struct {
+	Paddr     *uint64
+	Sess      *Session
+	Pcred     Upcred
+	Ucred     Uucred
+	Pad_cgo_0 [4]byte
+	Vm        Vmspace
+	Ppid      int32
+	Pgid      int32
+	Jobc      int16
+	Pad_cgo_1 [2]byte
+	Tdev      int32
+	Tpgid     int32
+	Pad_cgo_2 [4]byte
+	Tsess     *Session
+	Wmesg     [8]int8
+	Xsize     int32
+	Xrssize   int16
+	Xccount   int16
+	Xswrss    int16
+	Pad_cgo_3 [2]byte
+	Flag      int32
+	Login     [12]int8
+	Spare     [4]int32
+	Pad_cgo_4 [4]byte
+}
+
+type Proc struct{}
+
+type Session struct{}
+
+type ucred struct {
+	Link  _Ctype_struct___0
+	Ref   uint64
+	Posix Posix_cred
+	Label *Label
+	Audit Au_session
+}
+
+type Uucred struct {
+	Ref       int32
+	UID       uint32
+	Ngroups   int16
+	Pad_cgo_0 [2]byte
+	Groups    [16]uint32
+}
+
+type Upcred struct {
+	Pc_lock   [72]int8
+	Pc_ucred  *ucred
+	P_ruid    uint32
+	P_svuid   uint32
+	P_rgid    uint32
+	P_svgid   uint32
+	P_refcnt  int32
+	Pad_cgo_0 [4]byte
+}
+
+type Vmspace struct {
+	Dummy     int32
+	Pad_cgo_0 [4]byte
+	Dummy2    *int8
+	Dummy3    [5]int32
+	Pad_cgo_1 [4]byte
+	Dummy4    [3]*int8
+}
+
+type Sigacts struct{}
+
+type ExternProc struct {
+	P_un        [16]byte
+	P_vmspace   uint64
+	P_sigacts   uint64
+	Pad_cgo_0   [3]byte
+	P_flag      int32
+	P_stat      int8
+	P_pid       int32
+	P_oppid     int32
+	P_dupfd     int32
+	Pad_cgo_1   [4]byte
+	User_stack  uint64
+	Exit_thread uint64
+	P_debugger  int32
+	Sigwait     int32
+	P_estcpu    uint32
+	P_cpticks   int32
+	P_pctcpu    uint32
+	Pad_cgo_2   [4]byte
+	P_wchan     uint64
+	P_wmesg     uint64
+	P_swtime    uint32
+	P_slptime   uint32
+	P_realtimer Itimerval
+	P_rtime     Timeval
+	P_uticks    uint64
+	P_sticks    uint64
+	P_iticks    uint64
+	P_traceflag int32
+	Pad_cgo_3   [4]byte
+	P_tracep    uint64
+	P_siglist   int32
+	Pad_cgo_4   [4]byte
+	P_textvp    uint64
+	P_holdcnt   int32
+	P_sigmask   uint32
+	P_sigignore uint32
+	P_sigcatch  uint32
+	P_priority  uint8
+	P_usrpri    uint8
+	P_nice      int8
+	P_comm      [17]int8
+	Pad_cgo_5   [4]byte
+	P_pgrp      uint64
+	P_addr      uint64
+	P_xstat     uint16
+	P_acflag    uint16
+	Pad_cgo_6   [4]byte
+	P_ru        uint64
+}
+
+type Itimerval struct {
+	Interval Timeval
+	Value    Timeval
+}
+
+type Vnode struct{}
+
+type Pgrp struct{}
+
+type UserStruct struct{}
+
+type Au_session struct {
+	Aia_p *AuditinfoAddr
+	Mask  AuMask
+}
+
+type Posix_cred struct {
+	UID       uint32
+	Ruid      uint32
+	Svuid     uint32
+	Ngroups   int16
+	Pad_cgo_0 [2]byte
+	Groups    [16]uint32
+	Rgid      uint32
+	Svgid     uint32
+	Gmuid     uint32
+	Flags     int32
+}
+
+type Label struct{}
+
+type ProcTaskInfo struct {
+	Virtual_size      uint64
+	Resident_size     uint64
+	Total_user        uint64
+	Total_system      uint64
+	Threads_user      uint64
+	Threads_system    uint64
+	Policy            int32
+	Faults            int32
+	Pageins           int32
+	Cow_faults        int32
+	Messages_sent     int32
+	Messages_received int32
+	Syscalls_mach     int32
+	Syscalls_unix     int32
+	Csw               int32
+	Threadnum         int32
+	Numrunning        int32
+	Priority          int32
+}
+
+type vinfoStat struct {
+	Dev           uint32
+	Mode          uint16
+	Nlink         uint16
+	Ino           uint64
+	Uid           uint32
+	Gid           uint32
+	Atime         int64
+	Atimensec     int64
+	Mtime         int64
+	Mtimensec     int64
+	Ctime         int64
+	Ctimensec     int64
+	Birthtime     int64
+	Birthtimensec int64
+	Size          int64
+	Blocks        int64
+	Blksize       int32
+	Flags         uint32
+	Gen           uint32
+	Rdev          uint32
+	Qspare        [2]int64
+}
+
+type fsid struct {
+	Val [2]int32
+}
+
+type vnodeInfo struct {
+	Stat vinfoStat
+	Type int32
+	Pad  int32
+	Fsid fsid
+}
+
+type vnodeInfoPath struct {
+	Vi   vnodeInfo
+	Path [1024]int8
+}
+
+type vnodePathInfo struct {
+	Cdir vnodeInfoPath
+	Rdir vnodeInfoPath
+}
+
+type AuditinfoAddr struct {
+	Auid   uint32
+	Mask   AuMask
+	Termid AuTidAddr
+	Asid   int32
+	Flags  uint64
+}
+
+type AuMask struct {
+	Success uint32
+	Failure uint32
+}
+
+type AuTidAddr struct {
+	Port int32
+	Type uint32
+	Addr [4]uint32
+}
+
+type UcredQueue struct {
+	Next *ucred
+	Prev **ucred
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go
new file mode 100644
index 000000000..7ab1afb11
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_darwin_arm64.go
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build darwin && arm64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_darwin.go
+
+package process
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec       int64
+	Usec      int32
+	Pad_cgo_0 [4]byte
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type UGid_t uint32
+
+type KinfoProc struct {
+	Proc  ExternProc
+	Eproc Eproc
+}
+
+type Eproc struct {
+	Paddr     *Proc
+	Sess      *Session
+	Pcred     Upcred
+	Ucred     Uucred
+	Vm        Vmspace
+	Ppid      int32
+	Pgid      int32
+	Jobc      int16
+	Tdev      int32
+	Tpgid     int32
+	Tsess     *Session
+	Wmesg     [8]int8
+	Xsize     int32
+	Xrssize   int16
+	Xccount   int16
+	Xswrss    int16
+	Flag      int32
+	Login     [12]int8
+	Spare     [4]int32
+	Pad_cgo_0 [4]byte
+}
+
+type Proc struct{}
+
+type Session struct{}
+
+type ucred struct{}
+
+type Uucred struct {
+	Ref     int32
+	UID     uint32
+	Ngroups int16
+	Groups  [16]uint32
+}
+
+type Upcred struct {
+	Pc_lock   [72]int8
+	Pc_ucred  *ucred
+	P_ruid    uint32
+	P_svuid   uint32
+	P_rgid    uint32
+	P_svgid   uint32
+	P_refcnt  int32
+	Pad_cgo_0 [4]byte
+}
+
+type Vmspace struct {
+	Dummy  int32
+	Dummy2 *int8
+	Dummy3 [5]int32
+	Dummy4 [3]*int8
+}
+
+type Sigacts struct{}
+
+type ExternProc struct {
+	P_un        [16]byte
+	P_vmspace   uint64
+	P_sigacts   uint64
+	Pad_cgo_0   [3]byte
+	P_flag      int32
+	P_stat      int8
+	P_pid       int32
+	P_oppid     int32
+	P_dupfd     int32
+	Pad_cgo_1   [4]byte
+	User_stack  uint64
+	Exit_thread uint64
+	P_debugger  int32
+	Sigwait     int32
+	P_estcpu    uint32
+	P_cpticks   int32
+	P_pctcpu    uint32
+	Pad_cgo_2   [4]byte
+	P_wchan     uint64
+	P_wmesg     uint64
+	P_swtime    uint32
+	P_slptime   uint32
+	P_realtimer Itimerval
+	P_rtime     Timeval
+	P_uticks    uint64
+	P_sticks    uint64
+	P_iticks    uint64
+	P_traceflag int32
+	Pad_cgo_3   [4]byte
+	P_tracep    uint64
+	P_siglist   int32
+	Pad_cgo_4   [4]byte
+	P_textvp    uint64
+	P_holdcnt   int32
+	P_sigmask   uint32
+	P_sigignore uint32
+	P_sigcatch  uint32
+	P_priority  uint8
+	P_usrpri    uint8
+	P_nice      int8
+	P_comm      [17]int8
+	Pad_cgo_5   [4]byte
+	P_pgrp      uint64
+	P_addr      uint64
+	P_xstat     uint16
+	P_acflag    uint16
+	Pad_cgo_6   [4]byte
+	P_ru        uint64
+}
+
+type Itimerval struct {
+	Interval Timeval
+	Value    Timeval
+}
+
+type Vnode struct{}
+
+type Pgrp struct{}
+
+type UserStruct struct{}
+
+type Au_session struct {
+	Aia_p *AuditinfoAddr
+	Mask  AuMask
+}
+
+type Posix_cred struct{}
+
+type Label struct{}
+
+type ProcTaskInfo struct {
+	Virtual_size      uint64
+	Resident_size     uint64
+	Total_user        uint64
+	Total_system      uint64
+	Threads_user      uint64
+	Threads_system    uint64
+	Policy            int32
+	Faults            int32
+	Pageins           int32
+	Cow_faults        int32
+	Messages_sent     int32
+	Messages_received int32
+	Syscalls_mach     int32
+	Syscalls_unix     int32
+	Csw               int32
+	Threadnum         int32
+	Numrunning        int32
+	Priority          int32
+}
+
+type vinfoStat struct {
+	Dev           uint32
+	Mode          uint16
+	Nlink         uint16
+	Ino           uint64
+	Uid           uint32
+	Gid           uint32
+	Atime         int64
+	Atimensec     int64
+	Mtime         int64
+	Mtimensec     int64
+	Ctime         int64
+	Ctimensec     int64
+	Birthtime     int64
+	Birthtimensec int64
+	Size          int64
+	Blocks        int64
+	Blksize       int32
+	Flags         uint32
+	Gen           uint32
+	Rdev          uint32
+	Qspare        [2]int64
+}
+
+type fsid struct {
+	Val [2]int32
+}
+
+type vnodeInfo struct {
+	Stat vinfoStat
+	Type int32
+	Pad  int32
+	Fsid fsid
+}
+
+type vnodeInfoPath struct {
+	Vi   vnodeInfo
+	Path [1024]int8
+}
+
+type vnodePathInfo struct {
+	Cdir vnodeInfoPath
+	Rdir vnodeInfoPath
+}
+
+type AuditinfoAddr struct {
+	Auid   uint32
+	Mask   AuMask
+	Termid AuTidAddr
+	Asid   int32
+	Flags  uint64
+}
+type AuMask struct {
+	Success uint32
+	Failure uint32
+}
+type AuTidAddr struct {
+	Port int32
+	Type uint32
+	Addr [4]uint32
+}
+
+type UcredQueue struct {
+	Next *ucred
+	Prev **ucred
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_fallback.go b/vendor/github.com/shirou/gopsutil/v4/process/process_fallback.go
new file mode 100644
index 000000000..699311a9c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_fallback.go
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris && !plan9
+
+package process
+
+import (
+	"context"
+	"syscall"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+type Signal = syscall.Signal
+
+type MemoryMapsStat struct {
+	Path         string `json:"path"`
+	Rss          uint64 `json:"rss"`
+	Size         uint64 `json:"size"`
+	Pss          uint64 `json:"pss"`
+	SharedClean  uint64 `json:"sharedClean"`
+	SharedDirty  uint64 `json:"sharedDirty"`
+	PrivateClean uint64 `json:"privateClean"`
+	PrivateDirty uint64 `json:"privateDirty"`
+	Referenced   uint64 `json:"referenced"`
+	Anonymous    uint64 `json:"anonymous"`
+	Swap         uint64 `json:"swap"`
+}
+
+type MemoryInfoExStat struct{}
+
+func pidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProcessesWithContext(_ context.Context) ([]*Process, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func PidExistsWithContext(_ context.Context, _ int32) (bool, error) {
+	return false, common.ErrNotImplementedError
+}
+
+func (*Process) PpidWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) NameWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) TgidWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) ExeWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) CmdlineWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) createTimeWithContext(_ context.Context) (int64, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) CwdWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) StatusWithContext(_ context.Context) ([]string, error) {
+	return []string{""}, common.ErrNotImplementedError
+}
+
+func (*Process) ForegroundWithContext(_ context.Context) (bool, error) {
+	return false, common.ErrNotImplementedError
+}
+
+func (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) TerminalWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) NiceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) NumFDsWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) SendSignalWithContext(_ context.Context, _ Signal) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) SuspendWithContext(_ context.Context) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) ResumeWithContext(_ context.Context) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) TerminateWithContext(_ context.Context) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) KillWithContext(_ context.Context) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) UsernameWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) EnvironWithContext(_ context.Context) ([]string, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go
new file mode 100644
index 000000000..283af9bb3
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd.go
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd
+
+package process
+
+import (
+	"bytes"
+	"context"
+	"encoding/binary"
+	"errors"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+	var ret []int32
+	procs, err := ProcessesWithContext(ctx)
+	if err != nil {
+		return ret, nil
+	}
+
+	for _, p := range procs {
+		ret = append(ret, p.Pid)
+	}
+
+	return ret, nil
+}
+
+func (p *Process) PpidWithContext(_ context.Context) (int32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+
+	return k.Ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return "", err
+	}
+	name := common.IntToString(k.Comm[:])
+
+	if len(name) >= 15 {
+		cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
+		if err != nil {
+			return "", err
+		}
+		if len(cmdlineSlice) > 0 {
+			extendedName := filepath.Base(cmdlineSlice[0])
+			if strings.HasPrefix(extendedName, p.name) {
+				name = extendedName
+			}
+		}
+	}
+
+	return name, nil
+}
+
+func (p *Process) CwdWithContext(_ context.Context) (string, error) {
+	mib := []int32{CTLKern, KernProc, KernProcCwd, p.Pid}
+	buf, length, err := common.CallSyscall(mib)
+	if err != nil {
+		return "", err
+	}
+
+	if length != sizeOfKinfoFile {
+		return "", errors.New("unexpected size of KinfoFile")
+	}
+
+	var k kinfoFile
+	br := bytes.NewReader(buf)
+	if err := binary.Read(br, binary.LittleEndian, &k); err != nil {
+		return "", err
+	}
+	cwd := common.IntToString(k.Path[:])
+
+	return cwd, nil
+}
+
+func (p *Process) ExeWithContext(_ context.Context) (string, error) {
+	mib := []int32{CTLKern, KernProc, KernProcPathname, p.Pid}
+	buf, _, err := common.CallSyscall(mib)
+	if err != nil {
+		return "", err
+	}
+
+	return strings.Trim(string(buf), "\x00"), nil
+}
+
+func (p *Process) CmdlineWithContext(_ context.Context) (string, error) {
+	mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
+	buf, _, err := common.CallSyscall(mib)
+	if err != nil {
+		return "", err
+	}
+	ret := strings.FieldsFunc(string(buf), func(r rune) bool {
+		return r == '\u0000'
+	})
+
+	return strings.Join(ret, " "), nil
+}
+
+func (p *Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {
+	mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
+	buf, _, err := common.CallSyscall(mib)
+	if err != nil {
+		return nil, err
+	}
+	if len(buf) == 0 {
+		return nil, nil
+	}
+	if buf[len(buf)-1] == 0 {
+		buf = buf[:len(buf)-1]
+	}
+	parts := bytes.Split(buf, []byte{0})
+	var strParts []string
+	for _, p := range parts {
+		strParts = append(strParts, string(p))
+	}
+
+	return strParts, nil
+}
+
+func (p *Process) createTimeWithContext(_ context.Context) (int64, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+	return int64(k.Start.Sec)*1000 + int64(k.Start.Usec)/1000, nil
+}
+
+func (p *Process) StatusWithContext(_ context.Context) ([]string, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return []string{""}, err
+	}
+	var s string
+	switch k.Stat {
+	case SIDL:
+		s = Idle
+	case SRUN:
+		s = Running
+	case SSLEEP:
+		s = Sleep
+	case SSTOP:
+		s = Stop
+	case SZOMB:
+		s = Zombie
+	case SWAIT:
+		s = Wait
+	case SLOCK:
+		s = Lock
+	}
+
+	return []string{s}, nil
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+	// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+	pid := p.Pid
+	out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+	if err != nil {
+		return false, err
+	}
+	return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) UidsWithContext(_ context.Context) ([]uint32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+
+	uids := make([]uint32, 0, 3)
+
+	uids = append(uids, uint32(k.Ruid), uint32(k.Uid), uint32(k.Svuid))
+
+	return uids, nil
+}
+
+func (p *Process) GidsWithContext(_ context.Context) ([]uint32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+
+	gids := make([]uint32, 0, 3)
+	gids = append(gids, uint32(k.Rgid), uint32(k.Ngroups), uint32(k.Svgid))
+
+	return gids, nil
+}
+
+func (p *Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+
+	groups := make([]uint32, k.Ngroups)
+	for i := int16(0); i < k.Ngroups; i++ {
+		groups[i] = uint32(k.Groups[i])
+	}
+
+	return groups, nil
+}
+
+func (p *Process) TerminalWithContext(_ context.Context) (string, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return "", err
+	}
+
+	ttyNr := uint64(k.Tdev)
+
+	termmap, err := getTerminalMap()
+	if err != nil {
+		return "", err
+	}
+
+	return termmap[ttyNr], nil
+}
+
+func (p *Process) NiceWithContext(_ context.Context) (int32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+	return int32(k.Nice), nil
+}
+
+func (p *Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+	return &IOCountersStat{
+		ReadCount:  uint64(k.Rusage.Inblock),
+		WriteCount: uint64(k.Rusage.Oublock),
+	}, nil
+}
+
+func (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+
+	return k.Numthreads, nil
+}
+
+func (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+	return &cpu.TimesStat{
+		CPU:    "cpu",
+		User:   float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000,
+		System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000,
+	}, nil
+}
+
+func (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+	v, err := unix.Sysctl("vm.stats.vm.v_page_size")
+	if err != nil {
+		return nil, err
+	}
+	pageSize := binary.LittleEndian.Uint16([]byte(v))
+
+	return &MemoryInfoStat{
+		RSS: uint64(k.Rssize) * uint64(pageSize),
+		VMS: uint64(k.Size),
+	}, nil
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+	procs, err := ProcessesWithContext(ctx)
+	if err != nil {
+		return nil, nil
+	}
+	ret := make([]*Process, 0, len(procs))
+	for _, proc := range procs {
+		ppid, err := proc.PpidWithContext(ctx)
+		if err != nil {
+			continue
+		}
+		if ppid == p.Pid {
+			ret = append(ret, proc)
+		}
+	}
+	sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+	return ret, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+	return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+	return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, maxConn)
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+	results := []*Process{}
+
+	mib := []int32{CTLKern, KernProc, KernProcProc, 0}
+	buf, length, err := common.CallSyscall(mib)
+	if err != nil {
+		return results, err
+	}
+
+	// get kinfo_proc size
+	count := int(length / uint64(sizeOfKinfoProc))
+
+	// parse buf to procs
+	for i := 0; i < count; i++ {
+		b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
+		k, err := parseKinfoProc(b)
+		if err != nil {
+			continue
+		}
+		p, err := NewProcessWithContext(ctx, int32(k.Pid))
+		if err != nil {
+			continue
+		}
+
+		results = append(results, p)
+	}
+
+	return results, nil
+}
+
+func (*Process) NumFDsWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) getKProc() (*KinfoProc, error) {
+	mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
+
+	buf, length, err := common.CallSyscall(mib)
+	if err != nil {
+		return nil, err
+	}
+	if length != sizeOfKinfoProc {
+		return nil, errors.New("unexpected size of KinfoProc")
+	}
+
+	k, err := parseKinfoProc(buf)
+	if err != nil {
+		return nil, err
+	}
+	return &k, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_386.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_386.go
new file mode 100644
index 000000000..0193ba25b
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_386.go
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 14
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 7
+	KernProcCwd      = 42
+)
+
+const (
+	sizeofPtr      = 0x4
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x4
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x488
+	sizeOfKinfoProc    = 0x300
+	sizeOfKinfoFile    = 0x570 // TODO: should be changed by running on the target machine
+)
+
+const (
+	SIDL   = 1
+	SRUN   = 2
+	SSLEEP = 3
+	SSTOP  = 4
+	SZOMB  = 5
+	SWAIT  = 6
+	SLOCK  = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int32
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int32
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int32
+	Usec int32
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int32
+	Ixrss    int32
+	Idrss    int32
+	Isrss    int32
+	Minflt   int32
+	Majflt   int32
+	Nswap    int32
+	Inblock  int32
+	Oublock  int32
+	Msgsnd   int32
+	Msgrcv   int32
+	Nsignals int32
+	Nvcsw    int32
+	Nivcsw   int32
+}
+
+type Rlimit struct {
+	Cur int64
+	Max int64
+}
+
+type KinfoProc struct {
+	Structsize   int32
+	Layout       int32
+	Args         int32 /* pargs */
+	Paddr        int32 /* proc */
+	Addr         int32 /* user */
+	Tracep       int32 /* vnode */
+	Textvp       int32 /* vnode */
+	Fd           int32 /* filedesc */
+	Vmspace      int32 /* vmspace */
+	Wchan        int32
+	Pid          int32
+	Ppid         int32
+	Pgid         int32
+	Tpgid        int32
+	Sid          int32
+	Tsid         int32
+	Jobc         int16
+	Spare_short1 int16
+	Tdev         uint32
+	Siglist      [16]byte /* sigset */
+	Sigmask      [16]byte /* sigset */
+	Sigignore    [16]byte /* sigset */
+	Sigcatch     [16]byte /* sigset */
+	Uid          uint32
+	Ruid         uint32
+	Svuid        uint32
+	Rgid         uint32
+	Svgid        uint32
+	Ngroups      int16
+	Spare_short2 int16
+	Groups       [16]uint32
+	Size         uint32
+	Rssize       int32
+	Swrss        int32
+	Tsize        int32
+	Dsize        int32
+	Ssize        int32
+	Xstat        uint16
+	Acflag       uint16
+	Pctcpu       uint32
+	Estcpu       uint32
+	Slptime      uint32
+	Swtime       uint32
+	Cow          uint32
+	Runtime      uint64
+	Start        Timeval
+	Childtime    Timeval
+	Flag         int32
+	Kiflag       int32
+	Traceflag    int32
+	Stat         int8
+	Nice         int8
+	Lock         int8
+	Rqindex      int8
+	Oncpu        uint8
+	Lastcpu      uint8
+	Tdname       [17]int8
+	Wmesg        [9]int8
+	Login        [18]int8
+	Lockname     [9]int8
+	Comm         [20]int8
+	Emul         [17]int8
+	Loginclass   [18]int8
+	Sparestrings [50]int8
+	Spareints    [7]int32
+	Flag2        int32
+	Fibnum       int32
+	Cr_flags     uint32
+	Jid          int32
+	Numthreads   int32
+	Tid          int32
+	Pri          Priority
+	Rusage       Rusage
+	Rusage_ch    Rusage
+	Pcb          int32 /* pcb */
+	Kstack       int32
+	Udata        int32
+	Tdaddr       int32 /* thread */
+	Spareptrs    [6]int32
+	Sparelongs   [12]int32
+	Sflag        int32
+	Tdflags      int32
+}
+
+type Priority struct {
+	Class  uint8
+	Level  uint8
+	Native uint8
+	User   uint8
+}
+
+type KinfoVmentry struct {
+	Structsize       int32
+	Type             int32
+	Start            uint64
+	End              uint64
+	Offset           uint64
+	Vn_fileid        uint64
+	Vn_fsid          uint32
+	Flags            int32
+	Resident         int32
+	Private_resident int32
+	Protection       int32
+	Ref_count        int32
+	Shadow_count     int32
+	Vn_type          int32
+	Vn_size          uint64
+	Vn_rdev          uint32
+	Vn_mode          uint16
+	Status           uint16
+	X_kve_ispare     [12]int32
+	Path             [1024]int8
+}
+
+// TODO: should be changed by running on the target machine
+type kinfoFile struct {
+	Structsize     int32
+	Type           int32
+	Fd             int32
+	Ref_count      int32
+	Flags          int32
+	Pad0           int32
+	Offset         int64
+	Anon0          [304]byte
+	Status         uint16
+	Pad1           uint16
+	X_kf_ispare0   int32
+	Cap_rights     capRights
+	X_kf_cap_spare uint64
+	Path           [1024]int8 // changed from uint8 by hand
+}
+
+// TODO: should be changed by running on the target machine
+type capRights struct {
+	Rights [2]uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_amd64.go
new file mode 100644
index 000000000..67970f64f
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_amd64.go
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 14
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 7
+	KernProcCwd      = 42
+)
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x488
+	sizeOfKinfoProc    = 0x440
+	sizeOfKinfoFile    = 0x570
+)
+
+const (
+	SIDL   = 1
+	SRUN   = 2
+	SSLEEP = 3
+	SSTOP  = 4
+	SZOMB  = 5
+	SWAIT  = 6
+	SLOCK  = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur int64
+	Max int64
+}
+
+type KinfoProc struct {
+	Structsize     int32
+	Layout         int32
+	Args           int64 /* pargs */
+	Paddr          int64 /* proc */
+	Addr           int64 /* user */
+	Tracep         int64 /* vnode */
+	Textvp         int64 /* vnode */
+	Fd             int64 /* filedesc */
+	Vmspace        int64 /* vmspace */
+	Wchan          int64
+	Pid            int32
+	Ppid           int32
+	Pgid           int32
+	Tpgid          int32
+	Sid            int32
+	Tsid           int32
+	Jobc           int16
+	Spare_short1   int16
+	Tdev_freebsd11 uint32
+	Siglist        [16]byte /* sigset */
+	Sigmask        [16]byte /* sigset */
+	Sigignore      [16]byte /* sigset */
+	Sigcatch       [16]byte /* sigset */
+	Uid            uint32
+	Ruid           uint32
+	Svuid          uint32
+	Rgid           uint32
+	Svgid          uint32
+	Ngroups        int16
+	Spare_short2   int16
+	Groups         [16]uint32
+	Size           uint64
+	Rssize         int64
+	Swrss          int64
+	Tsize          int64
+	Dsize          int64
+	Ssize          int64
+	Xstat          uint16
+	Acflag         uint16
+	Pctcpu         uint32
+	Estcpu         uint32
+	Slptime        uint32
+	Swtime         uint32
+	Cow            uint32
+	Runtime        uint64
+	Start          Timeval
+	Childtime      Timeval
+	Flag           int64
+	Kiflag         int64
+	Traceflag      int32
+	Stat           int8
+	Nice           int8
+	Lock           int8
+	Rqindex        int8
+	Oncpu_old      uint8
+	Lastcpu_old    uint8
+	Tdname         [17]int8
+	Wmesg          [9]int8
+	Login          [18]int8
+	Lockname       [9]int8
+	Comm           [20]int8
+	Emul           [17]int8
+	Loginclass     [18]int8
+	Moretdname     [4]int8
+	Sparestrings   [46]int8
+	Spareints      [2]int32
+	Tdev           uint64
+	Oncpu          int32
+	Lastcpu        int32
+	Tracer         int32
+	Flag2          int32
+	Fibnum         int32
+	Cr_flags       uint32
+	Jid            int32
+	Numthreads     int32
+	Tid            int32
+	Pri            Priority
+	Rusage         Rusage
+	Rusage_ch      Rusage
+	Pcb            int64 /* pcb */
+	Kstack         int64
+	Udata          int64
+	Tdaddr         int64 /* thread */
+	Pd             int64 /* pwddesc, not accurate */
+	Spareptrs      [5]int64
+	Sparelongs     [12]int64
+	Sflag          int64
+	Tdflags        int64
+}
+
+type Priority struct {
+	Class  uint8
+	Level  uint8
+	Native uint8
+	User   uint8
+}
+
+type KinfoVmentry struct {
+	Structsize        int32
+	Type              int32
+	Start             uint64
+	End               uint64
+	Offset            uint64
+	Vn_fileid         uint64
+	Vn_fsid_freebsd11 uint32
+	Flags             int32
+	Resident          int32
+	Private_resident  int32
+	Protection        int32
+	Ref_count         int32
+	Shadow_count      int32
+	Vn_type           int32
+	Vn_size           uint64
+	Vn_rdev_freebsd11 uint32
+	Vn_mode           uint16
+	Status            uint16
+	Type_spec         [8]byte
+	Vn_rdev           uint64
+	X_kve_ispare      [8]int32
+	Path              [1024]int8
+}
+
+type kinfoFile struct {
+	Structsize     int32
+	Type           int32
+	Fd             int32
+	Ref_count      int32
+	Flags          int32
+	Pad0           int32
+	Offset         int64
+	Anon0          [304]byte
+	Status         uint16
+	Pad1           uint16
+	X_kf_ispare0   int32
+	Cap_rights     capRights
+	X_kf_cap_spare uint64
+	Path           [1024]int8
+}
+
+type capRights struct {
+	Rights [2]uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm.go
new file mode 100644
index 000000000..6c4fbf698
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm.go
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 14
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 7
+	KernProcCwd      = 42
+)
+
+const (
+	sizeofPtr      = 0x4
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x4
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x488
+	sizeOfKinfoProc    = 0x440
+	sizeOfKinfoFile    = 0x570 // TODO: should be changed by running on the target machine
+)
+
+const (
+	SIDL   = 1
+	SRUN   = 2
+	SSLEEP = 3
+	SSTOP  = 4
+	SZOMB  = 5
+	SWAIT  = 6
+	SLOCK  = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int32
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int32
+	Ixrss    int32
+	Idrss    int32
+	Isrss    int32
+	Minflt   int32
+	Majflt   int32
+	Nswap    int32
+	Inblock  int32
+	Oublock  int32
+	Msgsnd   int32
+	Msgrcv   int32
+	Nsignals int32
+	Nvcsw    int32
+	Nivcsw   int32
+}
+
+type Rlimit struct {
+	Cur int32
+	Max int32
+}
+
+type KinfoProc struct {
+	Structsize   int32
+	Layout       int32
+	Args         int32 /* pargs */
+	Paddr        int32 /* proc */
+	Addr         int32 /* user */
+	Tracep       int32 /* vnode */
+	Textvp       int32 /* vnode */
+	Fd           int32 /* filedesc */
+	Vmspace      int32 /* vmspace */
+	Wchan        int32
+	Pid          int32
+	Ppid         int32
+	Pgid         int32
+	Tpgid        int32
+	Sid          int32
+	Tsid         int32
+	Jobc         int16
+	Spare_short1 int16
+	Tdev         uint32
+	Siglist      [16]byte /* sigset */
+	Sigmask      [16]byte /* sigset */
+	Sigignore    [16]byte /* sigset */
+	Sigcatch     [16]byte /* sigset */
+	Uid          uint32
+	Ruid         uint32
+	Svuid        uint32
+	Rgid         uint32
+	Svgid        uint32
+	Ngroups      int16
+	Spare_short2 int16
+	Groups       [16]uint32
+	Size         uint32
+	Rssize       int32
+	Swrss        int32
+	Tsize        int32
+	Dsize        int32
+	Ssize        int32
+	Xstat        uint16
+	Acflag       uint16
+	Pctcpu       uint32
+	Estcpu       uint32
+	Slptime      uint32
+	Swtime       uint32
+	Cow          uint32
+	Runtime      uint64
+	Start        Timeval
+	Childtime    Timeval
+	Flag         int32
+	Kiflag       int32
+	Traceflag    int32
+	Stat         int8
+	Nice         int8
+	Lock         int8
+	Rqindex      int8
+	Oncpu        uint8
+	Lastcpu      uint8
+	Tdname       [17]int8
+	Wmesg        [9]int8
+	Login        [18]int8
+	Lockname     [9]int8
+	Comm         [20]int8
+	Emul         [17]int8
+	Loginclass   [18]int8
+	Sparestrings [50]int8
+	Spareints    [4]int32
+	Flag2        int32
+	Fibnum       int32
+	Cr_flags     uint32
+	Jid          int32
+	Numthreads   int32
+	Tid          int32
+	Pri          Priority
+	Rusage       Rusage
+	Rusage_ch    Rusage
+	Pcb          int32 /* pcb */
+	Kstack       int32
+	Udata        int32
+	Tdaddr       int32 /* thread */
+	Spareptrs    [6]int64
+	Sparelongs   [12]int64
+	Sflag        int64
+	Tdflags      int64
+}
+
+type Priority struct {
+	Class  uint8
+	Level  uint8
+	Native uint8
+	User   uint8
+}
+
+type KinfoVmentry struct {
+	Structsize       int32
+	Type             int32
+	Start            uint64
+	End              uint64
+	Offset           uint64
+	Vn_fileid        uint64
+	Vn_fsid          uint32
+	Flags            int32
+	Resident         int32
+	Private_resident int32
+	Protection       int32
+	Ref_count        int32
+	Shadow_count     int32
+	Vn_type          int32
+	Vn_size          uint64
+	Vn_rdev          uint32
+	Vn_mode          uint16
+	Status           uint16
+	X_kve_ispare     [12]int32
+	Path             [1024]int8
+}
+
+// TODO: should be changed by running on the target machine
+type kinfoFile struct {
+	Structsize     int32
+	Type           int32
+	Fd             int32
+	Ref_count      int32
+	Flags          int32
+	Pad0           int32
+	Offset         int64
+	Anon0          [304]byte
+	Status         uint16
+	Pad1           uint16
+	X_kf_ispare0   int32
+	Cap_rights     capRights
+	X_kf_cap_spare uint64
+	Path           [1024]int8 // changed from uint8 by hand
+}
+
+// TODO: should be changed by running on the target machine
+type capRights struct {
+	Rights [2]uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm64.go
new file mode 100644
index 000000000..dabdc3e30
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_freebsd_arm64.go
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build freebsd && arm64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs types_freebsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 14
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 7
+	KernProcCwd      = 42
+)
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x488
+	sizeOfKinfoProc    = 0x440
+	sizeOfKinfoFile    = 0x570
+)
+
+const (
+	SIDL   = 1
+	SRUN   = 2
+	SSLEEP = 3
+	SSTOP  = 4
+	SZOMB  = 5
+	SWAIT  = 6
+	SLOCK  = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur int64
+	Max int64
+}
+
+type KinfoProc struct {
+	Structsize     int32
+	Layout         int32
+	Args           int64 /* pargs */
+	Paddr          int64 /* proc */
+	Addr           int64 /* user */
+	Tracep         int64 /* vnode */
+	Textvp         int64 /* vnode */
+	Fd             int64 /* filedesc */
+	Vmspace        int64 /* vmspace */
+	Wchan          int64
+	Pid            int32
+	Ppid           int32
+	Pgid           int32
+	Tpgid          int32
+	Sid            int32
+	Tsid           int32
+	Jobc           int16
+	Spare_short1   int16
+	Tdev_freebsd11 uint32
+	Siglist        [16]byte /* sigset */
+	Sigmask        [16]byte /* sigset */
+	Sigignore      [16]byte /* sigset */
+	Sigcatch       [16]byte /* sigset */
+	Uid            uint32
+	Ruid           uint32
+	Svuid          uint32
+	Rgid           uint32
+	Svgid          uint32
+	Ngroups        int16
+	Spare_short2   int16
+	Groups         [16]uint32
+	Size           uint64
+	Rssize         int64
+	Swrss          int64
+	Tsize          int64
+	Dsize          int64
+	Ssize          int64
+	Xstat          uint16
+	Acflag         uint16
+	Pctcpu         uint32
+	Estcpu         uint32
+	Slptime        uint32
+	Swtime         uint32
+	Cow            uint32
+	Runtime        uint64
+	Start          Timeval
+	Childtime      Timeval
+	Flag           int64
+	Kiflag         int64
+	Traceflag      int32
+	Stat           uint8
+	Nice           int8
+	Lock           uint8
+	Rqindex        uint8
+	Oncpu_old      uint8
+	Lastcpu_old    uint8
+	Tdname         [17]uint8
+	Wmesg          [9]uint8
+	Login          [18]uint8
+	Lockname       [9]uint8
+	Comm           [20]int8 // changed from uint8 by hand
+	Emul           [17]uint8
+	Loginclass     [18]uint8
+	Moretdname     [4]uint8
+	Sparestrings   [46]uint8
+	Spareints      [2]int32
+	Tdev           uint64
+	Oncpu          int32
+	Lastcpu        int32
+	Tracer         int32
+	Flag2          int32
+	Fibnum         int32
+	Cr_flags       uint32
+	Jid            int32
+	Numthreads     int32
+	Tid            int32
+	Pri            Priority
+	Rusage         Rusage
+	Rusage_ch      Rusage
+	Pcb            int64 /* pcb */
+	Kstack         int64
+	Udata          int64
+	Tdaddr         int64 /* thread */
+	Pd             int64 /* pwddesc, not accurate */
+	Spareptrs      [5]int64
+	Sparelongs     [12]int64
+	Sflag          int64
+	Tdflags        int64
+}
+
+type Priority struct {
+	Class  uint8
+	Level  uint8
+	Native uint8
+	User   uint8
+}
+
+type KinfoVmentry struct {
+	Structsize        int32
+	Type              int32
+	Start             uint64
+	End               uint64
+	Offset            uint64
+	Vn_fileid         uint64
+	Vn_fsid_freebsd11 uint32
+	Flags             int32
+	Resident          int32
+	Private_resident  int32
+	Protection        int32
+	Ref_count         int32
+	Shadow_count      int32
+	Vn_type           int32
+	Vn_size           uint64
+	Vn_rdev_freebsd11 uint32
+	Vn_mode           uint16
+	Status            uint16
+	Type_spec         [8]byte
+	Vn_rdev           uint64
+	X_kve_ispare      [8]int32
+	Path              [1024]uint8
+}
+
+type kinfoFile struct {
+	Structsize     int32
+	Type           int32
+	Fd             int32
+	Ref_count      int32
+	Flags          int32
+	Pad0           int32
+	Offset         int64
+	Anon0          [304]byte
+	Status         uint16
+	Pad1           uint16
+	X_kf_ispare0   int32
+	Cap_rights     capRights
+	X_kf_cap_spare uint64
+	Path           [1024]int8 // changed from uint8 by hand
+}
+
+type capRights struct {
+	Rights [2]uint64
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_linux.go b/vendor/github.com/shirou/gopsutil/v4/process/process_linux.go
new file mode 100644
index 000000000..dc2f03bb5
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_linux.go
@@ -0,0 +1,1206 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux
+
+package process
+
+import (
+	"bufio"
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"math"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+
+	"github.com/tklauser/go-sysconf"
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+var pageSize = uint64(os.Getpagesize())
+
+const prioProcess = 0 // linux/resource.h
+
+var clockTicks = 100 // default value
+
+func init() {
+	clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
+	// ignore errors
+	if err == nil {
+		clockTicks = int(clkTck)
+	}
+}
+
+// MemoryInfoExStat is different between OSes
+type MemoryInfoExStat struct {
+	RSS    uint64 `json:"rss"`    // bytes
+	VMS    uint64 `json:"vms"`    // bytes
+	Shared uint64 `json:"shared"` // bytes
+	Text   uint64 `json:"text"`   // bytes
+	Lib    uint64 `json:"lib"`    // bytes
+	Data   uint64 `json:"data"`   // bytes
+	Dirty  uint64 `json:"dirty"`  // bytes
+}
+
+func (m MemoryInfoExStat) String() string {
+	s, _ := json.Marshal(m)
+	return string(s)
+}
+
+type MemoryMapsStat struct {
+	Path         string `json:"path"`
+	Rss          uint64 `json:"rss"`
+	Size         uint64 `json:"size"`
+	Pss          uint64 `json:"pss"`
+	SharedClean  uint64 `json:"sharedClean"`
+	SharedDirty  uint64 `json:"sharedDirty"`
+	PrivateClean uint64 `json:"privateClean"`
+	PrivateDirty uint64 `json:"privateDirty"`
+	Referenced   uint64 `json:"referenced"`
+	Anonymous    uint64 `json:"anonymous"`
+	Swap         uint64 `json:"swap"`
+}
+
+// String returns JSON value of the process.
+func (m MemoryMapsStat) String() string {
+	s, _ := json.Marshal(m)
+	return string(s)
+}
+
+func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
+	_, ppid, _, _, _, _, _, err := p.fillFromStatWithContext(ctx)
+	if err != nil {
+		return -1, err
+	}
+	return ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+	if p.name == "" {
+		if err := p.fillNameWithContext(ctx); err != nil {
+			return "", err
+		}
+	}
+	return p.name, nil
+}
+
+func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
+	if p.tgid == 0 {
+		if err := p.fillFromStatusWithContext(ctx); err != nil {
+			return 0, err
+		}
+	}
+	return p.tgid, nil
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+	return p.fillFromExeWithContext(ctx)
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+	return p.fillFromCmdlineWithContext(ctx)
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+	return p.fillSliceFromCmdlineWithContext(ctx)
+}
+
+func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
+	_, _, _, createTime, _, _, _, err := p.fillFromStatWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+	return createTime, nil
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+	return p.fillFromCwdWithContext(ctx)
+}
+
+func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) {
+	err := p.fillFromStatusWithContext(ctx)
+	if err != nil {
+		return []string{""}, err
+	}
+	return []string{p.status}, nil
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+	// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+	pid := p.Pid
+	statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat")
+	contents, err := os.ReadFile(statPath)
+	if err != nil {
+		return false, err
+	}
+	fields := strings.Fields(string(contents))
+	if len(fields) < 8 {
+		return false, fmt.Errorf("insufficient data in %s", statPath)
+	}
+	pgid := fields[4]
+	tpgid := fields[7]
+	return pgid == tpgid, nil
+}
+
+func (p *Process) UidsWithContext(ctx context.Context) ([]uint32, error) {
+	err := p.fillFromStatusWithContext(ctx)
+	if err != nil {
+		return []uint32{}, err
+	}
+	return p.uids, nil
+}
+
+func (p *Process) GidsWithContext(ctx context.Context) ([]uint32, error) {
+	err := p.fillFromStatusWithContext(ctx)
+	if err != nil {
+		return []uint32{}, err
+	}
+	return p.gids, nil
+}
+
+func (p *Process) GroupsWithContext(ctx context.Context) ([]uint32, error) {
+	err := p.fillFromStatusWithContext(ctx)
+	if err != nil {
+		return []uint32{}, err
+	}
+	return p.groups, nil
+}
+
+func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
+	t, _, _, _, _, _, _, err := p.fillFromStatWithContext(ctx)
+	if err != nil {
+		return "", err
+	}
+	termmap, err := getTerminalMap()
+	if err != nil {
+		return "", err
+	}
+	terminal := termmap[t]
+	return terminal, nil
+}
+
+func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
+	_, _, _, _, _, nice, _, err := p.fillFromStatWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+	return nice, nil
+}
+
+func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
+	return p.RlimitUsageWithContext(ctx, false)
+}
+
+func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
+	rlimits, err := p.fillFromLimitsWithContext(ctx)
+	if !gatherUsed || err != nil {
+		return rlimits, err
+	}
+
+	_, _, _, _, rtprio, nice, _, err := p.fillFromStatWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	if err := p.fillFromStatusWithContext(ctx); err != nil {
+		return nil, err
+	}
+
+	for i := range rlimits {
+		rs := &rlimits[i]
+		switch rs.Resource {
+		case RLIMIT_CPU:
+			times, err := p.TimesWithContext(ctx)
+			if err != nil {
+				return nil, err
+			}
+			rs.Used = uint64(times.User + times.System)
+		case RLIMIT_DATA:
+			rs.Used = uint64(p.memInfo.Data)
+		case RLIMIT_STACK:
+			rs.Used = uint64(p.memInfo.Stack)
+		case RLIMIT_RSS:
+			rs.Used = uint64(p.memInfo.RSS)
+		case RLIMIT_NOFILE:
+			n, err := p.NumFDsWithContext(ctx)
+			if err != nil {
+				return nil, err
+			}
+			rs.Used = uint64(n)
+		case RLIMIT_MEMLOCK:
+			rs.Used = uint64(p.memInfo.Locked)
+		case RLIMIT_AS:
+			rs.Used = uint64(p.memInfo.VMS)
+		case RLIMIT_LOCKS:
+			// TODO we can get the used value from /proc/$pid/locks. But linux doesn't enforce it, so not a high priority.
+		case RLIMIT_SIGPENDING:
+			rs.Used = p.sigInfo.PendingProcess
+		case RLIMIT_NICE:
+			// The rlimit for nice is a little unusual, in that 0 means the niceness cannot be decreased beyond the current value, but it can be increased.
+			// So effectively: if rs.Soft == 0 { rs.Soft = rs.Used }
+			rs.Used = uint64(nice)
+		case RLIMIT_RTPRIO:
+			rs.Used = uint64(rtprio)
+		}
+	}
+
+	return rlimits, err
+}
+
+func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
+	return p.fillFromIOWithContext(ctx)
+}
+
+func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
+	err := p.fillFromStatusWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return p.numCtxSwitches, nil
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+	_, fnames, err := p.fillFromfdListWithContext(ctx)
+	return int32(len(fnames)), err
+}
+
+func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
+	err := p.fillFromStatusWithContext(ctx)
+	if err != nil {
+		return 0, err
+	}
+	return p.numThreads, nil
+}
+
+func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
+	ret := make(map[int32]*cpu.TimesStat)
+	taskPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "task")
+
+	tids, err := readPidsFromDir(taskPath)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, tid := range tids {
+		_, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStatWithContext(ctx, tid)
+		if err != nil {
+			return nil, err
+		}
+		ret[tid] = cpuTimes
+	}
+
+	return ret, nil
+}
+
+func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
+	_, _, cpuTimes, _, _, _, _, err := p.fillFromStatWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return cpuTimes, nil
+}
+
+func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+	meminfo, _, err := p.fillFromStatmWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return meminfo, nil
+}
+
+func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
+	_, memInfoEx, err := p.fillFromStatmWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return memInfoEx, nil
+}
+
+func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
+	_, _, _, _, _, _, pageFaults, err := p.fillFromStatWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return pageFaults, nil
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+	statFiles, err := filepath.Glob(common.HostProcWithContext(ctx, "[0-9]*/stat"))
+	if err != nil {
+		return nil, err
+	}
+	ret := make([]*Process, 0, len(statFiles))
+	for _, statFile := range statFiles {
+		statContents, err := os.ReadFile(statFile)
+		if err != nil || len(statContents) == 0 {
+			continue
+		}
+		fields := splitProcStat(statContents)
+		pid, err := strconv.ParseInt(fields[1], 10, 32)
+		if err != nil {
+			continue
+		}
+		ppid, err := strconv.ParseInt(fields[4], 10, 32)
+		if err != nil {
+			continue
+		}
+		if ppid == int64(p.Pid) {
+			np, err := NewProcessWithContext(ctx, int32(pid))
+			if err != nil {
+				continue
+			}
+			ret = append(ret, np)
+		}
+	}
+	sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+	return ret, nil
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+	_, ofs, err := p.fillFromfdWithContext(ctx)
+	return ofs, err
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+	return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
+}
+
+func (p *Process) ConnectionsMaxWithContext(ctx context.Context, maxConn int) ([]net.ConnectionStat, error) {
+	return net.ConnectionsPidMaxWithContext(ctx, "all", p.Pid, maxConn)
+}
+
+func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
+	pid := p.Pid
+	var ret []MemoryMapsStat
+	smapsPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "smaps")
+	if grouped {
+		ret = make([]MemoryMapsStat, 1)
+		// If smaps_rollup exists (require kernel >= 4.15), then we will use it
+		// for pre-summed memory information for a process.
+		smapsRollupPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "smaps_rollup")
+		if _, err := os.Stat(smapsRollupPath); !os.IsNotExist(err) {
+			smapsPath = smapsRollupPath
+		}
+	}
+	contents, err := os.ReadFile(smapsPath)
+	if err != nil {
+		return nil, err
+	}
+	lines := strings.Split(string(contents), "\n")
+
+	// function of parsing a block
+	getBlock := func(firstLine []string, block []string) (MemoryMapsStat, error) {
+		m := MemoryMapsStat{}
+		if len(firstLine) >= 6 {
+			m.Path = strings.Join(firstLine[5:], " ")
+		}
+
+		for _, line := range block {
+			if strings.Contains(line, "VmFlags") {
+				continue
+			}
+			field := strings.Split(line, ":")
+			if len(field) < 2 {
+				continue
+			}
+			v := strings.TrimSpace(strings.TrimSuffix(field[1], " kB"))
+			t, err := strconv.ParseUint(v, 10, 64)
+			if err != nil {
+				return m, err
+			}
+
+			switch field[0] {
+			case "Size":
+				m.Size = t
+			case "Rss":
+				m.Rss = t
+			case "Pss":
+				m.Pss = t
+			case "Shared_Clean":
+				m.SharedClean = t
+			case "Shared_Dirty":
+				m.SharedDirty = t
+			case "Private_Clean":
+				m.PrivateClean = t
+			case "Private_Dirty":
+				m.PrivateDirty = t
+			case "Referenced":
+				m.Referenced = t
+			case "Anonymous":
+				m.Anonymous = t
+			case "Swap":
+				m.Swap = t
+			}
+		}
+		return m, nil
+	}
+
+	var firstLine []string
+	blocks := make([]string, 0, 16)
+
+	for i, line := range lines {
+		fields := strings.Fields(line)
+		if (len(fields) > 0 && !strings.HasSuffix(fields[0], ":")) || i == len(lines)-1 {
+			// new block section
+			if len(firstLine) > 0 && len(blocks) > 0 {
+				g, err := getBlock(firstLine, blocks)
+				if err != nil {
+					return &ret, err
+				}
+				if grouped {
+					ret[0].Size += g.Size
+					ret[0].Rss += g.Rss
+					ret[0].Pss += g.Pss
+					ret[0].SharedClean += g.SharedClean
+					ret[0].SharedDirty += g.SharedDirty
+					ret[0].PrivateClean += g.PrivateClean
+					ret[0].PrivateDirty += g.PrivateDirty
+					ret[0].Referenced += g.Referenced
+					ret[0].Anonymous += g.Anonymous
+					ret[0].Swap += g.Swap
+				} else {
+					ret = append(ret, g)
+				}
+			}
+			// starts new block
+			blocks = make([]string, 0, 16)
+			firstLine = fields
+		} else {
+			blocks = append(blocks, line)
+		}
+	}
+
+	return &ret, nil
+}
+
+func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
+	environPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "environ")
+
+	environContent, err := os.ReadFile(environPath)
+	if err != nil {
+		return nil, err
+	}
+
+	return strings.Split(string(environContent), "\000"), nil
+}
+
+/**
+** Internal functions
+**/
+
+func limitToUint(val string) (uint64, error) {
+	if val == "unlimited" {
+		return math.MaxUint64, nil
+	}
+	res, err := strconv.ParseUint(val, 10, 64)
+	if err != nil {
+		return 0, err
+	}
+	return res, nil
+}
+
+// Get num_fds from /proc/(pid)/limits
+func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, error) {
+	pid := p.Pid
+	limitsFile := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "limits")
+	d, err := os.Open(limitsFile)
+	if err != nil {
+		return nil, err
+	}
+	defer d.Close()
+
+	var limitStats []RlimitStat
+
+	limitsScanner := bufio.NewScanner(d)
+	for limitsScanner.Scan() {
+		var statItem RlimitStat
+
+		str := strings.Fields(limitsScanner.Text())
+
+		// Remove the header line
+		if strings.Contains(str[len(str)-1], "Units") {
+			continue
+		}
+
+		// Assert that last item is a Hard limit
+		statItem.Hard, err = limitToUint(str[len(str)-1])
+		if err != nil {
+			// On error remove last item and try once again since it can be unit or header line
+			str = str[:len(str)-1]
+			statItem.Hard, err = limitToUint(str[len(str)-1])
+			if err != nil {
+				return nil, err
+			}
+		}
+		// Remove last item from string
+		str = str[:len(str)-1]
+
+		// Now last item is a Soft limit
+		statItem.Soft, err = limitToUint(str[len(str)-1])
+		if err != nil {
+			return nil, err
+		}
+		// Remove last item from string
+		str = str[:len(str)-1]
+
+		// The rest is a stats name
+		resourceName := strings.Join(str, " ")
+		switch resourceName {
+		case "Max cpu time":
+			statItem.Resource = RLIMIT_CPU
+		case "Max file size":
+			statItem.Resource = RLIMIT_FSIZE
+		case "Max data size":
+			statItem.Resource = RLIMIT_DATA
+		case "Max stack size":
+			statItem.Resource = RLIMIT_STACK
+		case "Max core file size":
+			statItem.Resource = RLIMIT_CORE
+		case "Max resident set":
+			statItem.Resource = RLIMIT_RSS
+		case "Max processes":
+			statItem.Resource = RLIMIT_NPROC
+		case "Max open files":
+			statItem.Resource = RLIMIT_NOFILE
+		case "Max locked memory":
+			statItem.Resource = RLIMIT_MEMLOCK
+		case "Max address space":
+			statItem.Resource = RLIMIT_AS
+		case "Max file locks":
+			statItem.Resource = RLIMIT_LOCKS
+		case "Max pending signals":
+			statItem.Resource = RLIMIT_SIGPENDING
+		case "Max msgqueue size":
+			statItem.Resource = RLIMIT_MSGQUEUE
+		case "Max nice priority":
+			statItem.Resource = RLIMIT_NICE
+		case "Max realtime priority":
+			statItem.Resource = RLIMIT_RTPRIO
+		case "Max realtime timeout":
+			statItem.Resource = RLIMIT_RTTIME
+		default:
+			continue
+		}
+
+		limitStats = append(limitStats, statItem)
+	}
+
+	if err := limitsScanner.Err(); err != nil {
+		return nil, err
+	}
+
+	return limitStats, nil
+}
+
+// Get list of /proc/(pid)/fd files
+func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) {
+	pid := p.Pid
+	statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "fd")
+	d, err := os.Open(statPath)
+	if err != nil {
+		return statPath, []string{}, err
+	}
+	defer d.Close()
+	fnames, err := d.Readdirnames(-1)
+	return statPath, fnames, err
+}
+
+// Get num_fds from /proc/(pid)/fd
+func (p *Process) fillFromfdWithContext(ctx context.Context) (int32, []OpenFilesStat, error) {
+	statPath, fnames, err := p.fillFromfdListWithContext(ctx)
+	if err != nil {
+		return 0, nil, err
+	}
+	numFDs := int32(len(fnames))
+
+	openfiles := make([]OpenFilesStat, 0, numFDs)
+	for _, fd := range fnames {
+		fpath := filepath.Join(statPath, fd)
+		path, err := common.Readlink(fpath)
+		if err != nil {
+			continue
+		}
+		t, err := strconv.ParseUint(fd, 10, 64)
+		if err != nil {
+			return numFDs, openfiles, err
+		}
+		o := OpenFilesStat{
+			Path: path,
+			Fd:   t,
+		}
+		openfiles = append(openfiles, o)
+	}
+
+	return numFDs, openfiles, nil
+}
+
+// Get cwd from /proc/(pid)/cwd
+func (p *Process) fillFromCwdWithContext(ctx context.Context) (string, error) {
+	pid := p.Pid
+	cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cwd")
+	cwd, err := os.Readlink(cwdPath)
+	if err != nil {
+		return "", err
+	}
+	return string(cwd), nil
+}
+
+// Get exe from /proc/(pid)/exe
+func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) {
+	pid := p.Pid
+	exePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "exe")
+	exe, err := os.Readlink(exePath)
+	if err != nil {
+		return "", err
+	}
+	return string(exe), nil
+}
+
+// Get cmdline from /proc/(pid)/cmdline
+func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {
+	pid := p.Pid
+	cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
+	cmdline, err := os.ReadFile(cmdPath)
+	if err != nil {
+		return "", err
+	}
+	ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
+		return r == '\u0000'
+	})
+
+	return strings.Join(ret, " "), nil
+}
+
+func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {
+	pid := p.Pid
+	cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
+	cmdline, err := os.ReadFile(cmdPath)
+	if err != nil {
+		return nil, err
+	}
+	if len(cmdline) == 0 {
+		return nil, nil
+	}
+
+	cmdline = bytes.TrimRight(cmdline, "\x00")
+
+	parts := bytes.Split(cmdline, []byte{0})
+	var strParts []string
+	for _, p := range parts {
+		strParts = append(strParts, string(p))
+	}
+
+	return strParts, nil
+}
+
+// Get IO status from /proc/(pid)/io
+func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) {
+	pid := p.Pid
+	ioPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "io")
+	ioline, err := os.ReadFile(ioPath)
+	if err != nil {
+		return nil, err
+	}
+	lines := strings.Split(string(ioline), "\n")
+	ret := &IOCountersStat{}
+
+	for _, line := range lines {
+		field := strings.Fields(line)
+		if len(field) < 2 {
+			continue
+		}
+		t, err := strconv.ParseUint(field[1], 10, 64)
+		if err != nil {
+			return nil, err
+		}
+		param := strings.TrimSuffix(field[0], ":")
+		switch param {
+		case "syscr":
+			ret.ReadCount = t
+		case "syscw":
+			ret.WriteCount = t
+		case "read_bytes":
+			ret.DiskReadBytes = t
+		case "write_bytes":
+			ret.DiskWriteBytes = t
+		case "rchar":
+			ret.ReadBytes = t
+		case "wchar":
+			ret.WriteBytes = t
+		}
+	}
+
+	return ret, nil
+}
+
+// Get memory info from /proc/(pid)/statm
+func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) {
+	pid := p.Pid
+	memPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "statm")
+	contents, err := os.ReadFile(memPath)
+	if err != nil {
+		return nil, nil, err
+	}
+	fields := strings.Split(string(contents), " ")
+
+	vms, err := strconv.ParseUint(fields[0], 10, 64)
+	if err != nil {
+		return nil, nil, err
+	}
+	rss, err := strconv.ParseUint(fields[1], 10, 64)
+	if err != nil {
+		return nil, nil, err
+	}
+	memInfo := &MemoryInfoStat{
+		RSS: rss * pageSize,
+		VMS: vms * pageSize,
+	}
+
+	shared, err := strconv.ParseUint(fields[2], 10, 64)
+	if err != nil {
+		return nil, nil, err
+	}
+	text, err := strconv.ParseUint(fields[3], 10, 64)
+	if err != nil {
+		return nil, nil, err
+	}
+	lib, err := strconv.ParseUint(fields[4], 10, 64)
+	if err != nil {
+		return nil, nil, err
+	}
+	dirty, err := strconv.ParseUint(fields[5], 10, 64)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	memInfoEx := &MemoryInfoExStat{
+		RSS:    rss * pageSize,
+		VMS:    vms * pageSize,
+		Shared: shared * pageSize,
+		Text:   text * pageSize,
+		Lib:    lib * pageSize,
+		Dirty:  dirty * pageSize,
+	}
+
+	return memInfo, memInfoEx, nil
+}
+
+// Get name from /proc/(pid)/comm or /proc/(pid)/status
+func (p *Process) fillNameWithContext(ctx context.Context) error {
+	err := p.fillFromCommWithContext(ctx)
+	if err == nil && p.name != "" && len(p.name) < 15 {
+		return nil
+	}
+	return p.fillFromStatusWithContext(ctx)
+}
+
+// Get name from /proc/(pid)/comm
+func (p *Process) fillFromCommWithContext(ctx context.Context) error {
+	pid := p.Pid
+	statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "comm")
+	contents, err := os.ReadFile(statPath)
+	if err != nil {
+		return err
+	}
+
+	p.name = strings.TrimSuffix(string(contents), "\n")
+	return nil
+}
+
+// Get various status from /proc/(pid)/status
+func (p *Process) fillFromStatus() error {
+	return p.fillFromStatusWithContext(context.Background())
+}
+
+func (p *Process) fillFromStatusWithContext(ctx context.Context) error {
+	pid := p.Pid
+	statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status")
+	contents, err := os.ReadFile(statPath)
+	if err != nil {
+		return err
+	}
+	lines := strings.Split(string(contents), "\n")
+	p.numCtxSwitches = &NumCtxSwitchesStat{}
+	p.memInfo = &MemoryInfoStat{}
+	p.sigInfo = &SignalInfoStat{}
+	for _, line := range lines {
+		tabParts := strings.SplitN(line, "\t", 2)
+		if len(tabParts) < 2 {
+			continue
+		}
+		value := tabParts[1]
+		switch strings.TrimRight(tabParts[0], ":") {
+		case "Name":
+			p.name = strings.Trim(value, " \t")
+			if len(p.name) >= 15 {
+				cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
+				if err != nil {
+					return err
+				}
+				if len(cmdlineSlice) > 0 {
+					extendedName := filepath.Base(cmdlineSlice[0])
+					if strings.HasPrefix(extendedName, p.name) {
+						p.name = extendedName
+					}
+				}
+			}
+			// Ensure we have a copy and not reference into slice
+			p.name = string([]byte(p.name))
+		case "State":
+			p.status = convertStatusChar(value[0:1])
+			// Ensure we have a copy and not reference into slice
+			p.status = string([]byte(p.status))
+		case "PPid", "Ppid":
+			pval, err := strconv.ParseInt(value, 10, 32)
+			if err != nil {
+				return err
+			}
+			p.parent = int32(pval)
+		case "Tgid":
+			pval, err := strconv.ParseInt(value, 10, 32)
+			if err != nil {
+				return err
+			}
+			p.tgid = int32(pval)
+		case "Uid":
+			p.uids = make([]uint32, 0, 4)
+			for _, i := range strings.Split(value, "\t") {
+				v, err := strconv.ParseUint(i, 10, 32)
+				if err != nil {
+					return err
+				}
+				p.uids = append(p.uids, uint32(v))
+			}
+		case "Gid":
+			p.gids = make([]uint32, 0, 4)
+			for _, i := range strings.Split(value, "\t") {
+				v, err := strconv.ParseUint(i, 10, 32)
+				if err != nil {
+					return err
+				}
+				p.gids = append(p.gids, uint32(v))
+			}
+		case "Groups":
+			groups := strings.Fields(value)
+			p.groups = make([]uint32, 0, len(groups))
+			for _, i := range groups {
+				v, err := strconv.ParseUint(i, 10, 32)
+				if err != nil {
+					return err
+				}
+				p.groups = append(p.groups, uint32(v))
+			}
+		case "Threads":
+			v, err := strconv.ParseInt(value, 10, 32)
+			if err != nil {
+				return err
+			}
+			p.numThreads = int32(v)
+		case "voluntary_ctxt_switches":
+			v, err := strconv.ParseInt(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.numCtxSwitches.Voluntary = v
+		case "nonvoluntary_ctxt_switches":
+			v, err := strconv.ParseInt(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.numCtxSwitches.Involuntary = v
+		case "VmRSS":
+			value = strings.TrimSpace(strings.TrimSuffix(value, " kB"))
+			v, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.memInfo.RSS = v * 1024
+		case "VmSize":
+			value = strings.TrimSpace(strings.TrimSuffix(value, " kB"))
+			v, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.memInfo.VMS = v * 1024
+		case "VmSwap":
+			value = strings.TrimSpace(strings.TrimSuffix(value, " kB"))
+			v, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.memInfo.Swap = v * 1024
+		case "VmHWM":
+			value = strings.TrimSpace(strings.TrimSuffix(value, " kB"))
+			v, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.memInfo.HWM = v * 1024
+		case "VmData":
+			value = strings.TrimSpace(strings.TrimSuffix(value, " kB"))
+			v, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.memInfo.Data = v * 1024
+		case "VmStk":
+			value = strings.TrimSpace(strings.TrimSuffix(value, " kB"))
+			v, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.memInfo.Stack = v * 1024
+		case "VmLck":
+			value = strings.TrimSpace(strings.TrimSuffix(value, " kB"))
+			v, err := strconv.ParseUint(value, 10, 64)
+			if err != nil {
+				return err
+			}
+			p.memInfo.Locked = v * 1024
+		case "SigPnd":
+			if len(value) > 16 {
+				value = value[len(value)-16:]
+			}
+			v, err := strconv.ParseUint(value, 16, 64)
+			if err != nil {
+				return err
+			}
+			p.sigInfo.PendingThread = v
+		case "ShdPnd":
+			if len(value) > 16 {
+				value = value[len(value)-16:]
+			}
+			v, err := strconv.ParseUint(value, 16, 64)
+			if err != nil {
+				return err
+			}
+			p.sigInfo.PendingProcess = v
+		case "SigBlk":
+			if len(value) > 16 {
+				value = value[len(value)-16:]
+			}
+			v, err := strconv.ParseUint(value, 16, 64)
+			if err != nil {
+				return err
+			}
+			p.sigInfo.Blocked = v
+		case "SigIgn":
+			if len(value) > 16 {
+				value = value[len(value)-16:]
+			}
+			v, err := strconv.ParseUint(value, 16, 64)
+			if err != nil {
+				return err
+			}
+			p.sigInfo.Ignored = v
+		case "SigCgt":
+			if len(value) > 16 {
+				value = value[len(value)-16:]
+			}
+			v, err := strconv.ParseUint(value, 16, 64)
+			if err != nil {
+				return err
+			}
+			p.sigInfo.Caught = v
+		}
+
+	}
+	return nil
+}
+
+func (p *Process) fillFromTIDStat(tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
+	return p.fillFromTIDStatWithContext(context.Background(), tid)
+}
+
+func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
+	pid := p.Pid
+	var statPath string
+
+	if tid == -1 {
+		statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat")
+	} else {
+		statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat")
+	}
+
+	contents, err := os.ReadFile(statPath)
+	if err == nil && len(contents) == 0 {
+		err = fmt.Errorf("process %d: stat file is empty, process may have terminated", pid)
+	}
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+	// Indexing from one, as described in `man proc` about the file /proc/[pid]/stat
+	fields := splitProcStat(contents)
+	if len(fields) < 23 {
+		return 0, 0, nil, 0, 0, 0, nil, fmt.Errorf("malformed stat file: expected at least 23 fields, got %d", len(fields))
+	}
+
+	terminal, err := strconv.ParseUint(fields[7], 10, 64)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+
+	ppid, err := strconv.ParseInt(fields[4], 10, 32)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+	utime, err := strconv.ParseFloat(fields[14], 64)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+
+	stime, err := strconv.ParseFloat(fields[15], 64)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+
+	// There is no such thing as iotime in stat file.  As an approximation, we
+	// will use delayacct_blkio_ticks (aggregated block I/O delays, as per Linux
+	// docs).  Note: I am assuming at least Linux 2.6.18
+	var iotime float64
+	if len(fields) > 42 {
+		iotime, err = strconv.ParseFloat(fields[42], 64)
+		if err != nil {
+			iotime = 0 // Ancient linux version, most likely
+		}
+	} else {
+		iotime = 0 // e.g. SmartOS containers
+	}
+
+	cpuTimes := &cpu.TimesStat{
+		CPU:    "cpu",
+		User:   utime / float64(clockTicks),
+		System: stime / float64(clockTicks),
+		Iowait: iotime / float64(clockTicks),
+	}
+
+	bootTime, _ := common.BootTimeWithContext(ctx, enableBootTimeCache)
+	t, err := strconv.ParseUint(fields[22], 10, 64)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+	createTime := int64((t * 1000 / uint64(clockTicks)) + uint64(bootTime*1000))
+
+	rtpriority, err := strconv.ParseInt(fields[18], 10, 32)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+	if rtpriority < 0 {
+		rtpriority = rtpriority*-1 - 1
+	} else {
+		rtpriority = 0
+	}
+
+	//	p.Nice = mustParseInt32(fields[18])
+	// use syscall instead of parse Stat file
+	snice, _ := unix.Getpriority(prioProcess, int(pid))
+	nice := int32(snice) // FIXME: is this true?
+
+	minFault, err := strconv.ParseUint(fields[10], 10, 64)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+	cMinFault, err := strconv.ParseUint(fields[11], 10, 64)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+	majFault, err := strconv.ParseUint(fields[12], 10, 64)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+	cMajFault, err := strconv.ParseUint(fields[13], 10, 64)
+	if err != nil {
+		return 0, 0, nil, 0, 0, 0, nil, err
+	}
+
+	faults := &PageFaultsStat{
+		MinorFaults:      minFault,
+		MajorFaults:      majFault,
+		ChildMinorFaults: cMinFault,
+		ChildMajorFaults: cMajFault,
+	}
+
+	return terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, faults, nil
+}
+
+func (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
+	return p.fillFromTIDStatWithContext(ctx, -1)
+}
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+	return readPidsFromDir(common.HostProcWithContext(ctx))
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+	out := []*Process{}
+
+	pids, err := PidsWithContext(ctx)
+	if err != nil {
+		return out, err
+	}
+
+	for _, pid := range pids {
+		p, err := NewProcessWithContext(ctx, pid)
+		if err != nil {
+			continue
+		}
+		out = append(out, p)
+	}
+
+	return out, nil
+}
+
+func readPidsFromDir(path string) ([]int32, error) {
+	var ret []int32
+
+	d, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer d.Close()
+
+	fnames, err := d.Readdirnames(-1)
+	if err != nil {
+		return nil, err
+	}
+	for _, fname := range fnames {
+		if !strictIntPtrn.MatchString(fname) {
+			continue
+		}
+		pid, err := strconv.ParseInt(fname, 10, 32)
+		if err != nil {
+			// if not numeric name, just skip
+			continue
+		}
+		ret = append(ret, int32(pid))
+	}
+
+	return ret, nil
+}
+
+func splitProcStat(content []byte) []string {
+	nameStart := bytes.IndexByte(content, '(')
+	nameEnd := bytes.LastIndexByte(content, ')')
+	restFields := strings.Fields(string(content[nameEnd+2:])) // +2 skip ') '
+	name := content[nameStart+1 : nameEnd]
+	pid := strings.TrimSpace(string(content[:nameStart]))
+	fields := make([]string, 3, len(restFields)+3)
+	fields[1] = string(pid)
+	fields[2] = string(name)
+	fields = append(fields, restFields...)
+	return fields
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go
new file mode 100644
index 000000000..31fdb85bc
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd.go
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd
+
+package process
+
+import (
+	"bytes"
+	"context"
+	"encoding/binary"
+	"errors"
+	"io"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/mem"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+	var ret []int32
+	procs, err := ProcessesWithContext(ctx)
+	if err != nil {
+		return ret, nil
+	}
+
+	for _, p := range procs {
+		ret = append(ret, p.Pid)
+	}
+
+	return ret, nil
+}
+
+func (p *Process) PpidWithContext(_ context.Context) (int32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+
+	return k.Ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return "", err
+	}
+	name := common.IntToString(k.Comm[:])
+
+	if len(name) >= 15 {
+		cmdlineSlice, err := p.CmdlineSliceWithContext(ctx)
+		if err != nil {
+			return "", err
+		}
+		if len(cmdlineSlice) > 0 {
+			extendedName := filepath.Base(cmdlineSlice[0])
+			if strings.HasPrefix(extendedName, p.name) {
+				name = extendedName
+			}
+		}
+	}
+
+	return name, nil
+}
+
+func (p *Process) CwdWithContext(_ context.Context) (string, error) {
+	mib := []int32{CTLKern, KernProcCwd, p.Pid}
+	buf, _, err := common.CallSyscall(mib)
+	if err != nil {
+		return "", err
+	}
+	return common.ByteToString(buf), nil
+}
+
+func (*Process) ExeWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (p *Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {
+	mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv}
+	buf, _, err := common.CallSyscall(mib)
+	if err != nil {
+		return nil, err
+	}
+
+	/* From man sysctl(2):
+	The buffer pointed to by oldp is filled with an array of char
+	pointers followed by the strings themselves. The last char
+	pointer is a NULL pointer. */
+	var strParts []string
+	r := bytes.NewReader(buf)
+	baseAddr := uintptr(unsafe.Pointer(&buf[0]))
+	for {
+		argvp, err := readPtr(r)
+		if err != nil {
+			return nil, err
+		}
+		if argvp == 0 { // check for a NULL pointer
+			break
+		}
+		offset := argvp - baseAddr
+		length := uintptr(bytes.IndexByte(buf[offset:], 0))
+		str := string(buf[offset : offset+length])
+		strParts = append(strParts, str)
+	}
+
+	return strParts, nil
+}
+
+// readPtr reads a pointer data from a given reader. WARNING: only little
+// endian architectures are supported.
+func readPtr(r io.Reader) (uintptr, error) {
+	switch sizeofPtr {
+	case 4:
+		var p uint32
+		if err := binary.Read(r, binary.LittleEndian, &p); err != nil {
+			return 0, err
+		}
+		return uintptr(p), nil
+	case 8:
+		var p uint64
+		if err := binary.Read(r, binary.LittleEndian, &p); err != nil {
+			return 0, err
+		}
+		return uintptr(p), nil
+	default:
+		return 0, errors.New("unsupported pointer size")
+	}
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+	argv, err := p.CmdlineSliceWithContext(ctx)
+	if err != nil {
+		return "", err
+	}
+	return strings.Join(argv, " "), nil
+}
+
+func (*Process) createTimeWithContext(_ context.Context) (int64, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) StatusWithContext(_ context.Context) ([]string, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return []string{""}, err
+	}
+	var s string
+	switch k.Stat {
+	case SIDL:
+	case SRUN:
+	case SONPROC:
+		s = Running
+	case SSLEEP:
+		s = Sleep
+	case SSTOP:
+		s = Stop
+	case SDEAD:
+		s = Zombie
+	}
+
+	return []string{s}, nil
+}
+
+func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
+	// see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details
+	pid := p.Pid
+	out, err := invoke.CommandWithContext(ctx, "ps", "-o", "stat=", "-p", strconv.Itoa(int(pid)))
+	if err != nil {
+		return false, err
+	}
+	return strings.IndexByte(string(out), '+') != -1, nil
+}
+
+func (p *Process) UidsWithContext(_ context.Context) ([]uint32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+
+	uids := make([]uint32, 0, 3)
+
+	uids = append(uids, uint32(k.Ruid), uint32(k.Uid), uint32(k.Svuid))
+
+	return uids, nil
+}
+
+func (p *Process) GidsWithContext(_ context.Context) ([]uint32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+
+	gids := make([]uint32, 0, 3)
+	gids = append(gids, uint32(k.Rgid), uint32(k.Ngroups), uint32(k.Svgid))
+
+	return gids, nil
+}
+
+func (p *Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+
+	groups := make([]uint32, k.Ngroups)
+	for i := int16(0); i < k.Ngroups; i++ {
+		groups[i] = uint32(k.Groups[i])
+	}
+
+	return groups, nil
+}
+
+func (p *Process) TerminalWithContext(_ context.Context) (string, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return "", err
+	}
+
+	ttyNr := uint64(k.Tdev)
+
+	termmap, err := getTerminalMap()
+	if err != nil {
+		return "", err
+	}
+
+	return termmap[ttyNr], nil
+}
+
+func (p *Process) NiceWithContext(_ context.Context) (int32, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return 0, err
+	}
+	return int32(k.Nice), nil
+}
+
+func (p *Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+	return &IOCountersStat{
+		ReadCount:  uint64(k.Uru_inblock),
+		WriteCount: uint64(k.Uru_oublock),
+	}, nil
+}
+
+func (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {
+	/* not supported, just return 1 */
+	return 1, nil
+}
+
+func (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+	return &cpu.TimesStat{
+		CPU:    "cpu",
+		User:   float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000,
+		System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000,
+	}, nil
+}
+
+func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
+	k, err := p.getKProc()
+	if err != nil {
+		return nil, err
+	}
+	pageSize, err := mem.GetPageSizeWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	return &MemoryInfoStat{
+		RSS: uint64(k.Vm_rssize) * pageSize,
+		VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) +
+			uint64(k.Vm_ssize),
+	}, nil
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+	procs, err := ProcessesWithContext(ctx)
+	if err != nil {
+		return nil, nil
+	}
+	ret := make([]*Process, 0, len(procs))
+	for _, proc := range procs {
+		ppid, err := proc.PpidWithContext(ctx)
+		if err != nil {
+			continue
+		}
+		if ppid == p.Pid {
+			ret = append(ret, proc)
+		}
+	}
+	sort.Slice(ret, func(i, j int) bool { return ret[i].Pid < ret[j].Pid })
+	return ret, nil
+}
+
+func (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+	results := []*Process{}
+
+	buf, length, err := callKernProcSyscall(KernProcAll, 0)
+	if err != nil {
+		return results, err
+	}
+
+	// get kinfo_proc size
+	count := int(length / uint64(sizeOfKinfoProc))
+
+	// parse buf to procs
+	for i := 0; i < count; i++ {
+		b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
+		k, err := parseKinfoProc(b)
+		if err != nil {
+			continue
+		}
+		p, err := NewProcessWithContext(ctx, int32(k.Pid))
+		if err != nil {
+			continue
+		}
+
+		results = append(results, p)
+	}
+
+	return results, nil
+}
+
+func (*Process) NumFDsWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) getKProc() (*KinfoProc, error) {
+	buf, length, err := callKernProcSyscall(KernProcPID, p.Pid)
+	if err != nil {
+		return nil, err
+	}
+	if length != sizeOfKinfoProc {
+		return nil, errors.New("unexpected size of KinfoProc")
+	}
+
+	k, err := parseKinfoProc(buf)
+	if err != nil {
+		return nil, err
+	}
+	return &k, nil
+}
+
+func callKernProcSyscall(op, arg int32) ([]byte, uint64, error) {
+	mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0}
+	mibptr := unsafe.Pointer(&mib[0])
+	miblen := uint64(len(mib))
+	length := uint64(0)
+	_, _, err := unix.Syscall6(
+		unix.SYS___SYSCTL,
+		uintptr(mibptr),
+		uintptr(miblen),
+		0,
+		uintptr(unsafe.Pointer(&length)),
+		0,
+		0)
+	if err != 0 {
+		return nil, length, err
+	}
+
+	count := int32(length / uint64(sizeOfKinfoProc))
+	mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count}
+	mibptr = unsafe.Pointer(&mib[0])
+	miblen = uint64(len(mib))
+	// get proc info itself
+	buf := make([]byte, length)
+	_, _, err = unix.Syscall6(
+		unix.SYS___SYSCTL,
+		uintptr(mibptr),
+		uintptr(miblen),
+		uintptr(unsafe.Pointer(&buf[0])),
+		uintptr(unsafe.Pointer(&length)),
+		0,
+		0)
+	if err != 0 {
+		return buf, length, err
+	}
+
+	return buf, length, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_386.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_386.go
new file mode 100644
index 000000000..5b84706a7
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_386.go
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && 386
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_openbsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 66
+	KernProcAll      = 0
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 55
+	KernProcCwd      = 78
+	KernProcArgv     = 1
+	KernProcEnv      = 3
+)
+
+const (
+	ArgMax = 256 * 1024
+)
+
+const (
+	sizeofPtr      = 0x4
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x4
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x38
+	sizeOfKinfoProc    = 0x264
+)
+
+const (
+	SIDL    = 1
+	SRUN    = 2
+	SSLEEP  = 3
+	SSTOP   = 4
+	SZOMB   = 5
+	SDEAD   = 6
+	SONPROC = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int32
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int32
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int32
+	Ixrss    int32
+	Idrss    int32
+	Isrss    int32
+	Minflt   int32
+	Majflt   int32
+	Nswap    int32
+	Inblock  int32
+	Oublock  int32
+	Msgsnd   int32
+	Msgrcv   int32
+	Nsignals int32
+	Nvcsw    int32
+	Nivcsw   int32
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type KinfoProc struct {
+	Forw         uint64
+	Back         uint64
+	Paddr        uint64
+	Addr         uint64
+	Fd           uint64
+	Stats        uint64
+	Limit        uint64
+	Vmspace      uint64
+	Sigacts      uint64
+	Sess         uint64
+	Tsess        uint64
+	Ru           uint64
+	Eflag        int32
+	Exitsig      int32
+	Flag         int32
+	Pid          int32
+	Ppid         int32
+	Sid          int32
+	X_pgid       int32
+	Tpgid        int32
+	Uid          uint32
+	Ruid         uint32
+	Gid          uint32
+	Rgid         uint32
+	Groups       [16]uint32
+	Ngroups      int16
+	Jobc         int16
+	Tdev         uint32
+	Estcpu       uint32
+	Rtime_sec    uint32
+	Rtime_usec   uint32
+	Cpticks      int32
+	Pctcpu       uint32
+	Swtime       uint32
+	Slptime      uint32
+	Schedflags   int32
+	Uticks       uint64
+	Sticks       uint64
+	Iticks       uint64
+	Tracep       uint64
+	Traceflag    int32
+	Holdcnt      int32
+	Siglist      int32
+	Sigmask      uint32
+	Sigignore    uint32
+	Sigcatch     uint32
+	Stat         int8
+	Priority     uint8
+	Usrpri       uint8
+	Nice         uint8
+	Xstat        uint16
+	Acflag       uint16
+	Comm         [24]int8
+	Wmesg        [8]int8
+	Wchan        uint64
+	Login        [32]int8
+	Vm_rssize    int32
+	Vm_tsize     int32
+	Vm_dsize     int32
+	Vm_ssize     int32
+	Uvalid       int64
+	Ustart_sec   uint64
+	Ustart_usec  uint32
+	Uutime_sec   uint32
+	Uutime_usec  uint32
+	Ustime_sec   uint32
+	Ustime_usec  uint32
+	Uru_maxrss   uint64
+	Uru_ixrss    uint64
+	Uru_idrss    uint64
+	Uru_isrss    uint64
+	Uru_minflt   uint64
+	Uru_majflt   uint64
+	Uru_nswap    uint64
+	Uru_inblock  uint64
+	Uru_oublock  uint64
+	Uru_msgsnd   uint64
+	Uru_msgrcv   uint64
+	Uru_nsignals uint64
+	Uru_nvcsw    uint64
+	Uru_nivcsw   uint64
+	Uctime_sec   uint32
+	Uctime_usec  uint32
+	Psflags      int32
+	Spare        int32
+	Svuid        uint32
+	Svgid        uint32
+	Emul         [8]int8
+	Rlim_rss_cur uint64
+	Cpuid        uint64
+	Vm_map_size  uint64
+	Tid          int32
+	Rtableid     uint32
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+	Start          uint32
+	End            uint32
+	Guard          uint32
+	Fspace         uint32
+	Fspace_augment uint32
+	Offset         uint64
+	Wired_count    int32
+	Etype          int32
+	Protection     int32
+	Max_protection int32
+	Advice         int32
+	Inheritance    int32
+	Flags          uint8
+	Pad_cgo_0      [3]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_amd64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_amd64.go
new file mode 100644
index 000000000..3229bb32c
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_amd64.go
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 66
+	KernProcAll      = 0
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 55
+	KernProcCwd      = 78
+	KernProcArgv     = 1
+	KernProcEnv      = 3
+)
+
+const (
+	ArgMax = 256 * 1024
+)
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x50
+	sizeOfKinfoProc    = 0x268
+)
+
+const (
+	SIDL    = 1
+	SRUN    = 2
+	SSLEEP  = 3
+	SSTOP   = 4
+	SZOMB   = 5
+	SDEAD   = 6
+	SONPROC = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type KinfoProc struct {
+	Forw         uint64
+	Back         uint64
+	Paddr        uint64
+	Addr         uint64
+	Fd           uint64
+	Stats        uint64
+	Limit        uint64
+	Vmspace      uint64
+	Sigacts      uint64
+	Sess         uint64
+	Tsess        uint64
+	Ru           uint64
+	Eflag        int32
+	Exitsig      int32
+	Flag         int32
+	Pid          int32
+	Ppid         int32
+	Sid          int32
+	X_pgid       int32
+	Tpgid        int32
+	Uid          uint32
+	Ruid         uint32
+	Gid          uint32
+	Rgid         uint32
+	Groups       [16]uint32
+	Ngroups      int16
+	Jobc         int16
+	Tdev         uint32
+	Estcpu       uint32
+	Rtime_sec    uint32
+	Rtime_usec   uint32
+	Cpticks      int32
+	Pctcpu       uint32
+	Swtime       uint32
+	Slptime      uint32
+	Schedflags   int32
+	Uticks       uint64
+	Sticks       uint64
+	Iticks       uint64
+	Tracep       uint64
+	Traceflag    int32
+	Holdcnt      int32
+	Siglist      int32
+	Sigmask      uint32
+	Sigignore    uint32
+	Sigcatch     uint32
+	Stat         int8
+	Priority     uint8
+	Usrpri       uint8
+	Nice         uint8
+	Xstat        uint16
+	Acflag       uint16
+	Comm         [24]int8
+	Wmesg        [8]int8
+	Wchan        uint64
+	Login        [32]int8
+	Vm_rssize    int32
+	Vm_tsize     int32
+	Vm_dsize     int32
+	Vm_ssize     int32
+	Uvalid       int64
+	Ustart_sec   uint64
+	Ustart_usec  uint32
+	Uutime_sec   uint32
+	Uutime_usec  uint32
+	Ustime_sec   uint32
+	Ustime_usec  uint32
+	Pad_cgo_0    [4]byte
+	Uru_maxrss   uint64
+	Uru_ixrss    uint64
+	Uru_idrss    uint64
+	Uru_isrss    uint64
+	Uru_minflt   uint64
+	Uru_majflt   uint64
+	Uru_nswap    uint64
+	Uru_inblock  uint64
+	Uru_oublock  uint64
+	Uru_msgsnd   uint64
+	Uru_msgrcv   uint64
+	Uru_nsignals uint64
+	Uru_nvcsw    uint64
+	Uru_nivcsw   uint64
+	Uctime_sec   uint32
+	Uctime_usec  uint32
+	Psflags      int32
+	Spare        int32
+	Svuid        uint32
+	Svgid        uint32
+	Emul         [8]int8
+	Rlim_rss_cur uint64
+	Cpuid        uint64
+	Vm_map_size  uint64
+	Tid          int32
+	Rtableid     uint32
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+	Start          uint64
+	End            uint64
+	Guard          uint64
+	Fspace         uint64
+	Fspace_augment uint64
+	Offset         uint64
+	Wired_count    int32
+	Etype          int32
+	Protection     int32
+	Max_protection int32
+	Advice         int32
+	Inheritance    int32
+	Flags          uint8
+	Pad_cgo_0      [7]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm.go
new file mode 100644
index 000000000..6f74ce756
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm.go
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && arm
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_openbsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 66
+	KernProcAll      = 0
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 55
+	KernProcCwd      = 78
+	KernProcArgv     = 1
+	KernProcEnv      = 3
+)
+
+const (
+	ArgMax = 256 * 1024
+)
+
+const (
+	sizeofPtr      = 0x4
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x4
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x38
+	sizeOfKinfoProc    = 0x264
+)
+
+const (
+	SIDL    = 1
+	SRUN    = 2
+	SSLEEP  = 3
+	SSTOP   = 4
+	SZOMB   = 5
+	SDEAD   = 6
+	SONPROC = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int32
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int32
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int32
+	Ixrss    int32
+	Idrss    int32
+	Isrss    int32
+	Minflt   int32
+	Majflt   int32
+	Nswap    int32
+	Inblock  int32
+	Oublock  int32
+	Msgsnd   int32
+	Msgrcv   int32
+	Nsignals int32
+	Nvcsw    int32
+	Nivcsw   int32
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type KinfoProc struct {
+	Forw         uint64
+	Back         uint64
+	Paddr        uint64
+	Addr         uint64
+	Fd           uint64
+	Stats        uint64
+	Limit        uint64
+	Vmspace      uint64
+	Sigacts      uint64
+	Sess         uint64
+	Tsess        uint64
+	Ru           uint64
+	Eflag        int32
+	Exitsig      int32
+	Flag         int32
+	Pid          int32
+	Ppid         int32
+	Sid          int32
+	X_pgid       int32
+	Tpgid        int32
+	Uid          uint32
+	Ruid         uint32
+	Gid          uint32
+	Rgid         uint32
+	Groups       [16]uint32
+	Ngroups      int16
+	Jobc         int16
+	Tdev         uint32
+	Estcpu       uint32
+	Rtime_sec    uint32
+	Rtime_usec   uint32
+	Cpticks      int32
+	Pctcpu       uint32
+	Swtime       uint32
+	Slptime      uint32
+	Schedflags   int32
+	Uticks       uint64
+	Sticks       uint64
+	Iticks       uint64
+	Tracep       uint64
+	Traceflag    int32
+	Holdcnt      int32
+	Siglist      int32
+	Sigmask      uint32
+	Sigignore    uint32
+	Sigcatch     uint32
+	Stat         int8
+	Priority     uint8
+	Usrpri       uint8
+	Nice         uint8
+	Xstat        uint16
+	Acflag       uint16
+	Comm         [24]int8
+	Wmesg        [8]int8
+	Wchan        uint64
+	Login        [32]int8
+	Vm_rssize    int32
+	Vm_tsize     int32
+	Vm_dsize     int32
+	Vm_ssize     int32
+	Uvalid       int64
+	Ustart_sec   uint64
+	Ustart_usec  uint32
+	Uutime_sec   uint32
+	Uutime_usec  uint32
+	Ustime_sec   uint32
+	Ustime_usec  uint32
+	Uru_maxrss   uint64
+	Uru_ixrss    uint64
+	Uru_idrss    uint64
+	Uru_isrss    uint64
+	Uru_minflt   uint64
+	Uru_majflt   uint64
+	Uru_nswap    uint64
+	Uru_inblock  uint64
+	Uru_oublock  uint64
+	Uru_msgsnd   uint64
+	Uru_msgrcv   uint64
+	Uru_nsignals uint64
+	Uru_nvcsw    uint64
+	Uru_nivcsw   uint64
+	Uctime_sec   uint32
+	Uctime_usec  uint32
+	Psflags      int32
+	Spare        int32
+	Svuid        uint32
+	Svgid        uint32
+	Emul         [8]int8
+	Rlim_rss_cur uint64
+	Cpuid        uint64
+	Vm_map_size  uint64
+	Tid          int32
+	Rtableid     uint32
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+	Start          uint32
+	End            uint32
+	Guard          uint32
+	Fspace         uint32
+	Fspace_augment uint32
+	Offset         uint64
+	Wired_count    int32
+	Etype          int32
+	Protection     int32
+	Max_protection int32
+	Advice         int32
+	Inheritance    int32
+	Flags          uint8
+	Pad_cgo_0      [3]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm64.go
new file mode 100644
index 000000000..910454562
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_arm64.go
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && arm64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_openbsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 66
+	KernProcAll      = 0
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 55
+	KernProcCwd      = 78
+	KernProcArgv     = 1
+	KernProcEnv      = 3
+)
+
+const (
+	ArgMax = 256 * 1024
+)
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x50
+	sizeOfKinfoProc    = 0x270
+)
+
+const (
+	SIDL    = 1
+	SRUN    = 2
+	SSLEEP  = 3
+	SSTOP   = 4
+	SZOMB   = 5
+	SDEAD   = 6
+	SONPROC = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type KinfoProc struct {
+	Forw         uint64
+	Back         uint64
+	Paddr        uint64
+	Addr         uint64
+	Fd           uint64
+	Stats        uint64
+	Limit        uint64
+	Vmspace      uint64
+	Sigacts      uint64
+	Sess         uint64
+	Tsess        uint64
+	Ru           uint64
+	Eflag        int32
+	Exitsig      int32
+	Flag         int32
+	Pid          int32
+	Ppid         int32
+	Sid          int32
+	X_pgid       int32
+	Tpgid        int32
+	Uid          uint32
+	Ruid         uint32
+	Gid          uint32
+	Rgid         uint32
+	Groups       [16]uint32
+	Ngroups      int16
+	Jobc         int16
+	Tdev         uint32
+	Estcpu       uint32
+	Rtime_sec    uint32
+	Rtime_usec   uint32
+	Cpticks      int32
+	Pctcpu       uint32
+	Swtime       uint32
+	Slptime      uint32
+	Schedflags   int32
+	Uticks       uint64
+	Sticks       uint64
+	Iticks       uint64
+	Tracep       uint64
+	Traceflag    int32
+	Holdcnt      int32
+	Siglist      int32
+	Sigmask      uint32
+	Sigignore    uint32
+	Sigcatch     uint32
+	Stat         int8
+	Priority     uint8
+	Usrpri       uint8
+	Nice         uint8
+	Xstat        uint16
+	Acflag       uint16
+	Comm         [24]int8
+	Wmesg        [8]uint8
+	Wchan        uint64
+	Login        [32]uint8
+	Vm_rssize    int32
+	Vm_tsize     int32
+	Vm_dsize     int32
+	Vm_ssize     int32
+	Uvalid       int64
+	Ustart_sec   uint64
+	Ustart_usec  uint32
+	Uutime_sec   uint32
+	Uutime_usec  uint32
+	Ustime_sec   uint32
+	Ustime_usec  uint32
+	Uru_maxrss   uint64
+	Uru_ixrss    uint64
+	Uru_idrss    uint64
+	Uru_isrss    uint64
+	Uru_minflt   uint64
+	Uru_majflt   uint64
+	Uru_nswap    uint64
+	Uru_inblock  uint64
+	Uru_oublock  uint64
+	Uru_msgsnd   uint64
+	Uru_msgrcv   uint64
+	Uru_nsignals uint64
+	Uru_nvcsw    uint64
+	Uru_nivcsw   uint64
+	Uctime_sec   uint32
+	Uctime_usec  uint32
+	Psflags      uint32
+	Spare        int32
+	Svuid        uint32
+	Svgid        uint32
+	Emul         [8]uint8
+	Rlim_rss_cur uint64
+	Cpuid        uint64
+	Vm_map_size  uint64
+	Tid          int32
+	Rtableid     uint32
+	Pledge       uint64
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+	Start          uint64
+	End            uint64
+	Guard          uint64
+	Fspace         uint64
+	Fspace_augment uint64
+	Offset         uint64
+	Wired_count    int32
+	Etype          int32
+	Protection     int32
+	Max_protection int32
+	Advice         int32
+	Inheritance    int32
+	Flags          uint8
+	Pad_cgo_0      [7]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_riscv64.go b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_riscv64.go
new file mode 100644
index 000000000..e3e0d36a0
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_openbsd_riscv64.go
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build openbsd && riscv64
+
+// Code generated by cmd/cgo -godefs; DO NOT EDIT.
+// cgo -godefs process/types_openbsd.go
+
+package process
+
+const (
+	CTLKern          = 1
+	KernProc         = 66
+	KernProcAll      = 0
+	KernProcPID      = 1
+	KernProcProc     = 8
+	KernProcPathname = 12
+	KernProcArgs     = 55
+	KernProcCwd      = 78
+	KernProcArgv     = 1
+	KernProcEnv      = 3
+)
+
+const (
+	ArgMax = 256 * 1024
+)
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+const (
+	sizeOfKinfoVmentry = 0x50
+	sizeOfKinfoProc    = 0x288
+)
+
+const (
+	SIDL    = 1
+	SRUN    = 2
+	SSLEEP  = 3
+	SSTOP   = 4
+	SZOMB   = 5
+	SDEAD   = 6
+	SONPROC = 7
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type KinfoProc struct {
+	Forw         uint64
+	Back         uint64
+	Paddr        uint64
+	Addr         uint64
+	Fd           uint64
+	Stats        uint64
+	Limit        uint64
+	Vmspace      uint64
+	Sigacts      uint64
+	Sess         uint64
+	Tsess        uint64
+	Ru           uint64
+	Eflag        int32
+	Exitsig      int32
+	Flag         int32
+	Pid          int32
+	Ppid         int32
+	Sid          int32
+	X_pgid       int32
+	Tpgid        int32
+	Uid          uint32
+	Ruid         uint32
+	Gid          uint32
+	Rgid         uint32
+	Groups       [16]uint32
+	Ngroups      int16
+	Jobc         int16
+	Tdev         uint32
+	Estcpu       uint32
+	Rtime_sec    uint32
+	Rtime_usec   uint32
+	Cpticks      int32
+	Pctcpu       uint32
+	Swtime       uint32
+	Slptime      uint32
+	Schedflags   int32
+	Uticks       uint64
+	Sticks       uint64
+	Iticks       uint64
+	Tracep       uint64
+	Traceflag    int32
+	Holdcnt      int32
+	Siglist      int32
+	Sigmask      uint32
+	Sigignore    uint32
+	Sigcatch     uint32
+	Stat         int8
+	Priority     uint8
+	Usrpri       uint8
+	Nice         uint8
+	Xstat        uint16
+	Spare        uint16
+	Comm         [24]int8
+	Wmesg        [8]uint8
+	Wchan        uint64
+	Login        [32]uint8
+	Vm_rssize    int32
+	Vm_tsize     int32
+	Vm_dsize     int32
+	Vm_ssize     int32
+	Uvalid       int64
+	Ustart_sec   uint64
+	Ustart_usec  uint32
+	Uutime_sec   uint32
+	Uutime_usec  uint32
+	Ustime_sec   uint32
+	Ustime_usec  uint32
+	Uru_maxrss   uint64
+	Uru_ixrss    uint64
+	Uru_idrss    uint64
+	Uru_isrss    uint64
+	Uru_minflt   uint64
+	Uru_majflt   uint64
+	Uru_nswap    uint64
+	Uru_inblock  uint64
+	Uru_oublock  uint64
+	Uru_msgsnd   uint64
+	Uru_msgrcv   uint64
+	Uru_nsignals uint64
+	Uru_nvcsw    uint64
+	Uru_nivcsw   uint64
+	Uctime_sec   uint32
+	Uctime_usec  uint32
+	Psflags      uint32
+	Acflag       uint32
+	Svuid        uint32
+	Svgid        uint32
+	Emul         [8]uint8
+	Rlim_rss_cur uint64
+	Cpuid        uint64
+	Vm_map_size  uint64
+	Tid          int32
+	Rtableid     uint32
+	Pledge       uint64
+	Name         [24]uint8
+}
+
+type Priority struct{}
+
+type KinfoVmentry struct {
+	Start          uint64
+	End            uint64
+	Guard          uint64
+	Fspace         uint64
+	Fspace_augment uint64
+	Offset         uint64
+	Wired_count    int32
+	Etype          int32
+	Protection     int32
+	Max_protection int32
+	Advice         int32
+	Inheritance    int32
+	Flags          uint8
+	Pad_cgo_0      [7]byte
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_plan9.go b/vendor/github.com/shirou/gopsutil/v4/process/process_plan9.go
new file mode 100644
index 000000000..bdb07ff28
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_plan9.go
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build plan9
+
+package process
+
+import (
+	"context"
+	"syscall"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+type Signal = syscall.Note
+
+type MemoryMapsStat struct {
+	Path         string `json:"path"`
+	Rss          uint64 `json:"rss"`
+	Size         uint64 `json:"size"`
+	Pss          uint64 `json:"pss"`
+	SharedClean  uint64 `json:"sharedClean"`
+	SharedDirty  uint64 `json:"sharedDirty"`
+	PrivateClean uint64 `json:"privateClean"`
+	PrivateDirty uint64 `json:"privateDirty"`
+	Referenced   uint64 `json:"referenced"`
+	Anonymous    uint64 `json:"anonymous"`
+	Swap         uint64 `json:"swap"`
+}
+
+type MemoryInfoExStat struct{}
+
+func pidsWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func ProcessesWithContext(_ context.Context) ([]*Process, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func PidExistsWithContext(_ context.Context, _ int32) (bool, error) {
+	return false, common.ErrNotImplementedError
+}
+
+func (*Process) PpidWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) NameWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) TgidWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) ExeWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) CmdlineWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) CmdlineSliceWithContext(_ context.Context) ([]string, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) createTimeWithContext(_ context.Context) (int64, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) CwdWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) StatusWithContext(_ context.Context) ([]string, error) {
+	return []string{""}, common.ErrNotImplementedError
+}
+
+func (*Process) ForegroundWithContext(_ context.Context) (bool, error) {
+	return false, common.ErrNotImplementedError
+}
+
+func (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) TerminalWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) NiceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) NumFDsWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) SendSignalWithContext(_ context.Context, _ Signal) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) SuspendWithContext(_ context.Context) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) ResumeWithContext(_ context.Context) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) TerminateWithContext(_ context.Context) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) KillWithContext(_ context.Context) error {
+	return common.ErrNotImplementedError
+}
+
+func (*Process) UsernameWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) EnvironWithContext(_ context.Context) ([]string, error) {
+	return nil, common.ErrNotImplementedError
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_posix.go b/vendor/github.com/shirou/gopsutil/v4/process/process_posix.go
new file mode 100644
index 000000000..9f0e93f31
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_posix.go
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build linux || freebsd || openbsd || darwin || solaris
+
+package process
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"os"
+	"os/user"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+type Signal = syscall.Signal
+
+// POSIX
+func getTerminalMap() (map[uint64]string, error) {
+	ret := make(map[uint64]string)
+	var termfiles []string
+
+	devPath := common.HostDev()
+
+	d, err := os.Open(devPath)
+	if err != nil {
+		return nil, err
+	}
+	defer d.Close()
+
+	devnames, err := d.Readdirnames(-1)
+	if err != nil {
+		return nil, err
+	}
+	for _, devname := range devnames {
+		if strings.HasPrefix(devname, "tty") {
+			termfiles = append(termfiles, filepath.Join(devPath, devname))
+		}
+	}
+
+	var ptsnames []string
+	ptsPath := filepath.Join(devPath, "pts")
+	ptsd, err := os.Open(ptsPath)
+	if err != nil {
+		ptsnames, _ = filepath.Glob(filepath.Join(devPath, "ttyp*"))
+		if ptsnames == nil {
+			return nil, err
+		}
+		termfiles = append(termfiles, ptsnames...)
+	} else {
+		defer ptsd.Close()
+		ptsnames, err = ptsd.Readdirnames(-1)
+		if err != nil {
+			return nil, err
+		}
+		for _, ptsname := range ptsnames {
+			termfiles = append(termfiles, filepath.Join(ptsPath, ptsname))
+		}
+	}
+
+	for _, name := range termfiles {
+		stat := unix.Stat_t{}
+		err = unix.Stat(name, &stat)
+		if err != nil {
+			return nil, err
+		}
+		rdev := uint64(stat.Rdev)
+		ret[rdev] = strings.TrimPrefix(name, devPath+string(os.PathSeparator))
+	}
+	return ret, nil
+}
+
+// isMount is a port of python's os.path.ismount()
+// https://github.com/python/cpython/blob/08ff4369afca84587b1c82034af4e9f64caddbf2/Lib/posixpath.py#L186-L216
+// https://docs.python.org/3/library/os.path.html#os.path.ismount
+func isMount(path string) bool {
+	// Check symlinkness with os.Lstat; unix.DT_LNK is not portable
+	fileInfo, err := os.Lstat(path)
+	if err != nil {
+		return false
+	}
+	if fileInfo.Mode()&os.ModeSymlink != 0 {
+		return false
+	}
+	var stat1 unix.Stat_t
+	if err := unix.Lstat(path, &stat1); err != nil {
+		return false
+	}
+	parent := filepath.Join(path, "..")
+	var stat2 unix.Stat_t
+	if err := unix.Lstat(parent, &stat2); err != nil {
+		return false
+	}
+	return stat1.Dev != stat2.Dev || stat1.Ino == stat2.Ino
+}
+
+func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
+	if pid <= 0 {
+		return false, fmt.Errorf("invalid pid %v", pid)
+	}
+	proc, err := os.FindProcess(int(pid))
+	if err != nil {
+		return false, err
+	}
+	defer proc.Release()
+
+	if isMount(common.HostProcWithContext(ctx)) { // if /<HOST_PROC>/proc exists and is mounted, check if /<HOST_PROC>/proc/<PID> folder exists
+		_, err := os.Stat(common.HostProcWithContext(ctx, strconv.Itoa(int(pid))))
+		if os.IsNotExist(err) {
+			return false, nil
+		}
+		return err == nil, err
+	}
+
+	// procfs does not exist or is not mounted, check PID existence by signalling the pid
+	err = proc.Signal(syscall.Signal(0))
+	if err == nil {
+		return true, nil
+	}
+	if errors.Is(err, os.ErrProcessDone) {
+		return false, nil
+	}
+	var errno syscall.Errno
+	if !errors.As(err, &errno) {
+		return false, err
+	}
+	switch errno {
+	case syscall.ESRCH:
+		return false, nil
+	case syscall.EPERM:
+		return true, nil
+	}
+
+	return false, err
+}
+
+func (p *Process) SendSignalWithContext(_ context.Context, sig syscall.Signal) error {
+	process, err := os.FindProcess(int(p.Pid))
+	if err != nil {
+		return err
+	}
+	defer process.Release()
+
+	err = process.Signal(sig)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (p *Process) SuspendWithContext(ctx context.Context) error {
+	return p.SendSignalWithContext(ctx, unix.SIGSTOP)
+}
+
+func (p *Process) ResumeWithContext(ctx context.Context) error {
+	return p.SendSignalWithContext(ctx, unix.SIGCONT)
+}
+
+func (p *Process) TerminateWithContext(ctx context.Context) error {
+	return p.SendSignalWithContext(ctx, unix.SIGTERM)
+}
+
+func (p *Process) KillWithContext(ctx context.Context) error {
+	return p.SendSignalWithContext(ctx, unix.SIGKILL)
+}
+
+func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
+	uids, err := p.UidsWithContext(ctx)
+	if err != nil {
+		return "", err
+	}
+	if len(uids) > 0 {
+		u, err := user.LookupId(strconv.Itoa(int(uids[0])))
+		if err != nil {
+			return "", err
+		}
+		return u.Username, nil
+	}
+	return "", nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_solaris.go b/vendor/github.com/shirou/gopsutil/v4/process/process_solaris.go
new file mode 100644
index 000000000..547d22872
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_solaris.go
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: BSD-3-Clause
+package process
+
+import (
+	"bytes"
+	"context"
+	"os"
+	"strconv"
+	"strings"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+type MemoryMapsStat struct {
+	Path         string `json:"path"`
+	Rss          uint64 `json:"rss"`
+	Size         uint64 `json:"size"`
+	Pss          uint64 `json:"pss"`
+	SharedClean  uint64 `json:"sharedClean"`
+	SharedDirty  uint64 `json:"sharedDirty"`
+	PrivateClean uint64 `json:"privateClean"`
+	PrivateDirty uint64 `json:"privateDirty"`
+	Referenced   uint64 `json:"referenced"`
+	Anonymous    uint64 `json:"anonymous"`
+	Swap         uint64 `json:"swap"`
+}
+
+type MemoryInfoExStat struct{}
+
+func pidsWithContext(ctx context.Context) ([]int32, error) {
+	return readPidsFromDir(common.HostProcWithContext(ctx))
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+	out := []*Process{}
+
+	pids, err := PidsWithContext(ctx)
+	if err != nil {
+		return out, err
+	}
+
+	for _, pid := range pids {
+		p, err := NewProcessWithContext(ctx, pid)
+		if err != nil {
+			continue
+		}
+		out = append(out, p)
+	}
+
+	return out, nil
+}
+
+func (*Process) PpidWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) NameWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) TgidWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
+	exe, err := p.fillFromPathAOutWithContext(ctx)
+	if os.IsNotExist(err) {
+		exe, err = p.fillFromExecnameWithContext(ctx)
+	}
+	return exe, err
+}
+
+func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
+	return p.fillFromCmdlineWithContext(ctx)
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+	return p.fillSliceFromCmdlineWithContext(ctx)
+}
+
+func (*Process) createTimeWithContext(_ context.Context) (int64, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
+	return p.fillFromPathCwdWithContext(ctx)
+}
+
+func (*Process) StatusWithContext(_ context.Context) ([]string, error) {
+	return []string{""}, common.ErrNotImplementedError
+}
+
+func (*Process) ForegroundWithContext(_ context.Context) (bool, error) {
+	return false, common.ErrNotImplementedError
+}
+
+func (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) TerminalWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+func (*Process) NiceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
+	_, fnames, err := p.fillFromfdListWithContext(ctx)
+	return int32(len(fnames)), err
+}
+
+func (*Process) NumThreadsWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ChildrenWithContext(_ context.Context) ([]*Process, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) OpenFilesWithContext(_ context.Context) ([]OpenFilesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ConnectionsWithContext(_ context.Context) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) EnvironWithContext(_ context.Context) ([]string, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+/**
+** Internal functions
+**/
+
+func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) {
+	pid := p.Pid
+	statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "fd")
+	d, err := os.Open(statPath)
+	if err != nil {
+		return statPath, []string{}, err
+	}
+	defer d.Close()
+	fnames, err := d.Readdirnames(-1)
+	return statPath, fnames, err
+}
+
+func (p *Process) fillFromPathCwdWithContext(ctx context.Context) (string, error) {
+	pid := p.Pid
+	cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "path", "cwd")
+	cwd, err := os.Readlink(cwdPath)
+	if err != nil {
+		return "", err
+	}
+	return cwd, nil
+}
+
+func (p *Process) fillFromPathAOutWithContext(ctx context.Context) (string, error) {
+	pid := p.Pid
+	cwdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "path", "a.out")
+	exe, err := os.Readlink(cwdPath)
+	if err != nil {
+		return "", err
+	}
+	return exe, nil
+}
+
+func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, error) {
+	pid := p.Pid
+	execNamePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "execname")
+	exe, err := os.ReadFile(execNamePath)
+	if err != nil {
+		return "", err
+	}
+	return string(exe), nil
+}
+
+func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {
+	pid := p.Pid
+	cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
+	cmdline, err := os.ReadFile(cmdPath)
+	if err != nil {
+		return "", err
+	}
+	ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
+		return r == '\u0000'
+	})
+
+	return strings.Join(ret, " "), nil
+}
+
+func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {
+	pid := p.Pid
+	cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline")
+	cmdline, err := os.ReadFile(cmdPath)
+	if err != nil {
+		return nil, err
+	}
+	if len(cmdline) == 0 {
+		return nil, nil
+	}
+	if cmdline[len(cmdline)-1] == 0 {
+		cmdline = cmdline[:len(cmdline)-1]
+	}
+	parts := bytes.Split(cmdline, []byte{0})
+	var strParts []string
+	for _, p := range parts {
+		strParts = append(strParts, string(p))
+	}
+
+	return strParts, nil
+}
+
+func readPidsFromDir(path string) ([]int32, error) {
+	var ret []int32
+
+	d, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer d.Close()
+
+	fnames, err := d.Readdirnames(-1)
+	if err != nil {
+		return nil, err
+	}
+	for _, fname := range fnames {
+		if !strictIntPtrn.MatchString(fname) {
+			continue
+		}
+		pid, err := strconv.ParseInt(fname, 10, 32)
+		if err != nil {
+			// if not numeric name, just skip
+			continue
+		}
+		ret = append(ret, int32(pid))
+	}
+
+	return ret, nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_windows.go b/vendor/github.com/shirou/gopsutil/v4/process/process_windows.go
new file mode 100644
index 000000000..19020e1ff
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_windows.go
@@ -0,0 +1,1260 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build windows
+
+package process
+
+import (
+	"bufio"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"reflect"
+	"syscall"
+	"time"
+	"unicode/utf16"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+
+	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/shirou/gopsutil/v4/internal/common"
+	"github.com/shirou/gopsutil/v4/net"
+)
+
+type Signal = syscall.Signal
+
+var (
+	modntdll             = windows.NewLazySystemDLL("ntdll.dll")
+	procNtResumeProcess  = modntdll.NewProc("NtResumeProcess")
+	procNtSuspendProcess = modntdll.NewProc("NtSuspendProcess")
+
+	modpsapi                     = windows.NewLazySystemDLL("psapi.dll")
+	procGetProcessMemoryInfo     = modpsapi.NewProc("GetProcessMemoryInfo")
+	procGetProcessImageFileNameW = modpsapi.NewProc("GetProcessImageFileNameW")
+
+	advapi32                  = windows.NewLazySystemDLL("advapi32.dll")
+	procLookupPrivilegeValue  = advapi32.NewProc("LookupPrivilegeValueW")
+	procAdjustTokenPrivileges = advapi32.NewProc("AdjustTokenPrivileges")
+
+	procQueryFullProcessImageNameW = common.Modkernel32.NewProc("QueryFullProcessImageNameW")
+	procGetPriorityClass           = common.Modkernel32.NewProc("GetPriorityClass")
+	procGetProcessIoCounters       = common.Modkernel32.NewProc("GetProcessIoCounters")
+	procGetNativeSystemInfo        = common.Modkernel32.NewProc("GetNativeSystemInfo")
+	procGetProcessHandleCount      = common.Modkernel32.NewProc("GetProcessHandleCount")
+
+	processorArchitecture uint
+)
+
+const processQueryInformation = windows.PROCESS_QUERY_LIMITED_INFORMATION
+
+type systemProcessorInformation struct {
+	ProcessorArchitecture uint16
+	ProcessorLevel        uint16
+	ProcessorRevision     uint16
+	Reserved              uint16
+	ProcessorFeatureBits  uint16
+}
+
+type systemInfo struct {
+	wProcessorArchitecture      uint16
+	wReserved                   uint16
+	dwpageSize                  uint32
+	lpMinimumApplicationAddress uintptr
+	lpMaximumApplicationAddress uintptr
+	dwActiveProcessorMask       uintptr
+	dwNumberOfProcessors        uint32
+	dwProcessorType             uint32
+	dwAllocationGranularity     uint32
+	wProcessorLevel             uint16
+	wProcessorRevision          uint16
+}
+
+// Memory_info_ex is different between OSes
+type MemoryInfoExStat struct{}
+
+type MemoryMapsStat struct{}
+
+// ioCounters is an equivalent representation of IO_COUNTERS in the Windows API.
+// https://docs.microsoft.com/windows/win32/api/winnt/ns-winnt-io_counters
+type ioCounters struct {
+	ReadOperationCount  uint64
+	WriteOperationCount uint64
+	OtherOperationCount uint64
+	ReadTransferCount   uint64
+	WriteTransferCount  uint64
+	OtherTransferCount  uint64
+}
+
+type processBasicInformation32 struct {
+	Reserved1       uint32
+	PebBaseAddress  uint32
+	Reserved2       uint32
+	Reserved3       uint32
+	UniqueProcessId uint32
+	Reserved4       uint32
+}
+
+type processBasicInformation64 struct {
+	Reserved1       uint64
+	PebBaseAddress  uint64
+	Reserved2       uint64
+	Reserved3       uint64
+	UniqueProcessId uint64
+	Reserved4       uint64
+}
+
+type processEnvironmentBlock32 struct {
+	Reserved1         [2]uint8
+	BeingDebugged     uint8
+	Reserved2         uint8
+	Reserved3         [2]uint32
+	Ldr               uint32
+	ProcessParameters uint32
+	// More fields which we don't use so far
+}
+
+type processEnvironmentBlock64 struct {
+	Reserved1         [2]uint8
+	BeingDebugged     uint8
+	Reserved2         uint8
+	_                 [4]uint8 // padding, since we are 64 bit, the next pointer is 64 bit aligned (when compiling for 32 bit, this is not the case without manual padding)
+	Reserved3         [2]uint64
+	Ldr               uint64
+	ProcessParameters uint64
+	// More fields which we don't use so far
+}
+
+type rtlUserProcessParameters32 struct {
+	Reserved1                      [16]uint8
+	ConsoleHandle                  uint32
+	ConsoleFlags                   uint32
+	StdInputHandle                 uint32
+	StdOutputHandle                uint32
+	StdErrorHandle                 uint32
+	CurrentDirectoryPathNameLength uint16
+	_                              uint16 // Max Length
+	CurrentDirectoryPathAddress    uint32
+	CurrentDirectoryHandle         uint32
+	DllPathNameLength              uint16
+	_                              uint16 // Max Length
+	DllPathAddress                 uint32
+	ImagePathNameLength            uint16
+	_                              uint16 // Max Length
+	ImagePathAddress               uint32
+	CommandLineLength              uint16
+	_                              uint16 // Max Length
+	CommandLineAddress             uint32
+	EnvironmentAddress             uint32
+	// More fields which we don't use so far
+}
+
+type rtlUserProcessParameters64 struct {
+	Reserved1                      [16]uint8
+	ConsoleHandle                  uint64
+	ConsoleFlags                   uint64
+	StdInputHandle                 uint64
+	StdOutputHandle                uint64
+	StdErrorHandle                 uint64
+	CurrentDirectoryPathNameLength uint16
+	_                              uint16 // Max Length
+	_                              uint32 // Padding
+	CurrentDirectoryPathAddress    uint64
+	CurrentDirectoryHandle         uint64
+	DllPathNameLength              uint16
+	_                              uint16 // Max Length
+	_                              uint32 // Padding
+	DllPathAddress                 uint64
+	ImagePathNameLength            uint16
+	_                              uint16 // Max Length
+	_                              uint32 // Padding
+	ImagePathAddress               uint64
+	CommandLineLength              uint16
+	_                              uint16 // Max Length
+	_                              uint32 // Padding
+	CommandLineAddress             uint64
+	EnvironmentAddress             uint64
+	// More fields which we don't use so far
+}
+
+type winLUID struct {
+	LowPart  winDWord
+	HighPart winLong
+}
+
+// LUID_AND_ATTRIBUTES
+type winLUIDAndAttributes struct {
+	Luid       winLUID
+	Attributes winDWord
+}
+
+// TOKEN_PRIVILEGES
+type winTokenPrivileges struct {
+	PrivilegeCount winDWord
+	Privileges     [1]winLUIDAndAttributes
+}
+
+type (
+	winLong  int32
+	winDWord uint32
+)
+
+func init() {
+	var sInfo systemInfo
+
+	procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sInfo)))
+	processorArchitecture = uint(sInfo.wProcessorArchitecture)
+
+	// enable SeDebugPrivilege https://github.com/midstar/proci/blob/6ec79f57b90ba3d9efa2a7b16ef9c9369d4be875/proci_windows.go#L80-L119
+	handle, err := syscall.GetCurrentProcess()
+	if err != nil {
+		return
+	}
+
+	var token syscall.Token
+	err = syscall.OpenProcessToken(handle, 0x0028, &token)
+	if err != nil {
+		return
+	}
+	defer token.Close()
+
+	tokenPrivileges := winTokenPrivileges{PrivilegeCount: 1}
+	lpName := syscall.StringToUTF16("SeDebugPrivilege")
+	ret, _, _ := procLookupPrivilegeValue.Call(
+		0,
+		uintptr(unsafe.Pointer(&lpName[0])),
+		uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0].Luid)))
+	if ret == 0 {
+		return
+	}
+
+	tokenPrivileges.Privileges[0].Attributes = 0x00000002 // SE_PRIVILEGE_ENABLED
+
+	procAdjustTokenPrivileges.Call(
+		uintptr(token),
+		0,
+		uintptr(unsafe.Pointer(&tokenPrivileges)),
+		uintptr(unsafe.Sizeof(tokenPrivileges)),
+		0,
+		0)
+}
+
+func pidsWithContext(_ context.Context) ([]int32, error) {
+	// inspired by https://gist.github.com/henkman/3083408
+	// and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
+	var ret []int32
+	var read uint32
+	var psSize uint32 = 1024
+	const dwordSize uint32 = 4
+
+	for {
+		ps := make([]uint32, psSize)
+		if err := windows.EnumProcesses(ps, &read); err != nil {
+			return nil, err
+		}
+		if uint32(len(ps)) == read/dwordSize { // ps buffer was too small to host every results, retry with a bigger one
+			psSize += 1024
+			continue
+		}
+		for _, pid := range ps[:read/dwordSize] {
+			ret = append(ret, int32(pid))
+		}
+		return ret, nil
+
+	}
+}
+
+func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
+	if pid == 0 { // special case for pid 0 System Idle Process
+		return true, nil
+	}
+	if pid < 0 {
+		return false, fmt.Errorf("invalid pid %v", pid)
+	}
+	if pid%4 != 0 {
+		// OpenProcess will succeed even on non-existing pid here https://devblogs.microsoft.com/oldnewthing/20080606-00/?p=22043
+		// so we list every pid just to be sure and be future-proof
+		pids, err := PidsWithContext(ctx)
+		if err != nil {
+			return false, err
+		}
+		for _, i := range pids {
+			if i == pid {
+				return true, err
+			}
+		}
+		return false, err
+	}
+	h, err := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid))
+	if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
+		return true, nil
+	}
+	if errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
+		return false, nil
+	}
+	if err != nil {
+		return false, err
+	}
+	defer windows.CloseHandle(h)
+	event, err := windows.WaitForSingleObject(h, 0)
+	return event == uint32(windows.WAIT_TIMEOUT), err
+}
+
+func (p *Process) PpidWithContext(_ context.Context) (int32, error) {
+	// if cached already, return from cache
+	cachedPpid := p.getPpid()
+	if cachedPpid != 0 {
+		return cachedPpid, nil
+	}
+
+	ppid, _, _, err := getFromSnapProcess(p.Pid)
+	if err != nil {
+		return 0, err
+	}
+
+	// no errors and not cached already, so cache it
+	p.setPpid(ppid)
+
+	return ppid, nil
+}
+
+func (p *Process) NameWithContext(ctx context.Context) (string, error) {
+	if p.Pid == 0 {
+		return "System Idle Process", nil
+	}
+	if p.name != "" {
+		return p.name, nil
+	}
+	if p.Pid == 4 {
+		return "System", nil
+	}
+
+	exe, err := p.ExeWithContext(ctx)
+	if err != nil {
+		return "", fmt.Errorf("could not get Name: %w", err)
+	}
+
+	name := filepath.Base(exe)
+	p.name = name
+	return name, nil
+}
+
+func (*Process) TgidWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (p *Process) ExeWithContext(_ context.Context) (string, error) {
+	c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
+	if err != nil {
+		return "", err
+	}
+	defer windows.CloseHandle(c)
+	buf := make([]uint16, syscall.MAX_LONG_PATH)
+	size := uint32(syscall.MAX_LONG_PATH)
+	if err := procQueryFullProcessImageNameW.Find(); err == nil { // Vista+
+		ret, _, err := procQueryFullProcessImageNameW.Call(
+			uintptr(c),
+			uintptr(0),
+			uintptr(unsafe.Pointer(&buf[0])),
+			uintptr(unsafe.Pointer(&size)))
+		if ret == 0 {
+			return "", err
+		}
+		return windows.UTF16ToString(buf), nil
+	}
+	// XP fallback
+	ret, _, err := procGetProcessImageFileNameW.Call(uintptr(c), uintptr(unsafe.Pointer(&buf[0])), uintptr(size))
+	if ret == 0 {
+		return "", err
+	}
+	return common.ConvertDOSPath(windows.UTF16ToString(buf)), nil
+}
+
+func (p *Process) CmdlineWithContext(_ context.Context) (string, error) {
+	cmdline, err := getProcessCommandLine(p.Pid)
+	if err != nil {
+		return "", fmt.Errorf("could not get CommandLine: %w", err)
+	}
+	return cmdline, nil
+}
+
+func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
+	cmdline, err := p.CmdlineWithContext(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return parseCmdline(cmdline)
+}
+
+func parseCmdline(cmdline string) ([]string, error) {
+	cmdlineptr, err := windows.UTF16PtrFromString(cmdline)
+	if err != nil {
+		return nil, err
+	}
+
+	var argc int32
+	argvptr, err := windows.CommandLineToArgv(cmdlineptr, &argc)
+	if err != nil {
+		return nil, err
+	}
+	defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argvptr))))
+
+	argv := make([]string, argc)
+	for i, v := range (*argvptr)[:argc] {
+		argv[i] = windows.UTF16ToString((*v)[:])
+	}
+	return argv, nil
+}
+
+func (p *Process) createTimeWithContext(_ context.Context) (int64, error) {
+	ru, err := getRusage(p.Pid)
+	if err != nil {
+		return 0, fmt.Errorf("could not get CreationDate: %w", err)
+	}
+
+	return ru.CreationTime.Nanoseconds() / 1000000, nil
+}
+
+func (p *Process) CwdWithContext(_ context.Context) (string, error) {
+	h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid))
+	if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
+		return "", nil
+	}
+	if err != nil {
+		return "", err
+	}
+	defer syscall.CloseHandle(syscall.Handle(h))
+
+	procIs32Bits := is32BitProcess(h)
+
+	if procIs32Bits {
+		userProcParams, err := getUserProcessParams32(h)
+		if err != nil {
+			return "", err
+		}
+		if userProcParams.CurrentDirectoryPathNameLength > 0 {
+			cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CurrentDirectoryPathAddress), uint(userProcParams.CurrentDirectoryPathNameLength))
+			if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {
+				return "", errors.New("cannot read current working directory")
+			}
+
+			return convertUTF16ToString(cwd), nil
+		}
+	} else {
+		userProcParams, err := getUserProcessParams64(h)
+		if err != nil {
+			return "", err
+		}
+		if userProcParams.CurrentDirectoryPathNameLength > 0 {
+			cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CurrentDirectoryPathAddress, uint(userProcParams.CurrentDirectoryPathNameLength))
+			if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {
+				return "", errors.New("cannot read current working directory")
+			}
+
+			return convertUTF16ToString(cwd), nil
+		}
+	}
+
+	// if we reach here, we have no cwd
+	return "", nil
+}
+
+func (*Process) StatusWithContext(_ context.Context) ([]string, error) {
+	return []string{""}, common.ErrNotImplementedError
+}
+
+func (*Process) ForegroundWithContext(_ context.Context) (bool, error) {
+	return false, common.ErrNotImplementedError
+}
+
+func (p *Process) UsernameWithContext(_ context.Context) (string, error) {
+	pid := p.Pid
+	c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
+	if err != nil {
+		return "", err
+	}
+	defer windows.CloseHandle(c)
+
+	var token syscall.Token
+	err = syscall.OpenProcessToken(syscall.Handle(c), syscall.TOKEN_QUERY, &token)
+	if err != nil {
+		return "", err
+	}
+	defer token.Close()
+	tokenUser, err := token.GetTokenUser()
+	if err != nil {
+		return "", err
+	}
+
+	user, domain, _, err := tokenUser.User.Sid.LookupAccount("")
+	return domain + "\\" + user, err
+}
+
+func (*Process) UidsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) GidsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) GroupsWithContext(_ context.Context) ([]uint32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) TerminalWithContext(_ context.Context) (string, error) {
+	return "", common.ErrNotImplementedError
+}
+
+// priorityClasses maps a win32 priority class to its WMI equivalent Win32_Process.Priority
+// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getpriorityclass
+// https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process
+var priorityClasses = map[int]int32{
+	0x00008000: 10, // ABOVE_NORMAL_PRIORITY_CLASS
+	0x00004000: 6,  // BELOW_NORMAL_PRIORITY_CLASS
+	0x00000080: 13, // HIGH_PRIORITY_CLASS
+	0x00000040: 4,  // IDLE_PRIORITY_CLASS
+	0x00000020: 8,  // NORMAL_PRIORITY_CLASS
+	0x00000100: 24, // REALTIME_PRIORITY_CLASS
+}
+
+func (p *Process) NiceWithContext(_ context.Context) (int32, error) {
+	c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
+	if err != nil {
+		return 0, err
+	}
+	defer windows.CloseHandle(c)
+	ret, _, err := procGetPriorityClass.Call(uintptr(c))
+	if ret == 0 {
+		return 0, err
+	}
+	priority, ok := priorityClasses[int(ret)]
+	if !ok {
+		return 0, fmt.Errorf("unknown priority class %v", ret)
+	}
+	return priority, nil
+}
+
+func (*Process) IOniceWithContext(_ context.Context) (int32, error) {
+	return 0, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitWithContext(_ context.Context) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) RlimitUsageWithContext(_ context.Context, _ bool) ([]RlimitStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) IOCountersWithContext(_ context.Context) (*IOCountersStat, error) {
+	c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
+	if err != nil {
+		return nil, err
+	}
+	defer windows.CloseHandle(c)
+	var counters ioCounters
+	ret, _, err := procGetProcessIoCounters.Call(uintptr(c), uintptr(unsafe.Pointer(&counters)))
+	if ret == 0 {
+		return nil, err
+	}
+	stats := &IOCountersStat{
+		ReadCount:  counters.ReadOperationCount,
+		ReadBytes:  counters.ReadTransferCount,
+		WriteCount: counters.WriteOperationCount,
+		WriteBytes: counters.WriteTransferCount,
+	}
+
+	return stats, nil
+}
+
+func (*Process) NumCtxSwitchesWithContext(_ context.Context) (*NumCtxSwitchesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+// NumFDsWithContext returns the number of handles for a process on Windows,
+// not the number of file descriptors (FDs).
+func (p *Process) NumFDsWithContext(_ context.Context) (int32, error) {
+	handle, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
+	if err != nil {
+		return 0, err
+	}
+	defer windows.CloseHandle(handle)
+
+	var handleCount uint32
+	ret, _, err := procGetProcessHandleCount.Call(uintptr(handle), uintptr(unsafe.Pointer(&handleCount)))
+	if ret == 0 {
+		return 0, err
+	}
+	return int32(handleCount), nil
+}
+
+func (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) {
+	ppid, ret, _, err := getFromSnapProcess(p.Pid)
+	if err != nil {
+		return 0, err
+	}
+
+	// if no errors and not cached already, cache ppid
+	p.parent = ppid
+	if p.getPpid() == 0 {
+		p.setPpid(ppid)
+	}
+
+	p.numThreads = ret
+
+	return ret, nil
+}
+
+func (*Process) ThreadsWithContext(_ context.Context) (map[int32]*cpu.TimesStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) {
+	sysTimes, err := getProcessCPUTimes(p.Pid)
+	if err != nil {
+		return nil, err
+	}
+
+	// User and kernel times are represented as a FILETIME structure
+	// which contains a 64-bit value representing the number of
+	// 100-nanosecond intervals since January 1, 1601 (UTC):
+	// http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
+	// To convert it into a float representing the seconds that the
+	// process has executed in user/kernel mode I borrowed the code
+	// below from psutil's _psutil_windows.c, and in turn from Python's
+	// Modules/posixmodule.c
+
+	user := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7
+	kernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7
+
+	return &cpu.TimesStat{
+		User:   user,
+		System: kernel,
+	}, nil
+}
+
+func (*Process) CPUAffinityWithContext(_ context.Context) ([]int32, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, error) {
+	mem, err := getMemoryInfo(p.Pid)
+	if err != nil {
+		return nil, err
+	}
+
+	ret := &MemoryInfoStat{
+		RSS: uint64(mem.WorkingSetSize),
+		VMS: uint64(mem.PagefileUsage),
+	}
+
+	return ret, nil
+}
+
+func (*Process) MemoryInfoExWithContext(_ context.Context) (*MemoryInfoExStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (p *Process) PageFaultsWithContext(_ context.Context) (*PageFaultsStat, error) {
+	mem, err := getMemoryInfo(p.Pid)
+	if err != nil {
+		return nil, err
+	}
+
+	ret := &PageFaultsStat{
+		// Since Windows does not distinguish between Major and Minor faults, all faults are treated as Major
+		MajorFaults: uint64(mem.PageFaultCount),
+	}
+
+	return ret, nil
+}
+
+func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
+	out := []*Process{}
+	snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(0))
+	if err != nil {
+		return out, err
+	}
+	defer windows.CloseHandle(snap)
+	var pe32 windows.ProcessEntry32
+	pe32.Size = uint32(unsafe.Sizeof(pe32))
+	if err := windows.Process32First(snap, &pe32); err != nil {
+		return out, err
+	}
+	for {
+		if pe32.ParentProcessID == uint32(p.Pid) {
+			p, err := NewProcessWithContext(ctx, int32(pe32.ProcessID))
+			if err == nil {
+				out = append(out, p)
+			}
+		}
+		if err = windows.Process32Next(snap, &pe32); err != nil {
+			break
+		}
+	}
+	return out, nil
+}
+
+func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
+	files := make([]OpenFilesStat, 0)
+	fileExists := make(map[string]bool)
+
+	process, err := windows.OpenProcess(common.ProcessQueryInformation, false, uint32(p.Pid))
+	if err != nil {
+		return nil, err
+	}
+	defer windows.CloseHandle(process)
+
+	buffer := make([]byte, 1024)
+	var size uint32
+
+	st := common.CallWithExpandingBuffer(
+		func() common.NtStatus {
+			return common.NtQuerySystemInformation(
+				common.SystemExtendedHandleInformationClass,
+				&buffer[0],
+				uint32(len(buffer)),
+				&size,
+			)
+		},
+		&buffer,
+		&size,
+	)
+	if st.IsError() {
+		return nil, st.Error()
+	}
+
+	handlesList := (*common.SystemExtendedHandleInformation)(unsafe.Pointer(&buffer[0]))
+	handles := make([]common.SystemExtendedHandleTableEntryInformation, int(handlesList.NumberOfHandles))
+	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&handles))
+	hdr.Data = uintptr(unsafe.Pointer(&handlesList.Handles[0]))
+
+	currentProcess, err := windows.GetCurrentProcess()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, handle := range handles {
+		var file uintptr
+		if int32(handle.UniqueProcessId) != p.Pid {
+			continue
+		}
+		if windows.DuplicateHandle(process, windows.Handle(handle.HandleValue), currentProcess, (*windows.Handle)(&file),
+			0, true, windows.DUPLICATE_SAME_ACCESS) != nil {
+			continue
+		}
+		// release the new handle
+		defer windows.CloseHandle(windows.Handle(file))
+
+		fileType, err := windows.GetFileType(windows.Handle(file))
+		if err != nil || fileType != windows.FILE_TYPE_DISK {
+			continue
+		}
+
+		var fileName string
+		ch := make(chan struct{}, 1)
+
+		go func() {
+			defer close(ch)
+			var buf [syscall.MAX_LONG_PATH]uint16
+			n, err := windows.GetFinalPathNameByHandle(windows.Handle(file), &buf[0], syscall.MAX_LONG_PATH, 0)
+			if err != nil {
+				return
+			}
+
+			fileName = string(utf16.Decode(buf[:n]))
+			ch <- struct{}{}
+		}()
+
+		select {
+		case <-time.NewTimer(100 * time.Millisecond).C:
+			continue
+		case <-ch:
+			fileInfo, err := os.Stat(fileName)
+			if err != nil || fileInfo.IsDir() {
+				continue
+			}
+
+			if _, exists := fileExists[fileName]; !exists {
+				files = append(files, OpenFilesStat{
+					Path: fileName,
+					Fd:   uint64(file),
+				})
+				fileExists[fileName] = true
+			}
+		case <-ctx.Done():
+			return files, ctx.Err()
+		}
+	}
+
+	return files, nil
+}
+
+func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
+	return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
+}
+
+func (*Process) ConnectionsMaxWithContext(_ context.Context, _ int) ([]net.ConnectionStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) MemoryMapsWithContext(_ context.Context, _ bool) (*[]MemoryMapsStat, error) {
+	return nil, common.ErrNotImplementedError
+}
+
+func (*Process) SendSignalWithContext(_ context.Context, _ syscall.Signal) error {
+	return common.ErrNotImplementedError
+}
+
+func (p *Process) SuspendWithContext(_ context.Context) error {
+	c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))
+	if err != nil {
+		return err
+	}
+	defer windows.CloseHandle(c)
+
+	r1, _, _ := procNtSuspendProcess.Call(uintptr(c))
+	if r1 != 0 {
+		// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
+		return fmt.Errorf("NtStatus='0x%.8X'", r1)
+	}
+
+	return nil
+}
+
+func (p *Process) ResumeWithContext(_ context.Context) error {
+	c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))
+	if err != nil {
+		return err
+	}
+	defer windows.CloseHandle(c)
+
+	r1, _, _ := procNtResumeProcess.Call(uintptr(c))
+	if r1 != 0 {
+		// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
+		return fmt.Errorf("NtStatus='0x%.8X'", r1)
+	}
+
+	return nil
+}
+
+func (p *Process) TerminateWithContext(_ context.Context) error {
+	proc, err := windows.OpenProcess(windows.PROCESS_TERMINATE, false, uint32(p.Pid))
+	if err != nil {
+		return err
+	}
+	err = windows.TerminateProcess(proc, 0)
+	windows.CloseHandle(proc)
+	return err
+}
+
+func (p *Process) KillWithContext(_ context.Context) error {
+	process, err := os.FindProcess(int(p.Pid))
+	if err != nil {
+		return err
+	}
+	defer process.Release()
+	return process.Kill()
+}
+
+func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
+	envVars, err := getProcessEnvironmentVariables(ctx, p.Pid)
+	if err != nil {
+		return nil, fmt.Errorf("could not get environment variables: %w", err)
+	}
+	return envVars, nil
+}
+
+// retrieve Ppid in a thread-safe manner
+func (p *Process) getPpid() int32 {
+	p.parentMutex.RLock()
+	defer p.parentMutex.RUnlock()
+	return p.parent
+}
+
+// cache Ppid in a thread-safe manner (WINDOWS ONLY)
+// see https://psutil.readthedocs.io/en/latest/#psutil.Process.ppid
+func (p *Process) setPpid(ppid int32) {
+	p.parentMutex.Lock()
+	defer p.parentMutex.Unlock()
+	p.parent = ppid
+}
+
+func getFromSnapProcess(pid int32) (int32, int32, string, error) { //nolint:unparam //FIXME
+	snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid))
+	if err != nil {
+		return 0, 0, "", err
+	}
+	defer windows.CloseHandle(snap)
+	var pe32 windows.ProcessEntry32
+	pe32.Size = uint32(unsafe.Sizeof(pe32))
+	err = windows.Process32First(snap, &pe32)
+	if err != nil {
+		return 0, 0, "", err
+	}
+	for {
+		if pe32.ProcessID == uint32(pid) {
+			szexe := windows.UTF16ToString(pe32.ExeFile[:])
+			return int32(pe32.ParentProcessID), int32(pe32.Threads), szexe, nil
+		}
+		if err = windows.Process32Next(snap, &pe32); err != nil {
+			break
+		}
+	}
+	return 0, 0, "", fmt.Errorf("couldn't find pid: %d", pid)
+}
+
+func buildSnapProcessMap() (map[uint32]windows.ProcessEntry32, error) {
+	snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
+	if err != nil {
+		return nil, err
+	}
+	defer windows.CloseHandle(snap)
+
+	var pe32 windows.ProcessEntry32
+	pe32.Size = uint32(unsafe.Sizeof(pe32))
+	if err := windows.Process32First(snap, &pe32); err != nil {
+		return nil, err
+	}
+
+	snapMap := make(map[uint32]windows.ProcessEntry32)
+	for {
+		snapMap[pe32.ProcessID] = pe32
+		if err := windows.Process32Next(snap, &pe32); err != nil {
+			if errors.Is(err, windows.ERROR_NO_MORE_FILES) {
+				break
+			}
+			return nil, err
+		}
+	}
+	return snapMap, nil
+}
+
+func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
+	out := []*Process{}
+
+	pids, err := PidsWithContext(ctx)
+	if err != nil {
+		return out, fmt.Errorf("could not get Processes %w", err)
+	}
+
+	// Note: The PID enumeration and snapshot creation are separate calls
+	// and may not be perfectly consistent due to timing.
+	snapMap, err := buildSnapProcessMap()
+	if err != nil {
+		return out, fmt.Errorf("could not build process snapshot: %w", err)
+	}
+
+	for _, pid := range pids {
+		p, err := NewProcessWithContext(ctx, pid)
+		if err != nil {
+			continue
+		}
+
+		if entry, ok := snapMap[uint32(pid)]; ok {
+			p.name = windows.UTF16ToString(entry.ExeFile[:])
+			p.setPpid(int32(entry.ParentProcessID))
+			p.numThreads = int32(entry.Threads)
+		}
+
+		out = append(out, p)
+	}
+
+	return out, nil
+}
+
+func getRusage(pid int32) (*windows.Rusage, error) {
+	var CPU windows.Rusage
+
+	c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
+	if err != nil {
+		return nil, err
+	}
+	defer windows.CloseHandle(c)
+
+	if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
+		return nil, err
+	}
+
+	return &CPU, nil
+}
+
+func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
+	var mem PROCESS_MEMORY_COUNTERS
+	c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
+	if err != nil {
+		return mem, err
+	}
+	defer windows.CloseHandle(c)
+	if err := getProcessMemoryInfo(c, &mem); err != nil {
+		return mem, err
+	}
+
+	return mem, err
+}
+
+func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
+	r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return err
+}
+
+type SYSTEM_TIMES struct { //nolint:revive //FIXME
+	CreateTime syscall.Filetime
+	ExitTime   syscall.Filetime
+	KernelTime syscall.Filetime
+	UserTime   syscall.Filetime
+}
+
+func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {
+	var times SYSTEM_TIMES
+
+	h, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
+	if err != nil {
+		return times, err
+	}
+	defer windows.CloseHandle(h)
+
+	err = syscall.GetProcessTimes(
+		syscall.Handle(h),
+		&times.CreateTime,
+		&times.ExitTime,
+		&times.KernelTime,
+		&times.UserTime,
+	)
+
+	return times, err
+}
+
+func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32, error) {
+	pebAddress, err := queryPebAddress(syscall.Handle(handle), true)
+	if err != nil {
+		return rtlUserProcessParameters32{}, fmt.Errorf("cannot locate process PEB: %w", err)
+	}
+
+	buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{})))
+	if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) {
+		return rtlUserProcessParameters32{}, errors.New("cannot read process PEB")
+	}
+	peb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0]))
+	userProcessAddress := uint64(peb.ProcessParameters)
+	buf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{})))
+	if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) {
+		return rtlUserProcessParameters32{}, errors.New("cannot read user process parameters")
+	}
+	return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil
+}
+
+func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64, error) {
+	pebAddress, err := queryPebAddress(syscall.Handle(handle), false)
+	if err != nil {
+		return rtlUserProcessParameters64{}, fmt.Errorf("cannot locate process PEB: %w", err)
+	}
+
+	buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{})))
+	if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) {
+		return rtlUserProcessParameters64{}, errors.New("cannot read process PEB")
+	}
+	peb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0]))
+	userProcessAddress := peb.ProcessParameters
+	buf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{})))
+	if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) {
+		return rtlUserProcessParameters64{}, errors.New("cannot read user process parameters")
+	}
+	return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil
+}
+
+func is32BitProcess(h windows.Handle) bool {
+	const (
+		PROCESSOR_ARCHITECTURE_INTEL = 0
+		PROCESSOR_ARCHITECTURE_ARM   = 5
+		PROCESSOR_ARCHITECTURE_ARM64 = 12
+		PROCESSOR_ARCHITECTURE_IA64  = 6
+		PROCESSOR_ARCHITECTURE_AMD64 = 9
+	)
+
+	var procIs32Bits bool
+	switch processorArchitecture {
+	case PROCESSOR_ARCHITECTURE_INTEL, PROCESSOR_ARCHITECTURE_ARM:
+		procIs32Bits = true
+	case PROCESSOR_ARCHITECTURE_ARM64, PROCESSOR_ARCHITECTURE_IA64, PROCESSOR_ARCHITECTURE_AMD64:
+		var wow64 uint
+
+		ret, _, _ := common.ProcNtQueryInformationProcess.Call(
+			uintptr(h),
+			uintptr(common.ProcessWow64Information),
+			uintptr(unsafe.Pointer(&wow64)),
+			uintptr(unsafe.Sizeof(wow64)),
+			uintptr(0),
+		)
+		if int(ret) >= 0 {
+			if wow64 != 0 {
+				procIs32Bits = true
+			}
+		} else {
+			// if the OS does not support the call, we fallback into the bitness of the app
+			if unsafe.Sizeof(wow64) == 4 {
+				procIs32Bits = true
+			}
+		}
+
+	default:
+		// for other unknown platforms, we rely on process platform
+		if unsafe.Sizeof(processorArchitecture) == 8 {
+			procIs32Bits = false
+		} else {
+			procIs32Bits = true
+		}
+	}
+	return procIs32Bits
+}
+
+func getProcessEnvironmentVariables(ctx context.Context, pid int32) ([]string, error) {
+	h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
+	if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
+		return nil, nil
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer syscall.CloseHandle(syscall.Handle(h))
+
+	procIs32Bits := is32BitProcess(h)
+
+	var processParameterBlockAddress uint64
+
+	if procIs32Bits {
+		peb, err := getUserProcessParams32(h)
+		if err != nil {
+			return nil, err
+		}
+		processParameterBlockAddress = uint64(peb.EnvironmentAddress)
+	} else {
+		peb, err := getUserProcessParams64(h)
+		if err != nil {
+			return nil, err
+		}
+		processParameterBlockAddress = peb.EnvironmentAddress
+	}
+	envvarScanner := bufio.NewScanner(&processReader{
+		processHandle:  h,
+		is32BitProcess: procIs32Bits,
+		offset:         processParameterBlockAddress,
+	})
+	envvarScanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+		if atEOF && len(data) == 0 {
+			return 0, nil, nil
+		}
+		// Check for UTF-16 zero character
+		for i := 0; i < len(data)-1; i += 2 {
+			if data[i] == 0 && data[i+1] == 0 {
+				return i + 2, data[0:i], nil
+			}
+		}
+		if atEOF {
+			return len(data), data, nil
+		}
+		// Request more data
+		return 0, nil, nil
+	})
+	var envVars []string
+	for envvarScanner.Scan() {
+		entry := envvarScanner.Bytes()
+		if len(entry) == 0 {
+			break // Block is finished
+		}
+		envVars = append(envVars, convertUTF16ToString(entry))
+		select {
+		case <-ctx.Done():
+			break
+		default:
+			continue
+		}
+	}
+	if err := envvarScanner.Err(); err != nil {
+		return nil, err
+	}
+	return envVars, nil
+}
+
+type processReader struct {
+	processHandle  windows.Handle
+	is32BitProcess bool
+	offset         uint64
+}
+
+func (p *processReader) Read(buf []byte) (int, error) {
+	processMemory := readProcessMemory(syscall.Handle(p.processHandle), p.is32BitProcess, p.offset, uint(len(buf)))
+	if len(processMemory) == 0 {
+		return 0, io.EOF
+	}
+	copy(buf, processMemory)
+	p.offset += uint64(len(processMemory))
+	return len(processMemory), nil
+}
+
+func getProcessCommandLine(pid int32) (string, error) {
+	h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
+	if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
+		return "", nil
+	}
+	if err != nil {
+		return "", err
+	}
+	defer syscall.CloseHandle(syscall.Handle(h))
+
+	procIs32Bits := is32BitProcess(h)
+
+	if procIs32Bits {
+		userProcParams, err := getUserProcessParams32(h)
+		if err != nil {
+			return "", err
+		}
+		if userProcParams.CommandLineLength > 0 {
+			cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CommandLineAddress), uint(userProcParams.CommandLineLength))
+			if len(cmdLine) != int(userProcParams.CommandLineLength) {
+				return "", errors.New("cannot read cmdline")
+			}
+
+			return convertUTF16ToString(cmdLine), nil
+		}
+	} else {
+		userProcParams, err := getUserProcessParams64(h)
+		if err != nil {
+			return "", err
+		}
+		if userProcParams.CommandLineLength > 0 {
+			cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength))
+			if len(cmdLine) != int(userProcParams.CommandLineLength) {
+				return "", errors.New("cannot read cmdline")
+			}
+
+			return convertUTF16ToString(cmdLine), nil
+		}
+	}
+
+	// if we reach here, we have no command line
+	return "", nil
+}
+
+func convertUTF16ToString(src []byte) string {
+	srcLen := len(src) / 2
+
+	codePoints := make([]uint16, srcLen)
+
+	srcIdx := 0
+	for i := 0; i < srcLen; i++ {
+		codePoints[i] = uint16(src[srcIdx]) | uint16(src[srcIdx+1])<<8
+		srcIdx += 2
+	}
+	return syscall.UTF16ToString(codePoints)
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_windows_32bit.go b/vendor/github.com/shirou/gopsutil/v4/process/process_windows_32bit.go
new file mode 100644
index 000000000..911351b16
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_windows_32bit.go
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build (windows && 386) || (windows && arm)
+
+package process
+
+import (
+	"errors"
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+type PROCESS_MEMORY_COUNTERS struct { //nolint:revive //FIXME
+	CB                         uint32
+	PageFaultCount             uint32
+	PeakWorkingSetSize         uint32
+	WorkingSetSize             uint32
+	QuotaPeakPagedPoolUsage    uint32
+	QuotaPagedPoolUsage        uint32
+	QuotaPeakNonPagedPoolUsage uint32
+	QuotaNonPagedPoolUsage     uint32
+	PagefileUsage              uint32
+	PeakPagefileUsage          uint32
+}
+
+func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) {
+	if is32BitProcess {
+		// we are on a 32-bit process reading an external 32-bit process
+		var info processBasicInformation32
+
+		ret, _, _ := common.ProcNtQueryInformationProcess.Call(
+			uintptr(procHandle),
+			uintptr(common.ProcessBasicInformation),
+			uintptr(unsafe.Pointer(&info)),
+			uintptr(unsafe.Sizeof(info)),
+			uintptr(0),
+		)
+		if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
+			return uint64(info.PebBaseAddress), nil
+		}
+		return 0, windows.NTStatus(ret)
+	}
+	// we are on a 32-bit process reading an external 64-bit process
+	if common.ProcNtWow64QueryInformationProcess64.Find() != nil {
+		return 0, errors.New("can't find API to query 64 bit process from 32 bit")
+	}
+	// avoid panic
+	var info processBasicInformation64
+
+	ret, _, _ := common.ProcNtWow64QueryInformationProcess64.Call(
+		uintptr(procHandle),
+		uintptr(common.ProcessBasicInformation),
+		uintptr(unsafe.Pointer(&info)),
+		uintptr(unsafe.Sizeof(info)),
+		uintptr(0),
+	)
+	if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
+		return info.PebBaseAddress, nil
+	}
+	return 0, windows.NTStatus(ret)
+}
+
+func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, size uint) []byte {
+	if is32BitProcess {
+		var read uint
+
+		buffer := make([]byte, size)
+
+		ret, _, _ := common.ProcNtReadVirtualMemory.Call(
+			uintptr(h),
+			uintptr(address),
+			uintptr(unsafe.Pointer(&buffer[0])),
+			uintptr(size),
+			uintptr(unsafe.Pointer(&read)),
+		)
+		if int(ret) >= 0 && read > 0 {
+			return buffer[:read]
+		}
+		// reading a 64-bit process from a 32-bit one
+	} else if common.ProcNtWow64ReadVirtualMemory64.Find() == nil { // avoid panic
+		var read uint64
+
+		buffer := make([]byte, size)
+
+		ret, _, _ := common.ProcNtWow64ReadVirtualMemory64.Call(
+			uintptr(h),
+			uintptr(address&0xFFFFFFFF), // the call expects a 64-bit value
+			uintptr(address>>32),
+			uintptr(unsafe.Pointer(&buffer[0])),
+			uintptr(size), // the call expects a 64-bit value
+			uintptr(0),    // but size is 32-bit so pass zero as the high dword
+			uintptr(unsafe.Pointer(&read)),
+		)
+		if int(ret) >= 0 && read > 0 {
+			return buffer[:uint(read)]
+		}
+	}
+
+	// if we reach here, an error happened
+	return nil
+}
diff --git a/vendor/github.com/shirou/gopsutil/v4/process/process_windows_64bit.go b/vendor/github.com/shirou/gopsutil/v4/process/process_windows_64bit.go
new file mode 100644
index 000000000..8cc26c375
--- /dev/null
+++ b/vendor/github.com/shirou/gopsutil/v4/process/process_windows_64bit.go
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: BSD-3-Clause
+//go:build (windows && amd64) || (windows && arm64)
+
+package process
+
+import (
+	"syscall"
+	"unsafe"
+
+	"golang.org/x/sys/windows"
+
+	"github.com/shirou/gopsutil/v4/internal/common"
+)
+
+type PROCESS_MEMORY_COUNTERS struct { //nolint:revive //FIXME
+	CB                         uint32
+	PageFaultCount             uint32
+	PeakWorkingSetSize         uint64
+	WorkingSetSize             uint64
+	QuotaPeakPagedPoolUsage    uint64
+	QuotaPagedPoolUsage        uint64
+	QuotaPeakNonPagedPoolUsage uint64
+	QuotaNonPagedPoolUsage     uint64
+	PagefileUsage              uint64
+	PeakPagefileUsage          uint64
+}
+
+func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) (uint64, error) {
+	if is32BitProcess {
+		// we are on a 64-bit process reading an external 32-bit process
+		var wow64 uint
+
+		ret, _, _ := common.ProcNtQueryInformationProcess.Call(
+			uintptr(procHandle),
+			uintptr(common.ProcessWow64Information),
+			uintptr(unsafe.Pointer(&wow64)),
+			uintptr(unsafe.Sizeof(wow64)),
+			uintptr(0),
+		)
+		if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
+			return uint64(wow64), nil
+		}
+		return 0, windows.NTStatus(ret)
+	}
+	// we are on a 64-bit process reading an external 64-bit process
+	var info processBasicInformation64
+
+	ret, _, _ := common.ProcNtQueryInformationProcess.Call(
+		uintptr(procHandle),
+		uintptr(common.ProcessBasicInformation),
+		uintptr(unsafe.Pointer(&info)),
+		uintptr(unsafe.Sizeof(info)),
+		uintptr(0),
+	)
+	if status := windows.NTStatus(ret); status == windows.STATUS_SUCCESS {
+		return info.PebBaseAddress, nil
+	}
+	return 0, windows.NTStatus(ret)
+}
+
+func readProcessMemory(procHandle syscall.Handle, _ bool, address uint64, size uint) []byte {
+	var read uint
+
+	buffer := make([]byte, size)
+
+	ret, _, _ := common.ProcNtReadVirtualMemory.Call(
+		uintptr(procHandle),
+		uintptr(address),
+		uintptr(unsafe.Pointer(&buffer[0])),
+		uintptr(size),
+		uintptr(unsafe.Pointer(&read)),
+	)
+	if int(ret) >= 0 && read > 0 {
+		return buffer[:read]
+	}
+	return nil
+}
diff --git a/vendor/github.com/stretchr/testify/LICENSE b/vendor/github.com/stretchr/testify/LICENSE
new file mode 100644
index 000000000..4b0421cf9
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go
new file mode 100644
index 000000000..ffb24e8e3
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go
@@ -0,0 +1,495 @@
+package assert
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"time"
+)
+
+// Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it.
+type CompareType = compareResult
+
+type compareResult int
+
+const (
+	compareLess compareResult = iota - 1
+	compareEqual
+	compareGreater
+)
+
+var (
+	intType   = reflect.TypeOf(int(1))
+	int8Type  = reflect.TypeOf(int8(1))
+	int16Type = reflect.TypeOf(int16(1))
+	int32Type = reflect.TypeOf(int32(1))
+	int64Type = reflect.TypeOf(int64(1))
+
+	uintType   = reflect.TypeOf(uint(1))
+	uint8Type  = reflect.TypeOf(uint8(1))
+	uint16Type = reflect.TypeOf(uint16(1))
+	uint32Type = reflect.TypeOf(uint32(1))
+	uint64Type = reflect.TypeOf(uint64(1))
+
+	uintptrType = reflect.TypeOf(uintptr(1))
+
+	float32Type = reflect.TypeOf(float32(1))
+	float64Type = reflect.TypeOf(float64(1))
+
+	stringType = reflect.TypeOf("")
+
+	timeType  = reflect.TypeOf(time.Time{})
+	bytesType = reflect.TypeOf([]byte{})
+)
+
+func compare(obj1, obj2 interface{}, kind reflect.Kind) (compareResult, bool) {
+	obj1Value := reflect.ValueOf(obj1)
+	obj2Value := reflect.ValueOf(obj2)
+
+	// throughout this switch we try and avoid calling .Convert() if possible,
+	// as this has a pretty big performance impact
+	switch kind {
+	case reflect.Int:
+		{
+			intobj1, ok := obj1.(int)
+			if !ok {
+				intobj1 = obj1Value.Convert(intType).Interface().(int)
+			}
+			intobj2, ok := obj2.(int)
+			if !ok {
+				intobj2 = obj2Value.Convert(intType).Interface().(int)
+			}
+			if intobj1 > intobj2 {
+				return compareGreater, true
+			}
+			if intobj1 == intobj2 {
+				return compareEqual, true
+			}
+			if intobj1 < intobj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Int8:
+		{
+			int8obj1, ok := obj1.(int8)
+			if !ok {
+				int8obj1 = obj1Value.Convert(int8Type).Interface().(int8)
+			}
+			int8obj2, ok := obj2.(int8)
+			if !ok {
+				int8obj2 = obj2Value.Convert(int8Type).Interface().(int8)
+			}
+			if int8obj1 > int8obj2 {
+				return compareGreater, true
+			}
+			if int8obj1 == int8obj2 {
+				return compareEqual, true
+			}
+			if int8obj1 < int8obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Int16:
+		{
+			int16obj1, ok := obj1.(int16)
+			if !ok {
+				int16obj1 = obj1Value.Convert(int16Type).Interface().(int16)
+			}
+			int16obj2, ok := obj2.(int16)
+			if !ok {
+				int16obj2 = obj2Value.Convert(int16Type).Interface().(int16)
+			}
+			if int16obj1 > int16obj2 {
+				return compareGreater, true
+			}
+			if int16obj1 == int16obj2 {
+				return compareEqual, true
+			}
+			if int16obj1 < int16obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Int32:
+		{
+			int32obj1, ok := obj1.(int32)
+			if !ok {
+				int32obj1 = obj1Value.Convert(int32Type).Interface().(int32)
+			}
+			int32obj2, ok := obj2.(int32)
+			if !ok {
+				int32obj2 = obj2Value.Convert(int32Type).Interface().(int32)
+			}
+			if int32obj1 > int32obj2 {
+				return compareGreater, true
+			}
+			if int32obj1 == int32obj2 {
+				return compareEqual, true
+			}
+			if int32obj1 < int32obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Int64:
+		{
+			int64obj1, ok := obj1.(int64)
+			if !ok {
+				int64obj1 = obj1Value.Convert(int64Type).Interface().(int64)
+			}
+			int64obj2, ok := obj2.(int64)
+			if !ok {
+				int64obj2 = obj2Value.Convert(int64Type).Interface().(int64)
+			}
+			if int64obj1 > int64obj2 {
+				return compareGreater, true
+			}
+			if int64obj1 == int64obj2 {
+				return compareEqual, true
+			}
+			if int64obj1 < int64obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Uint:
+		{
+			uintobj1, ok := obj1.(uint)
+			if !ok {
+				uintobj1 = obj1Value.Convert(uintType).Interface().(uint)
+			}
+			uintobj2, ok := obj2.(uint)
+			if !ok {
+				uintobj2 = obj2Value.Convert(uintType).Interface().(uint)
+			}
+			if uintobj1 > uintobj2 {
+				return compareGreater, true
+			}
+			if uintobj1 == uintobj2 {
+				return compareEqual, true
+			}
+			if uintobj1 < uintobj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Uint8:
+		{
+			uint8obj1, ok := obj1.(uint8)
+			if !ok {
+				uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8)
+			}
+			uint8obj2, ok := obj2.(uint8)
+			if !ok {
+				uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8)
+			}
+			if uint8obj1 > uint8obj2 {
+				return compareGreater, true
+			}
+			if uint8obj1 == uint8obj2 {
+				return compareEqual, true
+			}
+			if uint8obj1 < uint8obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Uint16:
+		{
+			uint16obj1, ok := obj1.(uint16)
+			if !ok {
+				uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16)
+			}
+			uint16obj2, ok := obj2.(uint16)
+			if !ok {
+				uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16)
+			}
+			if uint16obj1 > uint16obj2 {
+				return compareGreater, true
+			}
+			if uint16obj1 == uint16obj2 {
+				return compareEqual, true
+			}
+			if uint16obj1 < uint16obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Uint32:
+		{
+			uint32obj1, ok := obj1.(uint32)
+			if !ok {
+				uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32)
+			}
+			uint32obj2, ok := obj2.(uint32)
+			if !ok {
+				uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32)
+			}
+			if uint32obj1 > uint32obj2 {
+				return compareGreater, true
+			}
+			if uint32obj1 == uint32obj2 {
+				return compareEqual, true
+			}
+			if uint32obj1 < uint32obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Uint64:
+		{
+			uint64obj1, ok := obj1.(uint64)
+			if !ok {
+				uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64)
+			}
+			uint64obj2, ok := obj2.(uint64)
+			if !ok {
+				uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64)
+			}
+			if uint64obj1 > uint64obj2 {
+				return compareGreater, true
+			}
+			if uint64obj1 == uint64obj2 {
+				return compareEqual, true
+			}
+			if uint64obj1 < uint64obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Float32:
+		{
+			float32obj1, ok := obj1.(float32)
+			if !ok {
+				float32obj1 = obj1Value.Convert(float32Type).Interface().(float32)
+			}
+			float32obj2, ok := obj2.(float32)
+			if !ok {
+				float32obj2 = obj2Value.Convert(float32Type).Interface().(float32)
+			}
+			if float32obj1 > float32obj2 {
+				return compareGreater, true
+			}
+			if float32obj1 == float32obj2 {
+				return compareEqual, true
+			}
+			if float32obj1 < float32obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.Float64:
+		{
+			float64obj1, ok := obj1.(float64)
+			if !ok {
+				float64obj1 = obj1Value.Convert(float64Type).Interface().(float64)
+			}
+			float64obj2, ok := obj2.(float64)
+			if !ok {
+				float64obj2 = obj2Value.Convert(float64Type).Interface().(float64)
+			}
+			if float64obj1 > float64obj2 {
+				return compareGreater, true
+			}
+			if float64obj1 == float64obj2 {
+				return compareEqual, true
+			}
+			if float64obj1 < float64obj2 {
+				return compareLess, true
+			}
+		}
+	case reflect.String:
+		{
+			stringobj1, ok := obj1.(string)
+			if !ok {
+				stringobj1 = obj1Value.Convert(stringType).Interface().(string)
+			}
+			stringobj2, ok := obj2.(string)
+			if !ok {
+				stringobj2 = obj2Value.Convert(stringType).Interface().(string)
+			}
+			if stringobj1 > stringobj2 {
+				return compareGreater, true
+			}
+			if stringobj1 == stringobj2 {
+				return compareEqual, true
+			}
+			if stringobj1 < stringobj2 {
+				return compareLess, true
+			}
+		}
+	// Check for known struct types we can check for compare results.
+	case reflect.Struct:
+		{
+			// All structs enter here. We're not interested in most types.
+			if !obj1Value.CanConvert(timeType) {
+				break
+			}
+
+			// time.Time can be compared!
+			timeObj1, ok := obj1.(time.Time)
+			if !ok {
+				timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time)
+			}
+
+			timeObj2, ok := obj2.(time.Time)
+			if !ok {
+				timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time)
+			}
+
+			if timeObj1.Before(timeObj2) {
+				return compareLess, true
+			}
+			if timeObj1.Equal(timeObj2) {
+				return compareEqual, true
+			}
+			return compareGreater, true
+		}
+	case reflect.Slice:
+		{
+			// We only care about the []byte type.
+			if !obj1Value.CanConvert(bytesType) {
+				break
+			}
+
+			// []byte can be compared!
+			bytesObj1, ok := obj1.([]byte)
+			if !ok {
+				bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte)
+
+			}
+			bytesObj2, ok := obj2.([]byte)
+			if !ok {
+				bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte)
+			}
+
+			return compareResult(bytes.Compare(bytesObj1, bytesObj2)), true
+		}
+	case reflect.Uintptr:
+		{
+			uintptrObj1, ok := obj1.(uintptr)
+			if !ok {
+				uintptrObj1 = obj1Value.Convert(uintptrType).Interface().(uintptr)
+			}
+			uintptrObj2, ok := obj2.(uintptr)
+			if !ok {
+				uintptrObj2 = obj2Value.Convert(uintptrType).Interface().(uintptr)
+			}
+			if uintptrObj1 > uintptrObj2 {
+				return compareGreater, true
+			}
+			if uintptrObj1 == uintptrObj2 {
+				return compareEqual, true
+			}
+			if uintptrObj1 < uintptrObj2 {
+				return compareLess, true
+			}
+		}
+	}
+
+	return compareEqual, false
+}
+
+// Greater asserts that the first element is greater than the second
+//
+//	assert.Greater(t, 2, 1)
+//	assert.Greater(t, float64(2), float64(1))
+//	assert.Greater(t, "b", "a")
+func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	failMessage := fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2)
+	return compareTwoValues(t, e1, e2, []compareResult{compareGreater}, failMessage, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+//	assert.GreaterOrEqual(t, 2, 1)
+//	assert.GreaterOrEqual(t, 2, 2)
+//	assert.GreaterOrEqual(t, "b", "a")
+//	assert.GreaterOrEqual(t, "b", "b")
+func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	failMessage := fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2)
+	return compareTwoValues(t, e1, e2, []compareResult{compareGreater, compareEqual}, failMessage, msgAndArgs...)
+}
+
+// Less asserts that the first element is less than the second
+//
+//	assert.Less(t, 1, 2)
+//	assert.Less(t, float64(1), float64(2))
+//	assert.Less(t, "a", "b")
+func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	failMessage := fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2)
+	return compareTwoValues(t, e1, e2, []compareResult{compareLess}, failMessage, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+//	assert.LessOrEqual(t, 1, 2)
+//	assert.LessOrEqual(t, 2, 2)
+//	assert.LessOrEqual(t, "a", "b")
+//	assert.LessOrEqual(t, "b", "b")
+func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	failMessage := fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2)
+	return compareTwoValues(t, e1, e2, []compareResult{compareLess, compareEqual}, failMessage, msgAndArgs...)
+}
+
+// Positive asserts that the specified element is positive
+//
+//	assert.Positive(t, 1)
+//	assert.Positive(t, 1.23)
+func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	zero := reflect.Zero(reflect.TypeOf(e))
+	failMessage := fmt.Sprintf("\"%v\" is not positive", e)
+	return compareTwoValues(t, e, zero.Interface(), []compareResult{compareGreater}, failMessage, msgAndArgs...)
+}
+
+// Negative asserts that the specified element is negative
+//
+//	assert.Negative(t, -1)
+//	assert.Negative(t, -1.23)
+func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	zero := reflect.Zero(reflect.TypeOf(e))
+	failMessage := fmt.Sprintf("\"%v\" is not negative", e)
+	return compareTwoValues(t, e, zero.Interface(), []compareResult{compareLess}, failMessage, msgAndArgs...)
+}
+
+func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	e1Kind := reflect.ValueOf(e1).Kind()
+	e2Kind := reflect.ValueOf(e2).Kind()
+	if e1Kind != e2Kind {
+		return Fail(t, "Elements should be the same type", msgAndArgs...)
+	}
+
+	compareResult, isComparable := compare(e1, e2, e1Kind)
+	if !isComparable {
+		return Fail(t, fmt.Sprintf(`Can not compare type "%T"`, e1), msgAndArgs...)
+	}
+
+	if !containsValue(allowedComparesResults, compareResult) {
+		return Fail(t, failMessage, msgAndArgs...)
+	}
+
+	return true
+}
+
+func containsValue(values []compareResult, value compareResult) bool {
+	for _, v := range values {
+		if v == value {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go
new file mode 100644
index 000000000..c592f6ad5
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go
@@ -0,0 +1,866 @@
+// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
+
+package assert
+
+import (
+	http "net/http"
+	url "net/url"
+	time "time"
+)
+
+// Conditionf uses a Comparison to assert a complex condition.
+func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Condition(t, comp, append([]interface{}{msg}, args...)...)
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//	assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
+//	assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
+//	assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
+func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return DirExists(t, path, append([]interface{}{msg}, args...)...)
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
+}
+
+// Emptyf asserts that the given value is "empty".
+//
+// [Zero values] are "empty".
+//
+// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
+//
+// Slices, maps and channels with zero length are "empty".
+//
+// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
+//
+//	assert.Emptyf(t, obj, "error message %s", "formatted")
+//
+// [Zero values]: https://go.dev/ref/spec#The_zero_value
+func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Empty(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// Equalf asserts that two objects are equal.
+//
+//	assert.Equalf(t, 123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//	actualObj, err := SomeFunction()
+//	assert.EqualErrorf(t, err,  expectedErrorString, "error message %s", "formatted")
+func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
+}
+
+// EqualExportedValuesf asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+//	 type S struct {
+//		Exported     	int
+//		notExported   	int
+//	 }
+//	 assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
+//	 assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
+func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// EqualValuesf asserts that two objects are equal or convertible to the larger
+// type and equal.
+//
+//	assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
+func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+//	actualObj, err := SomeFunction()
+//	assert.Errorf(t, err, "error message %s", "formatted")
+func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Error(t, err, append([]interface{}{msg}, args...)...)
+}
+
+// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...)
+}
+
+// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+//	actualObj, err := SomeFunction()
+//	assert.ErrorContainsf(t, err,  expectedErrorSubString, "error message %s", "formatted")
+func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorContains(t, theError, contains, append([]interface{}{msg}, args...)...)
+}
+
+// ErrorIsf asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorIs(t, err, target, append([]interface{}{msg}, args...)...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//	assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
+}
+
+// EventuallyWithTf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+//	externalValue := false
+//	go func() {
+//		time.Sleep(8*time.Second)
+//		externalValue = true
+//	}()
+//	assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
+//		// add assertions as needed; any assertion failure will fail the current tick
+//		assert.True(c, externalValue, "expected 'externalValue' to be true")
+//	}, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
+func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return EventuallyWithT(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+//	assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
+func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Failf reports a failure through
+func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
+}
+
+// FailNowf fails test
+func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
+}
+
+// Falsef asserts that the specified value is false.
+//
+//	assert.Falsef(t, myBool, "error message %s", "formatted")
+func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return False(t, value, append([]interface{}{msg}, args...)...)
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return FileExists(t, path, append([]interface{}{msg}, args...)...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+//	assert.Greaterf(t, 2, 1, "error message %s", "formatted")
+//	assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
+//	assert.Greaterf(t, "b", "a", "error message %s", "formatted")
+func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Greater(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+//	assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
+//	assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
+//	assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
+//	assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
+func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+//	assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//	assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+//	assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+//	assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPStatusCodef asserts that a specified handler returns a specified status code.
+//
+//	assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...)
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+//	assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+//	assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+//	assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
+func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
+}
+
+// IsDecreasingf asserts that the collection is decreasing
+//
+//	assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted")
+//	assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted")
+//	assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
+func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsDecreasing(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// IsIncreasingf asserts that the collection is increasing
+//
+//	assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted")
+//	assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted")
+//	assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
+func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsIncreasing(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// IsNonDecreasingf asserts that the collection is not decreasing
+//
+//	assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted")
+//	assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted")
+//	assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
+func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNonDecreasing(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// IsNonIncreasingf asserts that the collection is not increasing
+//
+//	assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted")
+//	assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted")
+//	assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
+func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// IsNotTypef asserts that the specified objects are not of the same type.
+//
+//	assert.IsNotTypef(t, &NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
+func IsNotTypef(t TestingT, theType interface{}, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNotType(t, theType, object, append([]interface{}{msg}, args...)...)
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+//
+//	assert.IsTypef(t, &MyStruct{}, &MyStruct{}, "error message %s", "formatted")
+func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+//	assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+//	assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
+func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Len(t, object, length, append([]interface{}{msg}, args...)...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+//	assert.Lessf(t, 1, 2, "error message %s", "formatted")
+//	assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
+//	assert.Lessf(t, "a", "b", "error message %s", "formatted")
+func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Less(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+//	assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
+//	assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
+//	assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
+//	assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
+func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
+}
+
+// Negativef asserts that the specified element is negative
+//
+//	assert.Negativef(t, -1, "error message %s", "formatted")
+//	assert.Negativef(t, -1.23, "error message %s", "formatted")
+func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Negative(t, e, append([]interface{}{msg}, args...)...)
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//	assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
+}
+
+// Nilf asserts that the specified object is nil.
+//
+//	assert.Nilf(t, err, "error message %s", "formatted")
+func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Nil(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// NoDirExistsf checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoDirExists(t, path, append([]interface{}{msg}, args...)...)
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+//	  actualObj, err := SomeFunction()
+//	  if assert.NoErrorf(t, err, "error message %s", "formatted") {
+//		   assert.Equal(t, expectedObj, actualObj)
+//	  }
+func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoError(t, err, append([]interface{}{msg}, args...)...)
+}
+
+// NoFileExistsf checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoFileExists(t, path, append([]interface{}{msg}, args...)...)
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//	assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
+//	assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
+//	assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
+func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
+}
+
+// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should not match.
+// This is an inverse of ElementsMatch.
+//
+// assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
+//
+// assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
+//
+// assert.NotElementsMatchf(t, [1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
+func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
+}
+
+// NotEmptyf asserts that the specified object is NOT [Empty].
+//
+//	if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
+//	  assert.Equal(t, "two", obj[1])
+//	}
+func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+//	assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
+//
+//	assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
+func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// NotErrorAsf asserts that none of the errors in err's chain matches target,
+// but if so, sets target to that error value.
+func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotErrorAs(t, err, target, append([]interface{}{msg}, args...)...)
+}
+
+// NotErrorIsf asserts that none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...)
+}
+
+// NotImplementsf asserts that an object does not implement the specified interface.
+//
+//	assert.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotImplements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+//	assert.NotNilf(t, err, "error message %s", "formatted")
+func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotNil(t, object, append([]interface{}{msg}, args...)...)
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//	assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
+func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotPanics(t, f, append([]interface{}{msg}, args...)...)
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+//	assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
+//	assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
+func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
+}
+
+// NotSamef asserts that two pointers do not reference the same object.
+//
+//	assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
+// elements given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted")
+//	assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
+//	assert.NotSubsetf(t, [1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
+//	assert.NotSubsetf(t, {"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
+func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotZero(t, i, append([]interface{}{msg}, args...)...)
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+//	assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
+func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Panics(t, f, append([]interface{}{msg}, args...)...)
+}
+
+// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+//	assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...)
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//	assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
+}
+
+// Positivef asserts that the specified element is positive
+//
+//	assert.Positivef(t, 1, "error message %s", "formatted")
+//	assert.Positivef(t, 1.23, "error message %s", "formatted")
+func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Positive(t, e, append([]interface{}{msg}, args...)...)
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+//	assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
+//	assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
+func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+//	assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Subsetf asserts that the list (array, slice, or map) contains all elements
+// given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted")
+//	assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
+//	assert.Subsetf(t, [1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
+//	assert.Subsetf(t, {"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
+func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
+}
+
+// Truef asserts that the specified value is true.
+//
+//	assert.Truef(t, myBool, "error message %s", "formatted")
+func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return True(t, value, append([]interface{}{msg}, args...)...)
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+//	assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
+}
+
+// WithinRangef asserts that a time is within a time range (inclusive).
+//
+//	assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
+func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return WithinRange(t, actual, start, end, append([]interface{}{msg}, args...)...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
+}
+
+// Zerof asserts that i is the zero value for its type.
+func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Zero(t, i, append([]interface{}{msg}, args...)...)
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
new file mode 100644
index 000000000..d2bb0b817
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
@@ -0,0 +1,5 @@
+{{.CommentFormat}}
+func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
+	if h, ok := t.(tHelper); ok { h.Helper() }
+	return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
new file mode 100644
index 000000000..58db92845
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go
@@ -0,0 +1,1723 @@
+// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
+
+package assert
+
+import (
+	http "net/http"
+	url "net/url"
+	time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Condition(a.t, comp, msgAndArgs...)
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Conditionf(a.t, comp, msg, args...)
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//	a.Contains("Hello World", "World")
+//	a.Contains(["Hello", "World"], "World")
+//	a.Contains({"Hello": "World"}, "Hello")
+func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Contains(a.t, s, contains, msgAndArgs...)
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//	a.Containsf("Hello World", "World", "error message %s", "formatted")
+//	a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
+//	a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
+func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Containsf(a.t, s, contains, msg, args...)
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return DirExists(a.t, path, msgAndArgs...)
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return DirExistsf(a.t, path, msg, args...)
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
+func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return ElementsMatch(a.t, listA, listB, msgAndArgs...)
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return ElementsMatchf(a.t, listA, listB, msg, args...)
+}
+
+// Empty asserts that the given value is "empty".
+//
+// [Zero values] are "empty".
+//
+// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
+//
+// Slices, maps and channels with zero length are "empty".
+//
+// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
+//
+//	a.Empty(obj)
+//
+// [Zero values]: https://go.dev/ref/spec#The_zero_value
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Empty(a.t, object, msgAndArgs...)
+}
+
+// Emptyf asserts that the given value is "empty".
+//
+// [Zero values] are "empty".
+//
+// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
+//
+// Slices, maps and channels with zero length are "empty".
+//
+// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
+//
+//	a.Emptyf(obj, "error message %s", "formatted")
+//
+// [Zero values]: https://go.dev/ref/spec#The_zero_value
+func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Emptyf(a.t, object, msg, args...)
+}
+
+// Equal asserts that two objects are equal.
+//
+//	a.Equal(123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//	actualObj, err := SomeFunction()
+//	a.EqualError(err,  expectedErrorString)
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//	actualObj, err := SomeFunction()
+//	a.EqualErrorf(err,  expectedErrorString, "error message %s", "formatted")
+func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualErrorf(a.t, theError, errString, msg, args...)
+}
+
+// EqualExportedValues asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+//	 type S struct {
+//		Exported     	int
+//		notExported   	int
+//	 }
+//	 a.EqualExportedValues(S{1, 2}, S{1, 3}) => true
+//	 a.EqualExportedValues(S{1, 2}, S{2, 3}) => false
+func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualExportedValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualExportedValuesf asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+//	 type S struct {
+//		Exported     	int
+//		notExported   	int
+//	 }
+//	 a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
+//	 a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
+func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualExportedValuesf(a.t, expected, actual, msg, args...)
+}
+
+// EqualValues asserts that two objects are equal or convertible to the larger
+// type and equal.
+//
+//	a.EqualValues(uint32(123), int32(123))
+func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualValuesf asserts that two objects are equal or convertible to the larger
+// type and equal.
+//
+//	a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
+func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return EqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// Equalf asserts that two objects are equal.
+//
+//	a.Equalf(123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Equalf(a.t, expected, actual, msg, args...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//	actualObj, err := SomeFunction()
+//	a.Error(err)
+func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Error(a.t, err, msgAndArgs...)
+}
+
+// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorAs(a.t, err, target, msgAndArgs...)
+}
+
+// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorAsf(a.t, err, target, msg, args...)
+}
+
+// ErrorContains asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+//	actualObj, err := SomeFunction()
+//	a.ErrorContains(err,  expectedErrorSubString)
+func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorContains(a.t, theError, contains, msgAndArgs...)
+}
+
+// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+//	actualObj, err := SomeFunction()
+//	a.ErrorContainsf(err,  expectedErrorSubString, "error message %s", "formatted")
+func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorContainsf(a.t, theError, contains, msg, args...)
+}
+
+// ErrorIs asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorIs(a.t, err, target, msgAndArgs...)
+}
+
+// ErrorIsf asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return ErrorIsf(a.t, err, target, msg, args...)
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+//	actualObj, err := SomeFunction()
+//	a.Errorf(err, "error message %s", "formatted")
+func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Errorf(a.t, err, msg, args...)
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//	a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// EventuallyWithT asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+//	externalValue := false
+//	go func() {
+//		time.Sleep(8*time.Second)
+//		externalValue = true
+//	}()
+//	a.EventuallyWithT(func(c *assert.CollectT) {
+//		// add assertions as needed; any assertion failure will fail the current tick
+//		assert.True(c, externalValue, "expected 'externalValue' to be true")
+//	}, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
+func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// EventuallyWithTf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+//	externalValue := false
+//	go func() {
+//		time.Sleep(8*time.Second)
+//		externalValue = true
+//	}()
+//	a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
+//		// add assertions as needed; any assertion failure will fail the current tick
+//		assert.True(c, externalValue, "expected 'externalValue' to be true")
+//	}, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
+func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//	a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+//	a.Exactly(int32(123), int64(123))
+func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+//	a.Exactlyf(int32(123), int64(123), "error message %s", "formatted")
+func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Exactlyf(a.t, expected, actual, msg, args...)
+}
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNow fails test
+func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return FailNow(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNowf fails test
+func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return FailNowf(a.t, failureMessage, msg, args...)
+}
+
+// Failf reports a failure through
+func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Failf(a.t, failureMessage, msg, args...)
+}
+
+// False asserts that the specified value is false.
+//
+//	a.False(myBool)
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return False(a.t, value, msgAndArgs...)
+}
+
+// Falsef asserts that the specified value is false.
+//
+//	a.Falsef(myBool, "error message %s", "formatted")
+func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Falsef(a.t, value, msg, args...)
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return FileExists(a.t, path, msgAndArgs...)
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return FileExistsf(a.t, path, msg, args...)
+}
+
+// Greater asserts that the first element is greater than the second
+//
+//	a.Greater(2, 1)
+//	a.Greater(float64(2), float64(1))
+//	a.Greater("b", "a")
+func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Greater(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+//	a.GreaterOrEqual(2, 1)
+//	a.GreaterOrEqual(2, 2)
+//	a.GreaterOrEqual("b", "a")
+//	a.GreaterOrEqual("b", "b")
+func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+//	a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
+//	a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
+//	a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
+//	a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return GreaterOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+//	a.Greaterf(2, 1, "error message %s", "formatted")
+//	a.Greaterf(float64(2), float64(1), "error message %s", "formatted")
+//	a.Greaterf("b", "a", "error message %s", "formatted")
+func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Greaterf(a.t, e1, e2, msg, args...)
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//	a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+//	a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//	a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//	a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//	a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPError(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+//	a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPErrorf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//	a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+//	a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPStatusCode asserts that a specified handler returns a specified status code.
+//
+//	a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...)
+}
+
+// HTTPStatusCodef asserts that a specified handler returns a specified status code.
+//
+//	a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...)
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//	a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+//	a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//	a.Implements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+//	a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Implementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+//	a.InDelta(math.Pi, 22/7.0, 0.01)
+func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+//	a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
+func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InDeltaf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// IsDecreasing asserts that the collection is decreasing
+//
+//	a.IsDecreasing([]int{2, 1, 0})
+//	a.IsDecreasing([]float{2, 1})
+//	a.IsDecreasing([]string{"b", "a"})
+func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsDecreasing(a.t, object, msgAndArgs...)
+}
+
+// IsDecreasingf asserts that the collection is decreasing
+//
+//	a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted")
+//	a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted")
+//	a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted")
+func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsDecreasingf(a.t, object, msg, args...)
+}
+
+// IsIncreasing asserts that the collection is increasing
+//
+//	a.IsIncreasing([]int{1, 2, 3})
+//	a.IsIncreasing([]float{1, 2})
+//	a.IsIncreasing([]string{"a", "b"})
+func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsIncreasing(a.t, object, msgAndArgs...)
+}
+
+// IsIncreasingf asserts that the collection is increasing
+//
+//	a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted")
+//	a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted")
+//	a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted")
+func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsIncreasingf(a.t, object, msg, args...)
+}
+
+// IsNonDecreasing asserts that the collection is not decreasing
+//
+//	a.IsNonDecreasing([]int{1, 1, 2})
+//	a.IsNonDecreasing([]float{1, 2})
+//	a.IsNonDecreasing([]string{"a", "b"})
+func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNonDecreasing(a.t, object, msgAndArgs...)
+}
+
+// IsNonDecreasingf asserts that the collection is not decreasing
+//
+//	a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted")
+//	a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted")
+//	a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted")
+func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNonDecreasingf(a.t, object, msg, args...)
+}
+
+// IsNonIncreasing asserts that the collection is not increasing
+//
+//	a.IsNonIncreasing([]int{2, 1, 1})
+//	a.IsNonIncreasing([]float{2, 1})
+//	a.IsNonIncreasing([]string{"b", "a"})
+func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNonIncreasing(a.t, object, msgAndArgs...)
+}
+
+// IsNonIncreasingf asserts that the collection is not increasing
+//
+//	a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted")
+//	a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted")
+//	a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted")
+func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNonIncreasingf(a.t, object, msg, args...)
+}
+
+// IsNotType asserts that the specified objects are not of the same type.
+//
+//	a.IsNotType(&NotMyStruct{}, &MyStruct{})
+func (a *Assertions) IsNotType(theType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNotType(a.t, theType, object, msgAndArgs...)
+}
+
+// IsNotTypef asserts that the specified objects are not of the same type.
+//
+//	a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
+func (a *Assertions) IsNotTypef(theType interface{}, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsNotTypef(a.t, theType, object, msg, args...)
+}
+
+// IsType asserts that the specified objects are of the same type.
+//
+//	a.IsType(&MyStruct{}, &MyStruct{})
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+//
+//	a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted")
+func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return IsTypef(a.t, expectedType, object, msg, args...)
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//	a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return JSONEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+//	a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return JSONEqf(a.t, expected, actual, msg, args...)
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//	a.Len(mySlice, 3)
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Len(a.t, object, length, msgAndArgs...)
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+//	a.Lenf(mySlice, 3, "error message %s", "formatted")
+func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Lenf(a.t, object, length, msg, args...)
+}
+
+// Less asserts that the first element is less than the second
+//
+//	a.Less(1, 2)
+//	a.Less(float64(1), float64(2))
+//	a.Less("a", "b")
+func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Less(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+//	a.LessOrEqual(1, 2)
+//	a.LessOrEqual(2, 2)
+//	a.LessOrEqual("a", "b")
+//	a.LessOrEqual("b", "b")
+func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return LessOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+//	a.LessOrEqualf(1, 2, "error message %s", "formatted")
+//	a.LessOrEqualf(2, 2, "error message %s", "formatted")
+//	a.LessOrEqualf("a", "b", "error message %s", "formatted")
+//	a.LessOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return LessOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+//	a.Lessf(1, 2, "error message %s", "formatted")
+//	a.Lessf(float64(1), float64(2), "error message %s", "formatted")
+//	a.Lessf("a", "b", "error message %s", "formatted")
+func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Lessf(a.t, e1, e2, msg, args...)
+}
+
+// Negative asserts that the specified element is negative
+//
+//	a.Negative(-1)
+//	a.Negative(-1.23)
+func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Negative(a.t, e, msgAndArgs...)
+}
+
+// Negativef asserts that the specified element is negative
+//
+//	a.Negativef(-1, "error message %s", "formatted")
+//	a.Negativef(-1.23, "error message %s", "formatted")
+func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Negativef(a.t, e, msg, args...)
+}
+
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//	a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Never(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//	a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Neverf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Nil asserts that the specified object is nil.
+//
+//	a.Nil(err)
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Nil(a.t, object, msgAndArgs...)
+}
+
+// Nilf asserts that the specified object is nil.
+//
+//	a.Nilf(err, "error message %s", "formatted")
+func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Nilf(a.t, object, msg, args...)
+}
+
+// NoDirExists checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoDirExists(a.t, path, msgAndArgs...)
+}
+
+// NoDirExistsf checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoDirExistsf(a.t, path, msg, args...)
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//	  actualObj, err := SomeFunction()
+//	  if a.NoError(err) {
+//		   assert.Equal(t, expectedObj, actualObj)
+//	  }
+func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoError(a.t, err, msgAndArgs...)
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+//	  actualObj, err := SomeFunction()
+//	  if a.NoErrorf(err, "error message %s", "formatted") {
+//		   assert.Equal(t, expectedObj, actualObj)
+//	  }
+func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoErrorf(a.t, err, msg, args...)
+}
+
+// NoFileExists checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoFileExists(a.t, path, msgAndArgs...)
+}
+
+// NoFileExistsf checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NoFileExistsf(a.t, path, msg, args...)
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//	a.NotContains("Hello World", "Earth")
+//	a.NotContains(["Hello", "World"], "Earth")
+//	a.NotContains({"Hello": "World"}, "Earth")
+func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//	a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
+//	a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
+//	a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
+func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotContainsf(a.t, s, contains, msg, args...)
+}
+
+// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should not match.
+// This is an inverse of ElementsMatch.
+//
+// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false
+//
+// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true
+//
+// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true
+func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotElementsMatch(a.t, listA, listB, msgAndArgs...)
+}
+
+// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should not match.
+// This is an inverse of ElementsMatch.
+//
+// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
+//
+// a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
+//
+// a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
+func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotElementsMatchf(a.t, listA, listB, msg, args...)
+}
+
+// NotEmpty asserts that the specified object is NOT [Empty].
+//
+//	if a.NotEmpty(obj) {
+//	  assert.Equal(t, "two", obj[1])
+//	}
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEmpty(a.t, object, msgAndArgs...)
+}
+
+// NotEmptyf asserts that the specified object is NOT [Empty].
+//
+//	if a.NotEmptyf(obj, "error message %s", "formatted") {
+//	  assert.Equal(t, "two", obj[1])
+//	}
+func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEmptyf(a.t, object, msg, args...)
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//	a.NotEqual(obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualValues asserts that two objects are not equal even when converted to the same type
+//
+//	a.NotEqualValues(obj1, obj2)
+func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
+//
+//	a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted")
+func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+//	a.NotEqualf(obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotEqualf(a.t, expected, actual, msg, args...)
+}
+
+// NotErrorAs asserts that none of the errors in err's chain matches target,
+// but if so, sets target to that error value.
+func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotErrorAs(a.t, err, target, msgAndArgs...)
+}
+
+// NotErrorAsf asserts that none of the errors in err's chain matches target,
+// but if so, sets target to that error value.
+func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotErrorAsf(a.t, err, target, msg, args...)
+}
+
+// NotErrorIs asserts that none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotErrorIs(a.t, err, target, msgAndArgs...)
+}
+
+// NotErrorIsf asserts that none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotErrorIsf(a.t, err, target, msg, args...)
+}
+
+// NotImplements asserts that an object does not implement the specified interface.
+//
+//	a.NotImplements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotImplements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// NotImplementsf asserts that an object does not implement the specified interface.
+//
+//	a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotImplementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//	a.NotNil(err)
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotNil(a.t, object, msgAndArgs...)
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+//	a.NotNilf(err, "error message %s", "formatted")
+func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotNilf(a.t, object, msg, args...)
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//	a.NotPanics(func(){ RemainCalm() })
+func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotPanics(a.t, f, msgAndArgs...)
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//	a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
+func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotPanicsf(a.t, f, msg, args...)
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//	a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
+//	a.NotRegexp("^start", "it's not starting")
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotRegexp(a.t, rx, str, msgAndArgs...)
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+//	a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
+//	a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotRegexpf(a.t, rx, str, msg, args...)
+}
+
+// NotSame asserts that two pointers do not reference the same object.
+//
+//	a.NotSame(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotSame(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotSamef asserts that two pointers do not reference the same object.
+//
+//	a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotSamef(a.t, expected, actual, msg, args...)
+}
+
+// NotSubset asserts that the list (array, slice, or map) does NOT contain all
+// elements given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	a.NotSubset([1, 3, 4], [1, 2])
+//	a.NotSubset({"x": 1, "y": 2}, {"z": 3})
+//	a.NotSubset([1, 3, 4], {1: "one", 2: "two"})
+//	a.NotSubset({"x": 1, "y": 2}, ["z"])
+func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotSubset(a.t, list, subset, msgAndArgs...)
+}
+
+// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
+// elements given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
+//	a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
+//	a.NotSubsetf([1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
+//	a.NotSubsetf({"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
+func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotSubsetf(a.t, list, subset, msg, args...)
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotZero(a.t, i, msgAndArgs...)
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return NotZerof(a.t, i, msg, args...)
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//	a.Panics(func(){ GoCrazy() })
+func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Panics(a.t, f, msgAndArgs...)
+}
+
+// PanicsWithError asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+//	a.PanicsWithError("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return PanicsWithError(a.t, errString, f, msgAndArgs...)
+}
+
+// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+//	a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return PanicsWithErrorf(a.t, errString, f, msg, args...)
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//	a.PanicsWithValue("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return PanicsWithValue(a.t, expected, f, msgAndArgs...)
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//	a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return PanicsWithValuef(a.t, expected, f, msg, args...)
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+//	a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Panicsf(a.t, f, msg, args...)
+}
+
+// Positive asserts that the specified element is positive
+//
+//	a.Positive(1)
+//	a.Positive(1.23)
+func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Positive(a.t, e, msgAndArgs...)
+}
+
+// Positivef asserts that the specified element is positive
+//
+//	a.Positivef(1, "error message %s", "formatted")
+//	a.Positivef(1.23, "error message %s", "formatted")
+func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Positivef(a.t, e, msg, args...)
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//	a.Regexp(regexp.MustCompile("start"), "it's starting")
+//	a.Regexp("start...$", "it's not starting")
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+//	a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
+//	a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Regexpf(a.t, rx, str, msg, args...)
+}
+
+// Same asserts that two pointers reference the same object.
+//
+//	a.Same(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Same(a.t, expected, actual, msgAndArgs...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+//	a.Samef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Samef(a.t, expected, actual, msg, args...)
+}
+
+// Subset asserts that the list (array, slice, or map) contains all elements
+// given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	a.Subset([1, 2, 3], [1, 2])
+//	a.Subset({"x": 1, "y": 2}, {"x": 1})
+//	a.Subset([1, 2, 3], {1: "one", 2: "two"})
+//	a.Subset({"x": 1, "y": 2}, ["x"])
+func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Subset(a.t, list, subset, msgAndArgs...)
+}
+
+// Subsetf asserts that the list (array, slice, or map) contains all elements
+// given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
+//	a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
+//	a.Subsetf([1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
+//	a.Subsetf({"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
+func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Subsetf(a.t, list, subset, msg, args...)
+}
+
+// True asserts that the specified value is true.
+//
+//	a.True(myBool)
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return True(a.t, value, msgAndArgs...)
+}
+
+// Truef asserts that the specified value is true.
+//
+//	a.Truef(myBool, "error message %s", "formatted")
+func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Truef(a.t, value, msg, args...)
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//	a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
+func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+//	a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return WithinDurationf(a.t, expected, actual, delta, msg, args...)
+}
+
+// WithinRange asserts that a time is within a time range (inclusive).
+//
+//	a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
+func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return WithinRange(a.t, actual, start, end, msgAndArgs...)
+}
+
+// WithinRangef asserts that a time is within a time range (inclusive).
+//
+//	a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
+func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return WithinRangef(a.t, actual, start, end, msg, args...)
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return YAMLEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return YAMLEqf(a.t, expected, actual, msg, args...)
+}
+
+// Zero asserts that i is the zero value for its type.
+func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Zero(a.t, i, msgAndArgs...)
+}
+
+// Zerof asserts that i is the zero value for its type.
+func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	return Zerof(a.t, i, msg, args...)
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
new file mode 100644
index 000000000..188bb9e17
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
@@ -0,0 +1,5 @@
+{{.CommentWithoutT "a"}}
+func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
+	if h, ok := a.t.(tHelper); ok { h.Helper() }
+	return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go
new file mode 100644
index 000000000..2fdf80fdd
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go
@@ -0,0 +1,81 @@
+package assert
+
+import (
+	"fmt"
+	"reflect"
+)
+
+// isOrdered checks that collection contains orderable elements.
+func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
+	objKind := reflect.TypeOf(object).Kind()
+	if objKind != reflect.Slice && objKind != reflect.Array {
+		return false
+	}
+
+	objValue := reflect.ValueOf(object)
+	objLen := objValue.Len()
+
+	if objLen <= 1 {
+		return true
+	}
+
+	value := objValue.Index(0)
+	valueInterface := value.Interface()
+	firstValueKind := value.Kind()
+
+	for i := 1; i < objLen; i++ {
+		prevValue := value
+		prevValueInterface := valueInterface
+
+		value = objValue.Index(i)
+		valueInterface = value.Interface()
+
+		compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind)
+
+		if !isComparable {
+			return Fail(t, fmt.Sprintf(`Can not compare type "%T" and "%T"`, value, prevValue), msgAndArgs...)
+		}
+
+		if !containsValue(allowedComparesResults, compareResult) {
+			return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...)
+		}
+	}
+
+	return true
+}
+
+// IsIncreasing asserts that the collection is increasing
+//
+//	assert.IsIncreasing(t, []int{1, 2, 3})
+//	assert.IsIncreasing(t, []float{1, 2})
+//	assert.IsIncreasing(t, []string{"a", "b"})
+func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
+}
+
+// IsNonIncreasing asserts that the collection is not increasing
+//
+//	assert.IsNonIncreasing(t, []int{2, 1, 1})
+//	assert.IsNonIncreasing(t, []float{2, 1})
+//	assert.IsNonIncreasing(t, []string{"b", "a"})
+func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	return isOrdered(t, object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...)
+}
+
+// IsDecreasing asserts that the collection is decreasing
+//
+//	assert.IsDecreasing(t, []int{2, 1, 0})
+//	assert.IsDecreasing(t, []float{2, 1})
+//	assert.IsDecreasing(t, []string{"b", "a"})
+func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
+}
+
+// IsNonDecreasing asserts that the collection is not decreasing
+//
+//	assert.IsNonDecreasing(t, []int{1, 1, 2})
+//	assert.IsNonDecreasing(t, []float{1, 2})
+//	assert.IsNonDecreasing(t, []string{"a", "b"})
+func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
+}
diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go
new file mode 100644
index 000000000..de8de0cb6
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/assertions.go
@@ -0,0 +1,2295 @@
+package assert
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"math"
+	"os"
+	"reflect"
+	"regexp"
+	"runtime"
+	"runtime/debug"
+	"strings"
+	"time"
+	"unicode"
+	"unicode/utf8"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/pmezard/go-difflib/difflib"
+
+	// Wrapper around gopkg.in/yaml.v3
+	"github.com/stretchr/testify/assert/yaml"
+)
+
+//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+	Errorf(format string, args ...interface{})
+}
+
+// ComparisonAssertionFunc is a common function prototype when comparing two values.  Can be useful
+// for table driven tests.
+type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
+
+// ValueAssertionFunc is a common function prototype when validating a single value.  Can be useful
+// for table driven tests.
+type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
+
+// BoolAssertionFunc is a common function prototype when validating a bool value.  Can be useful
+// for table driven tests.
+type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
+
+// ErrorAssertionFunc is a common function prototype when validating an error value.  Can be useful
+// for table driven tests.
+type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
+
+// PanicAssertionFunc is a common function prototype when validating a panic value.  Can be useful
+// for table driven tests.
+type PanicAssertionFunc = func(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool
+
+// Comparison is a custom function that returns true on success and false on failure
+type Comparison func() (success bool)
+
+/*
+	Helper functions
+*/
+
+// ObjectsAreEqual determines if two objects are considered equal.
+//
+// This function does no assertion of any kind.
+func ObjectsAreEqual(expected, actual interface{}) bool {
+	if expected == nil || actual == nil {
+		return expected == actual
+	}
+
+	exp, ok := expected.([]byte)
+	if !ok {
+		return reflect.DeepEqual(expected, actual)
+	}
+
+	act, ok := actual.([]byte)
+	if !ok {
+		return false
+	}
+	if exp == nil || act == nil {
+		return exp == nil && act == nil
+	}
+	return bytes.Equal(exp, act)
+}
+
+// copyExportedFields iterates downward through nested data structures and creates a copy
+// that only contains the exported struct fields.
+func copyExportedFields(expected interface{}) interface{} {
+	if isNil(expected) {
+		return expected
+	}
+
+	expectedType := reflect.TypeOf(expected)
+	expectedKind := expectedType.Kind()
+	expectedValue := reflect.ValueOf(expected)
+
+	switch expectedKind {
+	case reflect.Struct:
+		result := reflect.New(expectedType).Elem()
+		for i := 0; i < expectedType.NumField(); i++ {
+			field := expectedType.Field(i)
+			isExported := field.IsExported()
+			if isExported {
+				fieldValue := expectedValue.Field(i)
+				if isNil(fieldValue) || isNil(fieldValue.Interface()) {
+					continue
+				}
+				newValue := copyExportedFields(fieldValue.Interface())
+				result.Field(i).Set(reflect.ValueOf(newValue))
+			}
+		}
+		return result.Interface()
+
+	case reflect.Ptr:
+		result := reflect.New(expectedType.Elem())
+		unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface())
+		result.Elem().Set(reflect.ValueOf(unexportedRemoved))
+		return result.Interface()
+
+	case reflect.Array, reflect.Slice:
+		var result reflect.Value
+		if expectedKind == reflect.Array {
+			result = reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem()
+		} else {
+			result = reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len())
+		}
+		for i := 0; i < expectedValue.Len(); i++ {
+			index := expectedValue.Index(i)
+			if isNil(index) {
+				continue
+			}
+			unexportedRemoved := copyExportedFields(index.Interface())
+			result.Index(i).Set(reflect.ValueOf(unexportedRemoved))
+		}
+		return result.Interface()
+
+	case reflect.Map:
+		result := reflect.MakeMap(expectedType)
+		for _, k := range expectedValue.MapKeys() {
+			index := expectedValue.MapIndex(k)
+			unexportedRemoved := copyExportedFields(index.Interface())
+			result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved))
+		}
+		return result.Interface()
+
+	default:
+		return expected
+	}
+}
+
+// ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are
+// considered equal. This comparison of only exported fields is applied recursively to nested data
+// structures.
+//
+// This function does no assertion of any kind.
+//
+// Deprecated: Use [EqualExportedValues] instead.
+func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool {
+	expectedCleaned := copyExportedFields(expected)
+	actualCleaned := copyExportedFields(actual)
+	return ObjectsAreEqualValues(expectedCleaned, actualCleaned)
+}
+
+// ObjectsAreEqualValues gets whether two objects are equal, or if their
+// values are equal.
+func ObjectsAreEqualValues(expected, actual interface{}) bool {
+	if ObjectsAreEqual(expected, actual) {
+		return true
+	}
+
+	expectedValue := reflect.ValueOf(expected)
+	actualValue := reflect.ValueOf(actual)
+	if !expectedValue.IsValid() || !actualValue.IsValid() {
+		return false
+	}
+
+	expectedType := expectedValue.Type()
+	actualType := actualValue.Type()
+	if !expectedType.ConvertibleTo(actualType) {
+		return false
+	}
+
+	if !isNumericType(expectedType) || !isNumericType(actualType) {
+		// Attempt comparison after type conversion
+		return reflect.DeepEqual(
+			expectedValue.Convert(actualType).Interface(), actual,
+		)
+	}
+
+	// If BOTH values are numeric, there are chances of false positives due
+	// to overflow or underflow. So, we need to make sure to always convert
+	// the smaller type to a larger type before comparing.
+	if expectedType.Size() >= actualType.Size() {
+		return actualValue.Convert(expectedType).Interface() == expected
+	}
+
+	return expectedValue.Convert(actualType).Interface() == actual
+}
+
+// isNumericType returns true if the type is one of:
+// int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64,
+// float32, float64, complex64, complex128
+func isNumericType(t reflect.Type) bool {
+	return t.Kind() >= reflect.Int && t.Kind() <= reflect.Complex128
+}
+
+/* CallerInfo is necessary because the assert functions use the testing object
+internally, causing it to print the file:line of the assert method, rather than where
+the problem actually occurred in calling code.*/
+
+// CallerInfo returns an array of strings containing the file and line number
+// of each stack frame leading from the current test to the assert call that
+// failed.
+func CallerInfo() []string {
+	var pc uintptr
+	var file string
+	var line int
+	var name string
+
+	const stackFrameBufferSize = 10
+	pcs := make([]uintptr, stackFrameBufferSize)
+
+	callers := []string{}
+	offset := 1
+
+	for {
+		n := runtime.Callers(offset, pcs)
+
+		if n == 0 {
+			break
+		}
+
+		frames := runtime.CallersFrames(pcs[:n])
+
+		for {
+			frame, more := frames.Next()
+			pc = frame.PC
+			file = frame.File
+			line = frame.Line
+
+			// This is a huge edge case, but it will panic if this is the case, see #180
+			if file == "<autogenerated>" {
+				break
+			}
+
+			f := runtime.FuncForPC(pc)
+			if f == nil {
+				break
+			}
+			name = f.Name()
+
+			// testing.tRunner is the standard library function that calls
+			// tests. Subtests are called directly by tRunner, without going through
+			// the Test/Benchmark/Example function that contains the t.Run calls, so
+			// with subtests we should break when we hit tRunner, without adding it
+			// to the list of callers.
+			if name == "testing.tRunner" {
+				break
+			}
+
+			parts := strings.Split(file, "/")
+			if len(parts) > 1 {
+				filename := parts[len(parts)-1]
+				dir := parts[len(parts)-2]
+				if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" {
+					callers = append(callers, fmt.Sprintf("%s:%d", file, line))
+				}
+			}
+
+			// Drop the package
+			dotPos := strings.LastIndexByte(name, '.')
+			name = name[dotPos+1:]
+			if isTest(name, "Test") ||
+				isTest(name, "Benchmark") ||
+				isTest(name, "Example") {
+				break
+			}
+
+			if !more {
+				break
+			}
+		}
+
+		// Next batch
+		offset += cap(pcs)
+	}
+
+	return callers
+}
+
+// Stolen from the `go test` tool.
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+	if !strings.HasPrefix(name, prefix) {
+		return false
+	}
+	if len(name) == len(prefix) { // "Test" is ok
+		return true
+	}
+	r, _ := utf8.DecodeRuneInString(name[len(prefix):])
+	return !unicode.IsLower(r)
+}
+
+func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
+	if len(msgAndArgs) == 0 || msgAndArgs == nil {
+		return ""
+	}
+	if len(msgAndArgs) == 1 {
+		msg := msgAndArgs[0]
+		if msgAsStr, ok := msg.(string); ok {
+			return msgAsStr
+		}
+		return fmt.Sprintf("%+v", msg)
+	}
+	if len(msgAndArgs) > 1 {
+		return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
+	}
+	return ""
+}
+
+// Aligns the provided message so that all lines after the first line start at the same location as the first line.
+// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab).
+// The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the
+// basis on which the alignment occurs).
+func indentMessageLines(message string, longestLabelLen int) string {
+	outBuf := new(bytes.Buffer)
+
+	for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
+		// no need to align first line because it starts at the correct location (after the label)
+		if i != 0 {
+			// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
+			outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
+		}
+		outBuf.WriteString(scanner.Text())
+	}
+
+	return outBuf.String()
+}
+
+type failNower interface {
+	FailNow()
+}
+
+// FailNow fails test
+func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	Fail(t, failureMessage, msgAndArgs...)
+
+	// We cannot extend TestingT with FailNow() and
+	// maintain backwards compatibility, so we fallback
+	// to panicking when FailNow is not available in
+	// TestingT.
+	// See issue #263
+
+	if t, ok := t.(failNower); ok {
+		t.FailNow()
+	} else {
+		panic("test failed and t is missing `FailNow()`")
+	}
+	return false
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	content := []labeledContent{
+		{"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
+		{"Error", failureMessage},
+	}
+
+	// Add test name if the Go version supports it
+	if n, ok := t.(interface {
+		Name() string
+	}); ok {
+		content = append(content, labeledContent{"Test", n.Name()})
+	}
+
+	message := messageFromMsgAndArgs(msgAndArgs...)
+	if len(message) > 0 {
+		content = append(content, labeledContent{"Messages", message})
+	}
+
+	t.Errorf("\n%s", ""+labeledOutput(content...))
+
+	return false
+}
+
+type labeledContent struct {
+	label   string
+	content string
+}
+
+// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
+//
+//	\t{{label}}:{{align_spaces}}\t{{content}}\n
+//
+// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
+// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
+// alignment is achieved, "\t{{content}}\n" is added for the output.
+//
+// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line.
+func labeledOutput(content ...labeledContent) string {
+	longestLabel := 0
+	for _, v := range content {
+		if len(v.label) > longestLabel {
+			longestLabel = len(v.label)
+		}
+	}
+	var output string
+	for _, v := range content {
+		output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
+	}
+	return output
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//	assert.Implements(t, (*MyInterface)(nil), new(MyObject))
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	interfaceType := reflect.TypeOf(interfaceObject).Elem()
+
+	if object == nil {
+		return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...)
+	}
+	if !reflect.TypeOf(object).Implements(interfaceType) {
+		return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...)
+	}
+
+	return true
+}
+
+// NotImplements asserts that an object does not implement the specified interface.
+//
+//	assert.NotImplements(t, (*MyInterface)(nil), new(MyObject))
+func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	interfaceType := reflect.TypeOf(interfaceObject).Elem()
+
+	if object == nil {
+		return Fail(t, fmt.Sprintf("Cannot check if nil does not implement %v", interfaceType), msgAndArgs...)
+	}
+	if reflect.TypeOf(object).Implements(interfaceType) {
+		return Fail(t, fmt.Sprintf("%T implements %v", object, interfaceType), msgAndArgs...)
+	}
+
+	return true
+}
+
+func isType(expectedType, object interface{}) bool {
+	return ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType))
+}
+
+// IsType asserts that the specified objects are of the same type.
+//
+//	assert.IsType(t, &MyStruct{}, &MyStruct{})
+func IsType(t TestingT, expectedType, object interface{}, msgAndArgs ...interface{}) bool {
+	if isType(expectedType, object) {
+		return true
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Fail(t, fmt.Sprintf("Object expected to be of type %T, but was %T", expectedType, object), msgAndArgs...)
+}
+
+// IsNotType asserts that the specified objects are not of the same type.
+//
+//	assert.IsNotType(t, &NotMyStruct{}, &MyStruct{})
+func IsNotType(t TestingT, theType, object interface{}, msgAndArgs ...interface{}) bool {
+	if !isType(theType, object) {
+		return true
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Fail(t, fmt.Sprintf("Object type expected to be different than %T", theType), msgAndArgs...)
+}
+
+// Equal asserts that two objects are equal.
+//
+//	assert.Equal(t, 123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if err := validateEqualArgs(expected, actual); err != nil {
+		return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
+			expected, actual, err), msgAndArgs...)
+	}
+
+	if !ObjectsAreEqual(expected, actual) {
+		diff := diff(expected, actual)
+		expected, actual = formatUnequalValues(expected, actual)
+		return Fail(t, fmt.Sprintf("Not equal: \n"+
+			"expected: %s\n"+
+			"actual  : %s%s", expected, actual, diff), msgAndArgs...)
+	}
+
+	return true
+}
+
+// validateEqualArgs checks whether provided arguments can be safely used in the
+// Equal/NotEqual functions.
+func validateEqualArgs(expected, actual interface{}) error {
+	if expected == nil && actual == nil {
+		return nil
+	}
+
+	if isFunction(expected) || isFunction(actual) {
+		return errors.New("cannot take func type as argument")
+	}
+	return nil
+}
+
+// Same asserts that two pointers reference the same object.
+//
+//	assert.Same(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	same, ok := samePointers(expected, actual)
+	if !ok {
+		return Fail(t, "Both arguments must be pointers", msgAndArgs...)
+	}
+
+	if !same {
+		// both are pointers but not the same type & pointing to the same address
+		return Fail(t, fmt.Sprintf("Not same: \n"+
+			"expected: %p %#[1]v\n"+
+			"actual  : %p %#[2]v",
+			expected, actual), msgAndArgs...)
+	}
+
+	return true
+}
+
+// NotSame asserts that two pointers do not reference the same object.
+//
+//	assert.NotSame(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	same, ok := samePointers(expected, actual)
+	if !ok {
+		// fails when the arguments are not pointers
+		return !(Fail(t, "Both arguments must be pointers", msgAndArgs...))
+	}
+
+	if same {
+		return Fail(t, fmt.Sprintf(
+			"Expected and actual point to the same object: %p %#[1]v",
+			expected), msgAndArgs...)
+	}
+	return true
+}
+
+// samePointers checks if two generic interface objects are pointers of the same
+// type pointing to the same object. It returns two values: same indicating if
+// they are the same type and point to the same object, and ok indicating that
+// both inputs are pointers.
+func samePointers(first, second interface{}) (same bool, ok bool) {
+	firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
+	if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
+		return false, false // not both are pointers
+	}
+
+	firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
+	if firstType != secondType {
+		return false, true // both are pointers, but of different types
+	}
+
+	// compare pointer addresses
+	return first == second, true
+}
+
+// formatUnequalValues takes two values of arbitrary types and returns string
+// representations appropriate to be presented to the user.
+//
+// If the values are not of like type, the returned strings will be prefixed
+// with the type name, and the value will be enclosed in parentheses similar
+// to a type conversion in the Go grammar.
+func formatUnequalValues(expected, actual interface{}) (e string, a string) {
+	if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
+		return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)),
+			fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual))
+	}
+	switch expected.(type) {
+	case time.Duration:
+		return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
+	}
+	return truncatingFormat(expected), truncatingFormat(actual)
+}
+
+// truncatingFormat formats the data and truncates it if it's too long.
+//
+// This helps keep formatted error messages lines from exceeding the
+// bufio.MaxScanTokenSize max line length that the go testing framework imposes.
+func truncatingFormat(data interface{}) string {
+	value := fmt.Sprintf("%#v", data)
+	max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed.
+	if len(value) > max {
+		value = value[0:max] + "<... truncated>"
+	}
+	return value
+}
+
+// EqualValues asserts that two objects are equal or convertible to the larger
+// type and equal.
+//
+//	assert.EqualValues(t, uint32(123), int32(123))
+func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	if !ObjectsAreEqualValues(expected, actual) {
+		diff := diff(expected, actual)
+		expected, actual = formatUnequalValues(expected, actual)
+		return Fail(t, fmt.Sprintf("Not equal: \n"+
+			"expected: %s\n"+
+			"actual  : %s%s", expected, actual, diff), msgAndArgs...)
+	}
+
+	return true
+}
+
+// EqualExportedValues asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+//	 type S struct {
+//		Exported     	int
+//		notExported   	int
+//	 }
+//	 assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true
+//	 assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false
+func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	aType := reflect.TypeOf(expected)
+	bType := reflect.TypeOf(actual)
+
+	if aType != bType {
+		return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
+	}
+
+	expected = copyExportedFields(expected)
+	actual = copyExportedFields(actual)
+
+	if !ObjectsAreEqualValues(expected, actual) {
+		diff := diff(expected, actual)
+		expected, actual = formatUnequalValues(expected, actual)
+		return Fail(t, fmt.Sprintf("Not equal (comparing only exported fields): \n"+
+			"expected: %s\n"+
+			"actual  : %s%s", expected, actual, diff), msgAndArgs...)
+	}
+
+	return true
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+//	assert.Exactly(t, int32(123), int64(123))
+func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	aType := reflect.TypeOf(expected)
+	bType := reflect.TypeOf(actual)
+
+	if aType != bType {
+		return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
+	}
+
+	return Equal(t, expected, actual, msgAndArgs...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//	assert.NotNil(t, err)
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	if !isNil(object) {
+		return true
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Fail(t, "Expected value not to be nil.", msgAndArgs...)
+}
+
+// isNil checks if a specified object is nil or not, without Failing.
+func isNil(object interface{}) bool {
+	if object == nil {
+		return true
+	}
+
+	value := reflect.ValueOf(object)
+	switch value.Kind() {
+	case
+		reflect.Chan, reflect.Func,
+		reflect.Interface, reflect.Map,
+		reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
+
+		return value.IsNil()
+	}
+
+	return false
+}
+
+// Nil asserts that the specified object is nil.
+//
+//	assert.Nil(t, err)
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	if isNil(object) {
+		return true
+	}
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
+}
+
+// isEmpty gets whether the specified object is considered empty or not.
+func isEmpty(object interface{}) bool {
+	// get nil case out of the way
+	if object == nil {
+		return true
+	}
+
+	return isEmptyValue(reflect.ValueOf(object))
+}
+
+// isEmptyValue gets whether the specified reflect.Value is considered empty or not.
+func isEmptyValue(objValue reflect.Value) bool {
+	if objValue.IsZero() {
+		return true
+	}
+	// Special cases of non-zero values that we consider empty
+	switch objValue.Kind() {
+	// collection types are empty when they have no element
+	// Note: array types are empty when they match their zero-initialized state.
+	case reflect.Chan, reflect.Map, reflect.Slice:
+		return objValue.Len() == 0
+	// non-nil pointers are empty if the value they point to is empty
+	case reflect.Ptr:
+		return isEmptyValue(objValue.Elem())
+	}
+	return false
+}
+
+// Empty asserts that the given value is "empty".
+//
+// [Zero values] are "empty".
+//
+// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
+//
+// Slices, maps and channels with zero length are "empty".
+//
+// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
+//
+//	assert.Empty(t, obj)
+//
+// [Zero values]: https://go.dev/ref/spec#The_zero_value
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	pass := isEmpty(object)
+	if !pass {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
+		Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
+	}
+
+	return pass
+}
+
+// NotEmpty asserts that the specified object is NOT [Empty].
+//
+//	if assert.NotEmpty(t, obj) {
+//	  assert.Equal(t, "two", obj[1])
+//	}
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
+	pass := !isEmpty(object)
+	if !pass {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
+		Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
+	}
+
+	return pass
+}
+
+// getLen tries to get the length of an object.
+// It returns (0, false) if impossible.
+func getLen(x interface{}) (length int, ok bool) {
+	v := reflect.ValueOf(x)
+	defer func() {
+		ok = recover() == nil
+	}()
+	return v.Len(), true
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//	assert.Len(t, mySlice, 3)
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	l, ok := getLen(object)
+	if !ok {
+		return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...)
+	}
+
+	if l != length {
+		return Fail(t, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
+	}
+	return true
+}
+
+// True asserts that the specified value is true.
+//
+//	assert.True(t, myBool)
+func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+	if !value {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
+		return Fail(t, "Should be true", msgAndArgs...)
+	}
+
+	return true
+}
+
+// False asserts that the specified value is false.
+//
+//	assert.False(t, myBool)
+func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
+	if value {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
+		return Fail(t, "Should be false", msgAndArgs...)
+	}
+
+	return true
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//	assert.NotEqual(t, obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if err := validateEqualArgs(expected, actual); err != nil {
+		return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
+			expected, actual, err), msgAndArgs...)
+	}
+
+	if ObjectsAreEqual(expected, actual) {
+		return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
+	}
+
+	return true
+}
+
+// NotEqualValues asserts that two objects are not equal even when converted to the same type
+//
+//	assert.NotEqualValues(t, obj1, obj2)
+func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	if ObjectsAreEqualValues(expected, actual) {
+		return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
+	}
+
+	return true
+}
+
+// containsElement try loop over the list check if the list includes the element.
+// return (false, false) if impossible.
+// return (true, false) if element was not found.
+// return (true, true) if element was found.
+func containsElement(list interface{}, element interface{}) (ok, found bool) {
+	listValue := reflect.ValueOf(list)
+	listType := reflect.TypeOf(list)
+	if listType == nil {
+		return false, false
+	}
+	listKind := listType.Kind()
+	defer func() {
+		if e := recover(); e != nil {
+			ok = false
+			found = false
+		}
+	}()
+
+	if listKind == reflect.String {
+		elementValue := reflect.ValueOf(element)
+		return true, strings.Contains(listValue.String(), elementValue.String())
+	}
+
+	if listKind == reflect.Map {
+		mapKeys := listValue.MapKeys()
+		for i := 0; i < len(mapKeys); i++ {
+			if ObjectsAreEqual(mapKeys[i].Interface(), element) {
+				return true, true
+			}
+		}
+		return true, false
+	}
+
+	for i := 0; i < listValue.Len(); i++ {
+		if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
+			return true, true
+		}
+	}
+	return true, false
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//	assert.Contains(t, "Hello World", "World")
+//	assert.Contains(t, ["Hello", "World"], "World")
+//	assert.Contains(t, {"Hello": "World"}, "Hello")
+func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	ok, found := containsElement(s, contains)
+	if !ok {
+		return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
+	}
+	if !found {
+		return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...)
+	}
+
+	return true
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//	assert.NotContains(t, "Hello World", "Earth")
+//	assert.NotContains(t, ["Hello", "World"], "Earth")
+//	assert.NotContains(t, {"Hello": "World"}, "Earth")
+func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	ok, found := containsElement(s, contains)
+	if !ok {
+		return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
+	}
+	if found {
+		return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...)
+	}
+
+	return true
+}
+
+// Subset asserts that the list (array, slice, or map) contains all elements
+// given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	assert.Subset(t, [1, 2, 3], [1, 2])
+//	assert.Subset(t, {"x": 1, "y": 2}, {"x": 1})
+//	assert.Subset(t, [1, 2, 3], {1: "one", 2: "two"})
+//	assert.Subset(t, {"x": 1, "y": 2}, ["x"])
+func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if subset == nil {
+		return true // we consider nil to be equal to the nil set
+	}
+
+	listKind := reflect.TypeOf(list).Kind()
+	if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
+		return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
+	}
+
+	subsetKind := reflect.TypeOf(subset).Kind()
+	if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
+		return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
+	}
+
+	if subsetKind == reflect.Map && listKind == reflect.Map {
+		subsetMap := reflect.ValueOf(subset)
+		actualMap := reflect.ValueOf(list)
+
+		for _, k := range subsetMap.MapKeys() {
+			ev := subsetMap.MapIndex(k)
+			av := actualMap.MapIndex(k)
+
+			if !av.IsValid() {
+				return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
+			}
+			if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
+				return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
+			}
+		}
+
+		return true
+	}
+
+	subsetList := reflect.ValueOf(subset)
+	if subsetKind == reflect.Map {
+		keys := make([]interface{}, subsetList.Len())
+		for idx, key := range subsetList.MapKeys() {
+			keys[idx] = key.Interface()
+		}
+		subsetList = reflect.ValueOf(keys)
+	}
+	for i := 0; i < subsetList.Len(); i++ {
+		element := subsetList.Index(i).Interface()
+		ok, found := containsElement(list, element)
+		if !ok {
+			return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...)
+		}
+		if !found {
+			return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...)
+		}
+	}
+
+	return true
+}
+
+// NotSubset asserts that the list (array, slice, or map) does NOT contain all
+// elements given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	assert.NotSubset(t, [1, 3, 4], [1, 2])
+//	assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
+//	assert.NotSubset(t, [1, 3, 4], {1: "one", 2: "two"})
+//	assert.NotSubset(t, {"x": 1, "y": 2}, ["z"])
+func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if subset == nil {
+		return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...)
+	}
+
+	listKind := reflect.TypeOf(list).Kind()
+	if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
+		return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
+	}
+
+	subsetKind := reflect.TypeOf(subset).Kind()
+	if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
+		return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
+	}
+
+	if subsetKind == reflect.Map && listKind == reflect.Map {
+		subsetMap := reflect.ValueOf(subset)
+		actualMap := reflect.ValueOf(list)
+
+		for _, k := range subsetMap.MapKeys() {
+			ev := subsetMap.MapIndex(k)
+			av := actualMap.MapIndex(k)
+
+			if !av.IsValid() {
+				return true
+			}
+			if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
+				return true
+			}
+		}
+
+		return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
+	}
+
+	subsetList := reflect.ValueOf(subset)
+	if subsetKind == reflect.Map {
+		keys := make([]interface{}, subsetList.Len())
+		for idx, key := range subsetList.MapKeys() {
+			keys[idx] = key.Interface()
+		}
+		subsetList = reflect.ValueOf(keys)
+	}
+	for i := 0; i < subsetList.Len(); i++ {
+		element := subsetList.Index(i).Interface()
+		ok, found := containsElement(list, element)
+		if !ok {
+			return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", list), msgAndArgs...)
+		}
+		if !found {
+			return true
+		}
+	}
+
+	return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
+func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if isEmpty(listA) && isEmpty(listB) {
+		return true
+	}
+
+	if !isList(t, listA, msgAndArgs...) || !isList(t, listB, msgAndArgs...) {
+		return false
+	}
+
+	extraA, extraB := diffLists(listA, listB)
+
+	if len(extraA) == 0 && len(extraB) == 0 {
+		return true
+	}
+
+	return Fail(t, formatListDiff(listA, listB, extraA, extraB), msgAndArgs...)
+}
+
+// isList checks that the provided value is array or slice.
+func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) {
+	kind := reflect.TypeOf(list).Kind()
+	if kind != reflect.Array && kind != reflect.Slice {
+		return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind),
+			msgAndArgs...)
+	}
+	return true
+}
+
+// diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B.
+// If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and
+// 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored.
+func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) {
+	aValue := reflect.ValueOf(listA)
+	bValue := reflect.ValueOf(listB)
+
+	aLen := aValue.Len()
+	bLen := bValue.Len()
+
+	// Mark indexes in bValue that we already used
+	visited := make([]bool, bLen)
+	for i := 0; i < aLen; i++ {
+		element := aValue.Index(i).Interface()
+		found := false
+		for j := 0; j < bLen; j++ {
+			if visited[j] {
+				continue
+			}
+			if ObjectsAreEqual(bValue.Index(j).Interface(), element) {
+				visited[j] = true
+				found = true
+				break
+			}
+		}
+		if !found {
+			extraA = append(extraA, element)
+		}
+	}
+
+	for j := 0; j < bLen; j++ {
+		if visited[j] {
+			continue
+		}
+		extraB = append(extraB, bValue.Index(j).Interface())
+	}
+
+	return
+}
+
+func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string {
+	var msg bytes.Buffer
+
+	msg.WriteString("elements differ")
+	if len(extraA) > 0 {
+		msg.WriteString("\n\nextra elements in list A:\n")
+		msg.WriteString(spewConfig.Sdump(extraA))
+	}
+	if len(extraB) > 0 {
+		msg.WriteString("\n\nextra elements in list B:\n")
+		msg.WriteString(spewConfig.Sdump(extraB))
+	}
+	msg.WriteString("\n\nlistA:\n")
+	msg.WriteString(spewConfig.Sdump(listA))
+	msg.WriteString("\n\nlistB:\n")
+	msg.WriteString(spewConfig.Sdump(listB))
+
+	return msg.String()
+}
+
+// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should not match.
+// This is an inverse of ElementsMatch.
+//
+// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false
+//
+// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true
+//
+// assert.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true
+func NotElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if isEmpty(listA) && isEmpty(listB) {
+		return Fail(t, "listA and listB contain the same elements", msgAndArgs)
+	}
+
+	if !isList(t, listA, msgAndArgs...) {
+		return Fail(t, "listA is not a list type", msgAndArgs...)
+	}
+	if !isList(t, listB, msgAndArgs...) {
+		return Fail(t, "listB is not a list type", msgAndArgs...)
+	}
+
+	extraA, extraB := diffLists(listA, listB)
+	if len(extraA) == 0 && len(extraB) == 0 {
+		return Fail(t, "listA and listB contain the same elements", msgAndArgs)
+	}
+
+	return true
+}
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	result := comp()
+	if !result {
+		Fail(t, "Condition failed!", msgAndArgs...)
+	}
+	return result
+}
+
+// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
+// methods, and represents a simple func that takes no arguments, and returns nothing.
+type PanicTestFunc func()
+
+// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
+func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) {
+	didPanic = true
+
+	defer func() {
+		message = recover()
+		if didPanic {
+			stack = string(debug.Stack())
+		}
+	}()
+
+	// call the target function
+	f()
+	didPanic = false
+
+	return
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//	assert.Panics(t, func(){ GoCrazy() })
+func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic {
+		return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
+	}
+
+	return true
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//	assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	funcDidPanic, panicValue, panickedStack := didPanic(f)
+	if !funcDidPanic {
+		return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
+	}
+	if panicValue != expected {
+		return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...)
+	}
+
+	return true
+}
+
+// PanicsWithError asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+//	assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	funcDidPanic, panicValue, panickedStack := didPanic(f)
+	if !funcDidPanic {
+		return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
+	}
+	panicErr, ok := panicValue.(error)
+	if !ok || panicErr.Error() != errString {
+		return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...)
+	}
+
+	return true
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//	assert.NotPanics(t, func(){ RemainCalm() })
+func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic {
+		return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...)
+	}
+
+	return true
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//	assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
+func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	dt := expected.Sub(actual)
+	if dt < -delta || dt > delta {
+		return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+	}
+
+	return true
+}
+
+// WithinRange asserts that a time is within a time range (inclusive).
+//
+//	assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
+func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	if end.Before(start) {
+		return Fail(t, "Start should be before end", msgAndArgs...)
+	}
+
+	if actual.Before(start) {
+		return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is before the range", actual, start, end), msgAndArgs...)
+	} else if actual.After(end) {
+		return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is after the range", actual, start, end), msgAndArgs...)
+	}
+
+	return true
+}
+
+func toFloat(x interface{}) (float64, bool) {
+	var xf float64
+	xok := true
+
+	switch xn := x.(type) {
+	case uint:
+		xf = float64(xn)
+	case uint8:
+		xf = float64(xn)
+	case uint16:
+		xf = float64(xn)
+	case uint32:
+		xf = float64(xn)
+	case uint64:
+		xf = float64(xn)
+	case int:
+		xf = float64(xn)
+	case int8:
+		xf = float64(xn)
+	case int16:
+		xf = float64(xn)
+	case int32:
+		xf = float64(xn)
+	case int64:
+		xf = float64(xn)
+	case float32:
+		xf = float64(xn)
+	case float64:
+		xf = xn
+	case time.Duration:
+		xf = float64(xn)
+	default:
+		xok = false
+	}
+
+	return xf, xok
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+//	assert.InDelta(t, math.Pi, 22/7.0, 0.01)
+func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	af, aok := toFloat(expected)
+	bf, bok := toFloat(actual)
+
+	if !aok || !bok {
+		return Fail(t, "Parameters must be numerical", msgAndArgs...)
+	}
+
+	if math.IsNaN(af) && math.IsNaN(bf) {
+		return true
+	}
+
+	if math.IsNaN(af) {
+		return Fail(t, "Expected must not be NaN", msgAndArgs...)
+	}
+
+	if math.IsNaN(bf) {
+		return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
+	}
+
+	dt := af - bf
+	if dt < -delta || dt > delta {
+		return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
+	}
+
+	return true
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if expected == nil || actual == nil ||
+		reflect.TypeOf(actual).Kind() != reflect.Slice ||
+		reflect.TypeOf(expected).Kind() != reflect.Slice {
+		return Fail(t, "Parameters must be slice", msgAndArgs...)
+	}
+
+	actualSlice := reflect.ValueOf(actual)
+	expectedSlice := reflect.ValueOf(expected)
+
+	for i := 0; i < actualSlice.Len(); i++ {
+		result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...)
+		if !result {
+			return result
+		}
+	}
+
+	return true
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if expected == nil || actual == nil ||
+		reflect.TypeOf(actual).Kind() != reflect.Map ||
+		reflect.TypeOf(expected).Kind() != reflect.Map {
+		return Fail(t, "Arguments must be maps", msgAndArgs...)
+	}
+
+	expectedMap := reflect.ValueOf(expected)
+	actualMap := reflect.ValueOf(actual)
+
+	if expectedMap.Len() != actualMap.Len() {
+		return Fail(t, "Arguments must have the same number of keys", msgAndArgs...)
+	}
+
+	for _, k := range expectedMap.MapKeys() {
+		ev := expectedMap.MapIndex(k)
+		av := actualMap.MapIndex(k)
+
+		if !ev.IsValid() {
+			return Fail(t, fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...)
+		}
+
+		if !av.IsValid() {
+			return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...)
+		}
+
+		if !InDelta(
+			t,
+			ev.Interface(),
+			av.Interface(),
+			delta,
+			msgAndArgs...,
+		) {
+			return false
+		}
+	}
+
+	return true
+}
+
+func calcRelativeError(expected, actual interface{}) (float64, error) {
+	af, aok := toFloat(expected)
+	bf, bok := toFloat(actual)
+	if !aok || !bok {
+		return 0, fmt.Errorf("Parameters must be numerical")
+	}
+	if math.IsNaN(af) && math.IsNaN(bf) {
+		return 0, nil
+	}
+	if math.IsNaN(af) {
+		return 0, errors.New("expected value must not be NaN")
+	}
+	if af == 0 {
+		return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
+	}
+	if math.IsNaN(bf) {
+		return 0, errors.New("actual value must not be NaN")
+	}
+
+	return math.Abs(af-bf) / math.Abs(af), nil
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if math.IsNaN(epsilon) {
+		return Fail(t, "epsilon must not be NaN", msgAndArgs...)
+	}
+	actualEpsilon, err := calcRelativeError(expected, actual)
+	if err != nil {
+		return Fail(t, err.Error(), msgAndArgs...)
+	}
+	if math.IsNaN(actualEpsilon) {
+		return Fail(t, "relative error is NaN", msgAndArgs...)
+	}
+	if actualEpsilon > epsilon {
+		return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
+			"        < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
+	}
+
+	return true
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	if expected == nil || actual == nil {
+		return Fail(t, "Parameters must be slice", msgAndArgs...)
+	}
+
+	expectedSlice := reflect.ValueOf(expected)
+	actualSlice := reflect.ValueOf(actual)
+
+	if expectedSlice.Type().Kind() != reflect.Slice {
+		return Fail(t, "Expected value must be slice", msgAndArgs...)
+	}
+
+	expectedLen := expectedSlice.Len()
+	if !IsType(t, expected, actual) || !Len(t, actual, expectedLen) {
+		return false
+	}
+
+	for i := 0; i < expectedLen; i++ {
+		if !InEpsilon(t, expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) {
+			return false
+		}
+	}
+
+	return true
+}
+
+/*
+	Errors
+*/
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//	  actualObj, err := SomeFunction()
+//	  if assert.NoError(t, err) {
+//		   assert.Equal(t, expectedObj, actualObj)
+//	  }
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
+	if err != nil {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
+		return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
+	}
+
+	return true
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//	actualObj, err := SomeFunction()
+//	assert.Error(t, err)
+func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
+	if err == nil {
+		if h, ok := t.(tHelper); ok {
+			h.Helper()
+		}
+		return Fail(t, "An error is expected but got nil.", msgAndArgs...)
+	}
+
+	return true
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//	actualObj, err := SomeFunction()
+//	assert.EqualError(t, err,  expectedErrorString)
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if !Error(t, theError, msgAndArgs...) {
+		return false
+	}
+	expected := errString
+	actual := theError.Error()
+	// don't need to use deep equals here, we know they are both strings
+	if expected != actual {
+		return Fail(t, fmt.Sprintf("Error message not equal:\n"+
+			"expected: %q\n"+
+			"actual  : %q", expected, actual), msgAndArgs...)
+	}
+	return true
+}
+
+// ErrorContains asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+//	actualObj, err := SomeFunction()
+//	assert.ErrorContains(t, err,  expectedErrorSubString)
+func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if !Error(t, theError, msgAndArgs...) {
+		return false
+	}
+
+	actual := theError.Error()
+	if !strings.Contains(actual, contains) {
+		return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...)
+	}
+
+	return true
+}
+
+// matchRegexp return true if a specified regexp matches a string.
+func matchRegexp(rx interface{}, str interface{}) bool {
+	var r *regexp.Regexp
+	if rr, ok := rx.(*regexp.Regexp); ok {
+		r = rr
+	} else {
+		r = regexp.MustCompile(fmt.Sprint(rx))
+	}
+
+	switch v := str.(type) {
+	case []byte:
+		return r.Match(v)
+	case string:
+		return r.MatchString(v)
+	default:
+		return r.MatchString(fmt.Sprint(v))
+	}
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//	assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//	assert.Regexp(t, "start...$", "it's not starting")
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	match := matchRegexp(rx, str)
+
+	if !match {
+		Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
+	}
+
+	return match
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//	assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//	assert.NotRegexp(t, "^start", "it's not starting")
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	match := matchRegexp(rx, str)
+
+	if match {
+		Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
+	}
+
+	return !match
+}
+
+// Zero asserts that i is the zero value for its type.
+func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
+		return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
+	}
+	return true
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
+		return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
+	}
+	return true
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	info, err := os.Lstat(path)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
+		}
+		return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
+	}
+	if info.IsDir() {
+		return Fail(t, fmt.Sprintf("%q is a directory", path), msgAndArgs...)
+	}
+	return true
+}
+
+// NoFileExists checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	info, err := os.Lstat(path)
+	if err != nil {
+		return true
+	}
+	if info.IsDir() {
+		return true
+	}
+	return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...)
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	info, err := os.Lstat(path)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
+		}
+		return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
+	}
+	if !info.IsDir() {
+		return Fail(t, fmt.Sprintf("%q is a file", path), msgAndArgs...)
+	}
+	return true
+}
+
+// NoDirExists checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	info, err := os.Lstat(path)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return true
+		}
+		return true
+	}
+	if !info.IsDir() {
+		return true
+	}
+	return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...)
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//	assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	var expectedJSONAsInterface, actualJSONAsInterface interface{}
+
+	if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
+		return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
+	}
+
+	// Shortcut if same bytes
+	if actual == expected {
+		return true
+	}
+
+	if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
+		return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
+	}
+
+	return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
+
+	if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
+		return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
+	}
+
+	// Shortcut if same bytes
+	if actual == expected {
+		return true
+	}
+
+	if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
+		return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
+	}
+
+	return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
+}
+
+func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
+	t := reflect.TypeOf(v)
+	k := t.Kind()
+
+	if k == reflect.Ptr {
+		t = t.Elem()
+		k = t.Kind()
+	}
+	return t, k
+}
+
+// diff returns a diff of both values as long as both are of the same type and
+// are a struct, map, slice, array or string. Otherwise it returns an empty string.
+func diff(expected interface{}, actual interface{}) string {
+	if expected == nil || actual == nil {
+		return ""
+	}
+
+	et, ek := typeAndKind(expected)
+	at, _ := typeAndKind(actual)
+
+	if et != at {
+		return ""
+	}
+
+	if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String {
+		return ""
+	}
+
+	var e, a string
+
+	switch et {
+	case reflect.TypeOf(""):
+		e = reflect.ValueOf(expected).String()
+		a = reflect.ValueOf(actual).String()
+	case reflect.TypeOf(time.Time{}):
+		e = spewConfigStringerEnabled.Sdump(expected)
+		a = spewConfigStringerEnabled.Sdump(actual)
+	default:
+		e = spewConfig.Sdump(expected)
+		a = spewConfig.Sdump(actual)
+	}
+
+	diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
+		A:        difflib.SplitLines(e),
+		B:        difflib.SplitLines(a),
+		FromFile: "Expected",
+		FromDate: "",
+		ToFile:   "Actual",
+		ToDate:   "",
+		Context:  1,
+	})
+
+	return "\n\nDiff:\n" + diff
+}
+
+func isFunction(arg interface{}) bool {
+	if arg == nil {
+		return false
+	}
+	return reflect.TypeOf(arg).Kind() == reflect.Func
+}
+
+var spewConfig = spew.ConfigState{
+	Indent:                  " ",
+	DisablePointerAddresses: true,
+	DisableCapacities:       true,
+	SortKeys:                true,
+	DisableMethods:          true,
+	MaxDepth:                10,
+}
+
+var spewConfigStringerEnabled = spew.ConfigState{
+	Indent:                  " ",
+	DisablePointerAddresses: true,
+	DisableCapacities:       true,
+	SortKeys:                true,
+	MaxDepth:                10,
+}
+
+type tHelper = interface {
+	Helper()
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//	assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
+func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	ch := make(chan bool, 1)
+	checkCond := func() { ch <- condition() }
+
+	timer := time.NewTimer(waitFor)
+	defer timer.Stop()
+
+	ticker := time.NewTicker(tick)
+	defer ticker.Stop()
+
+	var tickC <-chan time.Time
+
+	// Check the condition once first on the initial call.
+	go checkCond()
+
+	for {
+		select {
+		case <-timer.C:
+			return Fail(t, "Condition never satisfied", msgAndArgs...)
+		case <-tickC:
+			tickC = nil
+			go checkCond()
+		case v := <-ch:
+			if v {
+				return true
+			}
+			tickC = ticker.C
+		}
+	}
+}
+
+// CollectT implements the TestingT interface and collects all errors.
+type CollectT struct {
+	// A slice of errors. Non-nil slice denotes a failure.
+	// If it's non-nil but len(c.errors) == 0, this is also a failure
+	// obtained by direct c.FailNow() call.
+	errors []error
+}
+
+// Helper is like [testing.T.Helper] but does nothing.
+func (CollectT) Helper() {}
+
+// Errorf collects the error.
+func (c *CollectT) Errorf(format string, args ...interface{}) {
+	c.errors = append(c.errors, fmt.Errorf(format, args...))
+}
+
+// FailNow stops execution by calling runtime.Goexit.
+func (c *CollectT) FailNow() {
+	c.fail()
+	runtime.Goexit()
+}
+
+// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
+func (*CollectT) Reset() {
+	panic("Reset() is deprecated")
+}
+
+// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
+func (*CollectT) Copy(TestingT) {
+	panic("Copy() is deprecated")
+}
+
+func (c *CollectT) fail() {
+	if !c.failed() {
+		c.errors = []error{} // Make it non-nil to mark a failure.
+	}
+}
+
+func (c *CollectT) failed() bool {
+	return c.errors != nil
+}
+
+// EventuallyWithT asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+//	externalValue := false
+//	go func() {
+//		time.Sleep(8*time.Second)
+//		externalValue = true
+//	}()
+//	assert.EventuallyWithT(t, func(c *assert.CollectT) {
+//		// add assertions as needed; any assertion failure will fail the current tick
+//		assert.True(c, externalValue, "expected 'externalValue' to be true")
+//	}, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
+func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	var lastFinishedTickErrs []error
+	ch := make(chan *CollectT, 1)
+
+	checkCond := func() {
+		collect := new(CollectT)
+		defer func() {
+			ch <- collect
+		}()
+		condition(collect)
+	}
+
+	timer := time.NewTimer(waitFor)
+	defer timer.Stop()
+
+	ticker := time.NewTicker(tick)
+	defer ticker.Stop()
+
+	var tickC <-chan time.Time
+
+	// Check the condition once first on the initial call.
+	go checkCond()
+
+	for {
+		select {
+		case <-timer.C:
+			for _, err := range lastFinishedTickErrs {
+				t.Errorf("%v", err)
+			}
+			return Fail(t, "Condition never satisfied", msgAndArgs...)
+		case <-tickC:
+			tickC = nil
+			go checkCond()
+		case collect := <-ch:
+			if !collect.failed() {
+				return true
+			}
+			// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
+			lastFinishedTickErrs = collect.errors
+			tickC = ticker.C
+		}
+	}
+}
+
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//	assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
+func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+
+	ch := make(chan bool, 1)
+	checkCond := func() { ch <- condition() }
+
+	timer := time.NewTimer(waitFor)
+	defer timer.Stop()
+
+	ticker := time.NewTicker(tick)
+	defer ticker.Stop()
+
+	var tickC <-chan time.Time
+
+	// Check the condition once first on the initial call.
+	go checkCond()
+
+	for {
+		select {
+		case <-timer.C:
+			return true
+		case <-tickC:
+			tickC = nil
+			go checkCond()
+		case v := <-ch:
+			if v {
+				return Fail(t, "Condition satisfied", msgAndArgs...)
+			}
+			tickC = ticker.C
+		}
+	}
+}
+
+// ErrorIs asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if errors.Is(err, target) {
+		return true
+	}
+
+	var expectedText string
+	if target != nil {
+		expectedText = target.Error()
+		if err == nil {
+			return Fail(t, fmt.Sprintf("Expected error with %q in chain but got nil.", expectedText), msgAndArgs...)
+		}
+	}
+
+	chain := buildErrorChainString(err, false)
+
+	return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
+		"expected: %q\n"+
+		"in chain: %s", expectedText, chain,
+	), msgAndArgs...)
+}
+
+// NotErrorIs asserts that none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if !errors.Is(err, target) {
+		return true
+	}
+
+	var expectedText string
+	if target != nil {
+		expectedText = target.Error()
+	}
+
+	chain := buildErrorChainString(err, false)
+
+	return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
+		"found: %q\n"+
+		"in chain: %s", expectedText, chain,
+	), msgAndArgs...)
+}
+
+// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if errors.As(err, target) {
+		return true
+	}
+
+	expectedType := reflect.TypeOf(target).Elem().String()
+	if err == nil {
+		return Fail(t, fmt.Sprintf("An error is expected but got nil.\n"+
+			"expected: %s", expectedType), msgAndArgs...)
+	}
+
+	chain := buildErrorChainString(err, true)
+
+	return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
+		"expected: %s\n"+
+		"in chain: %s", expectedType, chain,
+	), msgAndArgs...)
+}
+
+// NotErrorAs asserts that none of the errors in err's chain matches target,
+// but if so, sets target to that error value.
+func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if !errors.As(err, target) {
+		return true
+	}
+
+	chain := buildErrorChainString(err, true)
+
+	return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
+		"found: %s\n"+
+		"in chain: %s", reflect.TypeOf(target).Elem().String(), chain,
+	), msgAndArgs...)
+}
+
+func unwrapAll(err error) (errs []error) {
+	errs = append(errs, err)
+	switch x := err.(type) {
+	case interface{ Unwrap() error }:
+		err = x.Unwrap()
+		if err == nil {
+			return
+		}
+		errs = append(errs, unwrapAll(err)...)
+	case interface{ Unwrap() []error }:
+		for _, err := range x.Unwrap() {
+			errs = append(errs, unwrapAll(err)...)
+		}
+	}
+	return
+}
+
+func buildErrorChainString(err error, withType bool) string {
+	if err == nil {
+		return ""
+	}
+
+	var chain string
+	errs := unwrapAll(err)
+	for i := range errs {
+		if i != 0 {
+			chain += "\n\t"
+		}
+		chain += fmt.Sprintf("%q", errs[i].Error())
+		if withType {
+			chain += fmt.Sprintf(" (%T)", errs[i])
+		}
+	}
+	return chain
+}
diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go
new file mode 100644
index 000000000..a0b953aa5
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/doc.go
@@ -0,0 +1,50 @@
+// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
+//
+// # Note
+//
+// All functions in this package return a bool value indicating whether the assertion has passed.
+//
+// # Example Usage
+//
+// The following is a complete example using assert in a standard test function:
+//
+//	import (
+//	  "testing"
+//	  "github.com/stretchr/testify/assert"
+//	)
+//
+//	func TestSomething(t *testing.T) {
+//
+//	  var a string = "Hello"
+//	  var b string = "Hello"
+//
+//	  assert.Equal(t, a, b, "The two words should be the same.")
+//
+//	}
+//
+// if you assert many times, use the format below:
+//
+//	import (
+//	  "testing"
+//	  "github.com/stretchr/testify/assert"
+//	)
+//
+//	func TestSomething(t *testing.T) {
+//	  assert := assert.New(t)
+//
+//	  var a string = "Hello"
+//	  var b string = "Hello"
+//
+//	  assert.Equal(a, b, "The two words should be the same.")
+//	}
+//
+// # Assertions
+//
+// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
+// All assertion functions take, as the first argument, the `*testing.T` object provided by the
+// testing framework. This allows the assertion funcs to write the failings and other details to
+// the correct place.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+package assert
diff --git a/vendor/github.com/stretchr/testify/assert/errors.go b/vendor/github.com/stretchr/testify/assert/errors.go
new file mode 100644
index 000000000..ac9dc9d1d
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/errors.go
@@ -0,0 +1,10 @@
+package assert
+
+import (
+	"errors"
+)
+
+// AnError is an error instance useful for testing.  If the code does not care
+// about error specifics, and only needs to return the error for example, this
+// error should be used to make the test code more readable.
+var AnError = errors.New("assert.AnError general error for testing")
diff --git a/vendor/github.com/stretchr/testify/assert/forward_assertions.go b/vendor/github.com/stretchr/testify/assert/forward_assertions.go
new file mode 100644
index 000000000..df189d234
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/forward_assertions.go
@@ -0,0 +1,16 @@
+package assert
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+	t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+	return &Assertions{
+		t: t,
+	}
+}
+
+//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs"
diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go
new file mode 100644
index 000000000..5a6bb75f2
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go
@@ -0,0 +1,165 @@
+package assert
+
+import (
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"strings"
+)
+
+// httpCode is a helper that returns HTTP code of the response. It returns -1 and
+// an error if building a new request fails.
+func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
+	w := httptest.NewRecorder()
+	req, err := http.NewRequest(method, url, http.NoBody)
+	if err != nil {
+		return -1, err
+	}
+	req.URL.RawQuery = values.Encode()
+	handler(w, req)
+	return w.Code, nil
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//	assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	code, err := httpCode(handler, method, url, values)
+	if err != nil {
+		Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
+	}
+
+	isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent
+	if !isSuccessCode {
+		Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
+	}
+
+	return isSuccessCode
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//	assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	code, err := httpCode(handler, method, url, values)
+	if err != nil {
+		Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
+	}
+
+	isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
+	if !isRedirectCode {
+		Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
+	}
+
+	return isRedirectCode
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//	assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	code, err := httpCode(handler, method, url, values)
+	if err != nil {
+		Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
+	}
+
+	isErrorCode := code >= http.StatusBadRequest
+	if !isErrorCode {
+		Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
+	}
+
+	return isErrorCode
+}
+
+// HTTPStatusCode asserts that a specified handler returns a specified status code.
+//
+//	assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	code, err := httpCode(handler, method, url, values)
+	if err != nil {
+		Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
+	}
+
+	successful := code == statuscode
+	if !successful {
+		Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code), msgAndArgs...)
+	}
+
+	return successful
+}
+
+// HTTPBody is a helper that returns HTTP body of the response. It returns
+// empty string if building a new request fails.
+func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
+	w := httptest.NewRecorder()
+	if len(values) > 0 {
+		url += "?" + values.Encode()
+	}
+	req, err := http.NewRequest(method, url, http.NoBody)
+	if err != nil {
+		return ""
+	}
+	handler(w, req)
+	return w.Body.String()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//	assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	body := HTTPBody(handler, method, url, values)
+
+	contains := strings.Contains(body, fmt.Sprint(str))
+	if !contains {
+		Fail(t, fmt.Sprintf("Expected response body for %q to contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...)
+	}
+
+	return contains
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//	assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	body := HTTPBody(handler, method, url, values)
+
+	contains := strings.Contains(body, fmt.Sprint(str))
+	if contains {
+		Fail(t, fmt.Sprintf("Expected response body for %q to NOT contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...)
+	}
+
+	return !contains
+}
diff --git a/vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go b/vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go
new file mode 100644
index 000000000..5a74c4f4d
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go
@@ -0,0 +1,24 @@
+//go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default
+
+// Package yaml is an implementation of YAML functions that calls a pluggable implementation.
+//
+// This implementation is selected with the testify_yaml_custom build tag.
+//
+//	go test -tags testify_yaml_custom
+//
+// This implementation can be used at build time to replace the default implementation
+// to avoid linking with [gopkg.in/yaml.v3].
+//
+// In your test package:
+//
+//		import assertYaml "github.com/stretchr/testify/assert/yaml"
+//
+//		func init() {
+//			assertYaml.Unmarshal = func (in []byte, out interface{}) error {
+//				// ...
+//	     			return nil
+//			}
+//		}
+package yaml
+
+var Unmarshal func(in []byte, out interface{}) error
diff --git a/vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go b/vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go
new file mode 100644
index 000000000..0bae80e34
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go
@@ -0,0 +1,36 @@
+//go:build !testify_yaml_fail && !testify_yaml_custom
+
+// Package yaml is just an indirection to handle YAML deserialization.
+//
+// This package is just an indirection that allows the builder to override the
+// indirection with an alternative implementation of this package that uses
+// another implementation of YAML deserialization. This allows to not either not
+// use YAML deserialization at all, or to use another implementation than
+// [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]).
+//
+// Alternative implementations are selected using build tags:
+//
+//   - testify_yaml_fail: [Unmarshal] always fails with an error
+//   - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it
+//     before calling any of [github.com/stretchr/testify/assert.YAMLEq] or
+//     [github.com/stretchr/testify/assert.YAMLEqf].
+//
+// Usage:
+//
+//	go test -tags testify_yaml_fail
+//
+// You can check with "go list" which implementation is linked:
+//
+//	go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
+//	go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
+//	go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
+//
+// [PR #1120]: https://github.com/stretchr/testify/pull/1120
+package yaml
+
+import goyaml "gopkg.in/yaml.v3"
+
+// Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal].
+func Unmarshal(in []byte, out interface{}) error {
+	return goyaml.Unmarshal(in, out)
+}
diff --git a/vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go b/vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go
new file mode 100644
index 000000000..8041803fd
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go
@@ -0,0 +1,17 @@
+//go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default
+
+// Package yaml is an implementation of YAML functions that always fail.
+//
+// This implementation can be used at build time to replace the default implementation
+// to avoid linking with [gopkg.in/yaml.v3]:
+//
+//	go test -tags testify_yaml_fail
+package yaml
+
+import "errors"
+
+var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)")
+
+func Unmarshal([]byte, interface{}) error {
+	return errNotImplemented
+}
diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go
new file mode 100644
index 000000000..c8e3f94a8
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/doc.go
@@ -0,0 +1,31 @@
+// Package require implements the same assertions as the `assert` package but
+// stops test execution when a test fails.
+//
+// # Example Usage
+//
+// The following is a complete example using require in a standard test function:
+//
+//	import (
+//	  "testing"
+//	  "github.com/stretchr/testify/require"
+//	)
+//
+//	func TestSomething(t *testing.T) {
+//
+//	  var a string = "Hello"
+//	  var b string = "Hello"
+//
+//	  require.Equal(t, a, b, "The two words should be the same.")
+//
+//	}
+//
+// # Assertions
+//
+// The `require` package have same global functions as in the `assert` package,
+// but instead of returning a boolean result they call `t.FailNow()`.
+// A consequence of this is that it must be called from the goroutine running
+// the test function, not from other goroutines created during the test.
+//
+// Every assertion function also takes an optional string message as the final argument,
+// allowing custom error messages to be appended to the message the assertion method outputs.
+package require
diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go
new file mode 100644
index 000000000..1dcb2338c
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go
@@ -0,0 +1,16 @@
+package require
+
+// Assertions provides assertion methods around the
+// TestingT interface.
+type Assertions struct {
+	t TestingT
+}
+
+// New makes a new Assertions object for the specified TestingT.
+func New(t TestingT) *Assertions {
+	return &Assertions{
+		t: t,
+	}
+}
+
+//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs"
diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go
new file mode 100644
index 000000000..2d02f9bce
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require.go
@@ -0,0 +1,2180 @@
+// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
+
+package require
+
+import (
+	assert "github.com/stretchr/testify/assert"
+	http "net/http"
+	url "net/url"
+	time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Condition(t, comp, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Conditionf(t, comp, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//	require.Contains(t, "Hello World", "World")
+//	require.Contains(t, ["Hello", "World"], "World")
+//	require.Contains(t, {"Hello": "World"}, "Hello")
+func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Contains(t, s, contains, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//	require.Containsf(t, "Hello World", "World", "error message %s", "formatted")
+//	require.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
+//	require.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
+func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Containsf(t, s, contains, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.DirExists(t, path, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.DirExistsf(t, path, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// require.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
+func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ElementsMatch(t, listA, listB, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// require.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ElementsMatchf(t, listA, listB, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Empty asserts that the given value is "empty".
+//
+// [Zero values] are "empty".
+//
+// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
+//
+// Slices, maps and channels with zero length are "empty".
+//
+// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
+//
+//	require.Empty(t, obj)
+//
+// [Zero values]: https://go.dev/ref/spec#The_zero_value
+func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Empty(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Emptyf asserts that the given value is "empty".
+//
+// [Zero values] are "empty".
+//
+// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
+//
+// Slices, maps and channels with zero length are "empty".
+//
+// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
+//
+//	require.Emptyf(t, obj, "error message %s", "formatted")
+//
+// [Zero values]: https://go.dev/ref/spec#The_zero_value
+func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Emptyf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Equal asserts that two objects are equal.
+//
+//	require.Equal(t, 123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Equal(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//	actualObj, err := SomeFunction()
+//	require.EqualError(t, err,  expectedErrorString)
+func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualError(t, theError, errString, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//	actualObj, err := SomeFunction()
+//	require.EqualErrorf(t, err,  expectedErrorString, "error message %s", "formatted")
+func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualErrorf(t, theError, errString, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualExportedValues asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+//	 type S struct {
+//		Exported     	int
+//		notExported   	int
+//	 }
+//	 require.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true
+//	 require.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false
+func EqualExportedValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualExportedValues(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualExportedValuesf asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+//	 type S struct {
+//		Exported     	int
+//		notExported   	int
+//	 }
+//	 require.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
+//	 require.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
+func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualExportedValuesf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualValues asserts that two objects are equal or convertible to the larger
+// type and equal.
+//
+//	require.EqualValues(t, uint32(123), int32(123))
+func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualValues(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EqualValuesf asserts that two objects are equal or convertible to the larger
+// type and equal.
+//
+//	require.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
+func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EqualValuesf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Equalf asserts that two objects are equal.
+//
+//	require.Equalf(t, 123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Equalf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//	actualObj, err := SomeFunction()
+//	require.Error(t, err)
+func Error(t TestingT, err error, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Error(t, err, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ErrorAs(t, err, target, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ErrorAsf(t, err, target, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ErrorContains asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+//	actualObj, err := SomeFunction()
+//	require.ErrorContains(t, err,  expectedErrorSubString)
+func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ErrorContains(t, theError, contains, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+//	actualObj, err := SomeFunction()
+//	require.ErrorContainsf(t, err,  expectedErrorSubString, "error message %s", "formatted")
+func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ErrorContainsf(t, theError, contains, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ErrorIs asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ErrorIs(t, err, target, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// ErrorIsf asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.ErrorIsf(t, err, target, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+//	actualObj, err := SomeFunction()
+//	require.Errorf(t, err, "error message %s", "formatted")
+func Errorf(t TestingT, err error, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Errorf(t, err, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//	require.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
+func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EventuallyWithT asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+//	externalValue := false
+//	go func() {
+//		time.Sleep(8*time.Second)
+//		externalValue = true
+//	}()
+//	require.EventuallyWithT(t, func(c *require.CollectT) {
+//		// add assertions as needed; any assertion failure will fail the current tick
+//		require.True(c, externalValue, "expected 'externalValue' to be true")
+//	}, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
+func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// EventuallyWithTf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+//	externalValue := false
+//	go func() {
+//		time.Sleep(8*time.Second)
+//		externalValue = true
+//	}()
+//	require.EventuallyWithTf(t, func(c *require.CollectT, "error message %s", "formatted") {
+//		// add assertions as needed; any assertion failure will fail the current tick
+//		require.True(c, externalValue, "expected 'externalValue' to be true")
+//	}, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
+func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.EventuallyWithTf(t, condition, waitFor, tick, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//	require.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+//	require.Exactly(t, int32(123), int64(123))
+func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Exactly(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+//	require.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
+func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Exactlyf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Fail reports a failure through
+func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Fail(t, failureMessage, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// FailNow fails test
+func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.FailNow(t, failureMessage, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// FailNowf fails test
+func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.FailNowf(t, failureMessage, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Failf reports a failure through
+func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Failf(t, failureMessage, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// False asserts that the specified value is false.
+//
+//	require.False(t, myBool)
+func False(t TestingT, value bool, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.False(t, value, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Falsef asserts that the specified value is false.
+//
+//	require.Falsef(t, myBool, "error message %s", "formatted")
+func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Falsef(t, value, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.FileExists(t, path, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.FileExistsf(t, path, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Greater asserts that the first element is greater than the second
+//
+//	require.Greater(t, 2, 1)
+//	require.Greater(t, float64(2), float64(1))
+//	require.Greater(t, "b", "a")
+func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Greater(t, e1, e2, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+//	require.GreaterOrEqual(t, 2, 1)
+//	require.GreaterOrEqual(t, 2, 2)
+//	require.GreaterOrEqual(t, "b", "a")
+//	require.GreaterOrEqual(t, "b", "b")
+func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+//	require.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
+//	require.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
+//	require.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
+//	require.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
+func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.GreaterOrEqualf(t, e1, e2, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+//	require.Greaterf(t, 2, 1, "error message %s", "formatted")
+//	require.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
+//	require.Greaterf(t, "b", "a", "error message %s", "formatted")
+func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Greaterf(t, e1, e2, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//	require.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+//	require.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//	require.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//	require.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//	require.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+//	require.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//	require.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+//	require.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPStatusCode asserts that a specified handler returns a specified status code.
+//
+//	require.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPStatusCodef asserts that a specified handler returns a specified status code.
+//
+//	require.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//	require.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+//	require.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//	require.Implements(t, (*MyInterface)(nil), new(MyObject))
+func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Implements(t, interfaceObject, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+//	require.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Implementsf(t, interfaceObject, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+//	require.InDelta(t, math.Pi, 22/7.0, 0.01)
+func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+//	require.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
+func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InDeltaf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsDecreasing asserts that the collection is decreasing
+//
+//	require.IsDecreasing(t, []int{2, 1, 0})
+//	require.IsDecreasing(t, []float{2, 1})
+//	require.IsDecreasing(t, []string{"b", "a"})
+func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsDecreasing(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsDecreasingf asserts that the collection is decreasing
+//
+//	require.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted")
+//	require.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted")
+//	require.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
+func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsDecreasingf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsIncreasing asserts that the collection is increasing
+//
+//	require.IsIncreasing(t, []int{1, 2, 3})
+//	require.IsIncreasing(t, []float{1, 2})
+//	require.IsIncreasing(t, []string{"a", "b"})
+func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsIncreasing(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsIncreasingf asserts that the collection is increasing
+//
+//	require.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted")
+//	require.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted")
+//	require.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
+func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsIncreasingf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsNonDecreasing asserts that the collection is not decreasing
+//
+//	require.IsNonDecreasing(t, []int{1, 1, 2})
+//	require.IsNonDecreasing(t, []float{1, 2})
+//	require.IsNonDecreasing(t, []string{"a", "b"})
+func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsNonDecreasing(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsNonDecreasingf asserts that the collection is not decreasing
+//
+//	require.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted")
+//	require.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted")
+//	require.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
+func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsNonDecreasingf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsNonIncreasing asserts that the collection is not increasing
+//
+//	require.IsNonIncreasing(t, []int{2, 1, 1})
+//	require.IsNonIncreasing(t, []float{2, 1})
+//	require.IsNonIncreasing(t, []string{"b", "a"})
+func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsNonIncreasing(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsNonIncreasingf asserts that the collection is not increasing
+//
+//	require.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted")
+//	require.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted")
+//	require.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
+func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsNonIncreasingf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsNotType asserts that the specified objects are not of the same type.
+//
+//	require.IsNotType(t, &NotMyStruct{}, &MyStruct{})
+func IsNotType(t TestingT, theType interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsNotType(t, theType, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsNotTypef asserts that the specified objects are not of the same type.
+//
+//	require.IsNotTypef(t, &NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
+func IsNotTypef(t TestingT, theType interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsNotTypef(t, theType, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsType asserts that the specified objects are of the same type.
+//
+//	require.IsType(t, &MyStruct{}, &MyStruct{})
+func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsType(t, expectedType, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+//
+//	require.IsTypef(t, &MyStruct{}, &MyStruct{}, "error message %s", "formatted")
+func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.IsTypef(t, expectedType, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//	require.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.JSONEq(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+//	require.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.JSONEqf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//	require.Len(t, mySlice, 3)
+func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Len(t, object, length, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+//	require.Lenf(t, mySlice, 3, "error message %s", "formatted")
+func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Lenf(t, object, length, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Less asserts that the first element is less than the second
+//
+//	require.Less(t, 1, 2)
+//	require.Less(t, float64(1), float64(2))
+//	require.Less(t, "a", "b")
+func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Less(t, e1, e2, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+//	require.LessOrEqual(t, 1, 2)
+//	require.LessOrEqual(t, 2, 2)
+//	require.LessOrEqual(t, "a", "b")
+//	require.LessOrEqual(t, "b", "b")
+func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.LessOrEqual(t, e1, e2, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+//	require.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
+//	require.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
+//	require.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
+//	require.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
+func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.LessOrEqualf(t, e1, e2, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Lessf asserts that the first element is less than the second
+//
+//	require.Lessf(t, 1, 2, "error message %s", "formatted")
+//	require.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
+//	require.Lessf(t, "a", "b", "error message %s", "formatted")
+func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Lessf(t, e1, e2, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Negative asserts that the specified element is negative
+//
+//	require.Negative(t, -1)
+//	require.Negative(t, -1.23)
+func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Negative(t, e, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Negativef asserts that the specified element is negative
+//
+//	require.Negativef(t, -1, "error message %s", "formatted")
+//	require.Negativef(t, -1.23, "error message %s", "formatted")
+func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Negativef(t, e, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//	require.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
+func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Never(t, condition, waitFor, tick, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//	require.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Neverf(t, condition, waitFor, tick, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Nil asserts that the specified object is nil.
+//
+//	require.Nil(t, err)
+func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Nil(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Nilf asserts that the specified object is nil.
+//
+//	require.Nilf(t, err, "error message %s", "formatted")
+func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Nilf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NoDirExists checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NoDirExists(t, path, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NoDirExistsf checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NoDirExistsf(t, path, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//	  actualObj, err := SomeFunction()
+//	  if require.NoError(t, err) {
+//		   require.Equal(t, expectedObj, actualObj)
+//	  }
+func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NoError(t, err, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+//	  actualObj, err := SomeFunction()
+//	  if require.NoErrorf(t, err, "error message %s", "formatted") {
+//		   require.Equal(t, expectedObj, actualObj)
+//	  }
+func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NoErrorf(t, err, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NoFileExists checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NoFileExists(t, path, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NoFileExistsf checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NoFileExistsf(t, path, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//	require.NotContains(t, "Hello World", "Earth")
+//	require.NotContains(t, ["Hello", "World"], "Earth")
+//	require.NotContains(t, {"Hello": "World"}, "Earth")
+func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotContains(t, s, contains, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//	require.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
+//	require.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
+//	require.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
+func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotContainsf(t, s, contains, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should not match.
+// This is an inverse of ElementsMatch.
+//
+// require.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false
+//
+// require.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true
+//
+// require.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true
+func NotElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotElementsMatch(t, listA, listB, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should not match.
+// This is an inverse of ElementsMatch.
+//
+// require.NotElementsMatchf(t, [1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
+//
+// require.NotElementsMatchf(t, [1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
+//
+// require.NotElementsMatchf(t, [1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
+func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotElementsMatchf(t, listA, listB, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEmpty asserts that the specified object is NOT [Empty].
+//
+//	if require.NotEmpty(t, obj) {
+//	  require.Equal(t, "two", obj[1])
+//	}
+func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEmpty(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEmptyf asserts that the specified object is NOT [Empty].
+//
+//	if require.NotEmptyf(t, obj, "error message %s", "formatted") {
+//	  require.Equal(t, "two", obj[1])
+//	}
+func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEmptyf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//	require.NotEqual(t, obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEqual(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEqualValues asserts that two objects are not equal even when converted to the same type
+//
+//	require.NotEqualValues(t, obj1, obj2)
+func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEqualValues(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
+//
+//	require.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
+func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEqualValuesf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+//	require.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotEqualf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotErrorAs asserts that none of the errors in err's chain matches target,
+// but if so, sets target to that error value.
+func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotErrorAs(t, err, target, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotErrorAsf asserts that none of the errors in err's chain matches target,
+// but if so, sets target to that error value.
+func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotErrorAsf(t, err, target, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotErrorIs asserts that none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotErrorIs(t, err, target, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotErrorIsf asserts that none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotErrorIsf(t, err, target, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotImplements asserts that an object does not implement the specified interface.
+//
+//	require.NotImplements(t, (*MyInterface)(nil), new(MyObject))
+func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotImplements(t, interfaceObject, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotImplementsf asserts that an object does not implement the specified interface.
+//
+//	require.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotImplementsf(t, interfaceObject, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//	require.NotNil(t, err)
+func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotNil(t, object, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+//	require.NotNilf(t, err, "error message %s", "formatted")
+func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotNilf(t, object, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//	require.NotPanics(t, func(){ RemainCalm() })
+func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotPanics(t, f, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//	require.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
+func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotPanicsf(t, f, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//	require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
+//	require.NotRegexp(t, "^start", "it's not starting")
+func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotRegexp(t, rx, str, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+//	require.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
+//	require.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
+func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotRegexpf(t, rx, str, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotSame asserts that two pointers do not reference the same object.
+//
+//	require.NotSame(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotSame(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotSamef asserts that two pointers do not reference the same object.
+//
+//	require.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotSamef(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotSubset asserts that the list (array, slice, or map) does NOT contain all
+// elements given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	require.NotSubset(t, [1, 3, 4], [1, 2])
+//	require.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
+//	require.NotSubset(t, [1, 3, 4], {1: "one", 2: "two"})
+//	require.NotSubset(t, {"x": 1, "y": 2}, ["z"])
+func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotSubset(t, list, subset, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
+// elements given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	require.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted")
+//	require.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
+//	require.NotSubsetf(t, [1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
+//	require.NotSubsetf(t, {"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
+func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotSubsetf(t, list, subset, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotZero(t, i, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.NotZerof(t, i, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//	require.Panics(t, func(){ GoCrazy() })
+func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Panics(t, f, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// PanicsWithError asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+//	require.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.PanicsWithError(t, errString, f, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+//	require.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.PanicsWithErrorf(t, errString, f, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//	require.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
+func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.PanicsWithValue(t, expected, f, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//	require.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.PanicsWithValuef(t, expected, f, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+//	require.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
+func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Panicsf(t, f, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Positive asserts that the specified element is positive
+//
+//	require.Positive(t, 1)
+//	require.Positive(t, 1.23)
+func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Positive(t, e, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Positivef asserts that the specified element is positive
+//
+//	require.Positivef(t, 1, "error message %s", "formatted")
+//	require.Positivef(t, 1.23, "error message %s", "formatted")
+func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Positivef(t, e, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//	require.Regexp(t, regexp.MustCompile("start"), "it's starting")
+//	require.Regexp(t, "start...$", "it's not starting")
+func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Regexp(t, rx, str, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+//	require.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
+//	require.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
+func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Regexpf(t, rx, str, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Same asserts that two pointers reference the same object.
+//
+//	require.Same(t, ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Same(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+//	require.Samef(t, ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Samef(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Subset asserts that the list (array, slice, or map) contains all elements
+// given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	require.Subset(t, [1, 2, 3], [1, 2])
+//	require.Subset(t, {"x": 1, "y": 2}, {"x": 1})
+//	require.Subset(t, [1, 2, 3], {1: "one", 2: "two"})
+//	require.Subset(t, {"x": 1, "y": 2}, ["x"])
+func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Subset(t, list, subset, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Subsetf asserts that the list (array, slice, or map) contains all elements
+// given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	require.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted")
+//	require.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
+//	require.Subsetf(t, [1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
+//	require.Subsetf(t, {"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
+func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Subsetf(t, list, subset, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// True asserts that the specified value is true.
+//
+//	require.True(t, myBool)
+func True(t TestingT, value bool, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.True(t, value, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Truef asserts that the specified value is true.
+//
+//	require.Truef(t, myBool, "error message %s", "formatted")
+func Truef(t TestingT, value bool, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Truef(t, value, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//	require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
+func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+//	require.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.WithinDurationf(t, expected, actual, delta, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// WithinRange asserts that a time is within a time range (inclusive).
+//
+//	require.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
+func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.WithinRange(t, actual, start, end, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// WithinRangef asserts that a time is within a time range (inclusive).
+//
+//	require.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
+func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.WithinRangef(t, actual, start, end, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.YAMLEqf(t, expected, actual, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Zero asserts that i is the zero value for its type.
+func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Zero(t, i, msgAndArgs...) {
+		return
+	}
+	t.FailNow()
+}
+
+// Zerof asserts that i is the zero value for its type.
+func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) {
+	if h, ok := t.(tHelper); ok {
+		h.Helper()
+	}
+	if assert.Zerof(t, i, msg, args...) {
+		return
+	}
+	t.FailNow()
+}
diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl
new file mode 100644
index 000000000..8b3283685
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl
@@ -0,0 +1,6 @@
+{{ replace .Comment "assert." "require."}}
+func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
+	if h, ok := t.(tHelper); ok { h.Helper() }
+	if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
+	t.FailNow()
+}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go
new file mode 100644
index 000000000..e6f7e9446
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go
@@ -0,0 +1,1724 @@
+// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
+
+package require
+
+import (
+	assert "github.com/stretchr/testify/assert"
+	http "net/http"
+	url "net/url"
+	time "time"
+)
+
+// Condition uses a Comparison to assert a complex condition.
+func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Condition(a.t, comp, msgAndArgs...)
+}
+
+// Conditionf uses a Comparison to assert a complex condition.
+func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Conditionf(a.t, comp, msg, args...)
+}
+
+// Contains asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//	a.Contains("Hello World", "World")
+//	a.Contains(["Hello", "World"], "World")
+//	a.Contains({"Hello": "World"}, "Hello")
+func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Contains(a.t, s, contains, msgAndArgs...)
+}
+
+// Containsf asserts that the specified string, list(array, slice...) or map contains the
+// specified substring or element.
+//
+//	a.Containsf("Hello World", "World", "error message %s", "formatted")
+//	a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
+//	a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
+func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Containsf(a.t, s, contains, msg, args...)
+}
+
+// DirExists checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	DirExists(a.t, path, msgAndArgs...)
+}
+
+// DirExistsf checks whether a directory exists in the given path. It also fails
+// if the path is a file rather a directory or there is an error checking whether it exists.
+func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	DirExistsf(a.t, path, msg, args...)
+}
+
+// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
+func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ElementsMatch(a.t, listA, listB, msgAndArgs...)
+}
+
+// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should match.
+//
+// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
+func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ElementsMatchf(a.t, listA, listB, msg, args...)
+}
+
+// Empty asserts that the given value is "empty".
+//
+// [Zero values] are "empty".
+//
+// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
+//
+// Slices, maps and channels with zero length are "empty".
+//
+// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
+//
+//	a.Empty(obj)
+//
+// [Zero values]: https://go.dev/ref/spec#The_zero_value
+func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Empty(a.t, object, msgAndArgs...)
+}
+
+// Emptyf asserts that the given value is "empty".
+//
+// [Zero values] are "empty".
+//
+// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
+//
+// Slices, maps and channels with zero length are "empty".
+//
+// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
+//
+//	a.Emptyf(obj, "error message %s", "formatted")
+//
+// [Zero values]: https://go.dev/ref/spec#The_zero_value
+func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Emptyf(a.t, object, msg, args...)
+}
+
+// Equal asserts that two objects are equal.
+//
+//	a.Equal(123, 123)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Equal(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualError asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//	actualObj, err := SomeFunction()
+//	a.EqualError(err,  expectedErrorString)
+func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualError(a.t, theError, errString, msgAndArgs...)
+}
+
+// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
+// and that it is equal to the provided error.
+//
+//	actualObj, err := SomeFunction()
+//	a.EqualErrorf(err,  expectedErrorString, "error message %s", "formatted")
+func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualErrorf(a.t, theError, errString, msg, args...)
+}
+
+// EqualExportedValues asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+//	 type S struct {
+//		Exported     	int
+//		notExported   	int
+//	 }
+//	 a.EqualExportedValues(S{1, 2}, S{1, 3}) => true
+//	 a.EqualExportedValues(S{1, 2}, S{2, 3}) => false
+func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualExportedValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualExportedValuesf asserts that the types of two objects are equal and their public
+// fields are also equal. This is useful for comparing structs that have private fields
+// that could potentially differ.
+//
+//	 type S struct {
+//		Exported     	int
+//		notExported   	int
+//	 }
+//	 a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
+//	 a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
+func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualExportedValuesf(a.t, expected, actual, msg, args...)
+}
+
+// EqualValues asserts that two objects are equal or convertible to the larger
+// type and equal.
+//
+//	a.EqualValues(uint32(123), int32(123))
+func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// EqualValuesf asserts that two objects are equal or convertible to the larger
+// type and equal.
+//
+//	a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
+func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// Equalf asserts that two objects are equal.
+//
+//	a.Equalf(123, 123, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses). Function equality
+// cannot be determined and will always fail.
+func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Equalf(a.t, expected, actual, msg, args...)
+}
+
+// Error asserts that a function returned an error (i.e. not `nil`).
+//
+//	actualObj, err := SomeFunction()
+//	a.Error(err)
+func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Error(a.t, err, msgAndArgs...)
+}
+
+// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ErrorAs(a.t, err, target, msgAndArgs...)
+}
+
+// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
+// This is a wrapper for errors.As.
+func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ErrorAsf(a.t, err, target, msg, args...)
+}
+
+// ErrorContains asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+//	actualObj, err := SomeFunction()
+//	a.ErrorContains(err,  expectedErrorSubString)
+func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ErrorContains(a.t, theError, contains, msgAndArgs...)
+}
+
+// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
+// and that the error contains the specified substring.
+//
+//	actualObj, err := SomeFunction()
+//	a.ErrorContainsf(err,  expectedErrorSubString, "error message %s", "formatted")
+func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ErrorContainsf(a.t, theError, contains, msg, args...)
+}
+
+// ErrorIs asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ErrorIs(a.t, err, target, msgAndArgs...)
+}
+
+// ErrorIsf asserts that at least one of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	ErrorIsf(a.t, err, target, msg, args...)
+}
+
+// Errorf asserts that a function returned an error (i.e. not `nil`).
+//
+//	actualObj, err := SomeFunction()
+//	a.Errorf(err, "error message %s", "formatted")
+func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Errorf(a.t, err, msg, args...)
+}
+
+// Eventually asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//	a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// EventuallyWithT asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+//	externalValue := false
+//	go func() {
+//		time.Sleep(8*time.Second)
+//		externalValue = true
+//	}()
+//	a.EventuallyWithT(func(c *assert.CollectT) {
+//		// add assertions as needed; any assertion failure will fail the current tick
+//		assert.True(c, externalValue, "expected 'externalValue' to be true")
+//	}, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
+func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// EventuallyWithTf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick. In contrast to Eventually,
+// it supplies a CollectT to the condition function, so that the condition
+// function can use the CollectT to call other assertions.
+// The condition is considered "met" if no errors are raised in a tick.
+// The supplied CollectT collects all errors from one tick (if there are any).
+// If the condition is not met before waitFor, the collected errors of
+// the last tick are copied to t.
+//
+//	externalValue := false
+//	go func() {
+//		time.Sleep(8*time.Second)
+//		externalValue = true
+//	}()
+//	a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
+//		// add assertions as needed; any assertion failure will fail the current tick
+//		assert.True(c, externalValue, "expected 'externalValue' to be true")
+//	}, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
+func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Eventuallyf asserts that given condition will be met in waitFor time,
+// periodically checking target function each tick.
+//
+//	a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Exactly asserts that two objects are equal in value and type.
+//
+//	a.Exactly(int32(123), int64(123))
+func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Exactly(a.t, expected, actual, msgAndArgs...)
+}
+
+// Exactlyf asserts that two objects are equal in value and type.
+//
+//	a.Exactlyf(int32(123), int64(123), "error message %s", "formatted")
+func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Exactlyf(a.t, expected, actual, msg, args...)
+}
+
+// Fail reports a failure through
+func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Fail(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNow fails test
+func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FailNow(a.t, failureMessage, msgAndArgs...)
+}
+
+// FailNowf fails test
+func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FailNowf(a.t, failureMessage, msg, args...)
+}
+
+// Failf reports a failure through
+func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Failf(a.t, failureMessage, msg, args...)
+}
+
+// False asserts that the specified value is false.
+//
+//	a.False(myBool)
+func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	False(a.t, value, msgAndArgs...)
+}
+
+// Falsef asserts that the specified value is false.
+//
+//	a.Falsef(myBool, "error message %s", "formatted")
+func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Falsef(a.t, value, msg, args...)
+}
+
+// FileExists checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FileExists(a.t, path, msgAndArgs...)
+}
+
+// FileExistsf checks whether a file exists in the given path. It also fails if
+// the path points to a directory or there is an error when trying to check the file.
+func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	FileExistsf(a.t, path, msg, args...)
+}
+
+// Greater asserts that the first element is greater than the second
+//
+//	a.Greater(2, 1)
+//	a.Greater(float64(2), float64(1))
+//	a.Greater("b", "a")
+func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Greater(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqual asserts that the first element is greater than or equal to the second
+//
+//	a.GreaterOrEqual(2, 1)
+//	a.GreaterOrEqual(2, 2)
+//	a.GreaterOrEqual("b", "a")
+//	a.GreaterOrEqual("b", "b")
+func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// GreaterOrEqualf asserts that the first element is greater than or equal to the second
+//
+//	a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
+//	a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
+//	a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
+//	a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	GreaterOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Greaterf asserts that the first element is greater than the second
+//
+//	a.Greaterf(2, 1, "error message %s", "formatted")
+//	a.Greaterf(float64(2), float64(1), "error message %s", "formatted")
+//	a.Greaterf("b", "a", "error message %s", "formatted")
+func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Greaterf(a.t, e1, e2, msg, args...)
+}
+
+// HTTPBodyContains asserts that a specified handler returns a
+// body that contains a string.
+//
+//	a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyContainsf asserts that a specified handler returns a
+// body that contains a string.
+//
+//	a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPBodyNotContains asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//	a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
+}
+
+// HTTPBodyNotContainsf asserts that a specified handler returns a
+// body that does not contain a string.
+//
+//	a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
+}
+
+// HTTPError asserts that a specified handler returns an error status code.
+//
+//	a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPError(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPErrorf asserts that a specified handler returns an error status code.
+//
+//	a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPErrorf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPRedirect asserts that a specified handler returns a redirect status code.
+//
+//	a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPRedirectf asserts that a specified handler returns a redirect status code.
+//
+//	a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
+}
+
+// HTTPStatusCode asserts that a specified handler returns a specified status code.
+//
+//	a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...)
+}
+
+// HTTPStatusCodef asserts that a specified handler returns a specified status code.
+//
+//	a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...)
+}
+
+// HTTPSuccess asserts that a specified handler returns a success status code.
+//
+//	a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
+}
+
+// HTTPSuccessf asserts that a specified handler returns a success status code.
+//
+//	a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
+//
+// Returns whether the assertion was successful (true) or not (false).
+func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
+}
+
+// Implements asserts that an object is implemented by the specified interface.
+//
+//	a.Implements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Implements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// Implementsf asserts that an object is implemented by the specified interface.
+//
+//	a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Implementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// InDelta asserts that the two numerals are within delta of each other.
+//
+//	a.InDelta(math.Pi, 22/7.0, 0.01)
+func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDelta(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
+func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaSlice is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// InDeltaSlicef is the same as InDelta, except it compares two slices.
+func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
+}
+
+// InDeltaf asserts that the two numerals are within delta of each other.
+//
+//	a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
+func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InDeltaf(a.t, expected, actual, delta, msg, args...)
+}
+
+// InEpsilon asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
+}
+
+// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
+func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// InEpsilonf asserts that expected and actual have a relative error less than epsilon
+func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
+}
+
+// IsDecreasing asserts that the collection is decreasing
+//
+//	a.IsDecreasing([]int{2, 1, 0})
+//	a.IsDecreasing([]float{2, 1})
+//	a.IsDecreasing([]string{"b", "a"})
+func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsDecreasing(a.t, object, msgAndArgs...)
+}
+
+// IsDecreasingf asserts that the collection is decreasing
+//
+//	a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted")
+//	a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted")
+//	a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted")
+func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsDecreasingf(a.t, object, msg, args...)
+}
+
+// IsIncreasing asserts that the collection is increasing
+//
+//	a.IsIncreasing([]int{1, 2, 3})
+//	a.IsIncreasing([]float{1, 2})
+//	a.IsIncreasing([]string{"a", "b"})
+func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsIncreasing(a.t, object, msgAndArgs...)
+}
+
+// IsIncreasingf asserts that the collection is increasing
+//
+//	a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted")
+//	a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted")
+//	a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted")
+func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsIncreasingf(a.t, object, msg, args...)
+}
+
+// IsNonDecreasing asserts that the collection is not decreasing
+//
+//	a.IsNonDecreasing([]int{1, 1, 2})
+//	a.IsNonDecreasing([]float{1, 2})
+//	a.IsNonDecreasing([]string{"a", "b"})
+func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsNonDecreasing(a.t, object, msgAndArgs...)
+}
+
+// IsNonDecreasingf asserts that the collection is not decreasing
+//
+//	a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted")
+//	a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted")
+//	a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted")
+func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsNonDecreasingf(a.t, object, msg, args...)
+}
+
+// IsNonIncreasing asserts that the collection is not increasing
+//
+//	a.IsNonIncreasing([]int{2, 1, 1})
+//	a.IsNonIncreasing([]float{2, 1})
+//	a.IsNonIncreasing([]string{"b", "a"})
+func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsNonIncreasing(a.t, object, msgAndArgs...)
+}
+
+// IsNonIncreasingf asserts that the collection is not increasing
+//
+//	a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted")
+//	a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted")
+//	a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted")
+func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsNonIncreasingf(a.t, object, msg, args...)
+}
+
+// IsNotType asserts that the specified objects are not of the same type.
+//
+//	a.IsNotType(&NotMyStruct{}, &MyStruct{})
+func (a *Assertions) IsNotType(theType interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsNotType(a.t, theType, object, msgAndArgs...)
+}
+
+// IsNotTypef asserts that the specified objects are not of the same type.
+//
+//	a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
+func (a *Assertions) IsNotTypef(theType interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsNotTypef(a.t, theType, object, msg, args...)
+}
+
+// IsType asserts that the specified objects are of the same type.
+//
+//	a.IsType(&MyStruct{}, &MyStruct{})
+func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsType(a.t, expectedType, object, msgAndArgs...)
+}
+
+// IsTypef asserts that the specified objects are of the same type.
+//
+//	a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted")
+func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	IsTypef(a.t, expectedType, object, msg, args...)
+}
+
+// JSONEq asserts that two JSON strings are equivalent.
+//
+//	a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
+func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	JSONEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// JSONEqf asserts that two JSON strings are equivalent.
+//
+//	a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
+func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	JSONEqf(a.t, expected, actual, msg, args...)
+}
+
+// Len asserts that the specified object has specific length.
+// Len also fails if the object has a type that len() not accept.
+//
+//	a.Len(mySlice, 3)
+func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Len(a.t, object, length, msgAndArgs...)
+}
+
+// Lenf asserts that the specified object has specific length.
+// Lenf also fails if the object has a type that len() not accept.
+//
+//	a.Lenf(mySlice, 3, "error message %s", "formatted")
+func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Lenf(a.t, object, length, msg, args...)
+}
+
+// Less asserts that the first element is less than the second
+//
+//	a.Less(1, 2)
+//	a.Less(float64(1), float64(2))
+//	a.Less("a", "b")
+func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Less(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqual asserts that the first element is less than or equal to the second
+//
+//	a.LessOrEqual(1, 2)
+//	a.LessOrEqual(2, 2)
+//	a.LessOrEqual("a", "b")
+//	a.LessOrEqual("b", "b")
+func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	LessOrEqual(a.t, e1, e2, msgAndArgs...)
+}
+
+// LessOrEqualf asserts that the first element is less than or equal to the second
+//
+//	a.LessOrEqualf(1, 2, "error message %s", "formatted")
+//	a.LessOrEqualf(2, 2, "error message %s", "formatted")
+//	a.LessOrEqualf("a", "b", "error message %s", "formatted")
+//	a.LessOrEqualf("b", "b", "error message %s", "formatted")
+func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	LessOrEqualf(a.t, e1, e2, msg, args...)
+}
+
+// Lessf asserts that the first element is less than the second
+//
+//	a.Lessf(1, 2, "error message %s", "formatted")
+//	a.Lessf(float64(1), float64(2), "error message %s", "formatted")
+//	a.Lessf("a", "b", "error message %s", "formatted")
+func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Lessf(a.t, e1, e2, msg, args...)
+}
+
+// Negative asserts that the specified element is negative
+//
+//	a.Negative(-1)
+//	a.Negative(-1.23)
+func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Negative(a.t, e, msgAndArgs...)
+}
+
+// Negativef asserts that the specified element is negative
+//
+//	a.Negativef(-1, "error message %s", "formatted")
+//	a.Negativef(-1.23, "error message %s", "formatted")
+func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Negativef(a.t, e, msg, args...)
+}
+
+// Never asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//	a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
+func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Never(a.t, condition, waitFor, tick, msgAndArgs...)
+}
+
+// Neverf asserts that the given condition doesn't satisfy in waitFor time,
+// periodically checking the target function each tick.
+//
+//	a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
+func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Neverf(a.t, condition, waitFor, tick, msg, args...)
+}
+
+// Nil asserts that the specified object is nil.
+//
+//	a.Nil(err)
+func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Nil(a.t, object, msgAndArgs...)
+}
+
+// Nilf asserts that the specified object is nil.
+//
+//	a.Nilf(err, "error message %s", "formatted")
+func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Nilf(a.t, object, msg, args...)
+}
+
+// NoDirExists checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoDirExists(a.t, path, msgAndArgs...)
+}
+
+// NoDirExistsf checks whether a directory does not exist in the given path.
+// It fails if the path points to an existing _directory_ only.
+func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoDirExistsf(a.t, path, msg, args...)
+}
+
+// NoError asserts that a function returned no error (i.e. `nil`).
+//
+//	  actualObj, err := SomeFunction()
+//	  if a.NoError(err) {
+//		   assert.Equal(t, expectedObj, actualObj)
+//	  }
+func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoError(a.t, err, msgAndArgs...)
+}
+
+// NoErrorf asserts that a function returned no error (i.e. `nil`).
+//
+//	  actualObj, err := SomeFunction()
+//	  if a.NoErrorf(err, "error message %s", "formatted") {
+//		   assert.Equal(t, expectedObj, actualObj)
+//	  }
+func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoErrorf(a.t, err, msg, args...)
+}
+
+// NoFileExists checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoFileExists(a.t, path, msgAndArgs...)
+}
+
+// NoFileExistsf checks whether a file does not exist in a given path. It fails
+// if the path points to an existing _file_ only.
+func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NoFileExistsf(a.t, path, msg, args...)
+}
+
+// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//	a.NotContains("Hello World", "Earth")
+//	a.NotContains(["Hello", "World"], "Earth")
+//	a.NotContains({"Hello": "World"}, "Earth")
+func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotContains(a.t, s, contains, msgAndArgs...)
+}
+
+// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
+// specified substring or element.
+//
+//	a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
+//	a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
+//	a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
+func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotContainsf(a.t, s, contains, msg, args...)
+}
+
+// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should not match.
+// This is an inverse of ElementsMatch.
+//
+// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false
+//
+// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true
+//
+// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true
+func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotElementsMatch(a.t, listA, listB, msgAndArgs...)
+}
+
+// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
+// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
+// the number of appearances of each of them in both lists should not match.
+// This is an inverse of ElementsMatch.
+//
+// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
+//
+// a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
+//
+// a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
+func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotElementsMatchf(a.t, listA, listB, msg, args...)
+}
+
+// NotEmpty asserts that the specified object is NOT [Empty].
+//
+//	if a.NotEmpty(obj) {
+//	  assert.Equal(t, "two", obj[1])
+//	}
+func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEmpty(a.t, object, msgAndArgs...)
+}
+
+// NotEmptyf asserts that the specified object is NOT [Empty].
+//
+//	if a.NotEmptyf(obj, "error message %s", "formatted") {
+//	  assert.Equal(t, "two", obj[1])
+//	}
+func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEmptyf(a.t, object, msg, args...)
+}
+
+// NotEqual asserts that the specified values are NOT equal.
+//
+//	a.NotEqual(obj1, obj2)
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEqual(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualValues asserts that two objects are not equal even when converted to the same type
+//
+//	a.NotEqualValues(obj1, obj2)
+func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEqualValues(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
+//
+//	a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted")
+func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEqualValuesf(a.t, expected, actual, msg, args...)
+}
+
+// NotEqualf asserts that the specified values are NOT equal.
+//
+//	a.NotEqualf(obj1, obj2, "error message %s", "formatted")
+//
+// Pointer variable equality is determined based on the equality of the
+// referenced values (as opposed to the memory addresses).
+func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotEqualf(a.t, expected, actual, msg, args...)
+}
+
+// NotErrorAs asserts that none of the errors in err's chain matches target,
+// but if so, sets target to that error value.
+func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotErrorAs(a.t, err, target, msgAndArgs...)
+}
+
+// NotErrorAsf asserts that none of the errors in err's chain matches target,
+// but if so, sets target to that error value.
+func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotErrorAsf(a.t, err, target, msg, args...)
+}
+
+// NotErrorIs asserts that none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotErrorIs(a.t, err, target, msgAndArgs...)
+}
+
+// NotErrorIsf asserts that none of the errors in err's chain matches target.
+// This is a wrapper for errors.Is.
+func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotErrorIsf(a.t, err, target, msg, args...)
+}
+
+// NotImplements asserts that an object does not implement the specified interface.
+//
+//	a.NotImplements((*MyInterface)(nil), new(MyObject))
+func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotImplements(a.t, interfaceObject, object, msgAndArgs...)
+}
+
+// NotImplementsf asserts that an object does not implement the specified interface.
+//
+//	a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
+func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotImplementsf(a.t, interfaceObject, object, msg, args...)
+}
+
+// NotNil asserts that the specified object is not nil.
+//
+//	a.NotNil(err)
+func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotNil(a.t, object, msgAndArgs...)
+}
+
+// NotNilf asserts that the specified object is not nil.
+//
+//	a.NotNilf(err, "error message %s", "formatted")
+func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotNilf(a.t, object, msg, args...)
+}
+
+// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//	a.NotPanics(func(){ RemainCalm() })
+func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotPanics(a.t, f, msgAndArgs...)
+}
+
+// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
+//
+//	a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
+func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotPanicsf(a.t, f, msg, args...)
+}
+
+// NotRegexp asserts that a specified regexp does not match a string.
+//
+//	a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
+//	a.NotRegexp("^start", "it's not starting")
+func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotRegexp(a.t, rx, str, msgAndArgs...)
+}
+
+// NotRegexpf asserts that a specified regexp does not match a string.
+//
+//	a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
+//	a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotRegexpf(a.t, rx, str, msg, args...)
+}
+
+// NotSame asserts that two pointers do not reference the same object.
+//
+//	a.NotSame(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotSame(a.t, expected, actual, msgAndArgs...)
+}
+
+// NotSamef asserts that two pointers do not reference the same object.
+//
+//	a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotSamef(a.t, expected, actual, msg, args...)
+}
+
+// NotSubset asserts that the list (array, slice, or map) does NOT contain all
+// elements given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	a.NotSubset([1, 3, 4], [1, 2])
+//	a.NotSubset({"x": 1, "y": 2}, {"z": 3})
+//	a.NotSubset([1, 3, 4], {1: "one", 2: "two"})
+//	a.NotSubset({"x": 1, "y": 2}, ["z"])
+func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotSubset(a.t, list, subset, msgAndArgs...)
+}
+
+// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
+// elements given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
+//	a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
+//	a.NotSubsetf([1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
+//	a.NotSubsetf({"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
+func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotSubsetf(a.t, list, subset, msg, args...)
+}
+
+// NotZero asserts that i is not the zero value for its type.
+func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotZero(a.t, i, msgAndArgs...)
+}
+
+// NotZerof asserts that i is not the zero value for its type.
+func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	NotZerof(a.t, i, msg, args...)
+}
+
+// Panics asserts that the code inside the specified PanicTestFunc panics.
+//
+//	a.Panics(func(){ GoCrazy() })
+func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Panics(a.t, f, msgAndArgs...)
+}
+
+// PanicsWithError asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+//	a.PanicsWithError("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	PanicsWithError(a.t, errString, f, msgAndArgs...)
+}
+
+// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
+// panics, and that the recovered panic value is an error that satisfies the
+// EqualError comparison.
+//
+//	a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	PanicsWithErrorf(a.t, errString, f, msg, args...)
+}
+
+// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//	a.PanicsWithValue("crazy error", func(){ GoCrazy() })
+func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	PanicsWithValue(a.t, expected, f, msgAndArgs...)
+}
+
+// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
+// the recovered panic value equals the expected panic value.
+//
+//	a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	PanicsWithValuef(a.t, expected, f, msg, args...)
+}
+
+// Panicsf asserts that the code inside the specified PanicTestFunc panics.
+//
+//	a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
+func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Panicsf(a.t, f, msg, args...)
+}
+
+// Positive asserts that the specified element is positive
+//
+//	a.Positive(1)
+//	a.Positive(1.23)
+func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Positive(a.t, e, msgAndArgs...)
+}
+
+// Positivef asserts that the specified element is positive
+//
+//	a.Positivef(1, "error message %s", "formatted")
+//	a.Positivef(1.23, "error message %s", "formatted")
+func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Positivef(a.t, e, msg, args...)
+}
+
+// Regexp asserts that a specified regexp matches a string.
+//
+//	a.Regexp(regexp.MustCompile("start"), "it's starting")
+//	a.Regexp("start...$", "it's not starting")
+func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Regexp(a.t, rx, str, msgAndArgs...)
+}
+
+// Regexpf asserts that a specified regexp matches a string.
+//
+//	a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
+//	a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
+func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Regexpf(a.t, rx, str, msg, args...)
+}
+
+// Same asserts that two pointers reference the same object.
+//
+//	a.Same(ptr1, ptr2)
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Same(a.t, expected, actual, msgAndArgs...)
+}
+
+// Samef asserts that two pointers reference the same object.
+//
+//	a.Samef(ptr1, ptr2, "error message %s", "formatted")
+//
+// Both arguments must be pointer variables. Pointer variable sameness is
+// determined based on the equality of both type and value.
+func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Samef(a.t, expected, actual, msg, args...)
+}
+
+// Subset asserts that the list (array, slice, or map) contains all elements
+// given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	a.Subset([1, 2, 3], [1, 2])
+//	a.Subset({"x": 1, "y": 2}, {"x": 1})
+//	a.Subset([1, 2, 3], {1: "one", 2: "two"})
+//	a.Subset({"x": 1, "y": 2}, ["x"])
+func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Subset(a.t, list, subset, msgAndArgs...)
+}
+
+// Subsetf asserts that the list (array, slice, or map) contains all elements
+// given in the subset (array, slice, or map).
+// Map elements are key-value pairs unless compared with an array or slice where
+// only the map key is evaluated.
+//
+//	a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
+//	a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
+//	a.Subsetf([1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
+//	a.Subsetf({"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
+func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Subsetf(a.t, list, subset, msg, args...)
+}
+
+// True asserts that the specified value is true.
+//
+//	a.True(myBool)
+func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	True(a.t, value, msgAndArgs...)
+}
+
+// Truef asserts that the specified value is true.
+//
+//	a.Truef(myBool, "error message %s", "formatted")
+func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Truef(a.t, value, msg, args...)
+}
+
+// WithinDuration asserts that the two times are within duration delta of each other.
+//
+//	a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
+func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
+}
+
+// WithinDurationf asserts that the two times are within duration delta of each other.
+//
+//	a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
+func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	WithinDurationf(a.t, expected, actual, delta, msg, args...)
+}
+
+// WithinRange asserts that a time is within a time range (inclusive).
+//
+//	a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
+func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	WithinRange(a.t, actual, start, end, msgAndArgs...)
+}
+
+// WithinRangef asserts that a time is within a time range (inclusive).
+//
+//	a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
+func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	WithinRangef(a.t, actual, start, end, msg, args...)
+}
+
+// YAMLEq asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	YAMLEq(a.t, expected, actual, msgAndArgs...)
+}
+
+// YAMLEqf asserts that two YAML strings are equivalent.
+func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	YAMLEqf(a.t, expected, actual, msg, args...)
+}
+
+// Zero asserts that i is the zero value for its type.
+func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Zero(a.t, i, msgAndArgs...)
+}
+
+// Zerof asserts that i is the zero value for its type.
+func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {
+	if h, ok := a.t.(tHelper); ok {
+		h.Helper()
+	}
+	Zerof(a.t, i, msg, args...)
+}
diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
new file mode 100644
index 000000000..54124df1d
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
@@ -0,0 +1,5 @@
+{{.CommentWithoutT "a"}}
+func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
+	if h, ok := a.t.(tHelper); ok { h.Helper() }
+	{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
+}
diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go
new file mode 100644
index 000000000..6b7ce929e
--- /dev/null
+++ b/vendor/github.com/stretchr/testify/require/requirements.go
@@ -0,0 +1,29 @@
+package require
+
+// TestingT is an interface wrapper around *testing.T
+type TestingT interface {
+	Errorf(format string, args ...interface{})
+	FailNow()
+}
+
+type tHelper = interface {
+	Helper()
+}
+
+// ComparisonAssertionFunc is a common function prototype when comparing two values.  Can be useful
+// for table driven tests.
+type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
+
+// ValueAssertionFunc is a common function prototype when validating a single value.  Can be useful
+// for table driven tests.
+type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
+
+// BoolAssertionFunc is a common function prototype when validating a bool value.  Can be useful
+// for table driven tests.
+type BoolAssertionFunc func(TestingT, bool, ...interface{})
+
+// ErrorAssertionFunc is a common function prototype when validating an error value.  Can be useful
+// for table driven tests.
+type ErrorAssertionFunc func(TestingT, error, ...interface{})
+
+//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs"
diff --git a/vendor/github.com/testcontainers/testcontainers-go/.gitignore b/vendor/github.com/testcontainers/testcontainers-go/.gitignore
new file mode 100644
index 000000000..c13cb1fb4
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/.gitignore
@@ -0,0 +1,33 @@
+# Generated by golang tooling
+debug.test
+vendor
+
+# Generated docs
+site/
+.direnv/
+src/mkdocs-codeinclude-plugin
+src/pip-delete-this-directory.txt
+.idea/
+.build/
+.DS_Store
+
+TEST-*.xml
+
+**/go.work
+
+# VS Code settings
+.vscode
+
+# Environment variables
+.env
+
+# Coverage files
+coverage.out
+
+# Usage metrics script binary
+usage-metrics/scripts/collect-metrics
+
+# Gas Town / Claude Code agent artifacts
+.beads/
+.claude/
+.runtime/
diff --git a/vendor/github.com/testcontainers/testcontainers-go/.golangci.yml b/vendor/github.com/testcontainers/testcontainers-go/.golangci.yml
new file mode 100644
index 000000000..bd3e9de7b
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/.golangci.yml
@@ -0,0 +1,120 @@
+formatters:
+  enable:
+    - gci
+    - gofumpt
+  settings:
+    gci:
+      sections:
+        - standard
+        - default
+        - prefix(github.com/testcontainers)
+
+linters:
+  enable:
+    - errorlint
+    - gocritic
+    - govet
+    - misspell
+    - nakedret
+    - nolintlint
+    - perfsprint
+    - prealloc
+    - revive
+    - testifylint
+    - thelper
+    - usestdlibvars
+  exclusions:
+    rules:
+      - linters:
+          - revive
+        path: "^exec/"
+        text: "var-naming: avoid package names that conflict with Go standard library package names"
+      - linters:
+          - revive
+        path: "^log/"
+        text: "var-naming: avoid package names that conflict with Go standard library package names"
+      - linters:
+          - revive
+        path: "modulegen/internal/(context|template)/"
+        text: "var-naming: avoid package names that conflict with Go standard library package names"
+      - linters:
+          - revive
+        path: "internal/sdk/types/"
+        text: "var-naming: avoid meaningless package names"
+      - linters:
+          - revive
+        path: "gcloud/internal/shared/"
+        text: "var-naming: avoid meaningless package names"
+    presets:
+      - comments
+      - common-false-positives
+      - legacy
+      - std-error-handling
+  settings:
+    errorlint:
+      asserts: true
+      comparison: true
+      errorf: true
+      errorf-multi: true
+    govet:
+      disable:
+        - fieldalignment
+        - shadow
+      enable-all: true
+    revive:
+      rules:
+        - name: blank-imports
+        - name: context-as-argument
+          arguments:
+            - allowTypesBefore: '*testing.T'
+        - name: context-keys-type
+        - name: dot-imports
+        - name: early-return
+          arguments:
+            - preserveScope
+        - name: empty-block
+        - name: error-naming
+          disabled: true
+        - name: error-return
+        - name: error-strings
+          disabled: true
+        - name: errorf
+        - name: increment-decrement
+        - name: indent-error-flow
+          arguments:
+            - preserveScope
+        - name: range
+        - name: receiver-naming
+        - name: redefines-builtin-id
+          disabled: true
+        - name: superfluous-else
+          arguments:
+            - preserveScope
+        - name: time-naming
+        - name: unexported-return
+          disabled: true
+        - name: unreachable-code
+        - name: unused-parameter
+        - name: use-any
+        - name: var-declaration
+        - name: var-naming
+          arguments:
+            - - ID
+            - - VM
+            - - upperCaseConst: true
+    staticcheck:
+      checks:
+        - all
+    testifylint:
+      disable:
+        - float-compare
+        - go-require
+      enable-all: true
+output:
+  formats:
+    text:
+      path: stdout
+run:
+  relative-path-mode: gitroot
+
+version: "2"
diff --git a/vendor/github.com/testcontainers/testcontainers-go/.mockery.yaml b/vendor/github.com/testcontainers/testcontainers-go/.mockery.yaml
new file mode 100644
index 000000000..2f96829f2
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/.mockery.yaml
@@ -0,0 +1,11 @@
+quiet: True
+disable-version-string: True
+with-expecter: True
+mockname: "mock{{.InterfaceName}}"
+filename: "{{ .InterfaceName | lower }}_mock_test.go"
+outpkg: "{{.PackageName}}_test"
+dir: "{{.InterfaceDir}}"
+packages:
+  github.com/testcontainers/testcontainers-go/wait:
+    interfaces:
+      StrategyTarget:
diff --git a/vendor/github.com/testcontainers/testcontainers-go/AI.md b/vendor/github.com/testcontainers/testcontainers-go/AI.md
new file mode 100644
index 000000000..f90971bb8
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/AI.md
@@ -0,0 +1,229 @@
+# AI Coding Agent Guidelines
+
+This document provides guidelines for AI coding agents working on the Testcontainers for Go repository.
+
+## Repository Overview
+
+This is a **Go monorepo** containing:
+- **Core library**: Root directory contains the main testcontainers-go library
+- **Modules**: `./modules/` directory with 50+ technology-specific modules (postgres, redis, kafka, etc.)
+- **Examples**: `./examples/` directory with example implementations
+- **Module generator**: `./modulegen/` directory with tools to generate new modules
+- **Documentation**: `./docs/` directory with MkDocs-based documentation
+
+## Environment Setup
+
+### Go Version
+- **Required**: Go 1.25.9
+- **Tool**: Use [gvm](https://github.com/andrewkroh/gvm) for version management
+- **CRITICAL**: Always run this before ANY Go command:
+  ```bash
+  # For Apple Silicon (M1/M2/M3)
+  eval "$(gvm 1.25.9 --arch=arm64)"
+
+  # For Intel/AMD (x86_64)
+  eval "$(gvm 1.25.9 --arch=amd64)"
+  ```
+
+### Project Structure
+Each module in `./modules/` is a separate Go module with:
+- `go.mod` / `go.sum` - Module dependencies
+- `{module}.go` - Main module implementation
+- `{module}_test.go` - Unit tests
+- `examples_test.go` - Testable examples for documentation
+- `Makefile` - Standard targets: `pre-commit`, `test-unit`
+
+## Development Workflow
+
+### Before Making Changes
+1. **Read existing code** in similar modules for patterns
+2. **Check documentation** in `docs/modules/index.md` for best practices
+3. **Run tests** to ensure baseline passes
+
+### Working with Modules
+1. **Change to module directory**: `cd modules/{module-name}`
+2. **Run pre-commit checks**: `make pre-commit` (linting, formatting, tidy)
+3. **Run tests**: `make test-unit`
+4. **Both together**: `make pre-commit test-unit`
+
+### Git Workflow
+- **Branch naming**: Use descriptive names like `chore-module-use-run`, `feat-add-xyz`, `fix-module-issue`
+  - **NEVER** use `main` branch for PRs (they will be auto-closed)
+- **Commit format**: Conventional commits (enforced by CI)
+  ```text
+  type(scope): description
+
+  Longer explanation if needed.
+
+  🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+  Co-Authored-By: Claude <noreply@anthropic.com>
+  ```
+- **Commit types** (enforced): `security`, `fix`, `feat`, `docs`, `chore`, `deps`
+- **Scope rules**:
+  - Optional (can be omitted for repo-level changes)
+  - Must be lowercase (uppercase scopes are rejected)
+  - Examples: `feat(redis)`, `chore(kafka)`, `docs`, `fix(postgres)`
+- **Subject rules**:
+  - Must NOT start with uppercase letter
+  - ✅ Good: `feat(redis): add support for clustering`
+  - ❌ Bad: `feat(redis): Add support for clustering`
+- **Breaking changes**: Add `!` after type: `feat(redis)!: remove deprecated API`
+- **Always include co-author footer** when AI assists with changes
+
+### Pull Requests
+- **Title format**: Same as commit format (validated by CI)
+  - `type(scope): description`
+  - Examples: `feat(redis): add clustering support`, `docs: improve module guide`, `chore(kafka): update tests`
+- **Title validation** enforced by `.github/workflows/conventions.yml`
+- **Labels**: Use appropriate labels (`chore`, `breaking change`, `documentation`, etc.)
+- **Body template**:
+  ```markdown
+  ## What does this PR do?
+
+  Brief description of changes.
+
+  ## Why is it important?
+
+  Context and rationale.
+
+  ## Related issues
+
+  - Relates to #issue-number
+  ```
+
+## Module Development Best Practices
+
+**📖 Detailed guide**: See [`docs/modules/index.md`](docs/modules/index.md) for comprehensive module development documentation.
+
+### Quick Reference
+
+#### Container Struct
+- **Name**: Use `Container`, not module-specific names like `PostgresContainer`
+- **Fields**: Use private fields for state management
+- **Embedding**: Always embed `testcontainers.Container`
+
+```go
+type Container struct {
+    testcontainers.Container
+    dbName   string  // private
+    user     string  // private
+}
+```
+
+#### Run Function Pattern
+Five-step implementation:
+1. Process custom options (if using intermediate settings)
+2. Build `moduleOpts` with defaults
+3. Add conditional options based on settings
+4. Append user options (allows overrides)
+5. Call `testcontainers.Run` and return with proper error wrapping
+
+```go
+func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) {
+    // See docs/modules/index.md for complete implementation
+    moduleOpts := []testcontainers.ContainerCustomizer{
+        testcontainers.WithExposedPorts("5432/tcp"),
+        // ... defaults
+    }
+    moduleOpts = append(moduleOpts, opts...)
+
+    ctr, err := testcontainers.Run(ctx, img, moduleOpts...)
+    if err != nil {
+        return nil, fmt.Errorf("run modulename: %w", err)
+    }
+    return &Container{Container: ctr}, nil
+}
+```
+
+#### Container Options
+- **Simple config**: Use built-in `testcontainers.With*` options
+- **Complex logic**: Use `testcontainers.CustomizeRequestOption`
+- **State transfer**: Create custom `Option` type
+
+**Critical rules:**
+- ✅ Return struct types (not interfaces)
+- ✅ Call built-in options directly: `testcontainers.WithFiles(f)(req)`
+- ❌ Don't use `.Customize()` method
+- ❌ Don't pass slices to variadic functions
+
+#### Common Patterns
+- **Env inspection**: Use `strings.CutPrefix` with early exit
+- **Variadic args**: Pass directly, not as slices
+- **Option order**: defaults → user options → post-processing
+- **Error format**: `fmt.Errorf("run modulename: %w", err)`
+
+**For complete examples and detailed explanations**, see [`docs/modules/index.md`](docs/modules/index.md).
+
+## Testing Guidelines
+
+### Running Tests
+- **From module directory**: `cd modules/{module} && make test-unit`
+- **Pre-commit checks**: `make pre-commit` (run this first to catch lint issues)
+- **Full check**: `make pre-commit test-unit`
+
+### Test Patterns
+- Use testable examples in `examples_test.go`
+- Follow existing test patterns in similar modules
+- Test both success and error cases
+- Use `t.Parallel()` when tests are independent
+
+### When Tests Fail
+1. **Read the error message carefully** - it usually tells you exactly what's wrong
+2. **Check if it's a lint issue** - run `make pre-commit` first
+3. **Verify Go version** - ensure using Go 1.25.9
+4. **Check Docker** - some tests require Docker daemon running
+
+## Common Pitfalls to Avoid
+
+### Code Issues
+- ❌ Using interface types as return values
+- ❌ Forgetting to run `eval "$(gvm 1.25.9 --arch=arm64)"`
+- ❌ Not handling errors from built-in options
+- ❌ Using module-specific container names (`PostgresContainer`)
+- ❌ Calling `.Customize()` method instead of direct function call
+
+### Git Issues
+- ❌ Forgetting co-author footer in commits
+- ❌ Not running tests before committing
+- ❌ Committing files outside module scope (use `git add modules/{module}/`)
+- ❌ Using uppercase in scope: `feat(Redis)` → use `feat(redis)`
+- ❌ Starting subject with uppercase: `fix: Add feature` → use `fix: add feature`
+- ❌ Using wrong commit type (only: `security`, `fix`, `feat`, `docs`, `chore`, `deps`)
+- ❌ Creating PR from `main` branch (will be auto-closed)
+
+### Testing Issues
+- ❌ Running tests without pre-commit checks first
+- ❌ Not changing to module directory before running make
+- ❌ Forgetting to set Go version before testing
+
+## Reference Documentation
+
+For detailed information, see:
+- **Module development**: `docs/modules/index.md` - Comprehensive best practices
+- **Contributing**: `docs/contributing.md` - General contribution guidelines
+- **Modules catalog**: [testcontainers.com/modules](https://testcontainers.com/modules/?language=go)
+- **API docs**: [pkg.go.dev/github.com/testcontainers/testcontainers-go](https://pkg.go.dev/github.com/testcontainers/testcontainers-go)
+
+## Module Generator
+
+To create a new module:
+
+```bash
+cd modulegen
+go run . new module --name mymodule --image "docker.io/myimage:tag"
+```
+
+This generates:
+- Module scaffolding with proper structure
+- Documentation template
+- Test files with examples
+- Makefile with standard targets
+
+The generator uses templates in `modulegen/_template/` that follow current best practices.
+
+## Need Help?
+
+- **Slack**: [testcontainers.slack.com](https://slack.testcontainers.org/)
+- **GitHub Discussions**: [github.com/testcontainers/testcontainers-go/discussions](https://github.com/testcontainers/testcontainers-go/discussions)
+- **Issues**: Check existing issues or create a new one with detailed context
diff --git a/vendor/github.com/testcontainers/testcontainers-go/CONTRIBUTING.md b/vendor/github.com/testcontainers/testcontainers-go/CONTRIBUTING.md
new file mode 100644
index 000000000..4736297eb
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/CONTRIBUTING.md
@@ -0,0 +1,13 @@
+# Contributing
+
+Please see the [main contributing guidelines](./docs/contributing.md).
+
+There are additional docs describing [contributing documentation changes](./docs/contributing.md).
+
+### GitHub Sponsorship
+
+Testcontainers is [in the GitHub Sponsors program](https://github.com/sponsors/testcontainers)!
+
+This repository is supported by our sponsors, meaning that issues are eligible to have a 'bounty' attached to them by sponsors.
+
+Please see [the bounty policy page](https://golang.testcontainers.org/bounty) if you are interested, either as a sponsor or as a contributor.
diff --git a/vendor/github.com/testcontainers/testcontainers-go/LICENSE b/vendor/github.com/testcontainers/testcontainers-go/LICENSE
new file mode 100644
index 000000000..607a9c3c4
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017-2019 Gianluca Arbezzano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/testcontainers/testcontainers-go/Makefile b/vendor/github.com/testcontainers/testcontainers-go/Makefile
new file mode 100644
index 000000000..5b7c50001
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/Makefile
@@ -0,0 +1,93 @@
+include ./commons-test.mk
+
+.PHONY: lint-all
+lint-all:
+	$(MAKE) lint
+	$(MAKE) -C modulegen lint
+	$(MAKE) -C examples lint-examples
+	$(MAKE) -C modules lint-modules
+
+.PHONY: test-all
+test-all: tools test-tools test-unit
+
+.PHONY: test-examples
+test-examples:
+	@echo "Running example tests..."
+	$(MAKE) -C examples test
+
+.PHONY: tidy-all
+tidy-all:
+	$(MAKE) tidy
+	$(MAKE) -C examples tidy-examples
+	$(MAKE) -C modules tidy-modules
+
+## --------------------------------------
+
+DOCS_CONTAINER=mkdocs-container
+DOCS_IMAGE=python:3.13
+
+.PHONY: clean-docs
+clean-docs:
+	@echo "Destroying docs"
+	docker rm -f $(DOCS_CONTAINER) || true
+
+.PHONY: serve-docs
+serve-docs:
+	docker run --rm --name $(DOCS_CONTAINER) -it -p 8000:8000 \
+		-v $(PWD):/testcontainers-go \
+		-w /testcontainers-go \
+		$(DOCS_IMAGE) bash -c "pip install -Ur requirements.txt && mkdocs serve -f mkdocs.yml -a 0.0.0.0:8000"
+
+## --------------------------------------
+
+# Compose tests: Make goals to test the compose module against the latest versions of the compose and compose-go repositories.
+#
+# The following goals are available:
+#
+# - compose-clean: Clean the .build directory, and clean the go.mod and go.sum files in the testcontainers-go compose module.
+# - compose-clone: Clone the compose and compose-go repositories into the .build directory.
+# - compose-replace: Replace the docker/compose/v5 dependency in the testcontainers-go compose module with the local copy.
+# - compose-spec-replace: Replace the compose-spec/compose-go/v2 dependency in the testcontainers-go compose module with the local copy.
+# - compose-tidy: Run "go mod tidy" in the testcontainers-go compose module.
+# - compose-test-all-latest: Test the testcontainers-go compose module against the latest versions of the compose and compose-go repositories.
+# - compose-test-latest: Test the testcontainers-go compose module against the latest version of the compose repository, using current version of the compose-spec repository.
+# - compose-test-spec-latest: Test the testcontainers-go compose module against the latest version of the compose-spec repository, using current version of the compose repository.
+
+.PHONY: compose-clean
+compose-clean:
+	rm -rf .build
+	cd modules/compose && git checkout -- go.mod go.sum
+
+.PHONY: compose-clone
+compose-clone: compose-clean
+	mkdir .build
+	git clone https://github.com/compose-spec/compose-go.git .build/compose-go & \
+	git clone https://github.com/docker/compose.git .build/compose
+	wait
+
+.PHONY: compose-replace
+compose-replace:
+	cd modules/compose && echo "replace github.com/docker/compose/v5 => ../../.build/compose" >> go.mod
+
+.PHONY: compose-spec-replace
+compose-spec-replace:
+	cd modules/compose && echo "replace github.com/compose-spec/compose-go/v2 => ../../.build/compose-go" >> go.mod
+
+.PHONY: compose-tidy
+compose-tidy:
+	cd modules/compose && go mod tidy
+
+# The following three goals are used in the GitHub Actions workflow to test the compose module against the latest versions of the compose and compose-spec repositories.
+# Please update the 'docker-projects-latest' workflow if you are making any changes to these goals.
+
+.PHONY: compose-test-all-latest
+compose-test-all-latest: compose-clone compose-replace compose-spec-replace compose-tidy
+	make -C modules/compose test-compose
+
+.PHONY: compose-test-latest
+compose-test-latest: compose-clone compose-replace compose-tidy
+	make -C modules/compose test-compose
+
+.PHONY: compose-test-spec-latest
+compose-test-spec-latest: compose-clone compose-spec-replace compose-tidy
+	make -C modules/compose test-compose
diff --git a/vendor/github.com/testcontainers/testcontainers-go/Pipfile b/vendor/github.com/testcontainers/testcontainers-go/Pipfile
new file mode 100644
index 000000000..ca5c98c2a
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/Pipfile
@@ -0,0 +1,16 @@
+[[source]]
+name = "pypi"
+url = "https://pypi.org/simple"
+verify_ssl = true
+
+[dev-packages]
+
+[packages]
+mkdocs = "==1.5.3"
+mkdocs-codeinclude-plugin = "==0.3.1"
+mkdocs-include-markdown-plugin = "==7.3.0"
+mkdocs-material = "==9.5.18"
+mkdocs-markdownextradata-plugin = "==0.2.6"
+
+[requires]
+python_version = "3.13"
diff --git a/vendor/github.com/testcontainers/testcontainers-go/Pipfile.lock b/vendor/github.com/testcontainers/testcontainers-go/Pipfile.lock
new file mode 100644
index 000000000..2a6138cc7
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/Pipfile.lock
@@ -0,0 +1,706 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "9836de74487210f57ac1040d06b403490e5171be35a8b5816a5361b4a2d02e01"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3.8"
+        },
+        "sources": [
+            {
+                "name": "pypi",
+                "url": "https://pypi.org/simple",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "babel": {
+            "hashes": [
+                "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363",
+                "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==2.14.0"
+        },
+        "bracex": {
+            "hashes": [
+                "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952",
+                "sha256:98f1347cd77e22ee8d967a30ad4e310b233f7754dbf31ff3fceb76145ba47dc7"
+            ],
+            "markers": "python_version >= '3.9'",
+            "version": "==2.6"
+        },
+        "certifi": {
+            "hashes": [
+                "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa",
+                "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==2026.2.25"
+        },
+        "charset-normalizer": {
+            "hashes": [
+                "sha256:06a7e86163334edfc5d20fe104db92fcd666e5a5df0977cb5680a506fe26cc8e",
+                "sha256:0c173ce3a681f309f31b87125fecec7a5d1347261ea11ebbb856fa6006b23c8c",
+                "sha256:0e28d62a8fc7a1fa411c43bd65e346f3bce9716dc51b897fbe930c5987b402d5",
+                "sha256:0e901eb1049fdb80f5bd11ed5ea1e498ec423102f7a9b9e4645d5b8204ff2815",
+                "sha256:11afb56037cbc4b1555a34dd69151e8e069bee82e613a73bef6e714ce733585f",
+                "sha256:150b8ce8e830eb7ccb029ec9ca36022f756986aaaa7956aad6d9ec90089338c0",
+                "sha256:172985e4ff804a7ad08eebec0a1640ece87ba5041d565fff23c8f99c1f389484",
+                "sha256:197c1a244a274bb016dd8b79204850144ef77fe81c5b797dc389327adb552407",
+                "sha256:1ae6b62897110aa7c79ea2f5dd38d1abca6db663687c0b1ad9aed6f6bae3d9d6",
+                "sha256:1cf0a70018692f85172348fe06d3a4b63f94ecb055e13a00c644d368eb82e5b8",
+                "sha256:1ed80ff870ca6de33f4d953fda4d55654b9a2b340ff39ab32fa3adbcd718f264",
+                "sha256:22c6f0c2fbc31e76c3b8a86fba1a56eda6166e238c29cdd3d14befdb4a4e4815",
+                "sha256:231d4da14bcd9301310faf492051bee27df11f2bc7549bc0bb41fef11b82daa2",
+                "sha256:259695e2ccc253feb2a016303543d691825e920917e31f894ca1a687982b1de4",
+                "sha256:2a24157fa36980478dd1770b585c0f30d19e18f4fb0c47c13aa568f871718579",
+                "sha256:2b1a63e8224e401cafe7739f77efd3f9e7f5f2026bda4aead8e59afab537784f",
+                "sha256:2bd9d128ef93637a5d7a6af25363cf5dec3fa21cf80e68055aad627f280e8afa",
+                "sha256:2e1d8ca8611099001949d1cdfaefc510cf0f212484fe7c565f735b68c78c3c95",
+                "sha256:2ef7fedc7a6ecbe99969cd09632516738a97eeb8bd7258bf8a0f23114c057dab",
+                "sha256:2f7fdd9b6e6c529d6a2501a2d36b240109e78a8ceaef5687cfcfa2bbe671d297",
+                "sha256:30f445ae60aad5e1f8bdbb3108e39f6fbc09f4ea16c815c66578878325f8f15a",
+                "sha256:31215157227939b4fb3d740cd23fe27be0439afef67b785a1eb78a3ae69cba9e",
+                "sha256:34315ff4fc374b285ad7f4a0bf7dcbfe769e1b104230d40f49f700d4ab6bbd84",
+                "sha256:3516bbb8d42169de9e61b8520cbeeeb716f12f4ecfe3fd30a9919aa16c806ca8",
+                "sha256:3778fd7d7cd04ae8f54651f4a7a0bd6e39a0cf20f801720a4c21d80e9b7ad6b0",
+                "sha256:39f5068d35621da2881271e5c3205125cc456f54e9030d3f723288c873a71bf9",
+                "sha256:404a1e552cf5b675a87f0651f8b79f5f1e6fd100ee88dc612f89aa16abd4486f",
+                "sha256:419a9d91bd238052642a51938af8ac05da5b3343becde08d5cdeab9046df9ee1",
+                "sha256:423fb7e748a08f854a08a222b983f4df1912b1daedce51a72bd24fe8f26a1843",
+                "sha256:4482481cb0572180b6fd976a4d5c72a30263e98564da68b86ec91f0fe35e8565",
+                "sha256:461598cd852bfa5a61b09cae2b1c02e2efcd166ee5516e243d540ac24bfa68a7",
+                "sha256:47955475ac79cc504ef2704b192364e51d0d473ad452caedd0002605f780101c",
+                "sha256:48696db7f18afb80a068821504296eb0787d9ce239b91ca15059d1d3eaacf13b",
+                "sha256:4be9f4830ba8741527693848403e2c457c16e499100963ec711b1c6f2049b7c7",
+                "sha256:4d1d02209e06550bdaef34af58e041ad71b88e624f5d825519da3a3308e22687",
+                "sha256:4f41da960b196ea355357285ad1316a00099f22d0929fe168343b99b254729c9",
+                "sha256:517ad0e93394ac532745129ceabdf2696b609ec9f87863d337140317ebce1c14",
+                "sha256:51fb3c322c81d20567019778cb5a4a6f2dc1c200b886bc0d636238e364848c89",
+                "sha256:5273b9f0b5835ff0350c0828faea623c68bfa65b792720c453e22b25cc72930f",
+                "sha256:530d548084c4a9f7a16ed4a294d459b4f229db50df689bfe92027452452943a0",
+                "sha256:530e8cebeea0d76bdcf93357aa5e41336f48c3dc709ac52da2bb167c5b8271d9",
+                "sha256:54fae94be3d75f3e573c9a1b5402dc593de19377013c9a0e4285e3d402dd3a2a",
+                "sha256:572d7c822caf521f0525ba1bce1a622a0b85cf47ffbdae6c9c19e3b5ac3c4389",
+                "sha256:58c948d0d086229efc484fe2f30c2d382c86720f55cd9bc33591774348ad44e0",
+                "sha256:5d11595abf8dd942a77883a39d81433739b287b6aa71620f15164f8096221b30",
+                "sha256:5f8ddd609f9e1af8c7bd6e2aca279c931aefecd148a14402d4e368f3171769fd",
+                "sha256:5feb91325bbceade6afab43eb3b508c63ee53579fe896c77137ded51c6b6958e",
+                "sha256:60c74963d8350241a79cb8feea80e54d518f72c26db618862a8f53e5023deaf9",
+                "sha256:613f19aa6e082cf96e17e3ffd89383343d0d589abda756b7764cf78361fd41dc",
+                "sha256:659a1e1b500fac8f2779dd9e1570464e012f43e580371470b45277a27baa7532",
+                "sha256:695f5c2823691a25f17bc5d5ffe79fa90972cc34b002ac6c843bb8a1720e950d",
+                "sha256:69dd852c2f0ad631b8b60cfbe25a28c0058a894de5abb566619c205ce0550eae",
+                "sha256:6cceb5473417d28edd20c6c984ab6fee6c6267d38d906823ebfe20b03d607dc2",
+                "sha256:71be7e0e01753a89cf024abf7ecb6bca2c81738ead80d43004d9b5e3f1244e64",
+                "sha256:74119174722c4349af9708993118581686f343adc1c8c9c007d59be90d077f3f",
+                "sha256:74a2e659c7ecbc73562e2a15e05039f1e22c75b7c7618b4b574a3ea9118d1557",
+                "sha256:7504e9b7dc05f99a9bbb4525c67a2c155073b44d720470a148b34166a69c054e",
+                "sha256:79090741d842f564b1b2827c0b82d846405b744d31e84f18d7a7b41c20e473ff",
+                "sha256:7a6967aaf043bceabab5412ed6bd6bd26603dae84d5cb75bf8d9a74a4959d398",
+                "sha256:7bda6eebafd42133efdca535b04ccb338ab29467b3f7bf79569883676fc628db",
+                "sha256:7edbed096e4a4798710ed6bc75dcaa2a21b68b6c356553ac4823c3658d53743a",
+                "sha256:7f9019c9cb613f084481bd6a100b12e1547cf2efe362d873c2e31e4035a6fa43",
+                "sha256:802168e03fba8bbc5ce0d866d589e4b1ca751d06edee69f7f3a19c5a9fe6b597",
+                "sha256:80d0a5615143c0b3225e5e3ef22c8d5d51f3f72ce0ea6fb84c943546c7b25b6c",
+                "sha256:82060f995ab5003a2d6e0f4ad29065b7672b6593c8c63559beefe5b443242c3e",
+                "sha256:836ab36280f21fc1a03c99cd05c6b7af70d2697e374c7af0b61ed271401a72a2",
+                "sha256:8761ac29b6c81574724322a554605608a9960769ea83d2c73e396f3df896ad54",
+                "sha256:87725cfb1a4f1f8c2fc9890ae2f42094120f4b44db9360be5d99a4c6b0e03a9e",
+                "sha256:899d28f422116b08be5118ef350c292b36fc15ec2daeb9ea987c89281c7bb5c4",
+                "sha256:8bc5f0687d796c05b1e28ab0d38a50e6309906ee09375dd3aff6a9c09dd6e8f4",
+                "sha256:8bea55c4eef25b0b19a0337dc4e3f9a15b00d569c77211fa8cde38684f234fb7",
+                "sha256:8e5a94886bedca0f9b78fecd6afb6629142fd2605aa70a125d49f4edc6037ee6",
+                "sha256:90ca27cd8da8118b18a52d5f547859cc1f8354a00cd1e8e5120df3e30d6279e5",
+                "sha256:92734d4d8d187a354a556626c221cd1a892a4e0802ccb2af432a1d85ec012194",
+                "sha256:947cf925bc916d90adba35a64c82aace04fa39b46b52d4630ece166655905a69",
+                "sha256:95b52c68d64c1878818687a473a10547b3292e82b6f6fe483808fb1468e2f52f",
+                "sha256:97d0235baafca5f2b09cf332cc275f021e694e8362c6bb9c96fc9a0eb74fc316",
+                "sha256:9ca4c0b502ab399ef89248a2c84c54954f77a070f28e546a85e91da627d1301e",
+                "sha256:9cc4fc6c196d6a8b76629a70ddfcd4635a6898756e2d9cac5565cf0654605d73",
+                "sha256:9cc6e6d9e571d2f863fa77700701dae73ed5f78881efc8b3f9a4398772ff53e8",
+                "sha256:a056d1ad2633548ca18ffa2f85c202cfb48b68615129143915b8dc72a806a923",
+                "sha256:a26611d9987b230566f24a0a125f17fe0de6a6aff9f25c9f564aaa2721a5fb88",
+                "sha256:a4474d924a47185a06411e0064b803c68be044be2d60e50e8bddcc2649957c1f",
+                "sha256:a4ea868bc28109052790eb2b52a9ab33f3aa7adc02f96673526ff47419490e21",
+                "sha256:a9e68c9d88823b274cf1e72f28cb5dc89c990edf430b0bfd3e2fb0785bfeabf4",
+                "sha256:aa9cccf4a44b9b62d8ba8b4dd06c649ba683e4bf04eea606d2e94cfc2d6ff4d6",
+                "sha256:ab30e5e3e706e3063bc6de96b118688cb10396b70bb9864a430f67df98c61ecc",
+                "sha256:ac2393c73378fea4e52aa56285a3d64be50f1a12395afef9cce47772f60334c2",
+                "sha256:ad8faf8df23f0378c6d527d8b0b15ea4a2e23c89376877c598c4870d1b2c7866",
+                "sha256:b35b200d6a71b9839a46b9b7fff66b6638bb52fc9658aa58796b0326595d3021",
+                "sha256:b3694e3f87f8ac7ce279d4355645b3c878d24d1424581b46282f24b92f5a4ae2",
+                "sha256:b4ff1d35e8c5bd078be89349b6f3a845128e685e751b6ea1169cf2160b344c4d",
+                "sha256:bbc8c8650c6e51041ad1be191742b8b421d05bbd3410f43fa2a00c8db87678e8",
+                "sha256:bc72863f4d9aba2e8fd9085e63548a324ba706d2ea2c83b260da08a59b9482de",
+                "sha256:bf625105bb9eef28a56a943fec8c8a98aeb80e7d7db99bd3c388137e6eb2d237",
+                "sha256:c2274ca724536f173122f36c98ce188fd24ce3dad886ec2b7af859518ce008a4",
+                "sha256:c45a03a4c69820a399f1dda9e1d8fbf3562eda46e7720458180302021b08f778",
+                "sha256:c8ae56368f8cc97c7e40a7ee18e1cedaf8e780cd8bc5ed5ac8b81f238614facb",
+                "sha256:c907cdc8109f6c619e6254212e794d6548373cc40e1ec75e6e3823d9135d29cc",
+                "sha256:ca0276464d148c72defa8bb4390cce01b4a0e425f3b50d1435aa6d7a18107602",
+                "sha256:cd5e2801c89992ed8c0a3f0293ae83c159a60d9a5d685005383ef4caca77f2c4",
+                "sha256:d08ec48f0a1c48d75d0356cea971921848fb620fdeba805b28f937e90691209f",
+                "sha256:d1a2ee9c1499fc8f86f4521f27a973c914b211ffa87322f4ee33bb35392da2c5",
+                "sha256:d5f5d1e9def3405f60e3ca8232d56f35c98fb7bf581efcc60051ebf53cb8b611",
+                "sha256:d60377dce4511655582e300dc1e5a5f24ba0cb229005a1d5c8d0cb72bb758ab8",
+                "sha256:d73beaac5e90173ac3deb9928a74763a6d230f494e4bfb422c217a0ad8e629bf",
+                "sha256:d7de2637729c67d67cf87614b566626057e95c303bc0a55ffe391f5205e7003d",
+                "sha256:dad6e0f2e481fffdcf776d10ebee25e0ef89f16d691f1e5dee4b586375fdc64b",
+                "sha256:dda86aba335c902b6149a02a55b38e96287157e609200811837678214ba2b1db",
+                "sha256:df01808ee470038c3f8dc4f48620df7225c49c2d6639e38f96e6d6ac6e6f7b0e",
+                "sha256:e1f6e2f00a6b8edb562826e4632e26d063ac10307e80f7461f7de3ad8ef3f077",
+                "sha256:e25369dc110d58ddf29b949377a93e0716d72a24f62bad72b2b39f155949c1fd",
+                "sha256:e3c701e954abf6fc03a49f7c579cc80c2c6cc52525340ca3186c41d3f33482ef",
+                "sha256:e5bcc1a1ae744e0bb59641171ae53743760130600da8db48cbb6e4918e186e4e",
+                "sha256:e68c14b04827dd76dcbd1aeea9e604e3e4b78322d8faf2f8132c7138efa340a8",
+                "sha256:e8aeb10fcbe92767f0fa69ad5a72deca50d0dca07fbde97848997d778a50c9fe",
+                "sha256:e985a16ff513596f217cee86c21371b8cd011c0f6f056d0920aa2d926c544058",
+                "sha256:ecbbd45615a6885fe3240eb9db73b9e62518b611850fdf8ab08bd56de7ad2b17",
+                "sha256:ee4ec14bc1680d6b0afab9aea2ef27e26d2024f18b24a2d7155a52b60da7e833",
+                "sha256:ef5960d965e67165d75b7c7ffc60a83ec5abfc5c11b764ec13ea54fbef8b4421",
+                "sha256:f0cdaecd4c953bfae0b6bb64910aaaca5a424ad9c72d85cb88417bb9814f7550",
+                "sha256:f1ce721c8a7dfec21fcbdfe04e8f68174183cf4e8188e0645e92aa23985c57ff",
+                "sha256:f50498891691e0864dc3da965f340fada0771f6142a378083dc4608f4ea513e2",
+                "sha256:f5ea69428fa1b49573eef0cc44a1d43bebd45ad0c611eb7d7eac760c7ae771bc",
+                "sha256:f61aa92e4aad0be58eb6eb4e0c21acf32cf8065f4b2cae5665da756c4ceef982",
+                "sha256:f6e4333fb15c83f7d1482a76d45a0818897b3d33f00efd215528ff7c51b8e35d",
+                "sha256:f820f24b09e3e779fe84c3c456cb4108a7aa639b0d1f02c28046e11bfcd088ed",
+                "sha256:f98059e4fcd3e3e4e2d632b7cf81c2faae96c43c60b569e9c621468082f1d104",
+                "sha256:fcce033e4021347d80ed9c66dcf1e7b1546319834b74445f561d2e2221de5659"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==3.4.6"
+        },
+        "click": {
+            "hashes": [
+                "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2",
+                "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96"
+            ],
+            "markers": "python_version >= '3.10'",
+            "version": "==8.4.1"
+        },
+        "colorama": {
+            "hashes": [
+                "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
+                "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'",
+            "version": "==0.4.6"
+        },
+        "ghp-import": {
+            "hashes": [
+                "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619",
+                "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"
+            ],
+            "version": "==2.1.0"
+        },
+        "idna": {
+            "hashes": [
+                "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8",
+                "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.8'",
+            "version": "==3.15"
+        },
+        "importlib-metadata": {
+            "hashes": [
+                "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1",
+                "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"
+            ],
+            "markers": "python_version < '3.10'",
+            "version": "==8.4.0"
+        },
+        "jinja2": {
+            "hashes": [
+                "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d",
+                "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==3.1.6"
+        },
+        "markdown": {
+            "hashes": [
+                "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950",
+                "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36"
+            ],
+            "markers": "python_version >= '3.10'",
+            "version": "==3.10.2"
+        },
+        "markupsafe": {
+            "hashes": [
+                "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f",
+                "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a",
+                "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf",
+                "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19",
+                "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf",
+                "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c",
+                "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175",
+                "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219",
+                "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb",
+                "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6",
+                "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab",
+                "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26",
+                "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1",
+                "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce",
+                "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218",
+                "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634",
+                "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695",
+                "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad",
+                "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73",
+                "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c",
+                "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe",
+                "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa",
+                "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559",
+                "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa",
+                "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37",
+                "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758",
+                "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f",
+                "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8",
+                "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d",
+                "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c",
+                "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97",
+                "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a",
+                "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19",
+                "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9",
+                "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9",
+                "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc",
+                "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2",
+                "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4",
+                "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354",
+                "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50",
+                "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698",
+                "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9",
+                "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b",
+                "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc",
+                "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115",
+                "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e",
+                "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485",
+                "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f",
+                "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12",
+                "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025",
+                "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009",
+                "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d",
+                "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b",
+                "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a",
+                "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5",
+                "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f",
+                "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d",
+                "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1",
+                "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287",
+                "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6",
+                "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f",
+                "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581",
+                "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed",
+                "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b",
+                "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c",
+                "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026",
+                "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8",
+                "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676",
+                "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6",
+                "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e",
+                "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d",
+                "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d",
+                "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01",
+                "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7",
+                "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419",
+                "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795",
+                "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1",
+                "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5",
+                "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d",
+                "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42",
+                "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe",
+                "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda",
+                "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e",
+                "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737",
+                "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523",
+                "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591",
+                "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc",
+                "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a",
+                "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"
+            ],
+            "markers": "python_version >= '3.9'",
+            "version": "==3.0.3"
+        },
+        "mergedeep": {
+            "hashes": [
+                "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8",
+                "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==1.3.4"
+        },
+        "mkdocs": {
+            "hashes": [
+                "sha256:3b3a78e736b31158d64dbb2f8ba29bd46a379d0c6e324c2246c3bc3d2189cfc1",
+                "sha256:eb7c99214dcb945313ba30426c2451b735992c73c2e10838f76d09e39ff4d0e2"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.7'",
+            "version": "==1.5.3"
+        },
+        "mkdocs-codeinclude-plugin": {
+            "hashes": [
+                "sha256:06bbbf0d4ac7eccaec6e0d89ce76d644a197cfed34880f541516e722ded6512a",
+                "sha256:443f32c9e4412b84ec084bd2b454020c5bf06cb9a958682e08a528e62b45da4d"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.11'",
+            "version": "==0.3.1"
+        },
+        "mkdocs-include-markdown-plugin": {
+            "hashes": [
+                "sha256:2800126746452e31c2e321bbd43c8190b356e0de353e20cbc16a34a3c3d6796c",
+                "sha256:5b5c99b5d3c9b9ce0114a9e60353bbafb6be53a26c2d3b74ec6b767a7a8e55ca"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.9'",
+            "version": "==7.3.0"
+        },
+        "mkdocs-markdownextradata-plugin": {
+            "hashes": [
+                "sha256:34dd40870781784c75809596b2d8d879da783815b075336d541de1f150c94242",
+                "sha256:4aed9b43b8bec65b02598387426ca4809099ea5f5aa78bf114f3296fd46686b5"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.6'",
+            "version": "==0.2.6"
+        },
+        "mkdocs-material": {
+            "hashes": [
+                "sha256:1e0e27fc9fe239f9064318acf548771a4629d5fd5dfd45444fd80a953fe21eb4",
+                "sha256:a43f470947053fa2405c33995f282d24992c752a50114f23f30da9d8d0c57e62"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.8'",
+            "version": "==9.5.18"
+        },
+        "mkdocs-material-extensions": {
+            "hashes": [
+                "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443",
+                "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==1.3.1"
+        },
+        "packaging": {
+            "hashes": [
+                "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e",
+                "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==26.2"
+        },
+        "paginate": {
+            "hashes": [
+                "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"
+            ],
+            "version": "==0.5.6"
+        },
+        "pathspec": {
+            "hashes": [
+                "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a",
+                "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189"
+            ],
+            "markers": "python_version >= '3.9'",
+            "version": "==1.1.1"
+        },
+        "platformdirs": {
+            "hashes": [
+                "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7",
+                "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a"
+            ],
+            "markers": "python_version >= '3.10'",
+            "version": "==4.10.0"
+        },
+        "pygments": {
+            "hashes": [
+                "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f",
+                "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.9'",
+            "version": "==2.20.0"
+        },
+        "pymdown-extensions": {
+            "hashes": [
+                "sha256:aace82bcccba3efc03e25d584e6a22d27a8e17caa3f4dd9f207e49b787aa9a91",
+                "sha256:d6ba157a6c03146a7fb122b2b9a121300056384eafeec9c9f9e584adfdb2a32d"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.9'",
+            "version": "==10.16.1"
+        },
+        "python-dateutil": {
+            "hashes": [
+                "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
+                "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
+            "version": "==2.9.0.post0"
+        },
+        "pytz": {
+            "hashes": [
+                "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812",
+                "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"
+            ],
+            "markers": "python_version < '3.9'",
+            "version": "==2024.1"
+        },
+        "pyyaml": {
+            "hashes": [
+                "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c",
+                "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a",
+                "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3",
+                "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956",
+                "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6",
+                "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c",
+                "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65",
+                "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a",
+                "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0",
+                "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b",
+                "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1",
+                "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6",
+                "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7",
+                "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e",
+                "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007",
+                "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310",
+                "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4",
+                "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9",
+                "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295",
+                "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea",
+                "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0",
+                "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e",
+                "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac",
+                "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9",
+                "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7",
+                "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35",
+                "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb",
+                "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b",
+                "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69",
+                "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5",
+                "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b",
+                "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c",
+                "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369",
+                "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd",
+                "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824",
+                "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198",
+                "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065",
+                "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c",
+                "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c",
+                "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764",
+                "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196",
+                "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b",
+                "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00",
+                "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac",
+                "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8",
+                "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e",
+                "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28",
+                "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3",
+                "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5",
+                "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4",
+                "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b",
+                "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf",
+                "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5",
+                "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702",
+                "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8",
+                "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788",
+                "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da",
+                "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d",
+                "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc",
+                "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c",
+                "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba",
+                "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f",
+                "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917",
+                "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5",
+                "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26",
+                "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f",
+                "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b",
+                "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be",
+                "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c",
+                "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3",
+                "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6",
+                "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926",
+                "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==6.0.3"
+        },
+        "pyyaml-env-tag": {
+            "hashes": [
+                "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04",
+                "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff"
+            ],
+            "markers": "python_version >= '3.9'",
+            "version": "==1.1"
+        },
+        "regex": {
+            "hashes": [
+                "sha256:05d9b6578a22db7dedb4df81451f360395828b04f4513980b6bd7a1412c679cc",
+                "sha256:08a1749f04fee2811c7617fdd46d2e46d09106fa8f475c884b65c01326eb15c5",
+                "sha256:0940038bec2fe9e26b203d636c44d31dd8766abc1fe66262da6484bd82461ccf",
+                "sha256:0a2a512d623f1f2d01d881513af9fc6a7c46e5cfffb7dc50c38ce959f9246c94",
+                "sha256:0a54a047b607fd2d2d52a05e6ad294602f1e0dec2291152b745870afc47c1397",
+                "sha256:0dd3f69098511e71880fb00f5815db9ed0ef62c05775395968299cb400aeab82",
+                "sha256:1031a5e7b048ee371ab3653aad3030ecfad6ee9ecdc85f0242c57751a05b0ac4",
+                "sha256:108e2dcf0b53a7c4ab8986842a8edcb8ab2e59919a74ff51c296772e8e74d0ae",
+                "sha256:144a1fc54765f5c5c36d6d4b073299832aa1ec6a746a6452c3ee7b46b3d3b11d",
+                "sha256:19d6c11bf35a6ad077eb23852827f91c804eeb71ecb85db4ee1386825b9dc4db",
+                "sha256:1f687a28640f763f23f8a9801fe9e1b37338bb1ca5d564ddd41619458f1f22d1",
+                "sha256:224803b74aab56aa7be313f92a8d9911dcade37e5f167db62a738d0c85fdac4b",
+                "sha256:23a412b7b1a7063f81a742463f38821097b6a37ce1e5b89dd8e871d14dbfd86b",
+                "sha256:25f87ae6b96374db20f180eab083aafe419b194e96e4f282c40191e71980c666",
+                "sha256:2630ca4e152c221072fd4a56d4622b5ada876f668ecd24d5ab62544ae6793ed6",
+                "sha256:28e1f28d07220c0f3da0e8fcd5a115bbb53f8b55cecf9bec0c946eb9a059a94c",
+                "sha256:2b51739ddfd013c6f657b55a508de8b9ea78b56d22b236052c3a85a675102dc6",
+                "sha256:2cc1b87bba1dd1a898e664a31012725e48af826bf3971e786c53e32e02adae6c",
+                "sha256:2fef0b38c34ae675fcbb1b5db760d40c3fc3612cfa186e9e50df5782cac02bcd",
+                "sha256:36f392dc7763fe7924575475736bddf9ab9f7a66b920932d0ea50c2ded2f5636",
+                "sha256:374f690e1dd0dbdcddea4a5c9bdd97632cf656c69113f7cd6a361f2a67221cb6",
+                "sha256:3986217ec830c2109875be740531feb8ddafe0dfa49767cdcd072ed7e8927962",
+                "sha256:39fb166d2196413bead229cd64a2ffd6ec78ebab83fff7d2701103cf9f4dfd26",
+                "sha256:4290035b169578ffbbfa50d904d26bec16a94526071ebec3dadbebf67a26b25e",
+                "sha256:43548ad74ea50456e1c68d3c67fff3de64c6edb85bcd511d1136f9b5376fc9d1",
+                "sha256:44a22ae1cfd82e4ffa2066eb3390777dc79468f866f0625261a93e44cdf6482b",
+                "sha256:457c2cd5a646dd4ed536c92b535d73548fb8e216ebee602aa9f48e068fc393f3",
+                "sha256:459226445c7d7454981c4c0ce0ad1a72e1e751c3e417f305722bbcee6697e06a",
+                "sha256:47af45b6153522733aa6e92543938e97a70ce0900649ba626cf5aad290b737b6",
+                "sha256:499334ad139557de97cbc4347ee921c0e2b5e9c0f009859e74f3f77918339257",
+                "sha256:57ba112e5530530fd175ed550373eb263db4ca98b5f00694d73b18b9a02e7185",
+                "sha256:5ce479ecc068bc2a74cb98dd8dba99e070d1b2f4a8371a7dfe631f85db70fe6e",
+                "sha256:5dbc1bcc7413eebe5f18196e22804a3be1bfdfc7e2afd415e12c068624d48247",
+                "sha256:6277d426e2f31bdbacb377d17a7475e32b2d7d1f02faaecc48d8e370c6a3ff31",
+                "sha256:66372c2a01782c5fe8e04bff4a2a0121a9897e19223d9eab30c54c50b2ebeb7f",
+                "sha256:670fa596984b08a4a769491cbdf22350431970d0112e03d7e4eeaecaafcd0fec",
+                "sha256:6f435946b7bf7a1b438b4e6b149b947c837cb23c704e780c19ba3e6855dbbdd3",
+                "sha256:7413167c507a768eafb5424413c5b2f515c606be5bb4ef8c5dee43925aa5718b",
+                "sha256:7c3d389e8d76a49923683123730c33e9553063d9041658f23897f0b396b2386f",
+                "sha256:7d77b6f63f806578c604dca209280e4c54f0fa9a8128bb8d2cc5fb6f99da4150",
+                "sha256:7e76b9cfbf5ced1aca15a0e5b6f229344d9b3123439ffce552b11faab0114a02",
+                "sha256:7f3502f03b4da52bbe8ba962621daa846f38489cae5c4a7b5d738f15f6443d17",
+                "sha256:7fe9739a686dc44733d52d6e4f7b9c77b285e49edf8570754b322bca6b85b4cc",
+                "sha256:83ab366777ea45d58f72593adf35d36ca911ea8bd838483c1823b883a121b0e4",
+                "sha256:84077821c85f222362b72fdc44f7a3a13587a013a45cf14534df1cbbdc9a6796",
+                "sha256:8bb381f777351bd534462f63e1c6afb10a7caa9fa2a421ae22c26e796fe31b1f",
+                "sha256:92da587eee39a52c91aebea8b850e4e4f095fe5928d415cb7ed656b3460ae79a",
+                "sha256:9301cc6db4d83d2c0719f7fcda37229691745168bf6ae849bea2e85fc769175d",
+                "sha256:965fd0cf4694d76f6564896b422724ec7b959ef927a7cb187fc6b3f4e4f59833",
+                "sha256:99d6a550425cc51c656331af0e2b1651e90eaaa23fb4acde577cf15068e2e20f",
+                "sha256:99ef6289b62042500d581170d06e17f5353b111a15aa6b25b05b91c6886df8fc",
+                "sha256:a1409c4eccb6981c7baabc8888d3550df518add6e06fe74fa1d9312c1838652d",
+                "sha256:a74fcf77d979364f9b69fcf8200849ca29a374973dc193a7317698aa37d8b01c",
+                "sha256:aaa179975a64790c1f2701ac562b5eeb733946eeb036b5bcca05c8d928a62f10",
+                "sha256:ac69b394764bb857429b031d29d9604842bc4cbfd964d764b1af1868eeebc4f0",
+                "sha256:b45d4503de8f4f3dc02f1d28a9b039e5504a02cc18906cfe744c11def942e9eb",
+                "sha256:b7d893c8cf0e2429b823ef1a1d360a25950ed11f0e2a9df2b5198821832e1947",
+                "sha256:b8eb28995771c087a73338f695a08c9abfdf723d185e57b97f6175c5051ff1ae",
+                "sha256:b91d529b47798c016d4b4c1d06cc826ac40d196da54f0de3c519f5a297c5076a",
+                "sha256:bc365ce25f6c7c5ed70e4bc674f9137f52b7dd6a125037f9132a7be52b8a252f",
+                "sha256:bf29304a8011feb58913c382902fde3395957a47645bf848eea695839aa101b7",
+                "sha256:c06bf3f38f0707592898428636cbb75d0a846651b053a1cf748763e3063a6925",
+                "sha256:c77d10ec3c1cf328b2f501ca32583625987ea0f23a0c2a49b37a39ee5c4c4630",
+                "sha256:cd196d056b40af073d95a2879678585f0b74ad35190fac04ca67954c582c6b61",
+                "sha256:d7a353ebfa7154c871a35caca7bfd8f9e18666829a1dc187115b80e35a29393e",
+                "sha256:d84308f097d7a513359757c69707ad339da799e53b7393819ec2ea36bc4beb58",
+                "sha256:dd7ef715ccb8040954d44cfeff17e6b8e9f79c8019daae2fd30a8806ef5435c0",
+                "sha256:e672cf9caaf669053121f1766d659a8813bd547edef6e009205378faf45c67b8",
+                "sha256:ecc6148228c9ae25ce403eade13a0961de1cb016bdb35c6eafd8e7b87ad028b1",
+                "sha256:f1c5742c31ba7d72f2dedf7968998730664b45e38827637e0f04a2ac7de2f5f1",
+                "sha256:f1d6e4b7b2ae3a6a9df53efbf199e4bfcff0959dbdb5fd9ced34d4407348e39a",
+                "sha256:f2fc053228a6bd3a17a9b0a3f15c3ab3cf95727b00557e92e1cfe094b88cc662",
+                "sha256:f57515750d07e14743db55d59759893fdb21d2668f39e549a7d6cad5d70f9fea",
+                "sha256:f85151ec5a232335f1be022b09fbbe459042ea1951d8a48fef251223fc67eee1",
+                "sha256:fb0315a2b26fde4005a7c401707c5352df274460f2f85b209cf6024271373013",
+                "sha256:fc0916c4295c64d6890a46e02d4482bb5ccf33bf1a824c0eaa9e83b148291f90",
+                "sha256:fd24fd140b69f0b0bcc9165c397e9b2e89ecbeda83303abf2a072609f60239e2",
+                "sha256:fdae0120cddc839eb8e3c15faa8ad541cc6d906d3eb24d82fb041cfe2807bc1e",
+                "sha256:fe00f4fe11c8a521b173e6324d862ee7ee3412bf7107570c9b564fe1119b56fb"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==2024.4.28"
+        },
+        "requests": {
+            "hashes": [
+                "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b",
+                "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.10'",
+            "version": "==2.33.0"
+        },
+        "six": {
+            "hashes": [
+                "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
+                "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
+            ],
+            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
+            "version": "==1.17.0"
+        },
+        "urllib3": {
+            "hashes": [
+                "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c",
+                "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"
+            ],
+            "index": "pypi",
+            "markers": "python_version >= '3.10'",
+            "version": "==2.7.0"
+        },
+        "watchdog": {
+            "hashes": [
+                "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a",
+                "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2",
+                "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f",
+                "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c",
+                "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c",
+                "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c",
+                "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0",
+                "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13",
+                "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134",
+                "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa",
+                "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e",
+                "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379",
+                "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a",
+                "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11",
+                "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282",
+                "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b",
+                "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f",
+                "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c",
+                "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112",
+                "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948",
+                "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881",
+                "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860",
+                "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3",
+                "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680",
+                "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26",
+                "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26",
+                "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e",
+                "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8",
+                "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c",
+                "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"
+            ],
+            "markers": "python_version >= '3.9'",
+            "version": "==6.0.0"
+        },
+        "wcmatch": {
+            "hashes": [
+                "sha256:5848ace7dbb0476e5e55ab63c6bbd529745089343427caa5537f230cc01beb8a",
+                "sha256:f11f94208c8c8484a16f4f48638a85d771d9513f4ab3f37595978801cb9465af"
+            ],
+            "markers": "python_version >= '3.9'",
+            "version": "==10.1"
+        },
+        "zipp": {
+            "hashes": [
+                "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064",
+                "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"
+            ],
+            "markers": "python_version >= '3.8'",
+            "version": "==3.20.1"
+        }
+    },
+    "develop": {}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/README.md b/vendor/github.com/testcontainers/testcontainers-go/README.md
new file mode 100644
index 000000000..ea21c6387
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/README.md
@@ -0,0 +1,21 @@
+# Testcontainers
+
+[![Main pipeline](https://github.com/testcontainers/testcontainers-go/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/testcontainers/testcontainers-go/actions/workflows/ci.yml)
+[![GoDoc Reference](https://pkg.go.dev/badge/github.com/testcontainers/testcontainers-go.svg)](https://pkg.go.dev/github.com/testcontainers/testcontainers-go)
+[![Go Report Card](https://goreportcard.com/badge/github.com/testcontainers/testcontainers-go)](https://goreportcard.com/report/github.com/testcontainers/testcontainers-go)
+[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=testcontainers_testcontainers-go&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=testcontainers_testcontainers-go)
+[![License](https://img.shields.io/badge/license-MIT-blue)](https://github.com/testcontainers/testcontainers-go/blob/main/LICENSE)
+
+[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=141451032&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=EastUs)
+
+[![Join our Slack](https://img.shields.io/badge/Slack-4A154B?logo=slack)](https://testcontainers.slack.com/)
+
+_Testcontainers for Go_ is a Go package that makes it simple to create and clean up container-based dependencies for
+automated integration/smoke tests. The clean, easy-to-use API enables developers to programmatically define containers
+that should be run as part of a test and clean up those resources when the test is done.
+
+You can find more information about _Testcontainers for Go_ at [golang.testcontainers.org](https://golang.testcontainers.org), which is rendered from the [./docs](./docs) directory.
+
+## Using _Testcontainers for Go_
+
+Please visit [the quickstart guide](https://golang.testcontainers.org/quickstart) to understand how to add the dependency to your Go project.
diff --git a/vendor/github.com/testcontainers/testcontainers-go/RELEASING.md b/vendor/github.com/testcontainers/testcontainers-go/RELEASING.md
new file mode 100644
index 000000000..a35e243cb
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/RELEASING.md
@@ -0,0 +1,201 @@
+# Releasing Testcontainers for Go
+
+In order to create a release, we have added a shell script that performs all the tasks for you, allowing a dry-run mode for checking it before creating the release. We are going to explain how to use it in this document.
+
+## Prerequisites
+
+First, it's really important that you first check that the [version.go](./internal/version.go) file is up-to-date, containing the right version you want to create. That file will be used by the automation to perform the release.
+Once the version file is correct in the repository:
+
+Second, check that the git remote for the `origin` is pointing to `github.com/testcontainers/testcontainers-go`. You can check it by running:
+
+```shell
+git remote -v
+```
+
+## Prepare the release
+
+Once the remote is properly set, please follow these steps:
+
+- Run the [pre-release.sh](./scripts/pre-release.sh) shell script to run it in dry-run mode.
+- You can use the `DRY_RUN` variable to enable or disable the dry-run mode. By default, it's enabled.
+- To prepare for a release, updating the _Testcontainers for Go_ dependency for all the modules and examples, without performing any Git operation:
+
+        DRY_RUN="false" ./scripts/pre-release.sh
+
+- The script will update the [mkdocs.yml](./mkdocks.yml) file, updating the `latest_version` field to the current version.
+- The script will update the `go.mod` files for each Go modules and example modules under the examples and modules directories, updating the version of the testcontainers-go dependency to the recently created tag.
+- The script will modify the docs for the each Go module **that was not released yet**, updating the version of _Testcontainers for Go_ where it was added to the recently created tag.
+
+An example execution, with dry-run mode enabled:
+
+```shell
+sed "s/latest_version: .*/latest_version: v0.20.1/g" /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml > /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml.tmp
+mv /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml.tmp /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" bigtable/go.mod > bigtable/go.mod.tmp
+mv bigtable/go.mod.tmp bigtable/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" cockroachdb/go.mod > cockroachdb/go.mod.tmp
+mv cockroachdb/go.mod.tmp cockroachdb/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" consul/go.mod > consul/go.mod.tmp
+mv consul/go.mod.tmp consul/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" datastore/go.mod > datastore/go.mod.tmp
+mv datastore/go.mod.tmp datastore/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" firestore/go.mod > firestore/go.mod.tmp
+mv firestore/go.mod.tmp firestore/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" mongodb/go.mod > mongodb/go.mod.tmp
+mv mongodb/go.mod.tmp mongodb/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" nginx/go.mod > nginx/go.mod.tmp
+mv nginx/go.mod.tmp nginx/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" pubsub/go.mod > pubsub/go.mod.tmp
+mv pubsub/go.mod.tmp pubsub/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" spanner/go.mod > spanner/go.mod.tmp
+mv spanner/go.mod.tmp spanner/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" toxiproxy/go.mod > toxiproxy/go.mod.tmp
+mv toxiproxy/go.mod.tmp toxiproxy/go.mod
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" compose/go.mod > compose/go.mod.tmp
+mv compose/go.mod.tmp compose/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" couchbase/go.mod > couchbase/go.mod.tmp
+mv couchbase/go.mod.tmp couchbase/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" localstack/go.mod > localstack/go.mod.tmp
+mv localstack/go.mod.tmp localstack/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" mysql/go.mod > mysql/go.mod.tmp
+mv mysql/go.mod.tmp mysql/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" neo4j/go.mod > neo4j/go.mod.tmp
+mv neo4j/go.mod.tmp neo4j/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" postgres/go.mod > postgres/go.mod.tmp
+mv postgres/go.mod.tmp postgres/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" pulsar/go.mod > pulsar/go.mod.tmp
+mv pulsar/go.mod.tmp pulsar/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" redis/go.mod > redis/go.mod.tmp
+mv redis/go.mod.tmp redis/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" redpanda/go.mod > redpanda/go.mod.tmp
+mv redpanda/go.mod.tmp redpanda/go.mod
+sed "s/testcontainers-go v.*/testcontainers-go v0.20.1/g" vault/go.mod > vault/go.mod.tmp
+mv vault/go.mod.tmp vault/go.mod
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+go mod tidy
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" couchbase.md > couchbase.md.tmp
+mv couchbase.md.tmp couchbase.md
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" localstack.md > localstack.md.tmp
+mv localstack.md.tmp localstack.md
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" mysql.md > mysql.md.tmp
+mv mysql.md.tmp mysql.md
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" neo4j.md > neo4j.md.tmp
+mv neo4j.md.tmp neo4j.md
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" postgres.md > postgres.md.tmp
+mv postgres.md.tmp postgres.md
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" pulsar.md > pulsar.md.tmp
+mv pulsar.md.tmp pulsar.md
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" redis.md > redis.md.tmp
+mv redis.md.tmp redis.md
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" redpanda.md > redpanda.md.tmp
+mv redpanda.md.tmp redpanda.md
+sed "s/Not available until the next release <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\"><span class=\"tc-version\">:material-tag: main<\/span><\/a>/Since <a href=\"https:\/\/github.com\/testcontainers\/testcontainers-go\/releases\/tag\/v0.20.1\"><span class=\"tc-version\">:material-tag: v0.20.1<\/span><\/a>/g" vault.md > vault.md.tmp
+mv vault.md.tmp vault.md
+```
+
+## Performing a release
+
+Once you are satisfied with the modified files in the git state:
+
+- Run the [release.sh](./scripts/release.sh) shell script to create the release in dry-run mode.
+- You can use the `DRY_RUN` variable to enable or disable the dry-run mode. By default, it's enabled.
+
+        DRY_RUN="false" ./scripts/release.sh
+
+- You can define the bump type, using the `BUMP_TYPE` environment variable. The default value is `minor`, but you can also use `major` or `patch` (the script will fail if the value is not one of these three):
+
+        BUMP_TYPE="major" ./scripts/release.sh
+
+- The script will commit the current state of the git repository, if the `DRY_RUN` variable is set to `false`. The modified files are the ones modified by the `pre-release.sh` script.
+- The script will create a git tag with the current value of the [version.go](./internal/version.go) file, starting with `v`: e.g. `v0.18.0`, for the following Go modules:
+    - the root module, representing the Testcontainers for Go library.
+    - all the Go modules living in both the `examples` and `modules` directory. The git tag value for these Go modules will be created using this name convention:
+
+             "${directory}/${module_name}/${version}", e.g. "examples/mysql/v0.18.0", "modules/compose/v0.18.0"
+
+- The script will update the [version.go](./internal/version.go) file, setting the next development version to the value defined in the `BUMP_TYPE` environment variable. For example, if the current version is `v0.18.0`, the script will update the [version.go](./internal/version.go) file with the next development version `v0.19.0`.
+- The script will create a commit in the **main** branch if the `DRY_RUN` variable is set to `false`.
+- The script will push the main branch including the tags to the upstream repository, https://github.com/testcontainers/testcontainers-go, if the `DRY_RUN` variable is set to `false`.
+- Finally, the script will trigger the Golang proxy to update the modules in https://proxy.golang.org/, if the `DRY_RUN` variable is set to `false`.
+
+An example execution, with dry-run mode enabled:
+
+```
+$ ./scripts/release.sh
+Current version: v0.20.1
+git add /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go
+git add /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/mkdocs.yml
+git add examples/**/go.*
+git add modules/**/go.*
+git commit -m chore: use new version (v0.20.1) in modules and examples
+git tag v0.20.1
+git tag examples/bigtable/v0.20.1
+git tag examples/datastore/v0.20.1
+git tag examples/firestore/v0.20.1
+git tag examples/mongodb/v0.20.1
+git tag examples/nginx/v0.20.1
+git tag examples/pubsub/v0.20.1
+git tag examples/spanner/v0.20.1
+git tag examples/toxiproxy/v0.20.1
+git tag modules/cockroachdb/v0.20.1
+git tag modules/compose/v0.20.1
+git tag modules/couchbase/v0.20.1
+git tag modules/localstack/v0.20.1
+git tag modules/mysql/v0.20.1
+git tag modules/neo4j/v0.20.1
+git tag modules/postgres/v0.20.1
+git tag modules/pulsar/v0.20.1
+git tag modules/redis/v0.20.1
+git tag modules/redpanda/v0.20.1
+git tag modules/vault/v0.20.1
+WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
+Producing a minor bump of the version, from 0.20.1 to 0.21.0
+sed "s/const Version = ".*"/const Version = "0.21.0"/g" /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go > /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go.tmp
+mv /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go.tmp /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go
+git add /Users/mdelapenya/sourcecode/src/github.com/testcontainers/testcontainers-go/internal/version.go
+git commit -m chore: prepare for next minor development cycle (0.21.0)
+git push origin main --tags
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/bigtable/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/datastore/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/firestore/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/mongodb/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/nginx/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/pubsub/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/spanner/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/examples/toxiproxy/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/cockroachdb/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/compose/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/couchbase/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/localstack/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/mysql/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/neo4j/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/postgres/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/pulsar/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/redis/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/redpanda/@v/v0.20.1.info
+curl https://proxy.golang.org/github.com/testcontainers/testcontainers-go/modules/vault/@v/v0.20.1.info
+```
+
+Right after that, you have to:
+- Verify that the commits are in the upstream repository, otherwise, update it with the current state of the main branch.
diff --git a/vendor/github.com/testcontainers/testcontainers-go/cleanup.go b/vendor/github.com/testcontainers/testcontainers-go/cleanup.go
new file mode 100644
index 000000000..2f8448636
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/cleanup.go
@@ -0,0 +1,125 @@
+package testcontainers
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"reflect"
+	"time"
+
+	"github.com/moby/moby/client"
+)
+
+// TerminateOptions is a type that holds the options for terminating a container.
+type TerminateOptions struct {
+	ctx         context.Context
+	stopTimeout *time.Duration
+	volumes     []string
+}
+
+// TerminateOption is a type that represents an option for terminating a container.
+type TerminateOption func(*TerminateOptions)
+
+// NewTerminateOptions returns a fully initialised TerminateOptions.
+// Defaults: StopTimeout: 10 seconds.
+func NewTerminateOptions(ctx context.Context, opts ...TerminateOption) *TerminateOptions {
+	timeout := time.Second * 10
+	options := &TerminateOptions{
+		stopTimeout: &timeout,
+		ctx:         ctx,
+	}
+	for _, opt := range opts {
+		opt(options)
+	}
+	return options
+}
+
+// Context returns the context to use during a Terminate.
+func (o *TerminateOptions) Context() context.Context {
+	return o.ctx
+}
+
+// StopTimeout returns the stop timeout to use during a Terminate.
+func (o *TerminateOptions) StopTimeout() *time.Duration {
+	return o.stopTimeout
+}
+
+// Cleanup performs any clean up needed
+func (o *TerminateOptions) Cleanup() error {
+	// TODO: simplify this when when perform the client refactor.
+	if len(o.volumes) == 0 {
+		return nil
+	}
+	apiClient, err := NewDockerClientWithOpts(o.ctx)
+	if err != nil {
+		return fmt.Errorf("docker client: %w", err)
+	}
+	defer apiClient.Close()
+	// Best effort to remove all volumes.
+	var errs []error
+	for _, volume := range o.volumes {
+		if _, errRemove := apiClient.VolumeRemove(o.ctx, volume, client.VolumeRemoveOptions{Force: true}); errRemove != nil {
+			errs = append(errs, fmt.Errorf("volume remove %q: %w", volume, errRemove))
+		}
+	}
+	return errors.Join(errs...)
+}
+
+// StopContext returns a TerminateOption that sets the context.
+// Default: context.Background().
+func StopContext(ctx context.Context) TerminateOption {
+	return func(c *TerminateOptions) {
+		c.ctx = ctx
+	}
+}
+
+// StopTimeout returns a TerminateOption that sets the timeout.
+// Default: See [Container.Stop].
+func StopTimeout(timeout time.Duration) TerminateOption {
+	return func(c *TerminateOptions) {
+		c.stopTimeout = &timeout
+	}
+}
+
+// RemoveVolumes returns a TerminateOption that sets additional volumes to remove.
+// This is useful when the container creates named volumes that should be removed
+// which are not removed by default.
+// Default: nil.
+func RemoveVolumes(volumes ...string) TerminateOption {
+	return func(c *TerminateOptions) {
+		c.volumes = volumes
+	}
+}
+
+// TerminateContainer calls [Container.Terminate] on the container if it is not nil.
+//
+// This should be called as a defer directly after [GenericContainer](...)
+// or a modules Run(...) to ensure the container is terminated when the
+// function ends.
+func TerminateContainer(container Container, options ...TerminateOption) error {
+	if isNil(container) {
+		return nil
+	}
+
+	err := container.Terminate(context.Background(), options...)
+	if !isCleanupSafe(err) {
+		return fmt.Errorf("terminate: %w", err)
+	}
+
+	return nil
+}
+
+// isNil returns true if val is nil or a nil instance false otherwise.
+func isNil(val any) bool {
+	if val == nil {
+		return true
+	}
+
+	valueOf := reflect.ValueOf(val)
+	switch valueOf.Kind() {
+	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice:
+		return valueOf.IsNil()
+	default:
+		return false
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/commons-test.mk b/vendor/github.com/testcontainers/testcontainers-go/commons-test.mk
new file mode 100644
index 000000000..a3381c5d6
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/commons-test.mk
@@ -0,0 +1,69 @@
+ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+GOBIN= $(GOPATH)/bin
+
+define go_install
+    go install $(1)
+endef
+
+$(GOBIN)/golangci-lint:
+	$(call go_install,github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.9.0)
+
+$(GOBIN)/gotestsum:
+	$(call go_install,gotest.tools/gotestsum@latest)
+
+$(GOBIN)/mockery:
+	$(call go_install,github.com/vektra/mockery/v2@v2.53.4)
+
+$(GOBIN)/gci:
+	$(call go_install,github.com/daixiang0/gci@v0.14.0)
+
+.PHONY: install
+install: $(GOBIN)/golangci-lint $(GOBIN)/gotestsum $(GOBIN)/mockery
+
+.PHONY: clean
+clean:
+	rm $(GOBIN)/golangci-lint
+	rm $(GOBIN)/gotestsum
+	rm $(GOBIN)/mockery
+
+.PHONY: dependencies-scan
+dependencies-scan:
+	@echo ">> Scanning dependencies in $(CURDIR)..."
+	go list -json -m all | docker run --rm -i sonatypecommunity/nancy:latest sleuth --skip-update-check
+
+.PHONY: lint
+lint: $(GOBIN)/golangci-lint
+	golangci-lint run -c $(ROOT_DIR)/.golangci.yml --fix
+
+.PHONY: generate
+generate: $(GOBIN)/gci
+generate: $(GOBIN)/mockery
+	go generate ./...
+
+.PHONY: test-%
+test-%: $(GOBIN)/gotestsum
+	@echo "Running $* tests..."
+	gotestsum \
+		--format short-verbose \
+		--rerun-fails=5 \
+		--packages="./..." \
+		--junitfile TEST-unit.xml \
+		-- \
+		-v \
+		-coverprofile=coverage.out \
+		-timeout=30m \
+		-race
+
+.PHONY: tools
+tools:
+	go mod download
+
+.PHONY: test-tools
+test-tools: $(GOBIN)/gotestsum
+
+.PHONY: tidy
+tidy:
+	go mod tidy
+
+.PHONY: pre-commit
+pre-commit: generate tidy lint
diff --git a/vendor/github.com/testcontainers/testcontainers-go/config.go b/vendor/github.com/testcontainers/testcontainers-go/config.go
new file mode 100644
index 000000000..91a333107
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/config.go
@@ -0,0 +1,29 @@
+package testcontainers
+
+import (
+	"github.com/testcontainers/testcontainers-go/internal/config"
+)
+
+// TestcontainersConfig represents the configuration for Testcontainers
+type TestcontainersConfig struct {
+	Host           string `properties:"docker.host,default="`                    // Deprecated: use Config.Host instead
+	TLSVerify      int    `properties:"docker.tls.verify,default=0"`             // Deprecated: use Config.TLSVerify instead
+	CertPath       string `properties:"docker.cert.path,default="`               // Deprecated: use Config.CertPath instead
+	RyukDisabled   bool   `properties:"ryuk.disabled,default=false"`             // Deprecated: use Config.RyukDisabled instead
+	RyukPrivileged bool   `properties:"ryuk.container.privileged,default=false"` // Deprecated: use Config.RyukPrivileged instead
+	Config         config.Config
+}
+
+// ReadConfig reads from testcontainers properties file, storing the result in a singleton instance
+// of the TestcontainersConfig struct
+func ReadConfig() TestcontainersConfig {
+	cfg := config.Read()
+	return TestcontainersConfig{
+		Host:           cfg.Host,
+		TLSVerify:      cfg.TLSVerify,
+		CertPath:       cfg.CertPath,
+		RyukDisabled:   cfg.RyukDisabled,
+		RyukPrivileged: cfg.RyukPrivileged,
+		Config:         cfg,
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/container.go b/vendor/github.com/testcontainers/testcontainers-go/container.go
new file mode 100644
index 000000000..b7f0b653e
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/container.go
@@ -0,0 +1,561 @@
+package testcontainers
+
+import (
+	"archive/tar"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"maps"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/cpuguy83/dockercfg"
+	"github.com/google/uuid"
+	"github.com/moby/go-archive"
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+	"github.com/moby/moby/api/types/registry"
+	"github.com/moby/moby/client"
+	"github.com/moby/patternmatcher/ignorefile"
+
+	tcexec "github.com/testcontainers/testcontainers-go/exec"
+	"github.com/testcontainers/testcontainers-go/internal/core"
+	"github.com/testcontainers/testcontainers-go/log"
+	"github.com/testcontainers/testcontainers-go/wait"
+)
+
+// Deprecated: Use [Container]
+//
+// DeprecatedContainer shows methods that were supported before, but are now deprecated
+type DeprecatedContainer interface {
+	GetHostEndpoint(ctx context.Context, port string) (string, string, error)
+	GetIPAddress(ctx context.Context) (string, error)
+	LivenessCheckPorts(ctx context.Context) (network.PortSet, error)
+	Terminate(ctx context.Context) error
+}
+
+// Container allows getting info about and controlling a single container instance
+type Container interface {
+	GetContainerID() string                                                      // get the container id from the provider
+	Endpoint(context.Context, string) (string, error)                            // get proto://ip:port string for the lowest exposed port
+	PortEndpoint(ctx context.Context, port string, proto string) (string, error) // get proto://ip:port string for the given exposed port
+	Host(context.Context) (string, error)                                        // get host where the container port is exposed
+	Inspect(context.Context) (*container.InspectResponse, error)                 // get container info
+	MappedPort(context.Context, string) (network.Port, error)                    // get externally mapped port for a container port
+	Ports(context.Context) (network.PortMap, error)                              // Deprecated: Use c.Inspect(ctx).NetworkSettings.Ports instead
+	SessionID() string                                                           // get session id
+	IsRunning() bool                                                             // IsRunning returns true if the container is running, false otherwise.
+	Start(context.Context) error                                                 // start the container
+	Stop(context.Context, *time.Duration) error                                  // stop the container
+
+	// Terminate stops and removes the container and its image if it was built and not flagged as kept.
+	Terminate(ctx context.Context, opts ...TerminateOption) error
+
+	Logs(context.Context) (io.ReadCloser, error)                    // Get logs of the container
+	FollowOutput(LogConsumer)                                       // Deprecated: it will be removed in the next major release
+	StartLogProducer(context.Context, ...LogProductionOption) error // Deprecated: Use the ContainerRequest instead
+	StopLogProducer() error                                         // Deprecated: it will be removed in the next major release
+	Name(context.Context) (string, error)                           // Deprecated: Use c.Inspect(ctx).Name instead
+	State(context.Context) (*container.State, error)                // returns container's running state
+	Networks(context.Context) ([]string, error)                     // get container networks
+	NetworkAliases(context.Context) (map[string][]string, error)    // get container network aliases for a network
+	Exec(ctx context.Context, cmd []string, options ...tcexec.ProcessOption) (int, io.Reader, error)
+	ContainerIP(context.Context) (string, error)    // get container ip
+	ContainerIPs(context.Context) ([]string, error) // get all container IPs
+	CopyToContainer(ctx context.Context, fileContent []byte, containerFilePath string, fileMode int64) error
+	CopyDirToContainer(ctx context.Context, hostDirPath string, containerParentPath string, fileMode int64) error
+	CopyFileToContainer(ctx context.Context, hostFilePath string, containerFilePath string, fileMode int64) error
+	CopyFileFromContainer(ctx context.Context, filePath string) (io.ReadCloser, error)
+	GetLogProductionErrorChannel() <-chan error
+}
+
+// ImageBuildInfo defines what is needed to build an image
+type ImageBuildInfo interface {
+	BuildOptions() (client.ImageBuildOptions, error) // converts the ImageBuildInfo to a build.ImageBuildOptions
+	GetContext() (io.Reader, error)                  // the path to the build context
+	GetDockerfile() string                           // the relative path to the Dockerfile, including the file itself
+	GetRepo() string                                 // get repo label for image
+	GetTag() string                                  // get tag label for image
+	BuildLogWriter() io.Writer                       // for output of build log, use io.Discard to disable the output
+	ShouldBuildImage() bool                          // return true if the image needs to be built
+	GetBuildArgs() map[string]*string                // return the environment args used to build the Dockerfile
+	GetAuthConfigs() map[string]registry.AuthConfig  // Deprecated. Testcontainers will detect registry credentials automatically. Return the auth configs to be able to pull from an authenticated docker registry
+}
+
+// FromDockerfile represents the parameters needed to build an image from a Dockerfile
+// rather than using a pre-built one
+type FromDockerfile struct {
+	Context        string                         // the path to the context of the docker build
+	ContextArchive io.ReadSeeker                  // the tar archive file to send to docker that contains the build context
+	Dockerfile     string                         // the path from the context to the Dockerfile for the image, defaults to "Dockerfile"
+	Repo           string                         // the repo label for image, defaults to UUID
+	Tag            string                         // the tag label for image, defaults to UUID
+	BuildArgs      map[string]*string             // enable user to pass build args to docker daemon
+	PrintBuildLog  bool                           // Deprecated: Use BuildLogWriter instead
+	BuildLogWriter io.Writer                      // for output of build log, defaults to io.Discard
+	AuthConfigs    map[string]registry.AuthConfig // Deprecated. Testcontainers will detect registry credentials automatically. Enable auth configs to be able to pull from an authenticated docker registry
+	// KeepImage describes whether DockerContainer.Terminate should not delete the
+	// container image. Useful for images that are built from a Dockerfile and take a
+	// long time to build. Keeping the image also Docker to reuse it.
+	KeepImage bool
+	// BuildOptionsModifier Modifier for the build options before image build. Use it for
+	// advanced configurations while building the image. Please consider that the modifier
+	// is called after the default build options are set.
+	BuildOptionsModifier func(*client.ImageBuildOptions)
+}
+
+type ContainerFile struct {
+	HostFilePath      string    // If Reader is present, HostFilePath is ignored
+	Reader            io.Reader // If Reader is present, HostFilePath is ignored
+	ContainerFilePath string
+	FileMode          int64
+}
+
+// validate validates the ContainerFile
+func (c *ContainerFile) validate() error {
+	if c.HostFilePath == "" && c.Reader == nil {
+		return errors.New("either HostFilePath or Reader must be specified")
+	}
+
+	if c.ContainerFilePath == "" {
+		return errors.New("ContainerFilePath must be specified")
+	}
+
+	return nil
+}
+
+// ContainerRequest represents the parameters used to get a running container
+type ContainerRequest struct {
+	FromDockerfile
+	HostAccessPorts          []int
+	Image                    string
+	ImageSubstitutors        []ImageSubstitutor
+	Entrypoint               []string
+	Env                      map[string]string
+	ExposedPorts             []string // allow specifying protocol info
+	Cmd                      []string
+	Labels                   map[string]string
+	Mounts                   ContainerMounts
+	Tmpfs                    map[string]string
+	RegistryCred             string // Deprecated: Testcontainers will detect registry credentials automatically
+	WaitingFor               wait.Strategy
+	Name                     string                                     // for specifying container name
+	Hostname                 string                                     // Deprecated: Use [ConfigModifier] instead. S
+	WorkingDir               string                                     // Deprecated: Use [ConfigModifier] instead. Specify the working directory of the container
+	ExtraHosts               []string                                   // Deprecated: Use HostConfigModifier instead
+	Privileged               bool                                       // Deprecated: Use [HostConfigModifier] instead. For starting privileged container
+	Networks                 []string                                   // for specifying network names
+	NetworkAliases           map[string][]string                        // for specifying network aliases
+	NetworkMode              container.NetworkMode                      // Deprecated: Use HostConfigModifier instead
+	Resources                container.Resources                        // Deprecated: Use HostConfigModifier instead
+	Files                    []ContainerFile                            // files which will be copied when container starts
+	User                     string                                     // Deprecated: Use [ConfigModifier] instead. For specifying uid:gid
+	SkipReaper               bool                                       // Deprecated: The reaper is globally controlled by the .testcontainers.properties file or the TESTCONTAINERS_RYUK_DISABLED environment variable
+	ReaperImage              string                                     // Deprecated: use WithImageName ContainerOption instead. Alternative reaper image
+	ReaperOptions            []ContainerOption                          // Deprecated: the reaper is configured at the properties level, for an entire test session
+	AutoRemove               bool                                       // Deprecated: Use HostConfigModifier instead. If set to true, the container will be removed from the host when stopped
+	AlwaysPullImage          bool                                       // Always pull image
+	ImagePlatform            string                                     // ImagePlatform describes the platform which the image runs on.
+	Binds                    []string                                   // Deprecated: Use HostConfigModifier instead
+	ShmSize                  int64                                      // Deprecated: Use [HostConfigModifier] instead. Amount of memory shared with the host (in bytes)
+	CapAdd                   []string                                   // Deprecated: Use HostConfigModifier instead. Add Linux capabilities
+	CapDrop                  []string                                   // Deprecated: Use HostConfigModifier instead. Drop Linux capabilities
+	ConfigModifier           func(*container.Config)                    // Modifier for the config before container creation
+	HostConfigModifier       func(*container.HostConfig)                // Modifier for the host config before container creation
+	EndpointSettingsModifier func(map[string]*network.EndpointSettings) // Modifier for the network settings before container creation
+	LifecycleHooks           []ContainerLifecycleHooks                  // define hooks to be executed during container lifecycle
+	LogConsumerCfg           *LogConsumerConfig                         // define the configuration for the log producer and its log consumers to follow the logs
+}
+
+// sessionID returns the session ID for the container request.
+func (c *ContainerRequest) sessionID() string {
+	if sessionID := c.Labels[core.LabelSessionID]; sessionID != "" {
+		return sessionID
+	}
+
+	return core.SessionID()
+}
+
+// containerOptions functional options for a container
+type containerOptions struct {
+	ImageName           string
+	RegistryCredentials string // Deprecated: Testcontainers will detect registry credentials automatically
+}
+
+// Deprecated: it will be removed in the next major release
+// functional option for setting the reaper image
+type ContainerOption func(*containerOptions)
+
+// Deprecated: it will be removed in the next major release
+// WithImageName sets the reaper image name
+func WithImageName(imageName string) ContainerOption {
+	return func(o *containerOptions) {
+		o.ImageName = imageName
+	}
+}
+
+// Deprecated: Testcontainers will detect registry credentials automatically, and it will be removed in the next major release
+// WithRegistryCredentials sets the reaper registry credentials
+func WithRegistryCredentials(registryCredentials string) ContainerOption {
+	return func(o *containerOptions) {
+		o.RegistryCredentials = registryCredentials
+	}
+}
+
+// Validate ensures that the ContainerRequest does not have invalid parameters configured to it
+// ex. make sure you are not specifying both an image as well as a context
+func (c *ContainerRequest) Validate() error {
+	validationMethods := []func() error{
+		c.validateContextAndImage,
+		c.validateContextOrImageIsSpecified,
+		c.validateMounts,
+	}
+
+	var err error
+	for _, validationMethod := range validationMethods {
+		err = validationMethod()
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// GetContext retrieve the build context for the request
+// Must be closed when no longer needed.
+func (c *ContainerRequest) GetContext() (io.Reader, error) {
+	includes := []string{"."}
+
+	if c.ContextArchive != nil {
+		return c.ContextArchive, nil
+	}
+
+	// always pass context as absolute path
+	abs, err := filepath.Abs(c.Context)
+	if err != nil {
+		return nil, fmt.Errorf("error getting absolute path: %w", err)
+	}
+	c.Context = abs
+
+	dockerIgnoreExists, excluded, err := parseDockerIgnore(abs)
+	if err != nil {
+		return nil, err
+	}
+
+	if dockerIgnoreExists {
+		// only add .dockerignore if it exists
+		includes = append(includes, ".dockerignore")
+	}
+
+	includes = append(includes, c.GetDockerfile())
+
+	buildContext, err := archive.TarWithOptions(
+		c.Context,
+		&archive.TarOptions{ExcludePatterns: excluded, IncludeFiles: includes},
+	)
+	if err != nil {
+		return nil, err
+	}
+
+	return buildContext, nil
+}
+
+// parseDockerIgnore returns if the file exists, the excluded files and an error if any
+func parseDockerIgnore(targetDir string) (bool, []string, error) {
+	// based on https://github.com/docker/cli/blob/master/cli/command/image/build/dockerignore.go#L14
+	fileLocation := filepath.Join(targetDir, ".dockerignore")
+	var excluded []string
+	exists := false
+	if f, openErr := os.Open(fileLocation); openErr == nil {
+		defer f.Close()
+
+		exists = true
+
+		var err error
+		excluded, err = ignorefile.ReadAll(f)
+		if err != nil {
+			return true, excluded, fmt.Errorf("error reading .dockerignore: %w", err)
+		}
+	}
+	return exists, excluded, nil
+}
+
+// GetBuildArgs returns the env args to be used when creating from Dockerfile
+func (c *ContainerRequest) GetBuildArgs() map[string]*string {
+	return c.BuildArgs
+}
+
+// GetDockerfile returns the Dockerfile from the ContainerRequest, defaults to "Dockerfile".
+// Sets FromDockerfile.Dockerfile to the default if blank.
+func (c *ContainerRequest) GetDockerfile() string {
+	if c.Dockerfile == "" {
+		c.Dockerfile = "Dockerfile"
+	}
+
+	return c.Dockerfile
+}
+
+// GetRepo returns the Repo label for image from the ContainerRequest, defaults to UUID.
+// Sets FromDockerfile.Repo to the default value if blank.
+func (c *ContainerRequest) GetRepo() string {
+	if c.Repo == "" {
+		c.Repo = uuid.NewString()
+	}
+
+	return strings.ToLower(c.Repo)
+}
+
+// GetTag returns the Tag label for image from the ContainerRequest, defaults to UUID.
+// Sets FromDockerfile.Tag to the default value if blank.
+func (c *ContainerRequest) GetTag() string {
+	if c.Tag == "" {
+		c.Tag = uuid.NewString()
+	}
+
+	return strings.ToLower(c.Tag)
+}
+
+// Deprecated: Testcontainers will detect registry credentials automatically, and it will be removed in the next major release.
+// GetAuthConfigs returns the auth configs to be able to pull from an authenticated docker registry.
+// Panics if an error occurs.
+func (c *ContainerRequest) GetAuthConfigs() map[string]registry.AuthConfig {
+	auth, err := getAuthConfigsFromDockerfile(c)
+	if err != nil {
+		panic(fmt.Sprintf("failed to get auth configs from Dockerfile: %v", err))
+	}
+	return auth
+}
+
+// dockerFileImages returns the images from the request Dockerfile.
+func (c *ContainerRequest) dockerFileImages() ([]string, error) {
+	if c.ContextArchive == nil {
+		// Source is a directory, we can read the Dockerfile directly.
+		images, err := core.ExtractImagesFromDockerfile(filepath.Join(c.Context, c.GetDockerfile()), c.GetBuildArgs())
+		if err != nil {
+			return nil, fmt.Errorf("extract images from Dockerfile: %w", err)
+		}
+
+		return images, nil
+	}
+
+	// Source is an archive, we need to read it to get the Dockerfile.
+	dockerFile := c.GetDockerfile()
+	tr := tar.NewReader(c.ContextArchive)
+
+	for {
+		hdr, err := tr.Next()
+		if err != nil {
+			if errors.Is(err, io.EOF) {
+				return nil, fmt.Errorf("dockerfile %q not found in context archive", dockerFile)
+			}
+
+			return nil, fmt.Errorf("reading tar archive: %w", err)
+		}
+
+		if hdr.Name != dockerFile {
+			continue
+		}
+
+		images, err := core.ExtractImagesFromReader(tr, c.GetBuildArgs())
+		if err != nil {
+			return nil, fmt.Errorf("extract images from Dockerfile: %w", err)
+		}
+
+		// Reset the archive to the beginning.
+		if _, err := c.ContextArchive.Seek(0, io.SeekStart); err != nil {
+			return nil, fmt.Errorf("seek context archive to start: %w", err)
+		}
+
+		return images, nil
+	}
+}
+
+// getAuthConfigsFromDockerfile returns the auth configs to be able to pull from an authenticated docker registry
+func getAuthConfigsFromDockerfile(c *ContainerRequest) (map[string]registry.AuthConfig, error) {
+	images, err := c.dockerFileImages()
+	if err != nil {
+		return nil, fmt.Errorf("docker file images: %w", err)
+	}
+
+	// Get the auth configs once for all images as it can be a time-consuming operation.
+	configs, err := getDockerAuthConfigs()
+	if err != nil {
+		return nil, err
+	}
+
+	authConfigs := map[string]registry.AuthConfig{}
+	for _, image := range images {
+		registry, authConfig, err := dockerImageAuth(context.Background(), image, configs)
+		if err != nil {
+			if !errors.Is(err, dockercfg.ErrCredentialsNotFound) {
+				return nil, fmt.Errorf("docker image auth %q: %w", image, err)
+			}
+
+			// Credentials not found no config to add.
+			continue
+		}
+
+		authConfigs[registry] = authConfig
+	}
+
+	return authConfigs, nil
+}
+
+func (c *ContainerRequest) ShouldBuildImage() bool {
+	return c.Context != "" || c.ContextArchive != nil
+}
+
+func (c *ContainerRequest) ShouldKeepBuiltImage() bool {
+	return c.KeepImage
+}
+
+// BuildLogWriter returns the io.Writer for output of log when building a Docker image from
+// a Dockerfile. It returns the BuildLogWriter from the ContainerRequest, defaults to io.Discard.
+// For backward compatibility, if BuildLogWriter is default and PrintBuildLog is true,
+// the function returns os.Stderr.
+//
+//nolint:staticcheck //FIXME
+func (c *ContainerRequest) BuildLogWriter() io.Writer {
+	if c.FromDockerfile.BuildLogWriter != nil {
+		return c.FromDockerfile.BuildLogWriter
+	}
+	if c.PrintBuildLog {
+		c.FromDockerfile.BuildLogWriter = os.Stderr
+	} else {
+		c.FromDockerfile.BuildLogWriter = io.Discard
+	}
+	return c.FromDockerfile.BuildLogWriter
+}
+
+// BuildOptions returns the image build options when building a Docker image from a Dockerfile.
+// It will apply some defaults and finally call the BuildOptionsModifier from the FromDockerfile struct,
+// if set.
+func (c *ContainerRequest) BuildOptions() (client.ImageBuildOptions, error) {
+	buildOptions := client.ImageBuildOptions{
+		Remove:      true,
+		ForceRemove: true,
+	}
+
+	if c.BuildOptionsModifier != nil {
+		c.BuildOptionsModifier(&buildOptions)
+	}
+
+	// apply mandatory values after the modifier
+	buildOptions.BuildArgs = c.GetBuildArgs()
+	buildOptions.Dockerfile = c.GetDockerfile()
+
+	// Make sure the auth configs from the Dockerfile are set right after the user-defined build options.
+	authsFromDockerfile, err := getAuthConfigsFromDockerfile(c)
+	if err != nil {
+		return client.ImageBuildOptions{}, fmt.Errorf("auth configs from Dockerfile: %w", err)
+	}
+
+	if buildOptions.AuthConfigs == nil {
+		buildOptions.AuthConfigs = map[string]registry.AuthConfig{}
+	}
+
+	maps.Copy(buildOptions.AuthConfigs, authsFromDockerfile)
+
+	// make sure the first tag is the one defined in the ContainerRequest
+	tag := fmt.Sprintf("%s:%s", c.GetRepo(), c.GetTag())
+
+	// apply substitutors to the built image
+	for _, is := range c.ImageSubstitutors {
+		modifiedTag, err := is.Substitute(tag)
+		if err != nil {
+			return client.ImageBuildOptions{}, fmt.Errorf("failed to substitute image %s with %s: %w", tag, is.Description(), err)
+		}
+
+		if modifiedTag != tag {
+			log.Printf("✍🏼 Replacing image with %s. From: %s to %s\n", is.Description(), tag, modifiedTag)
+			tag = modifiedTag
+		}
+	}
+
+	if len(buildOptions.Tags) > 0 {
+		// prepend the tag
+		buildOptions.Tags = append([]string{tag}, buildOptions.Tags...)
+	} else {
+		buildOptions.Tags = []string{tag}
+	}
+
+	if !c.ShouldKeepBuiltImage() {
+		dst := GenericLabels()
+		if err = core.MergeCustomLabels(dst, c.Labels); err != nil {
+			return client.ImageBuildOptions{}, err
+		}
+		if err = core.MergeCustomLabels(dst, buildOptions.Labels); err != nil {
+			return client.ImageBuildOptions{}, err
+		}
+		buildOptions.Labels = dst
+	}
+
+	// Do this as late as possible to ensure we don't leak the context on error/panic.
+	buildContext, err := c.GetContext()
+	if err != nil {
+		return client.ImageBuildOptions{}, err
+	}
+
+	buildOptions.Context = buildContext
+
+	return buildOptions, nil
+}
+
+func (c *ContainerRequest) validateContextAndImage() error {
+	if c.Context != "" && c.Image != "" {
+		return errors.New("you cannot specify both an Image and Context in a ContainerRequest")
+	}
+
+	return nil
+}
+
+func (c *ContainerRequest) validateContextOrImageIsSpecified() error {
+	if c.Context == "" && c.ContextArchive == nil && c.Image == "" {
+		return errors.New("you must specify either a build context or an image")
+	}
+
+	return nil
+}
+
+// validateMounts ensures that the mounts do not have duplicate targets.
+// It will check the Mounts and HostConfigModifier.Binds fields.
+func (c *ContainerRequest) validateMounts() error {
+	targets := make(map[string]bool, len(c.Mounts))
+
+	for idx := range c.Mounts {
+		m := c.Mounts[idx]
+		targetPath := m.Target.Target()
+		if targets[targetPath] {
+			return fmt.Errorf("%w: %s", ErrDuplicateMountTarget, targetPath)
+		}
+		targets[targetPath] = true
+	}
+
+	if c.HostConfigModifier == nil {
+		return nil
+	}
+
+	hostConfig := container.HostConfig{}
+
+	c.HostConfigModifier(&hostConfig)
+
+	if len(hostConfig.Binds) > 0 {
+		for _, bind := range hostConfig.Binds {
+			parts := strings.Split(bind, ":")
+			if len(parts) != 2 && len(parts) != 3 {
+				return fmt.Errorf("%w: %s", ErrInvalidBindMount, bind)
+			}
+			targetPath := parts[1]
+			if targets[targetPath] {
+				return fmt.Errorf("%w: %s", ErrDuplicateMountTarget, targetPath)
+			}
+			targets[targetPath] = true
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/docker.go b/vendor/github.com/testcontainers/testcontainers-go/docker.go
new file mode 100644
index 000000000..4346531b5
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/docker.go
@@ -0,0 +1,1953 @@
+package testcontainers
+
+import (
+	"archive/tar"
+	"bufio"
+	"context"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"io/fs"
+	"net"
+	"net/url"
+	"os"
+	"path/filepath"
+	"regexp"
+	"slices"
+	"strconv"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/cenkalti/backoff/v4"
+	"github.com/containerd/errdefs"
+	"github.com/containerd/platforms"
+	"github.com/moby/moby/api/pkg/authconfig"
+	"github.com/moby/moby/api/pkg/stdcopy"
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+	"github.com/moby/moby/client"
+	"github.com/moby/moby/client/pkg/jsonmessage"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+
+	tcexec "github.com/testcontainers/testcontainers-go/exec"
+	"github.com/testcontainers/testcontainers-go/internal/config"
+	"github.com/testcontainers/testcontainers-go/internal/core"
+	"github.com/testcontainers/testcontainers-go/log"
+	"github.com/testcontainers/testcontainers-go/wait"
+)
+
+// Implement interfaces
+var _ Container = (*DockerContainer)(nil)
+
+const (
+	Bridge        = "bridge" // Bridge network name (as well as driver)
+	Podman        = "podman"
+	ReaperDefault = "reaper_default" // Default network name when bridge is not available
+	packagePath   = "github.com/testcontainers/testcontainers-go"
+)
+
+var (
+	// createContainerFailDueToNameConflictRegex is a regular expression that matches the container is already in use error.
+	createContainerFailDueToNameConflictRegex = regexp.MustCompile("[Tt]he container name .* is already in use by .*")
+
+	// minLogProductionTimeout is the minimum log production timeout.
+	minLogProductionTimeout = time.Duration(5 * time.Second)
+
+	// maxLogProductionTimeout is the maximum log production timeout.
+	maxLogProductionTimeout = time.Duration(60 * time.Second)
+
+	// errLogProductionStop is the cause for stopping log production.
+	errLogProductionStop = errors.New("log production stopped")
+)
+
+// DockerContainer represents a container started using Docker
+type DockerContainer struct {
+	// Container ID from Docker
+	ID           string
+	WaitingFor   wait.Strategy
+	Image        string
+	exposedPorts []string // a reference to the container's requested exposed ports. It allows checking they are ready before any wait strategy
+
+	isRunning     atomic.Bool
+	imageWasBuilt bool
+	// keepBuiltImage makes Terminate not remove the image if imageWasBuilt.
+	keepBuiltImage    bool
+	provider          *DockerProvider
+	sessionID         string
+	terminationSignal chan bool
+	consumersMtx      sync.Mutex // protects consumers
+	consumers         []LogConsumer
+
+	// TODO: Remove locking and wait group once the deprecated StartLogProducer and
+	// StopLogProducer have been removed and hence logging can only be started and
+	// stopped once.
+
+	// logProductionCancel is used to signal the log production to stop.
+	logProductionCancel context.CancelCauseFunc
+	logProductionCtx    context.Context
+	// logProductionDone is closed when the log production goroutine exits.
+	logProductionDone chan struct{}
+
+	logProductionTimeout *time.Duration
+	logger               log.Logger
+	lifecycleHooks       []ContainerLifecycleHooks
+
+	healthStatus container.HealthStatus // container health status, will default to healthStatusNone if no healthcheck is present
+}
+
+// SetLogger sets the logger for the container
+func (c *DockerContainer) SetLogger(logger log.Logger) {
+	c.logger = logger
+}
+
+// SetProvider sets the provider for the container
+func (c *DockerContainer) SetProvider(provider *DockerProvider) {
+	c.provider = provider
+}
+
+// SetTerminationSignal sets the termination signal for the container
+func (c *DockerContainer) SetTerminationSignal(signal chan bool) {
+	c.terminationSignal = signal
+}
+
+func (c *DockerContainer) GetContainerID() string {
+	return c.ID
+}
+
+func (c *DockerContainer) IsRunning() bool {
+	return c.isRunning.Load()
+}
+
+// Endpoint gets proto://host:port string for the lowest numbered exposed port
+// Will returns just host:port if proto is ""
+func (c *DockerContainer) Endpoint(ctx context.Context, proto string) (string, error) {
+	inspect, err := c.Inspect(ctx)
+	if err != nil {
+		return "", err
+	}
+
+	// Get lowest numbered bound port.
+	var lowestPort network.Port
+	for port := range inspect.NetworkSettings.Ports {
+		if lowestPort.IsZero() || port.Num() < lowestPort.Num() {
+			lowestPort = port
+		}
+	}
+
+	return c.PortEndpoint(ctx, lowestPort.String(), proto)
+}
+
+// PortEndpoint gets proto://host:port string for the given exposed port
+// It returns proto://host:port or proto://[IPv6host]:port string for the given exposed port.
+// It returns just host:port or [IPv6host]:port if proto is blank.
+func (c *DockerContainer) PortEndpoint(ctx context.Context, port string, proto string) (string, error) {
+	host, err := c.Host(ctx)
+	if err != nil {
+		return "", err
+	}
+
+	outerPort, err := c.MappedPort(ctx, port)
+	if err != nil {
+		return "", err
+	}
+
+	hostPort := net.JoinHostPort(host, outerPort.Port())
+	if proto == "" {
+		return hostPort, nil
+	}
+
+	return proto + "://" + hostPort, nil
+}
+
+// Host gets host (ip or name) of the docker daemon where the container port is exposed
+// Warning: this is based on your Docker host setting. Will fail if using an SSH tunnel
+// You can use the "TESTCONTAINERS_HOST_OVERRIDE" env variable to set this yourself
+func (c *DockerContainer) Host(ctx context.Context) (string, error) {
+	host, err := c.provider.DaemonHost(ctx)
+	if err != nil {
+		return "", err
+	}
+	return host, nil
+}
+
+// Inspect gets the raw container info
+func (c *DockerContainer) Inspect(ctx context.Context) (*container.InspectResponse, error) {
+	jsonRaw, err := c.inspectRawContainer(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	return &jsonRaw.Container, nil
+}
+
+// MappedPort gets externally mapped port for a container port
+func (c *DockerContainer) MappedPort(ctx context.Context, port string) (network.Port, error) {
+	inspect, err := c.Inspect(ctx)
+	if err != nil {
+		return network.Port{}, fmt.Errorf("inspect: %w", err)
+	}
+	// The old nat.Port type (a plain string) accepted empty strings:
+	// nat.SplitProtoPort("") returns ("", ""), so Port() == "" and
+	// no container port matches, yielding "not found".
+	// See https://github.com/docker/go-connections/blob/v0.6.0/nat/nat.go#L101-L110
+	// Skip parsing here to preserve that behavior and avoid a
+	// ParsePort error on empty input.
+	var nwPort network.Port
+	if port != "" {
+		nwPort, err = network.ParsePort(port)
+		if err != nil {
+			return network.Port{}, err
+		}
+	}
+
+	if inspect.HostConfig.NetworkMode == "host" {
+		return nwPort, nil
+	}
+
+	ports := inspect.NetworkSettings.Ports
+
+	for k, p := range ports {
+		if k.Num() != nwPort.Num() {
+			continue
+		}
+		if nwPort.Proto() != "" && k.Proto() != nwPort.Proto() {
+			continue
+		}
+		if len(p) == 0 {
+			continue
+		}
+		pNum, _ := strconv.ParseUint(p[0].HostPort, 10, 16)
+		hPort, _ := network.PortFrom(uint16(pNum), k.Proto())
+		return hPort, nil
+	}
+
+	return network.Port{}, errdefs.ErrNotFound.WithMessage(fmt.Sprintf("port %q not found", nwPort))
+}
+
+// Deprecated: use c.Inspect(ctx).NetworkSettings.Ports instead.
+// Ports gets the exposed ports for the container.
+func (c *DockerContainer) Ports(ctx context.Context) (network.PortMap, error) {
+	inspect, err := c.Inspect(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return inspect.NetworkSettings.Ports, nil
+}
+
+// SessionID gets the current session id
+func (c *DockerContainer) SessionID() string {
+	return c.sessionID
+}
+
+// Start will start an already created container
+func (c *DockerContainer) Start(ctx context.Context) error {
+	err := c.startingHook(ctx)
+	if err != nil {
+		return fmt.Errorf("starting hook: %w", err)
+	}
+
+	if _, err := c.provider.client.ContainerStart(ctx, c.ID, client.ContainerStartOptions{}); err != nil {
+		return fmt.Errorf("container start: %w", err)
+	}
+	defer c.provider.Close()
+
+	err = c.startedHook(ctx)
+	if err != nil {
+		return fmt.Errorf("started hook: %w", err)
+	}
+
+	c.isRunning.Store(true)
+
+	err = c.readiedHook(ctx)
+	if err != nil {
+		return fmt.Errorf("readied hook: %w", err)
+	}
+
+	return nil
+}
+
+// Stop stops the container.
+//
+// In case the container fails to stop gracefully within a time frame specified
+// by the timeout argument, it is forcefully terminated (killed).
+//
+// If the timeout is nil, the container's StopTimeout value is used, if set,
+// otherwise the engine default. A negative timeout value can be specified,
+// meaning no timeout, i.e. no forceful termination is performed.
+//
+// All hooks are called in the following order:
+//   - [ContainerLifecycleHooks.PreStops]
+//   - [ContainerLifecycleHooks.PostStops]
+//
+// If the container is already stopped, the method is a no-op.
+func (c *DockerContainer) Stop(ctx context.Context, timeout *time.Duration) error {
+	// Note we can't check isRunning here because we allow external creation
+	// without exposing the ability to fully initialize the container state.
+	// See: https://github.com/testcontainers/testcontainers-go/issues/2667
+	// TODO: Add a check for isRunning when the above issue is resolved.
+	err := c.stoppingHook(ctx)
+	if err != nil {
+		return fmt.Errorf("stopping hook: %w", err)
+	}
+
+	var options client.ContainerStopOptions
+
+	if timeout != nil {
+		timeoutSeconds := int(timeout.Seconds())
+		options.Timeout = &timeoutSeconds
+	}
+
+	if _, err := c.provider.client.ContainerStop(ctx, c.ID, options); err != nil {
+		return fmt.Errorf("container stop: %w", err)
+	}
+
+	defer c.provider.Close()
+
+	c.isRunning.Store(false)
+
+	err = c.stoppedHook(ctx)
+	if err != nil {
+		return fmt.Errorf("stopped hook: %w", err)
+	}
+
+	return nil
+}
+
+// Terminate calls stops and then removes the container including its volumes.
+// If its image was built it and all child images are also removed unless
+// the [FromDockerfile.KeepImage] on the [ContainerRequest] was set to true.
+//
+// The following hooks are called in order:
+//   - [ContainerLifecycleHooks.PreTerminates]
+//   - [ContainerLifecycleHooks.PostTerminates]
+//
+// Default: timeout is 10 seconds.
+func (c *DockerContainer) Terminate(ctx context.Context, opts ...TerminateOption) error {
+	if c == nil {
+		return nil
+	}
+
+	options := NewTerminateOptions(ctx, opts...)
+	err := c.Stop(options.Context(), options.StopTimeout())
+	if err != nil && !isCleanupSafe(err) {
+		return fmt.Errorf("stop: %w", err)
+	}
+
+	select {
+	// Close reaper connection if it was attached.
+	case c.terminationSignal <- true:
+	default:
+	}
+
+	defer c.provider.client.Close()
+
+	// TODO: Handle errors from ContainerRemove more correctly, e.g. should we
+	// run the terminated hook?
+	var errs []error
+	errs = append(errs, c.terminatingHook(ctx))
+	_, err = c.provider.client.ContainerRemove(ctx, c.GetContainerID(), client.ContainerRemoveOptions{
+		RemoveVolumes: true,
+		Force:         true,
+	})
+	errs = append(errs, err)
+	errs = append(errs, c.terminatedHook(ctx))
+
+	if c.imageWasBuilt && !c.keepBuiltImage {
+		_, err := c.provider.client.ImageRemove(ctx, c.Image, client.ImageRemoveOptions{
+			Force:         true,
+			PruneChildren: true,
+		})
+		errs = append(errs, err)
+	}
+
+	c.sessionID = ""
+	c.isRunning.Store(false)
+
+	if err = options.Cleanup(); err != nil {
+		errs = append(errs, err)
+	}
+
+	return errors.Join(errs...)
+}
+
+// update container raw info
+func (c *DockerContainer) inspectRawContainer(ctx context.Context) (*client.ContainerInspectResult, error) {
+	defer c.provider.Close()
+	inspect, err := c.provider.client.ContainerInspect(ctx, c.ID, client.ContainerInspectOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	return &inspect, nil
+}
+
+// Logs will fetch both STDOUT and STDERR from the current container. Returns a
+// ReadCloser and leaves it up to the caller to extract what it wants.
+func (c *DockerContainer) Logs(ctx context.Context) (io.ReadCloser, error) {
+	rc, err := c.provider.client.ContainerLogs(ctx, c.ID, client.ContainerLogsOptions{
+		ShowStdout: true,
+		ShowStderr: true,
+	})
+	if err != nil {
+		return nil, err
+	}
+	defer c.provider.Close()
+
+	resp, err := c.Inspect(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	if resp.Config.Tty {
+		return rc, nil
+	}
+
+	return c.parseMultiplexedLogs(rc), nil
+}
+
+// parseMultiplexedLogs handles the multiplexed log format used when TTY is disabled
+func (c *DockerContainer) parseMultiplexedLogs(rc io.ReadCloser) io.ReadCloser {
+	const streamHeaderSize = 8
+
+	pr, pw := io.Pipe()
+	r := bufio.NewReader(rc)
+
+	go func() {
+		header := make([]byte, streamHeaderSize)
+		for {
+			_, errH := io.ReadFull(r, header)
+			if errH != nil {
+				_ = pw.CloseWithError(errH)
+				return
+			}
+
+			frameSize := binary.BigEndian.Uint32(header[4:])
+			if _, err := io.CopyN(pw, r, int64(frameSize)); err != nil {
+				pw.CloseWithError(err)
+				return
+			}
+		}
+	}()
+
+	return pr
+}
+
+// Deprecated: use the ContainerRequest.LogConsumerConfig field instead.
+func (c *DockerContainer) FollowOutput(consumer LogConsumer) {
+	c.followOutput(consumer)
+}
+
+// followOutput adds a LogConsumer to be sent logs from the container's
+// STDOUT and STDERR
+func (c *DockerContainer) followOutput(consumer LogConsumer) {
+	c.consumersMtx.Lock()
+	defer c.consumersMtx.Unlock()
+
+	c.consumers = append(c.consumers, consumer)
+}
+
+// consumersCopy returns a copy of the current consumers.
+func (c *DockerContainer) consumersCopy() []LogConsumer {
+	c.consumersMtx.Lock()
+	defer c.consumersMtx.Unlock()
+
+	return slices.Clone(c.consumers)
+}
+
+// resetConsumers resets the current consumers to the provided ones.
+func (c *DockerContainer) resetConsumers(consumers []LogConsumer) {
+	c.consumersMtx.Lock()
+	defer c.consumersMtx.Unlock()
+
+	c.consumers = c.consumers[:0]
+	c.consumers = append(c.consumers, consumers...)
+}
+
+// Deprecated: use c.Inspect(ctx).Name instead.
+// Name gets the name of the container.
+func (c *DockerContainer) Name(ctx context.Context) (string, error) {
+	inspect, err := c.Inspect(ctx)
+	if err != nil {
+		return "", err
+	}
+	return inspect.Name, nil
+}
+
+// State returns container's running state.
+func (c *DockerContainer) State(ctx context.Context) (*container.State, error) {
+	inspect, err := c.inspectRawContainer(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return inspect.Container.State, nil
+}
+
+// Networks gets the names of the networks the container is attached to.
+func (c *DockerContainer) Networks(ctx context.Context) ([]string, error) {
+	inspect, err := c.Inspect(ctx)
+	if err != nil {
+		return []string{}, err
+	}
+
+	networks := inspect.NetworkSettings.Networks
+
+	n := []string{}
+
+	for k := range networks {
+		n = append(n, k)
+	}
+
+	return n, nil
+}
+
+// ContainerIP gets the IP address of the primary network within the container.
+func (c *DockerContainer) ContainerIP(ctx context.Context) (string, error) {
+	inspect, err := c.Inspect(ctx)
+	if err != nil {
+		return "", err
+	}
+
+	var ip string
+	//  IPAddress is deprecated; use IP from "Networks" if only single network defined
+	networks := inspect.NetworkSettings.Networks
+	if len(networks) == 1 {
+		for _, v := range networks {
+			if v.IPAddress.IsValid() {
+				ip = v.IPAddress.String()
+			}
+		}
+	}
+
+	return ip, nil
+}
+
+// ContainerIPs gets the IP addresses of all the networks within the container.
+func (c *DockerContainer) ContainerIPs(ctx context.Context) ([]string, error) {
+	inspect, err := c.Inspect(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	networks := inspect.NetworkSettings.Networks
+	ips := make([]string, 0, len(networks))
+	for _, nw := range networks {
+		if nw.IPAddress.IsValid() {
+			ips = append(ips, nw.IPAddress.String())
+		}
+	}
+
+	return ips, nil
+}
+
+// NetworkAliases gets the aliases of the container for the networks it is attached to.
+func (c *DockerContainer) NetworkAliases(ctx context.Context) (map[string][]string, error) {
+	inspect, err := c.Inspect(ctx)
+	if err != nil {
+		return map[string][]string{}, err
+	}
+
+	networks := inspect.NetworkSettings.Networks
+
+	a := map[string][]string{}
+
+	for k := range networks {
+		a[k] = networks[k].Aliases
+	}
+
+	return a, nil
+}
+
+// Exec executes a command in the current container.
+// It returns the exit status of the executed command, an [io.Reader] containing the combined
+// stdout and stderr, and any encountered error. Note that reading directly from the [io.Reader]
+// may result in unexpected bytes due to custom stream multiplexing headers.
+// Use [tcexec.Multiplexed] option to read the combined output without the multiplexing headers.
+// Alternatively, to separate the stdout and stderr from [io.Reader] and interpret these headers properly,
+// [github.com/docker/docker/pkg/stdcopy.StdCopy] from the Docker API should be used.
+func (c *DockerContainer) Exec(ctx context.Context, cmd []string, options ...tcexec.ProcessOption) (int, io.Reader, error) {
+	cli := c.provider.client
+
+	processOptions := tcexec.NewProcessOptions(cmd)
+
+	// processing all the options in a first loop because for the multiplexed option
+	// we first need to have a containerExecCreateResponse
+	for _, o := range options {
+		o.Apply(processOptions)
+	}
+
+	response, err := cli.ExecCreate(ctx, c.ID, processOptions.ExecConfig)
+	if err != nil {
+		return 0, nil, fmt.Errorf("container exec create: %w", err)
+	}
+
+	hijack, err := cli.ExecAttach(ctx, response.ID, client.ExecAttachOptions{})
+	if err != nil {
+		return 0, nil, fmt.Errorf("container exec attach: %w", err)
+	}
+
+	processOptions.Reader = hijack.Reader
+
+	// second loop to process the multiplexed option, as now we have a reader
+	// from the created exec response.
+	for _, o := range options {
+		o.Apply(processOptions)
+	}
+
+	var exitCode int
+	for {
+		execResp, err := cli.ExecInspect(ctx, response.ID, client.ExecInspectOptions{})
+		if err != nil {
+			return 0, nil, fmt.Errorf("container exec inspect: %w", err)
+		}
+
+		if !execResp.Running {
+			exitCode = execResp.ExitCode
+			break
+		}
+
+		time.Sleep(100 * time.Millisecond)
+	}
+
+	return exitCode, processOptions.Reader, nil
+}
+
+type FileFromContainer struct {
+	underlying *io.ReadCloser
+	tarreader  *tar.Reader
+}
+
+func (fc *FileFromContainer) Read(b []byte) (int, error) {
+	return (*fc.tarreader).Read(b)
+}
+
+func (fc *FileFromContainer) Close() error {
+	return (*fc.underlying).Close()
+}
+
+func (c *DockerContainer) CopyFileFromContainer(ctx context.Context, filePath string) (io.ReadCloser, error) {
+	r, err := c.provider.client.CopyFromContainer(ctx, c.ID, client.CopyFromContainerOptions{
+		SourcePath: filePath,
+	})
+	if err != nil {
+		return nil, err
+	}
+	defer c.provider.Close()
+
+	tarReader := tar.NewReader(r.Content)
+
+	// if we got here we have exactly one file in the TAR-stream
+	// so we advance the index by one so the next call to Read will start reading it
+	_, err = tarReader.Next()
+	if err != nil {
+		return nil, err
+	}
+
+	ret := &FileFromContainer{
+		underlying: &r.Content,
+		tarreader:  tarReader,
+	}
+
+	return ret, nil
+}
+
+// CopyDirToContainer copies the contents of a directory to a parent path in the container. This parent path must exist in the container first
+// as we cannot create it
+func (c *DockerContainer) CopyDirToContainer(ctx context.Context, hostDirPath string, containerParentPath string, fileMode int64) error {
+	dir, err := isDir(hostDirPath)
+	if err != nil {
+		return err
+	}
+
+	if !dir {
+		// it's not a dir: let the consumer handle the error
+		return fmt.Errorf("path %s is not a directory", hostDirPath)
+	}
+
+	buff, err := tarDir(hostDirPath, fileMode)
+	if err != nil {
+		return err
+	}
+
+	// create the directory under its parent
+	parent := filepath.Dir(containerParentPath)
+
+	_, err = c.provider.client.CopyToContainer(ctx, c.ID, client.CopyToContainerOptions{
+		DestinationPath: parent,
+		Content:         buff,
+	})
+	if err != nil {
+		return err
+	}
+	defer c.provider.Close()
+
+	return nil
+}
+
+func (c *DockerContainer) CopyFileToContainer(ctx context.Context, hostFilePath string, containerFilePath string, fileMode int64) error {
+	dir, err := isDir(hostFilePath)
+	if err != nil {
+		return err
+	}
+
+	if dir {
+		return c.CopyDirToContainer(ctx, hostFilePath, containerFilePath, fileMode)
+	}
+
+	f, err := os.Open(hostFilePath)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	info, err := f.Stat()
+	if err != nil {
+		return err
+	}
+
+	// In Go 1.22 os.File is always an io.WriterTo. However, testcontainers
+	// currently allows Go 1.21, so we need to trick the compiler a little.
+	var file fs.File = f
+	return c.copyToContainer(ctx, func(tw io.Writer) error {
+		// Attempt optimized writeTo, implemented in linux
+		if wt, ok := file.(io.WriterTo); ok {
+			_, err := wt.WriteTo(tw)
+			return err
+		}
+		_, err := io.Copy(tw, f)
+		return err
+	}, info.Size(), containerFilePath, fileMode)
+}
+
+// CopyToContainer copies fileContent data to a file in container
+func (c *DockerContainer) CopyToContainer(ctx context.Context, fileContent []byte, containerFilePath string, fileMode int64) error {
+	return c.copyToContainer(ctx, func(tw io.Writer) error {
+		_, err := tw.Write(fileContent)
+		return err
+	}, int64(len(fileContent)), containerFilePath, fileMode)
+}
+
+func (c *DockerContainer) copyToContainer(ctx context.Context, fileContent func(tw io.Writer) error, fileContentSize int64, containerFilePath string, fileMode int64) error {
+	buffer, err := tarFile(containerFilePath, fileContent, fileContentSize, fileMode)
+	if err != nil {
+		return err
+	}
+
+	_, err = c.provider.client.CopyToContainer(ctx, c.ID, client.CopyToContainerOptions{
+		DestinationPath: "/",
+		Content:         buffer,
+	})
+	if err != nil {
+		return err
+	}
+	defer c.provider.Close()
+
+	return nil
+}
+
+// logConsumerWriter is a writer that writes to a LogConsumer.
+type logConsumerWriter struct {
+	log       Log
+	consumers []LogConsumer
+}
+
+// newLogConsumerWriter creates a new logConsumerWriter for logType that sends messages to all consumers.
+func newLogConsumerWriter(logType string, consumers []LogConsumer) *logConsumerWriter {
+	return &logConsumerWriter{
+		log:       Log{LogType: logType},
+		consumers: consumers,
+	}
+}
+
+// Write writes the p content to all consumers.
+func (lw logConsumerWriter) Write(p []byte) (int, error) {
+	lw.log.Content = p
+	for _, consumer := range lw.consumers {
+		consumer.Accept(lw.log)
+	}
+	return len(p), nil
+}
+
+type LogProductionOption func(*DockerContainer)
+
+// WithLogProductionTimeout is a functional option that sets the timeout for the log production.
+// If the timeout is lower than 5s or greater than 60s it will be set to 5s or 60s respectively.
+func WithLogProductionTimeout(timeout time.Duration) LogProductionOption {
+	return func(c *DockerContainer) {
+		c.logProductionTimeout = &timeout
+	}
+}
+
+// Deprecated: use the ContainerRequest.LogConsumerConfig field instead.
+func (c *DockerContainer) StartLogProducer(ctx context.Context, opts ...LogProductionOption) error {
+	return c.startLogProduction(ctx, opts...)
+}
+
+// startLogProduction will start a concurrent process that will continuously read logs
+// from the container and will send them to each added LogConsumer.
+//
+// Default log production timeout is 5s. It is used to set the context timeout
+// which means that each log-reading loop will last at up to the specified timeout.
+//
+// Use functional option WithLogProductionTimeout() to override default timeout. If it's
+// lower than 5s and greater than 60s it will be set to 5s or 60s respectively.
+func (c *DockerContainer) startLogProduction(ctx context.Context, opts ...LogProductionOption) error {
+	for _, opt := range opts {
+		opt(c)
+	}
+
+	// Validate the log production timeout.
+	switch {
+	case c.logProductionTimeout == nil:
+		c.logProductionTimeout = &minLogProductionTimeout
+	case *c.logProductionTimeout < minLogProductionTimeout:
+		c.logProductionTimeout = &minLogProductionTimeout
+	case *c.logProductionTimeout > maxLogProductionTimeout:
+		c.logProductionTimeout = &maxLogProductionTimeout
+	}
+
+	// Setup the log writers.
+
+	consumers := c.consumersCopy()
+	stdout := newLogConsumerWriter(StdoutLog, consumers)
+	stderr := newLogConsumerWriter(StderrLog, consumers)
+
+	// Setup the log production context which will be used to stop the log production.
+	c.logProductionCtx, c.logProductionCancel = context.WithCancelCause(ctx)
+	c.logProductionDone = make(chan struct{})
+
+	// We capture context cancel function to avoid data race with multiple
+	// calls to startLogProduction.
+	go func(cancel context.CancelCauseFunc, done chan struct{}) {
+		// Ensure the context is cancelled when log productions completes
+		// so that GetLogProductionErrorChannel functions correctly.
+		defer cancel(nil)
+		// Signal that the goroutine has exited so stopLogProduction can drain.
+		defer close(done)
+
+		c.logProducer(stdout, stderr)
+	}(c.logProductionCancel, c.logProductionDone)
+
+	return nil
+}
+
+// logProducer read logs from the container and writes them to stdout, stderr until either:
+//   - logProductionCtx is done
+//   - A fatal error occurs
+//   - No more logs are available
+func (c *DockerContainer) logProducer(stdout, stderr io.Writer) {
+	// Clean up idle client connections.
+	defer c.provider.Close()
+
+	// Setup the log options, start from the beginning.
+	options := &client.ContainerLogsOptions{
+		ShowStdout: true,
+		ShowStderr: true,
+		Follow:     true,
+	}
+
+	// Use a separate method so that timeout cancel function is
+	// called correctly.
+	for c.copyLogsTimeout(stdout, stderr, options) {
+	}
+}
+
+// copyLogsTimeout copies logs from the container to stdout and stderr with a timeout.
+// It returns true if the log production should be retried, false otherwise.
+func (c *DockerContainer) copyLogsTimeout(stdout, stderr io.Writer, options *client.ContainerLogsOptions) bool {
+	timeoutCtx, cancel := context.WithTimeout(c.logProductionCtx, *c.logProductionTimeout)
+	defer cancel()
+
+	err := c.copyLogs(timeoutCtx, stdout, stderr, *options)
+	switch {
+	case err == nil:
+		// No more logs available.
+		return false
+	case c.logProductionCtx.Err() != nil:
+		// Log production was stopped or caller context is done.
+		return false
+	case timeoutCtx.Err() != nil, errors.Is(err, net.ErrClosed):
+		// Timeout or client connection closed, retry.
+	default:
+		// Unexpected error, retry.
+		c.logger.Printf("Unexpected error reading logs: %v", err)
+	}
+
+	// Retry from the last log received.
+	now := time.Now()
+	options.Since = fmt.Sprintf("%d.%09d", now.Unix(), int64(now.Nanosecond()))
+
+	return true
+}
+
+// copyLogs copies logs from the container to stdout and stderr.
+func (c *DockerContainer) copyLogs(ctx context.Context, stdout, stderr io.Writer, options client.ContainerLogsOptions) error {
+	rc, err := c.provider.client.ContainerLogs(ctx, c.GetContainerID(), options)
+	if err != nil {
+		return fmt.Errorf("container logs: %w", err)
+	}
+	defer rc.Close()
+
+	if _, err = stdcopy.StdCopy(stdout, stderr, rc); err != nil {
+		return fmt.Errorf("stdcopy: %w", err)
+	}
+
+	return nil
+}
+
+// Deprecated: it will be removed in the next major release.
+func (c *DockerContainer) StopLogProducer() error {
+	return c.stopLogProduction()
+}
+
+// stopLogProduction will stop the concurrent process that is reading logs
+// and sending them to each added LogConsumer
+func (c *DockerContainer) stopLogProduction() error {
+	if c.logProductionCancel == nil {
+		return nil
+	}
+
+	// Wait for the log production goroutine to finish draining any buffered
+	// logs before cancelling. When the container has already exited, the
+	// goroutine will reach EOF naturally and close logProductionDone on its
+	// own. The bounded timeout prevents blocking indefinitely when the
+	// container is still actively streaming (e.g. Stop() called on a running
+	// container).
+	if c.logProductionDone != nil {
+		select {
+		case <-c.logProductionDone:
+			// Goroutine already finished naturally; nothing more to do.
+			return nil
+		case <-time.After(minLogProductionTimeout):
+			// Timed out waiting for natural exit; force-cancel now.
+		}
+	}
+
+	// Signal the log production to stop (for still-running containers).
+	c.logProductionCancel(errLogProductionStop)
+
+	// Wait for the goroutine to acknowledge the cancellation. Context
+	// cancellation propagates into the Docker transport and should unblock
+	// stdcopy.StdCopy promptly, but we bound the wait to match
+	// minLogProductionTimeout to guard against stuck kernel socket reads or
+	// daemon transport failures that might not honour context cancellation.
+	if c.logProductionDone != nil {
+		select {
+		case <-c.logProductionDone:
+		case <-time.After(minLogProductionTimeout):
+			c.logger.Printf("timeout waiting for log production goroutine to exit; a goroutine may have leaked")
+		}
+	}
+
+	if err := context.Cause(c.logProductionCtx); err != nil {
+		switch {
+		case errors.Is(err, errLogProductionStop):
+			// Log production was stopped.
+			return nil
+		case errors.Is(err, context.DeadlineExceeded),
+			errors.Is(err, context.Canceled):
+			// Parent context is done.
+			return nil
+		default:
+			return err
+		}
+	}
+
+	return nil
+}
+
+// GetLogProductionErrorChannel exposes the only way for the consumer
+// to be able to listen to errors and react to them.
+func (c *DockerContainer) GetLogProductionErrorChannel() <-chan error {
+	if c.logProductionCtx == nil {
+		return nil
+	}
+
+	errCh := make(chan error, 1)
+	go func(ctx context.Context) {
+		<-ctx.Done()
+		errCh <- context.Cause(ctx)
+		close(errCh)
+	}(c.logProductionCtx)
+
+	return errCh
+}
+
+// connectReaper connects the reaper to the container if it is needed.
+func (c *DockerContainer) connectReaper(ctx context.Context) error {
+	if c.provider.config.RyukDisabled || isReaperImage(c.Image) {
+		// Reaper is disabled or we are the reaper container.
+		return nil
+	}
+
+	reaper, err := spawner.reaper(context.WithValue(ctx, core.DockerHostContextKey, c.provider.host), core.SessionID(), c.provider)
+	if err != nil {
+		return fmt.Errorf("reaper: %w", err)
+	}
+
+	if c.terminationSignal, err = reaper.Connect(); err != nil {
+		return fmt.Errorf("reaper connect: %w", err)
+	}
+
+	return nil
+}
+
+// cleanupTermSignal triggers the termination signal if it was created and an error occurred.
+func (c *DockerContainer) cleanupTermSignal(err error) {
+	if c.terminationSignal != nil && err != nil {
+		c.terminationSignal <- true
+	}
+}
+
+// DockerNetwork represents a network started using Docker
+type DockerNetwork struct {
+	ID                string // Network ID from Docker
+	Driver            string
+	Name              string
+	provider          *DockerProvider
+	terminationSignal chan bool
+}
+
+// Remove is used to remove the network. It is usually triggered by as defer function.
+func (n *DockerNetwork) Remove(ctx context.Context) error {
+	select {
+	// close reaper if it was created
+	case n.terminationSignal <- true:
+	default:
+	}
+
+	defer n.provider.Close()
+
+	_, err := n.provider.client.NetworkRemove(ctx, n.ID, client.NetworkRemoveOptions{})
+	return err
+}
+
+func (n *DockerNetwork) SetTerminationSignal(signal chan bool) {
+	n.terminationSignal = signal
+}
+
+// DockerProvider implements the ContainerProvider interface
+type DockerProvider struct {
+	*DockerProviderOptions
+	client    client.APIClient
+	host      string
+	hostCache string
+	config    config.Config
+	mtx       sync.Mutex
+}
+
+// Client gets the docker client used by the provider
+func (p *DockerProvider) Client() client.APIClient {
+	return p.client
+}
+
+// Close closes the docker client used by the provider
+func (p *DockerProvider) Close() error {
+	if p.client == nil {
+		return nil
+	}
+
+	return p.client.Close()
+}
+
+// SetClient sets the docker client to be used by the provider
+func (p *DockerProvider) SetClient(c client.APIClient) {
+	p.client = c
+}
+
+var _ ContainerProvider = (*DockerProvider)(nil)
+
+// BuildImage will build and image from context and Dockerfile, then return the tag
+func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (string, error) {
+	var buildOptions client.ImageBuildOptions
+	resp, err := backoff.RetryNotifyWithData(
+		func() (client.ImageBuildResult, error) {
+			var err error
+			buildOptions, err = img.BuildOptions()
+			if err != nil {
+				return client.ImageBuildResult{}, backoff.Permanent(fmt.Errorf("build options: %w", err))
+			}
+			defer tryClose(buildOptions.Context) // release resources in any case
+
+			resp, err := p.client.ImageBuild(ctx, buildOptions.Context, buildOptions)
+			if err != nil {
+				if isPermanentClientError(err) {
+					return client.ImageBuildResult{}, backoff.Permanent(fmt.Errorf("build image: %w", err))
+				}
+				return client.ImageBuildResult{}, err
+			}
+			defer p.Close()
+
+			return resp, nil
+		},
+		backoff.WithContext(backoff.NewExponentialBackOff(), ctx),
+		func(err error, _ time.Duration) {
+			p.Logger.Printf("Failed to build image: %s, will retry", err)
+		},
+	)
+	if err != nil {
+		return "", err // Error is already wrapped.
+	}
+	defer resp.Body.Close()
+
+	// Always process the output, even if it is not printed
+	// to ensure that errors during the build process are
+	// correctly handled.
+	if err = jsonmessage.DisplayStream(resp.Body, img.BuildLogWriter()); err != nil {
+		return "", fmt.Errorf("build image: %w", err)
+	}
+
+	// the first tag is the one we want
+	return buildOptions.Tags[0], nil
+}
+
+// CreateContainer fulfils a request for a container without starting it
+func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerRequest) (con Container, err error) {
+	// defer the close of the Docker client connection the soonest
+	defer p.Close()
+
+	var defaultNetwork string
+	defaultNetwork, err = p.ensureDefaultNetwork(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("ensure default network: %w", err)
+	}
+
+	// If default network is not bridge make sure it is attached to the request
+	// as container won't be attached to it automatically
+	// in case of Podman the bridge network is called 'podman' as 'bridge' would conflict
+	if defaultNetwork != p.defaultBridgeNetworkName {
+		isAttached := slices.Contains(req.Networks, defaultNetwork)
+
+		if !isAttached {
+			req.Networks = append(req.Networks, defaultNetwork)
+		}
+	}
+
+	imageName := req.Image
+
+	env := []string{}
+	for envKey, envVar := range req.Env {
+		env = append(env, envKey+"="+envVar)
+	}
+
+	if req.Labels == nil {
+		req.Labels = make(map[string]string)
+	}
+
+	if err = req.Validate(); err != nil {
+		return nil, err
+	}
+
+	// always append the hub substitutor after the user-defined ones
+	req.ImageSubstitutors = append(req.ImageSubstitutors, newPrependHubRegistry(p.config.HubImageNamePrefix))
+
+	var platform *specs.Platform
+
+	defaultHooks := []ContainerLifecycleHooks{
+		DefaultLoggingHook(p.Logger),
+	}
+
+	origLifecycleHooks := req.LifecycleHooks
+	req.LifecycleHooks = []ContainerLifecycleHooks{
+		combineContainerHooks(defaultHooks, req.LifecycleHooks),
+	}
+
+	if req.ShouldBuildImage() {
+		if err = req.buildingHook(ctx); err != nil {
+			return nil, err
+		}
+
+		imageName, err = p.BuildImage(ctx, &req)
+		if err != nil {
+			return nil, err
+		}
+
+		req.Image = imageName
+		if err = req.builtHook(ctx); err != nil {
+			return nil, err
+		}
+	} else {
+		for _, is := range req.ImageSubstitutors {
+			modifiedTag, err := is.Substitute(imageName)
+			if err != nil {
+				return nil, fmt.Errorf("failed to substitute image %s with %s: %w", imageName, is.Description(), err)
+			}
+
+			if modifiedTag != imageName {
+				p.Logger.Printf("✍🏼 Replacing image with %s. From: %s to %s\n", is.Description(), imageName, modifiedTag)
+				imageName = modifiedTag
+			}
+		}
+
+		if req.ImagePlatform != "" {
+			p, err := platforms.Parse(req.ImagePlatform)
+			if err != nil {
+				return nil, fmt.Errorf("invalid platform %s: %w", req.ImagePlatform, err)
+			}
+			platform = &p
+		}
+
+		var shouldPullImage bool
+
+		if req.AlwaysPullImage {
+			shouldPullImage = true // If requested always attempt to pull image
+		} else {
+			img, err := p.client.ImageInspect(ctx, imageName)
+			if err != nil {
+				if !errdefs.IsNotFound(err) {
+					return nil, err
+				}
+				shouldPullImage = true
+			}
+			if platform != nil && (img.Architecture != platform.Architecture || img.Os != platform.OS) {
+				shouldPullImage = true
+			}
+		}
+
+		if shouldPullImage {
+			pullOpt := client.ImagePullOptions{}
+			if req.ImagePlatform != "" {
+				if pf, err := platforms.Parse(req.ImagePlatform); err == nil {
+					pullOpt.Platforms = append(pullOpt.Platforms, pf)
+				}
+			}
+			if err := p.attemptToPullImage(ctx, imageName, pullOpt); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	if !isReaperImage(imageName) {
+		// Add the labels that identify this as a testcontainers container and
+		// allow the reaper to terminate it if requested.
+		AddGenericLabels(req.Labels)
+	}
+
+	dockerInput := &container.Config{
+		Entrypoint: req.Entrypoint,
+		Image:      imageName,
+		Env:        env,
+		Labels:     req.Labels,
+		Cmd:        req.Cmd,
+	}
+
+	hostConfig := &container.HostConfig{
+		Tmpfs: req.Tmpfs,
+	}
+
+	networkingConfig := &network.NetworkingConfig{}
+
+	// default hooks include logger hook and pre-create hook
+	defaultHooks = append(defaultHooks,
+		defaultPreCreateHook(p, dockerInput, hostConfig, networkingConfig),
+		defaultCopyFileToContainerHook(req.Files),
+		defaultLogConsumersHook(req.LogConsumerCfg),
+		defaultReadinessHook(),
+	)
+
+	// in the case the container needs to access a local port
+	// we need to forward the local port to the container
+	if len(req.HostAccessPorts) > 0 {
+		// a container lifecycle hook will be added, which will expose the host ports to the container
+		// using a SSHD server running in a container. The SSHD server will be started and will
+		// forward the host ports to the container ports.
+		sshdForwardPortsHook, err := exposeHostPorts(ctx, &req, req.HostAccessPorts...)
+		if err != nil {
+			return nil, fmt.Errorf("expose host ports: %w", err)
+		}
+
+		defer func() {
+			if err != nil && con == nil {
+				// Container setup failed so ensure we clean up the sshd container too.
+				ctr := &DockerContainer{
+					provider:       p,
+					logger:         p.Logger,
+					lifecycleHooks: []ContainerLifecycleHooks{sshdForwardPortsHook},
+				}
+				err = errors.Join(ctr.terminatingHook(ctx))
+			}
+		}()
+
+		defaultHooks = append(defaultHooks, sshdForwardPortsHook)
+	}
+
+	// Combine with the original LifecycleHooks to avoid duplicate logging hooks.
+	req.LifecycleHooks = []ContainerLifecycleHooks{
+		combineContainerHooks(defaultHooks, origLifecycleHooks),
+	}
+
+	err = req.creatingHook(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	resp, err := p.client.ContainerCreate(ctx, client.ContainerCreateOptions{
+		Config:           dockerInput,
+		HostConfig:       hostConfig,
+		NetworkingConfig: networkingConfig,
+		Platform:         platform,
+		Name:             req.Name,
+	})
+	if err != nil {
+		return nil, fmt.Errorf("container create: %w", err)
+	}
+
+	// #248: If there is more than one network specified in the request attach newly created container to them one by one
+	if len(req.Networks) > 1 {
+		for _, n := range req.Networks[1:] {
+			nw, err := p.GetNetwork(ctx, NetworkRequest{
+				Name: n,
+			})
+			if err == nil {
+				endpointSetting := network.EndpointSettings{
+					Aliases: req.NetworkAliases[n],
+				}
+				_, err = p.client.NetworkConnect(ctx, nw.ID, client.NetworkConnectOptions{
+					Container:      resp.ID,
+					EndpointConfig: &endpointSetting,
+				})
+				if err != nil {
+					return nil, fmt.Errorf("network connect: %w", err)
+				}
+			}
+		}
+	}
+
+	// This should match the fields set in ContainerFromDockerResponse.
+	ctr := &DockerContainer{
+		ID:             resp.ID,
+		WaitingFor:     req.WaitingFor,
+		Image:          imageName,
+		imageWasBuilt:  req.ShouldBuildImage(),
+		keepBuiltImage: req.ShouldKeepBuiltImage(),
+		sessionID:      req.sessionID(),
+		exposedPorts:   req.ExposedPorts,
+		provider:       p,
+		logger:         p.Logger,
+		lifecycleHooks: req.LifecycleHooks,
+	}
+
+	if err = ctr.connectReaper(ctx); err != nil {
+		return ctr, err // No wrap as it would stutter.
+	}
+
+	// Wrapped so the returned error is passed to the cleanup function.
+	defer func(ctr *DockerContainer) {
+		ctr.cleanupTermSignal(err)
+	}(ctr)
+
+	if err = ctr.createdHook(ctx); err != nil {
+		// Return the container to allow caller to clean up.
+		return ctr, fmt.Errorf("created hook: %w", err)
+	}
+
+	return ctr, nil
+}
+
+func (p *DockerProvider) findContainerByName(ctx context.Context, name string) (*container.Summary, error) {
+	if name == "" {
+		return nil, nil
+	}
+
+	// Note that, 'name' filter will use regex to find the containers
+	containers, err := p.client.ContainerList(ctx, client.ContainerListOptions{
+		All:     true,
+		Filters: make(client.Filters).Add("name", fmt.Sprintf("^%s$", name)),
+	})
+	if err != nil {
+		return nil, fmt.Errorf("container list: %w", err)
+	}
+	defer p.Close()
+
+	if len(containers.Items) > 0 {
+		return &containers.Items[0], nil
+	}
+	return nil, nil
+}
+
+func (p *DockerProvider) waitContainerCreation(ctx context.Context, name string) (*container.Summary, error) {
+	return backoff.RetryNotifyWithData(
+		func() (*container.Summary, error) {
+			c, err := p.findContainerByName(ctx, name)
+			if err != nil {
+				if !errdefs.IsNotFound(err) && isPermanentClientError(err) {
+					return nil, backoff.Permanent(err)
+				}
+				return nil, err
+			}
+
+			if c == nil {
+				return nil, errdefs.ErrNotFound.WithMessage(fmt.Sprintf("container %s not found", name))
+			}
+			return c, nil
+		},
+		backoff.WithContext(backoff.NewExponentialBackOff(), ctx),
+		func(err error, duration time.Duration) {
+			if errdefs.IsNotFound(err) {
+				return
+			}
+			p.Logger.Printf("Waiting for container. Got an error: %v; Retrying in %d seconds", err, duration/time.Second)
+		},
+	)
+}
+
+func (p *DockerProvider) ReuseOrCreateContainer(ctx context.Context, req ContainerRequest) (con Container, err error) {
+	c, err := p.findContainerByName(ctx, req.Name)
+	if err != nil {
+		return nil, err
+	}
+	if c == nil {
+		createdContainer, err := p.CreateContainer(ctx, req)
+		if err == nil {
+			return createdContainer, nil
+		}
+		if !createContainerFailDueToNameConflictRegex.MatchString(err.Error()) {
+			return nil, err
+		}
+		c, err = p.waitContainerCreation(ctx, req.Name)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	sessionID := req.sessionID()
+
+	var termSignal chan bool
+	if !p.config.RyukDisabled {
+		r, err := spawner.reaper(context.WithValue(ctx, core.DockerHostContextKey, p.host), sessionID, p)
+		if err != nil {
+			return nil, fmt.Errorf("reaper: %w", err)
+		}
+
+		termSignal, err = r.Connect()
+		if err != nil {
+			return nil, fmt.Errorf("reaper connect: %w", err)
+		}
+
+		// Cleanup on error.
+		defer func() {
+			if err != nil {
+				termSignal <- true
+			}
+		}()
+	}
+
+	// default hooks include logger hook and pre-create hook
+	defaultHooks := []ContainerLifecycleHooks{
+		DefaultLoggingHook(p.Logger),
+		defaultReadinessHook(),
+		defaultLogConsumersHook(req.LogConsumerCfg),
+	}
+
+	dc := &DockerContainer{
+		ID:                c.ID,
+		WaitingFor:        req.WaitingFor,
+		Image:             c.Image,
+		sessionID:         sessionID,
+		exposedPorts:      req.ExposedPorts,
+		provider:          p,
+		terminationSignal: termSignal,
+		logger:            p.Logger,
+		lifecycleHooks:    []ContainerLifecycleHooks{combineContainerHooks(defaultHooks, req.LifecycleHooks)},
+	}
+
+	// Workaround for https://github.com/moby/moby/issues/50133.
+	// /containers/{id}/json API endpoint of Docker Engine takes data about container from master (not replica) database
+	// which is synchronized with container state after call of /containers/{id}/stop API endpoint.
+	dcState, err := dc.State(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("docker container state: %w", err)
+	}
+
+	// If a container was stopped programmatically, we want to ensure the container
+	// is running again, but only if it is not paused, as it's not possible to start
+	// a paused container. The Docker Engine returns the "cannot start a paused container,
+	// try unpause instead" error.
+	switch dcState.Status {
+	case container.StateRunning:
+		// cannot re-start a running container, but we still need
+		// to call the startup hooks.
+	case container.StatePaused:
+		// TODO: we should unpause the container here.
+		return nil, fmt.Errorf("cannot start a paused container: %w", errors.ErrUnsupported)
+	default:
+		if err := dc.Start(ctx); err != nil {
+			return dc, fmt.Errorf("start container %s in state %s: %w", req.Name, c.State, err)
+		}
+	}
+
+	err = dc.startedHook(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	dc.isRunning.Store(true)
+
+	err = dc.readiedHook(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	return dc, nil
+}
+
+// attemptToPullImage tries to pull the image while respecting the ctx cancellations.
+// Besides, if the image cannot be pulled due to ErrorNotFound then no need to retry but terminate immediately.
+func (p *DockerProvider) attemptToPullImage(ctx context.Context, tag string, pullOpt client.ImagePullOptions) error {
+	registry, imageAuth, err := DockerImageAuth(ctx, tag)
+	if err != nil {
+		p.Logger.Printf("No image auth found for %s. Setting empty credentials for the image: %s. This is expected for public images. Details: %s", registry, tag, err)
+	} else {
+		// see https://github.com/docker/docs/blob/e8e1204f914767128814dca0ea008644709c117f/engine/api/sdk/examples.md?plain=1#L649-L657
+		if encodedAuth, err := authconfig.Encode(imageAuth); err != nil {
+			p.Logger.Printf("Failed to marshal image auth. Setting empty credentials for the image: %s. Error is: %s", tag, err)
+		} else {
+			pullOpt.RegistryAuth = encodedAuth
+		}
+	}
+
+	var pull io.ReadCloser
+	err = backoff.RetryNotify(
+		func() error {
+			pull, err = p.client.ImagePull(ctx, tag, pullOpt)
+			if err != nil {
+				if isPermanentClientError(err) {
+					return backoff.Permanent(err)
+				}
+				return err
+			}
+			defer p.Close()
+
+			return nil
+		},
+		backoff.WithContext(backoff.NewExponentialBackOff(), ctx),
+		func(err error, _ time.Duration) {
+			p.Logger.Printf("Failed to pull image: %s, will retry", err)
+		},
+	)
+	if err != nil {
+		return err
+	}
+	defer pull.Close()
+
+	// download of docker image finishes at EOF of the pull request
+	_, err = io.Copy(io.Discard, pull)
+	return err
+}
+
+// Health measure the healthiness of the provider. Right now we leverage the
+// docker-client Info endpoint to see if the daemon is reachable.
+func (p *DockerProvider) Health(ctx context.Context) error {
+	_, err := p.client.Info(ctx, client.InfoOptions{})
+	defer p.Close()
+
+	return err
+}
+
+// RunContainer takes a RequestContainer as input and it runs a container via the docker sdk
+func (p *DockerProvider) RunContainer(ctx context.Context, req ContainerRequest) (Container, error) {
+	c, err := p.CreateContainer(ctx, req)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := c.Start(ctx); err != nil {
+		return c, fmt.Errorf("%w: could not start container", err)
+	}
+
+	return c, nil
+}
+
+// Config provides the TestcontainersConfig read from $HOME/.testcontainers.properties or
+// the environment variables
+func (p *DockerProvider) Config() TestcontainersConfig {
+	return TestcontainersConfig{
+		Host:           p.config.Host,
+		TLSVerify:      p.config.TLSVerify,
+		CertPath:       p.config.CertPath,
+		RyukDisabled:   p.config.RyukDisabled,
+		RyukPrivileged: p.config.RyukPrivileged,
+		Config:         p.config,
+	}
+}
+
+// DaemonHost gets the host or ip of the Docker daemon where ports are exposed on
+// Warning: this is based on your Docker host setting. Will fail if using an SSH tunnel
+// You can use the "TESTCONTAINERS_HOST_OVERRIDE" env variable to set this yourself
+func (p *DockerProvider) DaemonHost(ctx context.Context) (string, error) {
+	p.mtx.Lock()
+	defer p.mtx.Unlock()
+
+	return p.daemonHostLocked(ctx)
+}
+
+func (p *DockerProvider) daemonHostLocked(ctx context.Context) (string, error) {
+	if p.hostCache != "" {
+		return p.hostCache, nil
+	}
+
+	host, exists := os.LookupEnv("TESTCONTAINERS_HOST_OVERRIDE")
+	if exists {
+		p.hostCache = host
+		return p.hostCache, nil
+	}
+
+	// infer from Docker host
+	daemonURL, err := url.Parse(p.client.DaemonHost())
+	if err != nil {
+		return "", err
+	}
+	defer p.Close()
+
+	switch daemonURL.Scheme {
+	case "http", "https", "tcp":
+		p.hostCache = daemonURL.Hostname()
+	case "unix", "npipe":
+		if core.InAContainer() {
+			defaultNetwork, err := p.ensureDefaultNetworkLocked(ctx)
+			if err != nil {
+				return "", fmt.Errorf("ensure default network: %w", err)
+			}
+			ip, err := p.getGatewayIP(ctx, defaultNetwork)
+			if err != nil {
+				ip, err = core.DefaultGatewayIP()
+				if err != nil {
+					ip = "localhost"
+				}
+			}
+			p.hostCache = ip
+		} else {
+			p.hostCache = "localhost"
+		}
+	default:
+		return "", errors.New("could not determine host through env or docker host")
+	}
+
+	return p.hostCache, nil
+}
+
+// Deprecated: use network.New instead
+// CreateNetwork returns the object representing a new network identified by its name
+func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest) (net Network, err error) {
+	// defer the close of the Docker client connection the soonest
+	defer p.Close()
+
+	if _, err = p.ensureDefaultNetwork(ctx); err != nil {
+		return nil, fmt.Errorf("ensure default network: %w", err)
+	}
+
+	if req.Labels == nil {
+		req.Labels = make(map[string]string)
+	}
+
+	nc := client.NetworkCreateOptions{
+		Driver:     req.Driver,
+		Internal:   req.Internal,
+		EnableIPv6: req.EnableIPv6,
+		Attachable: req.Attachable,
+		Labels:     req.Labels,
+		IPAM:       req.IPAM,
+	}
+
+	sessionID := req.sessionID()
+
+	var termSignal chan bool
+	if !p.config.RyukDisabled {
+		r, err := spawner.reaper(context.WithValue(ctx, core.DockerHostContextKey, p.host), sessionID, p)
+		if err != nil {
+			return nil, fmt.Errorf("reaper: %w", err)
+		}
+
+		termSignal, err = r.Connect()
+		if err != nil {
+			return nil, fmt.Errorf("reaper connect: %w", err)
+		}
+
+		// Cleanup on error.
+		defer func() {
+			if err != nil {
+				termSignal <- true
+			}
+		}()
+	}
+
+	// add the labels that the reaper will use to terminate the network to the request
+	core.AddDefaultLabels(sessionID, req.Labels)
+
+	response, err := p.client.NetworkCreate(ctx, req.Name, nc)
+	if err != nil {
+		return &DockerNetwork{}, fmt.Errorf("create network: %w", err)
+	}
+
+	n := &DockerNetwork{
+		ID:                response.ID,
+		Driver:            req.Driver,
+		Name:              req.Name,
+		terminationSignal: termSignal,
+		provider:          p,
+	}
+
+	return n, nil
+}
+
+// GetNetwork returns the object representing the network identified by its name
+func (p *DockerProvider) GetNetwork(ctx context.Context, req NetworkRequest) (network.Inspect, error) {
+	networkResource, err := p.client.NetworkInspect(ctx, req.Name, client.NetworkInspectOptions{
+		Verbose: true,
+	})
+	if err != nil {
+		return network.Inspect{}, err
+	}
+
+	return networkResource.Network, err
+}
+
+func (p *DockerProvider) GetGatewayIP(ctx context.Context) (string, error) {
+	// Use a default network as defined in the DockerProvider
+	defaultNetwork, err := p.ensureDefaultNetwork(ctx)
+	if err != nil {
+		return "", fmt.Errorf("ensure default network: %w", err)
+	}
+	return p.getGatewayIP(ctx, defaultNetwork)
+}
+
+func (p *DockerProvider) getGatewayIP(ctx context.Context, defaultNetwork string) (string, error) {
+	nw, err := p.GetNetwork(ctx, NetworkRequest{Name: defaultNetwork})
+	if err != nil {
+		return "", err
+	}
+
+	var ip string
+	for _, cfg := range nw.IPAM.Config {
+		if cfg.Gateway.IsValid() {
+			ip = cfg.Gateway.String()
+			break
+		}
+	}
+	if ip == "" {
+		return "", errors.New("failed to get gateway IP from network settings")
+	}
+
+	return ip, nil
+}
+
+// ensureDefaultNetwork ensures that defaultNetwork is set and creates
+// it if it does not exist, returning its value.
+// It is safe to call this method concurrently.
+func (p *DockerProvider) ensureDefaultNetwork(ctx context.Context) (string, error) {
+	p.mtx.Lock()
+	defer p.mtx.Unlock()
+	return p.ensureDefaultNetworkLocked(ctx)
+}
+
+func (p *DockerProvider) ensureDefaultNetworkLocked(ctx context.Context) (string, error) {
+	if p.defaultNetwork != "" {
+		// Already set.
+		return p.defaultNetwork, nil
+	}
+
+	networkResources, err := p.client.NetworkList(ctx, client.NetworkListOptions{})
+	if err != nil {
+		return "", fmt.Errorf("network list: %w", err)
+	}
+
+	// TODO: remove once we have docker context support via #2810
+	// Prefer the default bridge network if it exists.
+	// This makes the results stable as network list order is not guaranteed.
+	for _, nw := range networkResources.Items {
+		switch nw.Name {
+		case p.defaultBridgeNetworkName:
+			p.defaultNetwork = p.defaultBridgeNetworkName
+			return p.defaultNetwork, nil
+		case ReaperDefault:
+			p.defaultNetwork = ReaperDefault
+		}
+	}
+
+	if p.defaultNetwork != "" {
+		return p.defaultNetwork, nil
+	}
+
+	// Create a bridge network for the container communications.
+	_, err = p.client.NetworkCreate(ctx, ReaperDefault, client.NetworkCreateOptions{
+		Driver:     Bridge,
+		Attachable: true,
+		Labels:     GenericLabels(),
+	})
+	// If the network already exists, we can ignore the error as that can
+	// happen if we are running multiple tests in parallel and we only
+	// need to ensure that the network exists.
+	if err != nil && !errdefs.IsConflict(err) {
+		return "", fmt.Errorf("network create: %w", err)
+	}
+
+	p.defaultNetwork = ReaperDefault
+
+	return p.defaultNetwork, nil
+}
+
+// ContainerFromType builds a Docker container struct from the response of the Docker API
+func (p *DockerProvider) ContainerFromType(ctx context.Context, response container.Summary) (ctr *DockerContainer, err error) {
+	exposedPorts := make([]string, len(response.Ports))
+	for i, port := range response.Ports {
+		exposedPorts[i] = fmt.Sprintf("%d/%s", port.PublicPort, port.Type)
+	}
+
+	// This should match the fields set in CreateContainer.
+	ctr = &DockerContainer{
+		ID:            response.ID,
+		Image:         response.Image,
+		imageWasBuilt: false,
+		sessionID:     response.Labels[core.LabelSessionID],
+		exposedPorts:  exposedPorts,
+		provider:      p,
+		logger:        p.Logger,
+		lifecycleHooks: []ContainerLifecycleHooks{
+			DefaultLoggingHook(p.Logger),
+		},
+	}
+	ctr.isRunning.Store(response.State == "running")
+
+	if err = ctr.connectReaper(ctx); err != nil {
+		return nil, err
+	}
+
+	// Wrapped so the returned error is passed to the cleanup function.
+	defer func(ctr *DockerContainer) {
+		ctr.cleanupTermSignal(err)
+	}(ctr)
+
+	// populate the raw representation of the container
+	resp, err := ctr.inspectRawContainer(ctx)
+	if err != nil {
+		// Return the container to allow caller to clean up.
+		return ctr, fmt.Errorf("inspect raw container: %w", err)
+	}
+
+	// the health status of the container, if any
+	if health := resp.Container.State.Health; health != nil {
+		ctr.healthStatus = health.Status
+	}
+
+	return ctr, nil
+}
+
+// ListImages list images from the provider. If an image has multiple Tags, each tag is reported
+// individually with the same ID and same labels
+func (p *DockerProvider) ListImages(ctx context.Context) ([]ImageInfo, error) {
+	images := []ImageInfo{}
+
+	imageList, err := p.client.ImageList(ctx, client.ImageListOptions{})
+	if err != nil {
+		return images, fmt.Errorf("listing images %w", err)
+	}
+
+	for _, img := range imageList.Items {
+		for _, tag := range img.RepoTags {
+			images = append(images, ImageInfo{ID: img.ID, Name: tag})
+		}
+	}
+
+	return images, nil
+}
+
+// SaveImages exports a list of images as an uncompressed tar
+func (p *DockerProvider) SaveImages(ctx context.Context, output string, images ...string) error {
+	return p.SaveImagesWithOpts(ctx, output, images)
+}
+
+// SaveImagesWithOpts exports a list of images as an uncompressed tar, passing options to the provider
+func (p *DockerProvider) SaveImagesWithOpts(ctx context.Context, output string, images []string, opts ...SaveImageOption) error {
+	saveOpts := saveImageOptions{}
+
+	for _, opt := range opts {
+		if err := opt(&saveOpts); err != nil {
+			return fmt.Errorf("applying save image option: %w", err)
+		}
+	}
+
+	outputFile, err := os.Create(output)
+	if err != nil {
+		return fmt.Errorf("opening output file %w", err)
+	}
+	defer func() {
+		_ = outputFile.Close()
+	}()
+
+	imageReader, err := p.client.ImageSave(ctx, images, saveOpts.dockerSaveOpts...)
+	if err != nil {
+		return fmt.Errorf("saving images %w", err)
+	}
+	defer func() {
+		_ = imageReader.Close()
+	}()
+
+	// Attempt optimized readFrom, implemented in linux
+	_, err = outputFile.ReadFrom(imageReader)
+	if err != nil {
+		return fmt.Errorf("writing images to output %w", err)
+	}
+
+	return nil
+}
+
+func SaveDockerImageWithPlatforms(platforms ...specs.Platform) SaveImageOption {
+	return func(opts *saveImageOptions) error {
+		opts.dockerSaveOpts = append(opts.dockerSaveOpts, client.ImageSaveWithPlatforms(platforms...))
+		opts.platforms = append(opts.platforms, platforms...)
+
+		return nil
+	}
+}
+
+// PullImage pulls image from registry
+func (p *DockerProvider) PullImage(ctx context.Context, img string) error {
+	return p.attemptToPullImage(ctx, img, client.ImagePullOptions{})
+}
+
+// PullImageWithOpts pulls image from registry, passing options to the provider.
+func (p *DockerProvider) PullImageWithOpts(ctx context.Context, img string, opts ...PullImageOption) error {
+	pullOpts := pullImageOptions{}
+
+	for _, opt := range opts {
+		if err := opt(&pullOpts); err != nil {
+			return fmt.Errorf("applying pull image option: %w", err)
+		}
+	}
+
+	return p.attemptToPullImage(ctx, img, pullOpts.dockerPullOpts)
+}
+
+func PullDockerImageWithPlatform(platform specs.Platform) PullImageOption {
+	return func(opts *pullImageOptions) error {
+		opts.dockerPullOpts.Platforms = append(opts.dockerPullOpts.Platforms, platform)
+
+		return nil
+	}
+}
+
+var permanentClientErrors = []func(error) bool{
+	errdefs.IsNotFound,
+	errdefs.IsInvalidArgument,
+	errdefs.IsUnauthorized,
+	errdefs.IsPermissionDenied,
+	errdefs.IsNotImplemented,
+	errdefs.IsInternal,
+}
+
+func isPermanentClientError(err error) bool {
+	for _, isErrFn := range permanentClientErrors {
+		if isErrFn(err) {
+			return true
+		}
+	}
+	return false
+}
+
+func tryClose(r io.Reader) {
+	rc, ok := r.(io.Closer)
+	if ok {
+		_ = rc.Close()
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/docker_auth.go b/vendor/github.com/testcontainers/testcontainers-go/docker_auth.go
new file mode 100644
index 000000000..eaa313f95
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/docker_auth.go
@@ -0,0 +1,290 @@
+package testcontainers
+
+import (
+	"context"
+	"crypto/md5"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/url"
+	"os"
+	"strings"
+	"sync"
+
+	"github.com/cpuguy83/dockercfg"
+	"github.com/moby/moby/api/types/registry"
+	"github.com/moby/moby/client"
+
+	"github.com/testcontainers/testcontainers-go/internal/core"
+)
+
+// defaultRegistryFn is variable overwritten in tests to check for behaviour with different default values.
+var defaultRegistryFn = defaultRegistry
+
+// getRegistryCredentials is a variable overwritten in tests to mock the dockercfg.GetRegistryCredentials function.
+var getRegistryCredentials = dockercfg.GetRegistryCredentials
+
+// DockerImageAuth returns the auth config for the given Docker image, extracting first its Docker registry.
+// Finally, it will use the credential helpers to extract the information from the docker config file
+// for that registry, if it exists.
+func DockerImageAuth(ctx context.Context, image string) (string, registry.AuthConfig, error) {
+	configs, err := getDockerAuthConfigs()
+	if err != nil {
+		reg := core.ExtractRegistry(image, defaultRegistryFn(ctx))
+		return reg, registry.AuthConfig{}, err
+	}
+
+	return dockerImageAuth(ctx, image, configs)
+}
+
+// dockerImageAuth returns the auth config for the given Docker image.
+func dockerImageAuth(ctx context.Context, image string, configs map[string]registry.AuthConfig) (string, registry.AuthConfig, error) {
+	defaultRegistry := defaultRegistryFn(ctx)
+	reg := core.ExtractRegistry(image, defaultRegistry)
+
+	// Normalize Docker Hub aliases for credential lookup
+	if strings.EqualFold(reg, "docker.io") ||
+		strings.EqualFold(reg, "registry.hub.docker.com") ||
+		strings.EqualFold(reg, "registry-1.docker.io") {
+		reg = defaultRegistry // This is https://index.docker.io/v1/
+	}
+
+	if cfg, ok := getRegistryAuth(reg, configs); ok {
+		return reg, cfg, nil
+	}
+
+	return reg, registry.AuthConfig{}, dockercfg.ErrCredentialsNotFound
+}
+
+func getRegistryAuth(reg string, cfgs map[string]registry.AuthConfig) (registry.AuthConfig, bool) {
+	if cfg, ok := cfgs[reg]; ok {
+		return cfg, true
+	}
+
+	// fallback match using authentication key host
+	for k, cfg := range cfgs {
+		keyURL, err := url.Parse(k)
+		if err != nil {
+			continue
+		}
+
+		host := keyURL.Host
+		if keyURL.Scheme == "" {
+			// url.Parse: The url may be relative (a path, without a host) [...]
+			host = keyURL.Path
+		}
+
+		if host == reg {
+			return cfg, true
+		}
+	}
+
+	return registry.AuthConfig{}, false
+}
+
+// defaultRegistry returns the default registry to use when pulling images
+// It will use the docker daemon to get the default registry, returning "https://index.docker.io/v1/" if
+// it fails to get the information from the daemon
+func defaultRegistry(ctx context.Context) string {
+	apiClient, err := NewDockerClientWithOpts(ctx)
+	if err != nil {
+		return core.IndexDockerIO
+	}
+	defer apiClient.Close()
+
+	info, err := apiClient.Info(ctx, client.InfoOptions{})
+	if err != nil {
+		return core.IndexDockerIO
+	}
+
+	return info.Info.IndexServerAddress
+}
+
+// authConfigResult is a result looking up auth details for key.
+type authConfigResult struct {
+	key string
+	cfg registry.AuthConfig
+	err error
+}
+
+// credentialsCache is a cache for registry credentials.
+type credentialsCache struct {
+	entries map[string]credentials
+	mtx     sync.RWMutex
+}
+
+// credentials represents the username and password for a registry.
+type credentials struct {
+	username string
+	password string
+}
+
+var creds = &credentialsCache{entries: map[string]credentials{}}
+
+// AuthConfig updates the details in authConfig for the given hostname
+// as determined by the details in configKey.
+func (c *credentialsCache) AuthConfig(hostname, configKey string, authConfig *registry.AuthConfig) error {
+	u, p, err := creds.get(hostname, configKey)
+	if err != nil {
+		return err
+	}
+
+	if u != "" {
+		authConfig.Username = u
+		authConfig.Password = p
+	} else {
+		authConfig.IdentityToken = p
+	}
+
+	return nil
+}
+
+// get returns the username and password for the given hostname
+// as determined by the details in configPath.
+// If the username is empty, the password is an identity token.
+func (c *credentialsCache) get(hostname, configKey string) (string, string, error) {
+	key := configKey + ":" + hostname
+	c.mtx.RLock()
+	entry, ok := c.entries[key]
+	c.mtx.RUnlock()
+
+	if ok {
+		return entry.username, entry.password, nil
+	}
+
+	// No entry found, request and cache.
+	user, password, err := getRegistryCredentials(hostname)
+	if err != nil {
+		return "", "", fmt.Errorf("getting credentials for %s: %w", hostname, err)
+	}
+
+	c.mtx.Lock()
+	c.entries[key] = credentials{username: user, password: password}
+	c.mtx.Unlock()
+
+	return user, password, nil
+}
+
+// configKey returns a key to use for caching credentials based on
+// the contents of the currently active config.
+func configKey(cfg *dockercfg.Config) (string, error) {
+	h := md5.New()
+	if err := json.NewEncoder(h).Encode(cfg); err != nil {
+		return "", fmt.Errorf("encode config: %w", err)
+	}
+
+	return hex.EncodeToString(h.Sum(nil)), nil
+}
+
+// getDockerAuthConfigs returns a map with the auth configs from the docker config file
+// using the registry as the key
+func getDockerAuthConfigs() (map[string]registry.AuthConfig, error) {
+	cfg, err := getDockerConfig()
+	if err != nil {
+		if errors.Is(err, os.ErrNotExist) {
+			return map[string]registry.AuthConfig{}, nil
+		}
+
+		return nil, err
+	}
+
+	key, err := configKey(cfg)
+	if err != nil {
+		return nil, err
+	}
+
+	size := len(cfg.AuthConfigs) + len(cfg.CredentialHelpers)
+	cfgs := make(map[string]registry.AuthConfig, size)
+	results := make(chan authConfigResult, size)
+	var wg sync.WaitGroup
+	wg.Add(size)
+	for k, v := range cfg.AuthConfigs {
+		go func(k string, v dockercfg.AuthConfig) {
+			defer wg.Done()
+
+			ac := registry.AuthConfig{
+				Auth:          v.Auth,
+				IdentityToken: v.IdentityToken,
+				Password:      v.Password,
+				RegistryToken: v.RegistryToken,
+				ServerAddress: v.ServerAddress,
+				Username:      v.Username,
+			}
+
+			switch {
+			case ac.Username == "" && ac.Password == "":
+				// Look up credentials from the credential store.
+				if err := creds.AuthConfig(k, key, &ac); err != nil {
+					results <- authConfigResult{err: err}
+					return
+				}
+			case ac.Auth == "":
+				// Create auth from the username and password encoding.
+				ac.Auth = base64.StdEncoding.EncodeToString([]byte(ac.Username + ":" + ac.Password))
+			}
+
+			results <- authConfigResult{key: k, cfg: ac}
+		}(k, v)
+	}
+
+	// In the case where the auth field in the .docker/conf.json is empty, and the user has
+	// credential helpers registered the auth comes from there.
+	for k := range cfg.CredentialHelpers {
+		go func(k string) {
+			defer wg.Done()
+
+			var ac registry.AuthConfig
+			if err := creds.AuthConfig(k, key, &ac); err != nil {
+				results <- authConfigResult{err: err}
+				return
+			}
+
+			results <- authConfigResult{key: k, cfg: ac}
+		}(k)
+	}
+
+	go func() {
+		wg.Wait()
+		close(results)
+	}()
+
+	var errs []error
+	for result := range results {
+		if result.err != nil {
+			errs = append(errs, result.err)
+			continue
+		}
+
+		cfgs[result.key] = result.cfg
+	}
+
+	if len(errs) > 0 {
+		return nil, errors.Join(errs...)
+	}
+
+	return cfgs, nil
+}
+
+// getDockerConfig returns the docker config file. It will internally check, in this particular order:
+// 1. the DOCKER_AUTH_CONFIG environment variable, unmarshalling it into a dockercfg.Config
+// 2. the DOCKER_CONFIG environment variable, as the path to the config file
+// 3. else it will load the default config file, which is ~/.docker/config.json
+func getDockerConfig() (*dockercfg.Config, error) {
+	if env := os.Getenv("DOCKER_AUTH_CONFIG"); env != "" {
+		var cfg dockercfg.Config
+		if err := json.Unmarshal([]byte(env), &cfg); err != nil {
+			return nil, fmt.Errorf("unmarshal DOCKER_AUTH_CONFIG: %w", err)
+		}
+
+		return &cfg, nil
+	}
+
+	cfg, err := dockercfg.LoadDefaultConfig()
+	if err != nil {
+		return nil, fmt.Errorf("load default config: %w", err)
+	}
+
+	return &cfg, nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/docker_client.go b/vendor/github.com/testcontainers/testcontainers-go/docker_client.go
new file mode 100644
index 000000000..ae4ff511d
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/docker_client.go
@@ -0,0 +1,146 @@
+package testcontainers
+
+import (
+	"context"
+	"fmt"
+	"strings"
+	"sync"
+
+	"github.com/moby/moby/client"
+
+	"github.com/testcontainers/testcontainers-go/internal"
+	"github.com/testcontainers/testcontainers-go/internal/core"
+	"github.com/testcontainers/testcontainers-go/log"
+)
+
+// DockerClient is a wrapper around the docker client that is used by testcontainers-go.
+// It implements the SystemAPIClient interface in order to cache the docker info and reuse it.
+type DockerClient struct {
+	*client.Client // client is embedded into our own client
+}
+
+var (
+	// dockerInfo stores the docker info to be reused in the Info method
+	dockerInfo     client.SystemInfoResult
+	dockerInfoSet  bool
+	dockerInfoLock sync.Mutex
+)
+
+// implements SystemAPIClient interface
+var _ client.SystemAPIClient = &DockerClient{}
+
+// Events returns a channel to listen to events that happen to the docker daemon.
+func (c *DockerClient) Events(ctx context.Context, options client.EventsListOptions) client.EventsResult {
+	return c.Client.Events(ctx, options)
+}
+
+// Info returns information about the docker server. The result of Info is cached
+// and reused every time Info is called.
+// It will also print out the docker server info, and the resolved Docker paths, to the default logger.
+func (c *DockerClient) Info(ctx context.Context, options client.InfoOptions) (client.SystemInfoResult, error) {
+	dockerInfoLock.Lock()
+	defer dockerInfoLock.Unlock()
+	if dockerInfoSet {
+		return dockerInfo, nil
+	}
+
+	res, err := c.Client.Info(ctx, options)
+	if err != nil {
+		return res, fmt.Errorf("failed to retrieve docker info: %w", err)
+	}
+	dockerInfo = res
+	dockerInfoSet = true
+
+	infoMessage := `%v - Connected to docker: 
+  Server Version: %v
+  API Version: %v
+  Operating System: %v
+  Total Memory: %v MB%s
+  Testcontainers for Go Version: v%s
+  Resolved Docker Host: %s
+  Resolved Docker Socket Path: %s
+  Test SessionID: %s
+  Test ProcessID: %s
+`
+	infoLabels := ""
+	if len(dockerInfo.Info.Labels) > 0 {
+		infoLabels = `
+  Labels:`
+		var infoLabelsSb72 strings.Builder
+		for _, lb := range dockerInfo.Info.Labels {
+			infoLabelsSb72.WriteString("\n    " + lb)
+		}
+		infoLabels += infoLabelsSb72.String()
+	}
+
+	host, err := core.ExtractDockerHost(ctx)
+	if err != nil {
+		return dockerInfo, err
+	}
+	log.Printf(infoMessage, packagePath,
+		dockerInfo.Info.ServerVersion,
+		c.ClientVersion(),
+		dockerInfo.Info.OperatingSystem, dockerInfo.Info.MemTotal/1024/1024,
+		infoLabels,
+		internal.Version,
+		host,
+		core.MustExtractDockerSocket(ctx),
+		core.SessionID(),
+		core.ProcessID(),
+	)
+
+	return dockerInfo, nil
+}
+
+// RegistryLogin logs into a Docker registry.
+func (c *DockerClient) RegistryLogin(ctx context.Context, options client.RegistryLoginOptions) (client.RegistryLoginResult, error) {
+	return c.Client.RegistryLogin(ctx, options)
+}
+
+// DiskUsage returns the disk usage of all images.
+func (c *DockerClient) DiskUsage(ctx context.Context, options client.DiskUsageOptions) (client.DiskUsageResult, error) {
+	return c.Client.DiskUsage(ctx, options)
+}
+
+// Ping pings the docker server.
+func (c *DockerClient) Ping(ctx context.Context, options client.PingOptions) (client.PingResult, error) {
+	return c.Client.Ping(ctx, options)
+}
+
+// Deprecated: Use NewDockerClientWithOpts instead.
+func NewDockerClient() (*client.Client, error) {
+	cli, err := NewDockerClientWithOpts(context.Background())
+	if err != nil {
+		return nil, err
+	}
+
+	return cli.Client, nil
+}
+
+func NewDockerClientWithOpts(ctx context.Context, opt ...client.Opt) (*DockerClient, error) {
+	dockerClient, err := core.NewClient(ctx, opt...)
+	if err != nil {
+		return nil, err
+	}
+
+	tcClient := DockerClient{
+		Client: dockerClient,
+	}
+
+	if _, err = tcClient.Info(ctx, client.InfoOptions{}); err != nil {
+		// Fallback to environment, including the original options
+		if len(opt) == 0 {
+			opt = []client.Opt{client.FromEnv}
+		}
+
+		apiClient, err := client.New(opt...)
+		if err != nil {
+			return nil, err
+		}
+
+		tcClient.Client = apiClient
+	}
+	defer tcClient.Close()
+
+	return &tcClient, nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/docker_mounts.go b/vendor/github.com/testcontainers/testcontainers-go/docker_mounts.go
new file mode 100644
index 000000000..5d654b9a6
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/docker_mounts.go
@@ -0,0 +1,194 @@
+package testcontainers
+
+import (
+	"errors"
+	"path/filepath"
+
+	"github.com/moby/moby/api/types/mount"
+
+	"github.com/testcontainers/testcontainers-go/log"
+)
+
+var mountTypeMapping = map[MountType]mount.Type{
+	MountTypeBind:   mount.TypeBind, // Deprecated, it will be removed in a future release
+	MountTypeVolume: mount.TypeVolume,
+	MountTypeTmpfs:  mount.TypeTmpfs,
+	MountTypePipe:   mount.TypeNamedPipe,
+	MountTypeImage:  mount.TypeImage,
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+// BindMounter can optionally be implemented by mount sources
+// to support advanced scenarios based on mount.BindOptions
+type BindMounter interface {
+	GetBindOptions() *mount.BindOptions
+}
+
+// VolumeMounter can optionally be implemented by mount sources
+// to support advanced scenarios based on mount.VolumeOptions
+type VolumeMounter interface {
+	GetVolumeOptions() *mount.VolumeOptions
+}
+
+// TmpfsMounter can optionally be implemented by mount sources
+// to support advanced scenarios based on mount.TmpfsOptions
+type TmpfsMounter interface {
+	GetTmpfsOptions() *mount.TmpfsOptions
+}
+
+// ImageMounter can optionally be implemented by mount sources
+// to support advanced scenarios based on mount.ImageOptions
+type ImageMounter interface {
+	ImageOptions() *mount.ImageOptions
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+type DockerBindMountSource struct {
+	*mount.BindOptions
+
+	// HostPath is the path mounted into the container
+	// the same host path might be mounted to multiple locations within a single container
+	HostPath string
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+func (s DockerBindMountSource) Source() string {
+	return s.HostPath
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+func (DockerBindMountSource) Type() MountType {
+	return MountTypeBind
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+func (s DockerBindMountSource) GetBindOptions() *mount.BindOptions {
+	return s.BindOptions
+}
+
+type DockerVolumeMountSource struct {
+	*mount.VolumeOptions
+
+	// Name refers to the name of the volume to be mounted
+	// the same volume might be mounted to multiple locations within a single container
+	Name string
+}
+
+func (s DockerVolumeMountSource) Source() string {
+	return s.Name
+}
+
+func (DockerVolumeMountSource) Type() MountType {
+	return MountTypeVolume
+}
+
+func (s DockerVolumeMountSource) GetVolumeOptions() *mount.VolumeOptions {
+	return s.VolumeOptions
+}
+
+type DockerTmpfsMountSource struct {
+	GenericTmpfsMountSource
+	*mount.TmpfsOptions
+}
+
+func (s DockerTmpfsMountSource) GetTmpfsOptions() *mount.TmpfsOptions {
+	return s.TmpfsOptions
+}
+
+// DockerImageMountSource is a mount source for an image
+type DockerImageMountSource struct {
+	// imageName is the image name
+	imageName string
+
+	// subpath is the subpath to mount the image into
+	subpath string
+}
+
+// NewDockerImageMountSource creates a new DockerImageMountSource
+func NewDockerImageMountSource(imageName string, subpath string) DockerImageMountSource {
+	return DockerImageMountSource{
+		imageName: imageName,
+		subpath:   subpath,
+	}
+}
+
+// Validate validates the source of the mount, ensuring that the subpath is a relative path
+func (s DockerImageMountSource) Validate() error {
+	if !filepath.IsLocal(s.subpath) {
+		return errors.New("image mount source must be a local path")
+	}
+	return nil
+}
+
+// ImageOptions returns the image options for the image mount
+func (s DockerImageMountSource) ImageOptions() *mount.ImageOptions {
+	return &mount.ImageOptions{
+		Subpath: s.subpath,
+	}
+}
+
+// Source returns the image name for the image mount
+func (s DockerImageMountSource) Source() string {
+	return s.imageName
+}
+
+// Type returns the mount type for the image mount
+func (s DockerImageMountSource) Type() MountType {
+	return MountTypeImage
+}
+
+// PrepareMounts maps the given []ContainerMount to the corresponding
+// []mount.Mount for further processing
+func (m ContainerMounts) PrepareMounts() []mount.Mount {
+	return mapToDockerMounts(m)
+}
+
+// mapToDockerMounts maps the given []ContainerMount to the corresponding
+// []mount.Mount for further processing
+func mapToDockerMounts(containerMounts ContainerMounts) []mount.Mount {
+	mounts := make([]mount.Mount, 0, len(containerMounts))
+
+	for idx := range containerMounts {
+		m := containerMounts[idx]
+
+		var mountType mount.Type
+		if mt, ok := mountTypeMapping[m.Source.Type()]; ok {
+			mountType = mt
+		} else {
+			continue
+		}
+
+		containerMount := mount.Mount{
+			Type:     mountType,
+			Source:   m.Source.Source(),
+			ReadOnly: m.ReadOnly,
+			Target:   m.Target.Target(),
+		}
+
+		switch typedMounter := m.Source.(type) {
+		case VolumeMounter:
+			containerMount.VolumeOptions = typedMounter.GetVolumeOptions()
+		case TmpfsMounter:
+			containerMount.TmpfsOptions = typedMounter.GetTmpfsOptions()
+		case ImageMounter:
+			containerMount.ImageOptions = typedMounter.ImageOptions()
+		case BindMounter:
+			log.Printf("Mount type %s is not supported by Testcontainers for Go", m.Source.Type())
+		default:
+			// The provided source type has no custom options
+		}
+
+		if mountType == mount.TypeVolume {
+			if containerMount.VolumeOptions == nil {
+				containerMount.VolumeOptions = &mount.VolumeOptions{
+					Labels: make(map[string]string),
+				}
+			}
+			AddGenericLabels(containerMount.VolumeOptions.Labels)
+		}
+
+		mounts = append(mounts, containerMount)
+	}
+
+	return mounts
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/exec/processor.go b/vendor/github.com/testcontainers/testcontainers-go/exec/processor.go
new file mode 100644
index 000000000..072c7512e
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/exec/processor.go
@@ -0,0 +1,128 @@
+package exec
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"sync"
+
+	"github.com/moby/moby/api/pkg/stdcopy"
+	"github.com/moby/moby/client"
+)
+
+// ProcessOptions defines options applicable to the reader processor
+type ProcessOptions struct {
+	ExecConfig client.ExecCreateOptions
+	Reader     io.Reader
+}
+
+// NewProcessOptions returns a new ProcessOptions instance
+// with the given command and default options:
+// - detach: false
+// - attach stdout: true
+// - attach stderr: true
+func NewProcessOptions(cmd []string) *ProcessOptions {
+	return &ProcessOptions{
+		ExecConfig: client.ExecCreateOptions{
+			Cmd:          cmd,
+			AttachStdout: true,
+			AttachStderr: true,
+		},
+	}
+}
+
+// ProcessOption defines a common interface to modify the reader processor
+// These options can be passed to the Exec function in a variadic way to customize the returned Reader instance
+type ProcessOption interface {
+	Apply(opts *ProcessOptions)
+}
+
+type ProcessOptionFunc func(opts *ProcessOptions)
+
+func (fn ProcessOptionFunc) Apply(opts *ProcessOptions) {
+	fn(opts)
+}
+
+func WithUser(user string) ProcessOption {
+	return ProcessOptionFunc(func(opts *ProcessOptions) {
+		opts.ExecConfig.User = user
+	})
+}
+
+func WithWorkingDir(workingDir string) ProcessOption {
+	return ProcessOptionFunc(func(opts *ProcessOptions) {
+		opts.ExecConfig.WorkingDir = workingDir
+	})
+}
+
+func WithEnv(env []string) ProcessOption {
+	return ProcessOptionFunc(func(opts *ProcessOptions) {
+		opts.ExecConfig.Env = env
+	})
+}
+
+// safeBuffer is a goroutine safe buffer.
+type safeBuffer struct {
+	mtx sync.Mutex
+	buf bytes.Buffer
+	err error
+}
+
+// Error sets an error for the next read.
+func (sb *safeBuffer) Error(err error) {
+	sb.mtx.Lock()
+	defer sb.mtx.Unlock()
+
+	sb.err = err
+}
+
+// Write writes p to the buffer.
+// It is safe for concurrent use by multiple goroutines.
+func (sb *safeBuffer) Write(p []byte) (n int, err error) {
+	sb.mtx.Lock()
+	defer sb.mtx.Unlock()
+
+	return sb.buf.Write(p)
+}
+
+// Read reads up to len(p) bytes into p from the buffer.
+// It is safe for concurrent use by multiple goroutines.
+func (sb *safeBuffer) Read(p []byte) (n int, err error) {
+	sb.mtx.Lock()
+	defer sb.mtx.Unlock()
+
+	if sb.err != nil {
+		return 0, sb.err
+	}
+
+	return sb.buf.Read(p)
+}
+
+// Multiplexed returns a [ProcessOption] that configures the command execution
+// to combine stdout and stderr into a single stream without Docker's multiplexing headers.
+func Multiplexed() ProcessOption {
+	return ProcessOptionFunc(func(opts *ProcessOptions) {
+		// returning fast to bypass those options with a nil reader,
+		// which could be the case when other options are used
+		// to configure the exec creation.
+		if opts.Reader == nil {
+			return
+		}
+
+		done := make(chan struct{})
+
+		var outBuff safeBuffer
+		var errBuff safeBuffer
+		go func() {
+			defer close(done)
+			if _, err := stdcopy.StdCopy(&outBuff, &errBuff, opts.Reader); err != nil {
+				outBuff.Error(fmt.Errorf("copying output: %w", err))
+				return
+			}
+		}()
+
+		<-done
+
+		opts.Reader = io.MultiReader(&outBuff, &errBuff)
+	})
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/file.go b/vendor/github.com/testcontainers/testcontainers-go/file.go
new file mode 100644
index 000000000..9205208cb
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/file.go
@@ -0,0 +1,143 @@
+package testcontainers
+
+import (
+	"archive/tar"
+	"bytes"
+	"compress/gzip"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/testcontainers/testcontainers-go/log"
+)
+
+func isDir(path string) (bool, error) {
+	file, err := os.Open(path)
+	if err != nil {
+		return false, err
+	}
+	defer file.Close()
+
+	fileInfo, err := file.Stat()
+	if err != nil {
+		return false, err
+	}
+
+	if fileInfo.IsDir() {
+		return true, nil
+	}
+
+	return false, nil
+}
+
+// tarDir compress a directory using tar + gzip algorithms
+func tarDir(src string, fileMode int64) (*bytes.Buffer, error) {
+	// always pass src as absolute path
+	abs, err := filepath.Abs(src)
+	if err != nil {
+		return &bytes.Buffer{}, fmt.Errorf("error getting absolute path: %w", err)
+	}
+	src = abs
+
+	buffer := &bytes.Buffer{}
+
+	log.Printf(">> creating TAR file from directory: %s\n", src)
+
+	// tar > gzip > buffer
+	zr := gzip.NewWriter(buffer)
+	tw := tar.NewWriter(zr)
+
+	_, baseDir := filepath.Split(src)
+	// keep the path relative to the parent directory
+	index := strings.LastIndex(src, baseDir)
+
+	// walk through every file in the folder
+	err = filepath.Walk(src, func(file string, fi os.FileInfo, errFn error) error {
+		if errFn != nil {
+			return fmt.Errorf("error traversing the file system: %w", errFn)
+		}
+
+		// if a symlink, skip file
+		if fi.Mode().Type() == os.ModeSymlink {
+			log.Printf(">> skipping symlink: %s\n", file)
+			return nil
+		}
+
+		// generate tar header
+		header, err := tar.FileInfoHeader(fi, file)
+		if err != nil {
+			return fmt.Errorf("error getting file info header: %w", err)
+		}
+
+		// see https://pkg.go.dev/archive/tar#FileInfoHeader:
+		// Since fs.FileInfo's Name method only returns the base name of the file it describes,
+		// it may be necessary to modify Header.Name to provide the full path name of the file.
+		header.Name = filepath.ToSlash(file[index:])
+		header.Mode = fileMode
+
+		// write header
+		if err := tw.WriteHeader(header); err != nil {
+			return fmt.Errorf("error writing header: %w", err)
+		}
+
+		// if not a dir, write file content
+		if !fi.IsDir() {
+			data, err := os.Open(file)
+			if err != nil {
+				return fmt.Errorf("error opening file: %w", err)
+			}
+			defer data.Close()
+			if _, err := io.Copy(tw, data); err != nil {
+				return fmt.Errorf("error compressing file: %w", err)
+			}
+		}
+		return nil
+	})
+	if err != nil {
+		return buffer, err
+	}
+
+	// produce tar
+	if err := tw.Close(); err != nil {
+		return buffer, fmt.Errorf("error closing tar file: %w", err)
+	}
+	// produce gzip
+	if err := zr.Close(); err != nil {
+		return buffer, fmt.Errorf("error closing gzip file: %w", err)
+	}
+
+	return buffer, nil
+}
+
+// tarFile compress a single file using tar + gzip algorithms
+func tarFile(basePath string, fileContent func(tw io.Writer) error, fileContentSize int64, fileMode int64) (*bytes.Buffer, error) {
+	buffer := &bytes.Buffer{}
+
+	zr := gzip.NewWriter(buffer)
+	tw := tar.NewWriter(zr)
+
+	hdr := &tar.Header{
+		Name: basePath,
+		Mode: fileMode,
+		Size: fileContentSize,
+	}
+	if err := tw.WriteHeader(hdr); err != nil {
+		return buffer, err
+	}
+	if err := fileContent(tw); err != nil {
+		return buffer, err
+	}
+
+	// produce tar
+	if err := tw.Close(); err != nil {
+		return buffer, fmt.Errorf("error closing tar file: %w", err)
+	}
+	// produce gzip
+	if err := zr.Close(); err != nil {
+		return buffer, fmt.Errorf("error closing gzip file: %w", err)
+	}
+
+	return buffer, nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/generate.go b/vendor/github.com/testcontainers/testcontainers-go/generate.go
new file mode 100644
index 000000000..c1c5c5fd9
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/generate.go
@@ -0,0 +1,4 @@
+package testcontainers
+
+//go:generate mockery
+//go:generate gci write -s standard -s default -s prefix(github.com/testcontainers) .
diff --git a/vendor/github.com/testcontainers/testcontainers-go/generic.go b/vendor/github.com/testcontainers/testcontainers-go/generic.go
new file mode 100644
index 000000000..57dbe7603
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/generic.go
@@ -0,0 +1,140 @@
+package testcontainers
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"maps"
+	"sync"
+
+	"github.com/testcontainers/testcontainers-go/internal/core"
+	"github.com/testcontainers/testcontainers-go/log"
+)
+
+var (
+	reuseContainerMx  sync.Mutex
+	ErrReuseEmptyName = errors.New("with reuse option a container name mustn't be empty")
+)
+
+// GenericContainerRequest represents parameters to a generic container
+type GenericContainerRequest struct {
+	ContainerRequest              // embedded request for provider
+	Started          bool         // whether to auto-start the container
+	ProviderType     ProviderType // which provider to use, Docker if empty
+	Logger           log.Logger   // provide a container specific Logging - use default global logger if empty
+	Reuse            bool         // reuse an existing container if it exists or create a new one. a container name mustn't be empty
+}
+
+// Deprecated: will be removed in the future.
+// GenericNetworkRequest represents parameters to a generic network
+type GenericNetworkRequest struct {
+	NetworkRequest              // embedded request for provider
+	ProviderType   ProviderType // which provider to use, Docker if empty
+}
+
+// Deprecated: use network.New instead
+// GenericNetwork creates a generic network with parameters
+func GenericNetwork(ctx context.Context, req GenericNetworkRequest) (Network, error) {
+	provider, err := req.ProviderType.GetProvider()
+	if err != nil {
+		return nil, err
+	}
+	network, err := provider.CreateNetwork(ctx, req.NetworkRequest)
+	if err != nil {
+		return nil, fmt.Errorf("%w: failed to create network", err)
+	}
+
+	return network, nil
+}
+
+// GenericContainer creates a generic container with parameters
+func GenericContainer(ctx context.Context, req GenericContainerRequest) (Container, error) {
+	if req.Reuse && req.Name == "" {
+		return nil, ErrReuseEmptyName
+	}
+
+	logger := req.Logger
+	if logger == nil {
+		// Ensure there is always a non-nil logger by default
+		logger = log.Default()
+	}
+	provider, err := req.ProviderType.GetProvider(WithLogger(logger))
+	if err != nil {
+		return nil, fmt.Errorf("get provider: %w", err)
+	}
+	defer provider.Close()
+
+	var c Container
+	if req.Reuse {
+		// we must protect the reusability of the container in the case it's invoked
+		// in a parallel execution, via ParallelContainers or t.Parallel()
+		reuseContainerMx.Lock()
+		defer reuseContainerMx.Unlock()
+
+		c, err = provider.ReuseOrCreateContainer(ctx, req.ContainerRequest)
+	} else {
+		c, err = provider.CreateContainer(ctx, req.ContainerRequest)
+	}
+	if err != nil {
+		// At this point `c` might not be nil. Give the caller an opportunity to call Destroy on the container.
+		return c, fmt.Errorf("create container: %w", err)
+	}
+
+	if req.Started && !c.IsRunning() {
+		if err := c.Start(ctx); err != nil {
+			return c, fmt.Errorf("start container: %w", err)
+		}
+	}
+	return c, nil
+}
+
+// GenericProvider represents an abstraction for container and network providers
+type GenericProvider interface {
+	ContainerProvider
+	NetworkProvider
+	ImageProvider
+}
+
+// GenericLabels returns a map of labels that can be used to identify resources
+// created by this library. This includes the standard LabelSessionID if the
+// reaper is enabled, otherwise this is excluded to prevent resources being
+// incorrectly reaped.
+func GenericLabels() map[string]string {
+	return core.DefaultLabels(core.SessionID())
+}
+
+// AddGenericLabels adds the generic labels to target.
+func AddGenericLabels(target map[string]string) {
+	maps.Copy(target, GenericLabels())
+}
+
+// Run is a convenience function that creates a new container and starts it.
+// It calls the GenericContainer function and returns a concrete DockerContainer type.
+func Run(ctx context.Context, img string, opts ...ContainerCustomizer) (*DockerContainer, error) {
+	req := ContainerRequest{
+		Image: img,
+	}
+
+	genericContainerReq := GenericContainerRequest{
+		ContainerRequest: req,
+		Started:          true,
+	}
+
+	for _, opt := range opts {
+		if err := opt.Customize(&genericContainerReq); err != nil {
+			return nil, fmt.Errorf("customize: %w", err)
+		}
+	}
+
+	ctr, err := GenericContainer(ctx, genericContainerReq)
+	var c *DockerContainer
+	if ctr != nil {
+		c = ctr.(*DockerContainer)
+	}
+
+	if err != nil {
+		return c, fmt.Errorf("generic container: %w", err)
+	}
+
+	return c, nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/image.go b/vendor/github.com/testcontainers/testcontainers-go/image.go
new file mode 100644
index 000000000..0314f5949
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/image.go
@@ -0,0 +1,58 @@
+package testcontainers
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/moby/moby/client"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// ImageInfo represents summary information of an image
+type ImageInfo struct {
+	ID   string
+	Name string
+}
+
+type saveImageOptions struct {
+	dockerSaveOpts []client.ImageSaveOption
+	platforms      []specs.Platform
+}
+
+type SaveImageOption func(*saveImageOptions) error
+
+type pullImageOptions struct {
+	dockerPullOpts client.ImagePullOptions
+}
+
+type PullImageOption func(*pullImageOptions) error
+
+// ResolveSaveImageOptions applies save image options and returns the platform to
+// use for a coordinated containerd import, if exactly one platform was requested.
+func ResolveSaveImageOptions(opts ...SaveImageOption) (*specs.Platform, error) {
+	saveOpts := saveImageOptions{}
+
+	for _, opt := range opts {
+		if err := opt(&saveOpts); err != nil {
+			return nil, fmt.Errorf("applying save image option: %w", err)
+		}
+	}
+
+	switch len(saveOpts.platforms) {
+	case 0:
+		return nil, nil
+	case 1:
+		return &saveOpts.platforms[0], nil
+	default:
+		return nil, fmt.Errorf("at most one platform is supported, got %d", len(saveOpts.platforms))
+	}
+}
+
+// ImageProvider allows manipulating images
+type ImageProvider interface {
+	ListImages(context.Context) ([]ImageInfo, error)
+	SaveImages(context.Context, string, ...string) error
+	SaveImagesWithOpts(context.Context, string, []string, ...SaveImageOption) error
+	PullImage(context.Context, string) error
+	PullImageWithOpts(context.Context, string, ...PullImageOption) error
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/config/config.go b/vendor/github.com/testcontainers/testcontainers-go/internal/config/config.go
new file mode 100644
index 000000000..262f40d67
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/config/config.go
@@ -0,0 +1,185 @@
+package config
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strconv"
+	"sync"
+	"time"
+
+	"github.com/magiconair/properties"
+)
+
+const ReaperDefaultImage = "testcontainers/ryuk:0.14.0"
+
+var (
+	tcConfig     Config
+	tcConfigOnce = new(sync.Once)
+)
+
+// testcontainersConfig {
+
+// Config represents the configuration for Testcontainers.
+// User values are read from ~/.testcontainers.properties file which can be overridden
+// using the specified environment variables. For more information, see [Custom Configuration].
+//
+// The Ryuk prefixed fields controls the [Garbage Collector] feature, which ensures that
+// resources are cleaned up after the test execution.
+//
+// [Garbage Collector]: https://golang.testcontainers.org/features/garbage_collector/
+// [Custom Configuration]: https://golang.testcontainers.org/features/configuration/
+type Config struct {
+	// Host is the address of the Docker daemon.
+	//
+	// Environment variable: DOCKER_HOST
+	Host string `properties:"docker.host,default="`
+
+	// TLSVerify is a flag to enable or disable TLS verification when connecting to a Docker daemon.
+	//
+	// Environment variable: DOCKER_TLS_VERIFY
+	TLSVerify int `properties:"docker.tls.verify,default=0"`
+
+	// CertPath is the path to the directory containing the Docker certificates.
+	// This is used when connecting to a Docker daemon over TLS.
+	//
+	// Environment variable: DOCKER_CERT_PATH
+	CertPath string `properties:"docker.cert.path,default="`
+
+	// HubImageNamePrefix is the prefix used for the images pulled from the Docker Hub.
+	// This is useful when running tests in environments with restricted internet access.
+	//
+	// Environment variable: TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX
+	HubImageNamePrefix string `properties:"hub.image.name.prefix,default="`
+
+	// RyukDisabled is a flag to enable or disable the Garbage Collector.
+	// Setting this to true will prevent testcontainers from automatically cleaning up
+	// resources, which is particularly important in tests which timeout as they
+	// don't run test clean up.
+	//
+	// Environment variable: TESTCONTAINERS_RYUK_DISABLED
+	RyukDisabled bool `properties:"ryuk.disabled,default=false"`
+
+	// RyukPrivileged is a flag to enable or disable the privileged mode for the Garbage Collector container.
+	// Setting this to true will run the Garbage Collector container in privileged mode.
+	//
+	// Environment variable: TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED
+	RyukPrivileged bool `properties:"ryuk.container.privileged,default=false"`
+
+	// RyukReconnectionTimeout is the time to wait before attempting to reconnect to the Garbage Collector container.
+	//
+	// Environment variable: RYUK_RECONNECTION_TIMEOUT
+	RyukReconnectionTimeout time.Duration `properties:"ryuk.reconnection.timeout,default=10s"`
+
+	// RyukConnectionTimeout is the time to wait before timing out when connecting to the Garbage Collector container.
+	//
+	// Environment variable: RYUK_CONNECTION_TIMEOUT
+	RyukConnectionTimeout time.Duration `properties:"ryuk.connection.timeout,default=1m"`
+
+	// RyukVerbose is a flag to enable or disable verbose logging for the Garbage Collector.
+	//
+	// Environment variable: RYUK_VERBOSE
+	RyukVerbose bool `properties:"ryuk.verbose,default=false"`
+
+	// TestcontainersHost is the address of the Testcontainers host.
+	//
+	// Environment variable: TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE
+	TestcontainersHost string `properties:"tc.host,default="`
+}
+
+// }
+
+// Read reads from testcontainers properties file, if it exists
+// it is possible that certain values get overridden when set as environment variables
+func Read() Config {
+	tcConfigOnce.Do(func() {
+		tcConfig = read()
+	})
+
+	return tcConfig
+}
+
+// Reset resets the singleton instance of the Config struct,
+// allowing to read the configuration again.
+// Handy for testing, so do not use it in production code
+// This function is not thread-safe
+func Reset() {
+	tcConfigOnce = new(sync.Once)
+}
+
+func read() Config {
+	config := Config{}
+
+	applyEnvironmentConfiguration := func(config Config) Config {
+		ryukDisabledEnv := os.Getenv("TESTCONTAINERS_RYUK_DISABLED")
+		if parseBool(ryukDisabledEnv) {
+			config.RyukDisabled = ryukDisabledEnv == "true"
+		}
+
+		hubImageNamePrefix := os.Getenv("TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX")
+		if hubImageNamePrefix != "" {
+			config.HubImageNamePrefix = hubImageNamePrefix
+		}
+
+		ryukPrivilegedEnv := os.Getenv("TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED")
+		if parseBool(ryukPrivilegedEnv) {
+			config.RyukPrivileged = ryukPrivilegedEnv == "true"
+		}
+
+		ryukVerboseEnv := readTestcontainersEnv("RYUK_VERBOSE")
+		if parseBool(ryukVerboseEnv) {
+			config.RyukVerbose = ryukVerboseEnv == "true"
+		}
+
+		ryukReconnectionTimeoutEnv := readTestcontainersEnv("RYUK_RECONNECTION_TIMEOUT")
+		if timeout, err := time.ParseDuration(ryukReconnectionTimeoutEnv); err == nil {
+			config.RyukReconnectionTimeout = timeout
+		}
+
+		ryukConnectionTimeoutEnv := readTestcontainersEnv("RYUK_CONNECTION_TIMEOUT")
+		if timeout, err := time.ParseDuration(ryukConnectionTimeoutEnv); err == nil {
+			config.RyukConnectionTimeout = timeout
+		}
+
+		return config
+	}
+
+	home, err := os.UserHomeDir()
+	if err != nil {
+		return applyEnvironmentConfiguration(config)
+	}
+
+	tcProp := filepath.Join(home, ".testcontainers.properties")
+	// init from a file
+	properties, err := properties.LoadFile(tcProp, properties.UTF8)
+	if err != nil {
+		return applyEnvironmentConfiguration(config)
+	}
+
+	if err := properties.Decode(&config); err != nil {
+		fmt.Printf("invalid testcontainers properties file, returning an empty Testcontainers configuration: %v\n", err)
+		return applyEnvironmentConfiguration(config)
+	}
+
+	return applyEnvironmentConfiguration(config)
+}
+
+func parseBool(input string) bool {
+	_, err := strconv.ParseBool(input)
+	return err == nil
+}
+
+// readTestcontainersEnv reads the environment variable with the given name.
+// It checks for the environment variable with the given name first, and then
+// checks for the environment variable with the given name prefixed with "TESTCONTAINERS_".
+func readTestcontainersEnv(envVar string) string {
+	value := os.Getenv(envVar)
+	if value != "" {
+		return value
+	}
+
+	// TODO: remove this prefix after the next major release
+	const prefix string = "TESTCONTAINERS_"
+
+	return os.Getenv(prefix + envVar)
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/core/bootstrap.go b/vendor/github.com/testcontainers/testcontainers-go/internal/core/bootstrap.go
new file mode 100644
index 000000000..d249d9be3
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/core/bootstrap.go
@@ -0,0 +1,106 @@
+package core
+
+import (
+	"crypto/sha256"
+	"encoding/hex"
+	"fmt"
+	"os"
+
+	"github.com/google/uuid"
+	"github.com/shirou/gopsutil/v4/process"
+)
+
+// sessionID returns a unique session ID for the current test session. Because each Go package
+// will be run in a separate process, we need a way to identify the current test session.
+// By test session, we mean:
+//   - a single "go test" invocation (including flags)
+//   - a single "go test ./..." invocation (including flags)
+//   - the execution of a single test or a set of tests using the IDE
+//
+// As a consequence, with the sole goal of aggregating test execution across multiple
+// packages, this function will use the parent process ID (pid) of the current process
+// and its creation date, to use it to generate a unique session ID. We are using the parent pid because
+// the current process will be a child process of:
+//   - the process that is running the tests, e.g.: "go test";
+//   - the process that is running the application in development mode, e.g. "go run main.go -tags dev";
+//   - the process that is running the tests in the IDE, e.g.: "go test ./...".
+//
+// Finally, we will hash the combination of the "testcontainers-go:" string with the parent pid
+// and the creation date of that parent process to generate a unique session ID.
+//
+// This sessionID will be used to:
+//   - identify the test session, aggregating the test execution of multiple packages in the same test session.
+//   - tag the containers created by testcontainers-go, adding a label to the container with the session ID.
+var sessionID string
+
+// projectPath returns the current working directory of the parent test process running Testcontainers for Go.
+// If it's not possible to get that directory, the library will use the current working directory. If again
+// it's not possible to get the current working directory, the library will use a temporary directory.
+var projectPath string
+
+// processID returns a unique ID for the current test process. Because each Go package will be run in a separate process,
+// we need a way to identify the current test process, in the form of a UUID
+var processID string
+
+const sessionIDPlaceholder = "testcontainers-go:%d:%d"
+
+func init() {
+	processID = uuid.New().String()
+
+	parentPid := os.Getppid()
+	var createTime int64
+	fallbackCwd, err := os.Getwd()
+	if err != nil {
+		// very unlikely to fail, but if it does, we will use a temp dir
+		fallbackCwd = os.TempDir()
+	}
+
+	processes, err := process.Processes()
+	if err != nil {
+		sessionID = uuid.New().String()
+		projectPath = fallbackCwd
+		return
+	}
+
+	for _, p := range processes {
+		if int(p.Pid) != parentPid {
+			continue
+		}
+
+		cwd, err := p.Cwd()
+		if err != nil {
+			cwd = fallbackCwd
+		}
+		projectPath = cwd
+
+		t, err := p.CreateTime()
+		if err != nil {
+			sessionID = uuid.New().String()
+			return
+		}
+
+		createTime = t
+		break
+	}
+
+	hasher := sha256.New()
+	_, err = fmt.Fprintf(hasher, sessionIDPlaceholder, parentPid, createTime)
+	if err != nil {
+		sessionID = uuid.New().String()
+		return
+	}
+
+	sessionID = hex.EncodeToString(hasher.Sum(nil))
+}
+
+func ProcessID() string {
+	return processID
+}
+
+func ProjectPath() string {
+	return projectPath
+}
+
+func SessionID() string {
+	return sessionID
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/core/client.go b/vendor/github.com/testcontainers/testcontainers-go/internal/core/client.go
new file mode 100644
index 000000000..795e6640c
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/core/client.go
@@ -0,0 +1,53 @@
+package core
+
+import (
+	"context"
+	"path/filepath"
+
+	"github.com/moby/moby/client"
+
+	"github.com/testcontainers/testcontainers-go/internal"
+	"github.com/testcontainers/testcontainers-go/internal/config"
+)
+
+// NewClient returns a new docker client extracting the docker host from the different alternatives
+func NewClient(ctx context.Context, ops ...client.Opt) (*client.Client, error) {
+	dockerHost, err := ExtractDockerHost(ctx)
+	if err != nil {
+		return nil, err
+	}
+
+	tcConfig := config.Read()
+
+	opts := []client.Opt{client.FromEnv}
+	if dockerHost != "" {
+		opts = append(opts, client.WithHost(dockerHost))
+
+		// for further information, read https://docs.docker.com/engine/security/protect-access/
+		if tcConfig.TLSVerify == 1 {
+			cacertPath := filepath.Join(tcConfig.CertPath, "ca.pem")
+			certPath := filepath.Join(tcConfig.CertPath, "cert.pem")
+			keyPath := filepath.Join(tcConfig.CertPath, "key.pem")
+
+			opts = append(opts, client.WithTLSClientConfig(cacertPath, certPath, keyPath))
+		}
+	}
+
+	opts = append(opts, client.WithHTTPHeaders(
+		map[string]string{
+			"x-tc-pp":    ProjectPath(),
+			"x-tc-sid":   SessionID(),
+			"User-Agent": "tc-go/" + internal.Version,
+		}),
+	)
+
+	// passed options have priority over the default ones
+	opts = append(opts, ops...)
+
+	cli, err := client.New(opts...)
+	if err != nil {
+		return nil, err
+	}
+
+	return cli, nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_host.go b/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_host.go
new file mode 100644
index 000000000..fbb2e2b05
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_host.go
@@ -0,0 +1,334 @@
+package core
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"os"
+	"os/exec"
+	"strings"
+	"sync"
+
+	"github.com/moby/moby/client"
+
+	"github.com/testcontainers/testcontainers-go/internal/config"
+)
+
+type dockerHostContext string
+
+var DockerHostContextKey = dockerHostContext("docker_host")
+
+var (
+	ErrDockerHostNotSet               = errors.New("DOCKER_HOST is not set")
+	ErrDockerSocketOverrideNotSet     = errors.New("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE is not set")
+	ErrDockerSocketNotSetInContext    = errors.New("socket not set in context")
+	ErrDockerSocketNotSetInProperties = errors.New("socket not set in ~/.testcontainers.properties")
+	ErrNoUnixSchema                   = errors.New("URL schema is not unix")
+	ErrSocketNotFound                 = errors.New("socket not found")
+	ErrSocketNotFoundInPath           = errors.New("docker socket not found in " + DockerSocketPath)
+	// ErrTestcontainersHostNotSetInProperties this error is specific to Testcontainers
+	ErrTestcontainersHostNotSetInProperties = errors.New("tc.host not set in ~/.testcontainers.properties")
+)
+
+var (
+	dockerHostCache    string
+	dockerHostErrCache error
+	dockerHostOnce     sync.Once
+)
+
+var (
+	dockerSocketPathCache string
+	dockerSocketPathOnce  sync.Once
+)
+
+// deprecated
+// see https://github.com/testcontainers/testcontainers-java/blob/main/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java#L46
+func DefaultGatewayIP() (string, error) {
+	// see https://github.com/testcontainers/testcontainers-java/blob/3ad8d80e2484864e554744a4800a81f6b7982168/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java#L27
+	cmd := exec.Command("sh", "-c", "ip route|awk '/default/ { print $3 }'")
+	stdout, err := cmd.Output()
+	if err != nil {
+		return "", errors.New("failed to detect docker host")
+	}
+	ip := strings.TrimSpace(string(stdout))
+	if len(ip) == 0 {
+		return "", errors.New("failed to parse default gateway IP")
+	}
+	return ip, nil
+}
+
+// dockerHostCheck Use a vanilla Docker client to check if the Docker host is reachable.
+// It will avoid recursive calls to this function.
+var dockerHostCheck = func(ctx context.Context, host string) error {
+	cli, err := client.New(client.FromEnv, client.WithHost(host))
+	if err != nil {
+		return fmt.Errorf("new client: %w", err)
+	}
+	defer cli.Close()
+
+	_, err = cli.Info(ctx, client.InfoOptions{})
+	if err != nil {
+		return fmt.Errorf("docker info: %w", err)
+	}
+
+	return nil
+}
+
+// MustExtractDockerHost Extracts the docker host from the different alternatives, caching the result to avoid unnecessary
+// calculations. Use this function to get the actual Docker host. This function does not consider Windows containers at the moment.
+// The possible alternatives are:
+//
+//  1. Docker host from the "tc.host" property in the ~/.testcontainers.properties file.
+//  2. DOCKER_HOST environment variable.
+//  3. Docker host from context.
+//  4. Docker host from the default docker socket path, without the unix schema.
+//  5. Docker host from the "docker.host" property in the ~/.testcontainers.properties file.
+//  6. Rootless docker socket path.
+//  7. Else, because the Docker host is not set, it panics.
+func MustExtractDockerHost(ctx context.Context) string {
+	host, err := ExtractDockerHost(ctx)
+	if err != nil {
+		panic(err)
+	}
+	return host
+}
+
+func ExtractDockerHost(ctx context.Context) (string, error) {
+	dockerHostOnce.Do(func() {
+		dockerHostCache, dockerHostErrCache = extractDockerHost(ctx)
+	})
+	return dockerHostCache, dockerHostErrCache
+}
+
+// MustExtractDockerSocket Extracts the docker socket from the different alternatives, removing the socket schema and
+// caching the result to avoid unnecessary calculations. Use this function to get the docker socket path,
+// not the host (e.g. mounting the socket in a container). This function does not consider Windows containers at the moment.
+// The possible alternatives are:
+//
+//  1. Docker host from the "tc.host" property in the ~/.testcontainers.properties file.
+//  2. The TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE environment variable.
+//  3. Using a Docker client, check if the Info().OperatingSystem is "Docker Desktop" and return the default docker socket path for rootless docker.
+//  4. Else, Get the current Docker Host from the existing strategies: see MustExtractDockerHost.
+//  5. If the socket contains the unix schema, the schema is removed (e.g. unix:///var/run/docker.sock -> /var/run/docker.sock)
+//  6. Else, the default location of the docker socket is used (/var/run/docker.sock)
+//
+// It panics if a Docker client cannot be created, or the Docker host cannot be discovered.
+func MustExtractDockerSocket(ctx context.Context) string {
+	dockerSocketPathOnce.Do(func() {
+		dockerSocketPathCache = extractDockerSocket(ctx)
+	})
+
+	return dockerSocketPathCache
+}
+
+// extractDockerHost Extracts the docker host from the different alternatives, without caching the result.
+// This internal method is handy for testing purposes.
+func extractDockerHost(ctx context.Context) (string, error) {
+	dockerHostFns := []func(context.Context) (string, error){
+		testcontainersHostFromProperties,
+		dockerHostFromEnv,
+		dockerHostFromContext,
+		dockerSocketPath,
+		dockerHostFromProperties,
+		rootlessDockerSocketPath,
+	}
+
+	var errs []error
+	for _, dockerHostFn := range dockerHostFns {
+		dockerHost, err := dockerHostFn(ctx)
+		if err != nil {
+			if !isHostNotSet(err) {
+				errs = append(errs, err)
+			}
+			continue
+		}
+
+		if err = dockerHostCheck(ctx, dockerHost); err != nil {
+			errs = append(errs, fmt.Errorf("check host %q: %w", dockerHost, err))
+			continue
+		}
+
+		return dockerHost, nil
+	}
+
+	if len(errs) > 0 {
+		return "", errors.Join(errs...)
+	}
+
+	return "", ErrSocketNotFound
+}
+
+// extractDockerSocket Extracts the docker socket from the different alternatives, without caching the result.
+// It will internally use the default Docker client, calling the internal method extractDockerSocketFromClient with it.
+// This internal method is handy for testing purposes.
+// It panics if a Docker client cannot be created, or the Docker host is not discovered.
+func extractDockerSocket(ctx context.Context) string {
+	cli, err := NewClient(ctx)
+	if err != nil {
+		panic(err) // a Docker client is required to get the Docker info
+	}
+	defer cli.Close()
+
+	return extractDockerSocketFromClient(ctx, cli)
+}
+
+// extractDockerSocketFromClient Extracts the docker socket from the different alternatives, without caching the result,
+// and receiving an instance of the Docker API client interface.
+// This internal method is handy for testing purposes, passing a mock type simulating the desired behaviour.
+// It panics if the Docker Info call errors, or the Docker host is not discovered.
+func extractDockerSocketFromClient(ctx context.Context, cli client.APIClient) string {
+	// check that the socket is not a tcp or unix socket
+	checkDockerSocketFn := func(socket string) string {
+		// this use case will cover the case when the docker host is a tcp socket
+		if strings.HasPrefix(socket, TCPSchema) {
+			return DockerSocketPath
+		}
+
+		if strings.HasPrefix(socket, DockerSocketSchema) {
+			return strings.Replace(socket, DockerSocketSchema, "", 1)
+		}
+
+		return socket
+	}
+
+	tcHost, err := testcontainersHostFromProperties(ctx)
+	if err == nil {
+		return checkDockerSocketFn(tcHost)
+	}
+
+	testcontainersDockerSocket, err := dockerSocketOverridePath()
+	if err == nil {
+		return checkDockerSocketFn(testcontainersDockerSocket)
+	}
+
+	info, err := cli.Info(ctx, client.InfoOptions{})
+	if err != nil {
+		panic(err) // Docker Info is required to get the Operating System
+	}
+
+	// Because Docker Desktop runs in a VM, we need to use the default docker path for rootless docker
+	if info.Info.OperatingSystem == "Docker Desktop" {
+		if IsWindows() {
+			return WindowsDockerSocketPath
+		}
+
+		return DockerSocketPath
+	}
+
+	dockerHost, err := extractDockerHost(ctx)
+	if err != nil {
+		panic(err) // Docker host is required to get the Docker socket
+	}
+
+	return checkDockerSocketFn(dockerHost)
+}
+
+// isHostNotSet returns true if the error is related to the Docker host
+// not being set, false otherwise.
+func isHostNotSet(err error) bool {
+	switch {
+	case errors.Is(err, ErrTestcontainersHostNotSetInProperties),
+		errors.Is(err, ErrDockerHostNotSet),
+		errors.Is(err, ErrDockerSocketNotSetInContext),
+		errors.Is(err, ErrDockerSocketNotSetInProperties),
+		errors.Is(err, ErrSocketNotFoundInPath),
+		errors.Is(err, ErrXDGRuntimeDirNotSet),
+		errors.Is(err, ErrRootlessDockerNotFoundHomeRunDir),
+		errors.Is(err, ErrRootlessDockerNotFoundHomeDesktopDir),
+		errors.Is(err, ErrRootlessDockerNotFoundRunDir):
+		return true
+	default:
+		return false
+	}
+}
+
+// dockerHostFromEnv returns the docker host from the DOCKER_HOST environment variable, if it's not empty
+func dockerHostFromEnv(_ context.Context) (string, error) {
+	if dockerHostPath := os.Getenv("DOCKER_HOST"); dockerHostPath != "" {
+		return dockerHostPath, nil
+	}
+
+	return "", ErrDockerHostNotSet
+}
+
+// dockerHostFromContext returns the docker host from the Go context, if it's not empty
+func dockerHostFromContext(ctx context.Context) (string, error) {
+	if socketPath, ok := ctx.Value(DockerHostContextKey).(string); ok && socketPath != "" {
+		parsed, err := parseURL(socketPath)
+		if err != nil {
+			return "", err
+		}
+
+		return parsed, nil
+	}
+
+	return "", ErrDockerSocketNotSetInContext
+}
+
+// dockerHostFromProperties returns the docker host from the ~/.testcontainers.properties file, if it's not empty
+func dockerHostFromProperties(_ context.Context) (string, error) {
+	cfg := config.Read()
+	socketPath := cfg.Host
+	if socketPath != "" {
+		return socketPath, nil
+	}
+
+	return "", ErrDockerSocketNotSetInProperties
+}
+
+// dockerSocketOverridePath returns the docker socket from the TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE environment variable,
+// if it's not empty
+func dockerSocketOverridePath() (string, error) {
+	if dockerHostPath, exists := os.LookupEnv("TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE"); exists {
+		return dockerHostPath, nil
+	}
+
+	return "", ErrDockerSocketOverrideNotSet
+}
+
+// dockerSocketPath returns the docker socket from the default docker socket path, if it's not empty
+// and the socket exists
+func dockerSocketPath(_ context.Context) (string, error) {
+	if fileExists(DockerSocketPath) {
+		return DockerSocketPathWithSchema, nil
+	}
+
+	return "", ErrSocketNotFoundInPath
+}
+
+// testcontainersHostFromProperties returns the testcontainers host from the ~/.testcontainers.properties file, if it's not empty
+func testcontainersHostFromProperties(_ context.Context) (string, error) {
+	cfg := config.Read()
+	testcontainersHost := cfg.TestcontainersHost
+	if testcontainersHost != "" {
+		// Validate the URL format
+		_, err := parseURL(testcontainersHost)
+		if err != nil {
+			return "", err
+		}
+
+		// Return the original URL to preserve schema for Docker client
+		return testcontainersHost, nil
+	}
+
+	return "", ErrTestcontainersHostNotSetInProperties
+}
+
+// DockerEnvFile is the file that is created when running inside a container.
+// It's a variable to allow testing.
+// TODO: Remove this once context rework is done, which eliminates need for the default network creation.
+var DockerEnvFile = "/.dockerenv"
+
+// InAContainer returns true if the code is running inside a container
+// See https://github.com/docker/docker/blob/a9fa38b1edf30b23cae3eade0be48b3d4b1de14b/daemon/initlayer/setup_unix.go#L25
+func InAContainer() bool {
+	return inAContainer(DockerEnvFile)
+}
+
+func inAContainer(path string) bool {
+	// see https://github.com/testcontainers/testcontainers-java/blob/3ad8d80e2484864e554744a4800a81f6b7982168/core/src/main/java/org/testcontainers/dockerclient/DockerClientConfigUtils.java#L15
+	if _, err := os.Stat(path); err == nil {
+		return true
+	}
+	return false
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_rootless.go b/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_rootless.go
new file mode 100644
index 000000000..81083842e
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_rootless.go
@@ -0,0 +1,150 @@
+package core
+
+import (
+	"context"
+	"errors"
+	"net/url"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strconv"
+)
+
+var (
+	ErrRootlessDockerNotFound               = errors.New("rootless Docker not found")
+	ErrRootlessDockerNotFoundHomeDesktopDir = errors.New("checked path: ~/.docker/desktop/docker.sock")
+	ErrRootlessDockerNotFoundHomeRunDir     = errors.New("checked path: ~/.docker/run/docker.sock")
+	ErrRootlessDockerNotFoundRunDir         = errors.New("checked path: /run/user/${uid}/docker.sock")
+	ErrRootlessDockerNotFoundXDGRuntimeDir  = errors.New("checked path: $XDG_RUNTIME_DIR")
+	ErrRootlessDockerNotSupportedWindows    = errors.New("rootless Docker is not supported on Windows")
+	ErrXDGRuntimeDirNotSet                  = errors.New("XDG_RUNTIME_DIR is not set")
+)
+
+// baseRunDir is the base directory for the "/run/user/${uid}" directory.
+// It is a variable so it can be modified for testing.
+var baseRunDir = "/run"
+
+// IsWindows returns if the current OS is Windows. For that it checks the GOOS environment variable or the runtime.GOOS constant.
+func IsWindows() bool {
+	return os.Getenv("GOOS") == "windows" || runtime.GOOS == "windows"
+}
+
+// rootlessDockerSocketPath returns if the path to the rootless Docker socket exists.
+// The rootless socket path is determined by the following order:
+//
+//  1. XDG_RUNTIME_DIR environment variable.
+//  2. ~/.docker/run/docker.sock file.
+//  3. ~/.docker/desktop/docker.sock file.
+//  4. /run/user/${uid}/docker.sock file.
+//  5. Else, return ErrRootlessDockerNotFound, wrapping specific errors for each of the above paths.
+//
+// It should include the Docker socket schema (unix://) in the returned path.
+func rootlessDockerSocketPath(_ context.Context) (string, error) {
+	// adding a manner to test it on non-windows machines, setting the GOOS env var to windows
+	// This is needed because runtime.GOOS is a constant that returns the OS of the machine running the test
+	if IsWindows() {
+		return "", ErrRootlessDockerNotSupportedWindows
+	}
+
+	socketPathFns := []func() (string, error){
+		rootlessSocketPathFromEnv,
+		rootlessSocketPathFromHomeRunDir,
+		rootlessSocketPathFromHomeDesktopDir,
+		rootlessSocketPathFromRunDir,
+	}
+
+	var errs []error
+	for _, socketPathFn := range socketPathFns {
+		s, err := socketPathFn()
+		if err != nil {
+			if !isHostNotSet(err) {
+				errs = append(errs, err)
+			}
+			continue
+		}
+
+		return DockerSocketSchema + s, nil
+	}
+
+	if len(errs) > 0 {
+		return "", errors.Join(errs...)
+	}
+
+	return "", ErrRootlessDockerNotFound
+}
+
+func fileExists(f string) bool {
+	_, err := os.Stat(f)
+	return err == nil
+}
+
+func parseURL(s string) (string, error) {
+	hostURL, err := url.Parse(s)
+	if err != nil {
+		return "", err
+	}
+
+	switch hostURL.Scheme {
+	case "unix", "npipe":
+		return hostURL.Path, nil
+	case "tcp":
+		// return the original URL, as it is a valid TCP URL
+		return s, nil
+	default:
+		return "", ErrNoUnixSchema
+	}
+}
+
+// rootlessSocketPathFromEnv returns the path to the rootless Docker socket from the XDG_RUNTIME_DIR environment variable.
+// It should include the Docker socket schema (unix://) in the returned path.
+func rootlessSocketPathFromEnv() (string, error) {
+	xdgRuntimeDir, exists := os.LookupEnv("XDG_RUNTIME_DIR")
+	if exists {
+		f := filepath.Join(xdgRuntimeDir, "docker.sock")
+		if fileExists(f) {
+			return f, nil
+		}
+
+		return "", ErrRootlessDockerNotFoundXDGRuntimeDir
+	}
+
+	return "", ErrXDGRuntimeDirNotSet
+}
+
+// rootlessSocketPathFromHomeRunDir returns the path to the rootless Docker socket from the ~/.docker/run/docker.sock file.
+func rootlessSocketPathFromHomeRunDir() (string, error) {
+	home, err := os.UserHomeDir()
+	if err != nil {
+		return "", err
+	}
+
+	f := filepath.Join(home, ".docker", "run", "docker.sock")
+	if fileExists(f) {
+		return f, nil
+	}
+	return "", ErrRootlessDockerNotFoundHomeRunDir
+}
+
+// rootlessSocketPathFromHomeDesktopDir returns the path to the rootless Docker socket from the ~/.docker/desktop/docker.sock file.
+func rootlessSocketPathFromHomeDesktopDir() (string, error) {
+	home, err := os.UserHomeDir()
+	if err != nil {
+		return "", err
+	}
+
+	f := filepath.Join(home, ".docker", "desktop", "docker.sock")
+	if fileExists(f) {
+		return f, nil
+	}
+	return "", ErrRootlessDockerNotFoundHomeDesktopDir
+}
+
+// rootlessSocketPathFromRunDir returns the path to the rootless Docker socket from the /run/user/<uid>/docker.sock file.
+func rootlessSocketPathFromRunDir() (string, error) {
+	uid := os.Getuid()
+	f := filepath.Join(baseRunDir, "user", strconv.Itoa(uid), "docker.sock")
+	if fileExists(f) {
+		return f, nil
+	}
+	return "", ErrRootlessDockerNotFoundRunDir
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_socket.go b/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_socket.go
new file mode 100644
index 000000000..d34929014
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/core/docker_socket.go
@@ -0,0 +1,49 @@
+package core
+
+import (
+	"net/url"
+	"strings"
+
+	"github.com/moby/moby/client"
+)
+
+// DockerSocketSchema is the unix schema.
+var DockerSocketSchema = "unix://"
+
+// DockerSocketPath is the path to the docker socket under unix systems.
+var DockerSocketPath = "/var/run/docker.sock"
+
+// DockerSocketPathWithSchema is the path to the docker socket under unix systems with the unix schema.
+var DockerSocketPathWithSchema = DockerSocketSchema + DockerSocketPath
+
+// TCPSchema is the tcp schema.
+var TCPSchema = "tcp://"
+
+// WindowsDockerSocketPath is the path to the docker socket under windows systems.
+var WindowsDockerSocketPath = "//var/run/docker.sock"
+
+func init() {
+	const DefaultDockerHost = client.DefaultDockerHost
+
+	u, err := url.Parse(DefaultDockerHost)
+	if err != nil {
+		// unsupported default host specified by the docker client package,
+		// so revert to the default unix docker socket path
+		return
+	}
+
+	switch u.Scheme {
+	case "unix", "npipe":
+		DockerSocketSchema = u.Scheme + "://"
+		DockerSocketPath = u.Path
+		if !strings.HasPrefix(DockerSocketPath, "/") {
+			// seeing as the code in this module depends on DockerSocketPath having
+			// a slash (`/`) prefix, we add it here if it is missing.
+			// for the known environments, we do not foresee how the socket-path
+			// should miss the slash, however this extra if-condition is worth to
+			// save future pain from innocent users.
+			DockerSocketPath = "/" + DockerSocketPath
+		}
+		DockerSocketPathWithSchema = DockerSocketSchema + DockerSocketPath
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/core/images.go b/vendor/github.com/testcontainers/testcontainers-go/internal/core/images.go
new file mode 100644
index 000000000..90793f3fc
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/core/images.go
@@ -0,0 +1,143 @@
+package core
+
+import (
+	"bufio"
+	"io"
+	"net/url"
+	"os"
+	"regexp"
+	"strings"
+	"unicode/utf8"
+)
+
+const (
+	IndexDockerIO   = "https://index.docker.io/v1/"
+	maxURLRuneCount = 2083
+	minURLRuneCount = 3
+	URLSchema       = `((ftp|tcp|udp|wss?|https?):\/\/)`
+	URLUsername     = `(\S+(:\S*)?@)`
+	URLIP           = `([1-9]\d?|1\d\d|2[01]\d|22[0-3]|24\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-5]))`
+	IP              = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`
+	URLSubdomain    = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))`
+	URLPath         = `((\/|\?|#)[^\s]*)`
+	URLPort         = `(:(\d{1,5}))`
+	URL             = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$`
+)
+
+var rxURL = regexp.MustCompile(URL)
+
+// ExtractImagesFromDockerfile extracts images from the Dockerfile sourced from dockerfile.
+func ExtractImagesFromDockerfile(dockerfile string, buildArgs map[string]*string) ([]string, error) {
+	file, err := os.Open(dockerfile)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+
+	return ExtractImagesFromReader(file, buildArgs)
+}
+
+// ExtractImagesFromReader extracts images from the Dockerfile sourced from r.
+func ExtractImagesFromReader(r io.Reader, buildArgs map[string]*string) ([]string, error) {
+	var lines []string
+	scanner := bufio.NewScanner(r)
+	for scanner.Scan() {
+		lines = append(lines, scanner.Text())
+	}
+	if scanner.Err() != nil {
+		return nil, scanner.Err()
+	}
+
+	images := make([]string, 0, len(lines))
+
+	// extract images from dockerfile
+	for _, line := range lines {
+		line = strings.TrimSpace(line)
+		if !strings.HasPrefix(strings.ToUpper(line), "FROM") {
+			continue
+		}
+
+		// remove FROM
+		line = strings.TrimPrefix(line, "FROM")
+		parts := strings.Split(strings.TrimSpace(line), " ")
+		if len(parts) == 0 {
+			continue
+		}
+
+		// interpolate build args
+		for k, v := range buildArgs {
+			if v != nil {
+				parts[0] = strings.ReplaceAll(parts[0], "${"+k+"}", *v)
+			}
+		}
+		images = append(images, parts[0])
+	}
+
+	return images, nil
+}
+
+// ExtractRegistry extracts the registry from the image name, using a regular expression to extract the registry from the image name.
+// regular expression to extract the registry from the image name
+// the regular expression is based on the grammar defined in
+// - image:tag
+// - image
+// - repository/image:tag
+// - repository/image
+// - registry/image:tag
+// - registry/image
+// - registry/repository/image:tag
+// - registry/repository/image
+// - registry:port/repository/image:tag
+// - registry:port/repository/image
+// - registry:port/image:tag
+// - registry:port/image
+// Once extracted the registry, it is validated to check if it is a valid URL or an IP address.
+func ExtractRegistry(image string, fallback string) string {
+	exp := regexp.MustCompile(`^(?:(?P<registry>(https?://)?[^/]+)(?::(?P<port>\d+))?/)?(?:(?P<repository>[^/]+)/)?(?P<image>[^:]+)(?::(?P<tag>.+))?$`).FindStringSubmatch(image)
+	if len(exp) == 0 {
+		return ""
+	}
+
+	registry := exp[1]
+
+	// docker.io is an implicit reference, return fallback for normalization
+	if strings.EqualFold(registry, "docker.io") {
+		return fallback
+	}
+
+	// registry.hub.docker.com is an explicit registry reference, preserve it
+	if strings.EqualFold(registry, "registry.hub.docker.com") {
+		return "registry.hub.docker.com"
+	}
+
+	if IsURL(registry) {
+		return registry
+	}
+
+	return fallback
+}
+
+// IsURL checks if the string is a URL.
+// Extracted from https://github.com/asaskevich/govalidator/blob/f21760c49a8d/validator.go#L104
+func IsURL(str string) bool {
+	if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") {
+		return false
+	}
+	strTemp := str
+	if strings.Contains(str, ":") && !strings.Contains(str, "://") {
+		// support no indicated urlscheme but with colon for port number
+		// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
+		strTemp = "http://" + str
+	}
+	u, err := url.Parse(strTemp)
+	if err != nil {
+		return false
+	}
+	if strings.HasPrefix(u.Host, ".") {
+		return false
+	}
+	if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
+		return false
+	}
+	return rxURL.MatchString(str)
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/core/labels.go b/vendor/github.com/testcontainers/testcontainers-go/internal/core/labels.go
new file mode 100644
index 000000000..fdfee742f
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/core/labels.go
@@ -0,0 +1,72 @@
+package core
+
+import (
+	"errors"
+	"fmt"
+	"maps"
+	"strings"
+
+	"github.com/testcontainers/testcontainers-go/internal"
+	"github.com/testcontainers/testcontainers-go/internal/config"
+)
+
+const (
+	// LabelBase is the base label for all testcontainers labels.
+	LabelBase = "org.testcontainers"
+
+	// LabelLang specifies the language which created the test container.
+	LabelLang = LabelBase + ".lang"
+
+	// LabelReaper identifies the container as a reaper.
+	LabelReaper = LabelBase + ".reaper"
+
+	// LabelRyuk identifies the container as a ryuk.
+	LabelRyuk = LabelBase + ".ryuk"
+
+	// LabelSessionID specifies the session ID of the container.
+	LabelSessionID = LabelBase + ".sessionId"
+
+	// LabelVersion specifies the version of testcontainers which created the container.
+	LabelVersion = LabelBase + ".version"
+
+	// LabelReap specifies the container should be reaped by the reaper.
+	LabelReap = LabelBase + ".reap"
+)
+
+// DefaultLabels returns the standard set of labels which
+// includes LabelSessionID if the reaper is enabled.
+func DefaultLabels(sessionID string) map[string]string {
+	labels := map[string]string{
+		LabelBase:      "true",
+		LabelLang:      "go",
+		LabelVersion:   internal.Version,
+		LabelSessionID: sessionID,
+	}
+
+	if !config.Read().RyukDisabled {
+		labels[LabelReap] = "true"
+	}
+
+	return labels
+}
+
+// AddDefaultLabels adds the default labels for sessionID to target.
+func AddDefaultLabels(sessionID string, target map[string]string) {
+	maps.Copy(target, DefaultLabels(sessionID))
+}
+
+// MergeCustomLabels sets labels from src to dst.
+// If a key in src has [LabelBase] prefix returns an error.
+// If dst is nil returns an error.
+func MergeCustomLabels(dst, src map[string]string) error {
+	if dst == nil {
+		return errors.New("destination map is nil")
+	}
+	for key := range src {
+		if strings.HasPrefix(key, LabelBase) {
+			return fmt.Errorf("key %q has %q prefix", key, LabelBase)
+		}
+	}
+	maps.Copy(dst, src)
+	return nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/core/network/network.go b/vendor/github.com/testcontainers/testcontainers-go/internal/core/network/network.go
new file mode 100644
index 000000000..55081b3fb
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/core/network/network.go
@@ -0,0 +1,52 @@
+package network
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/moby/moby/api/types/network"
+	"github.com/moby/moby/client"
+
+	"github.com/testcontainers/testcontainers-go/internal/core"
+)
+
+const (
+	// FilterByID uses to filter network by identifier.
+	FilterByID = "id"
+
+	// FilterByName uses to filter network by name.
+	FilterByName = "name"
+)
+
+// Get returns a network by its ID.
+func Get(ctx context.Context, id string) (network.Summary, error) {
+	return get(ctx, FilterByID, id)
+}
+
+// GetByName returns a network by its name.
+func GetByName(ctx context.Context, name string) (network.Summary, error) {
+	return get(ctx, FilterByName, name)
+}
+
+func get(ctx context.Context, filter string, value string) (network.Summary, error) {
+	var nw network.Summary // initialize to the zero value
+
+	cli, err := core.NewClient(ctx)
+	if err != nil {
+		return nw, err
+	}
+	defer cli.Close()
+
+	list, err := cli.NetworkList(ctx, client.NetworkListOptions{
+		Filters: make(client.Filters).Add(filter, value),
+	})
+	if err != nil {
+		return nw, fmt.Errorf("failed to list networks: %w", err)
+	}
+
+	if len(list.Items) == 0 {
+		return nw, fmt.Errorf("network %s not found (filtering by %s)", value, filter)
+	}
+
+	return list.Items[0], nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/internal/version.go b/vendor/github.com/testcontainers/testcontainers-go/internal/version.go
new file mode 100644
index 000000000..d18d432b9
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/internal/version.go
@@ -0,0 +1,4 @@
+package internal
+
+// Version is the next development version of the application
+const Version = "0.43.0"
diff --git a/vendor/github.com/testcontainers/testcontainers-go/lifecycle.go b/vendor/github.com/testcontainers/testcontainers-go/lifecycle.go
new file mode 100644
index 000000000..90516df78
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/lifecycle.go
@@ -0,0 +1,674 @@
+package testcontainers
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"reflect"
+	"strings"
+	"time"
+
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+
+	"github.com/testcontainers/testcontainers-go/log"
+)
+
+// ContainerRequestHook is a hook that will be called before a container is created.
+// It can be used to modify container configuration before it is created,
+// using the different lifecycle hooks that are available:
+// - Creating
+// For that, it will receive a ContainerRequest, modify it and return an error if needed.
+type ContainerRequestHook func(ctx context.Context, req ContainerRequest) error
+
+// ContainerHook is a hook that will be called after a container is created
+// It can be used to modify the state of the container after it is created,
+// using the different lifecycle hooks that are available:
+// - Created
+// - Starting
+// - Started
+// - Readied
+// - Stopping
+// - Stopped
+// - Terminating
+// - Terminated
+// For that, it will receive a Container, modify it and return an error if needed.
+type ContainerHook func(ctx context.Context, ctr Container) error
+
+// ContainerLifecycleHooks is a struct that contains all the hooks that can be used
+// to modify the container lifecycle. All the container lifecycle hooks except the PreCreates hooks
+// will be passed to the container once it's created
+type ContainerLifecycleHooks struct {
+	PreBuilds      []ContainerRequestHook
+	PostBuilds     []ContainerRequestHook
+	PreCreates     []ContainerRequestHook
+	PostCreates    []ContainerHook
+	PreStarts      []ContainerHook
+	PostStarts     []ContainerHook
+	PostReadies    []ContainerHook
+	PreStops       []ContainerHook
+	PostStops      []ContainerHook
+	PreTerminates  []ContainerHook
+	PostTerminates []ContainerHook
+}
+
+// DefaultLoggingHook is a hook that will log the container lifecycle events
+var DefaultLoggingHook = func(logger log.Logger) ContainerLifecycleHooks {
+	shortContainerID := func(c Container) string {
+		return c.GetContainerID()[:12]
+	}
+
+	return ContainerLifecycleHooks{
+		PreBuilds: []ContainerRequestHook{
+			func(_ context.Context, req ContainerRequest) error {
+				logger.Printf("🐳 Building image %s:%s", req.GetRepo(), req.GetTag())
+				return nil
+			},
+		},
+		PostBuilds: []ContainerRequestHook{
+			func(_ context.Context, req ContainerRequest) error {
+				logger.Printf("✅ Built image %s", req.Image)
+				return nil
+			},
+		},
+		PreCreates: []ContainerRequestHook{
+			func(_ context.Context, req ContainerRequest) error {
+				logger.Printf("🐳 Creating container for image %s", req.Image)
+				return nil
+			},
+		},
+		PostCreates: []ContainerHook{
+			func(_ context.Context, c Container) error {
+				logger.Printf("✅ Container created: %s", shortContainerID(c))
+				return nil
+			},
+		},
+		PreStarts: []ContainerHook{
+			func(_ context.Context, c Container) error {
+				logger.Printf("🐳 Starting container: %s", shortContainerID(c))
+				return nil
+			},
+		},
+		PostStarts: []ContainerHook{
+			func(_ context.Context, c Container) error {
+				logger.Printf("✅ Container started: %s", shortContainerID(c))
+				return nil
+			},
+		},
+		PostReadies: []ContainerHook{
+			func(_ context.Context, c Container) error {
+				logger.Printf("🔔 Container is ready: %s", shortContainerID(c))
+				return nil
+			},
+		},
+		PreStops: []ContainerHook{
+			func(_ context.Context, c Container) error {
+				logger.Printf("🐳 Stopping container: %s", shortContainerID(c))
+				return nil
+			},
+		},
+		PostStops: []ContainerHook{
+			func(_ context.Context, c Container) error {
+				logger.Printf("✅ Container stopped: %s", shortContainerID(c))
+				return nil
+			},
+		},
+		PreTerminates: []ContainerHook{
+			func(_ context.Context, c Container) error {
+				logger.Printf("🐳 Terminating container: %s", shortContainerID(c))
+				return nil
+			},
+		},
+		PostTerminates: []ContainerHook{
+			func(_ context.Context, c Container) error {
+				logger.Printf("🚫 Container terminated: %s", shortContainerID(c))
+				return nil
+			},
+		},
+	}
+}
+
+// defaultPreCreateHook is a hook that will apply the default configuration to the container
+var defaultPreCreateHook = func(p *DockerProvider, dockerInput *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) ContainerLifecycleHooks {
+	return ContainerLifecycleHooks{
+		PreCreates: []ContainerRequestHook{
+			func(ctx context.Context, req ContainerRequest) error {
+				return p.preCreateContainerHook(ctx, req, dockerInput, hostConfig, networkingConfig)
+			},
+		},
+	}
+}
+
+// defaultCopyFileToContainerHook is a hook that will copy files to the container after it's created
+// but before it's started
+var defaultCopyFileToContainerHook = func(files []ContainerFile) ContainerLifecycleHooks {
+	return ContainerLifecycleHooks{
+		PostCreates: []ContainerHook{
+			// copy files to container after it's created
+			func(ctx context.Context, c Container) error {
+				for _, f := range files {
+					if err := f.validate(); err != nil {
+						return fmt.Errorf("invalid file: %w", err)
+					}
+
+					var err error
+					// Bytes takes precedence over HostFilePath
+					if f.Reader != nil {
+						bs, ioerr := io.ReadAll(f.Reader)
+						if ioerr != nil {
+							return fmt.Errorf("can't read from reader: %w", ioerr)
+						}
+
+						err = c.CopyToContainer(ctx, bs, f.ContainerFilePath, f.FileMode)
+					} else {
+						err = c.CopyFileToContainer(ctx, f.HostFilePath, f.ContainerFilePath, f.FileMode)
+					}
+
+					if err != nil {
+						return fmt.Errorf("can't copy %s to container: %w", f.HostFilePath, err)
+					}
+				}
+
+				return nil
+			},
+		},
+	}
+}
+
+// defaultLogConsumersHook is a hook that will start log consumers after the container is started
+var defaultLogConsumersHook = func(cfg *LogConsumerConfig) ContainerLifecycleHooks {
+	return ContainerLifecycleHooks{
+		PostStarts: []ContainerHook{
+			// Produce logs sending details to the log consumers.
+			// See combineContainerHooks for the order of execution.
+			func(ctx context.Context, c Container) error {
+				if cfg == nil || len(cfg.Consumers) == 0 {
+					return nil
+				}
+
+				dockerContainer := c.(*DockerContainer)
+				dockerContainer.resetConsumers(cfg.Consumers)
+
+				return dockerContainer.startLogProduction(ctx, cfg.Opts...)
+			},
+		},
+		PostStops: []ContainerHook{
+			// Stop the log production.
+			// See combineContainerHooks for the order of execution.
+			func(_ context.Context, c Container) error {
+				if cfg == nil || len(cfg.Consumers) == 0 {
+					return nil
+				}
+
+				dockerContainer := c.(*DockerContainer)
+				return dockerContainer.stopLogProduction()
+			},
+		},
+	}
+}
+
+// defaultReadinessHook is a hook that will wait for the container to be ready
+var defaultReadinessHook = func() ContainerLifecycleHooks {
+	return ContainerLifecycleHooks{
+		PostStarts: []ContainerHook{
+			// wait for the container to be ready
+			func(ctx context.Context, c Container) error {
+				dockerContainer := c.(*DockerContainer)
+
+				// if a Wait Strategy has been specified, wait before returning
+				if dockerContainer.WaitingFor != nil {
+					strategy := dockerContainer.WaitingFor
+					strategyDesc := "unknown strategy"
+					if s, ok := strategy.(fmt.Stringer); ok {
+						strategyDesc = s.String()
+					}
+					dockerContainer.logger.Printf(
+						"⏳ Waiting for container id %s image: %s. Waiting for: %+v",
+						dockerContainer.ID[:12], dockerContainer.Image, strategyDesc,
+					)
+					if err := strategy.WaitUntilReady(ctx, dockerContainer); err != nil {
+						return fmt.Errorf("wait until ready: %w", err)
+					}
+				}
+
+				dockerContainer.isRunning.Store(true)
+
+				return nil
+			},
+		},
+	}
+}
+
+// buildingHook is a hook that will be called before a container image is built.
+func (req ContainerRequest) buildingHook(ctx context.Context) error {
+	return req.applyLifecycleHooks(func(lifecycleHooks ContainerLifecycleHooks) error {
+		return lifecycleHooks.Building(ctx)(req)
+	})
+}
+
+// builtHook is a hook that will be called after a container image is built.
+func (req ContainerRequest) builtHook(ctx context.Context) error {
+	return req.applyLifecycleHooks(func(lifecycleHooks ContainerLifecycleHooks) error {
+		return lifecycleHooks.Built(ctx)(req)
+	})
+}
+
+// creatingHook is a hook that will be called before a container is created.
+func (req ContainerRequest) creatingHook(ctx context.Context) error {
+	return req.applyLifecycleHooks(func(lifecycleHooks ContainerLifecycleHooks) error {
+		return lifecycleHooks.Creating(ctx)(req)
+	})
+}
+
+// applyLifecycleHooks calls hook on all LifecycleHooks.
+func (req ContainerRequest) applyLifecycleHooks(hook func(lifecycleHooks ContainerLifecycleHooks) error) error {
+	var errs []error
+	for _, lifecycleHooks := range req.LifecycleHooks {
+		if err := hook(lifecycleHooks); err != nil {
+			errs = append(errs, err)
+		}
+	}
+
+	return errors.Join(errs...)
+}
+
+// createdHook is a hook that will be called after a container is created.
+func (c *DockerContainer) createdHook(ctx context.Context) error {
+	return c.applyLifecycleHooks(ctx, false, func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook {
+		return lifecycleHooks.PostCreates
+	})
+}
+
+// startingHook is a hook that will be called before a container is started.
+func (c *DockerContainer) startingHook(ctx context.Context) error {
+	return c.applyLifecycleHooks(ctx, true, func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook {
+		return lifecycleHooks.PreStarts
+	})
+}
+
+// startedHook is a hook that will be called after a container is started.
+func (c *DockerContainer) startedHook(ctx context.Context) error {
+	return c.applyLifecycleHooks(ctx, true, func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook {
+		return lifecycleHooks.PostStarts
+	})
+}
+
+// readiedHook is a hook that will be called after a container is ready.
+func (c *DockerContainer) readiedHook(ctx context.Context) error {
+	return c.applyLifecycleHooks(ctx, true, func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook {
+		return lifecycleHooks.PostReadies
+	})
+}
+
+// printLogs is a helper function that will print the logs of a Docker container
+// We are going to use this helper function to inform the user of the logs when an error occurs
+func (c *DockerContainer) printLogs(ctx context.Context, cause error) {
+	reader, err := c.Logs(ctx)
+	if err != nil {
+		c.logger.Printf("failed accessing container logs: %v\n", err)
+		return
+	}
+
+	b, err := io.ReadAll(reader)
+	if err != nil {
+		if len(b) > 0 {
+			c.logger.Printf("failed reading container logs: %v\npartial container logs (%s):\n%s", err, cause, b)
+		} else {
+			c.logger.Printf("failed reading container logs: %v\n", err)
+		}
+		return
+	}
+
+	c.logger.Printf("container logs (%s):\n%s", cause, b)
+}
+
+// stoppingHook is a hook that will be called before a container is stopped.
+func (c *DockerContainer) stoppingHook(ctx context.Context) error {
+	return c.applyLifecycleHooks(ctx, false, func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook {
+		return lifecycleHooks.PreStops
+	})
+}
+
+// stoppedHook is a hook that will be called after a container is stopped.
+func (c *DockerContainer) stoppedHook(ctx context.Context) error {
+	return c.applyLifecycleHooks(ctx, false, func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook {
+		return lifecycleHooks.PostStops
+	})
+}
+
+// terminatingHook is a hook that will be called before a container is terminated.
+func (c *DockerContainer) terminatingHook(ctx context.Context) error {
+	return c.applyLifecycleHooks(ctx, false, func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook {
+		return lifecycleHooks.PreTerminates
+	})
+}
+
+// terminatedHook is a hook that will be called after a container is terminated.
+func (c *DockerContainer) terminatedHook(ctx context.Context) error {
+	return c.applyLifecycleHooks(ctx, false, func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook {
+		return lifecycleHooks.PostTerminates
+	})
+}
+
+// applyLifecycleHooks applies all lifecycle hooks reporting the container logs on error if logError is true.
+func (c *DockerContainer) applyLifecycleHooks(ctx context.Context, logError bool, hooks func(lifecycleHooks ContainerLifecycleHooks) []ContainerHook) error {
+	var errs []error
+	for _, lifecycleHooks := range c.lifecycleHooks {
+		if err := containerHookFn(ctx, hooks(lifecycleHooks))(c); err != nil {
+			errs = append(errs, err)
+		}
+	}
+
+	if err := errors.Join(errs...); err != nil {
+		if logError {
+			select {
+			case <-ctx.Done():
+				// Context has timed out so need a new context to get logs.
+				ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
+				defer cancel()
+				c.printLogs(ctx, err)
+			default:
+				c.printLogs(ctx, err)
+			}
+		}
+
+		return err
+	}
+
+	return nil
+}
+
+// Building is a hook that will be called before a container image is built.
+func (c ContainerLifecycleHooks) Building(ctx context.Context) func(req ContainerRequest) error {
+	return containerRequestHook(ctx, c.PreBuilds)
+}
+
+// Building is a hook that will be called before a container image is built.
+func (c ContainerLifecycleHooks) Built(ctx context.Context) func(req ContainerRequest) error {
+	return containerRequestHook(ctx, c.PostBuilds)
+}
+
+// Creating is a hook that will be called before a container is created.
+func (c ContainerLifecycleHooks) Creating(ctx context.Context) func(req ContainerRequest) error {
+	return containerRequestHook(ctx, c.PreCreates)
+}
+
+// containerRequestHook returns a function that will iterate over all
+// the hooks and call them one by one until there is an error.
+func containerRequestHook(ctx context.Context, hooks []ContainerRequestHook) func(req ContainerRequest) error {
+	return func(req ContainerRequest) error {
+		for _, hook := range hooks {
+			if err := hook(ctx, req); err != nil {
+				return err
+			}
+		}
+
+		return nil
+	}
+}
+
+// containerHookFn is a helper function that will create a function to be returned by all the different
+// container lifecycle hooks. The created function will iterate over all the hooks and call them one by one.
+func containerHookFn(ctx context.Context, containerHook []ContainerHook) func(container Container) error {
+	return func(ctr Container) error {
+		var errs []error
+		for _, hook := range containerHook {
+			if err := hook(ctx, ctr); err != nil {
+				errs = append(errs, err)
+			}
+		}
+
+		return errors.Join(errs...)
+	}
+}
+
+// Created is a hook that will be called after a container is created
+func (c ContainerLifecycleHooks) Created(ctx context.Context) func(container Container) error {
+	return containerHookFn(ctx, c.PostCreates)
+}
+
+// Starting is a hook that will be called before a container is started
+func (c ContainerLifecycleHooks) Starting(ctx context.Context) func(container Container) error {
+	return containerHookFn(ctx, c.PreStarts)
+}
+
+// Started is a hook that will be called after a container is started
+func (c ContainerLifecycleHooks) Started(ctx context.Context) func(container Container) error {
+	return containerHookFn(ctx, c.PostStarts)
+}
+
+// Readied is a hook that will be called after a container is ready
+func (c ContainerLifecycleHooks) Readied(ctx context.Context) func(container Container) error {
+	return containerHookFn(ctx, c.PostReadies)
+}
+
+// Stopping is a hook that will be called before a container is stopped
+func (c ContainerLifecycleHooks) Stopping(ctx context.Context) func(container Container) error {
+	return containerHookFn(ctx, c.PreStops)
+}
+
+// Stopped is a hook that will be called after a container is stopped
+func (c ContainerLifecycleHooks) Stopped(ctx context.Context) func(container Container) error {
+	return containerHookFn(ctx, c.PostStops)
+}
+
+// Terminating is a hook that will be called before a container is terminated
+func (c ContainerLifecycleHooks) Terminating(ctx context.Context) func(container Container) error {
+	return containerHookFn(ctx, c.PreTerminates)
+}
+
+// Terminated is a hook that will be called after a container is terminated
+func (c ContainerLifecycleHooks) Terminated(ctx context.Context) func(container Container) error {
+	return containerHookFn(ctx, c.PostTerminates)
+}
+
+func (p *DockerProvider) preCreateContainerHook(ctx context.Context, req ContainerRequest, dockerInput *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig) error {
+	var mountErrors []error
+	for _, m := range req.Mounts {
+		// validate only the mount sources that implement the Validator interface
+		if v, ok := m.Source.(Validator); ok {
+			if err := v.Validate(); err != nil {
+				mountErrors = append(mountErrors, err)
+			}
+		}
+	}
+
+	if len(mountErrors) > 0 {
+		return errors.Join(mountErrors...)
+	}
+
+	// prepare mounts
+	hostConfig.Mounts = mapToDockerMounts(req.Mounts)
+
+	endpointSettings := map[string]*network.EndpointSettings{}
+
+	// #248: Docker allows only one network to be specified during container creation
+	// If there is more than one network specified in the request container should be attached to them
+	// once it is created. We will take a first network if any specified in the request and use it to create container
+	if len(req.Networks) > 0 {
+		attachContainerTo := req.Networks[0]
+
+		nw, err := p.GetNetwork(ctx, NetworkRequest{
+			Name: attachContainerTo,
+		})
+		if err == nil {
+			aliases := []string{}
+			if _, ok := req.NetworkAliases[attachContainerTo]; ok {
+				aliases = req.NetworkAliases[attachContainerTo]
+			}
+			endpointSetting := network.EndpointSettings{
+				Aliases:   aliases,
+				NetworkID: nw.ID,
+			}
+			endpointSettings[attachContainerTo] = &endpointSetting
+		}
+	}
+
+	if req.ConfigModifier == nil {
+		req.ConfigModifier = defaultConfigModifier(req)
+	}
+	req.ConfigModifier(dockerInput)
+
+	if req.HostConfigModifier == nil {
+		req.HostConfigModifier = defaultHostConfigModifier(req)
+	}
+	req.HostConfigModifier(hostConfig)
+
+	if req.EndpointSettingsModifier != nil {
+		req.EndpointSettingsModifier(endpointSettings)
+	}
+
+	networkingConfig.EndpointsConfig = endpointSettings
+
+	// Expose ports automatically if the container request exposes zero ports and the container
+	// does not run in a container network. The NetworkMode check must be done after the pre-creation
+	// Modifiers are called, so the network mode is already set.
+	exposedPorts := req.ExposedPorts
+	if len(exposedPorts) == 0 && !hostConfig.NetworkMode.IsContainer() {
+		image, err := p.client.ImageInspect(ctx, dockerInput.Image)
+		if err != nil {
+			return err
+		}
+
+		exposedPorts = exposedPorts[:0]
+		for port := range image.Config.ExposedPorts {
+			exposedPorts = append(exposedPorts, port)
+		}
+	}
+
+	exposedPortSet, err := parseExposedPorts(exposedPorts)
+	if err != nil {
+		return err
+	}
+
+	dockerInput.ExposedPorts = exposedPortSet
+	hostConfig.PortBindings = mergePortBindings(hostConfig.PortBindings, exposedPortSet)
+	return nil
+}
+
+// combineContainerHooks returns a ContainerLifecycle hook as the result
+// of combining the default hooks with the user-defined hooks.
+//
+// The order of hooks is the following:
+// - Pre-hooks run the default hooks first then the user-defined hooks
+// - Post-hooks run the user-defined hooks first then the default hooks
+func combineContainerHooks(defaultHooks, userDefinedHooks []ContainerLifecycleHooks) ContainerLifecycleHooks {
+	// We use reflection here to ensure that any new hooks are handled.
+	var hooks ContainerLifecycleHooks
+	hooksVal := reflect.ValueOf(&hooks).Elem()
+	hooksType := reflect.TypeOf(hooks)
+	for _, defaultHook := range defaultHooks {
+		defaultVal := reflect.ValueOf(defaultHook)
+		for i := range hooksType.NumField() {
+			if strings.HasPrefix(hooksType.Field(i).Name, "Pre") {
+				field := hooksVal.Field(i)
+				field.Set(reflect.AppendSlice(field, defaultVal.Field(i)))
+			}
+		}
+	}
+
+	// Append the user-defined hooks after the default pre-hooks
+	// and because the post hooks are still empty, the user-defined
+	// post-hooks will be the first ones to be executed.
+	for _, userDefinedHook := range userDefinedHooks {
+		userVal := reflect.ValueOf(userDefinedHook)
+		for i := range hooksType.NumField() {
+			field := hooksVal.Field(i)
+			field.Set(reflect.AppendSlice(field, userVal.Field(i)))
+		}
+	}
+
+	// Finally, append the default post-hooks.
+	for _, defaultHook := range defaultHooks {
+		defaultVal := reflect.ValueOf(defaultHook)
+		for i := range hooksType.NumField() {
+			if strings.HasPrefix(hooksType.Field(i).Name, "Post") {
+				field := hooksVal.Field(i)
+				field.Set(reflect.AppendSlice(field, defaultVal.Field(i)))
+			}
+		}
+	}
+
+	return hooks
+}
+
+func parseExposedPorts(specs []string) (network.PortSet, error) {
+	exposed := make(network.PortSet, len(specs))
+	for _, s := range specs {
+		pr, err := network.ParsePortRange(s)
+		if err != nil {
+			return nil, fmt.Errorf("invalid exposed port %q: %w", s, err)
+		}
+
+		for p := range pr.All() {
+			exposed[p] = struct{}{}
+		}
+	}
+	return exposed, nil
+}
+
+// mergePortBindings returns a PortMap for the given exposedPortSet.
+//
+// For each port in exposedPortSet, a binding is ensured:
+//   - If configPortMap contains bindings for that port, those bindings are used.
+//   - Otherwise, a default binding with HostPort "0" (ephemeral allocation)
+//     is assigned.
+//
+// Bindings for ports not present in exposedPortSet are not preserved.
+// Any binding with an empty HostPort is normalized to "0".
+//
+// TODO(thaJeztah): this logic seems the reverse of the docker CLI, which
+// exposes ports if the user requests a port-mapping (i.e., if a port-mapping
+// is requested, but not exposed, we map the port *and* add an entry to
+// ExposedPorts). The logic here is the reverse; any port "mapped" in
+// HostConfig.PortBindings is dropped if is not exposed.
+func mergePortBindings(configPortMap network.PortMap, exposedPortSet network.PortSet) network.PortMap {
+	if len(exposedPortSet) == 0 {
+		return network.PortMap{}
+	}
+
+	exposedPortMap := make(network.PortMap, len(exposedPortSet))
+	for p := range exposedPortSet {
+		bindings := configPortMap[p]
+		if len(bindings) == 0 {
+			exposedPortMap[p] = []network.PortBinding{{HostPort: "0"}}
+			continue
+		}
+
+		// Fix: Ensure that ports with empty HostPort get "0" for automatic allocation
+		// This fixes the UDP port binding issue where ports were getting HostPort:0 instead of being allocated
+		for i := range bindings {
+			if bindings[i].HostPort == "" {
+				bindings[i].HostPort = "0" // Tell Docker to allocate a random port
+			}
+		}
+		exposedPortMap[p] = bindings
+	}
+
+	return exposedPortMap
+}
+
+// defaultHostConfigModifier provides a default modifier including the deprecated fields
+func defaultConfigModifier(req ContainerRequest) func(config *container.Config) {
+	return func(config *container.Config) {
+		config.Hostname = req.Hostname
+		config.WorkingDir = req.WorkingDir
+		config.User = req.User
+	}
+}
+
+// defaultHostConfigModifier provides a default modifier including the deprecated fields
+func defaultHostConfigModifier(req ContainerRequest) func(hostConfig *container.HostConfig) {
+	return func(hostConfig *container.HostConfig) {
+		hostConfig.AutoRemove = req.AutoRemove
+		hostConfig.CapAdd = req.CapAdd
+		hostConfig.CapDrop = req.CapDrop
+		hostConfig.Binds = req.Binds
+		hostConfig.ExtraHosts = req.ExtraHosts
+		hostConfig.NetworkMode = req.NetworkMode
+		hostConfig.Resources = req.Resources
+		hostConfig.Privileged = req.Privileged
+		hostConfig.ShmSize = req.ShmSize
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/log/logger.go b/vendor/github.com/testcontainers/testcontainers-go/log/logger.go
new file mode 100644
index 000000000..d20e90a05
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/log/logger.go
@@ -0,0 +1,73 @@
+package log
+
+import (
+	"log"
+	"os"
+	"strings"
+	"testing"
+)
+
+// Validate our types implement the required interfaces.
+var (
+	_ Logger = (*log.Logger)(nil)
+	_ Logger = (*noopLogger)(nil)
+	_ Logger = (*testLogger)(nil)
+)
+
+// Logger defines the Logger interface.
+type Logger interface {
+	Printf(format string, v ...any)
+}
+
+// defaultLogger is the default Logger instance.
+var defaultLogger Logger = &noopLogger{}
+
+func init() {
+	// Enable default logger in the testing with a verbose flag.
+	if testing.Testing() {
+		// Parse manually because testing.Verbose() panics unless flag.Parse() has done.
+		for _, arg := range os.Args {
+			if strings.EqualFold(arg, "-test.v=true") || strings.EqualFold(arg, "-v") {
+				defaultLogger = log.New(os.Stderr, "", log.LstdFlags)
+			}
+		}
+	}
+}
+
+// Default returns the default Logger instance.
+func Default() Logger {
+	return defaultLogger
+}
+
+// SetDefault sets the default Logger instance.
+func SetDefault(logger Logger) {
+	defaultLogger = logger
+}
+
+func Printf(format string, v ...any) {
+	defaultLogger.Printf(format, v...)
+}
+
+type noopLogger struct{}
+
+// Printf implements Logging.
+func (n noopLogger) Printf(_ string, _ ...any) {
+	// NOOP
+}
+
+// TestLogger returns a Logging implementation for testing.TB
+// This way logs from testcontainers are part of the test output of a test suite or test case.
+func TestLogger(tb testing.TB) Logger {
+	tb.Helper()
+	return testLogger{TB: tb}
+}
+
+type testLogger struct {
+	testing.TB
+}
+
+// Printf implements Logging.
+func (t testLogger) Printf(format string, v ...any) {
+	t.Helper()
+	t.Logf(format, v...)
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/logconsumer.go b/vendor/github.com/testcontainers/testcontainers-go/logconsumer.go
new file mode 100644
index 000000000..95bf11198
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/logconsumer.go
@@ -0,0 +1,36 @@
+package testcontainers
+
+// StdoutLog is the log type for STDOUT
+const StdoutLog = "STDOUT"
+
+// StderrLog is the log type for STDERR
+const StderrLog = "STDERR"
+
+// logStruct {
+
+// Log represents a message that was created by a process,
+// LogType is either "STDOUT" or "STDERR",
+// Content is the byte contents of the message itself
+type Log struct {
+	LogType string
+	Content []byte
+}
+
+// }
+
+// logConsumerInterface {
+
+// LogConsumer represents any object that can
+// handle a Log, it is up to the LogConsumer instance
+// what to do with the log
+type LogConsumer interface {
+	Accept(Log)
+}
+
+// }
+
+// LogConsumerConfig is a configuration object for the producer/consumer pattern
+type LogConsumerConfig struct {
+	Opts      []LogProductionOption // options for the production of logs
+	Consumers []LogConsumer         // consumers for the logs
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/logger_option.go b/vendor/github.com/testcontainers/testcontainers-go/logger_option.go
new file mode 100644
index 000000000..d40dd93aa
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/logger_option.go
@@ -0,0 +1,45 @@
+package testcontainers
+
+import "github.com/testcontainers/testcontainers-go/log"
+
+// Validate our types implement the required interfaces.
+var (
+	_ ContainerCustomizer   = LoggerOption{}
+	_ GenericProviderOption = LoggerOption{}
+	_ DockerProviderOption  = LoggerOption{}
+)
+
+// WithLogger returns a generic option that sets the logger to be used.
+//
+// Consider calling this before other "With functions" as these may generate logs.
+//
+// This can be given a TestLogger to collect the logs from testcontainers into a
+// test case.
+func WithLogger(logger log.Logger) LoggerOption {
+	return LoggerOption{
+		logger: logger,
+	}
+}
+
+// LoggerOption is a generic option that sets the logger to be used.
+//
+// It can be used to set the logger for providers and containers.
+type LoggerOption struct {
+	logger log.Logger
+}
+
+// ApplyGenericTo implements GenericProviderOption.
+func (o LoggerOption) ApplyGenericTo(opts *GenericProviderOptions) {
+	opts.Logger = o.logger
+}
+
+// ApplyDockerTo implements DockerProviderOption.
+func (o LoggerOption) ApplyDockerTo(opts *DockerProviderOptions) {
+	opts.Logger = o.logger
+}
+
+// Customize implements ContainerCustomizer.
+func (o LoggerOption) Customize(req *GenericContainerRequest) error {
+	req.Logger = o.logger
+	return nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/mkdocs.yml b/vendor/github.com/testcontainers/testcontainers-go/mkdocs.yml
new file mode 100644
index 000000000..123271cfe
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/mkdocs.yml
@@ -0,0 +1,167 @@
+# This file is autogenerated by the 'modulegen' tool.
+site_name: Testcontainers for Go
+site_url: https://golang.testcontainers.org
+plugins:
+    - search
+    - codeinclude
+    - include-markdown
+    - markdownextradata
+theme:
+    name: material
+    custom_dir: docs/theme
+    palette:
+        scheme: testcontainers
+    font:
+        text: Roboto
+        code: Roboto Mono
+    logo: logo.svg
+    favicon: favicon.ico
+extra_css:
+    - css/extra.css
+    - css/tc-header.css
+    - css/usage-metrics.css
+extra_javascript:
+    - https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js
+    - https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js
+    - https://cdn.jsdelivr.net/npm/papaparse@5.4.1/papaparse.min.js
+    - js/usage-metrics.js
+repo_name: testcontainers-go
+repo_url: https://github.com/testcontainers/testcontainers-go
+markdown_extensions:
+    - admonition
+    - codehilite:
+        linenums: false
+    - pymdownx.superfences
+    - pymdownx.tabbed:
+        alternate_style: true
+    - pymdownx.snippets
+    - toc:
+        permalink: true
+    - attr_list
+    - pymdownx.emoji:
+        emoji_generator: !!python/name:material.extensions.emoji.to_svg
+        emoji_index: !!python/name:material.extensions.emoji.twemoji
+nav:
+    - Home: index.md
+    - Quickstart: quickstart.md
+    - Features:
+        - features/creating_container.md
+        - Wait Strategies:
+            - Introduction: features/wait/introduction.md
+            - Exec: features/wait/exec.md
+            - Exit: features/wait/exit.md
+            - File: features/wait/file.md
+            - Health: features/wait/health.md
+            - HostPort: features/wait/host_port.md
+            - HTTP: features/wait/http.md
+            - Log: features/wait/log.md
+            - SQL: features/wait/sql.md
+            - TLS: features/wait/tls.md
+            - Walk: features/wait/walk.md
+            - All: features/wait/all.md
+            - Any: features/wait/any.md
+        - features/files_and_mounts.md
+        - features/follow_logs.md
+        - features/garbage_collector.md
+        - features/build_from_dockerfile.md
+        - features/override_container_command.md
+        - features/networking.md
+        - features/configuration.md
+        - features/image_name_substitution.md
+        - features/test_session_semantics.md
+        - features/docker_auth.md
+        - features/docker_compose.md
+        - features/tls.md
+    - Modules:
+        - modules/index.md
+        - modules/aerospike.md
+        - modules/arangodb.md
+        - modules/artemis.md
+        - modules/azure.md
+        - modules/azurite.md
+        - modules/cassandra.md
+        - modules/chroma.md
+        - modules/clickhouse.md
+        - modules/cockroachdb.md
+        - modules/consul.md
+        - modules/couchbase.md
+        - modules/databend.md
+        - modules/dex.md
+        - modules/dind.md
+        - modules/dockermcpgateway.md
+        - modules/dockermodelrunner.md
+        - modules/dolt.md
+        - modules/dynamodb.md
+        - modules/elasticsearch.md
+        - modules/etcd.md
+        - modules/forgejo.md
+        - modules/gcloud.md
+        - modules/grafana-lgtm.md
+        - modules/inbucket.md
+        - modules/influxdb.md
+        - modules/k3s.md
+        - modules/k6.md
+        - modules/kafka.md
+        - modules/localstack.md
+        - modules/mariadb.md
+        - modules/meilisearch.md
+        - modules/memcached.md
+        - modules/milvus.md
+        - modules/minio.md
+        - modules/mockserver.md
+        - modules/mongodb-atlaslocal.md
+        - modules/mongodb.md
+        - modules/mssql.md
+        - modules/mysql.md
+        - modules/nats.md
+        - modules/nebulagraph.md
+        - modules/neo4j.md
+        - modules/ollama.md
+        - modules/openfga.md
+        - modules/openldap.md
+        - modules/opensearch.md
+        - modules/pinecone.md
+        - modules/postgres.md
+        - modules/pulsar.md
+        - modules/qdrant.md
+        - modules/rabbitmq.md
+        - modules/redis.md
+        - modules/redpanda.md
+        - modules/registry.md
+        - modules/scylladb.md
+        - modules/socat.md
+        - modules/solace.md
+        - modules/surrealdb.md
+        - modules/tidb.md
+        - modules/toxiproxy.md
+        - modules/valkey.md
+        - modules/vault.md
+        - modules/vearch.md
+        - modules/weaviate.md
+        - modules/yugabytedb.md
+    - Examples:
+        - examples/index.md
+        - examples/nginx.md
+    - System Requirements:
+        - system_requirements/index.md
+        - system_requirements/docker.md
+        - Continuous Integration:
+            - system_requirements/ci/aws_codebuild.md
+            - system_requirements/ci/bitbucket_pipelines.md
+            - system_requirements/ci/circle_ci.md
+            - system_requirements/ci/concourse_ci.md
+            - system_requirements/ci/dind_patterns.md
+            - system_requirements/ci/drone.md
+            - system_requirements/ci/gitlab_ci.md
+            - system_requirements/ci/tekton.md
+            - system_requirements/ci/travis.md
+        - system_requirements/using_colima.md
+        - system_requirements/using_podman.md
+        - system_requirements/rancher.md
+    - Usage Metrics: usage-metrics.md
+    - Dependabot: dependabot.md
+    - Contributing: contributing.md
+    - Getting help: getting_help.md
+edit_uri: edit/main/docs/
+extra:
+    latest_version: v0.43.0
diff --git a/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/LICENSE b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/LICENSE
new file mode 100644
index 000000000..607a9c3c4
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017-2019 Gianluca Arbezzano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/Makefile b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/Makefile
new file mode 100644
index 000000000..225f0c436
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/Makefile
@@ -0,0 +1,5 @@
+include ../../commons-test.mk
+
+.PHONY: test
+test:
+	$(MAKE) test-postgres
diff --git a/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/options.go b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/options.go
new file mode 100644
index 000000000..64d56cbdb
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/options.go
@@ -0,0 +1,39 @@
+package postgres
+
+import (
+	"github.com/testcontainers/testcontainers-go"
+)
+
+type options struct {
+	// SQLDriverName is the name of the SQL driver to use.
+	SQLDriverName string
+	Snapshot      string
+}
+
+func defaultOptions() options {
+	return options{
+		SQLDriverName: "postgres",
+		Snapshot:      defaultSnapshotName,
+	}
+}
+
+// Compiler check to ensure that Option implements the testcontainers.ContainerCustomizer interface.
+var _ testcontainers.ContainerCustomizer = (Option)(nil)
+
+// Option is an option for the Postgres container.
+type Option func(*options)
+
+// Customize is a NOOP. It's defined to satisfy the testcontainers.ContainerCustomizer interface.
+func (o Option) Customize(*testcontainers.GenericContainerRequest) error {
+	// NOOP to satisfy interface.
+	return nil
+}
+
+// WithSQLDriver sets the SQL driver to use for the container.
+// It is passed to sql.Open() to connect to the database when making or restoring snapshots.
+// This can be set if your app imports a different postgres driver, f.ex. "pgx"
+func WithSQLDriver(driver string) Option {
+	return func(o *options) {
+		o.SQLDriverName = driver
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/postgres.go b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/postgres.go
new file mode 100644
index 000000000..8c15b0806
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/postgres.go
@@ -0,0 +1,400 @@
+package postgres
+
+import (
+	"context"
+	"database/sql"
+	_ "embed"
+	"errors"
+	"fmt"
+	"io"
+	"path/filepath"
+	"strings"
+
+	"github.com/testcontainers/testcontainers-go"
+	"github.com/testcontainers/testcontainers-go/log"
+)
+
+const (
+	defaultUser         = "postgres"
+	defaultPassword     = "postgres"
+	defaultSnapshotName = "migrated_template"
+)
+
+//go:embed resources/customEntrypoint.sh
+var embeddedCustomEntrypoint string
+
+// PostgresContainer represents the postgres container type used in the module
+type PostgresContainer struct {
+	testcontainers.Container
+	dbName       string
+	user         string
+	password     string
+	snapshotName string
+	// sqlDriverName is passed to sql.Open() to connect to the database when making or restoring snapshots.
+	// This can be set if your app imports a different postgres driver, f.ex. "pgx"
+	sqlDriverName string
+}
+
+// MustConnectionString panics if the address cannot be determined.
+func (c *PostgresContainer) MustConnectionString(ctx context.Context, args ...string) string {
+	addr, err := c.ConnectionString(ctx, args...)
+	if err != nil {
+		panic(err)
+	}
+	return addr
+}
+
+// ConnectionString returns the connection string for the postgres container, using the default 5432 port, and
+// obtaining the host and exposed port from the container. It also accepts a variadic list of extra arguments
+// which will be appended to the connection string. The format of the extra arguments is the same as the
+// connection string format, e.g. "connect_timeout=10" or "application_name=myapp"
+func (c *PostgresContainer) ConnectionString(ctx context.Context, args ...string) (string, error) {
+	endpoint, err := c.PortEndpoint(ctx, "5432/tcp", "")
+	if err != nil {
+		return "", err
+	}
+
+	extraArgs := strings.Join(args, "&")
+	connStr := fmt.Sprintf("postgres://%s:%s@%s/%s?%s", c.user, c.password, endpoint, c.dbName, extraArgs)
+	return connStr, nil
+}
+
+// WithConfigFile sets the config file to be used for the postgres container
+// It will also set the "config_file" parameter to the path of the config file
+// as a command line argument to the container
+func WithConfigFile(cfg string) testcontainers.CustomizeRequestOption {
+	return func(req *testcontainers.GenericContainerRequest) error {
+		cfgFile := testcontainers.ContainerFile{
+			HostFilePath:      cfg,
+			ContainerFilePath: "/etc/postgresql.conf",
+			FileMode:          0o755,
+		}
+
+		if err := testcontainers.WithFiles(cfgFile)(req); err != nil {
+			return err
+		}
+
+		return testcontainers.WithCmdArgs("-c", "config_file=/etc/postgresql.conf")(req)
+	}
+}
+
+// WithDatabase sets the initial database to be created when the container starts
+// It can be used to define a different name for the default database that is created when the image is first started.
+// If it is not specified, then the value of WithUser will be used.
+func WithDatabase(dbName string) testcontainers.ContainerCustomizer {
+	return testcontainers.WithEnv(map[string]string{"POSTGRES_DB": dbName})
+}
+
+// WithInitScripts sets the init scripts to be run when the container starts.
+// These init scripts will be executed in sorted name order as defined by the container's current locale, which defaults to en_US.utf8.
+// If you need to run your scripts in a specific order, consider using `WithOrderedInitScripts` instead.
+func WithInitScripts(scripts ...string) testcontainers.CustomizeRequestOption {
+	containerFiles := make([]testcontainers.ContainerFile, 0, len(scripts))
+	for _, script := range scripts {
+		initScript := testcontainers.ContainerFile{
+			HostFilePath:      script,
+			ContainerFilePath: "/docker-entrypoint-initdb.d/" + filepath.Base(script),
+			FileMode:          0o755,
+		}
+		containerFiles = append(containerFiles, initScript)
+	}
+
+	return testcontainers.WithFiles(containerFiles...)
+}
+
+// WithOrderedInitScripts sets the init scripts to be run when the container starts.
+// The scripts will be run in the order that they are provided in this function.
+func WithOrderedInitScripts(scripts ...string) testcontainers.CustomizeRequestOption {
+	containerFiles := make([]testcontainers.ContainerFile, 0, len(scripts))
+	for idx, script := range scripts {
+		initScript := testcontainers.ContainerFile{
+			HostFilePath:      script,
+			ContainerFilePath: "/docker-entrypoint-initdb.d/" + fmt.Sprintf("%03d-%s", idx, filepath.Base(script)),
+			FileMode:          0o755,
+		}
+		containerFiles = append(containerFiles, initScript)
+	}
+
+	return testcontainers.WithFiles(containerFiles...)
+}
+
+// WithPassword sets the initial password of the user to be created when the container starts
+// It is required for you to use the PostgreSQL image. It must not be empty or undefined.
+// This environment variable sets the superuser password for PostgreSQL.
+func WithPassword(password string) testcontainers.ContainerCustomizer {
+	return testcontainers.WithEnv(map[string]string{"POSTGRES_PASSWORD": password})
+}
+
+// WithUsername sets the initial username to be created when the container starts
+// It is used in conjunction with WithPassword to set a user and its password.
+// It will create the specified user with superuser power and a database with the same name.
+// If it is not specified, then the default user of postgres will be used.
+func WithUsername(user string) testcontainers.ContainerCustomizer {
+	if user == "" {
+		user = defaultUser
+	}
+	return testcontainers.WithEnv(map[string]string{"POSTGRES_USER": user})
+}
+
+// Deprecated: use Run instead
+// RunContainer creates an instance of the Postgres container type
+func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*PostgresContainer, error) {
+	return Run(ctx, "postgres:16-alpine", opts...)
+}
+
+// Run creates an instance of the Postgres container type
+func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*PostgresContainer, error) {
+	// Gather all config options (defaults and then apply provided options)
+	settings := defaultOptions()
+	for _, opt := range opts {
+		if apply, ok := opt.(Option); ok {
+			apply(&settings)
+		}
+	}
+
+	moduleOpts := make([]testcontainers.ContainerCustomizer, 0, 3+len(opts))
+	moduleOpts = append(moduleOpts,
+		testcontainers.WithEnv(map[string]string{
+			"POSTGRES_USER":     defaultUser,
+			"POSTGRES_PASSWORD": defaultPassword,
+			"POSTGRES_DB":       defaultUser, // defaults to the user name
+		}),
+		testcontainers.WithExposedPorts("5432/tcp"),
+		testcontainers.WithCmd("postgres", "-c", "fsync=off"),
+	)
+
+	moduleOpts = append(moduleOpts, opts...)
+
+	ctr, err := testcontainers.Run(ctx, img, moduleOpts...)
+	var c *PostgresContainer
+	if ctr != nil {
+		c = &PostgresContainer{
+			Container:     ctr,
+			dbName:        defaultUser,
+			password:      defaultPassword,
+			user:          defaultUser,
+			sqlDriverName: settings.SQLDriverName,
+			snapshotName:  settings.Snapshot,
+		}
+	}
+
+	if err != nil {
+		return c, fmt.Errorf("run postgres: %w", err)
+	}
+
+	// Retrieve the actual env vars set on the container
+	inspect, err := ctr.Inspect(ctx)
+	if err != nil {
+		return c, fmt.Errorf("inspect postgres: %w", err)
+	}
+
+	var foundDB, foundUser, foundPass bool
+	for _, env := range inspect.Config.Env {
+		if v, ok := strings.CutPrefix(env, "POSTGRES_DB="); ok {
+			c.dbName, foundDB = v, true
+		}
+		if v, ok := strings.CutPrefix(env, "POSTGRES_USER="); ok {
+			c.user, foundUser = v, true
+		}
+		if v, ok := strings.CutPrefix(env, "POSTGRES_PASSWORD="); ok {
+			c.password, foundPass = v, true
+		}
+
+		if foundDB && foundUser && foundPass {
+			break
+		}
+	}
+
+	return c, nil
+}
+
+type snapshotConfig struct {
+	snapshotName string
+}
+
+// SnapshotOption is the type for passing options to the snapshot function of the database
+type SnapshotOption func(container *snapshotConfig) *snapshotConfig
+
+// WithSnapshotName adds a specific name to the snapshot database created from the main database defined on the
+// container. The snapshot must not have the same name as your main database, otherwise it will be overwritten
+func WithSnapshotName(name string) SnapshotOption {
+	return func(cfg *snapshotConfig) *snapshotConfig {
+		cfg.snapshotName = name
+		return cfg
+	}
+}
+
+// WithSSLSettings configures the Postgres server to run with the provided CA Chain
+// This will not function if the corresponding postgres conf is not correctly configured.
+// Namely the paths below must match what is set in the conf file
+func WithSSLCert(caCertFile string, certFile string, keyFile string) testcontainers.CustomizeRequestOption {
+	const defaultPermission = 0o600
+
+	return func(req *testcontainers.GenericContainerRequest) error {
+		const entrypointPath = "/usr/local/bin/docker-entrypoint-ssl.bash"
+
+		if err := testcontainers.WithFiles(
+			testcontainers.ContainerFile{
+				HostFilePath:      caCertFile,
+				ContainerFilePath: "/tmp/testcontainers-go/postgres/ca_cert.pem",
+				FileMode:          defaultPermission,
+			},
+			testcontainers.ContainerFile{
+				HostFilePath:      certFile,
+				ContainerFilePath: "/tmp/testcontainers-go/postgres/server.cert",
+				FileMode:          defaultPermission,
+			},
+			testcontainers.ContainerFile{
+				HostFilePath:      keyFile,
+				ContainerFilePath: "/tmp/testcontainers-go/postgres/server.key",
+				FileMode:          defaultPermission,
+			},
+			testcontainers.ContainerFile{
+				Reader:            strings.NewReader(embeddedCustomEntrypoint),
+				ContainerFilePath: entrypointPath,
+				FileMode:          defaultPermission,
+			},
+		)(req); err != nil {
+			return err
+		}
+
+		return testcontainers.WithEntrypoint("sh", entrypointPath)(req)
+	}
+}
+
+// Snapshot takes a snapshot of the current state of the database as a template, which can then be restored using
+// the Restore method. By default, the snapshot will be created under a database called migrated_template, you can
+// customize the snapshot name with the options.
+// If a snapshot already exists under the given/default name, it will be overwritten with the new snapshot.
+func (c *PostgresContainer) Snapshot(ctx context.Context, opts ...SnapshotOption) error {
+	snapshotName, err := c.checkSnapshotConfig(opts)
+	if err != nil {
+		return err
+	}
+
+	// execute the commands to create the snapshot, in order
+	if err := c.execCommandsSQL(ctx,
+		// Update pg_database to remove the template flag, then drop the database if it exists.
+		// This is needed because dropping a template database will fail.
+		// https://www.postgresql.org/docs/current/manage-ag-templatedbs.html
+		fmt.Sprintf(`UPDATE pg_database SET datistemplate = FALSE WHERE datname = '%s'`, snapshotName),
+		fmt.Sprintf(`DROP DATABASE IF EXISTS "%s"`, snapshotName),
+		// Create a copy of the database to another database to use as a template now that it was fully migrated
+		fmt.Sprintf(`CREATE DATABASE "%s" WITH TEMPLATE "%s" OWNER "%s"`, snapshotName, c.dbName, c.user),
+		// Snapshot the template database so we can restore it onto our original database going forward
+		fmt.Sprintf(`ALTER DATABASE "%s" WITH is_template = TRUE`, snapshotName),
+	); err != nil {
+		return err
+	}
+
+	c.snapshotName = snapshotName
+	return nil
+}
+
+// Restore will restore the database to a specific snapshot. By default, it will restore the last snapshot taken on the
+// database by the Snapshot method. If a snapshot name is provided, it will instead try to restore the snapshot by name.
+func (c *PostgresContainer) Restore(ctx context.Context, opts ...SnapshotOption) error {
+	snapshotName, err := c.checkSnapshotConfig(opts)
+	if err != nil {
+		return err
+	}
+
+	// execute the commands to restore the snapshot, in order
+	return c.execCommandsSQL(ctx,
+		// Terminate all connections to the template database explicitly as the forced drop below will sometimes
+		// not terminate them and then fail to drop the database.
+		fmt.Sprintf(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '%s' AND pid <> pg_backend_pid()`, snapshotName),
+		// Drop the database if it exists
+		fmt.Sprintf(`DROP DATABASE IF EXISTS "%s" with (FORCE)`, c.dbName),
+		// Then restore the previous snapshot
+		fmt.Sprintf(`CREATE DATABASE "%s" WITH TEMPLATE "%s" OWNER "%s"`, c.dbName, snapshotName, c.user),
+	)
+}
+
+func (c *PostgresContainer) checkSnapshotConfig(opts []SnapshotOption) (string, error) {
+	config := &snapshotConfig{}
+	for _, opt := range opts {
+		config = opt(config)
+	}
+
+	snapshotName := c.snapshotName
+	if config.snapshotName != "" {
+		snapshotName = config.snapshotName
+	}
+
+	if c.dbName == "postgres" {
+		return "", errors.New("cannot restore the postgres system database as it cannot be dropped to be restored")
+	}
+	return snapshotName, nil
+}
+
+func (c *PostgresContainer) execCommandsSQL(ctx context.Context, cmds ...string) error {
+	conn, cleanup, err := c.snapshotConnection(ctx)
+	if err != nil {
+		log.Printf("Could not connect to database to restore snapshot, falling back to `docker exec psql`: %v", err)
+		return c.execCommandsFallback(ctx, cmds)
+	}
+	if cleanup != nil {
+		defer cleanup()
+	}
+	for _, cmd := range cmds {
+		if _, err := conn.ExecContext(ctx, cmd); err != nil {
+			return fmt.Errorf("could not execute restore command %s: %w", cmd, err)
+		}
+	}
+	return nil
+}
+
+// snapshotConnection connects to the actual database using the "postgres" sql.DB driver, if it exists.
+// The returned function should be called as a defer() to close the pool.
+// No need to close the individual connection, that is done as part of the pool close.
+// Also, no need to cache the connection pool, since it is a single connection which is very fast to establish.
+func (c *PostgresContainer) snapshotConnection(ctx context.Context) (*sql.Conn, func(), error) {
+	// Connect to the database "postgres" instead of the app one
+	c2 := &PostgresContainer{
+		Container:     c.Container,
+		dbName:        "postgres",
+		user:          c.user,
+		password:      c.password,
+		sqlDriverName: c.sqlDriverName,
+	}
+
+	// Try to use an actual postgres connection, if the driver is loaded
+	connStr := c2.MustConnectionString(ctx, "sslmode=disable")
+	pool, err := sql.Open(c.sqlDriverName, connStr)
+	if err != nil {
+		return nil, nil, fmt.Errorf("sql.Open for snapshot connection failed: %w", err)
+	}
+
+	cleanupPool := func() {
+		if err := pool.Close(); err != nil {
+			log.Printf("Could not close database connection pool after restoring snapshot: %v", err)
+		}
+	}
+
+	conn, err := pool.Conn(ctx)
+	if err != nil {
+		cleanupPool()
+		return nil, nil, fmt.Errorf("DB.Conn for snapshot connection failed: %w", err)
+	}
+	return conn, cleanupPool, nil
+}
+
+func (c *PostgresContainer) execCommandsFallback(ctx context.Context, cmds []string) error {
+	for _, cmd := range cmds {
+		exitCode, reader, err := c.Exec(ctx, []string{"psql", "-v", "ON_ERROR_STOP=1", "-U", c.user, "-d", "postgres", "-c", cmd})
+		if err != nil {
+			return err
+		}
+		if exitCode != 0 {
+			buf := new(strings.Builder)
+			_, err := io.Copy(buf, reader)
+			if err != nil {
+				return fmt.Errorf("non-zero exit code for restore command, could not read command output: %w", err)
+			}
+
+			return fmt.Errorf("non-zero exit code for restore command: %s", buf.String())
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/resources/customEntrypoint.sh b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/resources/customEntrypoint.sh
new file mode 100644
index 000000000..ff4ffa429
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/resources/customEntrypoint.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+set -Eeo pipefail
+
+
+pUID=$(id -u postgres)
+pGID=$(id -g postgres)
+
+if [ -z "$pUID" ]
+then
+    echo "Unable to find postgres user id, required in order to chown key material"
+    exit 1
+fi
+
+if [ -z "$pGID" ]
+then
+    echo "Unable to find postgres group id, required in order to chown key material"
+    exit 1
+fi
+
+chown "$pUID":"$pGID" \
+    /tmp/testcontainers-go/postgres/ca_cert.pem \
+    /tmp/testcontainers-go/postgres/server.cert \
+    /tmp/testcontainers-go/postgres/server.key
+
+/usr/local/bin/docker-entrypoint.sh "$@"
diff --git a/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/wait_strategies.go b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/wait_strategies.go
new file mode 100644
index 000000000..92dc3f6ec
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/modules/postgres/wait_strategies.go
@@ -0,0 +1,27 @@
+package postgres
+
+import (
+	"github.com/testcontainers/testcontainers-go"
+	"github.com/testcontainers/testcontainers-go/wait"
+)
+
+// BasicWaitStrategies is a simple but reliable way to wait for postgres to start.
+// It returns a two-step wait strategy:
+//
+//   - It will wait for the container to log `database system is ready to accept connections` twice, because it will restart itself after the first startup.
+//   - It will then wait for docker to actually serve the port on localhost.
+//     For non-linux OSes like Mac and Windows, Docker or Rancher Desktop will have to start a separate proxy.
+//     Without this, the tests will be flaky on those OSes!
+func BasicWaitStrategies() testcontainers.CustomizeRequestOption {
+	// waitStrategy {
+	return testcontainers.WithAdditionalWaitStrategy(
+		// First, we wait for the container to log readiness twice.
+		// This is because it will restart itself after the first startup.
+		wait.ForLog("database system is ready to accept connections").WithOccurrence(2),
+		// Then, we wait for docker to actually serve the port on localhost.
+		// For non-linux OSes like Mac and Windows, Docker or Rancher Desktop will have to start a separate proxy.
+		// Without this, the tests will be flaky on those OSes!
+		wait.ForListeningPort("5432/tcp"),
+	)
+	// }
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/mounts.go b/vendor/github.com/testcontainers/testcontainers-go/mounts.go
new file mode 100644
index 000000000..2e1d2c7e6
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/mounts.go
@@ -0,0 +1,175 @@
+package testcontainers
+
+import (
+	"errors"
+	"path/filepath"
+)
+
+const (
+	MountTypeBind MountType = iota // Deprecated: Use MountTypeVolume instead
+	MountTypeVolume
+	MountTypeTmpfs
+	MountTypePipe
+	MountTypeImage
+)
+
+var (
+	ErrDuplicateMountTarget = errors.New("duplicate mount target detected")
+	ErrInvalidBindMount     = errors.New("invalid bind mount")
+)
+
+var (
+	_ ContainerMountSource = (*GenericBindMountSource)(nil) // Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+	_ ContainerMountSource = (*GenericVolumeMountSource)(nil)
+	_ ContainerMountSource = (*GenericTmpfsMountSource)(nil)
+	_ ContainerMountSource = (*GenericImageMountSource)(nil)
+)
+
+type (
+	// ContainerMounts represents a collection of mounts for a container
+	ContainerMounts []ContainerMount
+	MountType       uint
+)
+
+// ContainerMountSource is the base for all mount sources
+type ContainerMountSource interface {
+	// Source will be used as Source field in the final mount
+	// this might either be a volume name, a host path or might be empty e.g. for Tmpfs
+	Source() string
+
+	// Type determines the final mount type
+	// possible options are limited by the Docker API
+	Type() MountType
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+// GenericBindMountSource implements ContainerMountSource and represents a bind mount
+// Optionally mount.BindOptions might be added for advanced scenarios
+type GenericBindMountSource struct {
+	// HostPath is the path mounted into the container
+	// the same host path might be mounted to multiple locations within a single container
+	HostPath string
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+func (s GenericBindMountSource) Source() string {
+	return s.HostPath
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+func (GenericBindMountSource) Type() MountType {
+	return MountTypeBind
+}
+
+// GenericVolumeMountSource implements ContainerMountSource and represents a volume mount
+type GenericVolumeMountSource struct {
+	// Name refers to the name of the volume to be mounted
+	// the same volume might be mounted to multiple locations within a single container
+	Name string
+}
+
+func (s GenericVolumeMountSource) Source() string {
+	return s.Name
+}
+
+func (GenericVolumeMountSource) Type() MountType {
+	return MountTypeVolume
+}
+
+// GenericTmpfsMountSource implements ContainerMountSource and represents a TmpFS mount
+// Optionally mount.TmpfsOptions might be added for advanced scenarios
+type GenericTmpfsMountSource struct{}
+
+func (s GenericTmpfsMountSource) Source() string {
+	return ""
+}
+
+func (GenericTmpfsMountSource) Type() MountType {
+	return MountTypeTmpfs
+}
+
+// ContainerMountTarget represents the target path within a container where the mount will be available
+// Note that mount targets must be unique. It's not supported to mount different sources to the same target.
+type ContainerMountTarget string
+
+func (t ContainerMountTarget) Target() string {
+	return string(t)
+}
+
+// Deprecated: use Files or HostConfigModifier in the ContainerRequest, or copy files container APIs to make containers portable across Docker environments
+// BindMount returns a new ContainerMount with a GenericBindMountSource as source
+// This is a convenience method to cover typical use cases.
+func BindMount(hostPath string, mountTarget ContainerMountTarget) ContainerMount {
+	return ContainerMount{
+		Source: GenericBindMountSource{HostPath: hostPath},
+		Target: mountTarget,
+	}
+}
+
+// VolumeMount returns a new ContainerMount with a GenericVolumeMountSource as source
+// This is a convenience method to cover typical use cases.
+func VolumeMount(volumeName string, mountTarget ContainerMountTarget) ContainerMount {
+	return ContainerMount{
+		Source: GenericVolumeMountSource{Name: volumeName},
+		Target: mountTarget,
+	}
+}
+
+// ImageMount returns a new ContainerMount with a GenericImageMountSource as source
+// This is a convenience method to cover typical use cases.
+func ImageMount(imageName string, subpath string, mountTarget ContainerMountTarget) ContainerMount {
+	return ContainerMount{
+		Source: NewGenericImageMountSource(imageName, subpath),
+		Target: mountTarget,
+	}
+}
+
+// Mounts returns a ContainerMounts to support a more fluent API
+func Mounts(mounts ...ContainerMount) ContainerMounts {
+	return mounts
+}
+
+// ContainerMount models a mount into a container
+type ContainerMount struct {
+	// Source is typically either a GenericVolumeMountSource, as BindMount is not supported by all Docker environments
+	Source ContainerMountSource
+	// Target is the path where the mount should be mounted within the container
+	Target ContainerMountTarget
+	// ReadOnly determines if the mount should be read-only
+	ReadOnly bool
+}
+
+// GenericImageMountSource implements ContainerMountSource and represents an image mount
+type GenericImageMountSource struct {
+	// imageName refers to the name of the image to be mounted
+	// the same image might be mounted to multiple locations within a single container
+	imageName string
+	// subpath is the path within the image to be mounted
+	subpath string
+}
+
+// NewGenericImageMountSource creates a new GenericImageMountSource
+func NewGenericImageMountSource(imageName string, subpath string) GenericImageMountSource {
+	return GenericImageMountSource{
+		imageName: imageName,
+		subpath:   subpath,
+	}
+}
+
+// Source returns the name of the image to be mounted
+func (s GenericImageMountSource) Source() string {
+	return s.imageName
+}
+
+// Type returns the type of the mount
+func (GenericImageMountSource) Type() MountType {
+	return MountTypeImage
+}
+
+// Validate validates the source of the mount
+func (s GenericImageMountSource) Validate() error {
+	if !filepath.IsLocal(s.subpath) {
+		return errors.New("image mount source must be a local path")
+	}
+	return nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/network.go b/vendor/github.com/testcontainers/testcontainers-go/network.go
new file mode 100644
index 000000000..c5fa4eb52
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/network.go
@@ -0,0 +1,60 @@
+package testcontainers
+
+import (
+	"context"
+
+	"github.com/moby/moby/api/types/network"
+
+	"github.com/testcontainers/testcontainers-go/internal/core"
+)
+
+// NetworkProvider allows the creation of networks on an arbitrary system
+type NetworkProvider interface {
+	CreateNetwork(context.Context, NetworkRequest) (Network, error)      // create a network
+	GetNetwork(context.Context, NetworkRequest) (network.Inspect, error) // get a network
+}
+
+// Deprecated: will be removed in the future
+// Network allows getting info about a single network instance
+type Network interface {
+	Remove(context.Context) error // removes the network
+}
+
+// Deprecated: will be removed in the future.
+type DefaultNetwork string
+
+// Deprecated: will be removed in the future.
+func (n DefaultNetwork) ApplyGenericTo(opts *GenericProviderOptions) {
+	opts.defaultNetwork = string(n)
+}
+
+// Deprecated: will be removed in the future.
+func (n DefaultNetwork) ApplyDockerTo(opts *DockerProviderOptions) {
+	opts.defaultNetwork = string(n)
+}
+
+// Deprecated: will be removed in the future
+// NetworkRequest represents the parameters used to get a network
+type NetworkRequest struct {
+	Driver         string
+	CheckDuplicate bool // Deprecated: CheckDuplicate is deprecated since API v1.44, but it defaults to true when sent by the client package to older daemons.
+	Internal       bool
+	EnableIPv6     *bool
+	Name           string
+	Labels         map[string]string
+	Attachable     bool
+	IPAM           *network.IPAM
+
+	SkipReaper    bool              // Deprecated: The reaper is globally controlled by the .testcontainers.properties file or the TESTCONTAINERS_RYUK_DISABLED environment variable
+	ReaperImage   string            // Deprecated: use WithImageName ContainerOption instead. Alternative reaper registry
+	ReaperOptions []ContainerOption // Deprecated: the reaper is configured at the properties level, for an entire test session
+}
+
+// sessionID returns the session ID for the network request.
+func (r NetworkRequest) sessionID() string {
+	if sessionID := r.Labels[core.LabelSessionID]; sessionID != "" {
+		return sessionID
+	}
+
+	return core.SessionID()
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/options.go b/vendor/github.com/testcontainers/testcontainers-go/options.go
new file mode 100644
index 000000000..4a629cbe3
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/options.go
@@ -0,0 +1,538 @@
+package testcontainers
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"maps"
+	"path"
+	"time"
+
+	"dario.cat/mergo"
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+
+	tcexec "github.com/testcontainers/testcontainers-go/exec"
+	"github.com/testcontainers/testcontainers-go/internal/core"
+	"github.com/testcontainers/testcontainers-go/wait"
+)
+
+// ContainerCustomizer is an interface that can be used to configure the Testcontainers container
+// request. The passed request will be merged with the default one.
+type ContainerCustomizer interface {
+	Customize(req *GenericContainerRequest) error
+}
+
+// CustomizeRequestOption is a type that can be used to configure the Testcontainers container request.
+// The passed request will be merged with the default one.
+type CustomizeRequestOption func(req *GenericContainerRequest) error
+
+func (opt CustomizeRequestOption) Customize(req *GenericContainerRequest) error {
+	return opt(req)
+}
+
+// CustomizeRequest returns a function that can be used to merge the passed container request with the one that is used by the container.
+// Slices and Maps will be appended.
+func CustomizeRequest(src GenericContainerRequest) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if err := mergo.Merge(req, &src, mergo.WithOverride, mergo.WithAppendSlice); err != nil {
+			return fmt.Errorf("error merging container request, keeping the original one: %w", err)
+		}
+
+		return nil
+	}
+}
+
+// WithDockerfile allows to build a container from a Dockerfile
+func WithDockerfile(df FromDockerfile) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.FromDockerfile = df
+
+		return nil
+	}
+}
+
+// WithConfigModifier allows to override the default container config
+func WithConfigModifier(modifier func(config *container.Config)) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.ConfigModifier = modifier
+
+		return nil
+	}
+}
+
+// WithEndpointSettingsModifier allows to override the default endpoint settings
+func WithEndpointSettingsModifier(modifier func(settings map[string]*network.EndpointSettings)) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.EndpointSettingsModifier = modifier
+
+		return nil
+	}
+}
+
+// WithEnv sets the environment variables for a container.
+// If the environment variable already exists, it will be overridden.
+func WithEnv(envs map[string]string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if req.Env == nil {
+			req.Env = map[string]string{}
+		}
+
+		maps.Copy(req.Env, envs)
+
+		return nil
+	}
+}
+
+// WithHostConfigModifier allows to override the default host config
+func WithHostConfigModifier(modifier func(hostConfig *container.HostConfig)) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.HostConfigModifier = modifier
+
+		return nil
+	}
+}
+
+// WithHostPortAccess allows to expose the host ports to the container
+func WithHostPortAccess(ports ...int) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if req.HostAccessPorts == nil {
+			req.HostAccessPorts = []int{}
+		}
+
+		req.HostAccessPorts = append(req.HostAccessPorts, ports...)
+		return nil
+	}
+}
+
+// WithName will set the name of the container.
+func WithName(containerName string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if containerName == "" {
+			return errors.New("container name must be provided")
+		}
+		req.Name = containerName
+		return nil
+	}
+}
+
+// WithNoStart will prevent the container from being started after creation.
+func WithNoStart() CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.Started = false
+		return nil
+	}
+}
+
+// WithReuseByName will mark a container to be reused if it exists or create a new one if it doesn't.
+// A container name must be provided to identify the container to be reused.
+func WithReuseByName(containerName string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if err := WithName(containerName)(req); err != nil {
+			return err
+		}
+
+		req.Reuse = true
+		return nil
+	}
+}
+
+// WithImage sets the image for a container
+func WithImage(image string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.Image = image
+
+		return nil
+	}
+}
+
+// imageSubstitutor {
+
+// ImageSubstitutor represents a way to substitute container image names
+type ImageSubstitutor interface {
+	// Description returns the name of the type and a short description of how it modifies the image.
+	// Useful to be printed in logs
+	Description() string
+	Substitute(image string) (string, error)
+}
+
+// }
+
+// CustomHubSubstitutor represents a way to substitute the hub of an image with a custom one,
+// using provided value with respect to the HubImageNamePrefix configuration value.
+type CustomHubSubstitutor struct {
+	hub string
+}
+
+// NewCustomHubSubstitutor creates a new CustomHubSubstitutor
+func NewCustomHubSubstitutor(hub string) CustomHubSubstitutor {
+	return CustomHubSubstitutor{
+		hub: hub,
+	}
+}
+
+// Description returns the name of the type and a short description of how it modifies the image.
+func (c CustomHubSubstitutor) Description() string {
+	return fmt.Sprintf("CustomHubSubstitutor (replaces hub with %s)", c.hub)
+}
+
+// Substitute replaces the hub of the image with the provided one, with certain conditions:
+//   - if the hub is empty, the image is returned as is.
+//   - if the image already contains a registry, the image is returned as is.
+//   - if the HubImageNamePrefix configuration value is set, the image is returned as is.
+func (c CustomHubSubstitutor) Substitute(image string) (string, error) {
+	registry := core.ExtractRegistry(image, "")
+	cfg := ReadConfig()
+
+	exclusions := []func() bool{
+		func() bool { return c.hub == "" },
+		func() bool { return registry != "" },
+		func() bool { return cfg.Config.HubImageNamePrefix != "" },
+	}
+
+	for _, exclusion := range exclusions {
+		if exclusion() {
+			return image, nil
+		}
+	}
+
+	return path.Join(c.hub, image), nil
+}
+
+// prependHubRegistry represents a way to prepend a custom Hub registry to the image name,
+// using the HubImageNamePrefix configuration value
+type prependHubRegistry struct {
+	prefix string
+}
+
+// newPrependHubRegistry creates a new prependHubRegistry
+func newPrependHubRegistry(hubPrefix string) prependHubRegistry {
+	return prependHubRegistry{
+		prefix: hubPrefix,
+	}
+}
+
+// Description returns the name of the type and a short description of how it modifies the image.
+func (p prependHubRegistry) Description() string {
+	return fmt.Sprintf("HubImageSubstitutor (prepends %s)", p.prefix)
+}
+
+// Substitute prepends the Hub prefix to the image name, with certain conditions:
+//   - if the prefix is empty, the image is returned as is.
+//   - if the image is a non-hub image (e.g. where another registry is set), the image is returned as is.
+//   - if the image is a Docker Hub image where the hub registry is explicitly part of the name
+//     (i.e. anything with a registry.hub.docker.com host part), the image is returned as is.
+func (p prependHubRegistry) Substitute(image string) (string, error) {
+	registry := core.ExtractRegistry(image, "")
+
+	// add the exclusions in the right order
+	exclusions := []func() bool{
+		func() bool { return p.prefix == "" },                        // no prefix set at the configuration level
+		func() bool { return registry != "" },                        // non-hub image
+		func() bool { return registry == "docker.io" },               // explicitly including docker.io
+		func() bool { return registry == "registry.hub.docker.com" }, // explicitly including registry.hub.docker.com
+	}
+
+	for _, exclusion := range exclusions {
+		if exclusion() {
+			return image, nil
+		}
+	}
+
+	return path.Join(p.prefix, image), nil
+}
+
+// WithImageSubstitutors sets the image substitutors for a container
+func WithImageSubstitutors(fn ...ImageSubstitutor) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.ImageSubstitutors = fn
+
+		return nil
+	}
+}
+
+// WithLogConsumers sets the log consumers for a container
+func WithLogConsumers(consumer ...LogConsumer) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if req.LogConsumerCfg == nil {
+			req.LogConsumerCfg = &LogConsumerConfig{}
+		}
+
+		req.LogConsumerCfg.Consumers = consumer
+		return nil
+	}
+}
+
+// WithLogConsumerConfig sets the log consumer config for a container.
+// Beware that this option completely replaces the existing log consumer config,
+// including the log consumers and the log production options,
+// so it should be used with care.
+func WithLogConsumerConfig(config *LogConsumerConfig) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.LogConsumerCfg = config
+		return nil
+	}
+}
+
+// Executable represents an executable command to be sent to a container, including options,
+// as part of the different lifecycle hooks.
+type Executable interface {
+	AsCommand() []string
+	// Options can container two different types of options:
+	// - Docker's ExecConfigs (WithUser, WithWorkingDir, WithEnv, etc.)
+	// - testcontainers' ProcessOptions (i.e. Multiplexed response)
+	Options() []tcexec.ProcessOption
+}
+
+// ExecOptions is a struct that provides a default implementation for the Options method
+// of the Executable interface.
+type ExecOptions struct {
+	opts []tcexec.ProcessOption
+}
+
+func (ce ExecOptions) Options() []tcexec.ProcessOption {
+	return ce.opts
+}
+
+// RawCommand is a type that implements Executable and represents a command to be sent to a container
+type RawCommand struct {
+	ExecOptions
+	cmds []string
+}
+
+func NewRawCommand(cmds []string, opts ...tcexec.ProcessOption) RawCommand {
+	return RawCommand{
+		cmds: cmds,
+		ExecOptions: ExecOptions{
+			opts: opts,
+		},
+	}
+}
+
+// AsCommand returns the command as a slice of strings
+func (r RawCommand) AsCommand() []string {
+	return r.cmds
+}
+
+// WithStartupCommand will execute the command representation of each Executable into the container.
+// It will leverage the container lifecycle hooks to call the command right after the container
+// is started.
+func WithStartupCommand(execs ...Executable) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		startupCommandsHook := ContainerLifecycleHooks{
+			PostStarts: []ContainerHook{},
+		}
+
+		for _, exec := range execs {
+			execFn := func(ctx context.Context, c Container) error {
+				_, _, err := c.Exec(ctx, exec.AsCommand(), exec.Options()...)
+				return err
+			}
+
+			startupCommandsHook.PostStarts = append(startupCommandsHook.PostStarts, execFn)
+		}
+
+		req.LifecycleHooks = append(req.LifecycleHooks, startupCommandsHook)
+
+		return nil
+	}
+}
+
+// WithAfterReadyCommand will execute the command representation of each Executable into the container.
+// It will leverage the container lifecycle hooks to call the command right after the container
+// is ready.
+func WithAfterReadyCommand(execs ...Executable) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		postReadiesHook := make([]ContainerHook, 0, len(execs))
+
+		for _, exec := range execs {
+			execFn := func(ctx context.Context, c Container) error {
+				_, _, err := c.Exec(ctx, exec.AsCommand(), exec.Options()...)
+				return err
+			}
+
+			postReadiesHook = append(postReadiesHook, execFn)
+		}
+
+		req.LifecycleHooks = append(req.LifecycleHooks, ContainerLifecycleHooks{
+			PostReadies: postReadiesHook,
+		})
+
+		return nil
+	}
+}
+
+// WithWaitStrategy replaces the wait strategy for a container, using 60 seconds as deadline
+func WithWaitStrategy(strategies ...wait.Strategy) CustomizeRequestOption {
+	return WithWaitStrategyAndDeadline(60*time.Second, strategies...)
+}
+
+// WithAdditionalWaitStrategy appends the wait strategy for a container, using 60 seconds as deadline
+func WithAdditionalWaitStrategy(strategies ...wait.Strategy) CustomizeRequestOption {
+	return WithAdditionalWaitStrategyAndDeadline(60*time.Second, strategies...)
+}
+
+// WithWaitStrategyAndDeadline replaces the wait strategy for a container, including deadline
+func WithWaitStrategyAndDeadline(deadline time.Duration, strategies ...wait.Strategy) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.WaitingFor = wait.ForAll(strategies...).WithDeadline(deadline)
+
+		return nil
+	}
+}
+
+// WithAdditionalWaitStrategyAndDeadline appends the wait strategy for a container, including deadline
+func WithAdditionalWaitStrategyAndDeadline(deadline time.Duration, strategies ...wait.Strategy) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if req.WaitingFor == nil {
+			req.WaitingFor = wait.ForAll(strategies...).WithDeadline(deadline)
+			return nil
+		}
+
+		wss := make([]wait.Strategy, 0, len(strategies)+1)
+		wss = append(wss, req.WaitingFor)
+		wss = append(wss, strategies...)
+
+		req.WaitingFor = wait.ForAll(wss...).WithDeadline(deadline)
+
+		return nil
+	}
+}
+
+// WithImageMount mounts an image to a container, passing the source image name,
+// the relative subpath to mount in that image, and the mount point in the target container.
+// This option validates that the subpath is a relative path, raising an error otherwise.
+func WithImageMount(source string, subpath string, target ContainerMountTarget) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		src := NewDockerImageMountSource(source, subpath)
+
+		if err := src.Validate(); err != nil {
+			return fmt.Errorf("validate image mount source: %w", err)
+		}
+
+		req.Mounts = append(req.Mounts, ContainerMount{
+			Source: src,
+			Target: target,
+		})
+		return nil
+	}
+}
+
+// WithAlwaysPull will pull the image before starting the container
+func WithAlwaysPull() CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.AlwaysPullImage = true
+		return nil
+	}
+}
+
+// WithImagePlatform sets the platform for a container
+func WithImagePlatform(platform string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.ImagePlatform = platform
+		return nil
+	}
+}
+
+// WithEntrypoint completely replaces the entrypoint of a container
+func WithEntrypoint(entrypoint ...string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.Entrypoint = entrypoint
+		return nil
+	}
+}
+
+// WithEntrypointArgs appends the entrypoint arguments to the entrypoint of a container
+func WithEntrypointArgs(entrypointArgs ...string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.Entrypoint = append(req.Entrypoint, entrypointArgs...)
+		return nil
+	}
+}
+
+// WithExposedPorts appends the ports to the exposed ports for a container
+func WithExposedPorts(ports ...string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.ExposedPorts = append(req.ExposedPorts, ports...)
+		return nil
+	}
+}
+
+// WithCmd completely replaces the command for a container
+func WithCmd(cmd ...string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.Cmd = cmd
+		return nil
+	}
+}
+
+// WithCmdArgs appends the command arguments to the command for a container
+func WithCmdArgs(cmdArgs ...string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.Cmd = append(req.Cmd, cmdArgs...)
+		return nil
+	}
+}
+
+// WithLabels appends the labels to the labels for a container
+func WithLabels(labels map[string]string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if req.Labels == nil {
+			req.Labels = make(map[string]string)
+		}
+		maps.Copy(req.Labels, labels)
+		return nil
+	}
+}
+
+// WithLifecycleHooks completely replaces the lifecycle hooks for a container
+func WithLifecycleHooks(hooks ...ContainerLifecycleHooks) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.LifecycleHooks = hooks
+		return nil
+	}
+}
+
+// WithAdditionalLifecycleHooks appends lifecycle hooks to the existing ones for a container
+func WithAdditionalLifecycleHooks(hooks ...ContainerLifecycleHooks) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.LifecycleHooks = append(req.LifecycleHooks, hooks...)
+		return nil
+	}
+}
+
+// WithMounts appends the mounts to the mounts for a container
+func WithMounts(mounts ...ContainerMount) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.Mounts = append(req.Mounts, mounts...)
+		return nil
+	}
+}
+
+// WithTmpfs appends the tmpfs mounts to the tmpfs mounts for a container
+func WithTmpfs(tmpfs map[string]string) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		if req.Tmpfs == nil {
+			req.Tmpfs = make(map[string]string)
+		}
+		maps.Copy(req.Tmpfs, tmpfs)
+		return nil
+	}
+}
+
+// WithFiles appends the files to the files for a container
+func WithFiles(files ...ContainerFile) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.Files = append(req.Files, files...)
+		return nil
+	}
+}
+
+// WithProvider sets the provider type for a container
+func WithProvider(provider ProviderType) CustomizeRequestOption {
+	return func(req *GenericContainerRequest) error {
+		req.ProviderType = provider
+
+		return nil
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/parallel.go b/vendor/github.com/testcontainers/testcontainers-go/parallel.go
new file mode 100644
index 000000000..a75d011f9
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/parallel.go
@@ -0,0 +1,107 @@
+package testcontainers
+
+import (
+	"context"
+	"fmt"
+	"sync"
+)
+
+const (
+	defaultWorkersCount = 8
+)
+
+type ParallelContainerRequest []GenericContainerRequest
+
+// ParallelContainersOptions represents additional options for parallel running
+type ParallelContainersOptions struct {
+	WorkersCount int // count of parallel workers. If field empty(zero), default value will be 'defaultWorkersCount'
+}
+
+// ParallelContainersRequestError represents error from parallel request
+type ParallelContainersRequestError struct {
+	Request GenericContainerRequest
+	Error   error
+}
+
+type ParallelContainersError struct {
+	Errors []ParallelContainersRequestError
+}
+
+func (gpe ParallelContainersError) Error() string {
+	return fmt.Sprintf("%v", gpe.Errors)
+}
+
+// parallelContainersResult represents result.
+type parallelContainersResult struct {
+	ParallelContainersRequestError
+	Container Container
+}
+
+func parallelContainersRunner(
+	ctx context.Context,
+	requests <-chan GenericContainerRequest,
+	results chan<- parallelContainersResult,
+	wg *sync.WaitGroup,
+) {
+	defer wg.Done()
+	for req := range requests {
+		c, err := GenericContainer(ctx, req)
+		res := parallelContainersResult{Container: c}
+		if err != nil {
+			res.Request = req
+			res.Error = err
+		}
+		results <- res
+	}
+}
+
+// ParallelContainers creates a generic containers with parameters and run it in parallel mode
+func ParallelContainers(ctx context.Context, reqs ParallelContainerRequest, opt ParallelContainersOptions) ([]Container, error) {
+	if opt.WorkersCount == 0 {
+		opt.WorkersCount = defaultWorkersCount
+	}
+
+	tasksChanSize := min(opt.WorkersCount, len(reqs))
+
+	tasksChan := make(chan GenericContainerRequest, tasksChanSize)
+	resultsChan := make(chan parallelContainersResult, tasksChanSize)
+	done := make(chan struct{})
+
+	var wg sync.WaitGroup
+	wg.Add(tasksChanSize)
+
+	// run workers
+	for range tasksChanSize {
+		go parallelContainersRunner(ctx, tasksChan, resultsChan, &wg)
+	}
+
+	var errs []ParallelContainersRequestError
+	containers := make([]Container, 0, len(reqs))
+	go func() {
+		defer close(done)
+		for res := range resultsChan {
+			if res.Error != nil {
+				errs = append(errs, res.ParallelContainersRequestError)
+			} else {
+				containers = append(containers, res.Container)
+			}
+		}
+	}()
+
+	for _, req := range reqs {
+		tasksChan <- req
+	}
+	close(tasksChan)
+
+	wg.Wait()
+
+	close(resultsChan)
+
+	<-done
+
+	if len(errs) != 0 {
+		return containers, ParallelContainersError{Errors: errs}
+	}
+
+	return containers, nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/port_forwarding.go b/vendor/github.com/testcontainers/testcontainers-go/port_forwarding.go
new file mode 100644
index 000000000..e4639e3a4
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/port_forwarding.go
@@ -0,0 +1,413 @@
+package testcontainers
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"slices"
+	"sync"
+	"time"
+
+	"github.com/google/uuid"
+	"github.com/moby/moby/api/types/container"
+	"golang.org/x/crypto/ssh"
+
+	"github.com/testcontainers/testcontainers-go/internal/core/network"
+	"github.com/testcontainers/testcontainers-go/wait"
+)
+
+const (
+	// hubSshdImage {
+	sshdImage string = "testcontainers/sshd:1.4.0"
+	// }
+
+	// HostInternal is the internal hostname used to reach the host from the container,
+	// using the SSHD container as a bridge.
+	HostInternal string = "host.testcontainers.internal"
+	user         string = "root"
+	sshPort             = "22/tcp"
+)
+
+// sshPassword is a random password generated for the SSHD container.
+var sshPassword = uuid.NewString()
+
+// exposeHostPorts performs all the necessary steps to expose the host ports to the container, leveraging
+// the SSHD container to create the tunnel, and the container lifecycle hooks to manage the tunnel lifecycle.
+// At least one port must be provided to expose.
+// The steps are:
+// 1. Create a new SSHD container.
+// 2. Expose the host ports to the container after the container is ready.
+// 3. Close the SSH sessions before killing the container.
+func exposeHostPorts(ctx context.Context, req *ContainerRequest, ports ...int) (sshdConnectHook ContainerLifecycleHooks, err error) {
+	if len(ports) == 0 {
+		return sshdConnectHook, errors.New("no ports to expose")
+	}
+
+	// Use the first network of the container to connect to the SSHD container.
+	var sshdFirstNetwork string
+	if len(req.Networks) > 0 {
+		sshdFirstNetwork = req.Networks[0]
+	}
+
+	if sshdFirstNetwork == "bridge" && len(req.Networks) > 1 {
+		sshdFirstNetwork = req.Networks[1]
+	}
+
+	opts := []ContainerCustomizer{}
+	if len(req.Networks) > 0 {
+		// get the first network of the container to connect the SSHD container to it.
+		nw, err := network.GetByName(ctx, sshdFirstNetwork)
+		if err != nil {
+			return sshdConnectHook, fmt.Errorf("get network %q: %w", sshdFirstNetwork, err)
+		}
+
+		dockerNw := DockerNetwork{
+			ID:   nw.ID,
+			Name: nw.Name,
+		}
+
+		// WithNetwork reuses an already existing network, attaching the container to it.
+		// Finally it sets the network alias on that network to the given alias.
+		// TODO: Using an anonymous function to avoid cyclic dependencies with the network package.
+		withNetwork := func(aliases []string, nw *DockerNetwork) CustomizeRequestOption {
+			return func(req *GenericContainerRequest) error {
+				networkName := nw.Name
+
+				// attaching to the network because it was created with success or it already existed.
+				req.Networks = append(req.Networks, networkName)
+
+				if req.NetworkAliases == nil {
+					req.NetworkAliases = make(map[string][]string)
+				}
+				req.NetworkAliases[networkName] = aliases
+				return nil
+			}
+		}
+
+		opts = append(opts, withNetwork([]string{HostInternal}, &dockerNw))
+	}
+
+	// start the SSHD container with the provided options
+	sshdContainer, err := newSshdContainer(ctx, opts...)
+	// Ensure the SSHD container is stopped and removed in case of error.
+	defer func() {
+		if err != nil {
+			err = errors.Join(err, TerminateContainer(sshdContainer))
+		}
+	}()
+	if err != nil {
+		return sshdConnectHook, fmt.Errorf("new sshd container: %w", err)
+	}
+
+	// IP in the first network of the container.
+	inspect, err := sshdContainer.Inspect(ctx)
+	if err != nil {
+		return sshdConnectHook, fmt.Errorf("inspect sshd container: %w", err)
+	}
+
+	var sshdIP string
+	single := len(inspect.NetworkSettings.Networks) == 1
+	for name, nw := range inspect.NetworkSettings.Networks {
+		if name == sshdFirstNetwork || single {
+			if nw.IPAddress.IsValid() {
+				sshdIP = nw.IPAddress.String()
+				break
+			}
+		}
+	}
+
+	if sshdIP == "" {
+		return sshdConnectHook, errors.New("sshd container IP not found")
+	}
+
+	if req.HostConfigModifier == nil {
+		req.HostConfigModifier = func(_ *container.HostConfig) {}
+	}
+
+	// do not override the original HostConfigModifier
+	originalHCM := req.HostConfigModifier
+	req.HostConfigModifier = func(hostConfig *container.HostConfig) {
+		// adding the host internal alias to the container as an extra host
+		// to allow the container to reach the SSHD container.
+		hostConfig.ExtraHosts = append(hostConfig.ExtraHosts, fmt.Sprintf("%s:%s", HostInternal, sshdIP))
+
+		modes := []container.NetworkMode{container.NetworkMode(sshdFirstNetwork), "none", "host"}
+		// if the container is not in one of the modes, attach it to the first network of the SSHD container
+		found := slices.Contains(modes, hostConfig.NetworkMode)
+		if !found {
+			req.Networks = append(req.Networks, sshdFirstNetwork)
+		}
+
+		// invoke the original HostConfigModifier with the updated hostConfig
+		originalHCM(hostConfig)
+	}
+
+	stopHooks := []ContainerHook{
+		func(ctx context.Context, _ Container) error {
+			if ctx.Err() != nil {
+				// Context already canceled, need to create a new one to ensure
+				// the SSH session is closed.
+				var cancel context.CancelFunc
+				ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
+				defer cancel()
+			}
+
+			return TerminateContainer(sshdContainer, StopContext(ctx))
+		},
+	}
+
+	// after the container is ready, create the SSH tunnel
+	// for each exposed port from the host.
+	sshdConnectHook = ContainerLifecycleHooks{
+		PostReadies: []ContainerHook{
+			func(ctx context.Context, _ Container) error {
+				return sshdContainer.exposeHostPort(ctx, req.HostAccessPorts...)
+			},
+		},
+		PostStops:     stopHooks,
+		PreTerminates: stopHooks,
+	}
+
+	return sshdConnectHook, nil
+}
+
+// newSshdContainer creates a new SSHD container with the provided options.
+func newSshdContainer(ctx context.Context, opts ...ContainerCustomizer) (*sshdContainer, error) {
+	moduleOpts := make([]ContainerCustomizer, 0, 3+len(opts))
+	moduleOpts = append(moduleOpts,
+		WithExposedPorts(sshPort),
+		WithEnv(map[string]string{"PASSWORD": sshPassword}),
+		WithWaitStrategy(wait.ForListeningPort(sshPort)),
+	)
+	moduleOpts = append(moduleOpts, opts...)
+
+	c, err := Run(ctx, sshdImage, moduleOpts...)
+	var sshd *sshdContainer
+	if c != nil {
+		sshd = &sshdContainer{Container: c}
+	}
+
+	if err != nil {
+		return sshd, fmt.Errorf("run sshd container: %w", err)
+	}
+
+	if err = sshd.clientConfig(ctx); err != nil {
+		// Return the container and the error to the caller to handle it.
+		return sshd, err
+	}
+
+	return sshd, nil
+}
+
+// sshdContainer represents the SSHD container type used for the port forwarding container.
+// It's an internal type that extends the DockerContainer type, to add the SSH tunnelling capabilities.
+type sshdContainer struct {
+	Container
+	port           string
+	sshConfig      *ssh.ClientConfig
+	portForwarders []*portForwarder
+}
+
+// Terminate stops the container and closes the SSH session
+func (sshdC *sshdContainer) Terminate(ctx context.Context, opts ...TerminateOption) error {
+	return errors.Join(
+		sshdC.closePorts(),
+		sshdC.Container.Terminate(ctx, opts...),
+	)
+}
+
+// Stop stops the container and closes the SSH session
+func (sshdC *sshdContainer) Stop(ctx context.Context, timeout *time.Duration) error {
+	return errors.Join(
+		sshdC.closePorts(),
+		sshdC.Container.Stop(ctx, timeout),
+	)
+}
+
+// closePorts closes all port forwarders.
+func (sshdC *sshdContainer) closePorts() error {
+	var errs []error
+	for _, pfw := range sshdC.portForwarders {
+		if err := pfw.Close(); err != nil {
+			errs = append(errs, err)
+		}
+	}
+	sshdC.portForwarders = nil // Ensure the port forwarders are not used after closing.
+	return errors.Join(errs...)
+}
+
+// clientConfig sets up the SSHD client configuration.
+func (sshdC *sshdContainer) clientConfig(ctx context.Context) error {
+	mappedPort, err := sshdC.MappedPort(ctx, sshPort)
+	if err != nil {
+		return fmt.Errorf("mapped port: %w", err)
+	}
+
+	sshdC.port = mappedPort.Port()
+	sshdC.sshConfig = &ssh.ClientConfig{
+		User:            user,
+		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+		Auth:            []ssh.AuthMethod{ssh.Password(sshPassword)},
+	}
+
+	return nil
+}
+
+// exposeHostPort exposes the host ports to the container.
+func (sshdC *sshdContainer) exposeHostPort(ctx context.Context, ports ...int) (err error) {
+	defer func() {
+		if err != nil {
+			err = errors.Join(err, sshdC.closePorts())
+		}
+	}()
+	for _, port := range ports {
+		pf, err := newPortForwarder(ctx, "localhost:"+sshdC.port, sshdC.sshConfig, port)
+		if err != nil {
+			return fmt.Errorf("new port forwarder: %w", err)
+		}
+
+		sshdC.portForwarders = append(sshdC.portForwarders, pf)
+	}
+
+	return nil
+}
+
+// portForwarder forwards a port from the container to the host.
+type portForwarder struct {
+	client      *ssh.Client
+	listener    net.Listener
+	dialTimeout time.Duration
+	localAddr   string
+	ctx         context.Context
+	cancel      context.CancelFunc
+
+	// closeMtx protects the close operation
+	closeMtx sync.Mutex
+	closeErr error
+}
+
+// newPortForwarder creates a new running portForwarder for the given port.
+// The context is only used for the initial SSH connection.
+func newPortForwarder(ctx context.Context, sshDAddr string, sshConfig *ssh.ClientConfig, port int) (pf *portForwarder, err error) {
+	var d net.Dialer
+	conn, err := d.DialContext(ctx, "tcp", sshDAddr)
+	if err != nil {
+		return nil, fmt.Errorf("ssh dial: %w", err)
+	}
+
+	// Ensure the connection is closed in case of error.
+	defer func() {
+		if err != nil {
+			err = errors.Join(err, conn.Close())
+		}
+	}()
+
+	c, chans, reqs, err := ssh.NewClientConn(conn, sshDAddr, sshConfig)
+	if err != nil {
+		return nil, fmt.Errorf("ssh new client conn: %w", err)
+	}
+
+	client := ssh.NewClient(c, chans, reqs)
+
+	listener, err := client.Listen("tcp", fmt.Sprintf("localhost:%d", port))
+	if err != nil {
+		return nil, fmt.Errorf("listening on remote port %d: %w", port, err)
+	}
+
+	ctx, cancel := context.WithCancel(context.Background())
+
+	pf = &portForwarder{
+		client:      client,
+		listener:    listener,
+		localAddr:   fmt.Sprintf("localhost:%d", port),
+		ctx:         ctx,
+		cancel:      cancel,
+		dialTimeout: time.Second * 2,
+	}
+
+	go pf.run()
+
+	return pf, nil
+}
+
+// Close closes the port forwarder.
+func (pf *portForwarder) Close() error {
+	pf.closeMtx.Lock()
+	defer pf.closeMtx.Unlock()
+
+	select {
+	case <-pf.ctx.Done():
+		// Already closed.
+		return pf.closeErr
+	default:
+	}
+
+	var errs []error
+	if err := pf.listener.Close(); err != nil {
+		errs = append(errs, fmt.Errorf("close listener: %w", err))
+	}
+	if err := pf.client.Close(); err != nil {
+		errs = append(errs, fmt.Errorf("close client: %w", err))
+	}
+
+	pf.closeErr = errors.Join(errs...)
+	pf.cancel()
+
+	return pf.closeErr
+}
+
+// run forwards the port from the remote connection to the local connection.
+func (pf *portForwarder) run() {
+	for {
+		remote, err := pf.listener.Accept()
+		if err != nil {
+			if errors.Is(err, io.EOF) {
+				// The listener has been closed.
+				return
+			}
+
+			// Ignore errors as they are transient and we want requests to
+			// continue to be accepted.
+			continue
+		}
+
+		go pf.tunnel(remote)
+	}
+}
+
+// tunnel runs a tunnel between two connections; as soon as the forwarder
+// context is cancelled or one connection copies returns, irrespective of
+// the error, both connections are closed.
+func (pf *portForwarder) tunnel(remote net.Conn) {
+	defer remote.Close()
+
+	ctx, cancel := context.WithTimeout(pf.ctx, pf.dialTimeout)
+	defer cancel()
+
+	var dialer net.Dialer
+	local, err := dialer.DialContext(ctx, "tcp", pf.localAddr)
+	if err != nil {
+		// Nothing we can do with the error.
+		return
+	}
+	defer local.Close()
+
+	ctx, cancel = context.WithCancel(pf.ctx)
+
+	go func() {
+		defer cancel()
+		io.Copy(local, remote) //nolint:errcheck // Nothing useful we can do with the error.
+	}()
+
+	go func() {
+		defer cancel()
+		io.Copy(remote, local) //nolint:errcheck // Nothing useful we can do with the error.
+	}()
+
+	// Wait for the context to be done before returning which triggers
+	// both connections to close. This is done to prevent the copies
+	// blocking forever on unused connections.
+	<-ctx.Done()
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/provider.go b/vendor/github.com/testcontainers/testcontainers-go/provider.go
new file mode 100644
index 000000000..210f451fc
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/provider.go
@@ -0,0 +1,158 @@
+package testcontainers
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/testcontainers/testcontainers-go/internal/config"
+	"github.com/testcontainers/testcontainers-go/internal/core"
+	"github.com/testcontainers/testcontainers-go/log"
+)
+
+// possible provider types
+const (
+	ProviderDefault ProviderType = iota // default will auto-detect provider from DOCKER_HOST environment variable
+	ProviderDocker
+	ProviderPodman
+)
+
+type (
+	// ProviderType is an enum for the possible providers
+	ProviderType int
+
+	// GenericProviderOptions defines options applicable to all providers
+	GenericProviderOptions struct {
+		Logger         log.Logger
+		defaultNetwork string
+	}
+
+	// GenericProviderOption defines a common interface to modify GenericProviderOptions
+	// These options can be passed to GetProvider in a variadic way to customize the returned GenericProvider instance
+	GenericProviderOption interface {
+		ApplyGenericTo(opts *GenericProviderOptions)
+	}
+
+	// GenericProviderOptionFunc is a shorthand to implement the GenericProviderOption interface
+	GenericProviderOptionFunc func(opts *GenericProviderOptions)
+
+	// DockerProviderOptions defines options applicable to DockerProvider
+	DockerProviderOptions struct {
+		defaultBridgeNetworkName string
+		*GenericProviderOptions
+	}
+
+	// DockerProviderOption defines a common interface to modify DockerProviderOptions
+	// These can be passed to NewDockerProvider in a variadic way to customize the returned DockerProvider instance
+	DockerProviderOption interface {
+		ApplyDockerTo(opts *DockerProviderOptions)
+	}
+
+	// DockerProviderOptionFunc is a shorthand to implement the DockerProviderOption interface
+	DockerProviderOptionFunc func(opts *DockerProviderOptions)
+)
+
+func (f DockerProviderOptionFunc) ApplyDockerTo(opts *DockerProviderOptions) {
+	f(opts)
+}
+
+func Generic2DockerOptions(opts ...GenericProviderOption) []DockerProviderOption {
+	converted := make([]DockerProviderOption, 0, len(opts))
+	for _, o := range opts {
+		switch c := o.(type) {
+		case DockerProviderOption:
+			converted = append(converted, c)
+		default:
+			converted = append(converted, DockerProviderOptionFunc(func(opts *DockerProviderOptions) {
+				o.ApplyGenericTo(opts.GenericProviderOptions)
+			}))
+		}
+	}
+
+	return converted
+}
+
+func WithDefaultBridgeNetwork(bridgeNetworkName string) DockerProviderOption {
+	return DockerProviderOptionFunc(func(opts *DockerProviderOptions) {
+		opts.defaultBridgeNetworkName = bridgeNetworkName
+	})
+}
+
+func (f GenericProviderOptionFunc) ApplyGenericTo(opts *GenericProviderOptions) {
+	f(opts)
+}
+
+// ContainerProvider allows the creation of containers on an arbitrary system
+type ContainerProvider interface {
+	Close() error                                                                // close the provider
+	CreateContainer(context.Context, ContainerRequest) (Container, error)        // create a container without starting it
+	ReuseOrCreateContainer(context.Context, ContainerRequest) (Container, error) // reuses a container if it exists or creates a container without starting
+	RunContainer(context.Context, ContainerRequest) (Container, error)           // create a container and start it
+	Health(context.Context) error
+	Config() TestcontainersConfig
+}
+
+// GetProvider provides the provider implementation for a certain type
+func (t ProviderType) GetProvider(opts ...GenericProviderOption) (GenericProvider, error) {
+	opt := &GenericProviderOptions{
+		Logger: log.Default(),
+	}
+
+	for _, o := range opts {
+		o.ApplyGenericTo(opt)
+	}
+
+	pt := t
+	if pt == ProviderDefault && strings.Contains(os.Getenv("DOCKER_HOST"), "podman.sock") {
+		pt = ProviderPodman
+	}
+
+	switch pt {
+	case ProviderDefault, ProviderDocker:
+		providerOptions := append(Generic2DockerOptions(opts...), WithDefaultBridgeNetwork(Bridge))
+		provider, err := NewDockerProvider(providerOptions...)
+		if err != nil {
+			return nil, fmt.Errorf("%w, failed to create Docker provider", err)
+		}
+		return provider, nil
+	case ProviderPodman:
+		providerOptions := append(Generic2DockerOptions(opts...), WithDefaultBridgeNetwork(Podman))
+		provider, err := NewDockerProvider(providerOptions...)
+		if err != nil {
+			return nil, fmt.Errorf("%w, failed to create Docker provider", err)
+		}
+		return provider, nil
+	}
+	return nil, errors.New("unknown provider")
+}
+
+// NewDockerProvider creates a Docker provider with the EnvClient
+func NewDockerProvider(provOpts ...DockerProviderOption) (*DockerProvider, error) {
+	o := &DockerProviderOptions{
+		GenericProviderOptions: &GenericProviderOptions{
+			Logger: log.Default(),
+		},
+	}
+
+	for idx := range provOpts {
+		provOpts[idx].ApplyDockerTo(o)
+	}
+
+	ctx := context.Background()
+	host, err := core.ExtractDockerHost(ctx)
+	if err != nil {
+		return nil, err
+	}
+	c, err := NewDockerClientWithOpts(ctx)
+	if err != nil {
+		return nil, err
+	}
+	return &DockerProvider{
+		DockerProviderOptions: o,
+		client:                c,
+		host:                  host,
+		config:                config.Read(),
+	}, nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/reaper.go b/vendor/github.com/testcontainers/testcontainers-go/reaper.go
new file mode 100644
index 000000000..776529d05
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/reaper.go
@@ -0,0 +1,591 @@
+package testcontainers
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+
+	"github.com/cenkalti/backoff/v4"
+	"github.com/containerd/errdefs"
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+	"github.com/moby/moby/client"
+
+	"github.com/testcontainers/testcontainers-go/internal/config"
+	"github.com/testcontainers/testcontainers-go/internal/core"
+	"github.com/testcontainers/testcontainers-go/log"
+	"github.com/testcontainers/testcontainers-go/wait"
+)
+
+const (
+	// Deprecated: it has been replaced by the internal core.LabelLang
+	TestcontainerLabel = "org.testcontainers.golang"
+	// Deprecated: it has been replaced by the internal core.LabelSessionID
+	TestcontainerLabelSessionID = TestcontainerLabel + ".sessionId"
+	// Deprecated: it has been replaced by the internal core.LabelReaper
+	TestcontainerLabelIsReaper = TestcontainerLabel + ".reaper"
+)
+
+var (
+	// Deprecated: it has been replaced by an internal value
+	ReaperDefaultImage = config.ReaperDefaultImage
+
+	// defaultReaperPort is the default port that the reaper listens on if not
+	// overridden by the RYUK_PORT environment variable.
+	defaultReaperPort = network.MustParsePort("8080/tcp")
+
+	// errReaperNotFound is returned when no reaper container is found.
+	errReaperNotFound = errors.New("reaper not found")
+
+	// errReaperDisabled is returned if a reaper is requested but the
+	// config has it disabled.
+	errReaperDisabled = errors.New("reaper disabled")
+
+	// spawner is the singleton instance of reaperSpawner.
+	spawner = &reaperSpawner{}
+
+	// reaperAck is the expected response from the reaper container.
+	reaperAck = []byte("ACK\n")
+)
+
+// ReaperProvider represents a provider for the reaper to run itself with
+// The ContainerProvider interface should usually satisfy this as well, so it is pluggable
+type ReaperProvider interface {
+	RunContainer(ctx context.Context, req ContainerRequest) (Container, error)
+	Config() TestcontainersConfig
+}
+
+// Deprecated: it's not possible to create a reaper any more. Compose module uses this method
+// to create a reaper for the compose stack.
+//
+// # NewReaper creates a Reaper with a sessionID to identify containers and a provider to use
+//
+// The caller must call Connect at least once on the returned Reaper and use the returned
+// result otherwise the reaper will be kept open until the process exits.
+func NewReaper(ctx context.Context, sessionID string, provider ReaperProvider, _ string) (*Reaper, error) {
+	reaper, err := spawner.reaper(ctx, sessionID, provider)
+	if err != nil {
+		return nil, fmt.Errorf("reaper: %w", err)
+	}
+
+	return reaper, nil
+}
+
+// reaperContainerNameFromSessionID returns the container name that uniquely
+// identifies the container based on the session id.
+func reaperContainerNameFromSessionID(sessionID string) string {
+	// The session id is 64 characters, so we will not hit the limit of 128
+	// characters for container names.
+	return "reaper_" + sessionID
+}
+
+// reaperSpawner is a singleton that manages the reaper container.
+type reaperSpawner struct {
+	instance *Reaper
+	mtx      sync.Mutex
+}
+
+// port returns the port that a new reaper should listen on.
+func (r *reaperSpawner) port() network.Port {
+	if port := os.Getenv("RYUK_PORT"); port != "" {
+		natPort, err := network.ParsePort(port + "/tcp")
+		if err != nil {
+			panic(fmt.Sprintf("invalid RYUK_PORT value %q: %s", port, err))
+		}
+		return natPort
+	}
+
+	return defaultReaperPort
+}
+
+// backoff returns a backoff policy for the reaper spawner.
+// It will take at most 20 seconds, doing each attempt every 100ms - 250ms.
+func (r *reaperSpawner) backoff() *backoff.ExponentialBackOff {
+	// We want random intervals between 100ms and 250ms for concurrent executions
+	// to not be synchronized: it could be the case that multiple executions of this
+	// function happen at the same time (specifically when called from a different test
+	// process execution), and we want to avoid that they all try to find the reaper
+	// container at the same time.
+	b := &backoff.ExponentialBackOff{
+		InitialInterval:     time.Millisecond * 100,
+		RandomizationFactor: backoff.DefaultRandomizationFactor,
+		Multiplier:          backoff.DefaultMultiplier,
+		// Adjust MaxInterval to compensate for randomization factor which can be added to
+		// returned interval so we have a maximum of 250ms.
+		MaxInterval:    time.Duration(float64(time.Millisecond*250) * backoff.DefaultRandomizationFactor),
+		MaxElapsedTime: time.Second * 20,
+		Stop:           backoff.Stop,
+		Clock:          backoff.SystemClock,
+	}
+	b.Reset()
+
+	return b
+}
+
+// cleanup terminates the reaper container if set.
+func (r *reaperSpawner) cleanup() error {
+	r.mtx.Lock()
+	defer r.mtx.Unlock()
+
+	return r.cleanupLocked()
+}
+
+// cleanupLocked terminates the reaper container if set.
+// It must be called with the lock held.
+func (r *reaperSpawner) cleanupLocked() error {
+	if r.instance == nil {
+		return nil
+	}
+
+	err := TerminateContainer(r.instance.container)
+	r.instance = nil
+
+	return err
+}
+
+// lookupContainer returns a DockerContainer type with the reaper container in the case
+// it's found in the running state, and including the labels for sessionID, reaper, and ryuk.
+// It will perform a retry with exponential backoff to allow for the container to be started and
+// avoid potential false negatives.
+func (r *reaperSpawner) lookupContainer(ctx context.Context, sessionID string) (*DockerContainer, error) {
+	dockerClient, err := NewDockerClientWithOpts(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("new client: %w", err)
+	}
+	defer dockerClient.Close()
+
+	provider, err := NewDockerProvider()
+	if err != nil {
+		return nil, fmt.Errorf("new provider: %w", err)
+	}
+
+	provider.SetClient(dockerClient)
+
+	opts := client.ContainerListOptions{
+		All: true,
+		Filters: make(client.Filters).
+			Add("label", fmt.Sprintf("%s=%s", core.LabelSessionID, sessionID)).
+			Add("label", fmt.Sprintf("%s=%t", core.LabelReaper, true)).
+			Add("label", fmt.Sprintf("%s=%t", core.LabelRyuk, true)).
+			Add("name", reaperContainerNameFromSessionID(sessionID)),
+	}
+
+	return backoff.RetryWithData(
+		func() (*DockerContainer, error) {
+			resp, err := dockerClient.ContainerList(ctx, opts)
+			if err != nil {
+				return nil, fmt.Errorf("container list: %w", err)
+			}
+
+			if len(resp.Items) == 0 {
+				// No reaper container not found.
+				return nil, backoff.Permanent(errReaperNotFound)
+			}
+
+			if len(resp.Items) > 1 {
+				return nil, fmt.Errorf("found %d reaper containers for session ID %q", len(resp.Items), sessionID)
+			}
+
+			r, err := provider.ContainerFromType(ctx, resp.Items[0])
+			if err != nil {
+				return nil, fmt.Errorf("from docker: %w", err)
+			}
+
+			switch r.healthStatus {
+			case "", container.Healthy, container.NoHealthcheck:
+				return r, nil
+			default:
+				return nil, fmt.Errorf("container not healthy: %s", r.healthStatus)
+			}
+		},
+		backoff.WithContext(r.backoff(), ctx),
+	)
+}
+
+// isRunning returns an error if the container is not running.
+func (r *reaperSpawner) isRunning(ctx context.Context, ctr Container) error {
+	state, err := ctr.State(ctx)
+	if err != nil {
+		return fmt.Errorf("container state: %w", err)
+	}
+
+	if !state.Running {
+		// Use NotFound error to indicate the container is not running
+		// and should be recreated.
+		return errdefs.ErrNotFound.WithMessage("container state: " + string(state.Status))
+	}
+
+	return nil
+}
+
+// retryError returns a permanent error if the error is not considered retryable.
+func (r *reaperSpawner) retryError(err error) error {
+	var timeout interface {
+		Timeout() bool
+	}
+	switch {
+	case isCleanupSafe(err),
+		createContainerFailDueToNameConflictRegex.MatchString(err.Error()),
+		errors.Is(err, syscall.ECONNREFUSED),
+		errors.Is(err, syscall.ECONNRESET),
+		errors.Is(err, syscall.ECONNABORTED),
+		errors.Is(err, syscall.ETIMEDOUT),
+		errors.Is(err, os.ErrDeadlineExceeded),
+		errors.As(err, &timeout) && timeout.Timeout(),
+		errors.Is(err, context.DeadlineExceeded),
+		errors.Is(err, context.Canceled):
+		// Retryable error.
+		return err
+	default:
+		return backoff.Permanent(err)
+	}
+}
+
+// reaper returns an existing Reaper instance if it exists and is running, otherwise
+// a new Reaper instance will be created with a sessionID to identify containers in
+// the same test session/program. If connect is true, the reaper will be connected
+// to the reaper container.
+// Returns an error if config.RyukDisabled is true.
+//
+// Safe for concurrent calls.
+func (r *reaperSpawner) reaper(ctx context.Context, sessionID string, provider ReaperProvider) (*Reaper, error) {
+	if config.Read().RyukDisabled {
+		return nil, errReaperDisabled
+	}
+
+	r.mtx.Lock()
+	defer r.mtx.Unlock()
+
+	return backoff.RetryWithData(
+		r.retryLocked(ctx, sessionID, provider),
+		backoff.WithContext(r.backoff(), ctx),
+	)
+}
+
+// retryLocked returns a function that can be used to create or reuse a reaper container.
+// If connect is true, the reaper will be connected to the reaper container.
+// It must be called with the lock held.
+func (r *reaperSpawner) retryLocked(ctx context.Context, sessionID string, provider ReaperProvider) func() (*Reaper, error) {
+	return func() (reaper *Reaper, err error) {
+		reaper, err = r.reuseOrCreate(ctx, sessionID, provider)
+		// Ensure that the reaper is terminated if an error occurred.
+		defer func() {
+			if err != nil {
+				if reaper != nil {
+					err = errors.Join(err, TerminateContainer(reaper.container))
+				}
+				err = r.retryError(errors.Join(err, r.cleanupLocked()))
+			}
+		}()
+		if err != nil {
+			return nil, err
+		}
+
+		if err = r.isRunning(ctx, reaper.container); err != nil {
+			return nil, err
+		}
+
+		// Check we can still connect.
+		termSignal, err := reaper.connect(ctx)
+		if err != nil {
+			return nil, fmt.Errorf("connect: %w", err)
+		}
+
+		reaper.setOrSignal(termSignal)
+
+		r.instance = reaper
+
+		return reaper, nil
+	}
+}
+
+// reuseOrCreate returns an existing Reaper instance if it exists, otherwise a new Reaper instance.
+func (r *reaperSpawner) reuseOrCreate(ctx context.Context, sessionID string, provider ReaperProvider) (*Reaper, error) {
+	if r.instance != nil {
+		// We already have an associated reaper.
+		return r.instance, nil
+	}
+
+	// Look for an existing reaper created in the same test session but in a
+	// different test process execution e.g. when running tests in parallel.
+	container, err := r.lookupContainer(context.Background(), sessionID)
+	if err != nil {
+		if !errors.Is(err, errReaperNotFound) {
+			return nil, fmt.Errorf("look up container: %w", err)
+		}
+
+		// The reaper container was not found, continue to create a new one.
+		reaper, err := r.newReaper(ctx, sessionID, provider)
+		if err != nil {
+			return nil, fmt.Errorf("new reaper: %w", err)
+		}
+
+		return reaper, nil
+	}
+
+	// A reaper container exists re-use it.
+	reaper, err := r.fromContainer(ctx, sessionID, provider, container)
+	if err != nil {
+		return nil, fmt.Errorf("from container %q: %w", container.ID[:8], err)
+	}
+
+	return reaper, nil
+}
+
+// fromContainer constructs a Reaper from an already running reaper DockerContainer.
+func (r *reaperSpawner) fromContainer(ctx context.Context, sessionID string, provider ReaperProvider, dockerContainer *DockerContainer) (*Reaper, error) {
+	log.Printf("⏳ Waiting for Reaper %q to be ready", dockerContainer.ID[:8])
+
+	// Reusing an existing container so we determine the port from the container's exposed ports.
+	if err := wait.ForExposedPort().
+		WithPollInterval(100*time.Millisecond).
+		SkipInternalCheck().
+		WaitUntilReady(ctx, dockerContainer); err != nil {
+		return nil, fmt.Errorf("wait for reaper %s: %w", dockerContainer.ID[:8], err)
+	}
+
+	endpoint, err := dockerContainer.Endpoint(ctx, "")
+	if err != nil {
+		return nil, fmt.Errorf("port endpoint: %w", err)
+	}
+
+	log.Printf("🔥 Reaper obtained from Docker for this test session %s", dockerContainer.ID[:8])
+
+	return &Reaper{
+		Provider:  provider,
+		SessionID: sessionID,
+		Endpoint:  endpoint,
+		container: dockerContainer,
+	}, nil
+}
+
+// defaultRyukWaitStrategy returns the wait strategy used when creating a new
+// reaper container. It combines a log match for "Started" (the moment ryuk's
+// TCP listener is bound inside the container, which is the readiness signal
+// also used by other Testcontainers libraries) with a host port-mapping check,
+// to guard against the docker-proxy accepting TCP connections before the ryuk
+// process is actually listening — a race that surfaced once the ryuk binary
+// was UPX-compressed.
+func defaultRyukWaitStrategy(port string) wait.Strategy {
+	return wait.ForAll(
+		wait.ForLog("Started"),
+		wait.ForListeningPort(port),
+	)
+}
+
+// newReaper creates a connected Reaper with a sessionID to identify containers
+// and a provider to use.
+func (r *reaperSpawner) newReaper(ctx context.Context, sessionID string, provider ReaperProvider) (reaper *Reaper, err error) {
+	dockerHostMount := core.MustExtractDockerSocket(ctx)
+
+	port := r.port()
+	tcConfig := provider.Config().Config
+	req := ContainerRequest{
+		Image:        config.ReaperDefaultImage,
+		ExposedPorts: []string{port.String()},
+		Labels:       core.DefaultLabels(sessionID),
+		WaitingFor:   defaultRyukWaitStrategy(port.String()),
+		Name:         reaperContainerNameFromSessionID(sessionID),
+		HostConfigModifier: func(hc *container.HostConfig) {
+			hc.AutoRemove = true
+			hc.Binds = []string{dockerHostMount + ":/var/run/docker.sock"}
+			hc.NetworkMode = Bridge
+			hc.Privileged = tcConfig.RyukPrivileged
+		},
+		Env: map[string]string{},
+	}
+	if to := tcConfig.RyukConnectionTimeout; to > time.Duration(0) {
+		req.Env["RYUK_CONNECTION_TIMEOUT"] = to.String()
+	}
+	if to := tcConfig.RyukReconnectionTimeout; to > time.Duration(0) {
+		req.Env["RYUK_RECONNECTION_TIMEOUT"] = to.String()
+	}
+	if tcConfig.RyukVerbose {
+		req.Env["RYUK_VERBOSE"] = "true"
+	}
+
+	// Setup reaper-specific labels for the reaper container.
+	req.Labels[core.LabelReaper] = "true"
+	req.Labels[core.LabelRyuk] = "true"
+	delete(req.Labels, core.LabelReap)
+
+	// Attach reaper container to a requested network if it is specified
+	if p, ok := provider.(*DockerProvider); ok {
+		defaultNetwork, err := p.ensureDefaultNetwork(ctx)
+		if err != nil {
+			return nil, fmt.Errorf("ensure default network: %w", err)
+		}
+
+		req.Networks = append(req.Networks, defaultNetwork)
+	}
+
+	c, err := provider.RunContainer(ctx, req)
+	defer func() {
+		if err != nil {
+			err = errors.Join(err, TerminateContainer(c))
+		}
+	}()
+	if err != nil {
+		return nil, fmt.Errorf("run container: %w", err)
+	}
+
+	endpoint, err := c.PortEndpoint(ctx, port.String(), "")
+	if err != nil {
+		return nil, fmt.Errorf("port endpoint: %w", err)
+	}
+
+	return &Reaper{
+		Provider:  provider,
+		SessionID: sessionID,
+		Endpoint:  endpoint,
+		container: c,
+	}, nil
+}
+
+// Reaper is used to start a sidecar container that cleans up resources
+type Reaper struct {
+	Provider   ReaperProvider
+	SessionID  string
+	Endpoint   string
+	container  Container
+	mtx        sync.Mutex // Protects termSignal.
+	termSignal chan bool
+}
+
+// Connect connects to the reaper container and sends the labels to it
+// so that it can clean up the containers with the same labels.
+//
+// It returns a channel that can be closed to terminate the connection.
+// Returns an error if config.RyukDisabled is true.
+func (r *Reaper) Connect() (chan bool, error) {
+	if config.Read().RyukDisabled {
+		return nil, errReaperDisabled
+	}
+
+	if termSignal := r.useTermSignal(); termSignal != nil {
+		return termSignal, nil
+	}
+
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
+	defer cancel()
+
+	return r.connect(ctx)
+}
+
+// close signals the connection to close if needed.
+// Safe for concurrent calls.
+func (r *Reaper) close() {
+	r.mtx.Lock()
+	defer r.mtx.Unlock()
+
+	if r.termSignal != nil {
+		r.termSignal <- true
+		r.termSignal = nil
+	}
+}
+
+// setOrSignal sets the reapers termSignal field if nil
+// otherwise consumes by sending true to it.
+// Safe for concurrent calls.
+func (r *Reaper) setOrSignal(termSignal chan bool) {
+	r.mtx.Lock()
+	defer r.mtx.Unlock()
+
+	if r.termSignal != nil {
+		// Already have an existing connection, close the new one.
+		termSignal <- true
+		return
+	}
+
+	// First or new unused termSignal, assign for caller to reuse.
+	r.termSignal = termSignal
+}
+
+// useTermSignal if termSignal is not nil returns it
+// and sets it to nil, otherwise returns nil.
+//
+// Safe for concurrent calls.
+func (r *Reaper) useTermSignal() chan bool {
+	r.mtx.Lock()
+	defer r.mtx.Unlock()
+
+	if r.termSignal == nil {
+		return nil
+	}
+
+	// Use existing connection.
+	term := r.termSignal
+	r.termSignal = nil
+
+	return term
+}
+
+// connect connects to the reaper container and sends the labels to it
+// so that it can clean up the containers with the same labels.
+//
+// It returns a channel that can be sent true to terminate the connection.
+// Returns an error if config.RyukDisabled is true.
+func (r *Reaper) connect(ctx context.Context) (chan bool, error) {
+	var d net.Dialer
+	conn, err := d.DialContext(ctx, "tcp", r.Endpoint)
+	if err != nil {
+		return nil, fmt.Errorf("dial reaper %s: %w", r.Endpoint, err)
+	}
+
+	terminationSignal := make(chan bool)
+	go func() {
+		defer conn.Close()
+		if err := r.handshake(conn); err != nil {
+			log.Printf("Reaper handshake failed: %s", err)
+		}
+		<-terminationSignal
+	}()
+	return terminationSignal, nil
+}
+
+// handshake sends the labels to the reaper container and reads the ACK.
+func (r *Reaper) handshake(conn net.Conn) error {
+	labels := core.DefaultLabels(r.SessionID)
+	labelFilters := make([]string, 0, len(labels))
+	for l, v := range labels {
+		labelFilters = append(labelFilters, fmt.Sprintf("label=%s=%s", l, v))
+	}
+
+	filters := []byte(strings.Join(labelFilters, "&") + "\n")
+	buf := make([]byte, 4)
+	if _, err := conn.Write(filters); err != nil {
+		return fmt.Errorf("writing filters: %w", err)
+	}
+
+	n, err := io.ReadFull(conn, buf)
+	if err != nil {
+		return fmt.Errorf("read ack: %w", err)
+	}
+
+	if !bytes.Equal(reaperAck, buf[:n]) {
+		// We have received the ACK so all done.
+		return fmt.Errorf("unexpected reaper response: %s", buf[:n])
+	}
+
+	return nil
+}
+
+// Deprecated: internally replaced by core.DefaultLabels(sessionID)
+//
+// Labels returns the container labels to use so that this Reaper cleans them up
+func (r *Reaper) Labels() map[string]string {
+	return GenericLabels()
+}
+
+// isReaperImage returns true if the image name is the reaper image.
+func isReaperImage(name string) bool {
+	return strings.HasSuffix(name, config.ReaperDefaultImage)
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/requirements.txt b/vendor/github.com/testcontainers/testcontainers-go/requirements.txt
new file mode 100644
index 000000000..a2970c671
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/requirements.txt
@@ -0,0 +1,5 @@
+mkdocs==1.5.3
+mkdocs-codeinclude-plugin==0.3.1
+mkdocs-include-markdown-plugin==7.2.2
+mkdocs-material==9.5.18
+mkdocs-markdownextradata-plugin==0.2.6
diff --git a/vendor/github.com/testcontainers/testcontainers-go/runtime.txt b/vendor/github.com/testcontainers/testcontainers-go/runtime.txt
new file mode 100644
index 000000000..24ee5b1be
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/runtime.txt
@@ -0,0 +1 @@
+3.13
diff --git a/vendor/github.com/testcontainers/testcontainers-go/testcontainers.go b/vendor/github.com/testcontainers/testcontainers-go/testcontainers.go
new file mode 100644
index 000000000..77ba722c7
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/testcontainers.go
@@ -0,0 +1,54 @@
+package testcontainers
+
+import (
+	"context"
+
+	"github.com/testcontainers/testcontainers-go/internal/core"
+)
+
+// Deprecated: use MustExtractDockerHost instead.
+func ExtractDockerSocket() string {
+	return MustExtractDockerSocket(context.Background())
+}
+
+// MustExtractDockerSocket Extracts the docker socket from the different alternatives, removing the socket schema.
+// Use this function to get the docker socket path, not the host (e.g. mounting the socket in a container).
+// This function does not consider Windows containers at the moment.
+// The possible alternatives are:
+//
+//  1. Docker host from the "tc.host" property in the ~/.testcontainers.properties file.
+//  2. The TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE environment variable.
+//  3. Using a Docker client, check if the Info().OperatingSystem is "Docker Desktop" and return the default docker socket path for rootless docker.
+//  4. Else, Get the current Docker Host from the existing strategies: see MustExtractDockerHost.
+//  5. If the socket contains the unix schema, the schema is removed (e.g. unix:///var/run/docker.sock -> /var/run/docker.sock)
+//  6. Else, the default location of the docker socket is used (/var/run/docker.sock)
+//
+// It panics if a Docker client cannot be created, or the Docker host cannot be discovered.
+func MustExtractDockerSocket(ctx context.Context) string {
+	return core.MustExtractDockerSocket(ctx)
+}
+
+// SessionID returns a unique session ID for the current test session. Because each Go package
+// will be run in a separate process, we need a way to identify the current test session.
+// By test session, we mean:
+//   - a single "go test" invocation (including flags)
+//   - a single "go test ./..." invocation (including flags)
+//   - the execution of a single test or a set of tests using the IDE
+//
+// As a consequence, with the sole goal of aggregating test execution across multiple
+// packages, this variable will contain the value of the parent process ID (pid) of the current process
+// and its creation date, to use it to generate a unique session ID. We are using the parent pid because
+// the current process will be a child process of:
+//   - the process that is running the tests, e.g.: "go test";
+//   - the process that is running the application in development mode, e.g. "go run main.go -tags dev";
+//   - the process that is running the tests in the IDE, e.g.: "go test ./...".
+//
+// Finally, we will hash the combination of the "testcontainers-go:" string with the parent pid
+// and the creation date of that parent process to generate a unique session ID.
+//
+// This sessionID will be used to:
+//   - identify the test session, aggregating the test execution of multiple packages in the same test session.
+//   - tag the containers created by testcontainers-go, adding a label to the container with the session ID.
+func SessionID() string {
+	return core.SessionID()
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/testing.go b/vendor/github.com/testcontainers/testcontainers-go/testing.go
new file mode 100644
index 000000000..47b360928
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/testing.go
@@ -0,0 +1,204 @@
+package testcontainers
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"os"
+	"regexp"
+	"strings"
+	"testing"
+
+	"github.com/containerd/errdefs"
+	"github.com/moby/moby/client"
+	"github.com/stretchr/testify/require"
+)
+
+// errAlreadyInProgress is a regular expression that matches the error for a container
+// removal that is already in progress.
+var errAlreadyInProgress = regexp.MustCompile(`removal of container .* is already in progress`)
+
+// SkipIfProviderIsNotHealthy is a utility function capable of skipping tests
+// if the provider is not healthy, or running at all.
+// This is a function designed to be used in your test, when Docker is not mandatory for CI/CD.
+// In this way tests that depend on Testcontainers won't run if the provider is provisioned correctly.
+func SkipIfProviderIsNotHealthy(t *testing.T) {
+	t.Helper()
+	defer func() {
+		if r := recover(); r != nil {
+			t.Skipf("Recovered from panic: %v. Docker is not running. Testcontainers can't perform is work without it", r)
+		}
+	}()
+
+	ctx := context.Background()
+	provider, err := ProviderDocker.GetProvider()
+	if err != nil {
+		t.Skipf("Docker is not running. Testcontainers can't perform is work without it: %s", err)
+	}
+	err = provider.Health(ctx)
+	if err != nil {
+		t.Skipf("Docker is not running. Testcontainers can't perform is work without it: %s", err)
+	}
+}
+
+// SkipIfDockerDesktop is a utility function capable of skipping tests
+// if tests are run using Docker Desktop or another VM-based Docker
+// environment (e.g. colima) where host network access is not available.
+func SkipIfDockerDesktop(t *testing.T, ctx context.Context) {
+	t.Helper()
+
+	// Colima runs Docker inside a Linux VM, so host networking doesn't work
+	// the same way as native Docker on Linux. Detect it via DOCKER_HOST which
+	// typically contains the colima socket path.
+	if strings.Contains(os.Getenv("DOCKER_HOST"), "colima") {
+		t.Skip("Skipping test that requires host network access when running in colima")
+	}
+
+	cli, err := NewDockerClientWithOpts(ctx)
+	require.NoErrorf(t, err, "failed to create docker client: %s", err)
+
+	res, err := cli.Info(ctx, client.InfoOptions{})
+	require.NoErrorf(t, err, "failed to get docker info: %s", err)
+
+	if res.Info.OperatingSystem == "Docker Desktop" {
+		t.Skip("Skipping test that requires host network access when running in Docker Desktop")
+	}
+}
+
+// SkipIfNotDockerDesktop is a utility function capable of skipping tests
+// if tests are not run using Docker Desktop.
+func SkipIfNotDockerDesktop(t *testing.T, ctx context.Context) {
+	t.Helper()
+	cli, err := NewDockerClientWithOpts(ctx)
+	require.NoErrorf(t, err, "failed to create docker client: %s", err)
+
+	res, err := cli.Info(ctx, client.InfoOptions{})
+	require.NoErrorf(t, err, "failed to get docker info: %s", err)
+
+	if res.Info.OperatingSystem != "Docker Desktop" {
+		t.Skip("Skipping test that needs Docker Desktop")
+	}
+}
+
+// exampleLogConsumer {
+
+// StdoutLogConsumer is a LogConsumer that prints the log to stdout
+type StdoutLogConsumer struct{}
+
+// Accept prints the log to stdout
+func (lc *StdoutLogConsumer) Accept(l Log) {
+	fmt.Print(string(l.Content))
+}
+
+// }
+
+// CleanupContainer is a helper function that schedules the container
+// to be stopped / terminated when the test ends.
+//
+// This should be called as a defer directly after (before any error check)
+// of [GenericContainer](...) or a modules Run(...) in a test to ensure the
+// container is stopped when the function ends.
+//
+// before any error check. If container is nil, it's a no-op.
+func CleanupContainer(tb testing.TB, ctr Container, options ...TerminateOption) {
+	tb.Helper()
+
+	tb.Cleanup(func() {
+		noErrorOrIgnored(tb, TerminateContainer(ctr, options...))
+	})
+}
+
+// CleanupNetwork is a helper function that schedules the network to be
+// removed when the test ends.
+// This should be the first call after NewNetwork(...) in a test before
+// any error check. If network is nil, it's a no-op.
+func CleanupNetwork(tb testing.TB, network Network) {
+	tb.Helper()
+
+	tb.Cleanup(func() {
+		if !isNil(network) {
+			noErrorOrIgnored(tb, network.Remove(context.Background()))
+		}
+	})
+}
+
+// noErrorOrIgnored is a helper function that checks if the error is nil or an error
+// we can ignore.
+func noErrorOrIgnored(tb testing.TB, err error) {
+	tb.Helper()
+
+	if isCleanupSafe(err) {
+		return
+	}
+
+	require.NoError(tb, err)
+}
+
+// causer is an interface that allows to get the cause of an error.
+type causer interface {
+	Cause() error
+}
+
+// wrapErr is an interface that allows to unwrap an error.
+type wrapErr interface {
+	Unwrap() error
+}
+
+// unwrapErrs is an interface that allows to unwrap multiple errors.
+type unwrapErrs interface {
+	Unwrap() []error
+}
+
+// isCleanupSafe reports whether all errors in err's tree are one of the
+// following, so can safely be ignored:
+//   - nil
+//   - not found
+//   - already in progress
+func isCleanupSafe(err error) bool {
+	if err == nil {
+		return true
+	}
+
+	// First try with containerd's errdefs
+	switch {
+	case errdefs.IsNotFound(err):
+		return true
+	case errdefs.IsConflict(err):
+		// Terminating a container that is already terminating.
+		if errAlreadyInProgress.MatchString(err.Error()) {
+			return true
+		}
+		return false
+	}
+
+	switch x := err.(type) { //nolint:errorlint // We need to check for interfaces.
+	case causer:
+		return isCleanupSafe(x.Cause())
+	case wrapErr:
+		return isCleanupSafe(x.Unwrap())
+	case unwrapErrs:
+		for _, e := range x.Unwrap() {
+			if !isCleanupSafe(e) {
+				return false
+			}
+		}
+		return true
+	default:
+		return false
+	}
+}
+
+// RequireContainerExec is a helper function that executes a command in a container
+// It insures that there is no error during the execution
+// Finally returns the output of its execution
+func RequireContainerExec(ctx context.Context, t *testing.T, container Container, cmd []string) string {
+	t.Helper()
+
+	code, out, err := container.Exec(ctx, cmd)
+	require.NoError(t, err)
+	require.Zero(t, code)
+
+	checkBytes, err := io.ReadAll(out)
+	require.NoError(t, err)
+	return string(checkBytes)
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/validator.go b/vendor/github.com/testcontainers/testcontainers-go/validator.go
new file mode 100644
index 000000000..a888586e8
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/validator.go
@@ -0,0 +1,7 @@
+package testcontainers
+
+// Validator is an interface that can be implemented by types that need to validate their state.
+type Validator interface {
+	// Validate validates the state of the type.
+	Validate() error
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/all.go b/vendor/github.com/testcontainers/testcontainers-go/wait/all.go
new file mode 100644
index 000000000..e65033073
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/all.go
@@ -0,0 +1,115 @@
+package wait
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"time"
+)
+
+// Implement interface
+var (
+	_ Strategy        = (*MultiStrategy)(nil)
+	_ StrategyTimeout = (*MultiStrategy)(nil)
+)
+
+type MultiStrategy struct {
+	// all Strategies should have a startupTimeout to avoid waiting infinitely
+	timeout  *time.Duration
+	deadline *time.Duration
+
+	// additional properties
+	Strategies []Strategy
+}
+
+// WithStartupTimeoutDefault sets the default timeout for all inner wait strategies
+func (ms *MultiStrategy) WithStartupTimeoutDefault(timeout time.Duration) *MultiStrategy {
+	ms.timeout = &timeout
+	return ms
+}
+
+// WithStartupTimeout sets a time.Duration which limits all wait strategies
+//
+// Deprecated: use WithDeadline
+func (ms *MultiStrategy) WithStartupTimeout(timeout time.Duration) Strategy {
+	return ms.WithDeadline(timeout)
+}
+
+// WithDeadline sets a time.Duration which limits all wait strategies
+func (ms *MultiStrategy) WithDeadline(deadline time.Duration) *MultiStrategy {
+	ms.deadline = &deadline
+	return ms
+}
+
+func ForAll(strategies ...Strategy) *MultiStrategy {
+	return &MultiStrategy{
+		Strategies: strategies,
+	}
+}
+
+func (ms *MultiStrategy) Timeout() *time.Duration {
+	return ms.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ms *MultiStrategy) String() string {
+	if len(ms.Strategies) == 0 {
+		return "all of: (none)"
+	}
+
+	var strategies []string
+	for _, strategy := range ms.Strategies {
+		if strategy == nil || reflect.ValueOf(strategy).IsNil() {
+			continue
+		}
+		if s, ok := strategy.(fmt.Stringer); ok {
+			strategies = append(strategies, s.String())
+		} else {
+			strategies = append(strategies, fmt.Sprintf("%T", strategy))
+		}
+	}
+
+	// Always include "all of:" prefix to make it clear this is a MultiStrategy
+	// even when there's only one strategy after filtering out nils
+	return "all of: [" + strings.Join(strategies, ", ") + "]"
+}
+
+func (ms *MultiStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	var cancel context.CancelFunc
+	if ms.deadline != nil {
+		ctx, cancel = context.WithTimeout(ctx, *ms.deadline)
+		defer cancel()
+	}
+
+	if len(ms.Strategies) == 0 {
+		return errors.New("no wait strategy supplied")
+	}
+
+	for _, strategy := range ms.Strategies {
+		if strategy == nil || reflect.ValueOf(strategy).IsNil() {
+			// A module could be appending strategies after part of the container initialization,
+			// and use wait.ForAll on a not initialized strategy.
+			// In this case, we just skip the nil strategy.
+			continue
+		}
+
+		strategyCtx := ctx
+
+		// Set default Timeout when strategy implements StrategyTimeout
+		if st, ok := strategy.(StrategyTimeout); ok {
+			if ms.Timeout() != nil && st.Timeout() == nil {
+				strategyCtx, cancel = context.WithTimeout(ctx, *ms.Timeout())
+				defer cancel()
+			}
+		}
+
+		err := strategy.WaitUntilReady(strategyCtx, target)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/any.go b/vendor/github.com/testcontainers/testcontainers-go/wait/any.go
new file mode 100644
index 000000000..15d9c1500
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/any.go
@@ -0,0 +1,128 @@
+package wait
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"time"
+)
+
+// Implement interface
+var (
+	_ Strategy        = (*AnyMultiStrategy)(nil)
+	_ StrategyTimeout = (*AnyMultiStrategy)(nil)
+)
+
+type AnyMultiStrategy struct {
+	// all Strategies should have a startupTimeout to avoid waiting infinitely
+	timeout  *time.Duration
+	deadline *time.Duration
+
+	// additional properties
+	Strategies []Strategy
+}
+
+// WithStartupTimeoutDefault sets the default timeout for all inner wait strategies.
+func (ms *AnyMultiStrategy) WithStartupTimeoutDefault(timeout time.Duration) *AnyMultiStrategy {
+	ms.timeout = &timeout
+	return ms
+}
+
+// WithDeadline sets a time.Duration which limits all wait strategies.
+func (ms *AnyMultiStrategy) WithDeadline(deadline time.Duration) *AnyMultiStrategy {
+	ms.deadline = &deadline
+	return ms
+}
+
+// ForAny returns a WaitStrategy that waits for any of the supplied conditions
+// to become true (after which it cancels the remaining ones).
+//
+// Failures are not permitted: any strategy which fails will have its error
+// immediately returned.
+func ForAny(strategies ...Strategy) *AnyMultiStrategy {
+	return &AnyMultiStrategy{
+		Strategies: strategies,
+	}
+}
+
+func (ms *AnyMultiStrategy) Timeout() *time.Duration {
+	return ms.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ms *AnyMultiStrategy) String() string {
+	if len(ms.Strategies) == 0 {
+		return "any of: (none)"
+	}
+
+	var strategies []string
+	for _, strategy := range ms.Strategies {
+		if strategy == nil || reflect.ValueOf(strategy).IsNil() {
+			continue
+		}
+		if s, ok := strategy.(fmt.Stringer); ok {
+			strategies = append(strategies, s.String())
+		} else {
+			strategies = append(strategies, fmt.Sprintf("%T", strategy))
+		}
+	}
+
+	// Always include "any of:" prefix to make it clear this is a AnyMultiStrategy
+	// even when there's only one strategy after filtering out nils.
+	return "any of: [" + strings.Join(strategies, ", ") + "]"
+}
+
+func (ms *AnyMultiStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	if len(ms.Strategies) == 0 {
+		return errors.New("no wait strategy supplied")
+	}
+
+	ctx, cancel := context.WithCancel(ctx)
+	defer cancel() // All remaining strategies will stop when this fires.
+
+	if ms.deadline != nil {
+		ctx, cancel = context.WithTimeout(ctx, *ms.deadline)
+		defer cancel()
+	}
+
+	resCh := make(chan error, len(ms.Strategies))
+	var valid int
+
+	for _, strategy := range ms.Strategies {
+		if strategy == nil || reflect.ValueOf(strategy).IsNil() {
+			// A module could be appending strategies after part of the container initialization,
+			// and use wait.ForAny on a not initialized strategy.
+			// In this case, we just skip the nil strategy.
+			continue
+		}
+		valid++
+
+		strategyCtx := ctx
+		// Set default Timeout when strategy implements StrategyTimeout
+		if st, ok := strategy.(StrategyTimeout); ok {
+			if ms.Timeout() != nil && st.Timeout() == nil {
+				strategyCtx, cancel = context.WithTimeout(ctx, *ms.Timeout())
+				defer cancel()
+			}
+		}
+		go func() { resCh <- strategy.WaitUntilReady(strategyCtx, target) }()
+	}
+
+	if valid == 0 {
+		return nil
+	}
+
+	for {
+		select {
+		case err := <-resCh:
+			if err != nil {
+				return err
+			}
+			return nil
+		case <-ctx.Done():
+			return fmt.Errorf("timed out waiting for strategies: %w", ctx.Err())
+		}
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/errors.go b/vendor/github.com/testcontainers/testcontainers-go/wait/errors.go
new file mode 100644
index 000000000..1b8cc946d
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/errors.go
@@ -0,0 +1,12 @@
+//go:build !windows
+
+package wait
+
+import (
+	"errors"
+	"syscall"
+)
+
+func isConnRefusedErr(err error) bool {
+	return errors.Is(err, syscall.ECONNREFUSED)
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/errors_windows.go b/vendor/github.com/testcontainers/testcontainers-go/wait/errors_windows.go
new file mode 100644
index 000000000..3ae346d8a
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/errors_windows.go
@@ -0,0 +1,9 @@
+package wait
+
+import (
+	"golang.org/x/sys/windows"
+)
+
+func isConnRefusedErr(err error) bool {
+	return err == windows.WSAECONNREFUSED
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/exec.go b/vendor/github.com/testcontainers/testcontainers-go/wait/exec.go
new file mode 100644
index 000000000..5338eb8a7
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/exec.go
@@ -0,0 +1,124 @@
+package wait
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"time"
+
+	tcexec "github.com/testcontainers/testcontainers-go/exec"
+)
+
+// Implement interface
+var (
+	_ Strategy        = (*ExecStrategy)(nil)
+	_ StrategyTimeout = (*ExecStrategy)(nil)
+)
+
+type ExecStrategy struct {
+	// all Strategies should have a startupTimeout to avoid waiting infinitely
+	timeout *time.Duration
+	cmd     []string
+
+	// additional properties
+	ExitCodeMatcher func(exitCode int) bool
+	ResponseMatcher func(body io.Reader) bool
+	PollInterval    time.Duration
+}
+
+// NewExecStrategy constructs an Exec strategy ...
+func NewExecStrategy(cmd []string) *ExecStrategy {
+	return &ExecStrategy{
+		cmd:             cmd,
+		ExitCodeMatcher: defaultExitCodeMatcher,
+		ResponseMatcher: func(_ io.Reader) bool { return true },
+		PollInterval:    defaultPollInterval(),
+	}
+}
+
+func defaultExitCodeMatcher(exitCode int) bool {
+	return exitCode == 0
+}
+
+// WithStartupTimeout can be used to change the default startup timeout
+func (ws *ExecStrategy) WithStartupTimeout(startupTimeout time.Duration) *ExecStrategy {
+	ws.timeout = &startupTimeout
+	return ws
+}
+
+func (ws *ExecStrategy) WithExitCode(exitCode int) *ExecStrategy {
+	return ws.WithExitCodeMatcher(func(actualCode int) bool {
+		return actualCode == exitCode
+	})
+}
+
+func (ws *ExecStrategy) WithExitCodeMatcher(exitCodeMatcher func(exitCode int) bool) *ExecStrategy {
+	ws.ExitCodeMatcher = exitCodeMatcher
+	return ws
+}
+
+func (ws *ExecStrategy) WithResponseMatcher(matcher func(body io.Reader) bool) *ExecStrategy {
+	ws.ResponseMatcher = matcher
+	return ws
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds
+func (ws *ExecStrategy) WithPollInterval(pollInterval time.Duration) *ExecStrategy {
+	ws.PollInterval = pollInterval
+	return ws
+}
+
+// ForExec is a convenience method to assign ExecStrategy
+func ForExec(cmd []string) *ExecStrategy {
+	return NewExecStrategy(cmd)
+}
+
+func (ws *ExecStrategy) Timeout() *time.Duration {
+	return ws.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ws *ExecStrategy) String() string {
+	if len(ws.cmd) == 0 {
+		return "exec command"
+	}
+	// Only show the command name and argument count to avoid exposing sensitive data
+	argCount := len(ws.cmd) - 1
+	if argCount == 0 {
+		return fmt.Sprintf("exec command %q", ws.cmd[0])
+	}
+	if argCount == 1 {
+		return fmt.Sprintf("exec command %q with 1 argument", ws.cmd[0])
+	}
+	return fmt.Sprintf("exec command %q with %d arguments", ws.cmd[0], argCount)
+}
+
+func (ws *ExecStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	timeout := defaultStartupTimeout()
+	if ws.timeout != nil {
+		timeout = *ws.timeout
+	}
+
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+
+	for {
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		case <-time.After(ws.PollInterval):
+			exitCode, resp, err := target.Exec(ctx, ws.cmd, tcexec.Multiplexed())
+			if err != nil {
+				return err
+			}
+			if !ws.ExitCodeMatcher(exitCode) {
+				continue
+			}
+			if ws.ResponseMatcher != nil && !ws.ResponseMatcher(resp) {
+				continue
+			}
+
+			return nil
+		}
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/exit.go b/vendor/github.com/testcontainers/testcontainers-go/wait/exit.go
new file mode 100644
index 000000000..6daf4c3fa
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/exit.go
@@ -0,0 +1,94 @@
+package wait
+
+import (
+	"context"
+	"strings"
+	"time"
+)
+
+// Implement interface
+var (
+	_ Strategy        = (*ExitStrategy)(nil)
+	_ StrategyTimeout = (*ExitStrategy)(nil)
+)
+
+// ExitStrategy will wait until container exit
+type ExitStrategy struct {
+	// all Strategies should have a timeout to avoid waiting infinitely
+	timeout *time.Duration
+
+	// additional properties
+	PollInterval time.Duration
+}
+
+// NewExitStrategy constructs with polling interval of 100 milliseconds without timeout by default
+func NewExitStrategy() *ExitStrategy {
+	return &ExitStrategy{
+		PollInterval: defaultPollInterval(),
+	}
+}
+
+// fluent builders for each property
+// since go has neither covariance nor generics, the return type must be the type of the concrete implementation
+// this is true for all properties, even the "shared" ones
+
+// WithExitTimeout can be used to change the default exit timeout
+func (ws *ExitStrategy) WithExitTimeout(exitTimeout time.Duration) *ExitStrategy {
+	ws.timeout = &exitTimeout
+	return ws
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds
+func (ws *ExitStrategy) WithPollInterval(pollInterval time.Duration) *ExitStrategy {
+	ws.PollInterval = pollInterval
+	return ws
+}
+
+// ForExit is the default construction for the fluid interface.
+//
+// For Example:
+//
+//	wait.
+//		ForExit().
+//		WithPollInterval(1 * time.Second)
+func ForExit() *ExitStrategy {
+	return NewExitStrategy()
+}
+
+func (ws *ExitStrategy) Timeout() *time.Duration {
+	return ws.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ws *ExitStrategy) String() string {
+	return "container to exit"
+}
+
+// WaitUntilReady implements Strategy.WaitUntilReady
+func (ws *ExitStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	if ws.timeout != nil {
+		var cancel context.CancelFunc
+		ctx, cancel = context.WithTimeout(ctx, *ws.timeout)
+		defer cancel()
+	}
+
+	for {
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		default:
+			state, err := target.State(ctx)
+			if err != nil {
+				if !strings.Contains(err.Error(), "No such container") {
+					return err
+				}
+				return nil
+			}
+			if state.Running {
+				time.Sleep(ws.PollInterval)
+				continue
+			}
+			return nil
+		}
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/file.go b/vendor/github.com/testcontainers/testcontainers-go/wait/file.go
new file mode 100644
index 000000000..5926b66a9
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/file.go
@@ -0,0 +1,120 @@
+package wait
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"time"
+
+	"github.com/containerd/errdefs"
+)
+
+var (
+	_ Strategy        = (*FileStrategy)(nil)
+	_ StrategyTimeout = (*FileStrategy)(nil)
+)
+
+// FileStrategy waits for a file to exist in the container.
+type FileStrategy struct {
+	timeout      *time.Duration
+	file         string
+	pollInterval time.Duration
+	matcher      func(io.Reader) error
+}
+
+// NewFileStrategy constructs an FileStrategy strategy.
+func NewFileStrategy(file string) *FileStrategy {
+	return &FileStrategy{
+		file:         file,
+		pollInterval: defaultPollInterval(),
+	}
+}
+
+// WithStartupTimeout can be used to change the default startup timeout
+func (ws *FileStrategy) WithStartupTimeout(startupTimeout time.Duration) *FileStrategy {
+	ws.timeout = &startupTimeout
+	return ws
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds
+func (ws *FileStrategy) WithPollInterval(pollInterval time.Duration) *FileStrategy {
+	ws.pollInterval = pollInterval
+	return ws
+}
+
+// WithMatcher can be used to consume the file content.
+// The matcher can return an errdefs.ErrNotFound to indicate that the file is not ready.
+// Any other error will be considered a failure.
+// Default: nil, will only wait for the file to exist.
+func (ws *FileStrategy) WithMatcher(matcher func(io.Reader) error) *FileStrategy {
+	ws.matcher = matcher
+	return ws
+}
+
+// ForFile is a convenience method to assign FileStrategy
+func ForFile(file string) *FileStrategy {
+	return NewFileStrategy(file)
+}
+
+// Timeout returns the timeout for the strategy
+func (ws *FileStrategy) Timeout() *time.Duration {
+	return ws.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ws *FileStrategy) String() string {
+	if ws.matcher != nil {
+		return fmt.Sprintf("file %q to exist and match condition", ws.file)
+	}
+	return fmt.Sprintf("file %q to exist", ws.file)
+}
+
+// WaitUntilReady waits until the file exists in the container and copies it to the target.
+func (ws *FileStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	timeout := defaultStartupTimeout()
+	if ws.timeout != nil {
+		timeout = *ws.timeout
+	}
+
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+
+	timer := time.NewTicker(ws.pollInterval)
+	defer timer.Stop()
+	for {
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		case <-timer.C:
+			if err := ws.matchFile(ctx, target); err != nil {
+				if errdefs.IsNotFound(err) {
+					// Not found, continue polling.
+					continue
+				}
+
+				return fmt.Errorf("copy from container: %w", err)
+			}
+			return nil
+		}
+	}
+}
+
+// matchFile tries to copy the file from the container and match it.
+func (ws *FileStrategy) matchFile(ctx context.Context, target StrategyTarget) error {
+	rc, err := target.CopyFileFromContainer(ctx, ws.file)
+	if err != nil {
+		return fmt.Errorf("copy from container: %w", err)
+	}
+	defer rc.Close()
+
+	if ws.matcher == nil {
+		// No matcher, just check if the file exists.
+		return nil
+	}
+
+	if err = ws.matcher(rc); err != nil {
+		return fmt.Errorf("matcher: %w", err)
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/health.go b/vendor/github.com/testcontainers/testcontainers-go/wait/health.go
new file mode 100644
index 000000000..6df6f0de6
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/health.go
@@ -0,0 +1,97 @@
+package wait
+
+import (
+	"context"
+	"time"
+
+	"github.com/moby/moby/api/types/container"
+)
+
+// Implement interface
+var (
+	_ Strategy        = (*HealthStrategy)(nil)
+	_ StrategyTimeout = (*HealthStrategy)(nil)
+)
+
+// HealthStrategy will wait until the container becomes healthy
+type HealthStrategy struct {
+	// all Strategies should have a startupTimeout to avoid waiting infinitely
+	timeout *time.Duration
+
+	// additional properties
+	PollInterval time.Duration
+}
+
+// NewHealthStrategy constructs with polling interval of 100 milliseconds and startup timeout of 60 seconds by default
+func NewHealthStrategy() *HealthStrategy {
+	return &HealthStrategy{
+		PollInterval: defaultPollInterval(),
+	}
+}
+
+// fluent builders for each property
+// since go has neither covariance nor generics, the return type must be the type of the concrete implementation
+// this is true for all properties, even the "shared" ones like startupTimeout
+
+// WithStartupTimeout can be used to change the default startup timeout
+func (ws *HealthStrategy) WithStartupTimeout(startupTimeout time.Duration) *HealthStrategy {
+	ws.timeout = &startupTimeout
+	return ws
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds
+func (ws *HealthStrategy) WithPollInterval(pollInterval time.Duration) *HealthStrategy {
+	ws.PollInterval = pollInterval
+	return ws
+}
+
+// ForHealthCheck is the default construction for the fluid interface.
+//
+// For Example:
+//
+//	wait.
+//		ForHealthCheck().
+//		WithPollInterval(1 * time.Second)
+func ForHealthCheck() *HealthStrategy {
+	return NewHealthStrategy()
+}
+
+func (ws *HealthStrategy) Timeout() *time.Duration {
+	return ws.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ws *HealthStrategy) String() string {
+	return "container to become healthy"
+}
+
+// WaitUntilReady implements Strategy.WaitUntilReady
+func (ws *HealthStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	timeout := defaultStartupTimeout()
+	if ws.timeout != nil {
+		timeout = *ws.timeout
+	}
+
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+
+	for {
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		default:
+			state, err := target.State(ctx)
+			if err != nil {
+				return err
+			}
+			if err := checkState(state); err != nil {
+				return err
+			}
+			if state.Health == nil || state.Health.Status != container.Healthy {
+				time.Sleep(ws.PollInterval)
+				continue
+			}
+			return nil
+		}
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go b/vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go
new file mode 100644
index 000000000..60cf5e4e5
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/host_port.go
@@ -0,0 +1,321 @@
+package wait
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net"
+	"os"
+	"time"
+
+	"github.com/moby/moby/api/types/network"
+
+	"github.com/testcontainers/testcontainers-go/log"
+)
+
+const (
+	exitEaccess     = 126 // container cmd can't be invoked (permission denied)
+	exitCmdNotFound = 127 // container cmd not found/does not exist or invalid bind-mount
+)
+
+// Implement interface
+var (
+	_ Strategy        = (*HostPortStrategy)(nil)
+	_ StrategyTimeout = (*HostPortStrategy)(nil)
+)
+
+var (
+	errShellNotExecutable = errors.New("/bin/sh command not executable")
+	errShellNotFound      = errors.New("/bin/sh command not found")
+)
+
+type HostPortStrategy struct {
+	// Port is a string containing port number and protocol in the format "80/tcp"
+	// which
+	Port string
+	// all WaitStrategies should have a startupTimeout to avoid waiting infinitely
+	timeout      *time.Duration
+	PollInterval time.Duration
+
+	// skipInternalCheck is a flag to skip the internal check, which is useful when
+	// a shell is not available in the container or when the container doesn't bind
+	// the port internally until additional conditions are met.
+	skipInternalCheck bool
+
+	// skipExternalCheck is a flag to skip the external check, which, if used with
+	// skipInternalCheck, makes strategy waiting only for port mapping completion
+	// without accessing port.
+	skipExternalCheck bool
+}
+
+// NewHostPortStrategy constructs a default host port strategy that waits for the given
+// port to be exposed. The default startup timeout is 60 seconds.
+func NewHostPortStrategy(port string) *HostPortStrategy {
+	return &HostPortStrategy{
+		Port:         port,
+		PollInterval: defaultPollInterval(),
+	}
+}
+
+// fluent builders for each property
+// since go has neither covariance nor generics, the return type must be the type of the concrete implementation
+// this is true for all properties, even the "shared" ones like startupTimeout
+
+// ForListeningPort returns a host port strategy that waits for the given port
+// to be exposed and bound internally the container.
+// Alias for `NewHostPortStrategy(port)`.
+func ForListeningPort(port string) *HostPortStrategy {
+	return NewHostPortStrategy(port)
+}
+
+// ForExposedPort returns a host port strategy that waits for the first port
+// to be exposed and bound internally the container.
+func ForExposedPort() *HostPortStrategy {
+	return NewHostPortStrategy("")
+}
+
+// ForMappedPort returns a host port strategy that waits for the given port
+// to be mapped without accessing the port itself.
+func ForMappedPort(port string) *HostPortStrategy {
+	return NewHostPortStrategy(port).SkipInternalCheck().SkipExternalCheck()
+}
+
+// SkipInternalCheck changes the host port strategy to skip the internal check,
+// which is useful when a shell is not available in the container or when the
+// container doesn't bind the port internally until additional conditions are met.
+func (hp *HostPortStrategy) SkipInternalCheck() *HostPortStrategy {
+	hp.skipInternalCheck = true
+
+	return hp
+}
+
+// SkipExternalCheck changes the host port strategy to skip the external check,
+// which, if used with SkipInternalCheck, makes strategy waiting only for port
+// mapping completion without accessing port.
+func (hp *HostPortStrategy) SkipExternalCheck() *HostPortStrategy {
+	hp.skipExternalCheck = true
+
+	return hp
+}
+
+// WithStartupTimeout can be used to change the default startup timeout
+func (hp *HostPortStrategy) WithStartupTimeout(startupTimeout time.Duration) *HostPortStrategy {
+	hp.timeout = &startupTimeout
+	return hp
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds
+func (hp *HostPortStrategy) WithPollInterval(pollInterval time.Duration) *HostPortStrategy {
+	hp.PollInterval = pollInterval
+	return hp
+}
+
+func (hp *HostPortStrategy) Timeout() *time.Duration {
+	return hp.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (hp *HostPortStrategy) String() string {
+	port := "first exposed port"
+	if hp.Port != "" {
+		port = "port " + hp.Port
+	}
+
+	var checks string
+	switch {
+	case hp.skipInternalCheck && hp.skipExternalCheck:
+		checks = " to be mapped"
+	case hp.skipInternalCheck:
+		checks = " to be accessible externally"
+	case hp.skipExternalCheck:
+		checks = " to be listening internally"
+	default:
+		checks = " to be listening"
+	}
+
+	return fmt.Sprintf("%s%s", port, checks)
+}
+
+// detectInternalPort returns the lowest internal port that is currently bound.
+// If no internal port is found, it returns the zero nat.Port value which
+// can be checked against an empty string.
+func (hp *HostPortStrategy) detectInternalPort(ctx context.Context, target StrategyTarget) (network.Port, error) {
+	var internalPort network.Port
+	inspect, err := target.Inspect(ctx)
+	if err != nil {
+		return internalPort, fmt.Errorf("inspect: %w", err)
+	}
+
+	for port := range inspect.NetworkSettings.Ports {
+		if internalPort.IsZero() || port.Num() < internalPort.Num() {
+			internalPort = port
+		}
+	}
+
+	return internalPort, nil
+}
+
+// WaitUntilReady implements Strategy.WaitUntilReady
+func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	timeout := defaultStartupTimeout()
+	if hp.timeout != nil {
+		timeout = *hp.timeout
+	}
+
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+
+	waitInterval := hp.PollInterval
+
+	var internalPort network.Port
+	if hp.Port != "" {
+		p, err := network.ParsePort(hp.Port)
+		if err != nil {
+			return err
+		}
+		internalPort = p
+	}
+
+	i := 0
+	if internalPort.IsZero() {
+		var err error
+		// Port is not specified, so we need to detect it.
+		internalPort, err = hp.detectInternalPort(ctx, target)
+		if err != nil {
+			return fmt.Errorf("detect internal port: %w", err)
+		}
+
+		for internalPort.IsZero() {
+			select {
+			case <-ctx.Done():
+				return fmt.Errorf("detect internal port: retries: %d, last err: %w, ctx err: %w", i, err, ctx.Err())
+			case <-time.After(waitInterval):
+				if err := checkTarget(ctx, target); err != nil {
+					return fmt.Errorf("detect internal port: check target: retries: %d, last err: %w", i, err)
+				}
+
+				internalPort, err = hp.detectInternalPort(ctx, target)
+				if err != nil {
+					return fmt.Errorf("detect internal port: %w", err)
+				}
+			}
+		}
+	}
+
+	port, err := target.MappedPort(ctx, internalPort.String())
+	i = 0
+
+	for port.IsZero() {
+		i++
+
+		select {
+		case <-ctx.Done():
+			return fmt.Errorf("mapped port: retries: %d, port: %q, last err: %w, ctx err: %w", i, port, err, ctx.Err())
+		case <-time.After(waitInterval):
+			if err := checkTarget(ctx, target); err != nil {
+				return fmt.Errorf("mapped port: check target: retries: %d, port: %q, last err: %w", i, port, err)
+			}
+			port, err = target.MappedPort(ctx, internalPort.String())
+			if err != nil {
+				log.Printf("mapped port: retries: %d, port: %q, err: %s\n", i, port, err)
+			}
+		}
+	}
+
+	if !hp.skipExternalCheck {
+		ipAddress, err := target.Host(ctx)
+		if err != nil {
+			return fmt.Errorf("host: %w", err)
+		}
+
+		if err := externalCheck(ctx, ipAddress, port, target, waitInterval); err != nil {
+			return fmt.Errorf("external check: %w", err)
+		}
+	}
+
+	if hp.skipInternalCheck {
+		return nil
+	}
+
+	if err = internalCheck(ctx, internalPort, target); err != nil {
+		switch {
+		case errors.Is(err, errShellNotExecutable):
+			log.Printf("Shell not executable in container, only external port validated")
+			return nil
+		case errors.Is(err, errShellNotFound):
+			log.Printf("Shell not found in container")
+			return nil
+		default:
+			return fmt.Errorf("internal check: %w", err)
+		}
+	}
+
+	return nil
+}
+
+func externalCheck(ctx context.Context, ipAddress string, port network.Port, target StrategyTarget, waitInterval time.Duration) error {
+	proto := port.Proto()
+
+	dialer := net.Dialer{}
+	address := net.JoinHostPort(ipAddress, port.Port())
+	for i := 0; ; i++ {
+		if err := checkTarget(ctx, target); err != nil {
+			return fmt.Errorf("check target: retries: %d address: %s: %w", i, address, err)
+		}
+		conn, err := dialer.DialContext(ctx, string(proto), address)
+		if err != nil {
+			var v *net.OpError
+			if errors.As(err, &v) {
+				var v2 *os.SyscallError
+				if errors.As(v.Err, &v2) {
+					if isConnRefusedErr(v2.Err) {
+						time.Sleep(waitInterval)
+						continue
+					}
+				}
+			}
+			return fmt.Errorf("dial: %w", err)
+		}
+
+		_ = conn.Close()
+		return nil
+	}
+}
+
+func internalCheck(ctx context.Context, internalPort network.Port, target StrategyTarget) error {
+	command := buildInternalCheckCommand(internalPort.Num())
+	for {
+		if ctx.Err() != nil {
+			return ctx.Err()
+		}
+		if err := checkTarget(ctx, target); err != nil {
+			return err
+		}
+		exitCode, _, err := target.Exec(ctx, []string{"/bin/sh", "-c", command})
+		if err != nil {
+			return fmt.Errorf("%w, host port waiting failed", err)
+		}
+
+		// Docker has an issue which override exit code 127 to 126 due to:
+		// https://github.com/moby/moby/issues/45795
+		// Handle both to ensure compatibility with Docker and Podman for now.
+		switch exitCode {
+		case 0:
+			return nil
+		case exitEaccess:
+			return errShellNotExecutable
+		case exitCmdNotFound:
+			return errShellNotFound
+		}
+	}
+}
+
+func buildInternalCheckCommand(internalPort uint16) string {
+	command := `(
+					cat /proc/net/tcp* | awk '{print $2}' | grep -i :%04x ||
+					nc -vz -w 1 localhost %d ||
+					/bin/sh -c '</dev/tcp/localhost/%d'
+				)
+				`
+	return "true && " + fmt.Sprintf(command, internalPort, internalPort, internalPort)
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/http.go b/vendor/github.com/testcontainers/testcontainers-go/wait/http.go
new file mode 100644
index 000000000..95208290c
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/http.go
@@ -0,0 +1,357 @@
+package wait
+
+import (
+	"bytes"
+	"context"
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"net/http"
+	"net/url"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+// Implement interface
+var (
+	_ Strategy        = (*HTTPStrategy)(nil)
+	_ StrategyTimeout = (*HTTPStrategy)(nil)
+)
+
+type HTTPStrategy struct {
+	// all Strategies should have a startupTimeout to avoid waiting infinitely
+	timeout *time.Duration
+
+	// additional properties
+	Port                   network.Port
+	Path                   string
+	StatusCodeMatcher      func(status int) bool
+	ResponseMatcher        func(body io.Reader) bool
+	UseTLS                 bool
+	AllowInsecure          bool
+	TLSConfig              *tls.Config // TLS config for HTTPS
+	Method                 string      // http method
+	Body                   io.Reader   // http request body
+	Headers                map[string]string
+	ResponseHeadersMatcher func(headers http.Header) bool
+	PollInterval           time.Duration
+	UserInfo               *url.Userinfo
+	ForceIPv4LocalHost     bool
+}
+
+// NewHTTPStrategy constructs an HTTP strategy waiting on port 80 and status code 200
+func NewHTTPStrategy(path string) *HTTPStrategy {
+	return &HTTPStrategy{
+		Port:                   network.Port{},
+		Path:                   path,
+		StatusCodeMatcher:      defaultStatusCodeMatcher,
+		ResponseMatcher:        func(_ io.Reader) bool { return true },
+		UseTLS:                 false,
+		TLSConfig:              nil,
+		Method:                 http.MethodGet,
+		Body:                   nil,
+		Headers:                map[string]string{},
+		ResponseHeadersMatcher: func(_ http.Header) bool { return true },
+		PollInterval:           defaultPollInterval(),
+		UserInfo:               nil,
+	}
+}
+
+func defaultStatusCodeMatcher(status int) bool {
+	return status == http.StatusOK
+}
+
+// fluent builders for each property
+// since go has neither covariance nor generics, the return type must be the type of the concrete implementation
+// this is true for all properties, even the "shared" ones like startupTimeout
+
+// WithStartupTimeout can be used to change the default startup timeout
+func (ws *HTTPStrategy) WithStartupTimeout(timeout time.Duration) *HTTPStrategy {
+	ws.timeout = &timeout
+	return ws
+}
+
+// WithPort set the port to wait for.
+// Default is the lowest numbered port.
+func (ws *HTTPStrategy) WithPort(port string) *HTTPStrategy {
+	if p, err := network.ParsePort(port); err == nil {
+		ws.Port = p
+	}
+	return ws
+}
+
+func (ws *HTTPStrategy) WithStatusCodeMatcher(statusCodeMatcher func(status int) bool) *HTTPStrategy {
+	ws.StatusCodeMatcher = statusCodeMatcher
+	return ws
+}
+
+func (ws *HTTPStrategy) WithResponseMatcher(matcher func(body io.Reader) bool) *HTTPStrategy {
+	ws.ResponseMatcher = matcher
+	return ws
+}
+
+func (ws *HTTPStrategy) WithTLS(useTLS bool, tlsconf ...*tls.Config) *HTTPStrategy {
+	ws.UseTLS = useTLS
+	if useTLS && len(tlsconf) > 0 {
+		ws.TLSConfig = tlsconf[0]
+	}
+	return ws
+}
+
+func (ws *HTTPStrategy) WithAllowInsecure(allowInsecure bool) *HTTPStrategy {
+	ws.AllowInsecure = allowInsecure
+	return ws
+}
+
+func (ws *HTTPStrategy) WithMethod(method string) *HTTPStrategy {
+	ws.Method = method
+	return ws
+}
+
+func (ws *HTTPStrategy) WithBody(reqdata io.Reader) *HTTPStrategy {
+	ws.Body = reqdata
+	return ws
+}
+
+func (ws *HTTPStrategy) WithHeaders(headers map[string]string) *HTTPStrategy {
+	ws.Headers = headers
+	return ws
+}
+
+func (ws *HTTPStrategy) WithResponseHeadersMatcher(matcher func(http.Header) bool) *HTTPStrategy {
+	ws.ResponseHeadersMatcher = matcher
+	return ws
+}
+
+func (ws *HTTPStrategy) WithBasicAuth(username, password string) *HTTPStrategy {
+	ws.UserInfo = url.UserPassword(username, password)
+	return ws
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds
+func (ws *HTTPStrategy) WithPollInterval(pollInterval time.Duration) *HTTPStrategy {
+	ws.PollInterval = pollInterval
+	return ws
+}
+
+// WithForcedIPv4LocalHost forces usage of localhost to be ipv4 127.0.0.1
+// to avoid ipv6 docker bugs https://github.com/moby/moby/issues/42442 https://github.com/moby/moby/issues/42375
+func (ws *HTTPStrategy) WithForcedIPv4LocalHost() *HTTPStrategy {
+	ws.ForceIPv4LocalHost = true
+	return ws
+}
+
+// ForHTTP is a convenience method similar to Wait.java
+// https://github.com/testcontainers/testcontainers-java/blob/1d85a3834bd937f80aad3a4cec249c027f31aeb4/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java
+func ForHTTP(path string) *HTTPStrategy {
+	return NewHTTPStrategy(path)
+}
+
+func (ws *HTTPStrategy) Timeout() *time.Duration {
+	return ws.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ws *HTTPStrategy) String() string {
+	proto := "HTTP"
+	if ws.UseTLS {
+		proto = "HTTPS"
+	}
+
+	port := "default"
+	if !ws.Port.IsZero() {
+		port = ws.Port.Port()
+	}
+
+	return fmt.Sprintf("%s %s request on port %s path %q", proto, ws.Method, port, ws.Path)
+}
+
+// WaitUntilReady implements Strategy.WaitUntilReady
+func (ws *HTTPStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	timeout := defaultStartupTimeout()
+	if ws.timeout != nil {
+		timeout = *ws.timeout
+	}
+
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+
+	ipAddress, err := target.Host(ctx)
+	if err != nil {
+		return err
+	}
+	// to avoid ipv6 docker bugs https://github.com/moby/moby/issues/42442 https://github.com/moby/moby/issues/42375
+	if ws.ForceIPv4LocalHost {
+		ipAddress = strings.Replace(ipAddress, "localhost", "127.0.0.1", 1)
+	}
+
+	var mappedPort network.Port
+	if ws.Port.IsZero() {
+		// No specific port requested; inspect container to find lowest exposed TCP port.
+		// We wait one polling interval before we grab the ports
+		// otherwise they might not be bound yet on startup.
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		case <-time.After(ws.PollInterval):
+			// Port should now be bound so just continue.
+		}
+
+		if err := checkTarget(ctx, target); err != nil {
+			return err
+		}
+
+		inspect, err := target.Inspect(ctx)
+		if err != nil {
+			return err
+		}
+
+		// Find the lowest numbered exposed tcp port.
+		var lowestPort network.Port
+		var hostPort string
+		for port, bindings := range inspect.NetworkSettings.Ports {
+			if len(bindings) == 0 || port.Proto() != "tcp" {
+				continue
+			}
+
+			if lowestPort.IsZero() || port.Num() < lowestPort.Num() {
+				lowestPort = port
+				hostPort = bindings[0].HostPort
+			}
+		}
+
+		if lowestPort.IsZero() {
+			return errors.New("no exposed tcp ports or mapped ports - cannot wait for status")
+		}
+
+		hPort, _ := strconv.ParseUint(hostPort, 10, 16)
+		mappedPort, _ = network.PortFrom(uint16(hPort), lowestPort.Proto())
+	} else {
+		// Specific port requested; use MappedPort to resolve it.
+		mappedPort, err = target.MappedPort(ctx, ws.Port.String())
+		for mappedPort.IsZero() {
+			select {
+			case <-ctx.Done():
+				return fmt.Errorf("%w: %w", ctx.Err(), err)
+			case <-time.After(ws.PollInterval):
+				if err := checkTarget(ctx, target); err != nil {
+					return err
+				}
+
+				mappedPort, err = target.MappedPort(ctx, ws.Port.String())
+			}
+		}
+
+		if mappedPort.Proto() != "tcp" {
+			return errors.New("cannot use HTTP client on non-TCP ports")
+		}
+	}
+
+	switch ws.Method {
+	case http.MethodGet, http.MethodHead, http.MethodPost,
+		http.MethodPut, http.MethodPatch, http.MethodDelete,
+		http.MethodConnect, http.MethodOptions, http.MethodTrace:
+	default:
+		if ws.Method != "" {
+			return fmt.Errorf("invalid http method %q", ws.Method)
+		}
+		ws.Method = http.MethodGet
+	}
+
+	tripper := &http.Transport{
+		Proxy: http.ProxyFromEnvironment,
+		DialContext: (&net.Dialer{
+			Timeout:   time.Second,
+			KeepAlive: 30 * time.Second,
+			DualStack: true,
+		}).DialContext,
+		ForceAttemptHTTP2:     true,
+		MaxIdleConns:          100,
+		IdleConnTimeout:       90 * time.Second,
+		TLSHandshakeTimeout:   10 * time.Second,
+		ExpectContinueTimeout: 1 * time.Second,
+		TLSClientConfig:       ws.TLSConfig,
+	}
+
+	var proto string
+	if ws.UseTLS {
+		proto = "https"
+		if ws.AllowInsecure {
+			if ws.TLSConfig == nil {
+				tripper.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
+			} else {
+				ws.TLSConfig.InsecureSkipVerify = true
+			}
+		}
+	} else {
+		proto = "http"
+	}
+
+	client := http.Client{Transport: tripper, Timeout: time.Second}
+	address := net.JoinHostPort(ipAddress, mappedPort.Port())
+
+	endpoint, err := url.Parse(ws.Path)
+	if err != nil {
+		return err
+	}
+	endpoint.Scheme = proto
+	endpoint.Host = address
+
+	if ws.UserInfo != nil {
+		endpoint.User = ws.UserInfo
+	}
+
+	// cache the body into a byte-slice so that it can be iterated over multiple times
+	var body []byte
+	if ws.Body != nil {
+		body, err = io.ReadAll(ws.Body)
+		if err != nil {
+			return err
+		}
+	}
+
+	for {
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		case <-time.After(ws.PollInterval):
+			if err := checkTarget(ctx, target); err != nil {
+				return err
+			}
+			req, err := http.NewRequestWithContext(ctx, ws.Method, endpoint.String(), bytes.NewReader(body))
+			if err != nil {
+				return err
+			}
+
+			for k, v := range ws.Headers {
+				req.Header.Set(k, v)
+			}
+
+			resp, err := client.Do(req)
+			if err != nil {
+				continue
+			}
+			if ws.StatusCodeMatcher != nil && !ws.StatusCodeMatcher(resp.StatusCode) {
+				_ = resp.Body.Close()
+				continue
+			}
+			if ws.ResponseMatcher != nil && !ws.ResponseMatcher(resp.Body) {
+				_ = resp.Body.Close()
+				continue
+			}
+			if ws.ResponseHeadersMatcher != nil && !ws.ResponseHeadersMatcher(resp.Header) {
+				_ = resp.Body.Close()
+				continue
+			}
+			if err := resp.Body.Close(); err != nil {
+				continue
+			}
+			return nil
+		}
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/log.go b/vendor/github.com/testcontainers/testcontainers-go/wait/log.go
new file mode 100644
index 000000000..11113dc92
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/log.go
@@ -0,0 +1,229 @@
+package wait
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"regexp"
+	"time"
+)
+
+// Implement interface
+var (
+	_ Strategy        = (*LogStrategy)(nil)
+	_ StrategyTimeout = (*LogStrategy)(nil)
+)
+
+// PermanentError is a special error that will stop the wait and return an error.
+type PermanentError struct {
+	err error
+}
+
+// Error implements the error interface.
+func (e *PermanentError) Error() string {
+	return e.err.Error()
+}
+
+// NewPermanentError creates a new PermanentError.
+func NewPermanentError(err error) *PermanentError {
+	return &PermanentError{err: err}
+}
+
+// LogStrategy will wait until a given log entry shows up in the docker logs
+type LogStrategy struct {
+	// all Strategies should have a startupTimeout to avoid waiting infinitely
+	timeout *time.Duration
+
+	// additional properties
+	Log          string
+	IsRegexp     bool
+	Occurrence   int
+	PollInterval time.Duration
+
+	// check is the function that will be called to check if the log entry is present.
+	check func([]byte) error
+
+	// submatchCallback is a callback that will be called with the sub matches of the regexp.
+	submatchCallback func(pattern string, matches [][][]byte) error
+
+	// re is the optional compiled regexp.
+	re *regexp.Regexp
+
+	// log byte slice version of [LogStrategy.Log] used for count checks.
+	log []byte
+}
+
+// NewLogStrategy constructs with polling interval of 100 milliseconds and startup timeout of 60 seconds by default
+func NewLogStrategy(log string) *LogStrategy {
+	return &LogStrategy{
+		Log:          log,
+		IsRegexp:     false,
+		Occurrence:   1,
+		PollInterval: defaultPollInterval(),
+	}
+}
+
+// fluent builders for each property
+// since go has neither covariance nor generics, the return type must be the type of the concrete implementation
+// this is true for all properties, even the "shared" ones like startupTimeout
+
+// AsRegexp can be used to change the default behavior of the log strategy to use regexp instead of plain text
+func (ws *LogStrategy) AsRegexp() *LogStrategy {
+	ws.IsRegexp = true
+	return ws
+}
+
+// Submatch configures a function that will be called with the result of
+// [regexp.Regexp.FindAllSubmatch], allowing the caller to process the results.
+// If the callback returns nil, the strategy will be considered successful.
+// Returning a [PermanentError] will stop the wait and return an error, otherwise
+// it will retry until the timeout is reached.
+// [LogStrategy.Occurrence] is ignored if this option is set.
+func (ws *LogStrategy) Submatch(callback func(pattern string, matches [][][]byte) error) *LogStrategy {
+	ws.submatchCallback = callback
+
+	return ws
+}
+
+// WithStartupTimeout can be used to change the default startup timeout
+func (ws *LogStrategy) WithStartupTimeout(timeout time.Duration) *LogStrategy {
+	ws.timeout = &timeout
+	return ws
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds
+func (ws *LogStrategy) WithPollInterval(pollInterval time.Duration) *LogStrategy {
+	ws.PollInterval = pollInterval
+	return ws
+}
+
+func (ws *LogStrategy) WithOccurrence(o int) *LogStrategy {
+	// the number of occurrence needs to be positive
+	if o <= 0 {
+		o = 1
+	}
+	ws.Occurrence = o
+	return ws
+}
+
+// ForLog is the default construction for the fluid interface.
+//
+// For Example:
+//
+//	wait.
+//		ForLog("some text").
+//		WithPollInterval(1 * time.Second)
+func ForLog(log string) *LogStrategy {
+	return NewLogStrategy(log)
+}
+
+func (ws *LogStrategy) Timeout() *time.Duration {
+	return ws.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ws *LogStrategy) String() string {
+	logType := "log message"
+	if ws.IsRegexp {
+		logType = "log pattern"
+	}
+
+	occurrence := ""
+	if ws.Occurrence > 1 {
+		occurrence = fmt.Sprintf(" (occurrence: %d)", ws.Occurrence)
+	}
+
+	return fmt.Sprintf("%s %q%s", logType, ws.Log, occurrence)
+}
+
+// WaitUntilReady implements Strategy.WaitUntilReady
+func (ws *LogStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	timeout := defaultStartupTimeout()
+	if ws.timeout != nil {
+		timeout = *ws.timeout
+	}
+
+	switch {
+	case ws.submatchCallback != nil:
+		ws.re = regexp.MustCompile(ws.Log)
+		ws.check = ws.checkSubmatch
+	case ws.IsRegexp:
+		ws.re = regexp.MustCompile(ws.Log)
+		ws.check = ws.checkRegexp
+	default:
+		ws.log = []byte(ws.Log)
+		ws.check = ws.checkCount
+	}
+
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+
+	var lastLen int
+	var lastError error
+	for {
+		select {
+		case <-ctx.Done():
+			return errors.Join(lastError, ctx.Err())
+		default:
+			checkErr := checkTarget(ctx, target)
+
+			reader, err := target.Logs(ctx)
+			if err != nil {
+				// TODO: fix as this will wait for timeout if the logs are not available.
+				time.Sleep(ws.PollInterval)
+				continue
+			}
+
+			b, err := io.ReadAll(reader)
+			if err != nil {
+				// TODO: fix as this will wait for timeout if the logs are not readable.
+				time.Sleep(ws.PollInterval)
+				continue
+			}
+
+			if lastLen == len(b) && checkErr != nil {
+				// Log length hasn't changed so we're not making progress.
+				return checkErr
+			}
+
+			if err := ws.check(b); err != nil {
+				var errPermanent *PermanentError
+				if errors.As(err, &errPermanent) {
+					return err
+				}
+
+				lastError = err
+				lastLen = len(b)
+				time.Sleep(ws.PollInterval)
+				continue
+			}
+
+			return nil
+		}
+	}
+}
+
+// checkCount checks if the log entry is present in the logs using a string count.
+func (ws *LogStrategy) checkCount(b []byte) error {
+	if count := bytes.Count(b, ws.log); count < ws.Occurrence {
+		return fmt.Errorf("%q matched %d times, expected %d", ws.Log, count, ws.Occurrence)
+	}
+
+	return nil
+}
+
+// checkRegexp checks if the log entry is present in the logs using a regexp count.
+func (ws *LogStrategy) checkRegexp(b []byte) error {
+	if matches := ws.re.FindAll(b, -1); len(matches) < ws.Occurrence {
+		return fmt.Errorf("`%s` matched %d times, expected %d", ws.Log, len(matches), ws.Occurrence)
+	}
+
+	return nil
+}
+
+// checkSubmatch checks if the log entry is present in the logs using a regexp sub match callback.
+func (ws *LogStrategy) checkSubmatch(b []byte) error {
+	return ws.submatchCallback(ws.Log, ws.re.FindAllSubmatch(b, -1))
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/nop.go b/vendor/github.com/testcontainers/testcontainers-go/wait/nop.go
new file mode 100644
index 000000000..8a23e7ea6
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/nop.go
@@ -0,0 +1,89 @@
+package wait
+
+import (
+	"context"
+	"io"
+	"time"
+
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+
+	"github.com/testcontainers/testcontainers-go/exec"
+)
+
+var (
+	_ Strategy        = (*NopStrategy)(nil)
+	_ StrategyTimeout = (*NopStrategy)(nil)
+)
+
+type NopStrategy struct {
+	timeout        *time.Duration
+	waitUntilReady func(context.Context, StrategyTarget) error
+}
+
+func ForNop(
+	waitUntilReady func(context.Context, StrategyTarget) error,
+) *NopStrategy {
+	return &NopStrategy{
+		waitUntilReady: waitUntilReady,
+	}
+}
+
+func (ws *NopStrategy) Timeout() *time.Duration {
+	return ws.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ws *NopStrategy) String() string {
+	return "custom wait condition"
+}
+
+func (ws *NopStrategy) WithStartupTimeout(timeout time.Duration) *NopStrategy {
+	ws.timeout = &timeout
+	return ws
+}
+
+func (ws *NopStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	return ws.waitUntilReady(ctx, target)
+}
+
+type NopStrategyTarget struct {
+	ReaderCloser   io.ReadCloser
+	ContainerState container.State
+}
+
+func (st NopStrategyTarget) Host(_ context.Context) (string, error) {
+	return "", nil
+}
+
+func (st NopStrategyTarget) Inspect(_ context.Context) (*container.InspectResponse, error) {
+	return nil, nil
+}
+
+// Deprecated: use Inspect instead
+func (st NopStrategyTarget) Ports(_ context.Context) (network.PortMap, error) {
+	return nil, nil
+}
+
+func (st NopStrategyTarget) MappedPort(_ context.Context, n string) (network.Port, error) {
+	if n == "" {
+		return network.Port{}, nil
+	}
+	return network.ParsePort(n)
+}
+
+func (st NopStrategyTarget) Logs(_ context.Context) (io.ReadCloser, error) {
+	return st.ReaderCloser, nil
+}
+
+func (st NopStrategyTarget) Exec(_ context.Context, _ []string, _ ...exec.ProcessOption) (int, io.Reader, error) {
+	return 0, nil, nil
+}
+
+func (st NopStrategyTarget) State(_ context.Context) (*container.State, error) {
+	return &st.ContainerState, nil
+}
+
+func (st NopStrategyTarget) CopyFileFromContainer(context.Context, string) (io.ReadCloser, error) {
+	return st.ReaderCloser, nil
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/sql.go b/vendor/github.com/testcontainers/testcontainers-go/wait/sql.go
new file mode 100644
index 000000000..e328be288
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/sql.go
@@ -0,0 +1,136 @@
+package wait
+
+import (
+	"context"
+	"database/sql"
+	"fmt"
+	"time"
+
+	"github.com/moby/moby/api/types/network"
+)
+
+var (
+	_ Strategy        = (*waitForSQL)(nil)
+	_ StrategyTimeout = (*waitForSQL)(nil)
+)
+
+const defaultForSQLQuery = "SELECT 1"
+
+// ForSQL constructs a new waitForSql strategy for the given driver
+func ForSQL(port string, driver string, url func(host string, port network.Port) string) *waitForSQL {
+	return &waitForSQL{
+		Port:           port,
+		URL:            url,
+		Driver:         driver,
+		startupTimeout: defaultStartupTimeout(),
+		PollInterval:   defaultPollInterval(),
+		query:          defaultForSQLQuery,
+	}
+}
+
+type waitForSQL struct {
+	timeout *time.Duration
+
+	URL            func(host string, port network.Port) string
+	Driver         string
+	Port           string
+	startupTimeout time.Duration
+	PollInterval   time.Duration
+	query          string
+}
+
+// WithStartupTimeout can be used to change the default startup timeout
+func (w *waitForSQL) WithStartupTimeout(timeout time.Duration) *waitForSQL {
+	w.timeout = &timeout
+	return w
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds
+func (w *waitForSQL) WithPollInterval(pollInterval time.Duration) *waitForSQL {
+	w.PollInterval = pollInterval
+	return w
+}
+
+// WithQuery can be used to override the default query used in the strategy.
+func (w *waitForSQL) WithQuery(query string) *waitForSQL {
+	w.query = query
+	return w
+}
+
+func (w *waitForSQL) Timeout() *time.Duration {
+	return w.timeout
+}
+
+// String returns a human-readable description of the wait strategy.
+func (w *waitForSQL) String() string {
+	port := "default"
+	if w.Port != "" {
+		p, err := network.ParsePort(w.Port)
+		if err == nil {
+			port = p.Port()
+		}
+	}
+
+	query := ""
+	if w.query != defaultForSQLQuery {
+		query = fmt.Sprintf(" with query %q", w.query)
+	}
+
+	return fmt.Sprintf("SQL database on port %s using driver %q%s", port, w.Driver, query)
+}
+
+// WaitUntilReady repeatedly tries to run "SELECT 1" or user defined query on the given port using sql and driver.
+//
+// If it doesn't succeed until the timeout value which defaults to 60 seconds, it will return an error.
+func (w *waitForSQL) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	timeout := defaultStartupTimeout()
+	if w.timeout != nil {
+		timeout = *w.timeout
+	}
+
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+
+	host, err := target.Host(ctx)
+	if err != nil {
+		return err
+	}
+
+	ticker := time.NewTicker(w.PollInterval)
+	defer ticker.Stop()
+
+	var port network.Port
+	port, err = target.MappedPort(ctx, w.Port)
+
+	for port.IsZero() {
+		select {
+		case <-ctx.Done():
+			return fmt.Errorf("%w: %w", ctx.Err(), err)
+		case <-ticker.C:
+			if err := checkTarget(ctx, target); err != nil {
+				return err
+			}
+			port, err = target.MappedPort(ctx, w.Port)
+		}
+	}
+
+	db, err := sql.Open(w.Driver, w.URL(host, port))
+	if err != nil {
+		return fmt.Errorf("sql.Open: %w", err)
+	}
+	defer db.Close()
+	for {
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		case <-ticker.C:
+			if err := checkTarget(ctx, target); err != nil {
+				return err
+			}
+			if _, err := db.ExecContext(ctx, w.query); err != nil {
+				continue
+			}
+			return nil
+		}
+	}
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/tls.go b/vendor/github.com/testcontainers/testcontainers-go/wait/tls.go
new file mode 100644
index 000000000..617f55940
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/tls.go
@@ -0,0 +1,187 @@
+package wait
+
+import (
+	"context"
+	"crypto/tls"
+	"crypto/x509"
+	"fmt"
+	"io"
+	"strings"
+	"time"
+)
+
+// Validate we implement interface.
+var _ Strategy = (*TLSStrategy)(nil)
+
+// TLSStrategy is a strategy for handling TLS.
+type TLSStrategy struct {
+	// General Settings.
+	timeout      *time.Duration
+	pollInterval time.Duration
+
+	// Custom Settings.
+	certFiles *x509KeyPair
+	rootFiles []string
+
+	// State.
+	tlsConfig *tls.Config
+}
+
+// x509KeyPair is a pair of certificate and key files.
+type x509KeyPair struct {
+	certPEMFile string
+	keyPEMFile  string
+}
+
+// ForTLSCert returns a CertStrategy that will add a Certificate to the [tls.Config]
+// constructed from PEM formatted certificate key file pair in the container.
+func ForTLSCert(certPEMFile, keyPEMFile string) *TLSStrategy {
+	return &TLSStrategy{
+		certFiles: &x509KeyPair{
+			certPEMFile: certPEMFile,
+			keyPEMFile:  keyPEMFile,
+		},
+		tlsConfig:    &tls.Config{},
+		pollInterval: defaultPollInterval(),
+	}
+}
+
+// ForTLSRootCAs returns a CertStrategy that sets the root CAs for the [tls.Config]
+// using the given PEM formatted files from the container.
+func ForTLSRootCAs(pemFiles ...string) *TLSStrategy {
+	return &TLSStrategy{
+		rootFiles:    pemFiles,
+		tlsConfig:    &tls.Config{},
+		pollInterval: defaultPollInterval(),
+	}
+}
+
+// WithRootCAs sets the root CAs for the [tls.Config] using the given files from
+// the container.
+func (ws *TLSStrategy) WithRootCAs(files ...string) *TLSStrategy {
+	ws.rootFiles = files
+	return ws
+}
+
+// WithCert sets the [tls.Config] Certificates using the given files from the container.
+func (ws *TLSStrategy) WithCert(certPEMFile, keyPEMFile string) *TLSStrategy {
+	ws.certFiles = &x509KeyPair{
+		certPEMFile: certPEMFile,
+		keyPEMFile:  keyPEMFile,
+	}
+	return ws
+}
+
+// WithServerName sets the server for the [tls.Config].
+func (ws *TLSStrategy) WithServerName(serverName string) *TLSStrategy {
+	ws.tlsConfig.ServerName = serverName
+	return ws
+}
+
+// WithStartupTimeout can be used to change the default startup timeout.
+func (ws *TLSStrategy) WithStartupTimeout(startupTimeout time.Duration) *TLSStrategy {
+	ws.timeout = &startupTimeout
+	return ws
+}
+
+// WithPollInterval can be used to override the default polling interval of 100 milliseconds.
+func (ws *TLSStrategy) WithPollInterval(pollInterval time.Duration) *TLSStrategy {
+	ws.pollInterval = pollInterval
+	return ws
+}
+
+// TLSConfig returns the TLS config once the strategy is ready.
+// If the strategy is nil, it returns nil.
+func (ws *TLSStrategy) TLSConfig() *tls.Config {
+	if ws == nil {
+		return nil
+	}
+
+	return ws.tlsConfig
+}
+
+// String returns a human-readable description of the wait strategy.
+func (ws *TLSStrategy) String() string {
+	var parts []string
+
+	if len(ws.rootFiles) > 0 {
+		parts = append(parts, fmt.Sprintf("root CAs %v", ws.rootFiles))
+	}
+
+	if ws.certFiles != nil {
+		parts = append(parts, fmt.Sprintf("cert %q and key %q", ws.certFiles.certPEMFile, ws.certFiles.keyPEMFile))
+	}
+
+	if len(parts) == 0 {
+		return "TLS certificates"
+	}
+
+	return strings.Join(parts, " and ")
+}
+
+// WaitUntilReady implements the [Strategy] interface.
+// It waits for the CA, client cert and key files to be available in the container and
+// uses them to setup the TLS config.
+func (ws *TLSStrategy) WaitUntilReady(ctx context.Context, target StrategyTarget) error {
+	size := len(ws.rootFiles)
+	if ws.certFiles != nil {
+		size += 2
+	}
+	strategies := make([]Strategy, 0, size)
+	for _, file := range ws.rootFiles {
+		strategies = append(strategies,
+			ForFile(file).WithMatcher(func(r io.Reader) error {
+				buf, err := io.ReadAll(r)
+				if err != nil {
+					return fmt.Errorf("read CA cert file %q: %w", file, err)
+				}
+
+				if ws.tlsConfig.RootCAs == nil {
+					ws.tlsConfig.RootCAs = x509.NewCertPool()
+				}
+
+				if !ws.tlsConfig.RootCAs.AppendCertsFromPEM(buf) {
+					return fmt.Errorf("invalid CA cert file %q", file)
+				}
+
+				return nil
+			}).WithPollInterval(ws.pollInterval),
+		)
+	}
+
+	if ws.certFiles != nil {
+		var certPEMBlock []byte
+		strategies = append(strategies,
+			ForFile(ws.certFiles.certPEMFile).WithMatcher(func(r io.Reader) error {
+				var err error
+				if certPEMBlock, err = io.ReadAll(r); err != nil {
+					return fmt.Errorf("read certificate cert %q: %w", ws.certFiles.certPEMFile, err)
+				}
+
+				return nil
+			}).WithPollInterval(ws.pollInterval),
+			ForFile(ws.certFiles.keyPEMFile).WithMatcher(func(r io.Reader) error {
+				keyPEMBlock, err := io.ReadAll(r)
+				if err != nil {
+					return fmt.Errorf("read certificate key %q: %w", ws.certFiles.keyPEMFile, err)
+				}
+
+				cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
+				if err != nil {
+					return fmt.Errorf("x509 key pair %q %q: %w", ws.certFiles.certPEMFile, ws.certFiles.keyPEMFile, err)
+				}
+
+				ws.tlsConfig.Certificates = []tls.Certificate{cert}
+
+				return nil
+			}).WithPollInterval(ws.pollInterval),
+		)
+	}
+
+	strategy := ForAll(strategies...)
+	if ws.timeout != nil {
+		strategy.WithStartupTimeout(*ws.timeout)
+	}
+
+	return strategy.WaitUntilReady(ctx, target)
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/wait.go b/vendor/github.com/testcontainers/testcontainers-go/wait/wait.go
new file mode 100644
index 000000000..43485001a
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/wait.go
@@ -0,0 +1,65 @@
+package wait
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"time"
+
+	"github.com/moby/moby/api/types/container"
+	"github.com/moby/moby/api/types/network"
+
+	"github.com/testcontainers/testcontainers-go/exec"
+)
+
+// Strategy defines the basic interface for a Wait Strategy
+type Strategy interface {
+	WaitUntilReady(context.Context, StrategyTarget) error
+}
+
+// StrategyTimeout allows MultiStrategy to configure a Strategy's Timeout
+type StrategyTimeout interface {
+	Timeout() *time.Duration
+}
+
+type StrategyTarget interface {
+	Host(context.Context) (string, error)
+	Inspect(context.Context) (*container.InspectResponse, error)
+	Ports(ctx context.Context) (network.PortMap, error) // Deprecated: use Inspect instead
+	MappedPort(context.Context, string) (network.Port, error)
+	Logs(context.Context) (io.ReadCloser, error)
+	Exec(context.Context, []string, ...exec.ProcessOption) (int, io.Reader, error)
+	State(context.Context) (*container.State, error)
+	CopyFileFromContainer(ctx context.Context, filePath string) (io.ReadCloser, error)
+}
+
+func checkTarget(ctx context.Context, target StrategyTarget) error {
+	state, err := target.State(ctx)
+	if err != nil {
+		return fmt.Errorf("get state: %w", err)
+	}
+
+	return checkState(state)
+}
+
+func checkState(state *container.State) error {
+	switch {
+	case state.Running:
+		return nil
+	case state.OOMKilled:
+		return errors.New("container crashed with out-of-memory (OOMKilled)")
+	case state.Status == container.StateExited:
+		return fmt.Errorf("container exited with code %d", state.ExitCode)
+	default:
+		return fmt.Errorf("unexpected container status %q", state.Status)
+	}
+}
+
+func defaultStartupTimeout() time.Duration {
+	return 60 * time.Second
+}
+
+func defaultPollInterval() time.Duration {
+	return 100 * time.Millisecond
+}
diff --git a/vendor/github.com/testcontainers/testcontainers-go/wait/walk.go b/vendor/github.com/testcontainers/testcontainers-go/wait/walk.go
new file mode 100644
index 000000000..04cb1badc
--- /dev/null
+++ b/vendor/github.com/testcontainers/testcontainers-go/wait/walk.go
@@ -0,0 +1,91 @@
+package wait
+
+import (
+	"errors"
+	"slices"
+)
+
+var (
+	// ErrVisitStop is used as a return value from [VisitFunc] to stop the walk.
+	// It is not returned as an error by any function.
+	ErrVisitStop = errors.New("stop the walk")
+
+	// Deprecated: use [ErrVisitStop] instead.
+	VisitStop = ErrVisitStop
+
+	// ErrVisitRemove is used as a return value from [VisitFunc] to have the current node removed.
+	// It is not returned as an error by any function.
+	ErrVisitRemove = errors.New("remove this strategy")
+
+	// Deprecated: use [ErrVisitRemove] instead.
+	VisitRemove = ErrVisitRemove
+)
+
+// VisitFunc is a function that visits a strategy node.
+// If it returns [ErrVisitStop], the walk stops.
+// If it returns [ErrVisitRemove], the current node is removed.
+type VisitFunc func(root Strategy) error
+
+// Walk walks the strategies tree and calls the visit function for each node.
+func Walk(root *Strategy, visit VisitFunc) error {
+	if root == nil {
+		return errors.New("root strategy is nil")
+	}
+
+	if err := walk(root, visit); err != nil {
+		if errors.Is(err, ErrVisitRemove) || errors.Is(err, ErrVisitStop) {
+			return nil
+		}
+		return err
+	}
+
+	return nil
+}
+
+// walk walks the strategies tree and calls the visit function for each node.
+// It returns an error if the visit function returns an error.
+func walk(root *Strategy, visit VisitFunc) error {
+	if *root == nil {
+		// No strategy.
+		return nil
+	}
+
+	// Allow the visit function to customize the behaviour of the walk before visiting the children.
+	if err := visit(*root); err != nil {
+		if errors.Is(err, ErrVisitRemove) {
+			*root = nil
+		}
+
+		return err
+	}
+
+	switch s := (*root).(type) {
+	case *MultiStrategy:
+		if err := walkAndMutate(&s.Strategies, visit); err != nil {
+			return err
+		}
+	case *AnyMultiStrategy:
+		if err := walkAndMutate(&s.Strategies, visit); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func walkAndMutate(strategies *[]Strategy, visit VisitFunc) error {
+	for i := 0; i < len(*strategies); {
+		if err := walk(&(*strategies)[i], visit); err != nil {
+			if errors.Is(err, ErrVisitRemove) {
+				*strategies = slices.Delete(*strategies, i, i+1)
+				if errors.Is(err, VisitStop) {
+					return VisitStop
+				}
+				continue
+			}
+			return err
+		}
+		i++
+	}
+	return nil
+}
diff --git a/vendor/golang.org/x/crypto/blowfish/block.go b/vendor/golang.org/x/crypto/blowfish/block.go
new file mode 100644
index 000000000..9d80f1952
--- /dev/null
+++ b/vendor/golang.org/x/crypto/blowfish/block.go
@@ -0,0 +1,159 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+// getNextWord returns the next big-endian uint32 value from the byte slice
+// at the given position in a circular manner, updating the position.
+func getNextWord(b []byte, pos *int) uint32 {
+	var w uint32
+	j := *pos
+	for i := 0; i < 4; i++ {
+		w = w<<8 | uint32(b[j])
+		j++
+		if j >= len(b) {
+			j = 0
+		}
+	}
+	*pos = j
+	return w
+}
+
+// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
+// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
+// pi and substitution tables for calls to Encrypt. This is used, primarily,
+// by the bcrypt package to reuse the Blowfish key schedule during its
+// set up. It's unlikely that you need to use this directly.
+func ExpandKey(key []byte, c *Cipher) {
+	j := 0
+	for i := 0; i < 18; i++ {
+		// Using inlined getNextWord for performance.
+		var d uint32
+		for k := 0; k < 4; k++ {
+			d = d<<8 | uint32(key[j])
+			j++
+			if j >= len(key) {
+				j = 0
+			}
+		}
+		c.p[i] ^= d
+	}
+
+	var l, r uint32
+	for i := 0; i < 18; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.p[i], c.p[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s0[i], c.s0[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s1[i], c.s1[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s2[i], c.s2[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s3[i], c.s3[i+1] = l, r
+	}
+}
+
+// This is similar to ExpandKey, but folds the salt during the key
+// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
+// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
+// and specializing it here is useful.
+func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
+	j := 0
+	for i := 0; i < 18; i++ {
+		c.p[i] ^= getNextWord(key, &j)
+	}
+
+	j = 0
+	var l, r uint32
+	for i := 0; i < 18; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.p[i], c.p[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s0[i], c.s0[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s1[i], c.s1[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s2[i], c.s2[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s3[i], c.s3[i+1] = l, r
+	}
+}
+
+func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+	xl, xr := l, r
+	xl ^= c.p[0]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
+	xr ^= c.p[17]
+	return xr, xl
+}
+
+func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+	xl, xr := l, r
+	xl ^= c.p[17]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
+	xr ^= c.p[0]
+	return xr, xl
+}
diff --git a/vendor/golang.org/x/crypto/blowfish/cipher.go b/vendor/golang.org/x/crypto/blowfish/cipher.go
new file mode 100644
index 000000000..089895680
--- /dev/null
+++ b/vendor/golang.org/x/crypto/blowfish/cipher.go
@@ -0,0 +1,99 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
+//
+// Blowfish is a legacy cipher and its short block size makes it vulnerable to
+// birthday bound attacks (see https://sweet32.info). It should only be used
+// where compatibility with legacy systems, not security, is the goal.
+//
+// Deprecated: any new system should use AES (from crypto/aes, if necessary in
+// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
+// golang.org/x/crypto/chacha20poly1305).
+package blowfish
+
+// The code is a port of Bruce Schneier's C implementation.
+// See https://www.schneier.com/blowfish.html.
+
+import "strconv"
+
+// The Blowfish block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of Blowfish encryption using a particular key.
+type Cipher struct {
+	p              [18]uint32
+	s0, s1, s2, s3 [256]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+	return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Blowfish key, from 1 to 56 bytes.
+func NewCipher(key []byte) (*Cipher, error) {
+	var result Cipher
+	if k := len(key); k < 1 || k > 56 {
+		return nil, KeySizeError(k)
+	}
+	initCipher(&result)
+	ExpandKey(key, &result)
+	return &result, nil
+}
+
+// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
+// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
+// sufficient and desirable. For bcrypt compatibility, the key can be over 56
+// bytes.
+func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
+	if len(salt) == 0 {
+		return NewCipher(key)
+	}
+	var result Cipher
+	if k := len(key); k < 1 {
+		return nil, KeySizeError(k)
+	}
+	initCipher(&result)
+	expandKeyWithSalt(key, salt, &result)
+	return &result, nil
+}
+
+// BlockSize returns the Blowfish block size, 8 bytes.
+// It is necessary to satisfy the Block interface in the
+// package "crypto/cipher".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+	l, r = encryptBlock(l, r, c)
+	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Decrypt decrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+	l, r = decryptBlock(l, r, c)
+	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+func initCipher(c *Cipher) {
+	copy(c.p[0:], p[0:])
+	copy(c.s0[0:], s0[0:])
+	copy(c.s1[0:], s1[0:])
+	copy(c.s2[0:], s2[0:])
+	copy(c.s3[0:], s3[0:])
+}
diff --git a/vendor/golang.org/x/crypto/blowfish/const.go b/vendor/golang.org/x/crypto/blowfish/const.go
new file mode 100644
index 000000000..d04077595
--- /dev/null
+++ b/vendor/golang.org/x/crypto/blowfish/const.go
@@ -0,0 +1,199 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The startup permutation array and substitution boxes.
+// They are the hexadecimal digits of PI; see:
+// https://www.schneier.com/code/constants.txt.
+
+package blowfish
+
+var s0 = [256]uint32{
+	0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+	0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+	0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+	0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+	0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+	0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+	0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+	0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+	0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+	0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+	0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+	0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+	0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+	0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+	0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+	0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+	0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+	0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+	0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+	0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+	0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+	0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+	0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+	0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+	0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+	0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+	0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+	0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+	0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+	0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+	0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+	0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+	0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+	0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+	0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+	0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+	0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+	0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+	0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+	0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+	0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+	0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+	0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+}
+
+var s1 = [256]uint32{
+	0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+	0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+	0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+	0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+	0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+	0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+	0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+	0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+	0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+	0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+	0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+	0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+	0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+	0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+	0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+	0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+	0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+	0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+	0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+	0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+	0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+	0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+	0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+	0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+	0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+	0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+	0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+	0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+	0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+	0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+	0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+	0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+	0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+	0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+	0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+	0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+	0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+	0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+	0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+	0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+	0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+	0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+	0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+}
+
+var s2 = [256]uint32{
+	0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+	0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+	0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+	0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+	0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+	0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+	0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+	0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+	0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+	0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+	0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+	0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+	0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+	0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+	0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+	0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+	0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+	0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+	0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+	0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+	0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+	0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+	0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+	0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+	0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+	0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+	0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+	0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+	0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+	0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+	0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+	0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+	0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+	0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+	0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+	0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+	0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+	0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+	0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+	0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+	0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+	0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+	0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+}
+
+var s3 = [256]uint32{
+	0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+	0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+	0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+	0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+	0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+	0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+	0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+	0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+	0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+	0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+	0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+	0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+	0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+	0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+	0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+	0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+	0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+	0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+	0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+	0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+	0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+	0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+	0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+	0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+	0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+	0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+	0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+	0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+	0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+	0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+	0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+	0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+	0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+	0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+	0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+	0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+	0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+	0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+	0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+	0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+	0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+	0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+	0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+}
+
+var p = [18]uint32{
+	0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+	0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+	0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
+}
diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go
new file mode 100644
index 000000000..048faef3a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/curve25519.go
@@ -0,0 +1,93 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package curve25519 provides an implementation of the X25519 function, which
+// performs scalar multiplication on the elliptic curve known as Curve25519
+// according to [RFC 7748].
+//
+// The curve25519 package is a wrapper for the X25519 implementation in the
+// crypto/ecdh package. It is [frozen] and is not accepting new features.
+//
+// [RFC 7748]: https://datatracker.ietf.org/doc/html/rfc7748
+// [frozen]: https://go.dev/wiki/Frozen
+package curve25519
+
+import "crypto/ecdh"
+
+// ScalarMult sets dst to the product scalar * point.
+//
+// Deprecated: when provided a low-order point, ScalarMult will set dst to all
+// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
+// will return an error.
+func ScalarMult(dst, scalar, point *[32]byte) {
+	if _, err := x25519(dst, scalar[:], point[:]); err != nil {
+		// The only error condition for x25519 when the inputs are 32 bytes long
+		// is if the output would have been the all-zero value.
+		for i := range dst {
+			dst[i] = 0
+		}
+	}
+}
+
+// ScalarBaseMult sets dst to the product scalar * base where base is the
+// standard generator.
+//
+// It is recommended to use the X25519 function with Basepoint instead, as
+// copying into fixed size arrays can lead to unexpected bugs.
+func ScalarBaseMult(dst, scalar *[32]byte) {
+	curve := ecdh.X25519()
+	priv, err := curve.NewPrivateKey(scalar[:])
+	if err != nil {
+		panic("curve25519: " + err.Error())
+	}
+	copy(dst[:], priv.PublicKey().Bytes())
+}
+
+const (
+	// ScalarSize is the size of the scalar input to X25519.
+	ScalarSize = 32
+	// PointSize is the size of the point input to X25519.
+	PointSize = 32
+)
+
+// Basepoint is the canonical Curve25519 generator.
+var Basepoint []byte
+
+var basePoint = [32]byte{9}
+
+func init() { Basepoint = basePoint[:] }
+
+// X25519 returns the result of the scalar multiplication (scalar * point),
+// according to RFC 7748, Section 5. scalar, point and the return value are
+// slices of 32 bytes.
+//
+// scalar can be generated at random, for example with crypto/rand. point should
+// be either Basepoint or the output of another X25519 call.
+//
+// If point is Basepoint (but not if it's a different slice with the same
+// contents) a precomputed implementation might be used for performance.
+func X25519(scalar, point []byte) ([]byte, error) {
+	// Outline the body of function, to let the allocation be inlined in the
+	// caller, and possibly avoid escaping to the heap.
+	var dst [32]byte
+	return x25519(&dst, scalar, point)
+}
+
+func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
+	curve := ecdh.X25519()
+	pub, err := curve.NewPublicKey(point)
+	if err != nil {
+		return nil, err
+	}
+	priv, err := curve.NewPrivateKey(scalar)
+	if err != nil {
+		return nil, err
+	}
+	out, err := priv.ECDH(pub)
+	if err != nil {
+		return nil, err
+	}
+	copy(dst[:], out)
+	return dst[:], nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/buffer.go b/vendor/golang.org/x/crypto/ssh/buffer.go
new file mode 100644
index 000000000..1ab07d078
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/buffer.go
@@ -0,0 +1,97 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"io"
+	"sync"
+)
+
+// buffer provides a linked list buffer for data exchange
+// between producer and consumer. Theoretically the buffer is
+// of unlimited capacity as it does no allocation of its own.
+type buffer struct {
+	// protects concurrent access to head, tail and closed
+	*sync.Cond
+
+	head *element // the buffer that will be read first
+	tail *element // the buffer that will be read last
+
+	closed bool
+}
+
+// An element represents a single link in a linked list.
+type element struct {
+	buf  []byte
+	next *element
+}
+
+// newBuffer returns an empty buffer that is not closed.
+func newBuffer() *buffer {
+	e := new(element)
+	b := &buffer{
+		Cond: newCond(),
+		head: e,
+		tail: e,
+	}
+	return b
+}
+
+// write makes buf available for Read to receive.
+// buf must not be modified after the call to write.
+func (b *buffer) write(buf []byte) {
+	b.Cond.L.Lock()
+	e := &element{buf: buf}
+	b.tail.next = e
+	b.tail = e
+	b.Cond.Signal()
+	b.Cond.L.Unlock()
+}
+
+// eof closes the buffer. Reads from the buffer once all
+// the data has been consumed will receive io.EOF.
+func (b *buffer) eof() {
+	b.Cond.L.Lock()
+	b.closed = true
+	b.Cond.Signal()
+	b.Cond.L.Unlock()
+}
+
+// Read reads data from the internal buffer in buf.  Reads will block
+// if no data is available, or until the buffer is closed.
+func (b *buffer) Read(buf []byte) (n int, err error) {
+	b.Cond.L.Lock()
+	defer b.Cond.L.Unlock()
+
+	for len(buf) > 0 {
+		// if there is data in b.head, copy it
+		if len(b.head.buf) > 0 {
+			r := copy(buf, b.head.buf)
+			buf, b.head.buf = buf[r:], b.head.buf[r:]
+			n += r
+			continue
+		}
+		// if there is a next buffer, make it the head
+		if len(b.head.buf) == 0 && b.head != b.tail {
+			b.head = b.head.next
+			continue
+		}
+
+		// if at least one byte has been copied, return
+		if n > 0 {
+			break
+		}
+
+		// if nothing was read, and there is nothing outstanding
+		// check to see if the buffer is closed.
+		if b.closed {
+			err = io.EOF
+			break
+		}
+		// out of buffers, wait for producer
+		b.Cond.Wait()
+	}
+	return
+}
diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go
new file mode 100644
index 000000000..6f75d77ec
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/certs.go
@@ -0,0 +1,640 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"sort"
+	"time"
+)
+
+// Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear
+// in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms.
+// Unlike key algorithm names, these are not passed to AlgorithmSigner nor
+// returned by MultiAlgorithmSigner and don't appear in the Signature.Format
+// field.
+const (
+	CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
+	// Deprecated: DSA is only supported at insecure key sizes, and was removed
+	// from major implementations.
+	CertAlgoDSAv01 = InsecureCertAlgoDSAv01
+	// Deprecated: DSA is only supported at insecure key sizes, and was removed
+	// from major implementations.
+	InsecureCertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
+	CertAlgoECDSA256v01    = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
+	CertAlgoECDSA384v01    = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
+	CertAlgoECDSA521v01    = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
+	CertAlgoSKECDSA256v01  = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
+	CertAlgoED25519v01     = "ssh-ed25519-cert-v01@openssh.com"
+	CertAlgoSKED25519v01   = "sk-ssh-ed25519-cert-v01@openssh.com"
+
+	// CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a
+	// Certificate.Type (or PublicKey.Type), but only in
+	// ClientConfig.HostKeyAlgorithms.
+	CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com"
+	CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com"
+)
+
+const (
+	// Deprecated: use CertAlgoRSAv01.
+	CertSigAlgoRSAv01 = CertAlgoRSAv01
+	// Deprecated: use CertAlgoRSASHA256v01.
+	CertSigAlgoRSASHA2256v01 = CertAlgoRSASHA256v01
+	// Deprecated: use CertAlgoRSASHA512v01.
+	CertSigAlgoRSASHA2512v01 = CertAlgoRSASHA512v01
+)
+
+// Certificate types distinguish between host and user
+// certificates. The values can be set in the CertType field of
+// Certificate.
+const (
+	UserCert = 1
+	HostCert = 2
+)
+
+// Signature represents a cryptographic signature.
+type Signature struct {
+	Format string
+	Blob   []byte
+	Rest   []byte `ssh:"rest"`
+}
+
+// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
+// a certificate does not expire.
+const CertTimeInfinity = 1<<64 - 1
+
+// An Certificate represents an OpenSSH certificate as defined in
+// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the
+// PublicKey interface, so it can be unmarshaled using
+// ParsePublicKey.
+type Certificate struct {
+	Nonce           []byte
+	Key             PublicKey
+	Serial          uint64
+	CertType        uint32
+	KeyId           string
+	ValidPrincipals []string
+	ValidAfter      uint64
+	ValidBefore     uint64
+	Permissions
+	Reserved     []byte
+	SignatureKey PublicKey
+	Signature    *Signature
+}
+
+// genericCertData holds the key-independent part of the certificate data.
+// Overall, certificates contain an nonce, public key fields and
+// key-independent fields.
+type genericCertData struct {
+	Serial          uint64
+	CertType        uint32
+	KeyId           string
+	ValidPrincipals []byte
+	ValidAfter      uint64
+	ValidBefore     uint64
+	CriticalOptions []byte
+	Extensions      []byte
+	Reserved        []byte
+	SignatureKey    []byte
+	Signature       []byte
+}
+
+func marshalStringList(namelist []string) []byte {
+	var to []byte
+	for _, name := range namelist {
+		s := struct{ N string }{name}
+		to = append(to, Marshal(&s)...)
+	}
+	return to
+}
+
+type optionsTuple struct {
+	Key   string
+	Value []byte
+}
+
+type optionsTupleValue struct {
+	Value string
+}
+
+// serialize a map of critical options or extensions
+// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
+// we need two length prefixes for a non-empty string value
+func marshalTuples(tups map[string]string) []byte {
+	keys := make([]string, 0, len(tups))
+	for key := range tups {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+
+	var ret []byte
+	for _, key := range keys {
+		s := optionsTuple{Key: key}
+		if value := tups[key]; len(value) > 0 {
+			s.Value = Marshal(&optionsTupleValue{value})
+		}
+		ret = append(ret, Marshal(&s)...)
+	}
+	return ret
+}
+
+// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
+// we need two length prefixes for a non-empty option value
+func parseTuples(in []byte) (map[string]string, error) {
+	tups := map[string]string{}
+	var lastKey string
+	var haveLastKey bool
+
+	for len(in) > 0 {
+		var key, val, extra []byte
+		var ok bool
+
+		if key, in, ok = parseString(in); !ok {
+			return nil, errShortRead
+		}
+		keyStr := string(key)
+		// according to [PROTOCOL.certkeys], the names must be in
+		// lexical order.
+		if haveLastKey && keyStr <= lastKey {
+			return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
+		}
+		lastKey, haveLastKey = keyStr, true
+		// the next field is a data field, which if non-empty has a string embedded
+		if val, in, ok = parseString(in); !ok {
+			return nil, errShortRead
+		}
+		if len(val) > 0 {
+			val, extra, ok = parseString(val)
+			if !ok {
+				return nil, errShortRead
+			}
+			if len(extra) > 0 {
+				return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
+			}
+			tups[keyStr] = string(val)
+		} else {
+			tups[keyStr] = ""
+		}
+	}
+	return tups, nil
+}
+
+func parseCert(in []byte, privAlgo string) (*Certificate, error) {
+	nonce, rest, ok := parseString(in)
+	if !ok {
+		return nil, errShortRead
+	}
+
+	key, rest, err := parsePubKey(rest, privAlgo)
+	if err != nil {
+		return nil, err
+	}
+
+	var g genericCertData
+	if err := Unmarshal(rest, &g); err != nil {
+		return nil, err
+	}
+
+	c := &Certificate{
+		Nonce:       nonce,
+		Key:         key,
+		Serial:      g.Serial,
+		CertType:    g.CertType,
+		KeyId:       g.KeyId,
+		ValidAfter:  g.ValidAfter,
+		ValidBefore: g.ValidBefore,
+	}
+
+	for principals := g.ValidPrincipals; len(principals) > 0; {
+		principal, rest, ok := parseString(principals)
+		if !ok {
+			return nil, errShortRead
+		}
+		c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
+		principals = rest
+	}
+
+	c.CriticalOptions, err = parseTuples(g.CriticalOptions)
+	if err != nil {
+		return nil, err
+	}
+	c.Extensions, err = parseTuples(g.Extensions)
+	if err != nil {
+		return nil, err
+	}
+	c.Reserved = g.Reserved
+	k, err := ParsePublicKey(g.SignatureKey)
+	if err != nil {
+		return nil, err
+	}
+	// The Type() function is intended to return only certificate key types, but
+	// we use certKeyAlgoNames anyway for safety, to match [Certificate.Type].
+	if _, ok := certKeyAlgoNames[k.Type()]; ok {
+		return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", k.Type())
+	}
+	c.SignatureKey = k
+	c.Signature, rest, ok = parseSignatureBody(g.Signature)
+	if !ok || len(rest) > 0 {
+		return nil, errors.New("ssh: signature parse error")
+	}
+
+	return c, nil
+}
+
+type openSSHCertSigner struct {
+	pub    *Certificate
+	signer Signer
+}
+
+type algorithmOpenSSHCertSigner struct {
+	*openSSHCertSigner
+	algorithmSigner AlgorithmSigner
+}
+
+// NewCertSigner returns a Signer that signs with the given Certificate, whose
+// private key is held by signer. It returns an error if the public key in cert
+// doesn't match the key used by signer.
+func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
+	if !bytes.Equal(cert.Key.Marshal(), signer.PublicKey().Marshal()) {
+		return nil, errors.New("ssh: signer and cert have different public key")
+	}
+
+	switch s := signer.(type) {
+	case MultiAlgorithmSigner:
+		return &multiAlgorithmSigner{
+			AlgorithmSigner: &algorithmOpenSSHCertSigner{
+				&openSSHCertSigner{cert, signer}, s},
+			supportedAlgorithms: s.Algorithms(),
+		}, nil
+	case AlgorithmSigner:
+		return &algorithmOpenSSHCertSigner{
+			&openSSHCertSigner{cert, signer}, s}, nil
+	default:
+		return &openSSHCertSigner{cert, signer}, nil
+	}
+}
+
+func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
+	return s.signer.Sign(rand, data)
+}
+
+func (s *openSSHCertSigner) PublicKey() PublicKey {
+	return s.pub
+}
+
+func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
+	return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm)
+}
+
+const sourceAddressCriticalOption = "source-address"
+
+// CertChecker does the work of verifying a certificate. Its methods
+// can be plugged into ClientConfig.HostKeyCallback and
+// ServerConfig.PublicKeyCallback. For the CertChecker to work,
+// minimally, the IsAuthority callback should be set.
+type CertChecker struct {
+	// SupportedCriticalOptions lists the CriticalOptions that the
+	// server application layer understands. These are only used
+	// for user certificates.
+	SupportedCriticalOptions []string
+
+	// IsUserAuthority should return true if the key is recognized as an
+	// authority for user certificate. This must be set if this CertChecker
+	// will be checking user certificates.
+	IsUserAuthority func(auth PublicKey) bool
+
+	// IsHostAuthority should report whether the key is recognized as
+	// an authority for this host. This must be set if this CertChecker
+	// will be checking host certificates.
+	IsHostAuthority func(auth PublicKey, address string) bool
+
+	// Clock is used for verifying time stamps. If nil, time.Now
+	// is used.
+	Clock func() time.Time
+
+	// UserKeyFallback is called when CertChecker.Authenticate encounters a
+	// public key that is not a certificate. It must implement validation
+	// of user keys or else, if nil, all such keys are rejected.
+	UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
+
+	// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
+	// public key that is not a certificate. It must implement host key
+	// validation or else, if nil, all such keys are rejected.
+	HostKeyFallback HostKeyCallback
+
+	// IsRevoked is called for each certificate so that revocation checking
+	// can be implemented. It should return true if the given certificate
+	// is revoked and false otherwise. If nil, no certificates are
+	// considered to have been revoked.
+	IsRevoked func(cert *Certificate) bool
+}
+
+// CheckHostKey checks a host key certificate. This method can be
+// plugged into ClientConfig.HostKeyCallback.
+func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
+	cert, ok := key.(*Certificate)
+	if !ok {
+		if c.HostKeyFallback != nil {
+			return c.HostKeyFallback(addr, remote, key)
+		}
+		return errors.New("ssh: non-certificate host key")
+	}
+	if cert.CertType != HostCert {
+		return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
+	}
+	if c.IsHostAuthority == nil {
+		return errors.New("ssh: cannot verify certificate, IsHostAuthority not set")
+	}
+	if !c.IsHostAuthority(cert.SignatureKey, addr) {
+		return fmt.Errorf("ssh: no authorities for hostname: %v", addr)
+	}
+
+	hostname, _, err := net.SplitHostPort(addr)
+	if err != nil {
+		return err
+	}
+
+	// Pass hostname only as principal for host certificates (consistent with OpenSSH)
+	return c.CheckCert(hostname, cert)
+}
+
+// Authenticate checks a user certificate. Authenticate can be used as
+// a value for ServerConfig.PublicKeyCallback.
+func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
+	cert, ok := pubKey.(*Certificate)
+	if !ok {
+		if c.UserKeyFallback != nil {
+			return c.UserKeyFallback(conn, pubKey)
+		}
+		return nil, errors.New("ssh: normal key pairs not accepted")
+	}
+
+	if cert.CertType != UserCert {
+		return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
+	}
+	if c.IsUserAuthority == nil {
+		return nil, errors.New("ssh: cannot verify certificate, IsUserAuthority not set")
+	}
+	if !c.IsUserAuthority(cert.SignatureKey) {
+		return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
+	}
+
+	if err := c.CheckCert(conn.User(), cert); err != nil {
+		return nil, err
+	}
+
+	return &cert.Permissions, nil
+}
+
+// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
+// the signature of the certificate.
+func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
+	if c.IsRevoked != nil && c.IsRevoked(cert) {
+		return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial)
+	}
+
+	for opt := range cert.CriticalOptions {
+		// sourceAddressCriticalOption will be enforced by
+		// serverAuthenticate
+		if opt == sourceAddressCriticalOption {
+			continue
+		}
+
+		found := false
+		for _, supp := range c.SupportedCriticalOptions {
+			if supp == opt {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
+		}
+	}
+
+	if len(cert.ValidPrincipals) > 0 {
+		// By default, certs are valid for all users/hosts.
+		found := false
+		for _, p := range cert.ValidPrincipals {
+			if p == principal {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
+		}
+	}
+
+	clock := c.Clock
+	if clock == nil {
+		clock = time.Now
+	}
+
+	unixNow := clock().Unix()
+	if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
+		return fmt.Errorf("ssh: cert is not yet valid")
+	}
+	if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
+		return fmt.Errorf("ssh: cert has expired")
+	}
+	// Match OpenSSH: the SK user-presence flag is never enforced on a
+	// certificate's CA signature. OpenSSH calls sshkey_verify with
+	// detailsp==NULL in sshkey.c:cert_parse, so the UP/UV flags are
+	// not even extracted. The UP bit on a CA signature reflects the
+	// CA operator's presence at signing time, which has no bearing on
+	// whether the user being authenticated is present now; enforcing
+	// it here would only break interop with certificates issued by
+	// non-interactive SK CAs. skKeyWithoutUP is a no-op for non-SK
+	// keys (the common case).
+	caKey := skKeyWithoutUP(cert.SignatureKey)
+	if err := caKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
+		return fmt.Errorf("ssh: certificate signature does not verify")
+	}
+
+	return nil
+}
+
+// SignCert signs the certificate with an authority, setting the Nonce,
+// SignatureKey, and Signature fields. If the authority implements the
+// MultiAlgorithmSigner interface the first algorithm in the list is used. This
+// is useful if you want to sign with a specific algorithm. As specified in
+// [SSH-CERTS], Section 2.1.1, authority can't be a [Certificate].
+func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
+	c.Nonce = make([]byte, 32)
+	if _, err := io.ReadFull(rand, c.Nonce); err != nil {
+		return err
+	}
+	// The Type() function is intended to return only certificate key types, but
+	// we use certKeyAlgoNames anyway for safety, to match [Certificate.Type].
+	if _, ok := certKeyAlgoNames[authority.PublicKey().Type()]; ok {
+		return fmt.Errorf("ssh: certificates cannot be used as authority (public key type %q)",
+			authority.PublicKey().Type())
+	}
+	c.SignatureKey = authority.PublicKey()
+
+	if v, ok := authority.(MultiAlgorithmSigner); ok {
+		if len(v.Algorithms()) == 0 {
+			return errors.New("the provided authority has no signature algorithm")
+		}
+		// Use the first algorithm in the list.
+		sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), v.Algorithms()[0])
+		if err != nil {
+			return err
+		}
+		c.Signature = sig
+		return nil
+	} else if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA {
+		// Default to KeyAlgoRSASHA512 for ssh-rsa signers.
+		// TODO: consider using KeyAlgoRSASHA256 as default.
+		sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), KeyAlgoRSASHA512)
+		if err != nil {
+			return err
+		}
+		c.Signature = sig
+		return nil
+	}
+
+	sig, err := authority.Sign(rand, c.bytesForSigning())
+	if err != nil {
+		return err
+	}
+	c.Signature = sig
+	return nil
+}
+
+// certKeyAlgoNames is a mapping from known certificate algorithm names to the
+// corresponding public key signature algorithm.
+//
+// This map must be kept in sync with the one in agent/client.go.
+var certKeyAlgoNames = map[string]string{
+	CertAlgoRSAv01:         KeyAlgoRSA,
+	CertAlgoRSASHA256v01:   KeyAlgoRSASHA256,
+	CertAlgoRSASHA512v01:   KeyAlgoRSASHA512,
+	InsecureCertAlgoDSAv01: InsecureKeyAlgoDSA,
+	CertAlgoECDSA256v01:    KeyAlgoECDSA256,
+	CertAlgoECDSA384v01:    KeyAlgoECDSA384,
+	CertAlgoECDSA521v01:    KeyAlgoECDSA521,
+	CertAlgoSKECDSA256v01:  KeyAlgoSKECDSA256,
+	CertAlgoED25519v01:     KeyAlgoED25519,
+	CertAlgoSKED25519v01:   KeyAlgoSKED25519,
+}
+
+// underlyingAlgo returns the signature algorithm associated with algo (which is
+// an advertised or negotiated public key or host key algorithm). These are
+// usually the same, except for certificate algorithms.
+func underlyingAlgo(algo string) string {
+	if a, ok := certKeyAlgoNames[algo]; ok {
+		return a
+	}
+	return algo
+}
+
+// certificateAlgo returns the certificate algorithms that uses the provided
+// underlying signature algorithm.
+func certificateAlgo(algo string) (certAlgo string, ok bool) {
+	for certName, algoName := range certKeyAlgoNames {
+		if algoName == algo {
+			return certName, true
+		}
+	}
+	return "", false
+}
+
+func (cert *Certificate) bytesForSigning() []byte {
+	c2 := *cert
+	c2.Signature = nil
+	out := c2.Marshal()
+	// Drop trailing signature length.
+	return out[:len(out)-4]
+}
+
+// Marshal serializes c into OpenSSH's wire format. It is part of the
+// PublicKey interface.
+func (c *Certificate) Marshal() []byte {
+	generic := genericCertData{
+		Serial:          c.Serial,
+		CertType:        c.CertType,
+		KeyId:           c.KeyId,
+		ValidPrincipals: marshalStringList(c.ValidPrincipals),
+		ValidAfter:      uint64(c.ValidAfter),
+		ValidBefore:     uint64(c.ValidBefore),
+		CriticalOptions: marshalTuples(c.CriticalOptions),
+		Extensions:      marshalTuples(c.Extensions),
+		Reserved:        c.Reserved,
+		SignatureKey:    c.SignatureKey.Marshal(),
+	}
+	if c.Signature != nil {
+		generic.Signature = Marshal(c.Signature)
+	}
+	genericBytes := Marshal(&generic)
+	keyBytes := c.Key.Marshal()
+	_, keyBytes, _ = parseString(keyBytes)
+	prefix := Marshal(&struct {
+		Name  string
+		Nonce []byte
+		Key   []byte `ssh:"rest"`
+	}{c.Type(), c.Nonce, keyBytes})
+
+	result := make([]byte, 0, len(prefix)+len(genericBytes))
+	result = append(result, prefix...)
+	result = append(result, genericBytes...)
+	return result
+}
+
+// Type returns the certificate algorithm name. It is part of the PublicKey interface.
+func (c *Certificate) Type() string {
+	certName, ok := certificateAlgo(c.Key.Type())
+	if !ok {
+		panic("unknown certificate type for key type " + c.Key.Type())
+	}
+	return certName
+}
+
+// Verify verifies a signature against the certificate's public
+// key. It is part of the PublicKey interface.
+func (c *Certificate) Verify(data []byte, sig *Signature) error {
+	return c.Key.Verify(data, sig)
+}
+
+func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
+	format, in, ok := parseString(in)
+	if !ok {
+		return
+	}
+
+	out = &Signature{
+		Format: string(format),
+	}
+
+	if out.Blob, in, ok = parseString(in); !ok {
+		return
+	}
+
+	switch out.Format {
+	case KeyAlgoSKECDSA256, CertAlgoSKECDSA256v01, KeyAlgoSKED25519, CertAlgoSKED25519v01:
+		out.Rest = in
+		return out, nil, ok
+	}
+
+	return out, in, ok
+}
+
+func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
+	sigBytes, rest, ok := parseString(in)
+	if !ok {
+		return
+	}
+
+	out, trailing, ok := parseSignatureBody(sigBytes)
+	if !ok || len(trailing) > 0 {
+		return nil, nil, false
+	}
+	return
+}
diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go
new file mode 100644
index 000000000..67379966b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/channel.go
@@ -0,0 +1,698 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"log"
+	"sync"
+	"sync/atomic"
+)
+
+const (
+	minPacketLength = 9
+	// channelMaxPacket contains the maximum number of bytes that will be
+	// sent in a single packet. As per RFC 4253, section 6.1, 32k is also
+	// the minimum.
+	channelMaxPacket = 1 << 15
+	// We follow OpenSSH here.
+	channelWindowSize = 64 * channelMaxPacket
+)
+
+// NewChannel represents an incoming request to a channel. It must either be
+// accepted for use by calling Accept, or rejected by calling Reject.
+type NewChannel interface {
+	// Accept accepts the channel creation request. It returns the Channel
+	// and a Go channel containing SSH requests. The Go channel must be
+	// serviced otherwise the Channel will hang.
+	Accept() (Channel, <-chan *Request, error)
+
+	// Reject rejects the channel creation request. After calling
+	// this, no other methods on the Channel may be called.
+	Reject(reason RejectionReason, message string) error
+
+	// ChannelType returns the type of the channel, as supplied by the
+	// client.
+	ChannelType() string
+
+	// ExtraData returns the arbitrary payload for this channel, as supplied
+	// by the client. This data is specific to the channel type.
+	ExtraData() []byte
+}
+
+// A Channel is an ordered, reliable, flow-controlled, duplex stream
+// that is multiplexed over an SSH connection.
+type Channel interface {
+	// Read reads up to len(data) bytes from the channel.
+	Read(data []byte) (int, error)
+
+	// Write writes len(data) bytes to the channel.
+	Write(data []byte) (int, error)
+
+	// Close signals end of channel use. No data may be sent after this
+	// call.
+	Close() error
+
+	// CloseWrite signals the end of sending in-band
+	// data. Requests may still be sent, and the other side may
+	// still send data
+	CloseWrite() error
+
+	// SendRequest sends a channel request.  If wantReply is true,
+	// it will wait for a reply and return the result as a
+	// boolean, otherwise the return value will be false. Channel
+	// requests are out-of-band messages so they may be sent even
+	// if the data stream is closed or blocked by flow control.
+	// If the channel is closed before a reply is returned, io.EOF
+	// is returned.
+	SendRequest(name string, wantReply bool, payload []byte) (bool, error)
+
+	// Stderr returns an io.ReadWriter that writes to this channel
+	// with the extended data type set to stderr. Stderr may
+	// safely be read and written from a different goroutine than
+	// Read and Write respectively.
+	Stderr() io.ReadWriter
+}
+
+// Request is a request sent outside of the normal stream of
+// data. Requests can either be specific to an SSH channel, or they
+// can be global.
+type Request struct {
+	Type      string
+	WantReply bool
+	Payload   []byte
+
+	ch  *channel
+	mux *mux
+}
+
+// Reply sends a response to a request. It must be called for all requests
+// where WantReply is true and is a no-op otherwise. The payload argument is
+// ignored for replies to channel-specific requests.
+func (r *Request) Reply(ok bool, payload []byte) error {
+	if !r.WantReply {
+		return nil
+	}
+
+	if r.ch == nil {
+		return r.mux.ackRequest(ok, payload)
+	}
+
+	return r.ch.ackRequest(ok)
+}
+
+// RejectionReason is an enumeration used when rejecting channel creation
+// requests. See RFC 4254, section 5.1.
+type RejectionReason uint32
+
+const (
+	Prohibited RejectionReason = iota + 1
+	ConnectionFailed
+	UnknownChannelType
+	ResourceShortage
+)
+
+// String converts the rejection reason to human readable form.
+func (r RejectionReason) String() string {
+	switch r {
+	case Prohibited:
+		return "administratively prohibited"
+	case ConnectionFailed:
+		return "connect failed"
+	case UnknownChannelType:
+		return "unknown channel type"
+	case ResourceShortage:
+		return "resource shortage"
+	}
+	return fmt.Sprintf("unknown reason %d", int(r))
+}
+
+// minPayloadSize returns min(limit, length) clamped to a uint32. It is used
+// to compute the size of the next channel data packet from the remaining
+// payload. The comparison is done in int64 because length is an int — on
+// 64-bit systems len(data) can exceed 2^32, and a direct uint32(length)
+// cast would silently truncate to 0 at every multiple of 2^32, causing
+// WriteExtended's loop to spin without making progress.
+func minPayloadSize(limit uint32, length int) uint32 {
+	if int64(length) > int64(limit) {
+		return limit
+	}
+	return uint32(length)
+}
+
+type channelDirection uint8
+
+const (
+	channelInbound channelDirection = iota
+	channelOutbound
+)
+
+// channel is an implementation of the Channel interface that works
+// with the mux class.
+type channel struct {
+	// R/O after creation
+	chanType          string
+	extraData         []byte
+	localId, remoteId uint32
+
+	// maxIncomingPayload and maxRemotePayload are the maximum
+	// payload sizes of normal and extended data packets for
+	// receiving and sending, respectively. The wire packet will
+	// be 9 or 13 bytes larger (excluding encryption overhead).
+	maxIncomingPayload uint32
+	maxRemotePayload   uint32
+
+	mux *mux
+
+	// decided is set to true if an accept or reject message has been sent
+	// (for outbound channels) or received (for inbound channels).
+	decided bool
+
+	// direction contains either channelOutbound, for channels created
+	// locally, or channelInbound, for channels created by the peer.
+	direction channelDirection
+
+	// Pending internal channel messages.
+	msg chan interface{}
+
+	// Since requests have no ID, there can be only one request
+	// with WantReply=true outstanding.  This lock is held by a
+	// goroutine that has such an outgoing request pending.
+	sentRequestMu sync.Mutex
+	// sentRequestPending is set to true while a SendRequest call with
+	// WantReply=true is in flight. handlePacket uses it as a gate: responses
+	// arriving while no request is pending are dropped to prevent a
+	// misbehaving peer from stalling the mux read loop by filling ch.msg
+	// with unsolicited channelRequestSuccess/Failure messages.
+	sentRequestPending atomic.Bool
+
+	incomingRequests chan *Request
+
+	sentEOF bool
+
+	// thread-safe data
+	remoteWin  window
+	pending    *buffer
+	extPending *buffer
+
+	// windowMu protects myWindow, the flow-control window, and myConsumed,
+	// the number of bytes consumed since we last increased myWindow
+	windowMu   sync.Mutex
+	myWindow   uint32
+	myConsumed uint32
+
+	// writeMu serializes calls to mux.conn.writePacket() and
+	// protects sentClose and packetPool. This mutex must be
+	// different from windowMu, as writePacket can block if there
+	// is a key exchange pending.
+	writeMu   sync.Mutex
+	sentClose bool
+
+	// packetPool has a buffer for each extended channel ID to
+	// save allocations during writes.
+	packetPool map[uint32][]byte
+}
+
+// writePacket sends a packet. If the packet is a channel close, it updates
+// sentClose. This method takes the lock c.writeMu.
+func (ch *channel) writePacket(packet []byte) error {
+	ch.writeMu.Lock()
+	if ch.sentClose {
+		ch.writeMu.Unlock()
+		return io.EOF
+	}
+	ch.sentClose = (packet[0] == msgChannelClose)
+	err := ch.mux.conn.writePacket(packet)
+	ch.writeMu.Unlock()
+	return err
+}
+
+func (ch *channel) sendMessage(msg interface{}) error {
+	if debugMux {
+		log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg)
+	}
+
+	p := Marshal(msg)
+	binary.BigEndian.PutUint32(p[1:], ch.remoteId)
+	return ch.writePacket(p)
+}
+
+// WriteExtended writes data to a specific extended stream. These streams are
+// used, for example, for stderr.
+func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) {
+	if ch.sentEOF {
+		return 0, io.EOF
+	}
+	// 1 byte message type, 4 bytes remoteId, 4 bytes data length
+	opCode := byte(msgChannelData)
+	headerLength := uint32(9)
+	if extendedCode > 0 {
+		headerLength += 4
+		opCode = msgChannelExtendedData
+	}
+
+	ch.writeMu.Lock()
+	packet := ch.packetPool[extendedCode]
+	// We don't remove the buffer from packetPool, so
+	// WriteExtended calls from different goroutines will be
+	// flagged as errors by the race detector.
+	ch.writeMu.Unlock()
+
+	for len(data) > 0 {
+		space := minPayloadSize(ch.maxRemotePayload, len(data))
+		if space, err = ch.remoteWin.reserve(space); err != nil {
+			return n, err
+		}
+		if want := headerLength + space; uint32(cap(packet)) < want {
+			packet = make([]byte, want)
+		} else {
+			packet = packet[:want]
+		}
+
+		todo := data[:space]
+
+		packet[0] = opCode
+		binary.BigEndian.PutUint32(packet[1:], ch.remoteId)
+		if extendedCode > 0 {
+			binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode))
+		}
+		binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo)))
+		copy(packet[headerLength:], todo)
+		if err = ch.writePacket(packet); err != nil {
+			return n, err
+		}
+
+		n += len(todo)
+		data = data[len(todo):]
+	}
+
+	ch.writeMu.Lock()
+	ch.packetPool[extendedCode] = packet
+	ch.writeMu.Unlock()
+
+	return n, err
+}
+
+func (ch *channel) handleData(packet []byte) error {
+	headerLen := 9
+	isExtendedData := packet[0] == msgChannelExtendedData
+	if isExtendedData {
+		headerLen = 13
+	}
+	if len(packet) < headerLen {
+		// malformed data packet
+		return parseError(packet[0])
+	}
+
+	var extended uint32
+	if isExtendedData {
+		extended = binary.BigEndian.Uint32(packet[5:])
+	}
+
+	length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen])
+	if length == 0 {
+		return nil
+	}
+	if length > ch.maxIncomingPayload {
+		// TODO(hanwen): should send Disconnect?
+		return errors.New("ssh: incoming packet exceeds maximum payload size")
+	}
+
+	data := packet[headerLen:]
+	if length != uint32(len(data)) {
+		return errors.New("ssh: wrong packet length")
+	}
+
+	ch.windowMu.Lock()
+	if ch.myWindow < length {
+		ch.windowMu.Unlock()
+		// TODO(hanwen): should send Disconnect with reason?
+		return errors.New("ssh: remote side wrote too much")
+	}
+	ch.myWindow -= length
+	ch.windowMu.Unlock()
+
+	if extended == 1 {
+		ch.extPending.write(data)
+	} else if extended > 0 {
+		// discard other extended data.
+	} else {
+		ch.pending.write(data)
+	}
+	return nil
+}
+
+func (c *channel) adjustWindow(adj uint32) error {
+	c.windowMu.Lock()
+	// Since myConsumed and myWindow are managed on our side, and can never
+	// exceed the initial window setting, we don't worry about overflow.
+	c.myConsumed += adj
+	var sendAdj uint32
+	if (channelWindowSize-c.myWindow > 3*c.maxIncomingPayload) ||
+		(c.myWindow < channelWindowSize/2) {
+		sendAdj = c.myConsumed
+		c.myConsumed = 0
+		c.myWindow += sendAdj
+	}
+	c.windowMu.Unlock()
+	if sendAdj == 0 {
+		return nil
+	}
+	return c.sendMessage(windowAdjustMsg{
+		AdditionalBytes: sendAdj,
+	})
+}
+
+func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) {
+	switch extended {
+	case 1:
+		n, err = c.extPending.Read(data)
+	case 0:
+		n, err = c.pending.Read(data)
+	default:
+		return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended)
+	}
+
+	if n > 0 {
+		err = c.adjustWindow(uint32(n))
+		// sendWindowAdjust can return io.EOF if the remote
+		// peer has closed the connection, however we want to
+		// defer forwarding io.EOF to the caller of Read until
+		// the buffer has been drained.
+		if n > 0 && err == io.EOF {
+			err = nil
+		}
+	}
+
+	return n, err
+}
+
+func (c *channel) close() {
+	c.pending.eof()
+	c.extPending.eof()
+	close(c.msg)
+	close(c.incomingRequests)
+	c.writeMu.Lock()
+	// This is not necessary for a normal channel teardown, but if
+	// there was another error, it is.
+	c.sentClose = true
+	c.writeMu.Unlock()
+	// Unblock writers.
+	c.remoteWin.close()
+}
+
+// responseMessageReceived is called when a success or failure message is
+// received on a channel to check that such a message is reasonable for the
+// given channel.
+func (ch *channel) responseMessageReceived() error {
+	if ch.direction == channelInbound {
+		return errors.New("ssh: channel response message received on inbound channel")
+	}
+	if ch.decided {
+		return errors.New("ssh: duplicate response received for channel")
+	}
+	ch.decided = true
+	return nil
+}
+
+func (ch *channel) handlePacket(packet []byte) error {
+	switch packet[0] {
+	case msgChannelData, msgChannelExtendedData:
+		return ch.handleData(packet)
+	case msgChannelClose:
+		ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId})
+		ch.mux.chanList.remove(ch.localId)
+		ch.close()
+		return nil
+	case msgChannelEOF:
+		// RFC 4254 is mute on how EOF affects dataExt messages but
+		// it is logical to signal EOF at the same time.
+		ch.extPending.eof()
+		ch.pending.eof()
+		return nil
+	}
+
+	decoded, err := decode(packet)
+	if err != nil {
+		return err
+	}
+
+	switch msg := decoded.(type) {
+	case *channelOpenFailureMsg:
+		if err := ch.responseMessageReceived(); err != nil {
+			return err
+		}
+		ch.mux.chanList.remove(msg.PeersID)
+		ch.msg <- msg
+	case *channelOpenConfirmMsg:
+		if err := ch.responseMessageReceived(); err != nil {
+			return err
+		}
+		if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
+			return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize)
+		}
+		ch.remoteId = msg.MyID
+		ch.maxRemotePayload = msg.MaxPacketSize
+		ch.remoteWin.add(msg.MyWindow)
+		ch.msg <- msg
+	case *windowAdjustMsg:
+		if !ch.remoteWin.add(msg.AdditionalBytes) {
+			return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes)
+		}
+	case *channelRequestMsg:
+		req := Request{
+			Type:      msg.Request,
+			WantReply: msg.WantReply,
+			Payload:   msg.RequestSpecificData,
+			ch:        ch,
+		}
+
+		ch.incomingRequests <- &req
+	case *channelRequestSuccessMsg, *channelRequestFailureMsg:
+		// Drop responses that arrive when no SendRequest is waiting, to
+		// prevent a malicious peer from filling ch.msg and stalling the
+		// mux read loop. The non-blocking send additionally protects the
+		// loop if a well-behaved caller is slow to read.
+		if !ch.sentRequestPending.Load() {
+			return nil
+		}
+		select {
+		case ch.msg <- msg:
+		default:
+		}
+	default:
+		ch.msg <- msg
+	}
+	return nil
+}
+
+func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel {
+	ch := &channel{
+		remoteWin:        window{Cond: newCond()},
+		myWindow:         channelWindowSize,
+		pending:          newBuffer(),
+		extPending:       newBuffer(),
+		direction:        direction,
+		incomingRequests: make(chan *Request, chanSize),
+		msg:              make(chan interface{}, chanSize),
+		chanType:         chanType,
+		extraData:        extraData,
+		mux:              m,
+		packetPool:       make(map[uint32][]byte),
+	}
+	ch.localId = m.chanList.add(ch)
+	return ch
+}
+
+var errUndecided = errors.New("ssh: must Accept or Reject channel")
+var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once")
+
+type extChannel struct {
+	code uint32
+	ch   *channel
+}
+
+func (e *extChannel) Write(data []byte) (n int, err error) {
+	return e.ch.WriteExtended(data, e.code)
+}
+
+func (e *extChannel) Read(data []byte) (n int, err error) {
+	return e.ch.ReadExtended(data, e.code)
+}
+
+func (ch *channel) Accept() (Channel, <-chan *Request, error) {
+	if ch.decided {
+		return nil, nil, errDecidedAlready
+	}
+	ch.maxIncomingPayload = channelMaxPacket
+	confirm := channelOpenConfirmMsg{
+		PeersID:       ch.remoteId,
+		MyID:          ch.localId,
+		MyWindow:      ch.myWindow,
+		MaxPacketSize: ch.maxIncomingPayload,
+	}
+	ch.decided = true
+	if err := ch.sendMessage(confirm); err != nil {
+		return nil, nil, err
+	}
+
+	return ch, ch.incomingRequests, nil
+}
+
+func (ch *channel) Reject(reason RejectionReason, message string) error {
+	if ch.decided {
+		return errDecidedAlready
+	}
+	reject := channelOpenFailureMsg{
+		PeersID:  ch.remoteId,
+		Reason:   reason,
+		Message:  message,
+		Language: "en",
+	}
+	ch.decided = true
+	err := ch.sendMessage(reject)
+
+	// Remove the channel from the mux to prevent memory leaks.
+	// Do not call ch.close() here: no goroutine holds a reference to a
+	// rejected channel's internal channels (msg, incomingRequests), so
+	// removing it from chanList is sufficient for GC. Calling close()
+	// would race with the mux loop goroutine (handlePacket or dropAll),
+	// causing a panic from closing an already-closed channel.
+	ch.mux.chanList.remove(ch.localId)
+
+	return err
+}
+
+func (ch *channel) Read(data []byte) (int, error) {
+	if !ch.decided {
+		return 0, errUndecided
+	}
+	return ch.ReadExtended(data, 0)
+}
+
+func (ch *channel) Write(data []byte) (int, error) {
+	if !ch.decided {
+		return 0, errUndecided
+	}
+	return ch.WriteExtended(data, 0)
+}
+
+func (ch *channel) CloseWrite() error {
+	if !ch.decided {
+		return errUndecided
+	}
+	ch.sentEOF = true
+	return ch.sendMessage(channelEOFMsg{
+		PeersID: ch.remoteId})
+}
+
+func (ch *channel) Close() error {
+	if !ch.decided {
+		return errUndecided
+	}
+
+	return ch.sendMessage(channelCloseMsg{
+		PeersID: ch.remoteId})
+}
+
+// Extended returns an io.ReadWriter that sends and receives data on the given,
+// SSH extended stream. Such streams are used, for example, for stderr.
+func (ch *channel) Extended(code uint32) io.ReadWriter {
+	if !ch.decided {
+		return nil
+	}
+	return &extChannel{code, ch}
+}
+
+func (ch *channel) Stderr() io.ReadWriter {
+	return ch.Extended(1)
+}
+
+func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
+	if !ch.decided {
+		return false, errUndecided
+	}
+
+	if wantReply {
+		ch.sentRequestMu.Lock()
+		defer ch.sentRequestMu.Unlock()
+
+		// Open the gate so that responses arriving while this request is in
+		// flight are allowed to reach ch.msg. Responses arriving while no
+		// request is pending are dropped by handlePacket.
+		ch.sentRequestPending.Store(true)
+		defer ch.sentRequestPending.Store(false)
+
+		// Drain any spurious responses that may have been buffered. This
+		// prevents a previously buffered unexpected response from being
+		// consumed instead of the actual response for this request.
+	drain:
+		for {
+			select {
+			case <-ch.msg:
+			default:
+				break drain
+			}
+		}
+	}
+
+	msg := channelRequestMsg{
+		PeersID:             ch.remoteId,
+		Request:             name,
+		WantReply:           wantReply,
+		RequestSpecificData: payload,
+	}
+
+	if err := ch.sendMessage(msg); err != nil {
+		return false, err
+	}
+
+	if wantReply {
+		m, ok := (<-ch.msg)
+		if !ok {
+			return false, io.EOF
+		}
+		switch m.(type) {
+		case *channelRequestFailureMsg:
+			return false, nil
+		case *channelRequestSuccessMsg:
+			return true, nil
+		default:
+			return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m)
+		}
+	}
+
+	return false, nil
+}
+
+// ackRequest either sends an ack or nack to the channel request.
+func (ch *channel) ackRequest(ok bool) error {
+	if !ch.decided {
+		return errUndecided
+	}
+
+	var msg interface{}
+	if !ok {
+		msg = channelRequestFailureMsg{
+			PeersID: ch.remoteId,
+		}
+	} else {
+		msg = channelRequestSuccessMsg{
+			PeersID: ch.remoteId,
+		}
+	}
+	return ch.sendMessage(msg)
+}
+
+func (ch *channel) ChannelType() string {
+	return ch.chanType
+}
+
+func (ch *channel) ExtraData() []byte {
+	return ch.extraData
+}
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go
new file mode 100644
index 000000000..48d019954
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/cipher.go
@@ -0,0 +1,789 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/des"
+	"crypto/fips140"
+	"crypto/rc4"
+	"crypto/subtle"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"hash"
+	"io"
+	"slices"
+
+	"golang.org/x/crypto/chacha20"
+	"golang.org/x/crypto/internal/poly1305"
+)
+
+const (
+	packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
+
+	// RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations
+	// MUST be able to process (plus a few more kilobytes for padding and mac). The RFC
+	// indicates implementations SHOULD be able to handle larger packet sizes, but then
+	// waffles on about reasonable limits.
+	//
+	// OpenSSH caps their maxPacket at 256kB so we choose to do
+	// the same. maxPacket is also used to ensure that uint32
+	// length fields do not overflow, so it should remain well
+	// below 4G.
+	maxPacket = 256 * 1024
+)
+
+// noneCipher implements cipher.Stream and provides no encryption. It is used
+// by the transport before the first key-exchange.
+type noneCipher struct{}
+
+func (c noneCipher) XORKeyStream(dst, src []byte) {
+	copy(dst, src)
+}
+
+func newAESCTR(key, iv []byte) (cipher.Stream, error) {
+	c, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	return cipher.NewCTR(c, iv), nil
+}
+
+func newRC4(key, iv []byte) (cipher.Stream, error) {
+	return rc4.NewCipher(key)
+}
+
+type cipherMode struct {
+	keySize int
+	ivSize  int
+	create  func(key, iv []byte, macKey []byte, algs DirectionAlgorithms) (packetCipher, error)
+}
+
+func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
+	return func(key, iv, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
+		stream, err := createFunc(key, iv)
+		if err != nil {
+			return nil, err
+		}
+
+		var streamDump []byte
+		if skip > 0 {
+			streamDump = make([]byte, 512)
+		}
+
+		for remainingToDump := skip; remainingToDump > 0; {
+			dumpThisTime := remainingToDump
+			if dumpThisTime > len(streamDump) {
+				dumpThisTime = len(streamDump)
+			}
+			stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
+			remainingToDump -= dumpThisTime
+		}
+
+		mac := macModes[algs.MAC].new(macKey)
+		return &streamPacketCipher{
+			mac:       mac,
+			etm:       macModes[algs.MAC].etm,
+			macResult: make([]byte, mac.Size()),
+			cipher:    stream,
+		}, nil
+	}
+}
+
+// cipherModes documents properties of supported ciphers. Ciphers not included
+// are not supported and will not be negotiated, even if explicitly configured.
+// When FIPS mode is enabled, only FIPS-approved algorithms are included.
+var cipherModes = map[string]*cipherMode{}
+
+func init() {
+	cipherModes[CipherAES128CTR] = &cipherMode{16, aes.BlockSize, streamCipherMode(0, newAESCTR)}
+	cipherModes[CipherAES192CTR] = &cipherMode{24, aes.BlockSize, streamCipherMode(0, newAESCTR)}
+	cipherModes[CipherAES256CTR] = &cipherMode{32, aes.BlockSize, streamCipherMode(0, newAESCTR)}
+	//  Use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode,
+	// we'll wire it up to NewGCMForSSH in Go 1.26.
+	//
+	// For now it means we'll work with fips140=on but not fips140=only.
+	cipherModes[CipherAES128GCM] = &cipherMode{16, 12, newGCMCipher}
+	cipherModes[CipherAES256GCM] = &cipherMode{32, 12, newGCMCipher}
+
+	if fips140.Enabled() {
+		defaultCiphers = slices.DeleteFunc(defaultCiphers, func(algo string) bool {
+			_, ok := cipherModes[algo]
+			return !ok
+		})
+		return
+	}
+
+	cipherModes[CipherChaCha20Poly1305] = &cipherMode{64, 0, newChaCha20Cipher}
+	// Insecure ciphers not included in the default configuration.
+	cipherModes[InsecureCipherRC4128] = &cipherMode{16, 0, streamCipherMode(1536, newRC4)}
+	cipherModes[InsecureCipherRC4256] = &cipherMode{32, 0, streamCipherMode(1536, newRC4)}
+	cipherModes[InsecureCipherRC4] = &cipherMode{16, 0, streamCipherMode(0, newRC4)}
+	// CBC mode is insecure and so is not included in the default config.
+	// (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.pdf). If absolutely
+	// needed, it's possible to specify a custom Config to enable it.
+	// You should expect that an active attacker can recover plaintext if
+	// you do.
+	cipherModes[InsecureCipherAES128CBC] = &cipherMode{16, aes.BlockSize, newAESCBCCipher}
+	cipherModes[InsecureCipherTripleDESCBC] = &cipherMode{24, des.BlockSize, newTripleDESCBCCipher}
+}
+
+// prefixLen is the length of the packet prefix that contains the packet length
+// and number of padding bytes.
+const prefixLen = 5
+
+// streamPacketCipher is a packetCipher using a stream cipher.
+type streamPacketCipher struct {
+	mac    hash.Hash
+	cipher cipher.Stream
+	etm    bool
+
+	// The following members are to avoid per-packet allocations.
+	prefix      [prefixLen]byte
+	seqNumBytes [4]byte
+	padding     [2 * packetSizeMultiple]byte
+	packetData  []byte
+	macResult   []byte
+}
+
+// readCipherPacket reads and decrypt a single packet from the reader argument.
+func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+	if _, err := io.ReadFull(r, s.prefix[:]); err != nil {
+		return nil, err
+	}
+
+	var encryptedPaddingLength [1]byte
+	if s.mac != nil && s.etm {
+		copy(encryptedPaddingLength[:], s.prefix[4:5])
+		s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
+	} else {
+		s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
+	}
+
+	length := binary.BigEndian.Uint32(s.prefix[0:4])
+	paddingLength := uint32(s.prefix[4])
+
+	var macSize uint32
+	if s.mac != nil {
+		s.mac.Reset()
+		binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
+		s.mac.Write(s.seqNumBytes[:])
+		if s.etm {
+			s.mac.Write(s.prefix[:4])
+			s.mac.Write(encryptedPaddingLength[:])
+		} else {
+			s.mac.Write(s.prefix[:])
+		}
+		macSize = uint32(s.mac.Size())
+	}
+
+	if length <= paddingLength+1 {
+		return nil, errors.New("ssh: invalid packet length, packet too small")
+	}
+
+	if length > maxPacket {
+		return nil, errors.New("ssh: invalid packet length, packet too large")
+	}
+
+	// the maxPacket check above ensures that length-1+macSize
+	// does not overflow.
+	if uint32(cap(s.packetData)) < length-1+macSize {
+		s.packetData = make([]byte, length-1+macSize)
+	} else {
+		s.packetData = s.packetData[:length-1+macSize]
+	}
+
+	if _, err := io.ReadFull(r, s.packetData); err != nil {
+		return nil, err
+	}
+	mac := s.packetData[length-1:]
+	data := s.packetData[:length-1]
+
+	if s.mac != nil && s.etm {
+		s.mac.Write(data)
+	}
+
+	s.cipher.XORKeyStream(data, data)
+
+	if s.mac != nil {
+		if !s.etm {
+			s.mac.Write(data)
+		}
+		s.macResult = s.mac.Sum(s.macResult[:0])
+		if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
+			return nil, errors.New("ssh: MAC failure")
+		}
+	}
+
+	return s.packetData[:length-paddingLength-1], nil
+}
+
+// writeCipherPacket encrypts and sends a packet of data to the writer argument
+func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+	if len(packet) > maxPacket {
+		return errors.New("ssh: packet too large")
+	}
+
+	aadlen := 0
+	if s.mac != nil && s.etm {
+		// packet length is not encrypted for EtM modes
+		aadlen = 4
+	}
+
+	paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple
+	if paddingLength < 4 {
+		paddingLength += packetSizeMultiple
+	}
+
+	length := len(packet) + 1 + paddingLength
+	binary.BigEndian.PutUint32(s.prefix[:], uint32(length))
+	s.prefix[4] = byte(paddingLength)
+	padding := s.padding[:paddingLength]
+	if _, err := io.ReadFull(rand, padding); err != nil {
+		return err
+	}
+
+	if s.mac != nil {
+		s.mac.Reset()
+		binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
+		s.mac.Write(s.seqNumBytes[:])
+
+		if s.etm {
+			// For EtM algorithms, the packet length must stay unencrypted,
+			// but the following data (padding length) must be encrypted
+			s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
+		}
+
+		s.mac.Write(s.prefix[:])
+
+		if !s.etm {
+			// For non-EtM algorithms, the algorithm is applied on unencrypted data
+			s.mac.Write(packet)
+			s.mac.Write(padding)
+		}
+	}
+
+	if !(s.mac != nil && s.etm) {
+		// For EtM algorithms, the padding length has already been encrypted
+		// and the packet length must remain unencrypted
+		s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
+	}
+
+	s.cipher.XORKeyStream(packet, packet)
+	s.cipher.XORKeyStream(padding, padding)
+
+	if s.mac != nil && s.etm {
+		// For EtM algorithms, packet and padding must be encrypted
+		s.mac.Write(packet)
+		s.mac.Write(padding)
+	}
+
+	if _, err := w.Write(s.prefix[:]); err != nil {
+		return err
+	}
+	if _, err := w.Write(packet); err != nil {
+		return err
+	}
+	if _, err := w.Write(padding); err != nil {
+		return err
+	}
+
+	if s.mac != nil {
+		s.macResult = s.mac.Sum(s.macResult[:0])
+		if _, err := w.Write(s.macResult); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+type gcmCipher struct {
+	aead   cipher.AEAD
+	prefix [4]byte
+	iv     []byte
+	buf    []byte
+}
+
+func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs DirectionAlgorithms) (packetCipher, error) {
+	c, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	aead, err := cipher.NewGCM(c)
+	if err != nil {
+		return nil, err
+	}
+
+	return &gcmCipher{
+		aead: aead,
+		iv:   iv,
+	}, nil
+}
+
+const gcmTagSize = 16
+
+func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+	// Pad out to multiple of 16 bytes. This is different from the
+	// stream cipher because that encrypts the length too.
+	padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple)
+	if padding < 4 {
+		padding += packetSizeMultiple
+	}
+
+	length := uint32(len(packet) + int(padding) + 1)
+	binary.BigEndian.PutUint32(c.prefix[:], length)
+	if _, err := w.Write(c.prefix[:]); err != nil {
+		return err
+	}
+
+	if cap(c.buf) < int(length) {
+		c.buf = make([]byte, length)
+	} else {
+		c.buf = c.buf[:length]
+	}
+
+	c.buf[0] = padding
+	copy(c.buf[1:], packet)
+	if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil {
+		return err
+	}
+	c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:])
+	if _, err := w.Write(c.buf); err != nil {
+		return err
+	}
+	c.incIV()
+
+	return nil
+}
+
+func (c *gcmCipher) incIV() {
+	for i := 4 + 7; i >= 4; i-- {
+		c.iv[i]++
+		if c.iv[i] != 0 {
+			break
+		}
+	}
+}
+
+func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+	if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
+		return nil, err
+	}
+	length := binary.BigEndian.Uint32(c.prefix[:])
+	if length > maxPacket {
+		return nil, errors.New("ssh: max packet length exceeded")
+	}
+
+	if cap(c.buf) < int(length+gcmTagSize) {
+		c.buf = make([]byte, length+gcmTagSize)
+	} else {
+		c.buf = c.buf[:length+gcmTagSize]
+	}
+
+	if _, err := io.ReadFull(r, c.buf); err != nil {
+		return nil, err
+	}
+
+	plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:])
+	if err != nil {
+		return nil, err
+	}
+	c.incIV()
+
+	if len(plain) == 0 {
+		return nil, errors.New("ssh: empty packet")
+	}
+
+	padding := plain[0]
+	if padding < 4 {
+		// padding is a byte, so it automatically satisfies
+		// the maximum size, which is 255.
+		return nil, fmt.Errorf("ssh: illegal padding %d", padding)
+	}
+
+	if int(padding)+1 >= len(plain) {
+		return nil, fmt.Errorf("ssh: padding %d too large", padding)
+	}
+	plain = plain[1 : length-uint32(padding)]
+	return plain, nil
+}
+
+// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
+type cbcCipher struct {
+	mac       hash.Hash
+	macSize   uint32
+	decrypter cipher.BlockMode
+	encrypter cipher.BlockMode
+
+	// The following members are to avoid per-packet allocations.
+	seqNumBytes [4]byte
+	packetData  []byte
+	macResult   []byte
+
+	// Amount of data we should still read to hide which
+	// verification error triggered.
+	oracleCamouflage uint32
+}
+
+func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
+	cbc := &cbcCipher{
+		mac:        macModes[algs.MAC].new(macKey),
+		decrypter:  cipher.NewCBCDecrypter(c, iv),
+		encrypter:  cipher.NewCBCEncrypter(c, iv),
+		packetData: make([]byte, 1024),
+	}
+	if cbc.mac != nil {
+		cbc.macSize = uint32(cbc.mac.Size())
+	}
+
+	return cbc, nil
+}
+
+func newAESCBCCipher(key, iv, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
+	c, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	cbc, err := newCBCCipher(c, key, iv, macKey, algs)
+	if err != nil {
+		return nil, err
+	}
+
+	return cbc, nil
+}
+
+func newTripleDESCBCCipher(key, iv, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) {
+	c, err := des.NewTripleDESCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	cbc, err := newCBCCipher(c, key, iv, macKey, algs)
+	if err != nil {
+		return nil, err
+	}
+
+	return cbc, nil
+}
+
+func maxUInt32(a, b int) uint32 {
+	if a > b {
+		return uint32(a)
+	}
+	return uint32(b)
+}
+
+const (
+	cbcMinPacketSizeMultiple = 8
+	cbcMinPacketSize         = 16
+	cbcMinPaddingSize        = 4
+)
+
+// cbcError represents a verification error that may leak information.
+type cbcError string
+
+func (e cbcError) Error() string { return string(e) }
+
+func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+	p, err := c.readCipherPacketLeaky(seqNum, r)
+	if err != nil {
+		if _, ok := err.(cbcError); ok {
+			// Verification error: read a fixed amount of
+			// data, to make distinguishing between
+			// failing MAC and failing length check more
+			// difficult.
+			io.CopyN(io.Discard, r, int64(c.oracleCamouflage))
+		}
+	}
+	return p, err
+}
+
+func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
+	blockSize := c.decrypter.BlockSize()
+
+	// Read the header, which will include some of the subsequent data in the
+	// case of block ciphers - this is copied back to the payload later.
+	// How many bytes of payload/padding will be read with this first read.
+	firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
+	firstBlock := c.packetData[:firstBlockLength]
+	if _, err := io.ReadFull(r, firstBlock); err != nil {
+		return nil, err
+	}
+
+	c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
+
+	c.decrypter.CryptBlocks(firstBlock, firstBlock)
+	length := binary.BigEndian.Uint32(firstBlock[:4])
+	if length > maxPacket {
+		return nil, cbcError("ssh: packet too large")
+	}
+	if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
+		// The minimum size of a packet is 16 (or the cipher block size, whichever
+		// is larger) bytes.
+		return nil, cbcError("ssh: packet too small")
+	}
+	// The length of the packet (including the length field but not the MAC) must
+	// be a multiple of the block size or 8, whichever is larger.
+	if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
+		return nil, cbcError("ssh: invalid packet length multiple")
+	}
+
+	paddingLength := uint32(firstBlock[4])
+	if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
+		return nil, cbcError("ssh: invalid packet length")
+	}
+
+	// Positions within the c.packetData buffer:
+	macStart := 4 + length
+	paddingStart := macStart - paddingLength
+
+	// Entire packet size, starting before length, ending at end of mac.
+	entirePacketSize := macStart + c.macSize
+
+	// Ensure c.packetData is large enough for the entire packet data.
+	if uint32(cap(c.packetData)) < entirePacketSize {
+		// Still need to upsize and copy, but this should be rare at runtime, only
+		// on upsizing the packetData buffer.
+		c.packetData = make([]byte, entirePacketSize)
+		copy(c.packetData, firstBlock)
+	} else {
+		c.packetData = c.packetData[:entirePacketSize]
+	}
+
+	n, err := io.ReadFull(r, c.packetData[firstBlockLength:])
+	if err != nil {
+		return nil, err
+	}
+	c.oracleCamouflage -= uint32(n)
+
+	remainingCrypted := c.packetData[firstBlockLength:macStart]
+	c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted)
+
+	mac := c.packetData[macStart:]
+	if c.mac != nil {
+		c.mac.Reset()
+		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
+		c.mac.Write(c.seqNumBytes[:])
+		c.mac.Write(c.packetData[:macStart])
+		c.macResult = c.mac.Sum(c.macResult[:0])
+		if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
+			return nil, cbcError("ssh: MAC failure")
+		}
+	}
+
+	return c.packetData[prefixLen:paddingStart], nil
+}
+
+func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+	effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
+
+	// Length of encrypted portion of the packet (header, payload, padding).
+	// Enforce minimum padding and packet size.
+	encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPacketSize)
+	// Enforce block size.
+	encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
+
+	length := encLength - 4
+	paddingLength := int(length) - (1 + len(packet))
+
+	// Overall buffer contains: header, payload, padding, mac.
+	// Space for the MAC is reserved in the capacity but not the slice length.
+	bufferSize := encLength + c.macSize
+	if uint32(cap(c.packetData)) < bufferSize {
+		c.packetData = make([]byte, encLength, bufferSize)
+	} else {
+		c.packetData = c.packetData[:encLength]
+	}
+
+	p := c.packetData
+
+	// Packet header.
+	binary.BigEndian.PutUint32(p, length)
+	p = p[4:]
+	p[0] = byte(paddingLength)
+
+	// Payload.
+	p = p[1:]
+	copy(p, packet)
+
+	// Padding.
+	p = p[len(packet):]
+	if _, err := io.ReadFull(rand, p); err != nil {
+		return err
+	}
+
+	if c.mac != nil {
+		c.mac.Reset()
+		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
+		c.mac.Write(c.seqNumBytes[:])
+		c.mac.Write(c.packetData)
+		// The MAC is now appended into the capacity reserved for it earlier.
+		c.packetData = c.mac.Sum(c.packetData)
+	}
+
+	c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength])
+
+	if _, err := w.Write(c.packetData); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com
+// AEAD, which is described here:
+//
+//	https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00
+//
+// the methods here also implement padding, which RFC 4253 Section 6
+// also requires of stream ciphers.
+type chacha20Poly1305Cipher struct {
+	lengthKey  [32]byte
+	contentKey [32]byte
+	buf        []byte
+}
+
+func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs DirectionAlgorithms) (packetCipher, error) {
+	if len(key) != 64 {
+		panic(len(key))
+	}
+
+	c := &chacha20Poly1305Cipher{
+		buf: make([]byte, 256),
+	}
+
+	copy(c.contentKey[:], key[:32])
+	copy(c.lengthKey[:], key[32:])
+	return c, nil
+}
+
+func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+	nonce := make([]byte, 12)
+	binary.BigEndian.PutUint32(nonce[8:], seqNum)
+	s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce)
+	if err != nil {
+		return nil, err
+	}
+	var polyKey, discardBuf [32]byte
+	s.XORKeyStream(polyKey[:], polyKey[:])
+	s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes
+
+	encryptedLength := c.buf[:4]
+	if _, err := io.ReadFull(r, encryptedLength); err != nil {
+		return nil, err
+	}
+
+	var lenBytes [4]byte
+	ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce)
+	if err != nil {
+		return nil, err
+	}
+	ls.XORKeyStream(lenBytes[:], encryptedLength)
+
+	length := binary.BigEndian.Uint32(lenBytes[:])
+	if length > maxPacket {
+		return nil, errors.New("ssh: invalid packet length, packet too large")
+	}
+
+	contentEnd := 4 + length
+	packetEnd := contentEnd + poly1305.TagSize
+	if uint32(cap(c.buf)) < packetEnd {
+		c.buf = make([]byte, packetEnd)
+		copy(c.buf[:], encryptedLength)
+	} else {
+		c.buf = c.buf[:packetEnd]
+	}
+
+	if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil {
+		return nil, err
+	}
+
+	var mac [poly1305.TagSize]byte
+	copy(mac[:], c.buf[contentEnd:packetEnd])
+	if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) {
+		return nil, errors.New("ssh: MAC failure")
+	}
+
+	plain := c.buf[4:contentEnd]
+	s.XORKeyStream(plain, plain)
+
+	if len(plain) == 0 {
+		return nil, errors.New("ssh: empty packet")
+	}
+
+	padding := plain[0]
+	if padding < 4 {
+		// padding is a byte, so it automatically satisfies
+		// the maximum size, which is 255.
+		return nil, fmt.Errorf("ssh: illegal padding %d", padding)
+	}
+
+	if int(padding)+1 >= len(plain) {
+		return nil, fmt.Errorf("ssh: padding %d too large", padding)
+	}
+
+	plain = plain[1 : len(plain)-int(padding)]
+
+	return plain, nil
+}
+
+func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
+	nonce := make([]byte, 12)
+	binary.BigEndian.PutUint32(nonce[8:], seqNum)
+	s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce)
+	if err != nil {
+		return err
+	}
+	var polyKey, discardBuf [32]byte
+	s.XORKeyStream(polyKey[:], polyKey[:])
+	s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes
+
+	// There is no blocksize, so fall back to multiple of 8 byte
+	// padding, as described in RFC 4253, Sec 6.
+	const packetSizeMultiple = 8
+
+	padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple
+	if padding < 4 {
+		padding += packetSizeMultiple
+	}
+
+	// size (4 bytes), padding (1), payload, padding, tag.
+	totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize
+	if cap(c.buf) < totalLength {
+		c.buf = make([]byte, totalLength)
+	} else {
+		c.buf = c.buf[:totalLength]
+	}
+
+	binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding))
+	ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce)
+	if err != nil {
+		return err
+	}
+	ls.XORKeyStream(c.buf, c.buf[:4])
+	c.buf[4] = byte(padding)
+	copy(c.buf[5:], payload)
+	packetEnd := 5 + len(payload) + padding
+	if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil {
+		return err
+	}
+
+	s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd])
+
+	var mac [poly1305.TagSize]byte
+	poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey)
+
+	copy(c.buf[packetEnd:], mac[:])
+
+	if _, err := w.Write(c.buf); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go
new file mode 100644
index 000000000..33079789b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/client.go
@@ -0,0 +1,283 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"net"
+	"os"
+	"sync"
+	"time"
+)
+
+// Client implements a traditional SSH client that supports shells,
+// subprocesses, TCP port/streamlocal forwarding and tunneled dialing.
+type Client struct {
+	Conn
+
+	handleForwardsOnce sync.Once // guards calling (*Client).handleForwards
+
+	forwards        forwardList // forwarded tcpip connections from the remote side
+	mu              sync.Mutex
+	channelHandlers map[string]chan NewChannel
+}
+
+// HandleChannelOpen returns a channel on which NewChannel requests
+// for the given type are sent. If the type already is being handled,
+// nil is returned. The channel is closed when the connection is closed.
+func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	if c.channelHandlers == nil {
+		// The SSH channel has been closed.
+		c := make(chan NewChannel)
+		close(c)
+		return c
+	}
+
+	ch := c.channelHandlers[channelType]
+	if ch != nil {
+		return nil
+	}
+
+	ch = make(chan NewChannel, chanSize)
+	c.channelHandlers[channelType] = ch
+	return ch
+}
+
+// NewClient creates a Client on top of the given connection.
+func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
+	conn := &Client{
+		Conn:            c,
+		channelHandlers: make(map[string]chan NewChannel, 1),
+	}
+
+	go conn.handleGlobalRequests(reqs)
+	go conn.handleChannelOpens(chans)
+	go func() {
+		conn.Wait()
+		conn.forwards.closeAll()
+	}()
+	return conn
+}
+
+// NewClientConn establishes an authenticated SSH connection using c
+// as the underlying transport.  The Request and NewChannel channels
+// must be serviced or the connection will hang.
+func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
+	fullConf := *config
+	fullConf.SetDefaults()
+	if fullConf.HostKeyCallback == nil {
+		c.Close()
+		return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback")
+	}
+
+	conn := &connection{
+		sshConn: sshConn{conn: c, user: fullConf.User},
+	}
+
+	if err := conn.clientHandshake(addr, &fullConf); err != nil {
+		c.Close()
+		return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %w", err)
+	}
+	conn.mux = newMux(conn.transport)
+	return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
+}
+
+// clientHandshake performs the client side key exchange. See RFC 4253 Section
+// 7.
+func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error {
+	if config.ClientVersion != "" {
+		c.clientVersion = []byte(config.ClientVersion)
+	} else {
+		c.clientVersion = []byte(packageVersion)
+	}
+	var err error
+	c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion)
+	if err != nil {
+		return err
+	}
+
+	c.transport = newClientTransport(
+		newTransport(c.sshConn.conn, config.Rand, true /* is client */),
+		c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr())
+	if err := c.transport.waitSession(); err != nil {
+		return err
+	}
+
+	c.sessionID = c.transport.getSessionID()
+	c.algorithms = c.transport.getAlgorithms()
+	return c.clientAuthenticate(config)
+}
+
+// verifyHostKeySignature verifies the host key obtained in the key exchange.
+// algo is the negotiated algorithm, and may be a certificate type.
+func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error {
+	sig, rest, ok := parseSignatureBody(result.Signature)
+	if len(rest) > 0 || !ok {
+		return errors.New("ssh: signature parse error")
+	}
+
+	if a := underlyingAlgo(algo); sig.Format != a {
+		return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, a)
+	}
+
+	return hostKey.Verify(result.H, sig)
+}
+
+// NewSession opens a new Session for this client. (A session is a remote
+// execution of a program.)
+func (c *Client) NewSession() (*Session, error) {
+	ch, in, err := c.OpenChannel("session", nil)
+	if err != nil {
+		return nil, err
+	}
+	return newSession(ch, in)
+}
+
+func (c *Client) handleGlobalRequests(incoming <-chan *Request) {
+	for r := range incoming {
+		// This handles keepalive messages and matches
+		// the behaviour of OpenSSH.
+		r.Reply(false, nil)
+	}
+}
+
+// handleChannelOpens channel open messages from the remote side.
+func (c *Client) handleChannelOpens(in <-chan NewChannel) {
+	for ch := range in {
+		c.mu.Lock()
+		handler := c.channelHandlers[ch.ChannelType()]
+		c.mu.Unlock()
+
+		if handler != nil {
+			handler <- ch
+		} else {
+			ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType()))
+		}
+	}
+
+	c.mu.Lock()
+	for _, ch := range c.channelHandlers {
+		close(ch)
+	}
+	c.channelHandlers = nil
+	c.mu.Unlock()
+}
+
+// Dial starts a client connection to the given SSH server. It is a
+// convenience function that connects to the given network address,
+// initiates the SSH handshake, and then sets up a Client.  For access
+// to incoming channels and requests, use net.Dial with NewClientConn
+// instead.
+func Dial(network, addr string, config *ClientConfig) (*Client, error) {
+	conn, err := net.DialTimeout(network, addr, config.Timeout)
+	if err != nil {
+		return nil, err
+	}
+	c, chans, reqs, err := NewClientConn(conn, addr, config)
+	if err != nil {
+		return nil, err
+	}
+	return NewClient(c, chans, reqs), nil
+}
+
+// HostKeyCallback is the function type used for verifying server
+// keys.  A HostKeyCallback must return nil if the host key is OK, or
+// an error to reject it. It receives the hostname as passed to Dial
+// or NewClientConn. The remote address is the RemoteAddr of the
+// net.Conn underlying the SSH connection.
+type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+
+// BannerCallback is the function type used for treat the banner sent by
+// the server. A BannerCallback receives the message sent by the remote server.
+type BannerCallback func(message string) error
+
+// A ClientConfig structure is used to configure a Client. It must not be
+// modified after having been passed to an SSH function.
+type ClientConfig struct {
+	// Config contains configuration that is shared between clients and
+	// servers.
+	Config
+
+	// User contains the username to authenticate as.
+	User string
+
+	// Auth contains possible authentication methods to use with the
+	// server. Only the first instance of a particular RFC 4252 method will
+	// be used during authentication.
+	Auth []AuthMethod
+
+	// HostKeyCallback is called during the cryptographic
+	// handshake to validate the server's host key. The client
+	// configuration must supply this callback for the connection
+	// to succeed. The functions InsecureIgnoreHostKey or
+	// FixedHostKey can be used for simplistic host key checks.
+	HostKeyCallback HostKeyCallback
+
+	// BannerCallback is called during the SSH dance to display a custom
+	// server's message. The client configuration can supply this callback to
+	// handle it as wished. The function BannerDisplayStderr can be used for
+	// simplistic display on Stderr.
+	BannerCallback BannerCallback
+
+	// ClientVersion contains the version identification string that will
+	// be used for the connection. If empty, a reasonable default is used.
+	ClientVersion string
+
+	// HostKeyAlgorithms lists the public key algorithms that the client will
+	// accept from the server for host key authentication, in order of
+	// preference. If empty, a reasonable default is used. Any
+	// string returned from a PublicKey.Type method may be used, or
+	// any of the CertAlgo and KeyAlgo constants.
+	HostKeyAlgorithms []string
+
+	// Timeout is the maximum amount of time for the TCP connection to establish.
+	//
+	// A Timeout of zero means no timeout.
+	Timeout time.Duration
+}
+
+// InsecureIgnoreHostKey returns a function that can be used for
+// ClientConfig.HostKeyCallback to accept any host key. It should
+// not be used for production code.
+func InsecureIgnoreHostKey() HostKeyCallback {
+	return func(hostname string, remote net.Addr, key PublicKey) error {
+		return nil
+	}
+}
+
+type fixedHostKey struct {
+	key PublicKey
+}
+
+func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error {
+	if f.key == nil {
+		return fmt.Errorf("ssh: required host key was nil")
+	}
+	if !bytes.Equal(key.Marshal(), f.key.Marshal()) {
+		return fmt.Errorf("ssh: host key mismatch")
+	}
+	return nil
+}
+
+// FixedHostKey returns a function for use in
+// ClientConfig.HostKeyCallback to accept only a specific host key.
+func FixedHostKey(key PublicKey) HostKeyCallback {
+	hk := &fixedHostKey{key}
+	return hk.check
+}
+
+// BannerDisplayStderr returns a function that can be used for
+// ClientConfig.BannerCallback to display banners on os.Stderr.
+func BannerDisplayStderr() BannerCallback {
+	return func(banner string) error {
+		_, err := os.Stderr.WriteString(banner)
+
+		return err
+	}
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go
new file mode 100644
index 000000000..4f2f75c36
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/client_auth.go
@@ -0,0 +1,792 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"slices"
+	"strings"
+)
+
+type authResult int
+
+const (
+	authFailure authResult = iota
+	authPartialSuccess
+	authSuccess
+)
+
+// clientAuthenticate authenticates with the remote server. See RFC 4252.
+func (c *connection) clientAuthenticate(config *ClientConfig) error {
+	// initiate user auth session
+	if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil {
+		return err
+	}
+	packet, err := c.transport.readPacket()
+	if err != nil {
+		return err
+	}
+	// The server may choose to send a SSH_MSG_EXT_INFO at this point (if we
+	// advertised willingness to receive one, which we always do) or not. See
+	// RFC 8308, Section 2.4.
+	extensions := make(map[string][]byte)
+	if len(packet) > 0 && packet[0] == msgExtInfo {
+		var extInfo extInfoMsg
+		if err := Unmarshal(packet, &extInfo); err != nil {
+			return err
+		}
+		payload := extInfo.Payload
+		for i := uint32(0); i < extInfo.NumExtensions; i++ {
+			name, rest, ok := parseString(payload)
+			if !ok {
+				return parseError(msgExtInfo)
+			}
+			value, rest, ok := parseString(rest)
+			if !ok {
+				return parseError(msgExtInfo)
+			}
+			extensions[string(name)] = value
+			payload = rest
+		}
+		packet, err = c.transport.readPacket()
+		if err != nil {
+			return err
+		}
+	}
+	var serviceAccept serviceAcceptMsg
+	if err := Unmarshal(packet, &serviceAccept); err != nil {
+		return err
+	}
+
+	// during the authentication phase the client first attempts the "none" method
+	// then any untried methods suggested by the server.
+	var tried []string
+	var lastMethods []string
+
+	sessionID := c.transport.getSessionID()
+	for auth := AuthMethod(new(noneAuth)); auth != nil; {
+		ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions)
+		if err != nil {
+			// On disconnect, return error immediately
+			if _, ok := err.(*disconnectMsg); ok {
+				return err
+			}
+			// We return the error later if there is no other method left to
+			// try.
+			ok = authFailure
+		}
+		if ok == authSuccess {
+			// success
+			return nil
+		} else if ok == authFailure {
+			if m := auth.method(); !slices.Contains(tried, m) {
+				tried = append(tried, m)
+			}
+		}
+		if methods == nil {
+			methods = lastMethods
+		}
+		lastMethods = methods
+
+		auth = nil
+
+	findNext:
+		for _, a := range config.Auth {
+			candidateMethod := a.method()
+			if slices.Contains(tried, candidateMethod) {
+				continue
+			}
+			for _, meth := range methods {
+				if meth == candidateMethod {
+					auth = a
+					break findNext
+				}
+			}
+		}
+
+		if auth == nil && err != nil {
+			// We have an error and there are no other authentication methods to
+			// try, so we return it.
+			return err
+		}
+	}
+	return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried)
+}
+
+// An AuthMethod represents an instance of an RFC 4252 authentication method.
+type AuthMethod interface {
+	// auth authenticates user over transport t.
+	// Returns true if authentication is successful.
+	// If authentication is not successful, a []string of alternative
+	// method names is returned. If the slice is nil, it will be ignored
+	// and the previous set of possible methods will be reused.
+	auth(session []byte, user string, p packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error)
+
+	// method returns the RFC 4252 method name.
+	method() string
+}
+
+// "none" authentication, RFC 4252 section 5.2.
+type noneAuth int
+
+func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
+	if err := c.writePacket(Marshal(&userAuthRequestMsg{
+		User:    user,
+		Service: serviceSSH,
+		Method:  "none",
+	})); err != nil {
+		return authFailure, nil, err
+	}
+
+	return handleAuthResponse(c)
+}
+
+func (n *noneAuth) method() string {
+	return "none"
+}
+
+// passwordCallback is an AuthMethod that fetches the password through
+// a function call, e.g. by prompting the user.
+type passwordCallback func() (password string, err error)
+
+func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
+	type passwordAuthMsg struct {
+		User     string `sshtype:"50"`
+		Service  string
+		Method   string
+		Reply    bool
+		Password string
+	}
+
+	pw, err := cb()
+	// REVIEW NOTE: is there a need to support skipping a password attempt?
+	// The program may only find out that the user doesn't have a password
+	// when prompting.
+	if err != nil {
+		return authFailure, nil, err
+	}
+
+	if err := c.writePacket(Marshal(&passwordAuthMsg{
+		User:     user,
+		Service:  serviceSSH,
+		Method:   cb.method(),
+		Reply:    false,
+		Password: pw,
+	})); err != nil {
+		return authFailure, nil, err
+	}
+
+	return handleAuthResponse(c)
+}
+
+func (cb passwordCallback) method() string {
+	return "password"
+}
+
+// Password returns an AuthMethod using the given password.
+func Password(secret string) AuthMethod {
+	return passwordCallback(func() (string, error) { return secret, nil })
+}
+
+// PasswordCallback returns an AuthMethod that uses a callback for
+// fetching a password.
+func PasswordCallback(prompt func() (secret string, err error)) AuthMethod {
+	return passwordCallback(prompt)
+}
+
+type publickeyAuthMsg struct {
+	User    string `sshtype:"50"`
+	Service string
+	Method  string
+	// HasSig indicates to the receiver packet that the auth request is signed and
+	// should be used for authentication of the request.
+	HasSig   bool
+	Algoname string
+	PubKey   []byte
+	// Sig is tagged with "rest" so Marshal will exclude it during
+	// validateKey
+	Sig []byte `ssh:"rest"`
+}
+
+// publicKeyCallback is an AuthMethod that uses a set of key
+// pairs for authentication.
+type publicKeyCallback func() ([]Signer, error)
+
+func (cb publicKeyCallback) method() string {
+	return "publickey"
+}
+
+func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiAlgorithmSigner, string, error) {
+	var as MultiAlgorithmSigner
+	keyFormat := signer.PublicKey().Type()
+
+	// If the signer implements MultiAlgorithmSigner we use the algorithms it
+	// support, if it implements AlgorithmSigner we assume it supports all
+	// algorithms, otherwise only the key format one.
+	switch s := signer.(type) {
+	case MultiAlgorithmSigner:
+		as = s
+	case AlgorithmSigner:
+		as = &multiAlgorithmSigner{
+			AlgorithmSigner:     s,
+			supportedAlgorithms: algorithmsForKeyFormat(underlyingAlgo(keyFormat)),
+		}
+	default:
+		as = &multiAlgorithmSigner{
+			AlgorithmSigner:     algorithmSignerWrapper{signer},
+			supportedAlgorithms: []string{underlyingAlgo(keyFormat)},
+		}
+	}
+
+	getFallbackAlgo := func() (string, error) {
+		// Fallback to use if there is no "server-sig-algs" extension or a
+		// common algorithm cannot be found. We use the public key format if the
+		// MultiAlgorithmSigner supports it, otherwise we return an error.
+		if !slices.Contains(as.Algorithms(), underlyingAlgo(keyFormat)) {
+			return "", fmt.Errorf("ssh: no common public key signature algorithm, server only supports %q for key type %q, signer only supports %v",
+				underlyingAlgo(keyFormat), keyFormat, as.Algorithms())
+		}
+		return keyFormat, nil
+	}
+
+	extPayload, ok := extensions["server-sig-algs"]
+	if !ok {
+		// If there is no "server-sig-algs" extension use the fallback
+		// algorithm.
+		algo, err := getFallbackAlgo()
+		return as, algo, err
+	}
+
+	// The server-sig-algs extension only carries underlying signature
+	// algorithm, but we are trying to select a protocol-level public key
+	// algorithm, which might be a certificate type. Extend the list of server
+	// supported algorithms to include the corresponding certificate algorithms.
+	serverAlgos := strings.Split(string(extPayload), ",")
+	for _, algo := range serverAlgos {
+		if certAlgo, ok := certificateAlgo(algo); ok {
+			serverAlgos = append(serverAlgos, certAlgo)
+		}
+	}
+
+	// Filter algorithms based on those supported by MultiAlgorithmSigner.
+	// Iterate over the signer's algorithms first to preserve its preference order.
+	supportedKeyAlgos := algorithmsForKeyFormat(keyFormat)
+	var keyAlgos []string
+	for _, signerAlgo := range as.Algorithms() {
+		if idx := slices.IndexFunc(supportedKeyAlgos, func(algo string) bool {
+			return underlyingAlgo(algo) == signerAlgo
+		}); idx >= 0 {
+			keyAlgos = append(keyAlgos, supportedKeyAlgos[idx])
+		}
+	}
+
+	algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos, true)
+	if err != nil {
+		// If there is no overlap, return the fallback algorithm to support
+		// servers that fail to list all supported algorithms.
+		algo, err := getFallbackAlgo()
+		return as, algo, err
+	}
+	return as, algo, nil
+}
+
+func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
+	// Authentication is performed by sending an enquiry to test if a key is
+	// acceptable to the remote. If the key is acceptable, the client will
+	// attempt to authenticate with the valid key.  If not the client will repeat
+	// the process with the remaining keys.
+
+	signers, err := cb()
+	if err != nil {
+		return authFailure, nil, err
+	}
+	var methods []string
+	var errSigAlgo error
+
+	origSignersLen := len(signers)
+	for idx := 0; idx < len(signers); idx++ {
+		signer := signers[idx]
+		pub := signer.PublicKey()
+		as, algo, err := pickSignatureAlgorithm(signer, extensions)
+		if err != nil && errSigAlgo == nil {
+			// If we cannot negotiate a signature algorithm store the first
+			// error so we can return it to provide a more meaningful message if
+			// no other signers work.
+			errSigAlgo = err
+			continue
+		}
+		ok, err := validateKey(pub, algo, user, c)
+		if err != nil {
+			return authFailure, nil, err
+		}
+		// OpenSSH 7.2-7.7 advertises support for rsa-sha2-256 and rsa-sha2-512
+		// in the "server-sig-algs" extension but doesn't support these
+		// algorithms for certificate authentication, so if the server rejects
+		// the key try to use the obtained algorithm as if "server-sig-algs" had
+		// not been implemented if supported from the algorithm signer.
+		if !ok && idx < origSignersLen && isRSACert(algo) && algo != CertAlgoRSAv01 {
+			if slices.Contains(as.Algorithms(), KeyAlgoRSA) {
+				// We retry using the compat algorithm after all signers have
+				// been tried normally.
+				signers = append(signers, &multiAlgorithmSigner{
+					AlgorithmSigner:     as,
+					supportedAlgorithms: []string{KeyAlgoRSA},
+				})
+			}
+		}
+		if !ok {
+			continue
+		}
+
+		pubKey := pub.Marshal()
+		data := buildDataSignedForAuth(session, userAuthRequestMsg{
+			User:    user,
+			Service: serviceSSH,
+			Method:  cb.method(),
+		}, algo, pubKey)
+		sign, err := as.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
+		if err != nil {
+			return authFailure, nil, err
+		}
+
+		// manually wrap the serialized signature in a string
+		s := Marshal(sign)
+		sig := make([]byte, stringLength(len(s)))
+		marshalString(sig, s)
+		msg := publickeyAuthMsg{
+			User:     user,
+			Service:  serviceSSH,
+			Method:   cb.method(),
+			HasSig:   true,
+			Algoname: algo,
+			PubKey:   pubKey,
+			Sig:      sig,
+		}
+		p := Marshal(&msg)
+		if err := c.writePacket(p); err != nil {
+			return authFailure, nil, err
+		}
+		var success authResult
+		success, methods, err = handleAuthResponse(c)
+		if err != nil {
+			return authFailure, nil, err
+		}
+
+		// If authentication succeeds or the list of available methods does not
+		// contain the "publickey" method, do not attempt to authenticate with any
+		// other keys.  According to RFC 4252 Section 7, the latter can occur when
+		// additional authentication methods are required.
+		if success == authSuccess || !slices.Contains(methods, cb.method()) {
+			return success, methods, err
+		}
+	}
+
+	return authFailure, methods, errSigAlgo
+}
+
+// validateKey validates the key provided is acceptable to the server.
+func validateKey(key PublicKey, algo string, user string, c packetConn) (bool, error) {
+	pubKey := key.Marshal()
+	msg := publickeyAuthMsg{
+		User:     user,
+		Service:  serviceSSH,
+		Method:   "publickey",
+		HasSig:   false,
+		Algoname: algo,
+		PubKey:   pubKey,
+	}
+	if err := c.writePacket(Marshal(&msg)); err != nil {
+		return false, err
+	}
+
+	return confirmKeyAck(key, c)
+}
+
+func confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
+	pubKey := key.Marshal()
+
+	for {
+		packet, err := c.readPacket()
+		if err != nil {
+			return false, err
+		}
+		switch packet[0] {
+		case msgUserAuthBanner:
+			if err := handleBannerResponse(c, packet); err != nil {
+				return false, err
+			}
+		case msgUserAuthPubKeyOk:
+			var msg userAuthPubKeyOkMsg
+			if err := Unmarshal(packet, &msg); err != nil {
+				return false, err
+			}
+			// According to RFC 4252 Section 7 the algorithm in
+			// SSH_MSG_USERAUTH_PK_OK should match that of the request but some
+			// servers send the key type instead. OpenSSH allows any algorithm
+			// that matches the public key, so we do the same.
+			// https://github.com/openssh/openssh-portable/blob/86bdd385/sshconnect2.c#L709
+			if !slices.Contains(algorithmsForKeyFormat(key.Type()), msg.Algo) {
+				return false, nil
+			}
+			if !bytes.Equal(msg.PubKey, pubKey) {
+				return false, nil
+			}
+			return true, nil
+		case msgUserAuthFailure:
+			return false, nil
+		default:
+			return false, unexpectedMessageError(msgUserAuthPubKeyOk, packet[0])
+		}
+	}
+}
+
+// PublicKeys returns an AuthMethod that uses the given key
+// pairs.
+func PublicKeys(signers ...Signer) AuthMethod {
+	return publicKeyCallback(func() ([]Signer, error) { return signers, nil })
+}
+
+// PublicKeysCallback returns an AuthMethod that runs the given
+// function to obtain a list of key pairs.
+func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod {
+	return publicKeyCallback(getSigners)
+}
+
+// handleAuthResponse returns whether the preceding authentication request succeeded
+// along with a list of remaining authentication methods to try next and
+// an error if an unexpected response was received.
+func handleAuthResponse(c packetConn) (authResult, []string, error) {
+	gotMsgExtInfo := false
+	for {
+		packet, err := c.readPacket()
+		if err != nil {
+			return authFailure, nil, err
+		}
+
+		switch packet[0] {
+		case msgUserAuthBanner:
+			if err := handleBannerResponse(c, packet); err != nil {
+				return authFailure, nil, err
+			}
+		case msgExtInfo:
+			// Ignore post-authentication RFC 8308 extensions, once.
+			if gotMsgExtInfo {
+				return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
+			}
+			gotMsgExtInfo = true
+		case msgUserAuthFailure:
+			var msg userAuthFailureMsg
+			if err := Unmarshal(packet, &msg); err != nil {
+				return authFailure, nil, err
+			}
+			if msg.PartialSuccess {
+				return authPartialSuccess, msg.Methods, nil
+			}
+			return authFailure, msg.Methods, nil
+		case msgUserAuthSuccess:
+			return authSuccess, nil, nil
+		default:
+			return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
+		}
+	}
+}
+
+func handleBannerResponse(c packetConn, packet []byte) error {
+	var msg userAuthBannerMsg
+	if err := Unmarshal(packet, &msg); err != nil {
+		return err
+	}
+
+	transport, ok := c.(*handshakeTransport)
+	if !ok {
+		return nil
+	}
+
+	if transport.bannerCallback != nil {
+		return transport.bannerCallback(msg.Message)
+	}
+
+	return nil
+}
+
+// KeyboardInteractiveChallenge should print questions, optionally
+// disabling echoing (e.g. for passwords), and return all the answers.
+// Challenge may be called multiple times in a single session. After
+// successful authentication, the server may send a challenge with no
+// questions, for which the name and instruction messages should be
+// printed.  RFC 4256 section 3.3 details how the UI should behave for
+// both CLI and GUI environments.
+type KeyboardInteractiveChallenge func(name, instruction string, questions []string, echos []bool) (answers []string, err error)
+
+// KeyboardInteractive returns an AuthMethod using a prompt/response
+// sequence controlled by the server.
+func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod {
+	return challenge
+}
+
+func (cb KeyboardInteractiveChallenge) method() string {
+	return "keyboard-interactive"
+}
+
+func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
+	type initiateMsg struct {
+		User       string `sshtype:"50"`
+		Service    string
+		Method     string
+		Language   string
+		Submethods string
+	}
+
+	if err := c.writePacket(Marshal(&initiateMsg{
+		User:    user,
+		Service: serviceSSH,
+		Method:  "keyboard-interactive",
+	})); err != nil {
+		return authFailure, nil, err
+	}
+
+	gotMsgExtInfo := false
+	gotUserAuthInfoRequest := false
+	for {
+		packet, err := c.readPacket()
+		if err != nil {
+			return authFailure, nil, err
+		}
+
+		// like handleAuthResponse, but with less options.
+		switch packet[0] {
+		case msgUserAuthBanner:
+			if err := handleBannerResponse(c, packet); err != nil {
+				return authFailure, nil, err
+			}
+			continue
+		case msgExtInfo:
+			// Ignore post-authentication RFC 8308 extensions, once.
+			if gotMsgExtInfo {
+				return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
+			}
+			gotMsgExtInfo = true
+			continue
+		case msgUserAuthInfoRequest:
+			// OK
+		case msgUserAuthFailure:
+			var msg userAuthFailureMsg
+			if err := Unmarshal(packet, &msg); err != nil {
+				return authFailure, nil, err
+			}
+			if msg.PartialSuccess {
+				return authPartialSuccess, msg.Methods, nil
+			}
+			if !gotUserAuthInfoRequest {
+				return authFailure, msg.Methods, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
+			}
+			return authFailure, msg.Methods, nil
+		case msgUserAuthSuccess:
+			return authSuccess, nil, nil
+		default:
+			return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
+		}
+
+		var msg userAuthInfoRequestMsg
+		if err := Unmarshal(packet, &msg); err != nil {
+			return authFailure, nil, err
+		}
+		gotUserAuthInfoRequest = true
+
+		// Manually unpack the prompt/echo pairs.
+		rest := msg.Prompts
+		var prompts []string
+		var echos []bool
+		for i := 0; i < int(msg.NumPrompts); i++ {
+			prompt, r, ok := parseString(rest)
+			if !ok || len(r) == 0 {
+				return authFailure, nil, errors.New("ssh: prompt format error")
+			}
+			prompts = append(prompts, string(prompt))
+			echos = append(echos, r[0] != 0)
+			rest = r[1:]
+		}
+
+		if len(rest) != 0 {
+			return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
+		}
+
+		answers, err := cb(msg.Name, msg.Instruction, prompts, echos)
+		if err != nil {
+			return authFailure, nil, err
+		}
+
+		if len(answers) != len(prompts) {
+			return authFailure, nil, fmt.Errorf("ssh: incorrect number of answers from keyboard-interactive callback %d (expected %d)", len(answers), len(prompts))
+		}
+		responseLength := 1 + 4
+		for _, a := range answers {
+			responseLength += stringLength(len(a))
+		}
+		serialized := make([]byte, responseLength)
+		p := serialized
+		p[0] = msgUserAuthInfoResponse
+		p = p[1:]
+		p = marshalUint32(p, uint32(len(answers)))
+		for _, a := range answers {
+			p = marshalString(p, []byte(a))
+		}
+
+		if err := c.writePacket(serialized); err != nil {
+			return authFailure, nil, err
+		}
+	}
+}
+
+type retryableAuthMethod struct {
+	authMethod AuthMethod
+	maxTries   int
+}
+
+func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (ok authResult, methods []string, err error) {
+	for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ {
+		ok, methods, err = r.authMethod.auth(session, user, c, rand, extensions)
+		if ok != authFailure || err != nil { // either success, partial success or error terminate
+			return ok, methods, err
+		}
+	}
+	return ok, methods, err
+}
+
+func (r *retryableAuthMethod) method() string {
+	return r.authMethod.method()
+}
+
+// RetryableAuthMethod is a decorator for other auth methods enabling them to
+// be retried up to maxTries before considering that AuthMethod itself failed.
+// If maxTries is <= 0, will retry indefinitely
+//
+// This is useful for interactive clients using challenge/response type
+// authentication (e.g. Keyboard-Interactive, Password, etc) where the user
+// could mistype their response resulting in the server issuing a
+// SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4
+// [keyboard-interactive]); Without this decorator, the non-retryable
+// AuthMethod would be removed from future consideration, and never tried again
+// (and so the user would never be able to retry their entry).
+func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod {
+	return &retryableAuthMethod{authMethod: auth, maxTries: maxTries}
+}
+
+// GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication.
+// See RFC 4462 section 3
+// gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details.
+// target is the server host you want to log in to.
+func GSSAPIWithMICAuthMethod(gssAPIClient GSSAPIClient, target string) AuthMethod {
+	if gssAPIClient == nil {
+		panic("gss-api client must be not nil with enable gssapi-with-mic")
+	}
+	return &gssAPIWithMICCallback{gssAPIClient: gssAPIClient, target: target}
+}
+
+type gssAPIWithMICCallback struct {
+	gssAPIClient GSSAPIClient
+	target       string
+}
+
+func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
+	m := &userAuthRequestMsg{
+		User:    user,
+		Service: serviceSSH,
+		Method:  g.method(),
+	}
+	// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST.
+	// See RFC 4462 section 3.2.
+	m.Payload = appendU32(m.Payload, 1)
+	m.Payload = appendString(m.Payload, string(krb5OID))
+	if err := c.writePacket(Marshal(m)); err != nil {
+		return authFailure, nil, err
+	}
+	// The server responds to the SSH_MSG_USERAUTH_REQUEST with either an
+	// SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or
+	// with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE.
+	// See RFC 4462 section 3.3.
+	// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check
+	// selected mech if it is valid.
+	packet, err := c.readPacket()
+	if err != nil {
+		return authFailure, nil, err
+	}
+	userAuthGSSAPIResp := &userAuthGSSAPIResponse{}
+	if err := Unmarshal(packet, userAuthGSSAPIResp); err != nil {
+		return authFailure, nil, err
+	}
+	// Start the loop into the exchange token.
+	// See RFC 4462 section 3.4.
+	var token []byte
+	defer g.gssAPIClient.DeleteSecContext()
+	for {
+		// Initiates the establishment of a security context between the application and a remote peer.
+		nextToken, needContinue, err := g.gssAPIClient.InitSecContext("host@"+g.target, token, false)
+		if err != nil {
+			return authFailure, nil, err
+		}
+		if len(nextToken) > 0 {
+			if err := c.writePacket(Marshal(&userAuthGSSAPIToken{
+				Token: nextToken,
+			})); err != nil {
+				return authFailure, nil, err
+			}
+		}
+		if !needContinue {
+			break
+		}
+		packet, err = c.readPacket()
+		if err != nil {
+			return authFailure, nil, err
+		}
+		switch packet[0] {
+		case msgUserAuthFailure:
+			var msg userAuthFailureMsg
+			if err := Unmarshal(packet, &msg); err != nil {
+				return authFailure, nil, err
+			}
+			if msg.PartialSuccess {
+				return authPartialSuccess, msg.Methods, nil
+			}
+			return authFailure, msg.Methods, nil
+		case msgUserAuthGSSAPIError:
+			userAuthGSSAPIErrorResp := &userAuthGSSAPIError{}
+			if err := Unmarshal(packet, userAuthGSSAPIErrorResp); err != nil {
+				return authFailure, nil, err
+			}
+			return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+
+				"Major Status: %d\n"+
+				"Minor Status: %d\n"+
+				"Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus,
+				userAuthGSSAPIErrorResp.Message)
+		case msgUserAuthGSSAPIToken:
+			userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
+			if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
+				return authFailure, nil, err
+			}
+			token = userAuthGSSAPITokenReq.Token
+		}
+	}
+	// Binding Encryption Keys.
+	// See RFC 4462 section 3.5.
+	micField := buildMIC(string(session), user, "ssh-connection", "gssapi-with-mic")
+	micToken, err := g.gssAPIClient.GetMIC(micField)
+	if err != nil {
+		return authFailure, nil, err
+	}
+	if err := c.writePacket(Marshal(&userAuthGSSAPIMIC{
+		MIC: micToken,
+	})); err != nil {
+		return authFailure, nil, err
+	}
+	return handleAuthResponse(c)
+}
+
+func (g *gssAPIWithMICCallback) method() string {
+	return "gssapi-with-mic"
+}
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
new file mode 100644
index 000000000..2e44e9c9e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -0,0 +1,727 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"crypto"
+	"crypto/fips140"
+	"crypto/rand"
+	"fmt"
+	"io"
+	"math"
+	"slices"
+	"sync"
+
+	_ "crypto/sha1"
+	_ "crypto/sha256"
+	_ "crypto/sha512"
+)
+
+// These are string constants in the SSH protocol.
+const (
+	compressionNone = "none"
+	serviceUserAuth = "ssh-userauth"
+	serviceSSH      = "ssh-connection"
+)
+
+// The ciphers currently or previously implemented by this library, to use in
+// [Config.Ciphers]. For a list, see the [Algorithms.Ciphers] returned by
+// [SupportedAlgorithms] or [InsecureAlgorithms].
+const (
+	CipherAES128GCM            = "aes128-gcm@openssh.com"
+	CipherAES256GCM            = "aes256-gcm@openssh.com"
+	CipherChaCha20Poly1305     = "chacha20-poly1305@openssh.com"
+	CipherAES128CTR            = "aes128-ctr"
+	CipherAES192CTR            = "aes192-ctr"
+	CipherAES256CTR            = "aes256-ctr"
+	InsecureCipherAES128CBC    = "aes128-cbc"
+	InsecureCipherTripleDESCBC = "3des-cbc"
+	InsecureCipherRC4          = "arcfour"
+	InsecureCipherRC4128       = "arcfour128"
+	InsecureCipherRC4256       = "arcfour256"
+)
+
+// The key exchanges currently or previously implemented by this library, to use
+// in [Config.KeyExchanges]. For a list, see the
+// [Algorithms.KeyExchanges] returned by [SupportedAlgorithms] or
+// [InsecureAlgorithms].
+const (
+	InsecureKeyExchangeDH1SHA1   = "diffie-hellman-group1-sha1"
+	InsecureKeyExchangeDH14SHA1  = "diffie-hellman-group14-sha1"
+	KeyExchangeDH14SHA256        = "diffie-hellman-group14-sha256"
+	KeyExchangeDH16SHA512        = "diffie-hellman-group16-sha512"
+	KeyExchangeECDHP256          = "ecdh-sha2-nistp256"
+	KeyExchangeECDHP384          = "ecdh-sha2-nistp384"
+	KeyExchangeECDHP521          = "ecdh-sha2-nistp521"
+	KeyExchangeCurve25519        = "curve25519-sha256"
+	InsecureKeyExchangeDHGEXSHA1 = "diffie-hellman-group-exchange-sha1"
+	KeyExchangeDHGEXSHA256       = "diffie-hellman-group-exchange-sha256"
+	// KeyExchangeMLKEM768X25519 is supported from Go 1.24.
+	KeyExchangeMLKEM768X25519 = "mlkem768x25519-sha256"
+
+	// An alias for KeyExchangeCurve25519SHA256. This kex ID will be added if
+	// KeyExchangeCurve25519SHA256 is requested for backward compatibility with
+	// OpenSSH versions up to 7.2.
+	keyExchangeCurve25519LibSSH = "curve25519-sha256@libssh.org"
+)
+
+// The message authentication code (MAC) currently or previously implemented by
+// this library, to use in [Config.MACs]. For a list, see the
+// [Algorithms.MACs] returned by [SupportedAlgorithms] or
+// [InsecureAlgorithms].
+const (
+	HMACSHA256ETM      = "hmac-sha2-256-etm@openssh.com"
+	HMACSHA512ETM      = "hmac-sha2-512-etm@openssh.com"
+	HMACSHA256         = "hmac-sha2-256"
+	HMACSHA512         = "hmac-sha2-512"
+	HMACSHA1           = "hmac-sha1"
+	InsecureHMACSHA196 = "hmac-sha1-96"
+)
+
+var (
+	// supportedKexAlgos specifies key-exchange algorithms implemented by this
+	// package in preference order, excluding those with security issues.
+	supportedKexAlgos = []string{
+		KeyExchangeMLKEM768X25519,
+		KeyExchangeCurve25519,
+		KeyExchangeECDHP256,
+		KeyExchangeECDHP384,
+		KeyExchangeECDHP521,
+		KeyExchangeDH14SHA256,
+		KeyExchangeDH16SHA512,
+		KeyExchangeDHGEXSHA256,
+	}
+	// defaultKexAlgos specifies the default preference for key-exchange
+	// algorithms in preference order.
+	defaultKexAlgos = []string{
+		KeyExchangeMLKEM768X25519,
+		KeyExchangeCurve25519,
+		KeyExchangeECDHP256,
+		KeyExchangeECDHP384,
+		KeyExchangeECDHP521,
+		KeyExchangeDH14SHA256,
+		InsecureKeyExchangeDH14SHA1,
+	}
+	// insecureKexAlgos specifies key-exchange algorithms implemented by this
+	// package and which have security issues.
+	insecureKexAlgos = []string{
+		InsecureKeyExchangeDH14SHA1,
+		InsecureKeyExchangeDH1SHA1,
+		InsecureKeyExchangeDHGEXSHA1,
+	}
+	// supportedCiphers specifies cipher algorithms implemented by this package
+	// in preference order, excluding those with security issues.
+	supportedCiphers = []string{
+		CipherAES128GCM,
+		CipherAES256GCM,
+		CipherChaCha20Poly1305,
+		CipherAES128CTR,
+		CipherAES192CTR,
+		CipherAES256CTR,
+	}
+	// defaultCiphers specifies the default preference for ciphers algorithms
+	// in preference order.
+	defaultCiphers = supportedCiphers
+	// insecureCiphers specifies cipher algorithms implemented by this
+	// package and which have security issues.
+	insecureCiphers = []string{
+		InsecureCipherAES128CBC,
+		InsecureCipherTripleDESCBC,
+		InsecureCipherRC4256,
+		InsecureCipherRC4128,
+		InsecureCipherRC4,
+	}
+	// supportedMACs specifies MAC algorithms implemented by this package in
+	// preference order, excluding those with security issues.
+	supportedMACs = []string{
+		HMACSHA256ETM,
+		HMACSHA512ETM,
+		HMACSHA256,
+		HMACSHA512,
+		HMACSHA1,
+	}
+	// defaultMACs specifies the default preference for MAC algorithms in
+	// preference order.
+	defaultMACs = []string{
+		HMACSHA256ETM,
+		HMACSHA512ETM,
+		HMACSHA256,
+		HMACSHA512,
+		HMACSHA1,
+		InsecureHMACSHA196,
+	}
+	// insecureMACs specifies MAC algorithms implemented by this
+	// package and which have security issues.
+	insecureMACs = []string{
+		InsecureHMACSHA196,
+	}
+	// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e.
+	// methods of authenticating servers) implemented by this package in
+	// preference order, excluding those with security issues.
+	supportedHostKeyAlgos = []string{
+		CertAlgoRSASHA256v01,
+		CertAlgoRSASHA512v01,
+		CertAlgoECDSA256v01,
+		CertAlgoECDSA384v01,
+		CertAlgoECDSA521v01,
+		CertAlgoED25519v01,
+		KeyAlgoRSASHA256,
+		KeyAlgoRSASHA512,
+		KeyAlgoECDSA256,
+		KeyAlgoECDSA384,
+		KeyAlgoECDSA521,
+		KeyAlgoED25519,
+	}
+	// defaultHostKeyAlgos specifies the default preference for host-key
+	// algorithms in preference order.
+	defaultHostKeyAlgos = []string{
+		CertAlgoRSASHA256v01,
+		CertAlgoRSASHA512v01,
+		CertAlgoRSAv01,
+		InsecureCertAlgoDSAv01,
+		CertAlgoECDSA256v01,
+		CertAlgoECDSA384v01,
+		CertAlgoECDSA521v01,
+		CertAlgoED25519v01,
+		KeyAlgoECDSA256,
+		KeyAlgoECDSA384,
+		KeyAlgoECDSA521,
+		KeyAlgoRSASHA256,
+		KeyAlgoRSASHA512,
+		KeyAlgoRSA,
+		InsecureKeyAlgoDSA,
+		KeyAlgoED25519,
+	}
+	// insecureHostKeyAlgos specifies host-key algorithms implemented by this
+	// package and which have security issues.
+	insecureHostKeyAlgos = []string{
+		KeyAlgoRSA,
+		InsecureKeyAlgoDSA,
+		CertAlgoRSAv01,
+		InsecureCertAlgoDSAv01,
+	}
+	// supportedPubKeyAuthAlgos specifies the supported client public key
+	// authentication algorithms. Note that this doesn't include certificate
+	// types since those use the underlying algorithm. Order is irrelevant.
+	supportedPubKeyAuthAlgos = []string{
+		KeyAlgoED25519,
+		KeyAlgoSKED25519,
+		KeyAlgoSKECDSA256,
+		KeyAlgoECDSA256,
+		KeyAlgoECDSA384,
+		KeyAlgoECDSA521,
+		KeyAlgoRSASHA256,
+		KeyAlgoRSASHA512,
+	}
+
+	// defaultPubKeyAuthAlgos specifies the preferred client public key
+	// authentication algorithms. This list is sent to the client if it supports
+	// the server-sig-algs extension. Order is irrelevant.
+	defaultPubKeyAuthAlgos = []string{
+		KeyAlgoED25519,
+		KeyAlgoSKED25519,
+		KeyAlgoSKECDSA256,
+		KeyAlgoECDSA256,
+		KeyAlgoECDSA384,
+		KeyAlgoECDSA521,
+		KeyAlgoRSASHA256,
+		KeyAlgoRSASHA512,
+		KeyAlgoRSA,
+		InsecureKeyAlgoDSA,
+	}
+	// insecurePubKeyAuthAlgos specifies client public key authentication
+	// algorithms implemented by this package and which have security issues.
+	insecurePubKeyAuthAlgos = []string{
+		KeyAlgoRSA,
+		InsecureKeyAlgoDSA,
+	}
+)
+
+// NegotiatedAlgorithms defines algorithms negotiated between client and server.
+type NegotiatedAlgorithms struct {
+	KeyExchange string
+	HostKey     string
+	Read        DirectionAlgorithms
+	Write       DirectionAlgorithms
+}
+
+// Algorithms defines a set of algorithms that can be configured in the client
+// or server config for negotiation during a handshake.
+type Algorithms struct {
+	KeyExchanges   []string
+	Ciphers        []string
+	MACs           []string
+	HostKeys       []string
+	PublicKeyAuths []string
+}
+
+func init() {
+	if fips140.Enabled() {
+		defaultHostKeyAlgos = slices.DeleteFunc(defaultHostKeyAlgos, func(algo string) bool {
+			_, err := hashFunc(underlyingAlgo(algo))
+			return err != nil
+		})
+		defaultPubKeyAuthAlgos = slices.DeleteFunc(defaultPubKeyAuthAlgos, func(algo string) bool {
+			_, err := hashFunc(underlyingAlgo(algo))
+			return err != nil
+		})
+	}
+}
+
+func hashFunc(format string) (crypto.Hash, error) {
+	switch format {
+	case KeyAlgoRSASHA256, KeyAlgoECDSA256, KeyAlgoSKED25519, KeyAlgoSKECDSA256:
+		return crypto.SHA256, nil
+	case KeyAlgoECDSA384:
+		return crypto.SHA384, nil
+	case KeyAlgoRSASHA512, KeyAlgoECDSA521:
+		return crypto.SHA512, nil
+	case KeyAlgoED25519:
+		// KeyAlgoED25519 doesn't pre-hash.
+		return 0, nil
+	case KeyAlgoRSA, InsecureKeyAlgoDSA:
+		if fips140.Enabled() {
+			return 0, fmt.Errorf("ssh: hash algorithm for format %q not allowed in FIPS 140 mode", format)
+		}
+		return crypto.SHA1, nil
+	default:
+		return 0, fmt.Errorf("ssh: hash algorithm for format %q not mapped", format)
+	}
+}
+
+// SupportedAlgorithms returns algorithms currently implemented by this package,
+// excluding those with security issues, which are returned by
+// InsecureAlgorithms. The algorithms listed here are in preference order.
+func SupportedAlgorithms() Algorithms {
+	return Algorithms{
+		Ciphers:        slices.Clone(supportedCiphers),
+		MACs:           slices.Clone(supportedMACs),
+		KeyExchanges:   slices.Clone(supportedKexAlgos),
+		HostKeys:       slices.Clone(supportedHostKeyAlgos),
+		PublicKeyAuths: slices.Clone(supportedPubKeyAuthAlgos),
+	}
+}
+
+// InsecureAlgorithms returns algorithms currently implemented by this package
+// and which have security issues.
+func InsecureAlgorithms() Algorithms {
+	return Algorithms{
+		KeyExchanges:   slices.Clone(insecureKexAlgos),
+		Ciphers:        slices.Clone(insecureCiphers),
+		MACs:           slices.Clone(insecureMACs),
+		HostKeys:       slices.Clone(insecureHostKeyAlgos),
+		PublicKeyAuths: slices.Clone(insecurePubKeyAuthAlgos),
+	}
+}
+
+var supportedCompressions = []string{compressionNone}
+
+// algorithmsForKeyFormat returns the supported signature algorithms for a given
+// public key format (PublicKey.Type), in order of preference. See RFC 8332,
+// Section 2. See also the note in sendKexInit on backwards compatibility.
+func algorithmsForKeyFormat(keyFormat string) []string {
+	switch keyFormat {
+	case KeyAlgoRSA:
+		return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA}
+	case CertAlgoRSAv01:
+		return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01}
+	default:
+		return []string{keyFormat}
+	}
+}
+
+// keyFormatForAlgorithm returns the key format corresponding to the given
+// signature algorithm. It returns an empty string if the signature algorithm is
+// invalid or unsupported.
+func keyFormatForAlgorithm(sigAlgo string) string {
+	switch sigAlgo {
+	case KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512:
+		return KeyAlgoRSA
+	case CertAlgoRSAv01, CertAlgoRSASHA256v01, CertAlgoRSASHA512v01:
+		return CertAlgoRSAv01
+	case KeyAlgoED25519,
+		KeyAlgoSKED25519,
+		KeyAlgoSKECDSA256,
+		KeyAlgoECDSA256,
+		KeyAlgoECDSA384,
+		KeyAlgoECDSA521,
+		InsecureKeyAlgoDSA,
+		InsecureCertAlgoDSAv01,
+		CertAlgoECDSA256v01,
+		CertAlgoECDSA384v01,
+		CertAlgoECDSA521v01,
+		CertAlgoSKECDSA256v01,
+		CertAlgoED25519v01,
+		CertAlgoSKED25519v01:
+		return sigAlgo
+	default:
+		return ""
+	}
+}
+
+// isRSA returns whether algo is a supported RSA algorithm, including certificate
+// algorithms.
+func isRSA(algo string) bool {
+	algos := algorithmsForKeyFormat(KeyAlgoRSA)
+	return slices.Contains(algos, underlyingAlgo(algo))
+}
+
+func isRSACert(algo string) bool {
+	_, ok := certKeyAlgoNames[algo]
+	if !ok {
+		return false
+	}
+	return isRSA(algo)
+}
+
+// unexpectedMessageError results when the SSH message that we received didn't
+// match what we wanted.
+func unexpectedMessageError(expected, got uint8) error {
+	return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
+}
+
+// parseError results from a malformed SSH message.
+func parseError(tag uint8) error {
+	return fmt.Errorf("ssh: parse error in message type %d", tag)
+}
+
+func findCommon(what string, client []string, server []string, isClient bool) (string, error) {
+	for _, c := range client {
+		for _, s := range server {
+			if c == s {
+				return c, nil
+			}
+		}
+	}
+	err := &AlgorithmNegotiationError{
+		What: what,
+	}
+	if isClient {
+		err.SupportedAlgorithms = client
+		err.RequestedAlgorithms = server
+	} else {
+		err.SupportedAlgorithms = server
+		err.RequestedAlgorithms = client
+	}
+	return "", err
+}
+
+// AlgorithmNegotiationError defines the error returned if the client and the
+// server cannot agree on an algorithm for key exchange, host key, cipher, MAC.
+type AlgorithmNegotiationError struct {
+	What string
+	// RequestedAlgorithms lists the algorithms supported by the peer.
+	RequestedAlgorithms []string
+	// SupportedAlgorithms lists the algorithms supported on our side.
+	SupportedAlgorithms []string
+}
+
+func (a *AlgorithmNegotiationError) Error() string {
+	return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %v, peer offered: %v",
+		a.What, a.SupportedAlgorithms, a.RequestedAlgorithms)
+}
+
+// DirectionAlgorithms defines the algorithms negotiated in one direction
+// (either read or write).
+type DirectionAlgorithms struct {
+	Cipher      string
+	MAC         string
+	compression string
+}
+
+// rekeyBytes returns a rekeying intervals in bytes.
+func (a *DirectionAlgorithms) rekeyBytes() int64 {
+	// According to RFC 4344 block ciphers should rekey after
+	// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
+	// 128.
+	switch a.Cipher {
+	case CipherAES128CTR, CipherAES192CTR, CipherAES256CTR, CipherAES128GCM, CipherAES256GCM, InsecureCipherAES128CBC:
+		return 16 * (1 << 32)
+
+	}
+
+	// For others, stick with RFC 4253 recommendation to rekey after 1 Gb of data.
+	return 1 << 30
+}
+
+var aeadCiphers = map[string]bool{
+	CipherAES128GCM:        true,
+	CipherAES256GCM:        true,
+	CipherChaCha20Poly1305: true,
+}
+
+func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *NegotiatedAlgorithms, err error) {
+	result := &NegotiatedAlgorithms{}
+
+	result.KeyExchange, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos, isClient)
+	if err != nil {
+		return
+	}
+
+	result.HostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos, isClient)
+	if err != nil {
+		return
+	}
+
+	stoc, ctos := &result.Write, &result.Read
+	if isClient {
+		ctos, stoc = stoc, ctos
+	}
+
+	ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer, isClient)
+	if err != nil {
+		return
+	}
+
+	stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient, isClient)
+	if err != nil {
+		return
+	}
+
+	if !aeadCiphers[ctos.Cipher] {
+		ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer, isClient)
+		if err != nil {
+			return
+		}
+	}
+
+	if !aeadCiphers[stoc.Cipher] {
+		stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient, isClient)
+		if err != nil {
+			return
+		}
+	}
+
+	ctos.compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer, isClient)
+	if err != nil {
+		return
+	}
+
+	stoc.compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient, isClient)
+	if err != nil {
+		return
+	}
+
+	return result, nil
+}
+
+// If rekeythreshold is too small, we can't make any progress sending
+// stuff.
+const minRekeyThreshold uint64 = 256
+
+// Config contains configuration data common to both ServerConfig and
+// ClientConfig.
+type Config struct {
+	// Rand provides the source of entropy for cryptographic
+	// primitives. If Rand is nil, the cryptographic random reader
+	// in package crypto/rand will be used.
+	Rand io.Reader
+
+	// The maximum number of bytes sent or received after which a
+	// new key is negotiated. It must be at least 256. If
+	// unspecified, a size suitable for the chosen cipher is used.
+	RekeyThreshold uint64
+
+	// The allowed key exchanges algorithms. If unspecified then a default set
+	// of algorithms is used. Unsupported values are silently ignored.
+	KeyExchanges []string
+
+	// The allowed cipher algorithms. If unspecified then a sensible default is
+	// used. Unsupported values are silently ignored.
+	Ciphers []string
+
+	// The allowed MAC algorithms. If unspecified then a sensible default is
+	// used. Unsupported values are silently ignored.
+	MACs []string
+}
+
+// SetDefaults sets sensible values for unset fields in config. This is
+// exported for testing: Configs passed to SSH functions are copied and have
+// default values set automatically.
+func (c *Config) SetDefaults() {
+	if c.Rand == nil {
+		c.Rand = rand.Reader
+	}
+	if c.Ciphers == nil {
+		c.Ciphers = defaultCiphers
+	}
+	var ciphers []string
+	for _, c := range c.Ciphers {
+		if cipherModes[c] != nil {
+			// Ignore the cipher if we have no cipherModes definition.
+			ciphers = append(ciphers, c)
+		}
+	}
+	c.Ciphers = ciphers
+
+	if c.KeyExchanges == nil {
+		c.KeyExchanges = defaultKexAlgos
+	}
+	var kexs []string
+	for _, k := range c.KeyExchanges {
+		if kexAlgoMap[k] != nil {
+			// Ignore the KEX if we have no kexAlgoMap definition.
+			kexs = append(kexs, k)
+			if k == KeyExchangeCurve25519 && !slices.Contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) {
+				kexs = append(kexs, keyExchangeCurve25519LibSSH)
+			}
+		}
+	}
+	c.KeyExchanges = kexs
+
+	if c.MACs == nil {
+		c.MACs = defaultMACs
+	}
+	var macs []string
+	for _, m := range c.MACs {
+		if macModes[m] != nil {
+			// Ignore the MAC if we have no macModes definition.
+			macs = append(macs, m)
+		}
+	}
+	c.MACs = macs
+
+	if c.RekeyThreshold == 0 {
+		// cipher specific default
+	} else if c.RekeyThreshold < minRekeyThreshold {
+		c.RekeyThreshold = minRekeyThreshold
+	} else if c.RekeyThreshold >= math.MaxInt64 {
+		// Avoid weirdness if somebody uses -1 as a threshold.
+		c.RekeyThreshold = math.MaxInt64
+	}
+}
+
+// buildDataSignedForAuth returns the data that is signed in order to prove
+// possession of a private key. See RFC 4252, section 7. algo is the advertised
+// algorithm, and may be a certificate type.
+func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte {
+	data := struct {
+		Session []byte
+		Type    byte
+		User    string
+		Service string
+		Method  string
+		Sign    bool
+		Algo    string
+		PubKey  []byte
+	}{
+		sessionID,
+		msgUserAuthRequest,
+		req.User,
+		req.Service,
+		req.Method,
+		true,
+		algo,
+		pubKey,
+	}
+	return Marshal(data)
+}
+
+func appendU16(buf []byte, n uint16) []byte {
+	return append(buf, byte(n>>8), byte(n))
+}
+
+func appendU32(buf []byte, n uint32) []byte {
+	return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
+}
+
+func appendU64(buf []byte, n uint64) []byte {
+	return append(buf,
+		byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
+		byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
+}
+
+func appendInt(buf []byte, n int) []byte {
+	return appendU32(buf, uint32(n))
+}
+
+func appendString(buf []byte, s string) []byte {
+	buf = appendU32(buf, uint32(len(s)))
+	buf = append(buf, s...)
+	return buf
+}
+
+func appendBool(buf []byte, b bool) []byte {
+	if b {
+		return append(buf, 1)
+	}
+	return append(buf, 0)
+}
+
+// newCond is a helper to hide the fact that there is no usable zero
+// value for sync.Cond.
+func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
+
+// window represents the buffer available to clients
+// wishing to write to a channel.
+type window struct {
+	*sync.Cond
+	win          uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
+	writeWaiters int
+	closed       bool
+}
+
+// add adds win to the amount of window available
+// for consumers.
+func (w *window) add(win uint32) bool {
+	// a zero sized window adjust is a noop.
+	if win == 0 {
+		return true
+	}
+	w.L.Lock()
+	if w.win+win < win {
+		w.L.Unlock()
+		return false
+	}
+	w.win += win
+	// It is unusual that multiple goroutines would be attempting to reserve
+	// window space, but not guaranteed. Use broadcast to notify all waiters
+	// that additional window is available.
+	w.Broadcast()
+	w.L.Unlock()
+	return true
+}
+
+// close sets the window to closed, so all reservations fail
+// immediately.
+func (w *window) close() {
+	w.L.Lock()
+	w.closed = true
+	w.Broadcast()
+	w.L.Unlock()
+}
+
+// reserve reserves win from the available window capacity.
+// If no capacity remains, reserve will block. reserve may
+// return less than requested.
+func (w *window) reserve(win uint32) (uint32, error) {
+	var err error
+	w.L.Lock()
+	w.writeWaiters++
+	w.Broadcast()
+	for w.win == 0 && !w.closed {
+		w.Wait()
+	}
+	w.writeWaiters--
+	if w.win < win {
+		win = w.win
+	}
+	w.win -= win
+	if w.closed {
+		err = io.EOF
+	}
+	w.L.Unlock()
+	return win, err
+}
+
+// waitWriterBlocked waits until some goroutine is blocked for further
+// writes. It is used in tests only.
+func (w *window) waitWriterBlocked() {
+	w.Cond.L.Lock()
+	for w.writeWaiters == 0 {
+		w.Cond.Wait()
+	}
+	w.Cond.L.Unlock()
+}
diff --git a/vendor/golang.org/x/crypto/ssh/connection.go b/vendor/golang.org/x/crypto/ssh/connection.go
new file mode 100644
index 000000000..613a71a7b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/connection.go
@@ -0,0 +1,155 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"fmt"
+	"net"
+)
+
+// OpenChannelError is returned if the other side rejects an
+// OpenChannel request.
+type OpenChannelError struct {
+	Reason  RejectionReason
+	Message string
+}
+
+func (e *OpenChannelError) Error() string {
+	return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
+}
+
+// ConnMetadata holds metadata for the connection.
+type ConnMetadata interface {
+	// User returns the user ID for this connection.
+	User() string
+
+	// SessionID returns the session hash, also denoted by H.
+	SessionID() []byte
+
+	// ClientVersion returns the client's version string as hashed
+	// into the session ID.
+	ClientVersion() []byte
+
+	// ServerVersion returns the server's version string as hashed
+	// into the session ID.
+	ServerVersion() []byte
+
+	// RemoteAddr returns the remote address for this connection.
+	RemoteAddr() net.Addr
+
+	// LocalAddr returns the local address for this connection.
+	LocalAddr() net.Addr
+}
+
+// Conn represents an SSH connection for both server and client roles.
+// Conn is the basis for implementing an application layer, such
+// as ClientConn, which implements the traditional shell access for
+// clients.
+type Conn interface {
+	ConnMetadata
+
+	// SendRequest sends a global request, and returns the
+	// reply. If wantReply is true, it returns the response status
+	// and payload. See also RFC 4254, section 4.
+	SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error)
+
+	// OpenChannel tries to open an channel. If the request is
+	// rejected, it returns *OpenChannelError. On success it returns
+	// the SSH Channel and a Go channel for incoming, out-of-band
+	// requests. The Go channel must be serviced, or the
+	// connection will hang.
+	OpenChannel(name string, data []byte) (Channel, <-chan *Request, error)
+
+	// Close closes the underlying network connection
+	Close() error
+
+	// Wait blocks until the connection has shut down, and returns the
+	// error causing the shutdown.
+	Wait() error
+
+	// TODO(hanwen): consider exposing:
+	//   RequestKeyChange
+	//   Disconnect
+}
+
+// AlgorithmsConnMetadata is a ConnMetadata that can return the algorithms
+// negotiated between client and server.
+type AlgorithmsConnMetadata interface {
+	ConnMetadata
+	Algorithms() NegotiatedAlgorithms
+}
+
+// DiscardRequests consumes and rejects all requests from the
+// passed-in channel.
+func DiscardRequests(in <-chan *Request) {
+	for req := range in {
+		if req.WantReply {
+			req.Reply(false, nil)
+		}
+	}
+}
+
+// A connection represents an incoming connection.
+type connection struct {
+	transport *handshakeTransport
+	sshConn
+
+	// The connection protocol.
+	*mux
+}
+
+func (c *connection) Close() error {
+	return c.sshConn.conn.Close()
+}
+
+// sshConn provides net.Conn metadata, but disallows direct reads and
+// writes.
+type sshConn struct {
+	conn net.Conn
+
+	user          string
+	sessionID     []byte
+	clientVersion []byte
+	serverVersion []byte
+	algorithms    NegotiatedAlgorithms
+}
+
+func dup(src []byte) []byte {
+	dst := make([]byte, len(src))
+	copy(dst, src)
+	return dst
+}
+
+func (c *sshConn) User() string {
+	return c.user
+}
+
+func (c *sshConn) RemoteAddr() net.Addr {
+	return c.conn.RemoteAddr()
+}
+
+func (c *sshConn) Close() error {
+	return c.conn.Close()
+}
+
+func (c *sshConn) LocalAddr() net.Addr {
+	return c.conn.LocalAddr()
+}
+
+func (c *sshConn) SessionID() []byte {
+	return dup(c.sessionID)
+}
+
+func (c *sshConn) ClientVersion() []byte {
+	return dup(c.clientVersion)
+}
+
+func (c *sshConn) ServerVersion() []byte {
+	return dup(c.serverVersion)
+}
+
+func (c *sshConn) Algorithms() NegotiatedAlgorithms {
+	return c.algorithms
+}
diff --git a/vendor/golang.org/x/crypto/ssh/doc.go b/vendor/golang.org/x/crypto/ssh/doc.go
new file mode 100644
index 000000000..5b4de9eff
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/doc.go
@@ -0,0 +1,34 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package ssh implements an SSH client and server.
+
+SSH is a transport security protocol, an authentication protocol and a
+family of application protocols. The most typical application level
+protocol is a remote shell and this is specifically implemented.  However,
+the multiplexed nature of SSH is exposed to users that wish to support
+others.
+
+References:
+
+	[PROTOCOL]: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL?rev=HEAD
+	[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
+	[SSH-PARAMETERS]:    http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
+	[SSH-CERTS]:	https://datatracker.ietf.org/doc/html/draft-miller-ssh-cert-01
+	[FIPS 140-3 mode]: https://go.dev/doc/security/fips140
+
+This package does not fall under the stability promise of the Go language itself,
+so its API may be changed when pressing needs arise.
+
+# FIPS 140-3 mode
+
+When the program is in [FIPS 140-3 mode], this package behaves as if only SP
+800-140C and SP 800-140D approved cipher suites, signature algorithms,
+certificate public key types and sizes, and key exchange and derivation
+algorithms were implemented. Others are silently ignored and not negotiated, or
+rejected. This set may depend on the algorithms supported by the FIPS 140-3 Go
+Cryptographic Module selected with GOFIPS140, and may change across Go versions.
+*/
+package ssh
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go
new file mode 100644
index 000000000..4be3cbb6d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/handshake.go
@@ -0,0 +1,847 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"log"
+	"net"
+	"slices"
+	"strings"
+	"sync"
+)
+
+// debugHandshake, if set, prints messages sent and received.  Key
+// exchange messages are printed as if DH were used, so the debug
+// messages are wrong when using ECDH.
+const debugHandshake = false
+
+// chanSize sets the amount of buffering SSH connections. This is
+// primarily for testing: setting chanSize=0 uncovers deadlocks more
+// quickly.
+const chanSize = 16
+
+// maxPendingPackets sets the maximum number of packets to queue while waiting
+// for KEX to complete. This limits the total pending data to maxPendingPackets
+// * maxPacket bytes, which is ~16.8MB.
+const maxPendingPackets = 64
+
+// keyingTransport is a packet based transport that supports key
+// changes. It need not be thread-safe. It should pass through
+// msgNewKeys in both directions.
+type keyingTransport interface {
+	packetConn
+
+	// prepareKeyChange sets up a key change. The key change for a
+	// direction will be effected if a msgNewKeys message is sent
+	// or received.
+	prepareKeyChange(*NegotiatedAlgorithms, *kexResult) error
+
+	// setStrictMode sets the strict KEX mode, notably triggering
+	// sequence number resets on sending or receiving msgNewKeys.
+	// If the sequence number is already > 1 when setStrictMode
+	// is called, an error is returned.
+	setStrictMode() error
+
+	// setInitialKEXDone indicates to the transport that the initial key exchange
+	// was completed
+	setInitialKEXDone()
+}
+
+// handshakeTransport implements rekeying on top of a keyingTransport
+// and offers a thread-safe writePacket() interface.
+type handshakeTransport struct {
+	conn   keyingTransport
+	config *Config
+
+	serverVersion []byte
+	clientVersion []byte
+
+	// hostKeys is non-empty if we are the server. In that case,
+	// it contains all host keys that can be used to sign the
+	// connection.
+	hostKeys []Signer
+
+	// publicKeyAuthAlgorithms is non-empty if we are the server. In that case,
+	// it contains the supported client public key authentication algorithms.
+	publicKeyAuthAlgorithms []string
+
+	// hostKeyAlgorithms is non-empty if we are the client. In that case,
+	// we accept these key types from the server as host key.
+	hostKeyAlgorithms []string
+
+	// On read error, incoming is closed, and readError is set.
+	incoming  chan []byte
+	readError error
+
+	mu sync.Mutex
+	// Condition for the above mutex. It is used to notify a completed key
+	// exchange or a write failure. Writes can wait for this condition while a
+	// key exchange is in progress.
+	writeCond      *sync.Cond
+	writeError     error
+	sentInitPacket []byte
+	sentInitMsg    *kexInitMsg
+	// Used to queue writes when a key exchange is in progress. The length is
+	// limited by pendingPacketsSize. Once full, writes will block until the key
+	// exchange is completed or an error occurs. If not empty, it is emptied
+	// all at once when the key exchange is completed in kexLoop.
+	pendingPackets   [][]byte
+	writePacketsLeft uint32
+	writeBytesLeft   int64
+	userAuthComplete bool // whether the user authentication phase is complete
+
+	// If the read loop wants to schedule a kex, it pings this
+	// channel, and the write loop will send out a kex
+	// message.
+	requestKex chan struct{}
+
+	// If the other side requests or confirms a kex, its kexInit
+	// packet is sent here for the write loop to find it.
+	startKex    chan *pendingKex
+	kexLoopDone chan struct{} // closed (with writeError non-nil) when kexLoop exits
+
+	// data for host key checking
+	hostKeyCallback HostKeyCallback
+	dialAddress     string
+	remoteAddr      net.Addr
+
+	// bannerCallback is non-empty if we are the client and it has been set in
+	// ClientConfig. In that case it is called during the user authentication
+	// dance to handle a custom server's message.
+	bannerCallback BannerCallback
+
+	// Algorithms agreed in the last key exchange.
+	algorithms *NegotiatedAlgorithms
+
+	// Counters exclusively owned by readLoop.
+	readPacketsLeft uint32
+	readBytesLeft   int64
+
+	// The session ID or nil if first kex did not complete yet.
+	sessionID []byte
+
+	// strictMode indicates if the other side of the handshake indicated
+	// that we should be following the strict KEX protocol restrictions.
+	strictMode bool
+}
+
+type pendingKex struct {
+	otherInit []byte
+	done      chan error
+}
+
+func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport {
+	t := &handshakeTransport{
+		conn:          conn,
+		serverVersion: serverVersion,
+		clientVersion: clientVersion,
+		incoming:      make(chan []byte, chanSize),
+		requestKex:    make(chan struct{}, 1),
+		startKex:      make(chan *pendingKex),
+		kexLoopDone:   make(chan struct{}),
+
+		config: config,
+	}
+	t.writeCond = sync.NewCond(&t.mu)
+	t.resetReadThresholds()
+	t.resetWriteThresholds()
+
+	// We always start with a mandatory key exchange.
+	t.requestKex <- struct{}{}
+	return t
+}
+
+func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport {
+	t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
+	t.dialAddress = dialAddr
+	t.remoteAddr = addr
+	t.hostKeyCallback = config.HostKeyCallback
+	t.bannerCallback = config.BannerCallback
+	if config.HostKeyAlgorithms != nil {
+		t.hostKeyAlgorithms = config.HostKeyAlgorithms
+	} else {
+		t.hostKeyAlgorithms = defaultHostKeyAlgos
+	}
+	go t.readLoop()
+	go t.kexLoop()
+	return t
+}
+
+func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport {
+	t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
+	t.hostKeys = config.hostKeys
+	t.publicKeyAuthAlgorithms = config.PublicKeyAuthAlgorithms
+	go t.readLoop()
+	go t.kexLoop()
+	return t
+}
+
+func (t *handshakeTransport) getSessionID() []byte {
+	return t.sessionID
+}
+
+func (t *handshakeTransport) getAlgorithms() NegotiatedAlgorithms {
+	return *t.algorithms
+}
+
+// waitSession waits for the session to be established. This should be
+// the first thing to call after instantiating handshakeTransport.
+func (t *handshakeTransport) waitSession() error {
+	p, err := t.readPacket()
+	if err != nil {
+		return err
+	}
+	if p[0] != msgNewKeys {
+		return fmt.Errorf("ssh: first packet should be msgNewKeys")
+	}
+
+	return nil
+}
+
+func (t *handshakeTransport) id() string {
+	if len(t.hostKeys) > 0 {
+		return "server"
+	}
+	return "client"
+}
+
+func (t *handshakeTransport) printPacket(p []byte, write bool) {
+	action := "got"
+	if write {
+		action = "sent"
+	}
+
+	if p[0] == msgChannelData || p[0] == msgChannelExtendedData {
+		log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p))
+	} else {
+		msg, err := decode(p)
+		log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err)
+	}
+}
+
+func (t *handshakeTransport) readPacket() ([]byte, error) {
+	p, ok := <-t.incoming
+	if !ok {
+		return nil, t.readError
+	}
+	return p, nil
+}
+
+func (t *handshakeTransport) readLoop() {
+	first := true
+	for {
+		p, err := t.readOnePacket(first)
+		first = false
+		if err != nil {
+			t.readError = err
+			close(t.incoming)
+			break
+		}
+		// If this is the first kex, and strict KEX mode is enabled,
+		// we don't ignore any messages, as they may be used to manipulate
+		// the packet sequence numbers.
+		if !(t.sessionID == nil && t.strictMode) && (p[0] == msgIgnore || p[0] == msgDebug) {
+			continue
+		}
+		t.incoming <- p
+	}
+
+	// Stop writers too.
+	t.recordWriteError(t.readError)
+
+	// Unblock the writer should it wait for this.
+	close(t.startKex)
+
+	// Don't close t.requestKex; it's also written to from writePacket.
+}
+
+func (t *handshakeTransport) pushPacket(p []byte) error {
+	if debugHandshake {
+		t.printPacket(p, true)
+	}
+	return t.conn.writePacket(p)
+}
+
+func (t *handshakeTransport) getWriteError() error {
+	t.mu.Lock()
+	defer t.mu.Unlock()
+	return t.writeError
+}
+
+func (t *handshakeTransport) recordWriteError(err error) {
+	t.mu.Lock()
+	defer t.mu.Unlock()
+	if t.writeError == nil && err != nil {
+		t.writeError = err
+		t.writeCond.Broadcast()
+	}
+}
+
+func (t *handshakeTransport) requestKeyExchange() {
+	select {
+	case t.requestKex <- struct{}{}:
+	default:
+		// something already requested a kex, so do nothing.
+	}
+}
+
+func (t *handshakeTransport) resetWriteThresholds() {
+	t.writePacketsLeft = packetRekeyThreshold
+	if t.config.RekeyThreshold > 0 {
+		t.writeBytesLeft = int64(t.config.RekeyThreshold)
+	} else if t.algorithms != nil {
+		t.writeBytesLeft = t.algorithms.Write.rekeyBytes()
+	} else {
+		t.writeBytesLeft = 1 << 30
+	}
+}
+
+func (t *handshakeTransport) kexLoop() {
+
+write:
+	for t.getWriteError() == nil {
+		var request *pendingKex
+		var sent bool
+
+		for request == nil || !sent {
+			var ok bool
+			select {
+			case request, ok = <-t.startKex:
+				if !ok {
+					break write
+				}
+			case <-t.requestKex:
+				break
+			}
+
+			if !sent {
+				if err := t.sendKexInit(); err != nil {
+					t.recordWriteError(err)
+					break
+				}
+				sent = true
+			}
+		}
+
+		if err := t.getWriteError(); err != nil {
+			if request != nil {
+				request.done <- err
+			}
+			break
+		}
+
+		// We're not servicing t.requestKex, but that is OK:
+		// we never block on sending to t.requestKex.
+
+		// We're not servicing t.startKex, but the remote end
+		// has just sent us a kexInitMsg, so it can't send
+		// another key change request, until we close the done
+		// channel on the pendingKex request.
+
+		err := t.enterKeyExchange(request.otherInit)
+
+		t.mu.Lock()
+		t.writeError = err
+		t.sentInitPacket = nil
+		t.sentInitMsg = nil
+
+		t.resetWriteThresholds()
+
+		// we have completed the key exchange. Since the
+		// reader is still blocked, it is safe to clear out
+		// the requestKex channel. This avoids the situation
+		// where: 1) we consumed our own request for the
+		// initial kex, and 2) the kex from the remote side
+		// caused another send on the requestKex channel,
+	clear:
+		for {
+			select {
+			case <-t.requestKex:
+				//
+			default:
+				break clear
+			}
+		}
+
+		request.done <- t.writeError
+
+		// kex finished. Push packets that we received while
+		// the kex was in progress. Don't look at t.startKex
+		// and don't increment writtenSinceKex: if we trigger
+		// another kex while we are still busy with the last
+		// one, things will become very confusing.
+		for _, p := range t.pendingPackets {
+			t.writeError = t.pushPacket(p)
+			if t.writeError != nil {
+				break
+			}
+		}
+		t.pendingPackets = t.pendingPackets[:0]
+		// Unblock writePacket if waiting for KEX.
+		t.writeCond.Broadcast()
+		t.mu.Unlock()
+	}
+
+	// Unblock reader.
+	t.conn.Close()
+
+	// drain startKex channel. We don't service t.requestKex
+	// because nobody does blocking sends there.
+	for request := range t.startKex {
+		request.done <- t.getWriteError()
+	}
+
+	// Mark that the loop is done so that Close can return.
+	close(t.kexLoopDone)
+}
+
+// The protocol uses uint32 for packet counters, so we can't let them
+// reach 1<<32.  We will actually read and write more packets than
+// this, though: the other side may send more packets, and after we
+// hit this limit on writing we will send a few more packets for the
+// key exchange itself.
+const packetRekeyThreshold = (1 << 31)
+
+func (t *handshakeTransport) resetReadThresholds() {
+	t.readPacketsLeft = packetRekeyThreshold
+	if t.config.RekeyThreshold > 0 {
+		t.readBytesLeft = int64(t.config.RekeyThreshold)
+	} else if t.algorithms != nil {
+		t.readBytesLeft = t.algorithms.Read.rekeyBytes()
+	} else {
+		t.readBytesLeft = 1 << 30
+	}
+}
+
+func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
+	p, err := t.conn.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	if t.readPacketsLeft > 0 {
+		t.readPacketsLeft--
+	} else {
+		t.requestKeyExchange()
+	}
+
+	if t.readBytesLeft > 0 {
+		t.readBytesLeft -= int64(len(p))
+	} else {
+		t.requestKeyExchange()
+	}
+
+	if debugHandshake {
+		t.printPacket(p, false)
+	}
+
+	if first && p[0] != msgKexInit {
+		return nil, fmt.Errorf("ssh: first packet should be msgKexInit")
+	}
+
+	if p[0] != msgKexInit {
+		return p, nil
+	}
+
+	firstKex := t.sessionID == nil
+
+	kex := pendingKex{
+		done:      make(chan error, 1),
+		otherInit: p,
+	}
+	t.startKex <- &kex
+	err = <-kex.done
+
+	if debugHandshake {
+		log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err)
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	t.resetReadThresholds()
+
+	// By default, a key exchange is hidden from higher layers by
+	// translating it into msgIgnore.
+	successPacket := []byte{msgIgnore}
+	if firstKex {
+		// sendKexInit() for the first kex waits for
+		// msgNewKeys so the authentication process is
+		// guaranteed to happen over an encrypted transport.
+		successPacket = []byte{msgNewKeys}
+	}
+
+	return successPacket, nil
+}
+
+const (
+	kexStrictClient = "kex-strict-c-v00@openssh.com"
+	kexStrictServer = "kex-strict-s-v00@openssh.com"
+)
+
+// sendKexInit sends a key change message.
+func (t *handshakeTransport) sendKexInit() error {
+	t.mu.Lock()
+	defer t.mu.Unlock()
+	if t.sentInitMsg != nil {
+		// kexInits may be sent either in response to the other side,
+		// or because our side wants to initiate a key change, so we
+		// may have already sent a kexInit. In that case, don't send a
+		// second kexInit.
+		return nil
+	}
+
+	msg := &kexInitMsg{
+		CiphersClientServer:     t.config.Ciphers,
+		CiphersServerClient:     t.config.Ciphers,
+		MACsClientServer:        t.config.MACs,
+		MACsServerClient:        t.config.MACs,
+		CompressionClientServer: supportedCompressions,
+		CompressionServerClient: supportedCompressions,
+	}
+	io.ReadFull(t.config.Rand, msg.Cookie[:])
+
+	// We mutate the KexAlgos slice, in order to add the kex-strict extension algorithm,
+	// and possibly to add the ext-info extension algorithm. Since the slice may be the
+	// user owned KeyExchanges, we create our own slice in order to avoid using user
+	// owned memory by mistake.
+	msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+2) // room for kex-strict and ext-info
+	msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
+
+	isServer := len(t.hostKeys) > 0
+	if isServer {
+		for _, k := range t.hostKeys {
+			// If k is a MultiAlgorithmSigner, we restrict the signature
+			// algorithms. If k is a AlgorithmSigner, presume it supports all
+			// signature algorithms associated with the key format. If k is not
+			// an AlgorithmSigner, we can only assume it only supports the
+			// algorithms that matches the key format. (This means that Sign
+			// can't pick a different default).
+			keyFormat := k.PublicKey().Type()
+
+			switch s := k.(type) {
+			case MultiAlgorithmSigner:
+				for _, algo := range algorithmsForKeyFormat(keyFormat) {
+					if slices.Contains(s.Algorithms(), underlyingAlgo(algo)) {
+						msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo)
+					}
+				}
+			case AlgorithmSigner:
+				msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...)
+			default:
+				msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
+			}
+		}
+
+		if t.sessionID == nil {
+			msg.KexAlgos = append(msg.KexAlgos, kexStrictServer)
+		}
+	} else {
+		msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
+
+		// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
+		// algorithms the server supports for public key authentication. See RFC
+		// 8308, Section 2.1.
+		//
+		// We also send the strict KEX mode extension algorithm, in order to opt
+		// into the strict KEX mode.
+		if firstKeyExchange := t.sessionID == nil; firstKeyExchange {
+			msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
+			msg.KexAlgos = append(msg.KexAlgos, kexStrictClient)
+		}
+
+	}
+
+	packet := Marshal(msg)
+
+	// writePacket destroys the contents, so save a copy.
+	packetCopy := make([]byte, len(packet))
+	copy(packetCopy, packet)
+
+	if err := t.pushPacket(packetCopy); err != nil {
+		return err
+	}
+
+	t.sentInitMsg = msg
+	t.sentInitPacket = packet
+
+	return nil
+}
+
+var errSendBannerPhase = errors.New("ssh: SendAuthBanner outside of authentication phase")
+
+func (t *handshakeTransport) writePacket(p []byte) error {
+	t.mu.Lock()
+	defer t.mu.Unlock()
+
+	switch p[0] {
+	case msgKexInit:
+		return errors.New("ssh: only handshakeTransport can send kexInit")
+	case msgNewKeys:
+		return errors.New("ssh: only handshakeTransport can send newKeys")
+	case msgUserAuthBanner:
+		if t.userAuthComplete {
+			return errSendBannerPhase
+		}
+	case msgUserAuthSuccess:
+		t.userAuthComplete = true
+	}
+
+	if t.writeError != nil {
+		return t.writeError
+	}
+
+	if t.sentInitMsg != nil {
+		if len(t.pendingPackets) < maxPendingPackets {
+			// Copy the packet so the writer can reuse the buffer.
+			cp := make([]byte, len(p))
+			copy(cp, p)
+			t.pendingPackets = append(t.pendingPackets, cp)
+			return nil
+		}
+		for t.sentInitMsg != nil {
+			// Block and wait for KEX to complete or an error.
+			t.writeCond.Wait()
+			if t.writeError != nil {
+				return t.writeError
+			}
+		}
+	}
+
+	if t.writeBytesLeft > 0 {
+		t.writeBytesLeft -= int64(len(p))
+	} else {
+		t.requestKeyExchange()
+	}
+
+	if t.writePacketsLeft > 0 {
+		t.writePacketsLeft--
+	} else {
+		t.requestKeyExchange()
+	}
+
+	if err := t.pushPacket(p); err != nil {
+		t.writeError = err
+		t.writeCond.Broadcast()
+	}
+
+	return nil
+}
+
+func (t *handshakeTransport) Close() error {
+	// Close the connection. This should cause the readLoop goroutine to wake up
+	// and close t.startKex, which will shut down kexLoop if running.
+	err := t.conn.Close()
+
+	// Wait for the kexLoop goroutine to complete.
+	// At that point we know that the readLoop goroutine is complete too,
+	// because kexLoop itself waits for readLoop to close the startKex channel.
+	<-t.kexLoopDone
+
+	return err
+}
+
+func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
+	if debugHandshake {
+		log.Printf("%s entered key exchange", t.id())
+	}
+
+	otherInit := &kexInitMsg{}
+	if err := Unmarshal(otherInitPacket, otherInit); err != nil {
+		return err
+	}
+
+	magics := handshakeMagics{
+		clientVersion: t.clientVersion,
+		serverVersion: t.serverVersion,
+		clientKexInit: otherInitPacket,
+		serverKexInit: t.sentInitPacket,
+	}
+
+	clientInit := otherInit
+	serverInit := t.sentInitMsg
+	isClient := len(t.hostKeys) == 0
+	if isClient {
+		clientInit, serverInit = serverInit, clientInit
+
+		magics.clientKexInit = t.sentInitPacket
+		magics.serverKexInit = otherInitPacket
+	}
+
+	var err error
+	t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit)
+	if err != nil {
+		return err
+	}
+
+	if t.sessionID == nil && ((isClient && slices.Contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && slices.Contains(clientInit.KexAlgos, kexStrictClient))) {
+		t.strictMode = true
+		if err := t.conn.setStrictMode(); err != nil {
+			return err
+		}
+	}
+
+	// We don't send FirstKexFollows, but we handle receiving it.
+	//
+	// RFC 4253 section 7 defines the kex and the agreement method for
+	// first_kex_packet_follows. It states that the guessed packet
+	// should be ignored if the "kex algorithm and/or the host
+	// key algorithm is guessed wrong (server and client have
+	// different preferred algorithm), or if any of the other
+	// algorithms cannot be agreed upon". The other algorithms have
+	// already been checked above so the kex algorithm and host key
+	// algorithm are checked here.
+	if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) {
+		// other side sent a kex message for the wrong algorithm,
+		// which we have to ignore.
+		if _, err := t.conn.readPacket(); err != nil {
+			return err
+		}
+	}
+
+	kex, ok := kexAlgoMap[t.algorithms.KeyExchange]
+	if !ok {
+		return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.KeyExchange)
+	}
+
+	var result *kexResult
+	if len(t.hostKeys) > 0 {
+		result, err = t.server(kex, &magics)
+	} else {
+		result, err = t.client(kex, &magics)
+	}
+
+	if err != nil {
+		return err
+	}
+
+	firstKeyExchange := t.sessionID == nil
+	if firstKeyExchange {
+		t.sessionID = result.H
+	}
+	result.SessionID = t.sessionID
+
+	if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil {
+		return err
+	}
+	if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
+		return err
+	}
+
+	// On the server side, after the first SSH_MSG_NEWKEYS, send a SSH_MSG_EXT_INFO
+	// message with the server-sig-algs extension if the client supports it. See
+	// RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9.
+	if !isClient && firstKeyExchange && slices.Contains(clientInit.KexAlgos, "ext-info-c") {
+		supportedPubKeyAuthAlgosList := strings.Join(t.publicKeyAuthAlgorithms, ",")
+		extInfo := &extInfoMsg{
+			NumExtensions: 2,
+			Payload:       make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)+4+16+4+1),
+		}
+		extInfo.Payload = appendInt(extInfo.Payload, len("server-sig-algs"))
+		extInfo.Payload = append(extInfo.Payload, "server-sig-algs"...)
+		extInfo.Payload = appendInt(extInfo.Payload, len(supportedPubKeyAuthAlgosList))
+		extInfo.Payload = append(extInfo.Payload, supportedPubKeyAuthAlgosList...)
+		extInfo.Payload = appendInt(extInfo.Payload, len("ping@openssh.com"))
+		extInfo.Payload = append(extInfo.Payload, "ping@openssh.com"...)
+		extInfo.Payload = appendInt(extInfo.Payload, 1)
+		extInfo.Payload = append(extInfo.Payload, "0"...)
+		if err := t.conn.writePacket(Marshal(extInfo)); err != nil {
+			return err
+		}
+	}
+
+	if packet, err := t.conn.readPacket(); err != nil {
+		return err
+	} else if packet[0] != msgNewKeys {
+		return unexpectedMessageError(msgNewKeys, packet[0])
+	}
+
+	if firstKeyExchange {
+		// Indicates to the transport that the first key exchange is completed
+		// after receiving SSH_MSG_NEWKEYS.
+		t.conn.setInitialKEXDone()
+	}
+
+	return nil
+}
+
+// algorithmSignerWrapper is an AlgorithmSigner that only supports the default
+// key format algorithm.
+//
+// This is technically a violation of the AlgorithmSigner interface, but it
+// should be unreachable given where we use this. Anyway, at least it returns an
+// error instead of panicing or producing an incorrect signature.
+type algorithmSignerWrapper struct {
+	Signer
+}
+
+func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
+	if algorithm != underlyingAlgo(a.PublicKey().Type()) {
+		return nil, errors.New("ssh: internal error: algorithmSignerWrapper invoked with non-default algorithm")
+	}
+	return a.Sign(rand, data)
+}
+
+func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {
+	for _, k := range hostKeys {
+		if s, ok := k.(MultiAlgorithmSigner); ok {
+			if !slices.Contains(s.Algorithms(), underlyingAlgo(algo)) {
+				continue
+			}
+		}
+
+		if algo == k.PublicKey().Type() {
+			return algorithmSignerWrapper{k}
+		}
+
+		k, ok := k.(AlgorithmSigner)
+		if !ok {
+			continue
+		}
+		for _, a := range algorithmsForKeyFormat(k.PublicKey().Type()) {
+			if algo == a {
+				return k
+			}
+		}
+	}
+	return nil
+}
+
+func (t *handshakeTransport) server(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
+	hostKey := pickHostKey(t.hostKeys, t.algorithms.HostKey)
+	if hostKey == nil {
+		return nil, errors.New("ssh: internal error: negotiated unsupported signature type")
+	}
+
+	r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.HostKey)
+	return r, err
+}
+
+func (t *handshakeTransport) client(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
+	result, err := kex.Client(t.conn, t.config.Rand, magics)
+	if err != nil {
+		return nil, err
+	}
+
+	hostKey, err := ParsePublicKey(result.HostKey)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := verifyHostKeySignature(hostKey, t.algorithms.HostKey, result); err != nil {
+		return nil, err
+	}
+
+	err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey)
+	if err != nil {
+		return nil, err
+	}
+
+	return result, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go b/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go
new file mode 100644
index 000000000..af81d2665
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go
@@ -0,0 +1,93 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bcrypt_pbkdf implements bcrypt_pbkdf(3) from OpenBSD.
+//
+// See https://flak.tedunangst.com/post/bcrypt-pbkdf and
+// https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libutil/bcrypt_pbkdf.c.
+package bcrypt_pbkdf
+
+import (
+	"crypto/sha512"
+	"errors"
+	"golang.org/x/crypto/blowfish"
+)
+
+const blockSize = 32
+
+// Key derives a key from the password, salt and rounds count, returning a
+// []byte of length keyLen that can be used as cryptographic key.
+func Key(password, salt []byte, rounds, keyLen int) ([]byte, error) {
+	if rounds < 1 {
+		return nil, errors.New("bcrypt_pbkdf: number of rounds is too small")
+	}
+	if len(password) == 0 {
+		return nil, errors.New("bcrypt_pbkdf: empty password")
+	}
+	if len(salt) == 0 || len(salt) > 1<<20 {
+		return nil, errors.New("bcrypt_pbkdf: bad salt length")
+	}
+	if keyLen > 1024 {
+		return nil, errors.New("bcrypt_pbkdf: keyLen is too large")
+	}
+
+	numBlocks := (keyLen + blockSize - 1) / blockSize
+	key := make([]byte, numBlocks*blockSize)
+
+	h := sha512.New()
+	h.Write(password)
+	shapass := h.Sum(nil)
+
+	shasalt := make([]byte, 0, sha512.Size)
+	cnt, tmp := make([]byte, 4), make([]byte, blockSize)
+	for block := 1; block <= numBlocks; block++ {
+		h.Reset()
+		h.Write(salt)
+		cnt[0] = byte(block >> 24)
+		cnt[1] = byte(block >> 16)
+		cnt[2] = byte(block >> 8)
+		cnt[3] = byte(block)
+		h.Write(cnt)
+		bcryptHash(tmp, shapass, h.Sum(shasalt))
+
+		out := make([]byte, blockSize)
+		copy(out, tmp)
+		for i := 2; i <= rounds; i++ {
+			h.Reset()
+			h.Write(tmp)
+			bcryptHash(tmp, shapass, h.Sum(shasalt))
+			for j := 0; j < len(out); j++ {
+				out[j] ^= tmp[j]
+			}
+		}
+
+		for i, v := range out {
+			key[i*numBlocks+(block-1)] = v
+		}
+	}
+	return key[:keyLen], nil
+}
+
+var magic = []byte("OxychromaticBlowfishSwatDynamite")
+
+func bcryptHash(out, shapass, shasalt []byte) {
+	c, err := blowfish.NewSaltedCipher(shapass, shasalt)
+	if err != nil {
+		panic(err)
+	}
+	for i := 0; i < 64; i++ {
+		blowfish.ExpandKey(shasalt, c)
+		blowfish.ExpandKey(shapass, c)
+	}
+	copy(out, magic)
+	for i := 0; i < 32; i += 8 {
+		for j := 0; j < 64; j++ {
+			c.Encrypt(out[i:i+8], out[i:i+8])
+		}
+	}
+	// Swap bytes due to different endianness.
+	for i := 0; i < 32; i += 4 {
+		out[i+3], out[i+2], out[i+1], out[i] = out[i], out[i+1], out[i+2], out[i+3]
+	}
+}
diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go
new file mode 100644
index 000000000..5f7fdd851
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/kex.go
@@ -0,0 +1,807 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/fips140"
+	"crypto/rand"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"math/big"
+	"slices"
+
+	"golang.org/x/crypto/curve25519"
+)
+
+const (
+	// This is the group called diffie-hellman-group1-sha1 in RFC 4253 and
+	// Oakley Group 2 in RFC 2409.
+	oakleyGroup2 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
+	// This is the group called diffie-hellman-group14-sha1 in RFC 4253 and
+	// Oakley Group 14 in RFC 3526.
+	oakleyGroup14 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF"
+	// This is the group called diffie-hellman-group15-sha512 in RFC 8268 and
+	// Oakley Group 15 in RFC 3526.
+	oakleyGroup15 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
+	// This is the group called diffie-hellman-group16-sha512 in RFC 8268 and
+	// Oakley Group 16 in RFC 3526.
+	oakleyGroup16 = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF"
+)
+
+// kexResult captures the outcome of a key exchange.
+type kexResult struct {
+	// Session hash. See also RFC 4253, section 8.
+	H []byte
+
+	// Shared secret. See also RFC 4253, section 8.
+	K []byte
+
+	// Host key as hashed into H.
+	HostKey []byte
+
+	// Signature of H.
+	Signature []byte
+
+	// A cryptographic hash function that matches the security
+	// level of the key exchange algorithm. It is used for
+	// calculating H, and for deriving keys from H and K.
+	Hash crypto.Hash
+
+	// The session ID, which is the first H computed. This is used
+	// to derive key material inside the transport.
+	SessionID []byte
+}
+
+// handshakeMagics contains data that is always included in the
+// session hash.
+type handshakeMagics struct {
+	clientVersion, serverVersion []byte
+	clientKexInit, serverKexInit []byte
+}
+
+func (m *handshakeMagics) write(w io.Writer) {
+	writeString(w, m.clientVersion)
+	writeString(w, m.serverVersion)
+	writeString(w, m.clientKexInit)
+	writeString(w, m.serverKexInit)
+}
+
+// kexAlgorithm abstracts different key exchange algorithms.
+type kexAlgorithm interface {
+	// Server runs server-side key agreement, signing the result
+	// with a hostkey. algo is the negotiated algorithm, and may
+	// be a certificate type.
+	Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error)
+
+	// Client runs the client-side key agreement. Caller is
+	// responsible for verifying the host key signature.
+	Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
+}
+
+// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
+type dhGroup struct {
+	g, p, pMinus1 *big.Int
+	hashFunc      crypto.Hash
+}
+
+func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
+	if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 {
+		return nil, errors.New("ssh: DH parameter out of bounds")
+	}
+	return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
+}
+
+func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
+	var x *big.Int
+	for {
+		var err error
+		if x, err = rand.Int(randSource, group.pMinus1); err != nil {
+			return nil, err
+		}
+		if x.Sign() > 0 {
+			break
+		}
+	}
+
+	X := new(big.Int).Exp(group.g, x, group.p)
+	kexDHInit := kexDHInitMsg{
+		X: X,
+	}
+	if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
+		return nil, err
+	}
+
+	packet, err := c.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	var kexDHReply kexDHReplyMsg
+	if err = Unmarshal(packet, &kexDHReply); err != nil {
+		return nil, err
+	}
+
+	ki, err := group.diffieHellman(kexDHReply.Y, x)
+	if err != nil {
+		return nil, err
+	}
+
+	h := group.hashFunc.New()
+	magics.write(h)
+	writeString(h, kexDHReply.HostKey)
+	writeInt(h, X)
+	writeInt(h, kexDHReply.Y)
+	K := make([]byte, intLength(ki))
+	marshalInt(K, ki)
+	h.Write(K)
+
+	return &kexResult{
+		H:         h.Sum(nil),
+		K:         K,
+		HostKey:   kexDHReply.HostKey,
+		Signature: kexDHReply.Signature,
+		Hash:      group.hashFunc,
+	}, nil
+}
+
+func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
+	packet, err := c.readPacket()
+	if err != nil {
+		return
+	}
+	var kexDHInit kexDHInitMsg
+	if err = Unmarshal(packet, &kexDHInit); err != nil {
+		return
+	}
+
+	var y *big.Int
+	for {
+		if y, err = rand.Int(randSource, group.pMinus1); err != nil {
+			return
+		}
+		if y.Sign() > 0 {
+			break
+		}
+	}
+
+	Y := new(big.Int).Exp(group.g, y, group.p)
+	ki, err := group.diffieHellman(kexDHInit.X, y)
+	if err != nil {
+		return nil, err
+	}
+
+	hostKeyBytes := priv.PublicKey().Marshal()
+
+	h := group.hashFunc.New()
+	magics.write(h)
+	writeString(h, hostKeyBytes)
+	writeInt(h, kexDHInit.X)
+	writeInt(h, Y)
+
+	K := make([]byte, intLength(ki))
+	marshalInt(K, ki)
+	h.Write(K)
+
+	H := h.Sum(nil)
+
+	// H is already a hash, but the hostkey signing will apply its
+	// own key-specific hash algorithm.
+	sig, err := signAndMarshal(priv, randSource, H, algo)
+	if err != nil {
+		return nil, err
+	}
+
+	kexDHReply := kexDHReplyMsg{
+		HostKey:   hostKeyBytes,
+		Y:         Y,
+		Signature: sig,
+	}
+	packet = Marshal(&kexDHReply)
+
+	err = c.writePacket(packet)
+	return &kexResult{
+		H:         H,
+		K:         K,
+		HostKey:   hostKeyBytes,
+		Signature: sig,
+		Hash:      group.hashFunc,
+	}, err
+}
+
+// ecdh performs Elliptic Curve Diffie-Hellman key exchange as
+// described in RFC 5656, section 4.
+type ecdh struct {
+	curve elliptic.Curve
+}
+
+func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
+	ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
+	if err != nil {
+		return nil, err
+	}
+
+	kexInit := kexECDHInitMsg{
+		ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
+	}
+
+	serialized := Marshal(&kexInit)
+	if err := c.writePacket(serialized); err != nil {
+		return nil, err
+	}
+
+	packet, err := c.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	var reply kexECDHReplyMsg
+	if err = Unmarshal(packet, &reply); err != nil {
+		return nil, err
+	}
+
+	x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
+	if err != nil {
+		return nil, err
+	}
+
+	// generate shared secret
+	secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
+
+	h := ecHash(kex.curve).New()
+	magics.write(h)
+	writeString(h, reply.HostKey)
+	writeString(h, kexInit.ClientPubKey)
+	writeString(h, reply.EphemeralPubKey)
+	K := make([]byte, intLength(secret))
+	marshalInt(K, secret)
+	h.Write(K)
+
+	return &kexResult{
+		H:         h.Sum(nil),
+		K:         K,
+		HostKey:   reply.HostKey,
+		Signature: reply.Signature,
+		Hash:      ecHash(kex.curve),
+	}, nil
+}
+
+// unmarshalECKey parses and checks an EC key.
+func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
+	x, y = elliptic.Unmarshal(curve, pubkey)
+	if x == nil {
+		return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
+	}
+	if !validateECPublicKey(curve, x, y) {
+		return nil, nil, errors.New("ssh: public key not on curve")
+	}
+	return x, y, nil
+}
+
+// validateECPublicKey checks that the point is a valid public key for
+// the given curve. See [SEC1], 3.2.2
+func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
+	if x.Sign() == 0 && y.Sign() == 0 {
+		return false
+	}
+
+	if x.Cmp(curve.Params().P) >= 0 {
+		return false
+	}
+
+	if y.Cmp(curve.Params().P) >= 0 {
+		return false
+	}
+
+	if !curve.IsOnCurve(x, y) {
+		return false
+	}
+
+	// We don't check if N * PubKey == 0, since
+	//
+	// - the NIST curves have cofactor = 1, so this is implicit.
+	// (We don't foresee an implementation that supports non NIST
+	// curves)
+	//
+	// - for ephemeral keys, we don't need to worry about small
+	// subgroup attacks.
+	return true
+}
+
+func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
+	packet, err := c.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	var kexECDHInit kexECDHInitMsg
+	if err = Unmarshal(packet, &kexECDHInit); err != nil {
+		return nil, err
+	}
+
+	clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
+	if err != nil {
+		return nil, err
+	}
+
+	// We could cache this key across multiple users/multiple
+	// connection attempts, but the benefit is small. OpenSSH
+	// generates a new key for each incoming connection.
+	ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
+	if err != nil {
+		return nil, err
+	}
+
+	hostKeyBytes := priv.PublicKey().Marshal()
+
+	serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
+
+	// generate shared secret
+	secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
+
+	h := ecHash(kex.curve).New()
+	magics.write(h)
+	writeString(h, hostKeyBytes)
+	writeString(h, kexECDHInit.ClientPubKey)
+	writeString(h, serializedEphKey)
+
+	K := make([]byte, intLength(secret))
+	marshalInt(K, secret)
+	h.Write(K)
+
+	H := h.Sum(nil)
+
+	// H is already a hash, but the hostkey signing will apply its
+	// own key-specific hash algorithm.
+	sig, err := signAndMarshal(priv, rand, H, algo)
+	if err != nil {
+		return nil, err
+	}
+
+	reply := kexECDHReplyMsg{
+		EphemeralPubKey: serializedEphKey,
+		HostKey:         hostKeyBytes,
+		Signature:       sig,
+	}
+
+	serialized := Marshal(&reply)
+	if err := c.writePacket(serialized); err != nil {
+		return nil, err
+	}
+
+	return &kexResult{
+		H:         H,
+		K:         K,
+		HostKey:   reply.HostKey,
+		Signature: sig,
+		Hash:      ecHash(kex.curve),
+	}, nil
+}
+
+// ecHash returns the hash to match the given elliptic curve, see RFC
+// 5656, section 6.2.1
+func ecHash(curve elliptic.Curve) crypto.Hash {
+	bitSize := curve.Params().BitSize
+	switch {
+	case bitSize <= 256:
+		return crypto.SHA256
+	case bitSize <= 384:
+		return crypto.SHA384
+	}
+	return crypto.SHA512
+}
+
+// kexAlgoMap defines the supported KEXs. KEXs not included are not supported
+// and will not be negotiated, even if explicitly configured. When FIPS mode is
+// enabled, only FIPS-approved algorithms are included.
+var kexAlgoMap = map[string]kexAlgorithm{}
+
+func init() {
+	// mlkem768x25519-sha256 we'll work with fips140=on but not fips140=only
+	// until Go 1.26.
+	kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{}
+	kexAlgoMap[KeyExchangeECDHP521] = &ecdh{elliptic.P521()}
+	kexAlgoMap[KeyExchangeECDHP384] = &ecdh{elliptic.P384()}
+	kexAlgoMap[KeyExchangeECDHP256] = &ecdh{elliptic.P256()}
+
+	if fips140.Enabled() {
+		defaultKexAlgos = slices.DeleteFunc(defaultKexAlgos, func(algo string) bool {
+			_, ok := kexAlgoMap[algo]
+			return !ok
+		})
+		return
+	}
+
+	p, _ := new(big.Int).SetString(oakleyGroup2, 16)
+	kexAlgoMap[InsecureKeyExchangeDH1SHA1] = &dhGroup{
+		g:        new(big.Int).SetInt64(2),
+		p:        p,
+		pMinus1:  new(big.Int).Sub(p, bigOne),
+		hashFunc: crypto.SHA1,
+	}
+
+	p, _ = new(big.Int).SetString(oakleyGroup14, 16)
+	group14 := &dhGroup{
+		g:       new(big.Int).SetInt64(2),
+		p:       p,
+		pMinus1: new(big.Int).Sub(p, bigOne),
+	}
+
+	kexAlgoMap[InsecureKeyExchangeDH14SHA1] = &dhGroup{
+		g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
+		hashFunc: crypto.SHA1,
+	}
+	kexAlgoMap[KeyExchangeDH14SHA256] = &dhGroup{
+		g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
+		hashFunc: crypto.SHA256,
+	}
+
+	p, _ = new(big.Int).SetString(oakleyGroup16, 16)
+
+	kexAlgoMap[KeyExchangeDH16SHA512] = &dhGroup{
+		g:        new(big.Int).SetInt64(2),
+		p:        p,
+		pMinus1:  new(big.Int).Sub(p, bigOne),
+		hashFunc: crypto.SHA512,
+	}
+
+	kexAlgoMap[KeyExchangeCurve25519] = &curve25519sha256{}
+	kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{}
+	kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
+	kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
+}
+
+// curve25519sha256 implements the curve25519-sha256 (formerly known as
+// curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731.
+type curve25519sha256 struct{}
+
+type curve25519KeyPair struct {
+	priv [32]byte
+	pub  [32]byte
+}
+
+func (kp *curve25519KeyPair) generate(rand io.Reader) error {
+	if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
+		return err
+	}
+	p, err := curve25519.X25519(kp.priv[:], curve25519.Basepoint)
+	if err != nil {
+		return fmt.Errorf("curve25519: %w", err)
+	}
+	if len(p) != 32 {
+		return fmt.Errorf("curve25519: internal error: X25519 returned %d bytes, expected 32", len(p))
+	}
+	copy(kp.pub[:], p)
+	return nil
+}
+
+func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
+	var kp curve25519KeyPair
+	if err := kp.generate(rand); err != nil {
+		return nil, err
+	}
+	if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
+		return nil, err
+	}
+
+	packet, err := c.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	var reply kexECDHReplyMsg
+	if err = Unmarshal(packet, &reply); err != nil {
+		return nil, err
+	}
+	if len(reply.EphemeralPubKey) != 32 {
+		return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
+	}
+
+	secret, err := curve25519.X25519(kp.priv[:], reply.EphemeralPubKey)
+	if err != nil {
+		return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err)
+	}
+
+	h := crypto.SHA256.New()
+	magics.write(h)
+	writeString(h, reply.HostKey)
+	writeString(h, kp.pub[:])
+	writeString(h, reply.EphemeralPubKey)
+
+	ki := new(big.Int).SetBytes(secret[:])
+	K := make([]byte, intLength(ki))
+	marshalInt(K, ki)
+	h.Write(K)
+
+	return &kexResult{
+		H:         h.Sum(nil),
+		K:         K,
+		HostKey:   reply.HostKey,
+		Signature: reply.Signature,
+		Hash:      crypto.SHA256,
+	}, nil
+}
+
+func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
+	packet, err := c.readPacket()
+	if err != nil {
+		return
+	}
+	var kexInit kexECDHInitMsg
+	if err = Unmarshal(packet, &kexInit); err != nil {
+		return
+	}
+
+	if len(kexInit.ClientPubKey) != 32 {
+		return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
+	}
+
+	var kp curve25519KeyPair
+	if err := kp.generate(rand); err != nil {
+		return nil, err
+	}
+
+	secret, err := curve25519.X25519(kp.priv[:], kexInit.ClientPubKey)
+	if err != nil {
+		return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err)
+	}
+
+	hostKeyBytes := priv.PublicKey().Marshal()
+
+	h := crypto.SHA256.New()
+	magics.write(h)
+	writeString(h, hostKeyBytes)
+	writeString(h, kexInit.ClientPubKey)
+	writeString(h, kp.pub[:])
+
+	ki := new(big.Int).SetBytes(secret[:])
+	K := make([]byte, intLength(ki))
+	marshalInt(K, ki)
+	h.Write(K)
+
+	H := h.Sum(nil)
+
+	sig, err := signAndMarshal(priv, rand, H, algo)
+	if err != nil {
+		return nil, err
+	}
+
+	reply := kexECDHReplyMsg{
+		EphemeralPubKey: kp.pub[:],
+		HostKey:         hostKeyBytes,
+		Signature:       sig,
+	}
+	if err := c.writePacket(Marshal(&reply)); err != nil {
+		return nil, err
+	}
+	return &kexResult{
+		H:         H,
+		K:         K,
+		HostKey:   hostKeyBytes,
+		Signature: sig,
+		Hash:      crypto.SHA256,
+	}, nil
+}
+
+// dhGEXSHA implements the diffie-hellman-group-exchange-sha1 and
+// diffie-hellman-group-exchange-sha256 key agreement protocols,
+// as described in RFC 4419
+type dhGEXSHA struct {
+	hashFunc crypto.Hash
+}
+
+const (
+	dhGroupExchangeMinimumBits   = 2048
+	dhGroupExchangePreferredBits = 2048
+	dhGroupExchangeMaximumBits   = 8192
+)
+
+func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
+	// Send GexRequest
+	kexDHGexRequest := kexDHGexRequestMsg{
+		MinBits:       dhGroupExchangeMinimumBits,
+		PreferredBits: dhGroupExchangePreferredBits,
+		MaxBits:       dhGroupExchangeMaximumBits,
+	}
+	if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
+		return nil, err
+	}
+
+	// Receive GexGroup
+	packet, err := c.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	var msg kexDHGexGroupMsg
+	if err = Unmarshal(packet, &msg); err != nil {
+		return nil, err
+	}
+
+	// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
+	if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits {
+		return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen())
+	}
+
+	// Check if g is safe by verifying that 1 < g < p-1
+	pMinusOne := new(big.Int).Sub(msg.P, bigOne)
+	if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 {
+		return nil, fmt.Errorf("ssh: server provided gex g is not safe")
+	}
+
+	// Send GexInit
+	pHalf := new(big.Int).Rsh(msg.P, 1)
+	x, err := rand.Int(randSource, pHalf)
+	if err != nil {
+		return nil, err
+	}
+	X := new(big.Int).Exp(msg.G, x, msg.P)
+	kexDHGexInit := kexDHGexInitMsg{
+		X: X,
+	}
+	if err := c.writePacket(Marshal(&kexDHGexInit)); err != nil {
+		return nil, err
+	}
+
+	// Receive GexReply
+	packet, err = c.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	var kexDHGexReply kexDHGexReplyMsg
+	if err = Unmarshal(packet, &kexDHGexReply); err != nil {
+		return nil, err
+	}
+
+	if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 {
+		return nil, errors.New("ssh: DH parameter out of bounds")
+	}
+	kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P)
+
+	// Check if k is safe by verifying that k > 1 and k < p - 1
+	if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 {
+		return nil, fmt.Errorf("ssh: derived k is not safe")
+	}
+
+	h := gex.hashFunc.New()
+	magics.write(h)
+	writeString(h, kexDHGexReply.HostKey)
+	binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
+	binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
+	binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
+	writeInt(h, msg.P)
+	writeInt(h, msg.G)
+	writeInt(h, X)
+	writeInt(h, kexDHGexReply.Y)
+	K := make([]byte, intLength(kInt))
+	marshalInt(K, kInt)
+	h.Write(K)
+
+	return &kexResult{
+		H:         h.Sum(nil),
+		K:         K,
+		HostKey:   kexDHGexReply.HostKey,
+		Signature: kexDHGexReply.Signature,
+		Hash:      gex.hashFunc,
+	}, nil
+}
+
+// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
+func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
+	// Receive GexRequest
+	packet, err := c.readPacket()
+	if err != nil {
+		return
+	}
+	var kexDHGexRequest kexDHGexRequestMsg
+	if err = Unmarshal(packet, &kexDHGexRequest); err != nil {
+		return
+	}
+	// We check that the request received is valid and that the MaxBits
+	// requested are at least equal to our supported minimum. This is the same
+	// check done in OpenSSH:
+	// https://github.com/openssh/openssh-portable/blob/80a2f64b/kexgexs.c#L94
+	//
+	// Furthermore, we also check that the required MinBits are less than or
+	// equal to 4096 because we can use up to Oakley Group 16.
+	if kexDHGexRequest.MaxBits < kexDHGexRequest.MinBits || kexDHGexRequest.PreferredBits < kexDHGexRequest.MinBits ||
+		kexDHGexRequest.MaxBits < kexDHGexRequest.PreferredBits || kexDHGexRequest.MaxBits < dhGroupExchangeMinimumBits ||
+		kexDHGexRequest.MinBits > 4096 {
+		return nil, fmt.Errorf("ssh: DH GEX request out of range, min: %d, max: %d, preferred: %d", kexDHGexRequest.MinBits,
+			kexDHGexRequest.MaxBits, kexDHGexRequest.PreferredBits)
+	}
+
+	var p *big.Int
+	// We hardcode sending Oakley Group 14 (2048 bits), Oakley Group 15 (3072
+	// bits) or Oakley Group 16 (4096 bits), based on the requested max size.
+	if kexDHGexRequest.MaxBits < 3072 {
+		p, _ = new(big.Int).SetString(oakleyGroup14, 16)
+	} else if kexDHGexRequest.MaxBits < 4096 {
+		p, _ = new(big.Int).SetString(oakleyGroup15, 16)
+	} else {
+		p, _ = new(big.Int).SetString(oakleyGroup16, 16)
+	}
+
+	g := big.NewInt(2)
+	msg := &kexDHGexGroupMsg{
+		P: p,
+		G: g,
+	}
+	if err := c.writePacket(Marshal(msg)); err != nil {
+		return nil, err
+	}
+
+	// Receive GexInit
+	packet, err = c.readPacket()
+	if err != nil {
+		return
+	}
+	var kexDHGexInit kexDHGexInitMsg
+	if err = Unmarshal(packet, &kexDHGexInit); err != nil {
+		return
+	}
+
+	pHalf := new(big.Int).Rsh(p, 1)
+
+	y, err := rand.Int(randSource, pHalf)
+	if err != nil {
+		return
+	}
+	Y := new(big.Int).Exp(g, y, p)
+
+	pMinusOne := new(big.Int).Sub(p, bigOne)
+	if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 {
+		return nil, errors.New("ssh: DH parameter out of bounds")
+	}
+	kInt := new(big.Int).Exp(kexDHGexInit.X, y, p)
+
+	hostKeyBytes := priv.PublicKey().Marshal()
+
+	h := gex.hashFunc.New()
+	magics.write(h)
+	writeString(h, hostKeyBytes)
+	binary.Write(h, binary.BigEndian, kexDHGexRequest.MinBits)
+	binary.Write(h, binary.BigEndian, kexDHGexRequest.PreferredBits)
+	binary.Write(h, binary.BigEndian, kexDHGexRequest.MaxBits)
+	writeInt(h, p)
+	writeInt(h, g)
+	writeInt(h, kexDHGexInit.X)
+	writeInt(h, Y)
+
+	K := make([]byte, intLength(kInt))
+	marshalInt(K, kInt)
+	h.Write(K)
+
+	H := h.Sum(nil)
+
+	// H is already a hash, but the hostkey signing will apply its
+	// own key-specific hash algorithm.
+	sig, err := signAndMarshal(priv, randSource, H, algo)
+	if err != nil {
+		return nil, err
+	}
+
+	kexDHGexReply := kexDHGexReplyMsg{
+		HostKey:   hostKeyBytes,
+		Y:         Y,
+		Signature: sig,
+	}
+	packet = Marshal(&kexDHGexReply)
+
+	err = c.writePacket(packet)
+
+	return &kexResult{
+		H:         H,
+		K:         K,
+		HostKey:   hostKeyBytes,
+		Signature: sig,
+		Hash:      gex.hashFunc,
+	}, err
+}
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
new file mode 100644
index 000000000..3482c4d2c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -0,0 +1,1881 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/dsa"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/elliptic"
+	"crypto/md5"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha256"
+	"crypto/x509"
+	"encoding/asn1"
+	"encoding/base64"
+	"encoding/binary"
+	"encoding/hex"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io"
+	"math/big"
+	"slices"
+	"strings"
+
+	"golang.org/x/crypto/ssh/internal/bcrypt_pbkdf"
+)
+
+// Public key algorithms names. These values can appear in PublicKey.Type,
+// ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner
+// arguments.
+const (
+	KeyAlgoRSA = "ssh-rsa"
+	// Deprecated: DSA is only supported at insecure key sizes, and was removed
+	// from major implementations.
+	KeyAlgoDSA = InsecureKeyAlgoDSA
+	// Deprecated: DSA is only supported at insecure key sizes, and was removed
+	// from major implementations.
+	InsecureKeyAlgoDSA = "ssh-dss"
+	KeyAlgoECDSA256    = "ecdsa-sha2-nistp256"
+	KeyAlgoSKECDSA256  = "sk-ecdsa-sha2-nistp256@openssh.com"
+	KeyAlgoECDSA384    = "ecdsa-sha2-nistp384"
+	KeyAlgoECDSA521    = "ecdsa-sha2-nistp521"
+	KeyAlgoED25519     = "ssh-ed25519"
+	KeyAlgoSKED25519   = "sk-ssh-ed25519@openssh.com"
+
+	// KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms, not
+	// public key formats, so they can't appear as a PublicKey.Type. The
+	// corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2.
+	KeyAlgoRSASHA256 = "rsa-sha2-256"
+	KeyAlgoRSASHA512 = "rsa-sha2-512"
+)
+
+const (
+	// Deprecated: use KeyAlgoRSA.
+	SigAlgoRSA = KeyAlgoRSA
+	// Deprecated: use KeyAlgoRSASHA256.
+	SigAlgoRSASHA2256 = KeyAlgoRSASHA256
+	// Deprecated: use KeyAlgoRSASHA512.
+	SigAlgoRSASHA2512 = KeyAlgoRSASHA512
+)
+
+// parsePubKey parses a public key of the given algorithm.
+// Use ParsePublicKey for keys with prepended algorithm.
+func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) {
+	switch algo {
+	case KeyAlgoRSA:
+		return parseRSA(in)
+	case InsecureKeyAlgoDSA:
+		return parseDSA(in)
+	case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
+		return parseECDSA(in)
+	case KeyAlgoSKECDSA256:
+		return parseSKECDSA(in)
+	case KeyAlgoED25519:
+		return parseED25519(in)
+	case KeyAlgoSKED25519:
+		return parseSKEd25519(in)
+	case CertAlgoRSAv01, InsecureCertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
+		cert, err := parseCert(in, certKeyAlgoNames[algo])
+		if err != nil {
+			return nil, nil, err
+		}
+		return cert, nil, nil
+	}
+	if keyFormat := keyFormatForAlgorithm(algo); keyFormat != "" {
+		return nil, nil, fmt.Errorf("ssh: signature algorithm %q isn't a key format; key is malformed and should be re-encoded with type %q",
+			algo, keyFormat)
+	}
+
+	return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo)
+}
+
+// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format
+// (see sshd(8) manual page) once the options and key type fields have been
+// removed.
+func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) {
+	in = bytes.TrimSpace(in)
+
+	i := bytes.IndexAny(in, " \t")
+	if i == -1 {
+		i = len(in)
+	}
+	base64Key := in[:i]
+
+	key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key)))
+	n, err := base64.StdEncoding.Decode(key, base64Key)
+	if err != nil {
+		return nil, "", err
+	}
+	key = key[:n]
+	out, err = ParsePublicKey(key)
+	if err != nil {
+		return nil, "", err
+	}
+	comment = string(bytes.TrimSpace(in[i:]))
+	return out, comment, nil
+}
+
+// ParseKnownHosts parses an entry in the format of the known_hosts file.
+//
+// The known_hosts format is documented in the sshd(8) manual page. This
+// function will parse a single entry from in. On successful return, marker
+// will contain the optional marker value (i.e. "cert-authority" or "revoked")
+// or else be empty, hosts will contain the hosts that this entry matches,
+// pubKey will contain the public key and comment will contain any trailing
+// comment at the end of the line. See the sshd(8) manual page for the various
+// forms that a host string can take.
+//
+// The unparsed remainder of the input will be returned in rest. This function
+// can be called repeatedly to parse multiple entries.
+//
+// If no entries were found in the input then err will be io.EOF. Otherwise a
+// non-nil err value indicates a parse error.
+func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) {
+	for len(in) > 0 {
+		end := bytes.IndexByte(in, '\n')
+		if end != -1 {
+			rest = in[end+1:]
+			in = in[:end]
+		} else {
+			rest = nil
+		}
+
+		end = bytes.IndexByte(in, '\r')
+		if end != -1 {
+			in = in[:end]
+		}
+
+		in = bytes.TrimSpace(in)
+		if len(in) == 0 || in[0] == '#' {
+			in = rest
+			continue
+		}
+
+		i := bytes.IndexAny(in, " \t")
+		if i == -1 {
+			in = rest
+			continue
+		}
+
+		// Strip out the beginning of the known_host key.
+		// This is either an optional marker or a (set of) hostname(s).
+		keyFields := bytes.Fields(in)
+		if len(keyFields) < 3 || len(keyFields) > 5 {
+			return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data")
+		}
+
+		// keyFields[0] is either "@cert-authority", "@revoked" or a comma separated
+		// list of hosts
+		marker := ""
+		if keyFields[0][0] == '@' {
+			marker = string(keyFields[0][1:])
+			keyFields = keyFields[1:]
+		}
+
+		hosts := string(keyFields[0])
+		// keyFields[1] contains the key type (e.g. “ssh-rsa”).
+		// However, that information is duplicated inside the
+		// base64-encoded key and so is ignored here.
+
+		key := bytes.Join(keyFields[2:], []byte(" "))
+		if pubKey, comment, err = parseAuthorizedKey(key); err != nil {
+			return "", nil, nil, "", nil, err
+		}
+
+		return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil
+	}
+
+	return "", nil, nil, "", nil, io.EOF
+}
+
+// ParseAuthorizedKey parses a public key from an authorized_keys file used in
+// OpenSSH according to the sshd(8) manual page. Invalid lines are ignored.
+func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) {
+	var lastErr error
+	for len(in) > 0 {
+		end := bytes.IndexByte(in, '\n')
+		if end != -1 {
+			rest = in[end+1:]
+			in = in[:end]
+		} else {
+			rest = nil
+		}
+
+		end = bytes.IndexByte(in, '\r')
+		if end != -1 {
+			in = in[:end]
+		}
+
+		in = bytes.TrimSpace(in)
+		if len(in) == 0 || in[0] == '#' {
+			in = rest
+			continue
+		}
+
+		i := bytes.IndexAny(in, " \t")
+		if i == -1 {
+			in = rest
+			continue
+		}
+
+		if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
+			return out, comment, options, rest, nil
+		} else {
+			lastErr = err
+		}
+
+		// No key type recognised. Maybe there's an options field at
+		// the beginning.
+		var b byte
+		inQuote := false
+		var candidateOptions []string
+		optionStart := 0
+		for i, b = range in {
+			isEnd := !inQuote && (b == ' ' || b == '\t')
+			if (b == ',' && !inQuote) || isEnd {
+				if i-optionStart > 0 {
+					candidateOptions = append(candidateOptions, string(in[optionStart:i]))
+				}
+				optionStart = i + 1
+			}
+			if isEnd {
+				break
+			}
+			if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) {
+				inQuote = !inQuote
+			}
+		}
+		for i < len(in) && (in[i] == ' ' || in[i] == '\t') {
+			i++
+		}
+		if i == len(in) {
+			// Invalid line: unmatched quote
+			in = rest
+			continue
+		}
+
+		in = in[i:]
+		i = bytes.IndexAny(in, " \t")
+		if i == -1 {
+			in = rest
+			continue
+		}
+
+		if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
+			options = candidateOptions
+			return out, comment, options, rest, nil
+		} else {
+			lastErr = err
+		}
+
+		in = rest
+		continue
+	}
+
+	if lastErr != nil {
+		return nil, "", nil, nil, fmt.Errorf("ssh: no key found; last parsing error for ignored line: %w", lastErr)
+	}
+
+	return nil, "", nil, nil, errors.New("ssh: no key found")
+}
+
+// ParsePublicKey parses an SSH public key or certificate formatted for use in
+// the SSH wire protocol according to RFC 4253, section 6.6.
+func ParsePublicKey(in []byte) (out PublicKey, err error) {
+	algo, in, ok := parseString(in)
+	if !ok {
+		return nil, errShortRead
+	}
+	var rest []byte
+	out, rest, err = parsePubKey(in, string(algo))
+	if len(rest) > 0 {
+		return nil, errors.New("ssh: trailing junk in public key")
+	}
+
+	return out, err
+}
+
+// MarshalAuthorizedKey serializes key for inclusion in an OpenSSH
+// authorized_keys file. The return value ends with newline.
+func MarshalAuthorizedKey(key PublicKey) []byte {
+	b := &bytes.Buffer{}
+	b.WriteString(key.Type())
+	b.WriteByte(' ')
+	e := base64.NewEncoder(base64.StdEncoding, b)
+	e.Write(key.Marshal())
+	e.Close()
+	b.WriteByte('\n')
+	return b.Bytes()
+}
+
+// MarshalPrivateKey returns a PEM block with the private key serialized in the
+// OpenSSH format.
+func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error) {
+	return marshalOpenSSHPrivateKey(key, comment, unencryptedOpenSSHMarshaler)
+}
+
+// MarshalPrivateKeyWithPassphrase returns a PEM block holding the encrypted
+// private key serialized in the OpenSSH format.
+func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment string, passphrase []byte) (*pem.Block, error) {
+	return marshalOpenSSHPrivateKey(key, comment, passphraseProtectedOpenSSHMarshaler(passphrase))
+}
+
+// PublicKey represents a public key using an unspecified algorithm.
+//
+// Some PublicKeys provided by this package also implement CryptoPublicKey.
+type PublicKey interface {
+	// Type returns the key format name, e.g. "ssh-rsa".
+	Type() string
+
+	// Marshal returns the serialized key data in SSH wire format, with the name
+	// prefix. To unmarshal the returned data, use the ParsePublicKey function.
+	Marshal() []byte
+
+	// Verify that sig is a signature on the given data using this key. This
+	// method will hash the data appropriately first. sig.Format is allowed to
+	// be any signature algorithm compatible with the key type, the caller
+	// should check if it has more stringent requirements.
+	Verify(data []byte, sig *Signature) error
+}
+
+// CryptoPublicKey, if implemented by a PublicKey,
+// returns the underlying crypto.PublicKey form of the key.
+type CryptoPublicKey interface {
+	CryptoPublicKey() crypto.PublicKey
+}
+
+// A Signer can create signatures that verify against a public key.
+//
+// Some Signers provided by this package also implement MultiAlgorithmSigner.
+type Signer interface {
+	// PublicKey returns the associated PublicKey.
+	PublicKey() PublicKey
+
+	// Sign returns a signature for the given data. This method will hash the
+	// data appropriately first. The signature algorithm is expected to match
+	// the key format returned by the PublicKey.Type method (and not to be any
+	// alternative algorithm supported by the key format).
+	Sign(rand io.Reader, data []byte) (*Signature, error)
+}
+
+// An AlgorithmSigner is a Signer that also supports specifying an algorithm to
+// use for signing.
+//
+// An AlgorithmSigner can't advertise the algorithms it supports, unless it also
+// implements MultiAlgorithmSigner, so it should be prepared to be invoked with
+// every algorithm supported by the public key format.
+type AlgorithmSigner interface {
+	Signer
+
+	// SignWithAlgorithm is like Signer.Sign, but allows specifying a desired
+	// signing algorithm. Callers may pass an empty string for the algorithm in
+	// which case the AlgorithmSigner will use a default algorithm. This default
+	// doesn't currently control any behavior in this package.
+	SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
+}
+
+// MultiAlgorithmSigner is an AlgorithmSigner that also reports the algorithms
+// supported by that signer.
+type MultiAlgorithmSigner interface {
+	AlgorithmSigner
+
+	// Algorithms returns the available algorithms in preference order. The list
+	// must not be empty, and it must not include certificate types.
+	Algorithms() []string
+}
+
+// NewSignerWithAlgorithms returns a signer restricted to the specified
+// algorithms. The algorithms must be set in preference order. The list must not
+// be empty, and it must not include certificate types. An error is returned if
+// the specified algorithms are incompatible with the public key type.
+func NewSignerWithAlgorithms(signer AlgorithmSigner, algorithms []string) (MultiAlgorithmSigner, error) {
+	if len(algorithms) == 0 {
+		return nil, errors.New("ssh: please specify at least one valid signing algorithm")
+	}
+	var signerAlgos []string
+	supportedAlgos := algorithmsForKeyFormat(underlyingAlgo(signer.PublicKey().Type()))
+	if s, ok := signer.(*multiAlgorithmSigner); ok {
+		signerAlgos = s.Algorithms()
+	} else {
+		signerAlgos = supportedAlgos
+	}
+
+	for _, algo := range algorithms {
+		if !slices.Contains(supportedAlgos, algo) {
+			return nil, fmt.Errorf("ssh: algorithm %q is not supported for key type %q",
+				algo, signer.PublicKey().Type())
+		}
+		if !slices.Contains(signerAlgos, algo) {
+			return nil, fmt.Errorf("ssh: algorithm %q is restricted for the provided signer", algo)
+		}
+	}
+	return &multiAlgorithmSigner{
+		AlgorithmSigner:     signer,
+		supportedAlgorithms: algorithms,
+	}, nil
+}
+
+type multiAlgorithmSigner struct {
+	AlgorithmSigner
+	supportedAlgorithms []string
+}
+
+func (s *multiAlgorithmSigner) Algorithms() []string {
+	return s.supportedAlgorithms
+}
+
+func (s *multiAlgorithmSigner) isAlgorithmSupported(algorithm string) bool {
+	if algorithm == "" {
+		algorithm = underlyingAlgo(s.PublicKey().Type())
+	}
+	for _, algo := range s.supportedAlgorithms {
+		if algorithm == algo {
+			return true
+		}
+	}
+	return false
+}
+
+func (s *multiAlgorithmSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
+	if !s.isAlgorithmSupported(algorithm) {
+		return nil, fmt.Errorf("ssh: algorithm %q is not supported: %v", algorithm, s.supportedAlgorithms)
+	}
+	return s.AlgorithmSigner.SignWithAlgorithm(rand, data, algorithm)
+}
+
+type rsaPublicKey rsa.PublicKey
+
+func (r *rsaPublicKey) Type() string {
+	return "ssh-rsa"
+}
+
+// parseRSA parses an RSA key according to RFC 4253, section 6.6.
+func parseRSA(in []byte) (out PublicKey, rest []byte, err error) {
+	var w struct {
+		E    *big.Int
+		N    *big.Int
+		Rest []byte `ssh:"rest"`
+	}
+	if err := Unmarshal(in, &w); err != nil {
+		return nil, nil, err
+	}
+
+	// 8192 bits is also the maximum RSA key size accepted by crypto/tls for
+	// signature verification:
+	// https://github.com/golang/go/blob/69801b25/src/crypto/tls/handshake_client.go#L1096
+	if w.N.BitLen() > 8192 {
+		return nil, nil, errors.New("ssh: rsa modulus too large")
+	}
+	if w.E.BitLen() > 24 {
+		return nil, nil, errors.New("ssh: exponent too large")
+	}
+	e := w.E.Int64()
+	if e < 3 || e&1 == 0 {
+		return nil, nil, errors.New("ssh: incorrect exponent")
+	}
+
+	var key rsa.PublicKey
+	key.E = int(e)
+	key.N = w.N
+	return (*rsaPublicKey)(&key), w.Rest, nil
+}
+
+func (r *rsaPublicKey) Marshal() []byte {
+	e := new(big.Int).SetInt64(int64(r.E))
+	// RSA publickey struct layout should match the struct used by
+	// parseRSACert in the x/crypto/ssh/agent package.
+	wirekey := struct {
+		Name string
+		E    *big.Int
+		N    *big.Int
+	}{
+		KeyAlgoRSA,
+		e,
+		r.N,
+	}
+	return Marshal(&wirekey)
+}
+
+func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
+	supportedAlgos := algorithmsForKeyFormat(r.Type())
+	if !slices.Contains(supportedAlgos, sig.Format) {
+		return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
+	}
+	hash, err := hashFunc(sig.Format)
+	if err != nil {
+		return err
+	}
+	h := hash.New()
+	h.Write(data)
+	digest := h.Sum(nil)
+
+	// Signatures in PKCS1v15 must match the key's modulus in
+	// length. However with SSH, some signers provide RSA
+	// signatures which are missing the MSB 0's of the bignum
+	// represented. With ssh-rsa signatures, this is encouraged by
+	// the spec (even though e.g. OpenSSH will give the full
+	// length unconditionally). With rsa-sha2-* signatures, the
+	// verifier is allowed to support these, even though they are
+	// out of spec. See RFC 4253 Section 6.6 for ssh-rsa and RFC
+	// 8332 Section 3 for rsa-sha2-* details.
+	//
+	// In practice:
+	// * OpenSSH always allows "short" signatures:
+	//   https://github.com/openssh/openssh-portable/blob/V_9_8_P1/ssh-rsa.c#L526
+	//   but always generates padded signatures:
+	//   https://github.com/openssh/openssh-portable/blob/V_9_8_P1/ssh-rsa.c#L439
+	//
+	// * PuTTY versions 0.81 and earlier will generate short
+	//   signatures for all RSA signature variants. Note that
+	//   PuTTY is embedded in other software, such as WinSCP and
+	//   FileZilla. At the time of writing, a patch has been
+	//   applied to PuTTY to generate padded signatures for
+	//   rsa-sha2-*, but not yet released:
+	//   https://git.tartarus.org/?p=simon/putty.git;a=commitdiff;h=a5bcf3d384e1bf15a51a6923c3724cbbee022d8e
+	//
+	// * SSH.NET versions 2024.0.0 and earlier will generate short
+	//   signatures for all RSA signature variants, fixed in 2024.1.0:
+	//   https://github.com/sshnet/SSH.NET/releases/tag/2024.1.0
+	//
+	// As a result, we pad these up to the key size by inserting
+	// leading 0's.
+	//
+	// Note that support for short signatures with rsa-sha2-* may
+	// be removed in the future due to such signatures not being
+	// allowed by the spec.
+	blob := sig.Blob
+	keySize := (*rsa.PublicKey)(r).Size()
+	if len(blob) < keySize {
+		padded := make([]byte, keySize)
+		copy(padded[keySize-len(blob):], blob)
+		blob = padded
+	}
+	return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, blob)
+}
+
+func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
+	return (*rsa.PublicKey)(r)
+}
+
+type dsaPublicKey dsa.PublicKey
+
+func (k *dsaPublicKey) Type() string {
+	return "ssh-dss"
+}
+
+func checkDSAParams(param *dsa.Parameters) error {
+	// SSH specifies FIPS 186-2, which only provided a single size
+	// (1024 bits) DSA key. FIPS 186-3 allows for larger key
+	// sizes, which would confuse SSH.
+	if l := param.P.BitLen(); l != 1024 {
+		return fmt.Errorf("ssh: unsupported DSA key size %d", l)
+	}
+
+	// FIPS 186-2 specifies that Q must be exactly 160 bits. We must enforce
+	// this to prevent DoS attacks where an attacker sends a huge Q which makes
+	// verification slow.
+	if l := param.Q.BitLen(); l != 160 {
+		return fmt.Errorf("ssh: unsupported DSA sub-prime size %d", l)
+	}
+
+	// The generator G is an element of the group, so it must be strictly less
+	// than the modulus P.
+	if param.G.Cmp(param.P) >= 0 {
+		return errors.New("ssh: DSA generator larger than modulus")
+	}
+
+	// G must be positive.
+	if param.G.Sign() <= 0 {
+		return errors.New("ssh: DSA generator must be positive")
+	}
+
+	return nil
+}
+
+// parseDSA parses an DSA key according to RFC 4253, section 6.6.
+func parseDSA(in []byte) (out PublicKey, rest []byte, err error) {
+	var w struct {
+		P, Q, G, Y *big.Int
+		Rest       []byte `ssh:"rest"`
+	}
+	if err := Unmarshal(in, &w); err != nil {
+		return nil, nil, err
+	}
+
+	param := dsa.Parameters{
+		P: w.P,
+		Q: w.Q,
+		G: w.G,
+	}
+	if err := checkDSAParams(&param); err != nil {
+		return nil, nil, err
+	}
+
+	// The public value Y must be a non-zero element of the group, i.e.
+	// strictly between 0 and P. crypto/dsa.Verify does not range-check Y,
+	// so we reject out-of-range values here to prevent a maliciously
+	// oversized Y from slowing verification.
+	if w.Y.Sign() <= 0 || w.Y.Cmp(w.P) >= 0 {
+		return nil, nil, errors.New("ssh: DSA public value Y out of range")
+	}
+
+	key := &dsaPublicKey{
+		Parameters: param,
+		Y:          w.Y,
+	}
+	return key, w.Rest, nil
+}
+
+func (k *dsaPublicKey) Marshal() []byte {
+	// DSA publickey struct layout should match the struct used by
+	// parseDSACert in the x/crypto/ssh/agent package.
+	w := struct {
+		Name       string
+		P, Q, G, Y *big.Int
+	}{
+		k.Type(),
+		k.P,
+		k.Q,
+		k.G,
+		k.Y,
+	}
+
+	return Marshal(&w)
+}
+
+func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
+	if sig.Format != k.Type() {
+		return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
+	}
+	hash, err := hashFunc(sig.Format)
+	if err != nil {
+		return err
+	}
+	h := hash.New()
+	h.Write(data)
+	digest := h.Sum(nil)
+
+	// Per RFC 4253, section 6.6,
+	// The value for 'dss_signature_blob' is encoded as a string containing
+	// r, followed by s (which are 160-bit integers, without lengths or
+	// padding, unsigned, and in network byte order).
+	// For DSS purposes, sig.Blob should be exactly 40 bytes in length.
+	if len(sig.Blob) != 40 {
+		return errors.New("ssh: DSA signature parse error")
+	}
+	r := new(big.Int).SetBytes(sig.Blob[:20])
+	s := new(big.Int).SetBytes(sig.Blob[20:])
+	if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) {
+		return nil
+	}
+	return errors.New("ssh: signature did not verify")
+}
+
+func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey {
+	return (*dsa.PublicKey)(k)
+}
+
+type dsaPrivateKey struct {
+	*dsa.PrivateKey
+}
+
+func (k *dsaPrivateKey) PublicKey() PublicKey {
+	return (*dsaPublicKey)(&k.PrivateKey.PublicKey)
+}
+
+func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
+	return k.SignWithAlgorithm(rand, data, k.PublicKey().Type())
+}
+
+func (k *dsaPrivateKey) Algorithms() []string {
+	return []string{k.PublicKey().Type()}
+}
+
+func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
+	if algorithm != "" && algorithm != k.PublicKey().Type() {
+		return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
+	}
+
+	hash, err := hashFunc(k.PublicKey().Type())
+	if err != nil {
+		return nil, err
+	}
+	h := hash.New()
+	h.Write(data)
+	digest := h.Sum(nil)
+	r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
+	if err != nil {
+		return nil, err
+	}
+
+	sig := make([]byte, 40)
+	rb := r.Bytes()
+	sb := s.Bytes()
+
+	copy(sig[20-len(rb):20], rb)
+	copy(sig[40-len(sb):], sb)
+
+	return &Signature{
+		Format: k.PublicKey().Type(),
+		Blob:   sig,
+	}, nil
+}
+
+type ecdsaPublicKey ecdsa.PublicKey
+
+func (k *ecdsaPublicKey) Type() string {
+	return "ecdsa-sha2-" + k.nistID()
+}
+
+func (k *ecdsaPublicKey) nistID() string {
+	switch k.Params().BitSize {
+	case 256:
+		return "nistp256"
+	case 384:
+		return "nistp384"
+	case 521:
+		return "nistp521"
+	}
+	panic("ssh: unsupported ecdsa key size")
+}
+
+type ed25519PublicKey ed25519.PublicKey
+
+func (k ed25519PublicKey) Type() string {
+	return KeyAlgoED25519
+}
+
+func parseED25519(in []byte) (out PublicKey, rest []byte, err error) {
+	var w struct {
+		KeyBytes []byte
+		Rest     []byte `ssh:"rest"`
+	}
+
+	if err := Unmarshal(in, &w); err != nil {
+		return nil, nil, err
+	}
+
+	if l := len(w.KeyBytes); l != ed25519.PublicKeySize {
+		return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l)
+	}
+
+	return ed25519PublicKey(w.KeyBytes), w.Rest, nil
+}
+
+func (k ed25519PublicKey) Marshal() []byte {
+	w := struct {
+		Name     string
+		KeyBytes []byte
+	}{
+		KeyAlgoED25519,
+		[]byte(k),
+	}
+	return Marshal(&w)
+}
+
+func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error {
+	if sig.Format != k.Type() {
+		return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
+	}
+	if l := len(k); l != ed25519.PublicKeySize {
+		return fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l)
+	}
+
+	if ok := ed25519.Verify(ed25519.PublicKey(k), b, sig.Blob); !ok {
+		return errors.New("ssh: signature did not verify")
+	}
+
+	return nil
+}
+
+func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey {
+	return ed25519.PublicKey(k)
+}
+
+func supportedEllipticCurve(curve elliptic.Curve) bool {
+	return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521()
+}
+
+// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
+func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) {
+	var w struct {
+		Curve    string
+		KeyBytes []byte
+		Rest     []byte `ssh:"rest"`
+	}
+
+	if err := Unmarshal(in, &w); err != nil {
+		return nil, nil, err
+	}
+
+	key := new(ecdsa.PublicKey)
+
+	switch w.Curve {
+	case "nistp256":
+		key.Curve = elliptic.P256()
+	case "nistp384":
+		key.Curve = elliptic.P384()
+	case "nistp521":
+		key.Curve = elliptic.P521()
+	default:
+		return nil, nil, errors.New("ssh: unsupported curve")
+	}
+
+	key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes)
+	if key.X == nil || key.Y == nil {
+		return nil, nil, errors.New("ssh: invalid curve point")
+	}
+	return (*ecdsaPublicKey)(key), w.Rest, nil
+}
+
+func (k *ecdsaPublicKey) Marshal() []byte {
+	// See RFC 5656, section 3.1.
+	keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y)
+	// ECDSA publickey struct layout should match the struct used by
+	// parseECDSACert in the x/crypto/ssh/agent package.
+	w := struct {
+		Name string
+		ID   string
+		Key  []byte
+	}{
+		k.Type(),
+		k.nistID(),
+		keyBytes,
+	}
+
+	return Marshal(&w)
+}
+
+func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
+	if sig.Format != k.Type() {
+		return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
+	}
+	hash, err := hashFunc(sig.Format)
+	if err != nil {
+		return err
+	}
+	h := hash.New()
+	h.Write(data)
+	digest := h.Sum(nil)
+
+	// Per RFC 5656, section 3.1.2,
+	// The ecdsa_signature_blob value has the following specific encoding:
+	//    mpint    r
+	//    mpint    s
+	var ecSig struct {
+		R *big.Int
+		S *big.Int
+	}
+
+	if err := Unmarshal(sig.Blob, &ecSig); err != nil {
+		return err
+	}
+
+	if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) {
+		return nil
+	}
+	return errors.New("ssh: signature did not verify")
+}
+
+func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey {
+	return (*ecdsa.PublicKey)(k)
+}
+
+// skFields holds the additional fields present in U2F/FIDO2 signatures.
+// See openssh/PROTOCOL.u2f 'SSH U2F Signatures' for details.
+type skFields struct {
+	// Flags contains U2F/FIDO2 flags such as 'user present'
+	Flags byte
+	// Counter is a monotonic signature counter which can be
+	// used to detect concurrent use of a private key, should
+	// it be extracted from hardware.
+	Counter uint32
+}
+
+// flagUserPresence is the "user present" bit (UP) in the SK signature
+// flags, matching the FIDO CTAP2 authenticatorData UP flag. See
+// openssh/PROTOCOL.u2f.
+const flagUserPresence = 0x01
+
+// errSKMissingUserPresence is returned by SK key Verify methods when
+// the signature does not assert user presence and the key was not
+// marked as no-touch-required.
+var errSKMissingUserPresence = errors.New("ssh: signature missing required user presence flag")
+
+type skECDSAPublicKey struct {
+	// application is a URL-like string, typically "ssh:" for SSH.
+	// see openssh/PROTOCOL.u2f for details.
+	application string
+	ecdsa.PublicKey
+	// noTouchRequired, when true, disables the default user-presence
+	// check in Verify. It is set by skKeyWithoutUP on a clone of the
+	// key, never on an instance shared across authentication attempts.
+	noTouchRequired bool
+}
+
+func (k *skECDSAPublicKey) Type() string {
+	return KeyAlgoSKECDSA256
+}
+
+func (k *skECDSAPublicKey) nistID() string {
+	return "nistp256"
+}
+
+func parseSKECDSA(in []byte) (out PublicKey, rest []byte, err error) {
+	var w struct {
+		Curve       string
+		KeyBytes    []byte
+		Application string
+		Rest        []byte `ssh:"rest"`
+	}
+
+	if err := Unmarshal(in, &w); err != nil {
+		return nil, nil, err
+	}
+
+	key := new(skECDSAPublicKey)
+	key.application = w.Application
+
+	if w.Curve != "nistp256" {
+		return nil, nil, errors.New("ssh: unsupported curve")
+	}
+	key.Curve = elliptic.P256()
+
+	key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes)
+	if key.X == nil || key.Y == nil {
+		return nil, nil, errors.New("ssh: invalid curve point")
+	}
+
+	return key, w.Rest, nil
+}
+
+func (k *skECDSAPublicKey) Marshal() []byte {
+	// See RFC 5656, section 3.1.
+	keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y)
+	w := struct {
+		Name        string
+		ID          string
+		Key         []byte
+		Application string
+	}{
+		k.Type(),
+		k.nistID(),
+		keyBytes,
+		k.application,
+	}
+
+	return Marshal(&w)
+}
+
+func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error {
+	if sig.Format != k.Type() {
+		return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
+	}
+	hash, err := hashFunc(sig.Format)
+	if err != nil {
+		return err
+	}
+	h := hash.New()
+	h.Write([]byte(k.application))
+	appDigest := h.Sum(nil)
+
+	h.Reset()
+	h.Write(data)
+	dataDigest := h.Sum(nil)
+
+	var ecSig struct {
+		R *big.Int
+		S *big.Int
+	}
+	if err := Unmarshal(sig.Blob, &ecSig); err != nil {
+		return err
+	}
+
+	var skf skFields
+	if err := Unmarshal(sig.Rest, &skf); err != nil {
+		return err
+	}
+
+	if skf.Flags&flagUserPresence == 0 && !k.noTouchRequired {
+		return errSKMissingUserPresence
+	}
+
+	blob := struct {
+		ApplicationDigest []byte `ssh:"rest"`
+		Flags             byte
+		Counter           uint32
+		MessageDigest     []byte `ssh:"rest"`
+	}{
+		appDigest,
+		skf.Flags,
+		skf.Counter,
+		dataDigest,
+	}
+
+	original := Marshal(blob)
+
+	h.Reset()
+	h.Write(original)
+	digest := h.Sum(nil)
+
+	if ecdsa.Verify((*ecdsa.PublicKey)(&k.PublicKey), digest, ecSig.R, ecSig.S) {
+		return nil
+	}
+	return errors.New("ssh: signature did not verify")
+}
+
+func (k *skECDSAPublicKey) CryptoPublicKey() crypto.PublicKey {
+	return &k.PublicKey
+}
+
+type skEd25519PublicKey struct {
+	// application is a URL-like string, typically "ssh:" for SSH.
+	// see openssh/PROTOCOL.u2f for details.
+	application string
+	ed25519.PublicKey
+	// noTouchRequired, when true, disables the default user-presence
+	// check in Verify. It is set by skKeyWithoutUP on a clone of the
+	// key, never on an instance shared across authentication attempts.
+	noTouchRequired bool
+}
+
+func (k *skEd25519PublicKey) Type() string {
+	return KeyAlgoSKED25519
+}
+
+func parseSKEd25519(in []byte) (out PublicKey, rest []byte, err error) {
+	var w struct {
+		KeyBytes    []byte
+		Application string
+		Rest        []byte `ssh:"rest"`
+	}
+
+	if err := Unmarshal(in, &w); err != nil {
+		return nil, nil, err
+	}
+
+	if l := len(w.KeyBytes); l != ed25519.PublicKeySize {
+		return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l)
+	}
+
+	key := new(skEd25519PublicKey)
+	key.application = w.Application
+	key.PublicKey = ed25519.PublicKey(w.KeyBytes)
+
+	return key, w.Rest, nil
+}
+
+func (k *skEd25519PublicKey) Marshal() []byte {
+	w := struct {
+		Name        string
+		KeyBytes    []byte
+		Application string
+	}{
+		KeyAlgoSKED25519,
+		[]byte(k.PublicKey),
+		k.application,
+	}
+	return Marshal(&w)
+}
+
+func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error {
+	if sig.Format != k.Type() {
+		return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
+	}
+	if l := len(k.PublicKey); l != ed25519.PublicKeySize {
+		return fmt.Errorf("invalid size %d for Ed25519 public key", l)
+	}
+
+	hash, err := hashFunc(sig.Format)
+	if err != nil {
+		return err
+	}
+	h := hash.New()
+	h.Write([]byte(k.application))
+	appDigest := h.Sum(nil)
+
+	h.Reset()
+	h.Write(data)
+	dataDigest := h.Sum(nil)
+
+	var edSig struct {
+		Signature []byte `ssh:"rest"`
+	}
+
+	if err := Unmarshal(sig.Blob, &edSig); err != nil {
+		return err
+	}
+
+	var skf skFields
+	if err := Unmarshal(sig.Rest, &skf); err != nil {
+		return err
+	}
+
+	if skf.Flags&flagUserPresence == 0 && !k.noTouchRequired {
+		return errSKMissingUserPresence
+	}
+
+	blob := struct {
+		ApplicationDigest []byte `ssh:"rest"`
+		Flags             byte
+		Counter           uint32
+		MessageDigest     []byte `ssh:"rest"`
+	}{
+		appDigest,
+		skf.Flags,
+		skf.Counter,
+		dataDigest,
+	}
+
+	original := Marshal(blob)
+
+	if ok := ed25519.Verify(k.PublicKey, original, edSig.Signature); !ok {
+		return errors.New("ssh: signature did not verify")
+	}
+
+	return nil
+}
+
+func (k *skEd25519PublicKey) CryptoPublicKey() crypto.PublicKey {
+	return k.PublicKey
+}
+
+// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
+// *ecdsa.PrivateKey or any other crypto.Signer and returns a
+// corresponding Signer instance. ECDSA keys must use P-256, P-384 or
+// P-521. DSA keys must use parameter size L1024N160.
+func NewSignerFromKey(key interface{}) (Signer, error) {
+	switch key := key.(type) {
+	case crypto.Signer:
+		return NewSignerFromSigner(key)
+	case *dsa.PrivateKey:
+		return newDSAPrivateKey(key)
+	default:
+		return nil, fmt.Errorf("ssh: unsupported key type %T", key)
+	}
+}
+
+func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) {
+	if err := checkDSAParams(&key.PublicKey.Parameters); err != nil {
+		return nil, err
+	}
+
+	return &dsaPrivateKey{key}, nil
+}
+
+type wrappedSigner struct {
+	signer crypto.Signer
+	pubKey PublicKey
+}
+
+// NewSignerFromSigner takes any crypto.Signer implementation and
+// returns a corresponding Signer interface. This can be used, for
+// example, with keys kept in hardware modules.
+func NewSignerFromSigner(signer crypto.Signer) (Signer, error) {
+	pubKey, err := NewPublicKey(signer.Public())
+	if err != nil {
+		return nil, err
+	}
+
+	return &wrappedSigner{signer, pubKey}, nil
+}
+
+func (s *wrappedSigner) PublicKey() PublicKey {
+	return s.pubKey
+}
+
+func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
+	return s.SignWithAlgorithm(rand, data, s.pubKey.Type())
+}
+
+func (s *wrappedSigner) Algorithms() []string {
+	return algorithmsForKeyFormat(s.pubKey.Type())
+}
+
+func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
+	if algorithm == "" {
+		algorithm = s.pubKey.Type()
+	}
+
+	if !slices.Contains(s.Algorithms(), algorithm) {
+		return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type())
+	}
+
+	hashFunc, err := hashFunc(algorithm)
+	if err != nil {
+		return nil, err
+	}
+	var digest []byte
+	if hashFunc != 0 {
+		h := hashFunc.New()
+		h.Write(data)
+		digest = h.Sum(nil)
+	} else {
+		digest = data
+	}
+
+	signature, err := s.signer.Sign(rand, digest, hashFunc)
+	if err != nil {
+		return nil, err
+	}
+
+	// crypto.Signer.Sign is expected to return an ASN.1-encoded signature
+	// for ECDSA and DSA, but that's not the encoding expected by SSH, so
+	// re-encode.
+	switch s.pubKey.(type) {
+	case *ecdsaPublicKey, *dsaPublicKey:
+		type asn1Signature struct {
+			R, S *big.Int
+		}
+		asn1Sig := new(asn1Signature)
+		_, err := asn1.Unmarshal(signature, asn1Sig)
+		if err != nil {
+			return nil, err
+		}
+
+		switch s.pubKey.(type) {
+		case *ecdsaPublicKey:
+			signature = Marshal(asn1Sig)
+
+		case *dsaPublicKey:
+			signature = make([]byte, 40)
+			r := asn1Sig.R.Bytes()
+			s := asn1Sig.S.Bytes()
+			copy(signature[20-len(r):20], r)
+			copy(signature[40-len(s):40], s)
+		}
+	}
+
+	return &Signature{
+		Format: algorithm,
+		Blob:   signature,
+	}, nil
+}
+
+// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey,
+// or ed25519.PublicKey returns a corresponding PublicKey instance.
+// ECDSA keys must use P-256, P-384 or P-521.
+func NewPublicKey(key interface{}) (PublicKey, error) {
+	switch key := key.(type) {
+	case *rsa.PublicKey:
+		return (*rsaPublicKey)(key), nil
+	case *ecdsa.PublicKey:
+		if !supportedEllipticCurve(key.Curve) {
+			return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported")
+		}
+		return (*ecdsaPublicKey)(key), nil
+	case *dsa.PublicKey:
+		return (*dsaPublicKey)(key), nil
+	case ed25519.PublicKey:
+		if l := len(key); l != ed25519.PublicKeySize {
+			return nil, fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l)
+		}
+		return ed25519PublicKey(key), nil
+	default:
+		return nil, fmt.Errorf("ssh: unsupported key type %T", key)
+	}
+}
+
+// ParsePrivateKey returns a Signer from a PEM encoded private key. It supports
+// the same keys as ParseRawPrivateKey. If the private key is encrypted, it
+// will return a PassphraseMissingError.
+func ParsePrivateKey(pemBytes []byte) (Signer, error) {
+	key, err := ParseRawPrivateKey(pemBytes)
+	if err != nil {
+		return nil, err
+	}
+
+	return NewSignerFromKey(key)
+}
+
+// ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private
+// key and passphrase. It supports the same keys as
+// ParseRawPrivateKeyWithPassphrase.
+func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer, error) {
+	key, err := ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase)
+	if err != nil {
+		return nil, err
+	}
+
+	return NewSignerFromKey(key)
+}
+
+// encryptedBlock tells whether a private key is
+// encrypted by examining its Proc-Type header
+// for a mention of ENCRYPTED
+// according to RFC 1421 Section 4.6.1.1.
+func encryptedBlock(block *pem.Block) bool {
+	return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED")
+}
+
+// A PassphraseMissingError indicates that parsing this private key requires a
+// passphrase. Use ParsePrivateKeyWithPassphrase.
+type PassphraseMissingError struct {
+	// PublicKey will be set if the private key format includes an unencrypted
+	// public key along with the encrypted private key.
+	PublicKey PublicKey
+}
+
+func (*PassphraseMissingError) Error() string {
+	return "ssh: this private key is passphrase protected"
+}
+
+// ParseRawPrivateKey returns a private key from a PEM encoded private key. It supports
+// RSA, DSA, ECDSA, and Ed25519 private keys in PKCS#1, PKCS#8, OpenSSL, and OpenSSH
+// formats. If the private key is encrypted, it will return a PassphraseMissingError.
+func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
+	block, _ := pem.Decode(pemBytes)
+	if block == nil {
+		return nil, errors.New("ssh: no key found")
+	}
+
+	if encryptedBlock(block) {
+		return nil, &PassphraseMissingError{}
+	}
+
+	switch block.Type {
+	case "RSA PRIVATE KEY":
+		return x509.ParsePKCS1PrivateKey(block.Bytes)
+	// RFC5208 - https://tools.ietf.org/html/rfc5208
+	case "PRIVATE KEY":
+		return x509.ParsePKCS8PrivateKey(block.Bytes)
+	case "EC PRIVATE KEY":
+		return x509.ParseECPrivateKey(block.Bytes)
+	case "DSA PRIVATE KEY":
+		return ParseDSAPrivateKey(block.Bytes)
+	case "OPENSSH PRIVATE KEY":
+		return parseOpenSSHPrivateKey(block.Bytes, unencryptedOpenSSHKey)
+	default:
+		return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
+	}
+}
+
+// ParseRawPrivateKeyWithPassphrase returns a private key decrypted with
+// passphrase from a PEM encoded private key. If the passphrase is wrong, it
+// will return x509.IncorrectPasswordError.
+func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{}, error) {
+	block, _ := pem.Decode(pemBytes)
+	if block == nil {
+		return nil, errors.New("ssh: no key found")
+	}
+
+	if block.Type == "OPENSSH PRIVATE KEY" {
+		return parseOpenSSHPrivateKey(block.Bytes, passphraseProtectedOpenSSHKey(passphrase))
+	}
+
+	if !encryptedBlock(block) || !x509.IsEncryptedPEMBlock(block) {
+		return nil, errors.New("ssh: not an encrypted key")
+	}
+
+	buf, err := x509.DecryptPEMBlock(block, passphrase)
+	if err != nil {
+		if err == x509.IncorrectPasswordError {
+			return nil, err
+		}
+		return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err)
+	}
+
+	var result interface{}
+
+	switch block.Type {
+	case "RSA PRIVATE KEY":
+		result, err = x509.ParsePKCS1PrivateKey(buf)
+	case "EC PRIVATE KEY":
+		result, err = x509.ParseECPrivateKey(buf)
+	case "DSA PRIVATE KEY":
+		result, err = ParseDSAPrivateKey(buf)
+	default:
+		err = fmt.Errorf("ssh: unsupported key type %q", block.Type)
+	}
+	// Because of deficiencies in the format, DecryptPEMBlock does not always
+	// detect an incorrect password. In these cases decrypted DER bytes is
+	// random noise. If the parsing of the key returns an asn1.StructuralError
+	// we return x509.IncorrectPasswordError.
+	if _, ok := err.(asn1.StructuralError); ok {
+		return nil, x509.IncorrectPasswordError
+	}
+
+	return result, err
+}
+
+// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as
+// specified by the OpenSSL DSA man page.
+func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
+	var k struct {
+		Version int
+		P       *big.Int
+		Q       *big.Int
+		G       *big.Int
+		Pub     *big.Int
+		Priv    *big.Int
+	}
+	rest, err := asn1.Unmarshal(der, &k)
+	if err != nil {
+		return nil, errors.New("ssh: failed to parse DSA key: " + err.Error())
+	}
+	if len(rest) > 0 {
+		return nil, errors.New("ssh: garbage after DSA key")
+	}
+
+	return &dsa.PrivateKey{
+		PublicKey: dsa.PublicKey{
+			Parameters: dsa.Parameters{
+				P: k.P,
+				Q: k.Q,
+				G: k.G,
+			},
+			Y: k.Pub,
+		},
+		X: k.Priv,
+	}, nil
+}
+
+func unencryptedOpenSSHKey(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) {
+	if kdfName != "none" || cipherName != "none" {
+		return nil, &PassphraseMissingError{}
+	}
+	if kdfOpts != "" {
+		return nil, errors.New("ssh: invalid openssh private key")
+	}
+	return privKeyBlock, nil
+}
+
+func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc {
+	return func(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) {
+		if kdfName == "none" || cipherName == "none" {
+			return nil, errors.New("ssh: key is not password protected")
+		}
+		if kdfName != "bcrypt" {
+			return nil, fmt.Errorf("ssh: unknown KDF %q, only supports %q", kdfName, "bcrypt")
+		}
+
+		var opts struct {
+			Salt   string
+			Rounds uint32
+		}
+		if err := Unmarshal([]byte(kdfOpts), &opts); err != nil {
+			return nil, err
+		}
+
+		k, err := bcrypt_pbkdf.Key(passphrase, []byte(opts.Salt), int(opts.Rounds), 32+16)
+		if err != nil {
+			return nil, err
+		}
+		key, iv := k[:32], k[32:]
+
+		c, err := aes.NewCipher(key)
+		if err != nil {
+			return nil, err
+		}
+		switch cipherName {
+		case "aes256-ctr":
+			ctr := cipher.NewCTR(c, iv)
+			ctr.XORKeyStream(privKeyBlock, privKeyBlock)
+		case "aes256-cbc":
+			if len(privKeyBlock)%c.BlockSize() != 0 {
+				return nil, fmt.Errorf("ssh: invalid encrypted private key length, not a multiple of the block size")
+			}
+			cbc := cipher.NewCBCDecrypter(c, iv)
+			cbc.CryptBlocks(privKeyBlock, privKeyBlock)
+		default:
+			return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", cipherName, "aes256-ctr", "aes256-cbc")
+		}
+
+		return privKeyBlock, nil
+	}
+}
+
+func unencryptedOpenSSHMarshaler(privKeyBlock []byte) ([]byte, string, string, string, error) {
+	key := generateOpenSSHPadding(privKeyBlock, 8)
+	return key, "none", "none", "", nil
+}
+
+func passphraseProtectedOpenSSHMarshaler(passphrase []byte) openSSHEncryptFunc {
+	return func(privKeyBlock []byte) ([]byte, string, string, string, error) {
+		salt := make([]byte, 16)
+		if _, err := rand.Read(salt); err != nil {
+			return nil, "", "", "", err
+		}
+
+		opts := struct {
+			Salt   []byte
+			Rounds uint32
+		}{salt, 16}
+
+		// Derive key to encrypt the private key block.
+		k, err := bcrypt_pbkdf.Key(passphrase, salt, int(opts.Rounds), 32+aes.BlockSize)
+		if err != nil {
+			return nil, "", "", "", err
+		}
+
+		// Add padding matching the block size of AES.
+		keyBlock := generateOpenSSHPadding(privKeyBlock, aes.BlockSize)
+
+		// Encrypt the private key using the derived secret.
+
+		dst := make([]byte, len(keyBlock))
+		key, iv := k[:32], k[32:]
+		block, err := aes.NewCipher(key)
+		if err != nil {
+			return nil, "", "", "", err
+		}
+
+		stream := cipher.NewCTR(block, iv)
+		stream.XORKeyStream(dst, keyBlock)
+
+		return dst, "aes256-ctr", "bcrypt", string(Marshal(opts)), nil
+	}
+}
+
+const privateKeyAuthMagic = "openssh-key-v1\x00"
+
+type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error)
+type openSSHEncryptFunc func(PrivKeyBlock []byte) (ProtectedKeyBlock []byte, cipherName, kdfName, kdfOptions string, err error)
+
+type openSSHEncryptedPrivateKey struct {
+	CipherName   string
+	KdfName      string
+	KdfOpts      string
+	NumKeys      uint32
+	PubKey       []byte
+	PrivKeyBlock []byte
+	Rest         []byte `ssh:"rest"`
+}
+
+type openSSHPrivateKey struct {
+	Check1  uint32
+	Check2  uint32
+	Keytype string
+	Rest    []byte `ssh:"rest"`
+}
+
+type openSSHRSAPrivateKey struct {
+	N       *big.Int
+	E       *big.Int
+	D       *big.Int
+	Iqmp    *big.Int
+	P       *big.Int
+	Q       *big.Int
+	Comment string
+	Pad     []byte `ssh:"rest"`
+}
+
+type openSSHEd25519PrivateKey struct {
+	Pub     []byte
+	Priv    []byte
+	Comment string
+	Pad     []byte `ssh:"rest"`
+}
+
+type openSSHECDSAPrivateKey struct {
+	Curve   string
+	Pub     []byte
+	D       *big.Int
+	Comment string
+	Pad     []byte `ssh:"rest"`
+}
+
+// parseOpenSSHPrivateKey parses an OpenSSH private key, using the decrypt
+// function to unwrap the encrypted portion. unencryptedOpenSSHKey can be used
+// as the decrypt function to parse an unencrypted private key. See
+// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key.
+func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.PrivateKey, error) {
+	if len(key) < len(privateKeyAuthMagic) || string(key[:len(privateKeyAuthMagic)]) != privateKeyAuthMagic {
+		return nil, errors.New("ssh: invalid openssh private key format")
+	}
+	remaining := key[len(privateKeyAuthMagic):]
+
+	var w openSSHEncryptedPrivateKey
+	if err := Unmarshal(remaining, &w); err != nil {
+		return nil, err
+	}
+	if w.NumKeys != 1 {
+		// We only support single key files, and so does OpenSSH.
+		// https://github.com/openssh/openssh-portable/blob/4103a3ec7/sshkey.c#L4171
+		return nil, errors.New("ssh: multi-key files are not supported")
+	}
+
+	privKeyBlock, err := decrypt(w.CipherName, w.KdfName, w.KdfOpts, w.PrivKeyBlock)
+	if err != nil {
+		if err, ok := err.(*PassphraseMissingError); ok {
+			pub, errPub := ParsePublicKey(w.PubKey)
+			if errPub != nil {
+				return nil, fmt.Errorf("ssh: failed to parse embedded public key: %v", errPub)
+			}
+			err.PublicKey = pub
+		}
+		return nil, err
+	}
+
+	var pk1 openSSHPrivateKey
+	if err := Unmarshal(privKeyBlock, &pk1); err != nil || pk1.Check1 != pk1.Check2 {
+		if w.CipherName != "none" {
+			return nil, x509.IncorrectPasswordError
+		}
+		return nil, errors.New("ssh: malformed OpenSSH key")
+	}
+
+	switch pk1.Keytype {
+	case KeyAlgoRSA:
+		var key openSSHRSAPrivateKey
+		if err := Unmarshal(pk1.Rest, &key); err != nil {
+			return nil, err
+		}
+
+		if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
+			return nil, err
+		}
+
+		pk := &rsa.PrivateKey{
+			PublicKey: rsa.PublicKey{
+				N: key.N,
+				E: int(key.E.Int64()),
+			},
+			D:      key.D,
+			Primes: []*big.Int{key.P, key.Q},
+		}
+
+		if err := pk.Validate(); err != nil {
+			return nil, err
+		}
+
+		pk.Precompute()
+
+		return pk, nil
+	case KeyAlgoED25519:
+		var key openSSHEd25519PrivateKey
+		if err := Unmarshal(pk1.Rest, &key); err != nil {
+			return nil, err
+		}
+
+		if len(key.Priv) != ed25519.PrivateKeySize {
+			return nil, errors.New("ssh: private key unexpected length")
+		}
+
+		if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
+			return nil, err
+		}
+
+		pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
+		copy(pk, key.Priv)
+		return &pk, nil
+	case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
+		var key openSSHECDSAPrivateKey
+		if err := Unmarshal(pk1.Rest, &key); err != nil {
+			return nil, err
+		}
+
+		if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
+			return nil, err
+		}
+
+		var curve elliptic.Curve
+		switch key.Curve {
+		case "nistp256":
+			curve = elliptic.P256()
+		case "nistp384":
+			curve = elliptic.P384()
+		case "nistp521":
+			curve = elliptic.P521()
+		default:
+			return nil, errors.New("ssh: unhandled elliptic curve: " + key.Curve)
+		}
+
+		X, Y := elliptic.Unmarshal(curve, key.Pub)
+		if X == nil || Y == nil {
+			return nil, errors.New("ssh: failed to unmarshal public key")
+		}
+
+		if key.D.Cmp(curve.Params().N) >= 0 {
+			return nil, errors.New("ssh: scalar is out of range")
+		}
+
+		x, y := curve.ScalarBaseMult(key.D.Bytes())
+		if x.Cmp(X) != 0 || y.Cmp(Y) != 0 {
+			return nil, errors.New("ssh: public key does not match private key")
+		}
+
+		return &ecdsa.PrivateKey{
+			PublicKey: ecdsa.PublicKey{
+				Curve: curve,
+				X:     X,
+				Y:     Y,
+			},
+			D: key.D,
+		}, nil
+	default:
+		return nil, errors.New("ssh: unhandled key type")
+	}
+}
+
+func marshalOpenSSHPrivateKey(key crypto.PrivateKey, comment string, encrypt openSSHEncryptFunc) (*pem.Block, error) {
+	var w openSSHEncryptedPrivateKey
+	var pk1 openSSHPrivateKey
+
+	// Random check bytes.
+	var check uint32
+	if err := binary.Read(rand.Reader, binary.BigEndian, &check); err != nil {
+		return nil, err
+	}
+
+	pk1.Check1 = check
+	pk1.Check2 = check
+	w.NumKeys = 1
+
+	// Use a []byte directly on ed25519 keys.
+	if k, ok := key.(*ed25519.PrivateKey); ok {
+		key = *k
+	}
+
+	switch k := key.(type) {
+	case *rsa.PrivateKey:
+		E := new(big.Int).SetInt64(int64(k.PublicKey.E))
+		// Marshal public key:
+		// E and N are in reversed order in the public and private key.
+		pubKey := struct {
+			KeyType string
+			E       *big.Int
+			N       *big.Int
+		}{
+			KeyAlgoRSA,
+			E, k.PublicKey.N,
+		}
+		w.PubKey = Marshal(pubKey)
+
+		// Marshal private key.
+		key := openSSHRSAPrivateKey{
+			N:       k.PublicKey.N,
+			E:       E,
+			D:       k.D,
+			Iqmp:    k.Precomputed.Qinv,
+			P:       k.Primes[0],
+			Q:       k.Primes[1],
+			Comment: comment,
+		}
+		pk1.Keytype = KeyAlgoRSA
+		pk1.Rest = Marshal(key)
+	case ed25519.PrivateKey:
+		pub := make([]byte, ed25519.PublicKeySize)
+		priv := make([]byte, ed25519.PrivateKeySize)
+		copy(pub, k[32:])
+		copy(priv, k)
+
+		// Marshal public key.
+		pubKey := struct {
+			KeyType string
+			Pub     []byte
+		}{
+			KeyAlgoED25519, pub,
+		}
+		w.PubKey = Marshal(pubKey)
+
+		// Marshal private key.
+		key := openSSHEd25519PrivateKey{
+			Pub:     pub,
+			Priv:    priv,
+			Comment: comment,
+		}
+		pk1.Keytype = KeyAlgoED25519
+		pk1.Rest = Marshal(key)
+	case *ecdsa.PrivateKey:
+		var curve, keyType string
+		switch name := k.Curve.Params().Name; name {
+		case "P-256":
+			curve = "nistp256"
+			keyType = KeyAlgoECDSA256
+		case "P-384":
+			curve = "nistp384"
+			keyType = KeyAlgoECDSA384
+		case "P-521":
+			curve = "nistp521"
+			keyType = KeyAlgoECDSA521
+		default:
+			return nil, errors.New("ssh: unhandled elliptic curve " + name)
+		}
+
+		pub := elliptic.Marshal(k.Curve, k.PublicKey.X, k.PublicKey.Y)
+
+		// Marshal public key.
+		pubKey := struct {
+			KeyType string
+			Curve   string
+			Pub     []byte
+		}{
+			keyType, curve, pub,
+		}
+		w.PubKey = Marshal(pubKey)
+
+		// Marshal private key.
+		key := openSSHECDSAPrivateKey{
+			Curve:   curve,
+			Pub:     pub,
+			D:       k.D,
+			Comment: comment,
+		}
+		pk1.Keytype = keyType
+		pk1.Rest = Marshal(key)
+	default:
+		return nil, fmt.Errorf("ssh: unsupported key type %T", k)
+	}
+
+	var err error
+	// Add padding and encrypt the key if necessary.
+	w.PrivKeyBlock, w.CipherName, w.KdfName, w.KdfOpts, err = encrypt(Marshal(pk1))
+	if err != nil {
+		return nil, err
+	}
+
+	b := Marshal(w)
+	block := &pem.Block{
+		Type:  "OPENSSH PRIVATE KEY",
+		Bytes: append([]byte(privateKeyAuthMagic), b...),
+	}
+	return block, nil
+}
+
+func checkOpenSSHKeyPadding(pad []byte) error {
+	for i, b := range pad {
+		if int(b) != i+1 {
+			return errors.New("ssh: padding not as expected")
+		}
+	}
+	return nil
+}
+
+func generateOpenSSHPadding(block []byte, blockSize int) []byte {
+	for i, l := 0, len(block); (l+i)%blockSize != 0; i++ {
+		block = append(block, byte(i+1))
+	}
+	return block
+}
+
+// FingerprintLegacyMD5 returns the user presentation of the key's
+// fingerprint as described by RFC 4716 section 4.
+func FingerprintLegacyMD5(pubKey PublicKey) string {
+	md5sum := md5.Sum(pubKey.Marshal())
+	hexarray := make([]string, len(md5sum))
+	for i, c := range md5sum {
+		hexarray[i] = hex.EncodeToString([]byte{c})
+	}
+	return strings.Join(hexarray, ":")
+}
+
+// FingerprintSHA256 returns the user presentation of the key's
+// fingerprint as unpadded base64 encoded sha256 hash.
+// This format was introduced from OpenSSH 6.8.
+// https://www.openssh.com/txt/release-6.8
+// https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding)
+func FingerprintSHA256(pubKey PublicKey) string {
+	sha256sum := sha256.Sum256(pubKey.Marshal())
+	hash := base64.RawStdEncoding.EncodeToString(sha256sum[:])
+	return "SHA256:" + hash
+}
diff --git a/vendor/golang.org/x/crypto/ssh/mac.go b/vendor/golang.org/x/crypto/ssh/mac.go
new file mode 100644
index 000000000..87d626fbb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/mac.go
@@ -0,0 +1,84 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+// Message authentication support
+
+import (
+	"crypto/fips140"
+	"crypto/hmac"
+	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
+	"hash"
+	"slices"
+)
+
+type macMode struct {
+	keySize int
+	etm     bool
+	new     func(key []byte) hash.Hash
+}
+
+// truncatingMAC wraps around a hash.Hash and truncates the output digest to
+// a given size.
+type truncatingMAC struct {
+	length int
+	hmac   hash.Hash
+}
+
+func (t truncatingMAC) Write(data []byte) (int, error) {
+	return t.hmac.Write(data)
+}
+
+func (t truncatingMAC) Sum(in []byte) []byte {
+	out := t.hmac.Sum(in)
+	return out[:len(in)+t.length]
+}
+
+func (t truncatingMAC) Reset() {
+	t.hmac.Reset()
+}
+
+func (t truncatingMAC) Size() int {
+	return t.length
+}
+
+func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
+
+// macModes defines the supported MACs. MACs not included are not supported
+// and will not be negotiated, even if explicitly configured. When FIPS mode is
+// enabled, only FIPS-approved algorithms are included.
+var macModes = map[string]*macMode{}
+
+func init() {
+	macModes[HMACSHA512ETM] = &macMode{64, true, func(key []byte) hash.Hash {
+		return hmac.New(sha512.New, key)
+	}}
+	macModes[HMACSHA256ETM] = &macMode{32, true, func(key []byte) hash.Hash {
+		return hmac.New(sha256.New, key)
+	}}
+	macModes[HMACSHA512] = &macMode{64, false, func(key []byte) hash.Hash {
+		return hmac.New(sha512.New, key)
+	}}
+	macModes[HMACSHA256] = &macMode{32, false, func(key []byte) hash.Hash {
+		return hmac.New(sha256.New, key)
+	}}
+
+	if fips140.Enabled() {
+		defaultMACs = slices.DeleteFunc(defaultMACs, func(algo string) bool {
+			_, ok := macModes[algo]
+			return !ok
+		})
+		return
+	}
+
+	macModes[HMACSHA1] = &macMode{20, false, func(key []byte) hash.Hash {
+		return hmac.New(sha1.New, key)
+	}}
+	macModes[InsecureHMACSHA196] = &macMode{20, false, func(key []byte) hash.Hash {
+		return truncatingMAC{12, hmac.New(sha1.New, key)}
+	}}
+}
diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go
new file mode 100644
index 000000000..ab22c3d38
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/messages.go
@@ -0,0 +1,893 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"math/big"
+	"reflect"
+	"strconv"
+	"strings"
+)
+
+// These are SSH message type numbers. They are scattered around several
+// documents but many were taken from [SSH-PARAMETERS].
+const (
+	msgIgnore        = 2
+	msgUnimplemented = 3
+	msgDebug         = 4
+	msgNewKeys       = 21
+)
+
+// SSH messages:
+//
+// These structures mirror the wire format of the corresponding SSH messages.
+// They are marshaled using reflection with the marshal and unmarshal functions
+// in this file. The only wrinkle is that a final member of type []byte with a
+// ssh tag of "rest" receives the remainder of a packet when unmarshaling.
+
+// See RFC 4253, section 11.1.
+const msgDisconnect = 1
+
+// disconnectMsg is the message that signals a disconnect. It is also
+// the error type returned from mux.Wait()
+type disconnectMsg struct {
+	Reason   uint32 `sshtype:"1"`
+	Message  string
+	Language string
+}
+
+func (d *disconnectMsg) Error() string {
+	return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
+}
+
+// See RFC 4253, section 7.1.
+const msgKexInit = 20
+
+type kexInitMsg struct {
+	Cookie                  [16]byte `sshtype:"20"`
+	KexAlgos                []string
+	ServerHostKeyAlgos      []string
+	CiphersClientServer     []string
+	CiphersServerClient     []string
+	MACsClientServer        []string
+	MACsServerClient        []string
+	CompressionClientServer []string
+	CompressionServerClient []string
+	LanguagesClientServer   []string
+	LanguagesServerClient   []string
+	FirstKexFollows         bool
+	Reserved                uint32
+}
+
+// See RFC 4253, section 8.
+
+// Diffie-Hellman
+const msgKexDHInit = 30
+
+type kexDHInitMsg struct {
+	X *big.Int `sshtype:"30"`
+}
+
+const msgKexECDHInit = 30
+
+type kexECDHInitMsg struct {
+	ClientPubKey []byte `sshtype:"30"`
+}
+
+const msgKexECDHReply = 31
+
+type kexECDHReplyMsg struct {
+	HostKey         []byte `sshtype:"31"`
+	EphemeralPubKey []byte
+	Signature       []byte
+}
+
+const msgKexDHReply = 31
+
+type kexDHReplyMsg struct {
+	HostKey   []byte `sshtype:"31"`
+	Y         *big.Int
+	Signature []byte
+}
+
+// See RFC 4419, section 5.
+const msgKexDHGexGroup = 31
+
+type kexDHGexGroupMsg struct {
+	P *big.Int `sshtype:"31"`
+	G *big.Int
+}
+
+const msgKexDHGexInit = 32
+
+type kexDHGexInitMsg struct {
+	X *big.Int `sshtype:"32"`
+}
+
+const msgKexDHGexReply = 33
+
+type kexDHGexReplyMsg struct {
+	HostKey   []byte `sshtype:"33"`
+	Y         *big.Int
+	Signature []byte
+}
+
+const msgKexDHGexRequest = 34
+
+type kexDHGexRequestMsg struct {
+	MinBits       uint32 `sshtype:"34"`
+	PreferredBits uint32
+	MaxBits       uint32
+}
+
+// See RFC 4253, section 10.
+const msgServiceRequest = 5
+
+type serviceRequestMsg struct {
+	Service string `sshtype:"5"`
+}
+
+// See RFC 4253, section 10.
+const msgServiceAccept = 6
+
+type serviceAcceptMsg struct {
+	Service string `sshtype:"6"`
+}
+
+// See RFC 8308, section 2.3
+const msgExtInfo = 7
+
+type extInfoMsg struct {
+	NumExtensions uint32 `sshtype:"7"`
+	Payload       []byte `ssh:"rest"`
+}
+
+// See RFC 4252, section 5.
+const msgUserAuthRequest = 50
+
+type userAuthRequestMsg struct {
+	User    string `sshtype:"50"`
+	Service string
+	Method  string
+	Payload []byte `ssh:"rest"`
+}
+
+// Used for debug printouts of packets.
+type userAuthSuccessMsg struct {
+}
+
+// See RFC 4252, section 5.1
+const msgUserAuthFailure = 51
+
+type userAuthFailureMsg struct {
+	Methods        []string `sshtype:"51"`
+	PartialSuccess bool
+}
+
+// See RFC 4252, section 5.1
+const msgUserAuthSuccess = 52
+
+// See RFC 4252, section 5.4
+const msgUserAuthBanner = 53
+
+type userAuthBannerMsg struct {
+	Message string `sshtype:"53"`
+	// unused, but required to allow message parsing
+	Language string
+}
+
+// See RFC 4256, section 3.2
+const msgUserAuthInfoRequest = 60
+const msgUserAuthInfoResponse = 61
+
+type userAuthInfoRequestMsg struct {
+	Name        string `sshtype:"60"`
+	Instruction string
+	Language    string
+	NumPrompts  uint32
+	Prompts     []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 5.1.
+const msgChannelOpen = 90
+
+type channelOpenMsg struct {
+	ChanType         string `sshtype:"90"`
+	PeersID          uint32
+	PeersWindow      uint32
+	MaxPacketSize    uint32
+	TypeSpecificData []byte `ssh:"rest"`
+}
+
+const msgChannelExtendedData = 95
+const msgChannelData = 94
+
+// Used for debug print outs of packets.
+type channelDataMsg struct {
+	PeersID uint32 `sshtype:"94"`
+	Length  uint32
+	Rest    []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 5.1.
+const msgChannelOpenConfirm = 91
+
+type channelOpenConfirmMsg struct {
+	PeersID          uint32 `sshtype:"91"`
+	MyID             uint32
+	MyWindow         uint32
+	MaxPacketSize    uint32
+	TypeSpecificData []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 5.1.
+const msgChannelOpenFailure = 92
+
+type channelOpenFailureMsg struct {
+	PeersID  uint32 `sshtype:"92"`
+	Reason   RejectionReason
+	Message  string
+	Language string
+}
+
+const msgChannelRequest = 98
+
+type channelRequestMsg struct {
+	PeersID             uint32 `sshtype:"98"`
+	Request             string
+	WantReply           bool
+	RequestSpecificData []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 5.4.
+const msgChannelSuccess = 99
+
+type channelRequestSuccessMsg struct {
+	PeersID uint32 `sshtype:"99"`
+}
+
+// See RFC 4254, section 5.4.
+const msgChannelFailure = 100
+
+type channelRequestFailureMsg struct {
+	PeersID uint32 `sshtype:"100"`
+}
+
+// See RFC 4254, section 5.3
+const msgChannelClose = 97
+
+type channelCloseMsg struct {
+	PeersID uint32 `sshtype:"97"`
+}
+
+// See RFC 4254, section 5.3
+const msgChannelEOF = 96
+
+type channelEOFMsg struct {
+	PeersID uint32 `sshtype:"96"`
+}
+
+// See RFC 4254, section 4
+const msgGlobalRequest = 80
+
+type globalRequestMsg struct {
+	Type      string `sshtype:"80"`
+	WantReply bool
+	Data      []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 4
+const msgRequestSuccess = 81
+
+type globalRequestSuccessMsg struct {
+	Data []byte `ssh:"rest" sshtype:"81"`
+}
+
+// See RFC 4254, section 4
+const msgRequestFailure = 82
+
+type globalRequestFailureMsg struct {
+	Data []byte `ssh:"rest" sshtype:"82"`
+}
+
+// See RFC 4254, section 5.2
+const msgChannelWindowAdjust = 93
+
+type windowAdjustMsg struct {
+	PeersID         uint32 `sshtype:"93"`
+	AdditionalBytes uint32
+}
+
+// See RFC 4252, section 7
+const msgUserAuthPubKeyOk = 60
+
+type userAuthPubKeyOkMsg struct {
+	Algo   string `sshtype:"60"`
+	PubKey []byte
+}
+
+// See RFC 4462, section 3
+const msgUserAuthGSSAPIResponse = 60
+
+type userAuthGSSAPIResponse struct {
+	SupportMech []byte `sshtype:"60"`
+}
+
+const msgUserAuthGSSAPIToken = 61
+
+type userAuthGSSAPIToken struct {
+	Token []byte `sshtype:"61"`
+}
+
+const msgUserAuthGSSAPIMIC = 66
+
+type userAuthGSSAPIMIC struct {
+	MIC []byte `sshtype:"66"`
+}
+
+// See RFC 4462, section 3.9
+const msgUserAuthGSSAPIErrTok = 64
+
+type userAuthGSSAPIErrTok struct {
+	ErrorToken []byte `sshtype:"64"`
+}
+
+// See RFC 4462, section 3.8
+const msgUserAuthGSSAPIError = 65
+
+type userAuthGSSAPIError struct {
+	MajorStatus uint32 `sshtype:"65"`
+	MinorStatus uint32
+	Message     string
+	LanguageTag string
+}
+
+// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
+const msgPing = 192
+
+type pingMsg struct {
+	Data string `sshtype:"192"`
+}
+
+// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
+const msgPong = 193
+
+type pongMsg struct {
+	Data string `sshtype:"193"`
+}
+
+// typeTags returns the possible type bytes for the given reflect.Type, which
+// should be a struct. The possible values are separated by a '|' character.
+func typeTags(structType reflect.Type) (tags []byte) {
+	tagStr := structType.Field(0).Tag.Get("sshtype")
+
+	for _, tag := range strings.Split(tagStr, "|") {
+		i, err := strconv.Atoi(tag)
+		if err == nil {
+			tags = append(tags, byte(i))
+		}
+	}
+
+	return tags
+}
+
+func fieldError(t reflect.Type, field int, problem string) error {
+	if problem != "" {
+		problem = ": " + problem
+	}
+	return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem)
+}
+
+var errShortRead = errors.New("ssh: short read")
+
+// Unmarshal parses data in SSH wire format into a structure. The out
+// argument should be a pointer to struct. If the first member of the
+// struct has the "sshtype" tag set to a '|'-separated set of numbers
+// in decimal, the packet must start with one of those numbers. In
+// case of error, Unmarshal returns a ParseError or
+// UnexpectedMessageError.
+func Unmarshal(data []byte, out interface{}) error {
+	v := reflect.ValueOf(out).Elem()
+	structType := v.Type()
+	expectedTypes := typeTags(structType)
+
+	var expectedType byte
+	if len(expectedTypes) > 0 {
+		expectedType = expectedTypes[0]
+	}
+
+	if len(data) == 0 {
+		return parseError(expectedType)
+	}
+
+	if len(expectedTypes) > 0 {
+		goodType := false
+		for _, e := range expectedTypes {
+			if e > 0 && data[0] == e {
+				goodType = true
+				break
+			}
+		}
+		if !goodType {
+			return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes)
+		}
+		data = data[1:]
+	}
+
+	var ok bool
+	for i := 0; i < v.NumField(); i++ {
+		field := v.Field(i)
+		t := field.Type()
+		switch t.Kind() {
+		case reflect.Bool:
+			if len(data) < 1 {
+				return errShortRead
+			}
+			field.SetBool(data[0] != 0)
+			data = data[1:]
+		case reflect.Array:
+			if t.Elem().Kind() != reflect.Uint8 {
+				return fieldError(structType, i, "array of unsupported type")
+			}
+			if len(data) < t.Len() {
+				return errShortRead
+			}
+			for j, n := 0, t.Len(); j < n; j++ {
+				field.Index(j).Set(reflect.ValueOf(data[j]))
+			}
+			data = data[t.Len():]
+		case reflect.Uint64:
+			var u64 uint64
+			if u64, data, ok = parseUint64(data); !ok {
+				return errShortRead
+			}
+			field.SetUint(u64)
+		case reflect.Uint32:
+			var u32 uint32
+			if u32, data, ok = parseUint32(data); !ok {
+				return errShortRead
+			}
+			field.SetUint(uint64(u32))
+		case reflect.Uint8:
+			if len(data) < 1 {
+				return errShortRead
+			}
+			field.SetUint(uint64(data[0]))
+			data = data[1:]
+		case reflect.String:
+			var s []byte
+			if s, data, ok = parseString(data); !ok {
+				return fieldError(structType, i, "")
+			}
+			field.SetString(string(s))
+		case reflect.Slice:
+			switch t.Elem().Kind() {
+			case reflect.Uint8:
+				if structType.Field(i).Tag.Get("ssh") == "rest" {
+					field.Set(reflect.ValueOf(data))
+					data = nil
+				} else {
+					var s []byte
+					if s, data, ok = parseString(data); !ok {
+						return errShortRead
+					}
+					field.Set(reflect.ValueOf(s))
+				}
+			case reflect.String:
+				var nl []string
+				if nl, data, ok = parseNameList(data); !ok {
+					return errShortRead
+				}
+				field.Set(reflect.ValueOf(nl))
+			default:
+				return fieldError(structType, i, "slice of unsupported type")
+			}
+		case reflect.Ptr:
+			if t == bigIntType {
+				var n *big.Int
+				if n, data, ok = parseInt(data); !ok {
+					return errShortRead
+				}
+				field.Set(reflect.ValueOf(n))
+			} else {
+				return fieldError(structType, i, "pointer to unsupported type")
+			}
+		default:
+			return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t))
+		}
+	}
+
+	if len(data) != 0 {
+		return parseError(expectedType)
+	}
+
+	return nil
+}
+
+// Marshal serializes the message in msg to SSH wire format.  The msg
+// argument should be a struct or pointer to struct. If the first
+// member has the "sshtype" tag set to a number in decimal, that
+// number is prepended to the result. If the last of member has the
+// "ssh" tag set to "rest", its contents are appended to the output.
+func Marshal(msg interface{}) []byte {
+	out := make([]byte, 0, 64)
+	return marshalStruct(out, msg)
+}
+
+func marshalStruct(out []byte, msg interface{}) []byte {
+	v := reflect.Indirect(reflect.ValueOf(msg))
+	msgTypes := typeTags(v.Type())
+	if len(msgTypes) > 0 {
+		out = append(out, msgTypes[0])
+	}
+
+	for i, n := 0, v.NumField(); i < n; i++ {
+		field := v.Field(i)
+		switch t := field.Type(); t.Kind() {
+		case reflect.Bool:
+			var v uint8
+			if field.Bool() {
+				v = 1
+			}
+			out = append(out, v)
+		case reflect.Array:
+			if t.Elem().Kind() != reflect.Uint8 {
+				panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface()))
+			}
+			for j, l := 0, t.Len(); j < l; j++ {
+				out = append(out, uint8(field.Index(j).Uint()))
+			}
+		case reflect.Uint32:
+			out = appendU32(out, uint32(field.Uint()))
+		case reflect.Uint64:
+			out = appendU64(out, uint64(field.Uint()))
+		case reflect.Uint8:
+			out = append(out, uint8(field.Uint()))
+		case reflect.String:
+			s := field.String()
+			out = appendInt(out, len(s))
+			out = append(out, s...)
+		case reflect.Slice:
+			switch t.Elem().Kind() {
+			case reflect.Uint8:
+				if v.Type().Field(i).Tag.Get("ssh") != "rest" {
+					out = appendInt(out, field.Len())
+				}
+				out = append(out, field.Bytes()...)
+			case reflect.String:
+				offset := len(out)
+				out = appendU32(out, 0)
+				if n := field.Len(); n > 0 {
+					for j := 0; j < n; j++ {
+						f := field.Index(j)
+						if j != 0 {
+							out = append(out, ',')
+						}
+						out = append(out, f.String()...)
+					}
+					// overwrite length value
+					binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4))
+				}
+			default:
+				panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface()))
+			}
+		case reflect.Ptr:
+			if t == bigIntType {
+				var n *big.Int
+				nValue := reflect.ValueOf(&n)
+				nValue.Elem().Set(field)
+				needed := intLength(n)
+				oldLength := len(out)
+
+				if cap(out)-len(out) < needed {
+					newOut := make([]byte, len(out), 2*(len(out)+needed))
+					copy(newOut, out)
+					out = newOut
+				}
+				out = out[:oldLength+needed]
+				marshalInt(out[oldLength:], n)
+			} else {
+				panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface()))
+			}
+		}
+	}
+
+	return out
+}
+
+var bigOne = big.NewInt(1)
+
+func parseString(in []byte) (out, rest []byte, ok bool) {
+	if len(in) < 4 {
+		return
+	}
+	length := binary.BigEndian.Uint32(in)
+	in = in[4:]
+	if uint32(len(in)) < length {
+		return
+	}
+	out = in[:length]
+	rest = in[length:]
+	ok = true
+	return
+}
+
+var (
+	comma         = []byte{','}
+	emptyNameList = []string{}
+)
+
+func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
+	contents, rest, ok := parseString(in)
+	if !ok {
+		return
+	}
+	if len(contents) == 0 {
+		out = emptyNameList
+		return
+	}
+	parts := bytes.Split(contents, comma)
+	out = make([]string, len(parts))
+	for i, part := range parts {
+		out[i] = string(part)
+	}
+	return
+}
+
+func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
+	contents, rest, ok := parseString(in)
+	if !ok {
+		return
+	}
+	out = new(big.Int)
+
+	if len(contents) > 0 && contents[0]&0x80 == 0x80 {
+		// This is a negative number
+		notBytes := make([]byte, len(contents))
+		for i := range notBytes {
+			notBytes[i] = ^contents[i]
+		}
+		out.SetBytes(notBytes)
+		out.Add(out, bigOne)
+		out.Neg(out)
+	} else {
+		// Positive number
+		out.SetBytes(contents)
+	}
+	ok = true
+	return
+}
+
+func parseUint32(in []byte) (uint32, []byte, bool) {
+	if len(in) < 4 {
+		return 0, nil, false
+	}
+	return binary.BigEndian.Uint32(in), in[4:], true
+}
+
+func parseUint64(in []byte) (uint64, []byte, bool) {
+	if len(in) < 8 {
+		return 0, nil, false
+	}
+	return binary.BigEndian.Uint64(in), in[8:], true
+}
+
+func intLength(n *big.Int) int {
+	length := 4 /* length bytes */
+	if n.Sign() < 0 {
+		nMinus1 := new(big.Int).Neg(n)
+		nMinus1.Sub(nMinus1, bigOne)
+		bitLen := nMinus1.BitLen()
+		if bitLen%8 == 0 {
+			// The number will need 0xff padding
+			length++
+		}
+		length += (bitLen + 7) / 8
+	} else if n.Sign() == 0 {
+		// A zero is the zero length string
+	} else {
+		bitLen := n.BitLen()
+		if bitLen%8 == 0 {
+			// The number will need 0x00 padding
+			length++
+		}
+		length += (bitLen + 7) / 8
+	}
+
+	return length
+}
+
+func marshalUint32(to []byte, n uint32) []byte {
+	binary.BigEndian.PutUint32(to, n)
+	return to[4:]
+}
+
+func marshalUint64(to []byte, n uint64) []byte {
+	binary.BigEndian.PutUint64(to, n)
+	return to[8:]
+}
+
+func marshalInt(to []byte, n *big.Int) []byte {
+	lengthBytes := to
+	to = to[4:]
+	length := 0
+
+	if n.Sign() < 0 {
+		// A negative number has to be converted to two's-complement
+		// form. So we'll subtract 1 and invert. If the
+		// most-significant-bit isn't set then we'll need to pad the
+		// beginning with 0xff in order to keep the number negative.
+		nMinus1 := new(big.Int).Neg(n)
+		nMinus1.Sub(nMinus1, bigOne)
+		bytes := nMinus1.Bytes()
+		for i := range bytes {
+			bytes[i] ^= 0xff
+		}
+		if len(bytes) == 0 || bytes[0]&0x80 == 0 {
+			to[0] = 0xff
+			to = to[1:]
+			length++
+		}
+		nBytes := copy(to, bytes)
+		to = to[nBytes:]
+		length += nBytes
+	} else if n.Sign() == 0 {
+		// A zero is the zero length string
+	} else {
+		bytes := n.Bytes()
+		if len(bytes) > 0 && bytes[0]&0x80 != 0 {
+			// We'll have to pad this with a 0x00 in order to
+			// stop it looking like a negative number.
+			to[0] = 0
+			to = to[1:]
+			length++
+		}
+		nBytes := copy(to, bytes)
+		to = to[nBytes:]
+		length += nBytes
+	}
+
+	lengthBytes[0] = byte(length >> 24)
+	lengthBytes[1] = byte(length >> 16)
+	lengthBytes[2] = byte(length >> 8)
+	lengthBytes[3] = byte(length)
+	return to
+}
+
+func writeInt(w io.Writer, n *big.Int) {
+	length := intLength(n)
+	buf := make([]byte, length)
+	marshalInt(buf, n)
+	w.Write(buf)
+}
+
+func writeString(w io.Writer, s []byte) {
+	var lengthBytes [4]byte
+	lengthBytes[0] = byte(len(s) >> 24)
+	lengthBytes[1] = byte(len(s) >> 16)
+	lengthBytes[2] = byte(len(s) >> 8)
+	lengthBytes[3] = byte(len(s))
+	w.Write(lengthBytes[:])
+	w.Write(s)
+}
+
+func stringLength(n int) int {
+	return 4 + n
+}
+
+func marshalString(to []byte, s []byte) []byte {
+	to[0] = byte(len(s) >> 24)
+	to[1] = byte(len(s) >> 16)
+	to[2] = byte(len(s) >> 8)
+	to[3] = byte(len(s))
+	to = to[4:]
+	copy(to, s)
+	return to[len(s):]
+}
+
+var bigIntType = reflect.TypeFor[*big.Int]()
+
+// Decode a packet into its corresponding message.
+func decode(packet []byte) (interface{}, error) {
+	var msg interface{}
+	switch packet[0] {
+	case msgDisconnect:
+		msg = new(disconnectMsg)
+	case msgServiceRequest:
+		msg = new(serviceRequestMsg)
+	case msgServiceAccept:
+		msg = new(serviceAcceptMsg)
+	case msgExtInfo:
+		msg = new(extInfoMsg)
+	case msgKexInit:
+		msg = new(kexInitMsg)
+	case msgKexDHInit:
+		msg = new(kexDHInitMsg)
+	case msgKexDHReply:
+		msg = new(kexDHReplyMsg)
+	case msgUserAuthRequest:
+		msg = new(userAuthRequestMsg)
+	case msgUserAuthSuccess:
+		return new(userAuthSuccessMsg), nil
+	case msgUserAuthFailure:
+		msg = new(userAuthFailureMsg)
+	case msgUserAuthBanner:
+		msg = new(userAuthBannerMsg)
+	case msgUserAuthPubKeyOk:
+		msg = new(userAuthPubKeyOkMsg)
+	case msgGlobalRequest:
+		msg = new(globalRequestMsg)
+	case msgRequestSuccess:
+		msg = new(globalRequestSuccessMsg)
+	case msgRequestFailure:
+		msg = new(globalRequestFailureMsg)
+	case msgChannelOpen:
+		msg = new(channelOpenMsg)
+	case msgChannelData:
+		msg = new(channelDataMsg)
+	case msgChannelOpenConfirm:
+		msg = new(channelOpenConfirmMsg)
+	case msgChannelOpenFailure:
+		msg = new(channelOpenFailureMsg)
+	case msgChannelWindowAdjust:
+		msg = new(windowAdjustMsg)
+	case msgChannelEOF:
+		msg = new(channelEOFMsg)
+	case msgChannelClose:
+		msg = new(channelCloseMsg)
+	case msgChannelRequest:
+		msg = new(channelRequestMsg)
+	case msgChannelSuccess:
+		msg = new(channelRequestSuccessMsg)
+	case msgChannelFailure:
+		msg = new(channelRequestFailureMsg)
+	case msgUserAuthGSSAPIToken:
+		msg = new(userAuthGSSAPIToken)
+	case msgUserAuthGSSAPIMIC:
+		msg = new(userAuthGSSAPIMIC)
+	case msgUserAuthGSSAPIErrTok:
+		msg = new(userAuthGSSAPIErrTok)
+	case msgUserAuthGSSAPIError:
+		msg = new(userAuthGSSAPIError)
+	default:
+		return nil, unexpectedMessageError(0, packet[0])
+	}
+	if err := Unmarshal(packet, msg); err != nil {
+		return nil, err
+	}
+	return msg, nil
+}
+
+var packetTypeNames = map[byte]string{
+	msgDisconnect:          "disconnectMsg",
+	msgServiceRequest:      "serviceRequestMsg",
+	msgServiceAccept:       "serviceAcceptMsg",
+	msgExtInfo:             "extInfoMsg",
+	msgKexInit:             "kexInitMsg",
+	msgKexDHInit:           "kexDHInitMsg",
+	msgKexDHReply:          "kexDHReplyMsg",
+	msgUserAuthRequest:     "userAuthRequestMsg",
+	msgUserAuthSuccess:     "userAuthSuccessMsg",
+	msgUserAuthFailure:     "userAuthFailureMsg",
+	msgUserAuthPubKeyOk:    "userAuthPubKeyOkMsg",
+	msgGlobalRequest:       "globalRequestMsg",
+	msgRequestSuccess:      "globalRequestSuccessMsg",
+	msgRequestFailure:      "globalRequestFailureMsg",
+	msgChannelOpen:         "channelOpenMsg",
+	msgChannelData:         "channelDataMsg",
+	msgChannelOpenConfirm:  "channelOpenConfirmMsg",
+	msgChannelOpenFailure:  "channelOpenFailureMsg",
+	msgChannelWindowAdjust: "windowAdjustMsg",
+	msgChannelEOF:          "channelEOFMsg",
+	msgChannelClose:        "channelCloseMsg",
+	msgChannelRequest:      "channelRequestMsg",
+	msgChannelSuccess:      "channelRequestSuccessMsg",
+	msgChannelFailure:      "channelRequestFailureMsg",
+}
diff --git a/vendor/golang.org/x/crypto/ssh/mlkem.go b/vendor/golang.org/x/crypto/ssh/mlkem.go
new file mode 100644
index 000000000..ddc0ed1fc
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/mlkem.go
@@ -0,0 +1,168 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"crypto"
+	"crypto/mlkem"
+	"crypto/sha256"
+	"errors"
+	"fmt"
+	"io"
+
+	"golang.org/x/crypto/curve25519"
+)
+
+// mlkem768WithCurve25519sha256 implements the hybrid ML-KEM768 with
+// curve25519-sha256 key exchange method, as described by
+// draft-kampanakis-curdle-ssh-pq-ke-05 section 2.3.3.
+type mlkem768WithCurve25519sha256 struct{}
+
+func (kex *mlkem768WithCurve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
+	var c25519kp curve25519KeyPair
+	if err := c25519kp.generate(rand); err != nil {
+		return nil, err
+	}
+
+	seed := make([]byte, mlkem.SeedSize)
+	if _, err := io.ReadFull(rand, seed); err != nil {
+		return nil, err
+	}
+
+	mlkemDk, err := mlkem.NewDecapsulationKey768(seed)
+	if err != nil {
+		return nil, err
+	}
+
+	hybridKey := append(mlkemDk.EncapsulationKey().Bytes(), c25519kp.pub[:]...)
+	if err := c.writePacket(Marshal(&kexECDHInitMsg{hybridKey})); err != nil {
+		return nil, err
+	}
+
+	packet, err := c.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	var reply kexECDHReplyMsg
+	if err = Unmarshal(packet, &reply); err != nil {
+		return nil, err
+	}
+
+	if len(reply.EphemeralPubKey) != mlkem.CiphertextSize768+32 {
+		return nil, errors.New("ssh: peer's mlkem768x25519 public value has wrong length")
+	}
+
+	// Perform KEM decapsulate operation to obtain shared key from ML-KEM.
+	mlkem768Secret, err := mlkemDk.Decapsulate(reply.EphemeralPubKey[:mlkem.CiphertextSize768])
+	if err != nil {
+		return nil, err
+	}
+
+	// Complete Curve25519 ECDH to obtain its shared key.
+	c25519Secret, err := curve25519.X25519(c25519kp.priv[:], reply.EphemeralPubKey[mlkem.CiphertextSize768:])
+	if err != nil {
+		return nil, fmt.Errorf("ssh: peer's mlkem768x25519 public value is not valid: %w", err)
+	}
+	// Compute actual shared key.
+	h := sha256.New()
+	h.Write(mlkem768Secret)
+	h.Write(c25519Secret)
+	secret := h.Sum(nil)
+
+	h.Reset()
+	magics.write(h)
+	writeString(h, reply.HostKey)
+	writeString(h, hybridKey)
+	writeString(h, reply.EphemeralPubKey)
+
+	K := make([]byte, stringLength(len(secret)))
+	marshalString(K, secret)
+	h.Write(K)
+
+	return &kexResult{
+		H:         h.Sum(nil),
+		K:         K,
+		HostKey:   reply.HostKey,
+		Signature: reply.Signature,
+		Hash:      crypto.SHA256,
+	}, nil
+}
+
+func (kex *mlkem768WithCurve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (*kexResult, error) {
+	packet, err := c.readPacket()
+	if err != nil {
+		return nil, err
+	}
+
+	var kexInit kexECDHInitMsg
+	if err = Unmarshal(packet, &kexInit); err != nil {
+		return nil, err
+	}
+
+	if len(kexInit.ClientPubKey) != mlkem.EncapsulationKeySize768+32 {
+		return nil, errors.New("ssh: peer's ML-KEM768/curve25519 public value has wrong length")
+	}
+
+	encapsulationKey, err := mlkem.NewEncapsulationKey768(kexInit.ClientPubKey[:mlkem.EncapsulationKeySize768])
+	if err != nil {
+		return nil, fmt.Errorf("ssh: peer's ML-KEM768 encapsulation key is not valid: %w", err)
+	}
+	// Perform KEM encapsulate operation to obtain ciphertext and shared key.
+	mlkem768Secret, mlkem768Ciphertext := encapsulationKey.Encapsulate()
+
+	// Perform server side of Curve25519 ECDH to obtain server public value and
+	// shared key.
+	var c25519kp curve25519KeyPair
+	if err := c25519kp.generate(rand); err != nil {
+		return nil, err
+	}
+	c25519Secret, err := curve25519.X25519(c25519kp.priv[:], kexInit.ClientPubKey[mlkem.EncapsulationKeySize768:])
+	if err != nil {
+		return nil, fmt.Errorf("ssh: peer's ML-KEM768/curve25519 public value is not valid: %w", err)
+	}
+	hybridKey := append(mlkem768Ciphertext, c25519kp.pub[:]...)
+
+	// Compute actual shared key.
+	h := sha256.New()
+	h.Write(mlkem768Secret)
+	h.Write(c25519Secret)
+	secret := h.Sum(nil)
+
+	hostKeyBytes := priv.PublicKey().Marshal()
+
+	h.Reset()
+	magics.write(h)
+	writeString(h, hostKeyBytes)
+	writeString(h, kexInit.ClientPubKey)
+	writeString(h, hybridKey)
+
+	K := make([]byte, stringLength(len(secret)))
+	marshalString(K, secret)
+	h.Write(K)
+
+	H := h.Sum(nil)
+
+	sig, err := signAndMarshal(priv, rand, H, algo)
+	if err != nil {
+		return nil, err
+	}
+
+	reply := kexECDHReplyMsg{
+		EphemeralPubKey: hybridKey,
+		HostKey:         hostKeyBytes,
+		Signature:       sig,
+	}
+	if err := c.writePacket(Marshal(&reply)); err != nil {
+		return nil, err
+	}
+	return &kexResult{
+		H:         H,
+		K:         K,
+		HostKey:   hostKeyBytes,
+		Signature: sig,
+		Hash:      crypto.SHA256,
+	}, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go
new file mode 100644
index 000000000..3bc4afbd0
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/mux.go
@@ -0,0 +1,385 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+	"log"
+	"sync"
+	"sync/atomic"
+)
+
+// debugMux, if set, causes messages in the connection protocol to be
+// logged.
+const debugMux = false
+
+// chanList is a thread safe channel list.
+type chanList struct {
+	// protects concurrent access to chans
+	sync.Mutex
+
+	// chans are indexed by the local id of the channel, which the
+	// other side should send in the PeersId field.
+	chans []*channel
+
+	// This is a debugging aid: it offsets all IDs by this
+	// amount. This helps distinguish otherwise identical
+	// server/client muxes
+	offset uint32
+}
+
+// Assigns a channel ID to the given channel.
+func (c *chanList) add(ch *channel) uint32 {
+	c.Lock()
+	defer c.Unlock()
+	for i := range c.chans {
+		if c.chans[i] == nil {
+			c.chans[i] = ch
+			return uint32(i) + c.offset
+		}
+	}
+	c.chans = append(c.chans, ch)
+	return uint32(len(c.chans)-1) + c.offset
+}
+
+// getChan returns the channel for the given ID.
+func (c *chanList) getChan(id uint32) *channel {
+	id -= c.offset
+
+	c.Lock()
+	defer c.Unlock()
+	if id < uint32(len(c.chans)) {
+		return c.chans[id]
+	}
+	return nil
+}
+
+func (c *chanList) remove(id uint32) {
+	id -= c.offset
+	c.Lock()
+	if id < uint32(len(c.chans)) {
+		c.chans[id] = nil
+	}
+	c.Unlock()
+}
+
+// dropAll forgets all channels it knows, returning them in a slice.
+func (c *chanList) dropAll() []*channel {
+	c.Lock()
+	defer c.Unlock()
+	var r []*channel
+
+	for _, ch := range c.chans {
+		if ch == nil {
+			continue
+		}
+		r = append(r, ch)
+	}
+	c.chans = nil
+	return r
+}
+
+// mux represents the state for the SSH connection protocol, which
+// multiplexes many channels onto a single packet transport.
+type mux struct {
+	conn     packetConn
+	chanList chanList
+
+	incomingChannels chan NewChannel
+
+	globalSentMu      sync.Mutex
+	globalSentPending atomic.Bool
+	globalResponses   chan interface{}
+	incomingRequests  chan *Request
+
+	errCond *sync.Cond
+	err     error
+}
+
+// When debugging, each new chanList instantiation has a different
+// offset.
+var globalOff uint32
+
+func (m *mux) Wait() error {
+	m.errCond.L.Lock()
+	defer m.errCond.L.Unlock()
+	for m.err == nil {
+		m.errCond.Wait()
+	}
+	return m.err
+}
+
+// newMux returns a mux that runs over the given connection.
+func newMux(p packetConn) *mux {
+	m := &mux{
+		conn:             p,
+		incomingChannels: make(chan NewChannel, chanSize),
+		globalResponses:  make(chan interface{}, 1),
+		incomingRequests: make(chan *Request, chanSize),
+		errCond:          newCond(),
+	}
+	if debugMux {
+		m.chanList.offset = atomic.AddUint32(&globalOff, 1)
+	}
+
+	go m.loop()
+	return m
+}
+
+func (m *mux) sendMessage(msg interface{}) error {
+	p := Marshal(msg)
+	if debugMux {
+		log.Printf("send global(%d): %#v", m.chanList.offset, msg)
+	}
+	return m.conn.writePacket(p)
+}
+
+func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) {
+	if wantReply {
+		m.globalSentMu.Lock()
+		defer m.globalSentMu.Unlock()
+
+		// Open the gate so that responses arriving while this request is in
+		// flight are allowed to reach globalResponses. Any response arriving
+		// while no request is pending is dropped by handleGlobalPacket.
+		m.globalSentPending.Store(true)
+		defer m.globalSentPending.Store(false)
+
+		// Drain any spurious responses that may have been buffered. This prevents
+		// a previously buffered unexpected response from being consumed instead
+		// of the actual response for this request.
+	drain:
+		for {
+			select {
+			case <-m.globalResponses:
+			default:
+				break drain
+			}
+		}
+	}
+
+	if err := m.sendMessage(globalRequestMsg{
+		Type:      name,
+		WantReply: wantReply,
+		Data:      payload,
+	}); err != nil {
+		return false, nil, err
+	}
+
+	if !wantReply {
+		return false, nil, nil
+	}
+
+	msg, ok := <-m.globalResponses
+	if !ok {
+		return false, nil, io.EOF
+	}
+	switch msg := msg.(type) {
+	case *globalRequestFailureMsg:
+		return false, msg.Data, nil
+	case *globalRequestSuccessMsg:
+		return true, msg.Data, nil
+	default:
+		return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg)
+	}
+}
+
+// ackRequest must be called after processing a global request that
+// has WantReply set.
+func (m *mux) ackRequest(ok bool, data []byte) error {
+	if ok {
+		return m.sendMessage(globalRequestSuccessMsg{Data: data})
+	}
+	return m.sendMessage(globalRequestFailureMsg{Data: data})
+}
+
+func (m *mux) Close() error {
+	return m.conn.Close()
+}
+
+// loop runs the connection machine. It will process packets until an
+// error is encountered. To synchronize on loop exit, use mux.Wait.
+func (m *mux) loop() {
+	var err error
+	for err == nil {
+		err = m.onePacket()
+	}
+
+	for _, ch := range m.chanList.dropAll() {
+		ch.close()
+	}
+
+	close(m.incomingChannels)
+	close(m.incomingRequests)
+	close(m.globalResponses)
+
+	m.conn.Close()
+
+	m.errCond.L.Lock()
+	m.err = err
+	m.errCond.Broadcast()
+	m.errCond.L.Unlock()
+
+	if debugMux {
+		log.Println("loop exit", err)
+	}
+}
+
+// onePacket reads and processes one packet.
+func (m *mux) onePacket() error {
+	packet, err := m.conn.readPacket()
+	if err != nil {
+		return err
+	}
+
+	if debugMux {
+		if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData {
+			log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet))
+		} else {
+			p, _ := decode(packet)
+			log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet))
+		}
+	}
+
+	switch packet[0] {
+	case msgChannelOpen:
+		return m.handleChannelOpen(packet)
+	case msgGlobalRequest, msgRequestSuccess, msgRequestFailure:
+		return m.handleGlobalPacket(packet)
+	case msgPing:
+		var msg pingMsg
+		if err := Unmarshal(packet, &msg); err != nil {
+			return fmt.Errorf("failed to unmarshal ping@openssh.com message: %w", err)
+		}
+		return m.sendMessage(pongMsg(msg))
+	}
+
+	// assume a channel packet.
+	if len(packet) < 5 {
+		return parseError(packet[0])
+	}
+	id := binary.BigEndian.Uint32(packet[1:])
+	ch := m.chanList.getChan(id)
+	if ch == nil {
+		return m.handleUnknownChannelPacket(id, packet)
+	}
+
+	return ch.handlePacket(packet)
+}
+
+func (m *mux) handleGlobalPacket(packet []byte) error {
+	msg, err := decode(packet)
+	if err != nil {
+		return err
+	}
+
+	switch msg := msg.(type) {
+	case *globalRequestMsg:
+		m.incomingRequests <- &Request{
+			Type:      msg.Type,
+			WantReply: msg.WantReply,
+			Payload:   msg.Data,
+			mux:       m,
+		}
+	case *globalRequestSuccessMsg, *globalRequestFailureMsg:
+		// Drop responses that arrive when no SendRequest is waiting, to
+		// prevent a malicious peer from staging responses for a future
+		// caller.
+		if !m.globalSentPending.Load() {
+			return nil
+		}
+		select {
+		case m.globalResponses <- msg:
+		default:
+		}
+	default:
+		panic(fmt.Sprintf("not a global message %#v", msg))
+	}
+
+	return nil
+}
+
+// handleChannelOpen schedules a channel to be Accept()ed.
+func (m *mux) handleChannelOpen(packet []byte) error {
+	var msg channelOpenMsg
+	if err := Unmarshal(packet, &msg); err != nil {
+		return err
+	}
+
+	if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
+		failMsg := channelOpenFailureMsg{
+			PeersID:  msg.PeersID,
+			Reason:   ConnectionFailed,
+			Message:  "invalid request",
+			Language: "en_US.UTF-8",
+		}
+		return m.sendMessage(failMsg)
+	}
+
+	c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData)
+	c.remoteId = msg.PeersID
+	c.maxRemotePayload = msg.MaxPacketSize
+	c.remoteWin.add(msg.PeersWindow)
+	m.incomingChannels <- c
+	return nil
+}
+
+func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) {
+	ch, err := m.openChannel(chanType, extra)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return ch, ch.incomingRequests, nil
+}
+
+func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
+	ch := m.newChannel(chanType, channelOutbound, extra)
+
+	ch.maxIncomingPayload = channelMaxPacket
+
+	open := channelOpenMsg{
+		ChanType:         chanType,
+		PeersWindow:      ch.myWindow,
+		MaxPacketSize:    ch.maxIncomingPayload,
+		TypeSpecificData: extra,
+		PeersID:          ch.localId,
+	}
+	if err := m.sendMessage(open); err != nil {
+		return nil, err
+	}
+
+	switch msg := (<-ch.msg).(type) {
+	case *channelOpenConfirmMsg:
+		return ch, nil
+	case *channelOpenFailureMsg:
+		return nil, &OpenChannelError{msg.Reason, msg.Message}
+	default:
+		return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg)
+	}
+}
+
+func (m *mux) handleUnknownChannelPacket(id uint32, packet []byte) error {
+	msg, err := decode(packet)
+	if err != nil {
+		return err
+	}
+
+	switch msg := msg.(type) {
+	// RFC 4254 section 5.4 says unrecognized channel requests should
+	// receive a failure response.
+	case *channelRequestMsg:
+		if msg.WantReply {
+			return m.sendMessage(channelRequestFailureMsg{
+				PeersID: msg.PeersID,
+			})
+		}
+		return nil
+	default:
+		return fmt.Errorf("ssh: invalid channel %d", id)
+	}
+}
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go
new file mode 100644
index 000000000..0192a6750
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/server.go
@@ -0,0 +1,1056 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"slices"
+	"strings"
+)
+
+// The Permissions type holds fine-grained permissions that are
+// specific to a user or a specific authentication method for a user.
+// The Permissions value for a successful authentication attempt is
+// available in ServerConn, so it can be used to pass information from
+// the user-authentication phase to the application layer.
+type Permissions struct {
+	// CriticalOptions indicate restrictions to the default
+	// permissions, and are typically used in conjunction with
+	// user certificates. The standard for SSH certificates
+	// defines "force-command" (only allow the given command to
+	// execute) and "source-address" (only allow connections from
+	// the given address). The SSH package currently only enforces
+	// the "source-address" critical option. It is up to server
+	// implementations to enforce other critical options, such as
+	// "force-command", by checking them after the SSH handshake
+	// is successful. In general, SSH servers should reject
+	// connections that specify critical options that are unknown
+	// or not supported.
+	CriticalOptions map[string]string
+
+	// Extensions are extra functionality that the server may offer on
+	// authenticated connections. Lack of support for an extension does not
+	// preclude authenticating a user. Common extensions are
+	// "permit-agent-forwarding", "permit-X11-forwarding". In general the Go
+	// SSH library does not act on extensions and it is up to server
+	// implementations to honor them; extensions can also be used to pass data
+	// from the authentication callbacks to the server application layer.
+	//
+	// The one extension acted upon by this library is "no-touch-required",
+	// which applies only to security-key public keys
+	// (sk-ecdsa-sha2-nistp256@openssh.com and sk-ssh-ed25519@openssh.com).
+	// When present, it waives the default requirement that SK signatures
+	// assert user presence (i.e. a physical touch of the authenticator)
+	// during signature verification.
+	Extensions map[string]string
+
+	// ExtraData allows to store user defined data.
+	ExtraData map[any]any
+}
+
+type GSSAPIWithMICConfig struct {
+	// AllowLogin, must be set, is called when gssapi-with-mic
+	// authentication is selected (RFC 4462 section 3). The srcName is from the
+	// results of the GSS-API authentication. The format is username@DOMAIN.
+	// GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions.
+	// This callback is called after the user identity is established with GSSAPI to decide if the user can login with
+	// which permissions. If the user is allowed to login, it should return a nil error.
+	AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
+
+	// Server must be set. It's the implementation
+	// of the GSSAPIServer interface. See GSSAPIServer interface for details.
+	Server GSSAPIServer
+}
+
+// SendAuthBanner implements [ServerPreAuthConn].
+func (s *connection) SendAuthBanner(msg string) error {
+	return s.transport.writePacket(Marshal(&userAuthBannerMsg{
+		Message: msg,
+	}))
+}
+
+func (*connection) unexportedMethodForFutureProofing() {}
+
+// ServerPreAuthConn is the interface available on an incoming server
+// connection before authentication has completed.
+type ServerPreAuthConn interface {
+	unexportedMethodForFutureProofing() // permits growing ServerPreAuthConn safely later, ala testing.TB
+
+	ConnMetadata
+
+	// SendAuthBanner sends a banner message to the client.
+	// It returns an error once the authentication phase has ended.
+	SendAuthBanner(string) error
+}
+
+// noTouchRequiredExtension is the extension name used by OpenSSH in
+// authorized_keys options and certificate extensions to mark keys
+// whose signatures do not need to assert user presence (touch). See
+// ssh-keygen(1) and sshd(8).
+const noTouchRequiredExtension = "no-touch-required"
+
+// noTouchAllowed reports whether the user presence requirement on
+// SK signatures should be waived for this authentication attempt. The
+// requirement is waived when the "no-touch-required" extension is
+// present either in the Permissions returned by the auth callback
+// (authorized_keys-level opt-out) or in the certificate's own
+// Extensions (CA-level opt-out), matching OpenSSH behavior. OpenSSH
+// reads the per-key opt-out only from cert Extensions and
+// authorized_keys options (never from CriticalOptions); we follow the
+// same rule.
+func noTouchAllowed(pubKey PublicKey, perms *Permissions) bool {
+	if perms != nil {
+		if _, ok := perms.Extensions[noTouchRequiredExtension]; ok {
+			return true
+		}
+	}
+	if cert, ok := pubKey.(*Certificate); ok {
+		if _, ok := cert.Extensions[noTouchRequiredExtension]; ok {
+			return true
+		}
+	}
+	return false
+}
+
+// skKeyWithoutUP returns a PublicKey equivalent to pubKey but whose
+// Verify accepts SK signatures with the user-presence flag clear. If
+// pubKey is not (and does not wrap) an SK key, pubKey is returned
+// unchanged. The returned value never mutates pubKey: for SK keys a
+// shallow copy is made so that the noTouchRequired flag is set only on
+// the clone.
+//
+// The implementation is iterative rather than recursive. When pubKey
+// is a *Certificate we unwrap exactly one level to look at the inner
+// key. The SSH cert format forbids Certificate.Key from being another
+// Certificate (parseCert rejects it), but nothing stops callers from
+// constructing such a value directly in Go; a recursive descent could
+// otherwise be driven to unbounded depth by a hand-crafted or cyclic
+// Certificate. A malformed input of that shape simply returns
+// unchanged here.
+func skKeyWithoutUP(pubKey PublicKey) PublicKey {
+	cert, isCert := pubKey.(*Certificate)
+	target := pubKey
+	if isCert {
+		target = cert.Key
+	}
+	var cloned PublicKey
+	switch k := target.(type) {
+	case *skECDSAPublicKey:
+		c := *k
+		c.noTouchRequired = true
+		cloned = &c
+	case *skEd25519PublicKey:
+		c := *k
+		c.noTouchRequired = true
+		cloned = &c
+	default:
+		// Not an SK key (or a pathological *Certificate wrapping
+		// another *Certificate): pubKey is already usable for Verify.
+		return pubKey
+	}
+	if !isCert {
+		return cloned
+	}
+	c := *cert
+	c.Key = cloned
+	return &c
+}
+
+// ServerConfig holds server specific configuration data.
+type ServerConfig struct {
+	// Config contains configuration shared between client and server.
+	Config
+
+	// PublicKeyAuthAlgorithms specifies the supported client public key
+	// authentication algorithms. Note that this should not include certificate
+	// types since those use the underlying algorithm. This list is sent to the
+	// client if it supports the server-sig-algs extension. Order is irrelevant.
+	// If unspecified then a default set of algorithms is used.
+	PublicKeyAuthAlgorithms []string
+
+	hostKeys []Signer
+
+	// NoClientAuth is true if clients are allowed to connect without
+	// authenticating.
+	// To determine NoClientAuth at runtime, set NoClientAuth to true
+	// and the optional NoClientAuthCallback to a non-nil value.
+	NoClientAuth bool
+
+	// NoClientAuthCallback, if non-nil, is called when a user
+	// attempts to authenticate with auth method "none".
+	// NoClientAuth must also be set to true for this be used, or
+	// this func is unused.
+	NoClientAuthCallback func(ConnMetadata) (*Permissions, error)
+
+	// MaxAuthTries specifies the maximum number of authentication attempts
+	// permitted per connection. If set to a negative number, the number of
+	// attempts are unlimited. If set to zero, the number of attempts are limited
+	// to 6.
+	MaxAuthTries int
+
+	// PasswordCallback, if non-nil, is called when a user
+	// attempts to authenticate using a password.
+	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
+
+	// PublicKeyCallback, if non-nil, is called when a client
+	// offers a public key for authentication. It must return a nil error
+	// if the given public key can be used to authenticate the
+	// given user. For example, see CertChecker.Authenticate. A
+	// call to this function does not guarantee that the key
+	// offered is in fact used to authenticate. To record any data
+	// depending on the public key, store it inside a
+	// Permissions.Extensions entry.
+	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
+
+	// VerifiedPublicKeyCallback, if non-nil, is called after a client
+	// successfully confirms having control over a key that was previously
+	// approved by PublicKeyCallback. The permissions object passed to the
+	// callback is the one returned by PublicKeyCallback for the given public
+	// key and its ownership is transferred to the callback. The returned
+	// Permissions object can be the same object, optionally modified, or a
+	// completely new object. If VerifiedPublicKeyCallback is non-nil,
+	// PublicKeyCallback is not allowed to return a PartialSuccessError, which
+	// can instead be returned by VerifiedPublicKeyCallback.
+	//
+	// VerifiedPublicKeyCallback does not affect which authentication methods
+	// are included in the list of methods that can be attempted by the client.
+	VerifiedPublicKeyCallback func(conn ConnMetadata, key PublicKey, permissions *Permissions,
+		signatureAlgorithm string) (*Permissions, error)
+
+	// KeyboardInteractiveCallback, if non-nil, is called when
+	// keyboard-interactive authentication is selected (RFC
+	// 4256). The client object's Challenge function should be
+	// used to query the user. The callback may offer multiple
+	// Challenge rounds. To avoid information leaks, the client
+	// should be presented a challenge even if the user is
+	// unknown.
+	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
+
+	// AuthLogCallback, if non-nil, is called to log all authentication
+	// attempts.
+	AuthLogCallback func(conn ConnMetadata, method string, err error)
+
+	// PreAuthConnCallback, if non-nil, is called upon receiving a new connection
+	// before any authentication has started. The provided ServerPreAuthConn
+	// can be used at any time before authentication is complete, including
+	// after this callback has returned.
+	PreAuthConnCallback func(ServerPreAuthConn)
+
+	// ServerVersion is the version identification string to announce in
+	// the public handshake.
+	// If empty, a reasonable default is used.
+	// Note that RFC 4253 section 4.2 requires that this string start with
+	// "SSH-2.0-".
+	ServerVersion string
+
+	// BannerCallback, if present, is called and the return string is sent to
+	// the client after key exchange completed but before authentication.
+	BannerCallback func(conn ConnMetadata) string
+
+	// GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
+	// when gssapi-with-mic authentication is selected (RFC 4462 section 3).
+	GSSAPIWithMICConfig *GSSAPIWithMICConfig
+}
+
+// AddHostKey adds a private key as a host key. If an existing host
+// key exists with the same public key format, it is replaced. Each server
+// config must have at least one host key.
+func (s *ServerConfig) AddHostKey(key Signer) {
+	for i, k := range s.hostKeys {
+		if k.PublicKey().Type() == key.PublicKey().Type() {
+			s.hostKeys[i] = key
+			return
+		}
+	}
+
+	s.hostKeys = append(s.hostKeys, key)
+}
+
+// cachedPubKey contains the results of querying whether a public key is
+// acceptable for a user. This is a FIFO cache.
+type cachedPubKey struct {
+	user       string
+	pubKeyData []byte
+	result     error
+	perms      *Permissions
+}
+
+// maxCachedPubKeys is the number of cache entries we store.
+//
+// Due to consistent misuse of the PublicKeyCallback API, we have reduced this
+// to 1, such that the only key in the cache is the most recently seen one. This
+// forces the behavior that the last call to PublicKeyCallback will always be
+// with the key that is used for authentication.
+const maxCachedPubKeys = 1
+
+// pubKeyCache caches tests for public keys.  Since SSH clients
+// will query whether a public key is acceptable before attempting to
+// authenticate with it, we end up with duplicate queries for public
+// key validity.  The cache only applies to a single ServerConn.
+type pubKeyCache struct {
+	keys []cachedPubKey
+}
+
+// get returns the result for a given user/algo/key tuple.
+func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
+	for _, k := range c.keys {
+		if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
+			return k, true
+		}
+	}
+	return cachedPubKey{}, false
+}
+
+// add adds the given tuple to the cache.
+func (c *pubKeyCache) add(candidate cachedPubKey) {
+	if len(c.keys) >= maxCachedPubKeys {
+		c.keys = c.keys[1:]
+	}
+	c.keys = append(c.keys, candidate)
+}
+
+// ServerConn is an authenticated SSH connection, as seen from the
+// server
+type ServerConn struct {
+	Conn
+
+	// If the succeeding authentication callback returned a non-nil Permissions
+	// pointer, it is stored here. These are the permissions from the final,
+	// successful authentication method. Permissions returned by callbacks that
+	// return PartialSuccessError are not preserved and must be nil.
+	Permissions *Permissions
+}
+
+// NewServerConn starts a new SSH server with c as the underlying
+// transport.  It starts with a handshake and, if the handshake is
+// unsuccessful, it closes the connection and returns an error.  The
+// Request and NewChannel channels must be serviced, or the connection
+// will hang.
+//
+// The returned error may be of type *ServerAuthError for
+// authentication errors.
+func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
+	fullConf := *config
+	fullConf.SetDefaults()
+	if fullConf.MaxAuthTries == 0 {
+		fullConf.MaxAuthTries = 6
+	}
+	if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
+		fullConf.PublicKeyAuthAlgorithms = defaultPubKeyAuthAlgos
+	} else {
+		for _, algo := range fullConf.PublicKeyAuthAlgorithms {
+			if !slices.Contains(SupportedAlgorithms().PublicKeyAuths, algo) && !slices.Contains(InsecureAlgorithms().PublicKeyAuths, algo) {
+				c.Close()
+				return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
+			}
+		}
+	}
+
+	s := &connection{
+		sshConn: sshConn{conn: c},
+	}
+	perms, err := s.serverHandshake(&fullConf)
+	if err != nil {
+		c.Close()
+		return nil, nil, nil, err
+	}
+	return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
+}
+
+// signAndMarshal signs the data with the appropriate algorithm,
+// and serializes the result in SSH wire format. algo is the negotiate
+// algorithm and may be a certificate type.
+func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) {
+	sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
+	if err != nil {
+		return nil, err
+	}
+
+	return Marshal(sig), nil
+}
+
+// handshake performs key exchange and user authentication.
+func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
+	if len(config.hostKeys) == 0 {
+		return nil, errors.New("ssh: server has no host keys")
+	}
+
+	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
+		config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
+		config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
+		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
+	}
+
+	if config.ServerVersion != "" {
+		s.serverVersion = []byte(config.ServerVersion)
+	} else {
+		s.serverVersion = []byte(packageVersion)
+	}
+	var err error
+	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
+	if err != nil {
+		return nil, err
+	}
+
+	tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
+	s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
+
+	if err := s.transport.waitSession(); err != nil {
+		return nil, err
+	}
+
+	// We just did the key change, so the session ID is established.
+	s.sessionID = s.transport.getSessionID()
+	s.algorithms = s.transport.getAlgorithms()
+
+	var packet []byte
+	if packet, err = s.transport.readPacket(); err != nil {
+		return nil, err
+	}
+
+	var serviceRequest serviceRequestMsg
+	if err = Unmarshal(packet, &serviceRequest); err != nil {
+		return nil, err
+	}
+	if serviceRequest.Service != serviceUserAuth {
+		return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
+	}
+	serviceAccept := serviceAcceptMsg{
+		Service: serviceUserAuth,
+	}
+	if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
+		return nil, err
+	}
+
+	perms, err := s.serverAuthenticate(config)
+	if err != nil {
+		return nil, err
+	}
+	s.mux = newMux(s.transport)
+	return perms, err
+}
+
+func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
+	if addr == nil {
+		return errors.New("ssh: no address known for client, but source-address match required")
+	}
+
+	tcpAddr, ok := addr.(*net.TCPAddr)
+	if !ok {
+		return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
+	}
+
+	for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
+		if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
+			if allowedIP.Equal(tcpAddr.IP) {
+				return nil
+			}
+		} else {
+			_, ipNet, err := net.ParseCIDR(sourceAddr)
+			if err != nil {
+				return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
+			}
+
+			if ipNet.Contains(tcpAddr.IP) {
+				return nil
+			}
+		}
+	}
+
+	return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
+}
+
+func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
+	sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
+	gssAPIServer := gssapiConfig.Server
+	defer gssAPIServer.DeleteSecContext()
+	var srcName string
+	for {
+		var (
+			outToken     []byte
+			needContinue bool
+		)
+		outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token)
+		if err != nil {
+			return err, nil, nil
+		}
+		if len(outToken) != 0 {
+			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
+				Token: outToken,
+			})); err != nil {
+				return nil, nil, err
+			}
+		}
+		if !needContinue {
+			break
+		}
+		packet, err := s.transport.readPacket()
+		if err != nil {
+			return nil, nil, err
+		}
+		userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
+		if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
+			return nil, nil, err
+		}
+		token = userAuthGSSAPITokenReq.Token
+	}
+	packet, err := s.transport.readPacket()
+	if err != nil {
+		return nil, nil, err
+	}
+	userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
+	if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
+		return nil, nil, err
+	}
+	mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
+	if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
+		return err, nil, nil
+	}
+	perms, authErr = gssapiConfig.AllowLogin(s, srcName)
+	return authErr, perms, nil
+}
+
+// isAlgoCompatible checks if the signature format is compatible with the
+// selected algorithm taking into account edge cases that occur with old
+// clients.
+func isAlgoCompatible(algo, sigFormat string) bool {
+	// Compatibility for old clients.
+	//
+	// For certificate authentication with OpenSSH 7.2-7.7 signature format can
+	// be rsa-sha2-256 or rsa-sha2-512 for the algorithm
+	// ssh-rsa-cert-v01@openssh.com.
+	//
+	// With gpg-agent < 2.2.6 the algorithm can be rsa-sha2-256 or rsa-sha2-512
+	// for signature format ssh-rsa.
+	if isRSA(algo) && isRSA(sigFormat) {
+		return true
+	}
+	// Standard case: the underlying algorithm must match the signature format.
+	return underlyingAlgo(algo) == sigFormat
+}
+
+// ServerAuthError represents server authentication errors and is
+// sometimes returned by NewServerConn. It appends any authentication
+// errors that may occur, and is returned if all of the authentication
+// methods provided by the user failed to authenticate.
+type ServerAuthError struct {
+	// Errors contains authentication errors returned by the authentication
+	// callback methods. The first entry is typically ErrNoAuth.
+	Errors []error
+}
+
+func (l ServerAuthError) Error() string {
+	var errs []string
+	for _, err := range l.Errors {
+		errs = append(errs, err.Error())
+	}
+	return "[" + strings.Join(errs, ", ") + "]"
+}
+
+// ServerAuthCallbacks defines server-side authentication callbacks.
+type ServerAuthCallbacks struct {
+	// PasswordCallback behaves like [ServerConfig.PasswordCallback].
+	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
+
+	// PublicKeyCallback behaves like [ServerConfig.PublicKeyCallback].
+	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
+
+	// KeyboardInteractiveCallback behaves like [ServerConfig.KeyboardInteractiveCallback].
+	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
+
+	// GSSAPIWithMICConfig behaves like [ServerConfig.GSSAPIWithMICConfig].
+	GSSAPIWithMICConfig *GSSAPIWithMICConfig
+}
+
+// PartialSuccessError can be returned by any of the [ServerConfig]
+// authentication callbacks to indicate to the client that authentication has
+// partially succeeded, but further steps are required.
+type PartialSuccessError struct {
+	// Next defines the authentication callbacks to apply to further steps. The
+	// available methods communicated to the client are based on the non-nil
+	// ServerAuthCallbacks fields.
+	Next ServerAuthCallbacks
+}
+
+func (p *PartialSuccessError) Error() string {
+	return "ssh: authenticated with partial success"
+}
+
+// ErrNoAuth is the error value returned if no
+// authentication method has been passed yet. This happens as a normal
+// part of the authentication loop, since the client first tries
+// 'none' authentication to discover available methods.
+// It is returned in ServerAuthError.Errors from NewServerConn.
+var ErrNoAuth = errors.New("ssh: no auth passed yet")
+
+// BannerError is an error that can be returned by authentication handlers in
+// ServerConfig to send a banner message to the client.
+type BannerError struct {
+	Err     error
+	Message string
+}
+
+func (b *BannerError) Unwrap() error {
+	return b.Err
+}
+
+func (b *BannerError) Error() string {
+	if b.Err == nil {
+		return b.Message
+	}
+	return b.Err.Error()
+}
+
+func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
+	if config.PreAuthConnCallback != nil {
+		config.PreAuthConnCallback(s)
+	}
+
+	sessionID := s.transport.getSessionID()
+	var cache pubKeyCache
+	var perms *Permissions
+
+	authFailures := 0
+	noneAuthCount := 0
+	var authErrs []error
+	var calledBannerCallback bool
+	partialSuccessReturned := false
+	// Set the initial authentication callbacks from the config. They can be
+	// changed if a PartialSuccessError is returned.
+	authConfig := ServerAuthCallbacks{
+		PasswordCallback:            config.PasswordCallback,
+		PublicKeyCallback:           config.PublicKeyCallback,
+		KeyboardInteractiveCallback: config.KeyboardInteractiveCallback,
+		GSSAPIWithMICConfig:         config.GSSAPIWithMICConfig,
+	}
+
+userAuthLoop:
+	for {
+		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
+			discMsg := &disconnectMsg{
+				Reason:  2,
+				Message: "too many authentication failures",
+			}
+
+			if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
+				return nil, err
+			}
+			authErrs = append(authErrs, discMsg)
+			return nil, &ServerAuthError{Errors: authErrs}
+		}
+
+		var userAuthReq userAuthRequestMsg
+		if packet, err := s.transport.readPacket(); err != nil {
+			if err == io.EOF {
+				return nil, &ServerAuthError{Errors: authErrs}
+			}
+			return nil, err
+		} else if err = Unmarshal(packet, &userAuthReq); err != nil {
+			return nil, err
+		}
+
+		if userAuthReq.Service != serviceSSH {
+			return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
+		}
+
+		if s.user != userAuthReq.User && partialSuccessReturned {
+			return nil, fmt.Errorf("ssh: client changed the user after a partial success authentication, previous user %q, current user %q",
+				s.user, userAuthReq.User)
+		}
+
+		s.user = userAuthReq.User
+
+		if !calledBannerCallback && config.BannerCallback != nil {
+			calledBannerCallback = true
+			if msg := config.BannerCallback(s); msg != "" {
+				if err := s.SendAuthBanner(msg); err != nil {
+					return nil, err
+				}
+			}
+		}
+
+		perms = nil
+		authErr := ErrNoAuth
+
+		switch userAuthReq.Method {
+		case "none":
+			noneAuthCount++
+			// We don't allow none authentication after a partial success
+			// response.
+			if config.NoClientAuth && !partialSuccessReturned {
+				if config.NoClientAuthCallback != nil {
+					perms, authErr = config.NoClientAuthCallback(s)
+				} else {
+					authErr = nil
+				}
+			}
+		case "password":
+			if authConfig.PasswordCallback == nil {
+				authErr = errors.New("ssh: password auth not configured")
+				break
+			}
+			payload := userAuthReq.Payload
+			if len(payload) < 1 || payload[0] != 0 {
+				return nil, parseError(msgUserAuthRequest)
+			}
+			payload = payload[1:]
+			password, payload, ok := parseString(payload)
+			if !ok || len(payload) > 0 {
+				return nil, parseError(msgUserAuthRequest)
+			}
+
+			perms, authErr = authConfig.PasswordCallback(s, password)
+		case "keyboard-interactive":
+			if authConfig.KeyboardInteractiveCallback == nil {
+				authErr = errors.New("ssh: keyboard-interactive auth not configured")
+				break
+			}
+
+			prompter := &sshClientKeyboardInteractive{s}
+			perms, authErr = authConfig.KeyboardInteractiveCallback(s, prompter.Challenge)
+		case "publickey":
+			if authConfig.PublicKeyCallback == nil {
+				authErr = errors.New("ssh: publickey auth not configured")
+				break
+			}
+			payload := userAuthReq.Payload
+			if len(payload) < 1 {
+				return nil, parseError(msgUserAuthRequest)
+			}
+			isQuery := payload[0] == 0
+			payload = payload[1:]
+			algoBytes, payload, ok := parseString(payload)
+			if !ok {
+				return nil, parseError(msgUserAuthRequest)
+			}
+			algo := string(algoBytes)
+			if !slices.Contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
+				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
+				break
+			}
+
+			pubKeyData, payload, ok := parseString(payload)
+			if !ok {
+				return nil, parseError(msgUserAuthRequest)
+			}
+
+			pubKey, err := ParsePublicKey(pubKeyData)
+			if err != nil {
+				return nil, err
+			}
+
+			candidate, ok := cache.get(s.user, pubKeyData)
+			if !ok {
+				candidate.user = s.user
+				candidate.pubKeyData = pubKeyData
+				candidate.perms, candidate.result = authConfig.PublicKeyCallback(s, pubKey)
+				_, isPartialSuccessError := candidate.result.(*PartialSuccessError)
+				if isPartialSuccessError && config.VerifiedPublicKeyCallback != nil {
+					return nil, errors.New("ssh: invalid library usage: PublicKeyCallback must not return partial success when VerifiedPublicKeyCallback is defined")
+				}
+
+				if (candidate.result == nil || isPartialSuccessError) &&
+					candidate.perms != nil &&
+					candidate.perms.CriticalOptions != nil &&
+					candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
+					if err := checkSourceAddress(
+						s.RemoteAddr(),
+						candidate.perms.CriticalOptions[sourceAddressCriticalOption]); err != nil {
+						candidate.result = err
+					}
+				}
+				cache.add(candidate)
+			}
+
+			if isQuery {
+				// The client can query if the given public key
+				// would be okay.
+
+				if len(payload) > 0 {
+					return nil, parseError(msgUserAuthRequest)
+				}
+				_, isPartialSuccessError := candidate.result.(*PartialSuccessError)
+				if candidate.result == nil || isPartialSuccessError {
+					okMsg := userAuthPubKeyOkMsg{
+						Algo:   algo,
+						PubKey: pubKeyData,
+					}
+					if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
+						return nil, err
+					}
+					continue userAuthLoop
+				}
+				authErr = candidate.result
+			} else {
+				sig, payload, ok := parseSignature(payload)
+				if !ok || len(payload) > 0 {
+					return nil, parseError(msgUserAuthRequest)
+				}
+				// Ensure the declared public key algo is compatible with the
+				// decoded one. This check will ensure we don't accept e.g.
+				// ssh-rsa-cert-v01@openssh.com algorithm with ssh-rsa public
+				// key type. The algorithm and public key type must be
+				// consistent: both must be certificate algorithms, or neither.
+				if !slices.Contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
+					authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q",
+						pubKey.Type(), algo)
+					break
+				}
+				// Ensure the public key algo and signature algo
+				// are supported.  Compare the private key
+				// algorithm name that corresponds to algo with
+				// sig.Format.  This is usually the same, but
+				// for certs, the names differ.
+				if !slices.Contains(config.PublicKeyAuthAlgorithms, sig.Format) {
+					authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
+					break
+				}
+				if !isAlgoCompatible(algo, sig.Format) {
+					authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
+					break
+				}
+
+				signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData)
+				// pubKey is reused below for VerifiedPublicKeyCallback and
+				// must remain the key as presented by the client; derive a
+				// separate value for Verify that carries any applicable
+				// no-touch-required opt-out.
+				pubKeyForVerify := pubKey
+				if noTouchAllowed(pubKey, candidate.perms) {
+					pubKeyForVerify = skKeyWithoutUP(pubKey)
+				}
+				if err := pubKeyForVerify.Verify(signedData, sig); err != nil {
+					return nil, err
+				}
+
+				authErr = candidate.result
+				perms = candidate.perms
+				if authErr == nil && config.VerifiedPublicKeyCallback != nil {
+					// Only call VerifiedPublicKeyCallback after the key has been accepted
+					// and successfully verified. If authErr is non-nil, the key is not
+					// considered verified and the callback must not run.
+					perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo)
+				}
+				if authErr == nil && perms != nil && perms.CriticalOptions != nil {
+					if saco := perms.CriticalOptions[sourceAddressCriticalOption]; saco != "" {
+						if err := checkSourceAddress(s.RemoteAddr(), saco); err != nil {
+							authErr = err
+						}
+					}
+				}
+			}
+		case "gssapi-with-mic":
+			if authConfig.GSSAPIWithMICConfig == nil {
+				authErr = errors.New("ssh: gssapi-with-mic auth not configured")
+				break
+			}
+			gssapiConfig := authConfig.GSSAPIWithMICConfig
+			userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
+			if err != nil {
+				return nil, parseError(msgUserAuthRequest)
+			}
+			// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
+			if userAuthRequestGSSAPI.N == 0 {
+				authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
+				break
+			}
+			var i uint32
+			present := false
+			for i = 0; i < userAuthRequestGSSAPI.N; i++ {
+				if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
+					present = true
+					break
+				}
+			}
+			if !present {
+				authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
+				break
+			}
+			// Initial server response, see RFC 4462 section 3.3.
+			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
+				SupportMech: krb5OID,
+			})); err != nil {
+				return nil, err
+			}
+			// Exchange token, see RFC 4462 section 3.4.
+			packet, err := s.transport.readPacket()
+			if err != nil {
+				return nil, err
+			}
+			userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
+			if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
+				return nil, err
+			}
+			authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
+				userAuthReq)
+			if err != nil {
+				return nil, err
+			}
+		default:
+			authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
+		}
+
+		authErrs = append(authErrs, authErr)
+
+		if config.AuthLogCallback != nil {
+			config.AuthLogCallback(s, userAuthReq.Method, authErr)
+		}
+
+		var bannerErr *BannerError
+		if errors.As(authErr, &bannerErr) {
+			if bannerErr.Message != "" {
+				if err := s.SendAuthBanner(bannerErr.Message); err != nil {
+					return nil, err
+				}
+			}
+		}
+
+		if authErr == nil {
+			break userAuthLoop
+		}
+
+		var failureMsg userAuthFailureMsg
+
+		if partialSuccess, ok := authErr.(*PartialSuccessError); ok {
+			// Permissions are not preserved between authentication steps. To
+			// avoid confusion about the final state of the connection, we
+			// disallow returning non-nil Permissions combined with
+			// PartialSuccessError.
+			if perms != nil {
+				return nil, errors.New("ssh: permissions must be nil when returning PartialSuccessError")
+			}
+			// After a partial success error we don't allow changing the user
+			// name and execute the NoClientAuthCallback.
+			partialSuccessReturned = true
+
+			// In case a partial success is returned, the server may send
+			// a new set of authentication methods.
+			authConfig = partialSuccess.Next
+
+			// Reset pubkey cache, as the new PublicKeyCallback might
+			// accept a different set of public keys.
+			cache = pubKeyCache{}
+
+			// Send back a partial success message to the user.
+			failureMsg.PartialSuccess = true
+		} else {
+			// Allow initial attempt of 'none' without penalty.
+			if authFailures > 0 || userAuthReq.Method != "none" || noneAuthCount != 1 {
+				authFailures++
+			}
+			if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
+				// If we have hit the max attempts, don't bother sending the
+				// final SSH_MSG_USERAUTH_FAILURE message, since there are
+				// no more authentication methods which can be attempted,
+				// and this message may cause the client to re-attempt
+				// authentication while we send the disconnect message.
+				// Continue, and trigger the disconnect at the start of
+				// the loop.
+				//
+				// The SSH specification is somewhat confusing about this,
+				// RFC 4252 Section 5.1 requires each authentication failure
+				// be responded to with a respective SSH_MSG_USERAUTH_FAILURE
+				// message, but Section 4 says the server should disconnect
+				// after some number of attempts, but it isn't explicit which
+				// message should take precedence (i.e. should there be a failure
+				// message than a disconnect message, or if we are going to
+				// disconnect, should we only send that message.)
+				//
+				// Either way, OpenSSH disconnects immediately after the last
+				// failed authentication attempt, and given they are typically
+				// considered the golden implementation it seems reasonable
+				// to match that behavior.
+				continue
+			}
+		}
+
+		if authConfig.PasswordCallback != nil {
+			failureMsg.Methods = append(failureMsg.Methods, "password")
+		}
+		if authConfig.PublicKeyCallback != nil {
+			failureMsg.Methods = append(failureMsg.Methods, "publickey")
+		}
+		if authConfig.KeyboardInteractiveCallback != nil {
+			failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
+		}
+		if authConfig.GSSAPIWithMICConfig != nil && authConfig.GSSAPIWithMICConfig.Server != nil &&
+			authConfig.GSSAPIWithMICConfig.AllowLogin != nil {
+			failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
+		}
+
+		if len(failureMsg.Methods) == 0 {
+			return nil, errors.New("ssh: no authentication methods available")
+		}
+
+		if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
+			return nil, err
+		}
+	}
+
+	if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
+		return nil, err
+	}
+	return perms, nil
+}
+
+// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
+// asking the client on the other side of a ServerConn.
+type sshClientKeyboardInteractive struct {
+	*connection
+}
+
+func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
+	if len(questions) != len(echos) {
+		return nil, errors.New("ssh: echos and questions must have equal length")
+	}
+
+	var prompts []byte
+	for i := range questions {
+		prompts = appendString(prompts, questions[i])
+		prompts = appendBool(prompts, echos[i])
+	}
+
+	if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
+		Name:        name,
+		Instruction: instruction,
+		NumPrompts:  uint32(len(questions)),
+		Prompts:     prompts,
+	})); err != nil {
+		return nil, err
+	}
+
+	packet, err := c.transport.readPacket()
+	if err != nil {
+		return nil, err
+	}
+	if packet[0] != msgUserAuthInfoResponse {
+		return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
+	}
+	packet = packet[1:]
+
+	n, packet, ok := parseUint32(packet)
+	if !ok || int(n) != len(questions) {
+		return nil, parseError(msgUserAuthInfoResponse)
+	}
+
+	for i := uint32(0); i < n; i++ {
+		ans, rest, ok := parseString(packet)
+		if !ok {
+			return nil, parseError(msgUserAuthInfoResponse)
+		}
+
+		answers = append(answers, string(ans))
+		packet = rest
+	}
+	if len(packet) != 0 {
+		return nil, errors.New("ssh: junk at end of message")
+	}
+
+	return answers, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go
new file mode 100644
index 000000000..acef62259
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/session.go
@@ -0,0 +1,647 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+// Session implements an interactive session described in
+// "RFC 4254, section 6".
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"sync"
+)
+
+type Signal string
+
+// POSIX signals as listed in RFC 4254 Section 6.10.
+const (
+	SIGABRT Signal = "ABRT"
+	SIGALRM Signal = "ALRM"
+	SIGFPE  Signal = "FPE"
+	SIGHUP  Signal = "HUP"
+	SIGILL  Signal = "ILL"
+	SIGINT  Signal = "INT"
+	SIGKILL Signal = "KILL"
+	SIGPIPE Signal = "PIPE"
+	SIGQUIT Signal = "QUIT"
+	SIGSEGV Signal = "SEGV"
+	SIGTERM Signal = "TERM"
+	SIGUSR1 Signal = "USR1"
+	SIGUSR2 Signal = "USR2"
+)
+
+var signals = map[Signal]int{
+	SIGABRT: 6,
+	SIGALRM: 14,
+	SIGFPE:  8,
+	SIGHUP:  1,
+	SIGILL:  4,
+	SIGINT:  2,
+	SIGKILL: 9,
+	SIGPIPE: 13,
+	SIGQUIT: 3,
+	SIGSEGV: 11,
+	SIGTERM: 15,
+}
+
+type TerminalModes map[uint8]uint32
+
+// POSIX terminal mode flags as listed in RFC 4254 Section 8.
+const (
+	tty_OP_END    = 0
+	VINTR         = 1
+	VQUIT         = 2
+	VERASE        = 3
+	VKILL         = 4
+	VEOF          = 5
+	VEOL          = 6
+	VEOL2         = 7
+	VSTART        = 8
+	VSTOP         = 9
+	VSUSP         = 10
+	VDSUSP        = 11
+	VREPRINT      = 12
+	VWERASE       = 13
+	VLNEXT        = 14
+	VFLUSH        = 15
+	VSWTCH        = 16
+	VSTATUS       = 17
+	VDISCARD      = 18
+	IGNPAR        = 30
+	PARMRK        = 31
+	INPCK         = 32
+	ISTRIP        = 33
+	INLCR         = 34
+	IGNCR         = 35
+	ICRNL         = 36
+	IUCLC         = 37
+	IXON          = 38
+	IXANY         = 39
+	IXOFF         = 40
+	IMAXBEL       = 41
+	IUTF8         = 42 // RFC 8160
+	ISIG          = 50
+	ICANON        = 51
+	XCASE         = 52
+	ECHO          = 53
+	ECHOE         = 54
+	ECHOK         = 55
+	ECHONL        = 56
+	NOFLSH        = 57
+	TOSTOP        = 58
+	IEXTEN        = 59
+	ECHOCTL       = 60
+	ECHOKE        = 61
+	PENDIN        = 62
+	OPOST         = 70
+	OLCUC         = 71
+	ONLCR         = 72
+	OCRNL         = 73
+	ONOCR         = 74
+	ONLRET        = 75
+	CS7           = 90
+	CS8           = 91
+	PARENB        = 92
+	PARODD        = 93
+	TTY_OP_ISPEED = 128
+	TTY_OP_OSPEED = 129
+)
+
+// A Session represents a connection to a remote command or shell.
+type Session struct {
+	// Stdin specifies the remote process's standard input.
+	// If Stdin is nil, the remote process reads from an empty
+	// bytes.Buffer.
+	Stdin io.Reader
+
+	// Stdout and Stderr specify the remote process's standard
+	// output and error.
+	//
+	// If either is nil, Run connects the corresponding file
+	// descriptor to an instance of io.Discard. There is a
+	// fixed amount of buffering that is shared for the two streams.
+	// If either blocks it may eventually cause the remote
+	// command to block.
+	Stdout io.Writer
+	Stderr io.Writer
+
+	ch        Channel // the channel backing this session
+	started   bool    // true once Start, Run or Shell is invoked.
+	copyFuncs []func() error
+	errors    chan error // one send per copyFunc
+
+	// true if pipe method is active
+	stdinpipe, stdoutpipe, stderrpipe bool
+
+	// stdinPipeWriter is non-nil if StdinPipe has not been called
+	// and Stdin was specified by the user; it is the write end of
+	// a pipe connecting Session.Stdin to the stdin channel.
+	stdinPipeWriter io.WriteCloser
+
+	exitStatus chan error
+}
+
+// SendRequest sends an out-of-band channel request on the SSH channel
+// underlying the session.
+func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
+	return s.ch.SendRequest(name, wantReply, payload)
+}
+
+func (s *Session) Close() error {
+	return s.ch.Close()
+}
+
+// RFC 4254 Section 6.4.
+type setenvRequest struct {
+	Name  string
+	Value string
+}
+
+// Setenv sets an environment variable that will be applied to any
+// command executed by Shell or Run.
+func (s *Session) Setenv(name, value string) error {
+	msg := setenvRequest{
+		Name:  name,
+		Value: value,
+	}
+	ok, err := s.ch.SendRequest("env", true, Marshal(&msg))
+	if err == nil && !ok {
+		err = errors.New("ssh: setenv failed")
+	}
+	return err
+}
+
+// RFC 4254 Section 6.2.
+type ptyRequestMsg struct {
+	Term     string
+	Columns  uint32
+	Rows     uint32
+	Width    uint32
+	Height   uint32
+	Modelist string
+}
+
+// RequestPty requests the association of a pty with the session on the remote host.
+func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error {
+	var tm []byte
+	for k, v := range termmodes {
+		kv := struct {
+			Key byte
+			Val uint32
+		}{k, v}
+
+		tm = append(tm, Marshal(&kv)...)
+	}
+	tm = append(tm, tty_OP_END)
+	req := ptyRequestMsg{
+		Term:     term,
+		Columns:  uint32(w),
+		Rows:     uint32(h),
+		Width:    uint32(w * 8),
+		Height:   uint32(h * 8),
+		Modelist: string(tm),
+	}
+	ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req))
+	if err == nil && !ok {
+		err = errors.New("ssh: pty-req failed")
+	}
+	return err
+}
+
+// RFC 4254 Section 6.5.
+type subsystemRequestMsg struct {
+	Subsystem string
+}
+
+// RequestSubsystem requests the association of a subsystem with the session on the remote host.
+// A subsystem is a predefined command that runs in the background when the ssh session is initiated
+func (s *Session) RequestSubsystem(subsystem string) error {
+	msg := subsystemRequestMsg{
+		Subsystem: subsystem,
+	}
+	ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg))
+	if err == nil && !ok {
+		err = errors.New("ssh: subsystem request failed")
+	}
+	return err
+}
+
+// RFC 4254 Section 6.7.
+type ptyWindowChangeMsg struct {
+	Columns uint32
+	Rows    uint32
+	Width   uint32
+	Height  uint32
+}
+
+// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns.
+func (s *Session) WindowChange(h, w int) error {
+	req := ptyWindowChangeMsg{
+		Columns: uint32(w),
+		Rows:    uint32(h),
+		Width:   uint32(w * 8),
+		Height:  uint32(h * 8),
+	}
+	_, err := s.ch.SendRequest("window-change", false, Marshal(&req))
+	return err
+}
+
+// RFC 4254 Section 6.9.
+type signalMsg struct {
+	Signal string
+}
+
+// Signal sends the given signal to the remote process.
+// sig is one of the SIG* constants.
+func (s *Session) Signal(sig Signal) error {
+	msg := signalMsg{
+		Signal: string(sig),
+	}
+
+	_, err := s.ch.SendRequest("signal", false, Marshal(&msg))
+	return err
+}
+
+// RFC 4254 Section 6.5.
+type execMsg struct {
+	Command string
+}
+
+// Start runs cmd on the remote host. Typically, the remote
+// server passes cmd to the shell for interpretation.
+// A Session only accepts one call to Run, Start or Shell.
+func (s *Session) Start(cmd string) error {
+	if s.started {
+		return errors.New("ssh: session already started")
+	}
+	req := execMsg{
+		Command: cmd,
+	}
+
+	ok, err := s.ch.SendRequest("exec", true, Marshal(&req))
+	if err == nil && !ok {
+		err = fmt.Errorf("ssh: command %v failed", cmd)
+	}
+	if err != nil {
+		return err
+	}
+	return s.start()
+}
+
+// Run runs cmd on the remote host. Typically, the remote
+// server passes cmd to the shell for interpretation.
+// A Session only accepts one call to Run, Start, Shell, Output,
+// or CombinedOutput.
+//
+// The returned error is nil if the command runs, has no problems
+// copying stdin, stdout, and stderr, and exits with a zero exit
+// status.
+//
+// If the remote server does not send an exit status, an error of type
+// *ExitMissingError is returned. If the command completes
+// unsuccessfully or is interrupted by a signal, the error is of type
+// *ExitError. Other error types may be returned for I/O problems.
+func (s *Session) Run(cmd string) error {
+	err := s.Start(cmd)
+	if err != nil {
+		return err
+	}
+	return s.Wait()
+}
+
+// Output runs cmd on the remote host and returns its standard output.
+func (s *Session) Output(cmd string) ([]byte, error) {
+	if s.Stdout != nil {
+		return nil, errors.New("ssh: Stdout already set")
+	}
+	var b bytes.Buffer
+	s.Stdout = &b
+	err := s.Run(cmd)
+	return b.Bytes(), err
+}
+
+type singleWriter struct {
+	b  bytes.Buffer
+	mu sync.Mutex
+}
+
+func (w *singleWriter) Write(p []byte) (int, error) {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+	return w.b.Write(p)
+}
+
+// CombinedOutput runs cmd on the remote host and returns its combined
+// standard output and standard error.
+func (s *Session) CombinedOutput(cmd string) ([]byte, error) {
+	if s.Stdout != nil {
+		return nil, errors.New("ssh: Stdout already set")
+	}
+	if s.Stderr != nil {
+		return nil, errors.New("ssh: Stderr already set")
+	}
+	var b singleWriter
+	s.Stdout = &b
+	s.Stderr = &b
+	err := s.Run(cmd)
+	return b.b.Bytes(), err
+}
+
+// Shell starts a login shell on the remote host. A Session only
+// accepts one call to Run, Start, Shell, Output, or CombinedOutput.
+func (s *Session) Shell() error {
+	if s.started {
+		return errors.New("ssh: session already started")
+	}
+
+	ok, err := s.ch.SendRequest("shell", true, nil)
+	if err == nil && !ok {
+		return errors.New("ssh: could not start shell")
+	}
+	if err != nil {
+		return err
+	}
+	return s.start()
+}
+
+func (s *Session) start() error {
+	s.started = true
+
+	type F func(*Session)
+	for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} {
+		setupFd(s)
+	}
+
+	s.errors = make(chan error, len(s.copyFuncs))
+	for _, fn := range s.copyFuncs {
+		go func(fn func() error) {
+			s.errors <- fn()
+		}(fn)
+	}
+	return nil
+}
+
+// Wait waits for the remote command to exit.
+//
+// The returned error is nil if the command runs, has no problems
+// copying stdin, stdout, and stderr, and exits with a zero exit
+// status.
+//
+// If the remote server does not send an exit status, an error of type
+// *ExitMissingError is returned. If the command completes
+// unsuccessfully or is interrupted by a signal, the error is of type
+// *ExitError. Other error types may be returned for I/O problems.
+func (s *Session) Wait() error {
+	if !s.started {
+		return errors.New("ssh: session not started")
+	}
+	waitErr := <-s.exitStatus
+
+	if s.stdinPipeWriter != nil {
+		s.stdinPipeWriter.Close()
+	}
+	var copyError error
+	for range s.copyFuncs {
+		if err := <-s.errors; err != nil && copyError == nil {
+			copyError = err
+		}
+	}
+	if waitErr != nil {
+		return waitErr
+	}
+	return copyError
+}
+
+func (s *Session) wait(reqs <-chan *Request) error {
+	wm := Waitmsg{status: -1}
+	// Wait for msg channel to be closed before returning.
+	for msg := range reqs {
+		switch msg.Type {
+		case "exit-status":
+			wm.status = int(binary.BigEndian.Uint32(msg.Payload))
+		case "exit-signal":
+			var sigval struct {
+				Signal     string
+				CoreDumped bool
+				Error      string
+				Lang       string
+			}
+			if err := Unmarshal(msg.Payload, &sigval); err != nil {
+				return err
+			}
+
+			// Must sanitize strings?
+			wm.signal = sigval.Signal
+			wm.msg = sigval.Error
+			wm.lang = sigval.Lang
+		default:
+			// This handles keepalives and matches
+			// OpenSSH's behaviour.
+			if msg.WantReply {
+				msg.Reply(false, nil)
+			}
+		}
+	}
+	if wm.status == 0 {
+		return nil
+	}
+	if wm.status == -1 {
+		// exit-status was never sent from server
+		if wm.signal == "" {
+			// signal was not sent either.  RFC 4254
+			// section 6.10 recommends against this
+			// behavior, but it is allowed, so we let
+			// clients handle it.
+			return &ExitMissingError{}
+		}
+		wm.status = 128
+		if _, ok := signals[Signal(wm.signal)]; ok {
+			wm.status += signals[Signal(wm.signal)]
+		}
+	}
+
+	return &ExitError{wm}
+}
+
+// ExitMissingError is returned if a session is torn down cleanly, but
+// the server sends no confirmation of the exit status.
+type ExitMissingError struct{}
+
+func (e *ExitMissingError) Error() string {
+	return "wait: remote command exited without exit status or exit signal"
+}
+
+func (s *Session) stdin() {
+	if s.stdinpipe {
+		return
+	}
+	var stdin io.Reader
+	if s.Stdin == nil {
+		stdin = new(bytes.Buffer)
+	} else {
+		r, w := io.Pipe()
+		go func() {
+			_, err := io.Copy(w, s.Stdin)
+			w.CloseWithError(err)
+		}()
+		stdin, s.stdinPipeWriter = r, w
+	}
+	s.copyFuncs = append(s.copyFuncs, func() error {
+		_, err := io.Copy(s.ch, stdin)
+		if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF {
+			err = err1
+		}
+		return err
+	})
+}
+
+func (s *Session) stdout() {
+	if s.stdoutpipe {
+		return
+	}
+	if s.Stdout == nil {
+		s.Stdout = io.Discard
+	}
+	s.copyFuncs = append(s.copyFuncs, func() error {
+		_, err := io.Copy(s.Stdout, s.ch)
+		return err
+	})
+}
+
+func (s *Session) stderr() {
+	if s.stderrpipe {
+		return
+	}
+	if s.Stderr == nil {
+		s.Stderr = io.Discard
+	}
+	s.copyFuncs = append(s.copyFuncs, func() error {
+		_, err := io.Copy(s.Stderr, s.ch.Stderr())
+		return err
+	})
+}
+
+// sessionStdin reroutes Close to CloseWrite.
+type sessionStdin struct {
+	io.Writer
+	ch Channel
+}
+
+func (s *sessionStdin) Close() error {
+	return s.ch.CloseWrite()
+}
+
+// StdinPipe returns a pipe that will be connected to the
+// remote command's standard input when the command starts.
+func (s *Session) StdinPipe() (io.WriteCloser, error) {
+	if s.Stdin != nil {
+		return nil, errors.New("ssh: Stdin already set")
+	}
+	if s.started {
+		return nil, errors.New("ssh: StdinPipe after process started")
+	}
+	s.stdinpipe = true
+	return &sessionStdin{s.ch, s.ch}, nil
+}
+
+// StdoutPipe returns a pipe that will be connected to the
+// remote command's standard output when the command starts.
+// There is a fixed amount of buffering that is shared between
+// stdout and stderr streams. If the StdoutPipe reader is
+// not serviced fast enough it may eventually cause the
+// remote command to block.
+func (s *Session) StdoutPipe() (io.Reader, error) {
+	if s.Stdout != nil {
+		return nil, errors.New("ssh: Stdout already set")
+	}
+	if s.started {
+		return nil, errors.New("ssh: StdoutPipe after process started")
+	}
+	s.stdoutpipe = true
+	return s.ch, nil
+}
+
+// StderrPipe returns a pipe that will be connected to the
+// remote command's standard error when the command starts.
+// There is a fixed amount of buffering that is shared between
+// stdout and stderr streams. If the StderrPipe reader is
+// not serviced fast enough it may eventually cause the
+// remote command to block.
+func (s *Session) StderrPipe() (io.Reader, error) {
+	if s.Stderr != nil {
+		return nil, errors.New("ssh: Stderr already set")
+	}
+	if s.started {
+		return nil, errors.New("ssh: StderrPipe after process started")
+	}
+	s.stderrpipe = true
+	return s.ch.Stderr(), nil
+}
+
+// newSession returns a new interactive session on the remote host.
+func newSession(ch Channel, reqs <-chan *Request) (*Session, error) {
+	s := &Session{
+		ch: ch,
+	}
+	s.exitStatus = make(chan error, 1)
+	go func() {
+		s.exitStatus <- s.wait(reqs)
+	}()
+
+	return s, nil
+}
+
+// An ExitError reports unsuccessful completion of a remote command.
+type ExitError struct {
+	Waitmsg
+}
+
+func (e *ExitError) Error() string {
+	return e.Waitmsg.String()
+}
+
+// Waitmsg stores the information about an exited remote command
+// as reported by Wait.
+type Waitmsg struct {
+	status int
+	signal string
+	msg    string
+	lang   string
+}
+
+// ExitStatus returns the exit status of the remote command.
+func (w Waitmsg) ExitStatus() int {
+	return w.status
+}
+
+// Signal returns the exit signal of the remote command if
+// it was terminated violently.
+func (w Waitmsg) Signal() string {
+	return w.signal
+}
+
+// Msg returns the exit message given by the remote command
+func (w Waitmsg) Msg() string {
+	return w.msg
+}
+
+// Lang returns the language tag. See RFC 3066
+func (w Waitmsg) Lang() string {
+	return w.lang
+}
+
+func (w Waitmsg) String() string {
+	str := fmt.Sprintf("Process exited with status %v", w.status)
+	if w.signal != "" {
+		str += fmt.Sprintf(" from signal %v", w.signal)
+	}
+	if w.msg != "" {
+		str += fmt.Sprintf(". Reason was: %v", w.msg)
+	}
+	return str
+}
diff --git a/vendor/golang.org/x/crypto/ssh/ssh_gss.go b/vendor/golang.org/x/crypto/ssh/ssh_gss.go
new file mode 100644
index 000000000..a6249a122
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/ssh_gss.go
@@ -0,0 +1,145 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"encoding/asn1"
+	"errors"
+)
+
+var krb5OID []byte
+
+func init() {
+	krb5OID, _ = asn1.Marshal(krb5Mesh)
+}
+
+// GSSAPIClient provides the API to plug-in GSSAPI authentication for client logins.
+type GSSAPIClient interface {
+	// InitSecContext initiates the establishment of a security context for GSS-API between the
+	// ssh client and ssh server. Initially the token parameter should be specified as nil.
+	// The routine may return a outputToken which should be transferred to
+	// the ssh server, where the ssh server will present it to
+	// AcceptSecContext. If no token need be sent, InitSecContext will indicate this by setting
+	// needContinue to false. To complete the context
+	// establishment, one or more reply tokens may be required from the ssh
+	// server;if so, InitSecContext will return a needContinue which is true.
+	// In this case, InitSecContext should be called again when the
+	// reply token is received from the ssh server, passing the reply
+	// token to InitSecContext via the token parameters.
+	// See RFC 2743 section 2.2.1 and RFC 4462 section 3.4.
+	InitSecContext(target string, token []byte, isGSSDelegCreds bool) (outputToken []byte, needContinue bool, err error)
+	// GetMIC generates a cryptographic MIC for the SSH2 message, and places
+	// the MIC in a token for transfer to the ssh server.
+	// The contents of the MIC field are obtained by calling GSS_GetMIC()
+	// over the following, using the GSS-API context that was just
+	// established:
+	//  string    session identifier
+	//  byte      SSH_MSG_USERAUTH_REQUEST
+	//  string    user name
+	//  string    service
+	//  string    "gssapi-with-mic"
+	// See RFC 2743 section 2.3.1 and RFC 4462 3.5.
+	GetMIC(micFiled []byte) ([]byte, error)
+	// Whenever possible, it should be possible for
+	// DeleteSecContext() calls to be successfully processed even
+	// if other calls cannot succeed, thereby enabling context-related
+	// resources to be released.
+	// In addition to deleting established security contexts,
+	// gss_delete_sec_context must also be able to delete "half-built"
+	// security contexts resulting from an incomplete sequence of
+	// InitSecContext()/AcceptSecContext() calls.
+	// See RFC 2743 section 2.2.3.
+	DeleteSecContext() error
+}
+
+// GSSAPIServer provides the API to plug in GSSAPI authentication for server logins.
+type GSSAPIServer interface {
+	// AcceptSecContext allows a remotely initiated security context between the application
+	// and a remote peer to be established by the ssh client. The routine may return a
+	// outputToken which should be transferred to the ssh client,
+	// where the ssh client will present it to InitSecContext.
+	// If no token need be sent, AcceptSecContext will indicate this
+	// by setting the needContinue to false. To
+	// complete the context establishment, one or more reply tokens may be
+	// required from the ssh client. if so, AcceptSecContext
+	// will return a needContinue which is true, in which case it
+	// should be called again when the reply token is received from the ssh
+	// client, passing the token to AcceptSecContext via the
+	// token parameters.
+	// The srcName return value is the authenticated username.
+	// See RFC 2743 section 2.2.2 and RFC 4462 section 3.4.
+	AcceptSecContext(token []byte) (outputToken []byte, srcName string, needContinue bool, err error)
+	// VerifyMIC verifies that a cryptographic MIC, contained in the token parameter,
+	// fits the supplied message is received from the ssh client.
+	// See RFC 2743 section 2.3.2.
+	VerifyMIC(micField []byte, micToken []byte) error
+	// Whenever possible, it should be possible for
+	// DeleteSecContext() calls to be successfully processed even
+	// if other calls cannot succeed, thereby enabling context-related
+	// resources to be released.
+	// In addition to deleting established security contexts,
+	// gss_delete_sec_context must also be able to delete "half-built"
+	// security contexts resulting from an incomplete sequence of
+	// InitSecContext()/AcceptSecContext() calls.
+	// See RFC 2743 section 2.2.3.
+	DeleteSecContext() error
+}
+
+var (
+	// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,
+	// so we also support the krb5 mechanism only.
+	// See RFC 1964 section 1.
+	krb5Mesh = asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
+)
+
+// The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST
+// See RFC 4462 section 3.2.
+type userAuthRequestGSSAPI struct {
+	N    uint32
+	OIDS []asn1.ObjectIdentifier
+}
+
+func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
+	n, rest, ok := parseUint32(payload)
+	if !ok {
+		return nil, errors.New("parse uint32 failed")
+	}
+	// Each ASN.1 encoded OID must have a minimum
+	// of 2 bytes; 64 maximum mechanisms is an
+	// arbitrary, but reasonable ceiling.
+	const maxMechs = 64
+	if n > maxMechs || int(n)*2 > len(rest) {
+		return nil, errors.New("invalid mechanism count")
+	}
+	s := &userAuthRequestGSSAPI{
+		N:    n,
+		OIDS: make([]asn1.ObjectIdentifier, n),
+	}
+	for i := 0; i < int(n); i++ {
+		var (
+			desiredMech []byte
+			err         error
+		)
+		desiredMech, rest, ok = parseString(rest)
+		if !ok {
+			return nil, errors.New("parse string failed")
+		}
+		if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil {
+			return nil, err
+		}
+	}
+	return s, nil
+}
+
+// See RFC 4462 section 3.6.
+func buildMIC(sessionID string, username string, service string, authMethod string) []byte {
+	out := make([]byte, 0, 0)
+	out = appendString(out, sessionID)
+	out = append(out, msgUserAuthRequest)
+	out = appendString(out, username)
+	out = appendString(out, service)
+	out = appendString(out, authMethod)
+	return out
+}
diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go
new file mode 100644
index 000000000..152470fcb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/streamlocal.go
@@ -0,0 +1,116 @@
+package ssh
+
+import (
+	"errors"
+	"io"
+	"net"
+)
+
+// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
+// with "direct-streamlocal@openssh.com" string.
+//
+// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
+// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
+type streamLocalChannelOpenDirectMsg struct {
+	socketPath string
+	reserved0  string
+	reserved1  uint32
+}
+
+// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
+// with "forwarded-streamlocal@openssh.com" string.
+type forwardedStreamLocalPayload struct {
+	SocketPath string
+	Reserved0  string
+}
+
+// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
+// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
+type streamLocalChannelForwardMsg struct {
+	socketPath string
+}
+
+// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
+func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
+	c.handleForwardsOnce.Do(c.handleForwards)
+	m := streamLocalChannelForwardMsg{
+		socketPath,
+	}
+	// send message
+	ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m))
+	if err != nil {
+		return nil, err
+	}
+	if !ok {
+		return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
+	}
+	ch := c.forwards.add("unix", socketPath)
+
+	return &unixListener{socketPath, c, ch}, nil
+}
+
+func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
+	msg := streamLocalChannelOpenDirectMsg{
+		socketPath: socketPath,
+	}
+	ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg))
+	if err != nil {
+		return nil, err
+	}
+	go DiscardRequests(in)
+	return ch, err
+}
+
+type unixListener struct {
+	socketPath string
+
+	conn *Client
+	in   <-chan forward
+}
+
+// Accept waits for and returns the next connection to the listener.
+func (l *unixListener) Accept() (net.Conn, error) {
+	s, ok := <-l.in
+	if !ok {
+		return nil, io.EOF
+	}
+	ch, incoming, err := s.newCh.Accept()
+	if err != nil {
+		return nil, err
+	}
+	go DiscardRequests(incoming)
+
+	return &chanConn{
+		Channel: ch,
+		laddr: &net.UnixAddr{
+			Name: l.socketPath,
+			Net:  "unix",
+		},
+		raddr: &net.UnixAddr{
+			Name: "@",
+			Net:  "unix",
+		},
+	}, nil
+}
+
+// Close closes the listener.
+func (l *unixListener) Close() error {
+	// this also closes the listener.
+	l.conn.forwards.remove("unix", l.socketPath)
+	m := streamLocalChannelForwardMsg{
+		l.socketPath,
+	}
+	ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m))
+	if err == nil && !ok {
+		err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
+	}
+	return err
+}
+
+// Addr returns the listener's network address.
+func (l *unixListener) Addr() net.Addr {
+	return &net.UnixAddr{
+		Name: l.socketPath,
+		Net:  "unix",
+	}
+}
diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go
new file mode 100644
index 000000000..78c41fe5a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/tcpip.go
@@ -0,0 +1,545 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"math/rand"
+	"net"
+	"net/netip"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+// Listen requests the remote peer open a listening socket on
+// addr. Incoming connections will be available by calling Accept on
+// the returned net.Listener. The listener must be serviced, or the
+// SSH connection may hang.
+// N must be "tcp", "tcp4", "tcp6", or "unix".
+//
+// If the address is a hostname, it is sent to the remote peer as-is, without
+// being resolved locally, and the Listener Addr method will return a zero IP.
+func (c *Client) Listen(n, addr string) (net.Listener, error) {
+	switch n {
+	case "tcp", "tcp4", "tcp6":
+		host, portStr, err := net.SplitHostPort(addr)
+		if err != nil {
+			return nil, err
+		}
+		port, err := strconv.ParseInt(portStr, 10, 32)
+		if err != nil {
+			return nil, err
+		}
+		return c.listenTCPInternal(host, int(port))
+	case "unix":
+		return c.ListenUnix(addr)
+	default:
+		return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
+	}
+}
+
+// Automatic port allocation is broken with OpenSSH before 6.0. See
+// also https://bugzilla.mindrot.org/show_bug.cgi?id=2017.  In
+// particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0,
+// rather than the actual port number. This means you can never open
+// two different listeners with auto allocated ports. We work around
+// this by trying explicit ports until we succeed.
+
+const openSSHPrefix = "OpenSSH_"
+
+var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+// isBrokenOpenSSHVersion returns true if the given version string
+// specifies a version of OpenSSH that is known to have a bug in port
+// forwarding.
+func isBrokenOpenSSHVersion(versionStr string) bool {
+	i := strings.Index(versionStr, openSSHPrefix)
+	if i < 0 {
+		return false
+	}
+	i += len(openSSHPrefix)
+	j := i
+	for ; j < len(versionStr); j++ {
+		if versionStr[j] < '0' || versionStr[j] > '9' {
+			break
+		}
+	}
+	version, _ := strconv.Atoi(versionStr[i:j])
+	return version < 6
+}
+
+// autoPortListenWorkaround simulates automatic port allocation by
+// trying random ports repeatedly.
+func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) {
+	var sshListener net.Listener
+	var err error
+	const tries = 10
+	for i := 0; i < tries; i++ {
+		addr := *laddr
+		addr.Port = 1024 + portRandomizer.Intn(60000)
+		sshListener, err = c.ListenTCP(&addr)
+		if err == nil {
+			laddr.Port = addr.Port
+			return sshListener, err
+		}
+	}
+	return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err)
+}
+
+// RFC 4254 7.1
+type channelForwardMsg struct {
+	addr  string
+	rport uint32
+}
+
+// handleForwards starts goroutines handling forwarded connections.
+// It's called on first use by (*Client).ListenTCP to not launch
+// goroutines until needed.
+func (c *Client) handleForwards() {
+	go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip"))
+	go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
+}
+
+// ListenTCP requests the remote peer open a listening socket
+// on laddr. Incoming connections will be available by calling
+// Accept on the returned net.Listener.
+//
+// ListenTCP accepts an IP address, to provide a hostname use [Client.Listen]
+// with "tcp", "tcp4", or "tcp6" network instead.
+func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
+	c.handleForwardsOnce.Do(c.handleForwards)
+	if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
+		return c.autoPortListenWorkaround(laddr)
+	}
+
+	return c.listenTCPInternal(laddr.IP.String(), laddr.Port)
+}
+
+func (c *Client) listenTCPInternal(host string, port int) (net.Listener, error) {
+	c.handleForwardsOnce.Do(c.handleForwards)
+
+	m := channelForwardMsg{
+		host,
+		uint32(port),
+	}
+	// send message
+	ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m))
+	if err != nil {
+		return nil, err
+	}
+	if !ok {
+		return nil, errors.New("ssh: tcpip-forward request denied by peer")
+	}
+
+	// If the original port was 0, then the remote side will
+	// supply a real port number in the response.
+	if port == 0 {
+		var p struct {
+			Port uint32
+		}
+		if err := Unmarshal(resp, &p); err != nil {
+			return nil, err
+		}
+		port = int(p.Port)
+	}
+	// Construct a local address placeholder for the remote listener. If the
+	// original host is an IP address, preserve it so that Listener.Addr()
+	// reports the same IP. If the host is a hostname or cannot be parsed as an
+	// IP, fall back to IPv4zero. The port field is always set, even if the
+	// original port was 0, because in that case the remote server will assign
+	// one, allowing callers to determine which port was selected.
+	ip := net.IPv4zero
+	if parsed, err := netip.ParseAddr(host); err == nil {
+		ip = net.IP(parsed.AsSlice())
+	}
+	laddr := &net.TCPAddr{
+		IP:   ip,
+		Port: port,
+	}
+	addr := net.JoinHostPort(host, strconv.FormatInt(int64(port), 10))
+	ch := c.forwards.add("tcp", addr)
+
+	return &tcpListener{laddr, addr, c, ch}, nil
+}
+
+// forwardList stores a mapping between remote
+// forward requests and the tcpListeners.
+type forwardList struct {
+	sync.Mutex
+	entries []forwardEntry
+}
+
+// forwardEntry represents an established mapping of a laddr on a
+// remote ssh server to a channel connected to a tcpListener.
+type forwardEntry struct {
+	addr    string // host:port or socket path
+	network string // tcp or unix
+	c       chan forward
+}
+
+// forward represents an incoming forwarded tcpip connection. The
+// arguments to add/remove/lookup should be address as specified in
+// the original forward-request.
+type forward struct {
+	newCh NewChannel // the ssh client channel underlying this forward
+	raddr net.Addr   // the raddr of the incoming connection
+}
+
+func (l *forwardList) add(n, addr string) chan forward {
+	l.Lock()
+	defer l.Unlock()
+	f := forwardEntry{
+		addr:    addr,
+		network: n,
+		c:       make(chan forward, 1),
+	}
+	l.entries = append(l.entries, f)
+	return f.c
+}
+
+// See RFC 4254, section 7.2
+type forwardedTCPPayload struct {
+	Addr       string
+	Port       uint32
+	OriginAddr string
+	OriginPort uint32
+}
+
+// parseTCPAddr parses the originating address from the remote into a *net.TCPAddr.
+func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
+	if port == 0 || port > 65535 {
+		return nil, fmt.Errorf("ssh: port number out of range: %d", port)
+	}
+	ip, err := netip.ParseAddr(addr)
+	if err != nil {
+		return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr)
+	}
+	return &net.TCPAddr{IP: net.IP(ip.AsSlice()), Port: int(port)}, nil
+}
+
+func (l *forwardList) handleChannels(in <-chan NewChannel) {
+	for ch := range in {
+		var (
+			addr    string
+			network string
+			raddr   net.Addr
+			err     error
+		)
+		switch channelType := ch.ChannelType(); channelType {
+		case "forwarded-tcpip":
+			var payload forwardedTCPPayload
+			if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
+				ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
+				continue
+			}
+
+			// RFC 4254 section 7.2 specifies that incoming addresses should
+			// list the address that was connected, in string format. It is the
+			// same address used in the tcpip-forward request. The originator
+			// address is an IP address instead.
+			addr = net.JoinHostPort(payload.Addr, strconv.FormatUint(uint64(payload.Port), 10))
+
+			raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort)
+			if err != nil {
+				ch.Reject(ConnectionFailed, err.Error())
+				continue
+			}
+			network = "tcp"
+		case "forwarded-streamlocal@openssh.com":
+			var payload forwardedStreamLocalPayload
+			if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
+				ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error())
+				continue
+			}
+			addr = payload.SocketPath
+			raddr = &net.UnixAddr{
+				Name: "@",
+				Net:  "unix",
+			}
+			network = "unix"
+		default:
+			panic(fmt.Errorf("ssh: unknown channel type %s", channelType))
+		}
+		if ok := l.forward(network, addr, raddr, ch); !ok {
+			// Section 7.2, implementations MUST reject spurious incoming
+			// connections.
+			ch.Reject(Prohibited, "no forward for address")
+			continue
+		}
+
+	}
+}
+
+// remove removes the forward entry, and the channel feeding its
+// listener.
+func (l *forwardList) remove(n, addr string) {
+	l.Lock()
+	defer l.Unlock()
+	for i, f := range l.entries {
+		if n == f.network && addr == f.addr {
+			l.entries = append(l.entries[:i], l.entries[i+1:]...)
+			close(f.c)
+			return
+		}
+	}
+}
+
+// closeAll closes and clears all forwards.
+func (l *forwardList) closeAll() {
+	l.Lock()
+	defer l.Unlock()
+	for _, f := range l.entries {
+		close(f.c)
+	}
+	l.entries = nil
+}
+
+func (l *forwardList) forward(n, addr string, raddr net.Addr, ch NewChannel) bool {
+	l.Lock()
+	defer l.Unlock()
+	for _, f := range l.entries {
+		if n == f.network && addr == f.addr {
+			f.c <- forward{newCh: ch, raddr: raddr}
+			return true
+		}
+	}
+	return false
+}
+
+type tcpListener struct {
+	laddr *net.TCPAddr
+	addr  string
+
+	conn *Client
+	in   <-chan forward
+}
+
+// Accept waits for and returns the next connection to the listener.
+func (l *tcpListener) Accept() (net.Conn, error) {
+	s, ok := <-l.in
+	if !ok {
+		return nil, io.EOF
+	}
+	ch, incoming, err := s.newCh.Accept()
+	if err != nil {
+		return nil, err
+	}
+	go DiscardRequests(incoming)
+
+	return &chanConn{
+		Channel: ch,
+		laddr:   l.laddr,
+		raddr:   s.raddr,
+	}, nil
+}
+
+// Close closes the listener.
+func (l *tcpListener) Close() error {
+	host, port, err := net.SplitHostPort(l.addr)
+	if err != nil {
+		return err
+	}
+	rport, err := strconv.ParseUint(port, 10, 32)
+	if err != nil {
+		return err
+	}
+	m := channelForwardMsg{
+		host,
+		uint32(rport),
+	}
+
+	// this also closes the listener.
+	l.conn.forwards.remove("tcp", l.addr)
+	ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m))
+	if err == nil && !ok {
+		err = errors.New("ssh: cancel-tcpip-forward failed")
+	}
+	return err
+}
+
+// Addr returns the listener's network address.
+func (l *tcpListener) Addr() net.Addr {
+	return l.laddr
+}
+
+// DialContext initiates a connection to the addr from the remote host.
+//
+// The provided Context must be non-nil. If the context expires before the
+// connection is complete, an error is returned. Once successfully connected,
+// any expiration of the context will not affect the connection.
+//
+// See func Dial for additional information.
+func (c *Client) DialContext(ctx context.Context, n, addr string) (net.Conn, error) {
+	if err := ctx.Err(); err != nil {
+		return nil, err
+	}
+	type connErr struct {
+		conn net.Conn
+		err  error
+	}
+	ch := make(chan connErr)
+	go func() {
+		conn, err := c.Dial(n, addr)
+		select {
+		case ch <- connErr{conn, err}:
+		case <-ctx.Done():
+			if conn != nil {
+				conn.Close()
+			}
+		}
+	}()
+	select {
+	case res := <-ch:
+		return res.conn, res.err
+	case <-ctx.Done():
+		return nil, ctx.Err()
+	}
+}
+
+// Dial initiates a connection to the addr from the remote host.
+// The resulting connection has a zero LocalAddr() and RemoteAddr().
+func (c *Client) Dial(n, addr string) (net.Conn, error) {
+	var ch Channel
+	switch n {
+	case "tcp", "tcp4", "tcp6":
+		// Parse the address into host and numeric port.
+		host, portString, err := net.SplitHostPort(addr)
+		if err != nil {
+			return nil, err
+		}
+		port, err := strconv.ParseUint(portString, 10, 16)
+		if err != nil {
+			return nil, err
+		}
+		ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port))
+		if err != nil {
+			return nil, err
+		}
+		// Use a zero address for local and remote address.
+		zeroAddr := &net.TCPAddr{
+			IP:   net.IPv4zero,
+			Port: 0,
+		}
+		return &chanConn{
+			Channel: ch,
+			laddr:   zeroAddr,
+			raddr:   zeroAddr,
+		}, nil
+	case "unix":
+		var err error
+		ch, err = c.dialStreamLocal(addr)
+		if err != nil {
+			return nil, err
+		}
+		return &chanConn{
+			Channel: ch,
+			laddr: &net.UnixAddr{
+				Name: "@",
+				Net:  "unix",
+			},
+			raddr: &net.UnixAddr{
+				Name: addr,
+				Net:  "unix",
+			},
+		}, nil
+	default:
+		return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
+	}
+}
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is used
+// as the local address for the connection.
+func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) {
+	if laddr == nil {
+		laddr = &net.TCPAddr{
+			IP:   net.IPv4zero,
+			Port: 0,
+		}
+	}
+	ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port)
+	if err != nil {
+		return nil, err
+	}
+	return &chanConn{
+		Channel: ch,
+		laddr:   laddr,
+		raddr:   raddr,
+	}, nil
+}
+
+// RFC 4254 7.2
+type channelOpenDirectMsg struct {
+	raddr string
+	rport uint32
+	laddr string
+	lport uint32
+}
+
+func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) {
+	msg := channelOpenDirectMsg{
+		raddr: raddr,
+		rport: uint32(rport),
+		laddr: laddr,
+		lport: uint32(lport),
+	}
+	ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg))
+	if err != nil {
+		return nil, err
+	}
+	go DiscardRequests(in)
+	return ch, nil
+}
+
+type tcpChan struct {
+	Channel // the backing channel
+}
+
+// chanConn fulfills the net.Conn interface without
+// the tcpChan having to hold laddr or raddr directly.
+type chanConn struct {
+	Channel
+	laddr, raddr net.Addr
+}
+
+// LocalAddr returns the local network address.
+func (t *chanConn) LocalAddr() net.Addr {
+	return t.laddr
+}
+
+// RemoteAddr returns the remote network address.
+func (t *chanConn) RemoteAddr() net.Addr {
+	return t.raddr
+}
+
+// SetDeadline sets the read and write deadlines associated
+// with the connection.
+func (t *chanConn) SetDeadline(deadline time.Time) error {
+	if err := t.SetReadDeadline(deadline); err != nil {
+		return err
+	}
+	return t.SetWriteDeadline(deadline)
+}
+
+// SetReadDeadline sets the read deadline.
+// A zero value for t means Read will not time out.
+// After the deadline, the error from Read will implement net.Error
+// with Timeout() == true.
+func (t *chanConn) SetReadDeadline(deadline time.Time) error {
+	// for compatibility with previous version,
+	// the error message contains "tcpChan"
+	return errors.New("ssh: tcpChan: deadline not supported")
+}
+
+// SetWriteDeadline exists to satisfy the net.Conn interface
+// but is not implemented by this type.  It always returns an error.
+func (t *chanConn) SetWriteDeadline(deadline time.Time) error {
+	return errors.New("ssh: tcpChan: deadline not supported")
+}
diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go
new file mode 100644
index 000000000..fa3dd6a42
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/transport.go
@@ -0,0 +1,377 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"log"
+)
+
+// debugTransport if set, will print packet types as they go over the
+// wire. No message decoding is done, to minimize the impact on timing.
+const debugTransport = false
+
+// packetConn represents a transport that implements packet based
+// operations.
+type packetConn interface {
+	// Encrypt and send a packet of data to the remote peer.
+	writePacket(packet []byte) error
+
+	// Read a packet from the connection. The read is blocking,
+	// i.e. if error is nil, then the returned byte slice is
+	// always non-empty.
+	readPacket() ([]byte, error)
+
+	// Close closes the write-side of the connection.
+	Close() error
+}
+
+// transport is the keyingTransport that implements the SSH packet
+// protocol.
+type transport struct {
+	reader connectionState
+	writer connectionState
+
+	bufReader *bufio.Reader
+	bufWriter *bufio.Writer
+	rand      io.Reader
+	isClient  bool
+	io.Closer
+
+	strictMode     bool
+	initialKEXDone bool
+}
+
+// packetCipher represents a combination of SSH encryption/MAC
+// protocol.  A single instance should be used for one direction only.
+type packetCipher interface {
+	// writeCipherPacket encrypts the packet and writes it to w. The
+	// contents of the packet are generally scrambled.
+	writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
+
+	// readCipherPacket reads and decrypts a packet of data. The
+	// returned packet may be overwritten by future calls of
+	// readPacket.
+	readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error)
+}
+
+// connectionState represents one side (read or write) of the
+// connection. This is necessary because each direction has its own
+// keys, and can even have its own algorithms
+type connectionState struct {
+	packetCipher
+	seqNum           uint32
+	dir              direction
+	pendingKeyChange chan packetCipher
+}
+
+func (t *transport) setStrictMode() error {
+	if t.reader.seqNum != 1 {
+		return errors.New("ssh: sequence number != 1 when strict KEX mode requested")
+	}
+	t.strictMode = true
+	return nil
+}
+
+func (t *transport) setInitialKEXDone() {
+	t.initialKEXDone = true
+}
+
+// prepareKeyChange sets up key material for a keychange. The key changes in
+// both directions are triggered by reading and writing a msgNewKey packet
+// respectively.
+func (t *transport) prepareKeyChange(algs *NegotiatedAlgorithms, kexResult *kexResult) error {
+	ciph, err := newPacketCipher(t.reader.dir, algs.Read, kexResult)
+	if err != nil {
+		return err
+	}
+	t.reader.pendingKeyChange <- ciph
+
+	ciph, err = newPacketCipher(t.writer.dir, algs.Write, kexResult)
+	if err != nil {
+		return err
+	}
+	t.writer.pendingKeyChange <- ciph
+
+	return nil
+}
+
+func (t *transport) printPacket(p []byte, write bool) {
+	if len(p) == 0 {
+		return
+	}
+	who := "server"
+	if t.isClient {
+		who = "client"
+	}
+	what := "read"
+	if write {
+		what = "write"
+	}
+
+	log.Println(what, who, p[0])
+}
+
+// Read and decrypt next packet.
+func (t *transport) readPacket() (p []byte, err error) {
+	for {
+		p, err = t.reader.readPacket(t.bufReader, t.strictMode)
+		if err != nil {
+			break
+		}
+		// in strict mode we pass through DEBUG and IGNORE packets only during the initial KEX
+		if len(p) == 0 || (t.strictMode && !t.initialKEXDone) || (p[0] != msgIgnore && p[0] != msgDebug) {
+			break
+		}
+	}
+	if debugTransport {
+		t.printPacket(p, false)
+	}
+
+	return p, err
+}
+
+func (s *connectionState) readPacket(r *bufio.Reader, strictMode bool) ([]byte, error) {
+	packet, err := s.packetCipher.readCipherPacket(s.seqNum, r)
+	s.seqNum++
+	if err == nil && len(packet) == 0 {
+		err = errors.New("ssh: zero length packet")
+	}
+
+	if len(packet) > 0 {
+		switch packet[0] {
+		case msgNewKeys:
+			select {
+			case cipher := <-s.pendingKeyChange:
+				s.packetCipher = cipher
+				if strictMode {
+					s.seqNum = 0
+				}
+			default:
+				return nil, errors.New("ssh: got bogus newkeys message")
+			}
+
+		case msgDisconnect:
+			// Transform a disconnect message into an
+			// error. Since this is lowest level at which
+			// we interpret message types, doing it here
+			// ensures that we don't have to handle it
+			// elsewhere.
+			var msg disconnectMsg
+			if err := Unmarshal(packet, &msg); err != nil {
+				return nil, err
+			}
+			return nil, &msg
+		}
+	}
+
+	// The packet may point to an internal buffer, so copy the
+	// packet out here.
+	fresh := make([]byte, len(packet))
+	copy(fresh, packet)
+
+	return fresh, err
+}
+
+func (t *transport) writePacket(packet []byte) error {
+	if debugTransport {
+		t.printPacket(packet, true)
+	}
+	return t.writer.writePacket(t.bufWriter, t.rand, packet, t.strictMode)
+}
+
+func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte, strictMode bool) error {
+	changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
+
+	err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet)
+	if err != nil {
+		return err
+	}
+	if err = w.Flush(); err != nil {
+		return err
+	}
+	s.seqNum++
+	if changeKeys {
+		select {
+		case cipher := <-s.pendingKeyChange:
+			s.packetCipher = cipher
+			if strictMode {
+				s.seqNum = 0
+			}
+		default:
+			panic("ssh: no key material for msgNewKeys")
+		}
+	}
+	return err
+}
+
+func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport {
+	t := &transport{
+		bufReader: bufio.NewReader(rwc),
+		bufWriter: bufio.NewWriter(rwc),
+		rand:      rand,
+		reader: connectionState{
+			packetCipher:     &streamPacketCipher{cipher: noneCipher{}},
+			pendingKeyChange: make(chan packetCipher, 1),
+		},
+		writer: connectionState{
+			packetCipher:     &streamPacketCipher{cipher: noneCipher{}},
+			pendingKeyChange: make(chan packetCipher, 1),
+		},
+		Closer: rwc,
+	}
+	t.isClient = isClient
+
+	if isClient {
+		t.reader.dir = serverKeys
+		t.writer.dir = clientKeys
+	} else {
+		t.reader.dir = clientKeys
+		t.writer.dir = serverKeys
+	}
+
+	return t
+}
+
+type direction struct {
+	ivTag     []byte
+	keyTag    []byte
+	macKeyTag []byte
+}
+
+var (
+	serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
+	clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
+)
+
+// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
+// described in RFC 4253, section 6.4. direction should either be serverKeys
+// (to setup server->client keys) or clientKeys (for client->server keys).
+func newPacketCipher(d direction, algs DirectionAlgorithms, kex *kexResult) (packetCipher, error) {
+	cipherMode := cipherModes[algs.Cipher]
+	if cipherMode == nil {
+		return nil, fmt.Errorf("ssh: unsupported cipher %v", algs.Cipher)
+	}
+
+	iv := make([]byte, cipherMode.ivSize)
+	key := make([]byte, cipherMode.keySize)
+
+	generateKeyMaterial(iv, d.ivTag, kex)
+	generateKeyMaterial(key, d.keyTag, kex)
+
+	var macKey []byte
+	if !aeadCiphers[algs.Cipher] {
+		macMode := macModes[algs.MAC]
+		macKey = make([]byte, macMode.keySize)
+		generateKeyMaterial(macKey, d.macKeyTag, kex)
+	}
+
+	return cipherModes[algs.Cipher].create(key, iv, macKey, algs)
+}
+
+// generateKeyMaterial fills out with key material generated from tag, K, H
+// and sessionId, as specified in RFC 4253, section 7.2.
+func generateKeyMaterial(out, tag []byte, r *kexResult) {
+	var digestsSoFar []byte
+
+	h := r.Hash.New()
+	for len(out) > 0 {
+		h.Reset()
+		h.Write(r.K)
+		h.Write(r.H)
+
+		if len(digestsSoFar) == 0 {
+			h.Write(tag)
+			h.Write(r.SessionID)
+		} else {
+			h.Write(digestsSoFar)
+		}
+
+		digest := h.Sum(nil)
+		n := copy(out, digest)
+		out = out[n:]
+		if len(out) > 0 {
+			digestsSoFar = append(digestsSoFar, digest...)
+		}
+	}
+}
+
+const packageVersion = "SSH-2.0-Go"
+
+// Sends and receives a version line.  The versionLine string should
+// be US ASCII, start with "SSH-2.0-", and should not include a
+// newline. exchangeVersions returns the other side's version line.
+func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) {
+	// Contrary to the RFC, we do not ignore lines that don't
+	// start with "SSH-2.0-" to make the library usable with
+	// nonconforming servers.
+	for _, c := range versionLine {
+		// The spec disallows non US-ASCII chars, and
+		// specifically forbids null chars.
+		if c < 32 {
+			return nil, errors.New("ssh: junk character in version line")
+		}
+	}
+	if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil {
+		return
+	}
+
+	them, err = readVersion(rw)
+	return them, err
+}
+
+// maxVersionStringBytes is the maximum number of bytes that we'll
+// accept as a version string. RFC 4253 section 4.2 limits this at 255
+// chars
+const maxVersionStringBytes = 255
+
+// Read version string as specified by RFC 4253, section 4.2.
+func readVersion(r io.Reader) ([]byte, error) {
+	versionString := make([]byte, 0, 64)
+	var ok bool
+	var buf [1]byte
+
+	for length := 0; length < maxVersionStringBytes; length++ {
+		_, err := io.ReadFull(r, buf[:])
+		if err != nil {
+			return nil, err
+		}
+		// The RFC says that the version should be terminated with \r\n
+		// but several SSH servers actually only send a \n.
+		if buf[0] == '\n' {
+			if !bytes.HasPrefix(versionString, []byte("SSH-")) {
+				// RFC 4253 says we need to ignore all version string lines
+				// except the one containing the SSH version (provided that
+				// all the lines do not exceed 255 bytes in total).
+				versionString = versionString[:0]
+				continue
+			}
+			ok = true
+			break
+		}
+
+		// non ASCII chars are disallowed, but we are lenient,
+		// since Go doesn't use null-terminated strings.
+
+		// The RFC allows a comment after a space, however,
+		// all of it (version and comments) goes into the
+		// session hash.
+		versionString = append(versionString, buf[0])
+	}
+
+	if !ok {
+		return nil, errors.New("ssh: overflow reading version string")
+	}
+
+	// There might be a '\r' on the end which we should remove.
+	if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
+		versionString = versionString[:len(versionString)-1]
+	}
+	return versionString, nil
+}
diff --git a/vendor/golang.org/x/text/cases/cases.go b/vendor/golang.org/x/text/cases/cases.go
new file mode 100644
index 000000000..752cdf031
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/cases.go
@@ -0,0 +1,162 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go gen_trieval.go
+
+// Package cases provides general and language-specific case mappers.
+package cases // import "golang.org/x/text/cases"
+
+import (
+	"golang.org/x/text/language"
+	"golang.org/x/text/transform"
+)
+
+// References:
+// - Unicode Reference Manual Chapter 3.13, 4.2, and 5.18.
+// - https://www.unicode.org/reports/tr29/
+// - https://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt
+// - https://www.unicode.org/Public/6.3.0/ucd/SpecialCasing.txt
+// - https://www.unicode.org/Public/6.3.0/ucd/DerivedCoreProperties.txt
+// - https://www.unicode.org/Public/6.3.0/ucd/auxiliary/WordBreakProperty.txt
+// - https://www.unicode.org/Public/6.3.0/ucd/auxiliary/WordBreakTest.txt
+// - http://userguide.icu-project.org/transforms/casemappings
+
+// TODO:
+// - Case folding
+// - Wide and Narrow?
+// - Segmenter option for title casing.
+// - ASCII fast paths
+// - Encode Soft-Dotted property within trie somehow.
+
+// A Caser transforms given input to a certain case. It implements
+// transform.Transformer.
+//
+// A Caser may be stateful and should therefore not be shared between
+// goroutines.
+type Caser struct {
+	t transform.SpanningTransformer
+}
+
+// Bytes returns a new byte slice with the result of converting b to the case
+// form implemented by c.
+func (c Caser) Bytes(b []byte) []byte {
+	b, _, _ = transform.Bytes(c.t, b)
+	return b
+}
+
+// String returns a string with the result of transforming s to the case form
+// implemented by c.
+func (c Caser) String(s string) string {
+	s, _, _ = transform.String(c.t, s)
+	return s
+}
+
+// Reset resets the Caser to be reused for new input after a previous call to
+// Transform.
+func (c Caser) Reset() { c.t.Reset() }
+
+// Transform implements the transform.Transformer interface and transforms the
+// given input to the case form implemented by c.
+func (c Caser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	return c.t.Transform(dst, src, atEOF)
+}
+
+// Span implements the transform.SpanningTransformer interface.
+func (c Caser) Span(src []byte, atEOF bool) (n int, err error) {
+	return c.t.Span(src, atEOF)
+}
+
+// Upper returns a Caser for language-specific uppercasing.
+func Upper(t language.Tag, opts ...Option) Caser {
+	return Caser{makeUpper(t, getOpts(opts...))}
+}
+
+// Lower returns a Caser for language-specific lowercasing.
+func Lower(t language.Tag, opts ...Option) Caser {
+	return Caser{makeLower(t, getOpts(opts...))}
+}
+
+// Title returns a Caser for language-specific title casing. It uses an
+// approximation of the default Unicode Word Break algorithm.
+func Title(t language.Tag, opts ...Option) Caser {
+	return Caser{makeTitle(t, getOpts(opts...))}
+}
+
+// Fold returns a Caser that implements Unicode case folding. The returned Caser
+// is stateless and safe to use concurrently by multiple goroutines.
+//
+// Case folding does not normalize the input and may not preserve a normal form.
+// Use the collate or search package for more convenient and linguistically
+// sound comparisons. Use golang.org/x/text/secure/precis for string comparisons
+// where security aspects are a concern.
+func Fold(opts ...Option) Caser {
+	return Caser{makeFold(getOpts(opts...))}
+}
+
+// An Option is used to modify the behavior of a Caser.
+type Option func(o options) options
+
+// TODO: consider these options to take a boolean as well, like FinalSigma.
+// The advantage of using this approach is that other providers of a lower-case
+// algorithm could set different defaults by prefixing a user-provided slice
+// of options with their own. This is handy, for instance, for the precis
+// package which would override the default to not handle the Greek final sigma.
+
+var (
+	// NoLower disables the lowercasing of non-leading letters for a title
+	// caser.
+	NoLower Option = noLower
+
+	// Compact omits mappings in case folding for characters that would grow the
+	// input. (Unimplemented.)
+	Compact Option = compact
+)
+
+// TODO: option to preserve a normal form, if applicable?
+
+type options struct {
+	noLower bool
+	simple  bool
+
+	// TODO: segmenter, max ignorable, alternative versions, etc.
+
+	ignoreFinalSigma bool
+}
+
+func getOpts(o ...Option) (res options) {
+	for _, f := range o {
+		res = f(res)
+	}
+	return
+}
+
+func noLower(o options) options {
+	o.noLower = true
+	return o
+}
+
+func compact(o options) options {
+	o.simple = true
+	return o
+}
+
+// HandleFinalSigma specifies whether the special handling of Greek final sigma
+// should be enabled. Unicode prescribes handling the Greek final sigma for all
+// locales, but standards like IDNA and PRECIS override this default.
+func HandleFinalSigma(enable bool) Option {
+	if enable {
+		return handleFinalSigma
+	}
+	return ignoreFinalSigma
+}
+
+func ignoreFinalSigma(o options) options {
+	o.ignoreFinalSigma = true
+	return o
+}
+
+func handleFinalSigma(o options) options {
+	o.ignoreFinalSigma = false
+	return o
+}
diff --git a/vendor/golang.org/x/text/cases/context.go b/vendor/golang.org/x/text/cases/context.go
new file mode 100644
index 000000000..a28f45d7b
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/context.go
@@ -0,0 +1,376 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cases
+
+import "golang.org/x/text/transform"
+
+// A context is used for iterating over source bytes, fetching case info and
+// writing to a destination buffer.
+//
+// Casing operations may need more than one rune of context to decide how a rune
+// should be cased. Casing implementations should call checkpoint on context
+// whenever it is known to be safe to return the runes processed so far.
+//
+// It is recommended for implementations to not allow for more than 30 case
+// ignorables as lookahead (analogous to the limit in norm) and to use state if
+// unbounded lookahead is needed for cased runes.
+type context struct {
+	dst, src []byte
+	atEOF    bool
+
+	pDst int // pDst points past the last written rune in dst.
+	pSrc int // pSrc points to the start of the currently scanned rune.
+
+	// checkpoints safe to return in Transform, where nDst <= pDst and nSrc <= pSrc.
+	nDst, nSrc int
+	err        error
+
+	sz   int  // size of current rune
+	info info // case information of currently scanned rune
+
+	// State preserved across calls to Transform.
+	isMidWord bool // false if next cased letter needs to be title-cased.
+}
+
+func (c *context) Reset() {
+	c.isMidWord = false
+}
+
+// ret returns the return values for the Transform method. It checks whether
+// there were insufficient bytes in src to complete and introduces an error
+// accordingly, if necessary.
+func (c *context) ret() (nDst, nSrc int, err error) {
+	if c.err != nil || c.nSrc == len(c.src) {
+		return c.nDst, c.nSrc, c.err
+	}
+	// This point is only reached by mappers if there was no short destination
+	// buffer. This means that the source buffer was exhausted and that c.sz was
+	// set to 0 by next.
+	if c.atEOF && c.pSrc == len(c.src) {
+		return c.pDst, c.pSrc, nil
+	}
+	return c.nDst, c.nSrc, transform.ErrShortSrc
+}
+
+// retSpan returns the return values for the Span method. It checks whether
+// there were insufficient bytes in src to complete and introduces an error
+// accordingly, if necessary.
+func (c *context) retSpan() (n int, err error) {
+	_, nSrc, err := c.ret()
+	return nSrc, err
+}
+
+// checkpoint sets the return value buffer points for Transform to the current
+// positions.
+func (c *context) checkpoint() {
+	if c.err == nil {
+		c.nDst, c.nSrc = c.pDst, c.pSrc+c.sz
+	}
+}
+
+// unreadRune causes the last rune read by next to be reread on the next
+// invocation of next. Only one unreadRune may be called after a call to next.
+func (c *context) unreadRune() {
+	c.sz = 0
+}
+
+func (c *context) next() bool {
+	c.pSrc += c.sz
+	if c.pSrc == len(c.src) || c.err != nil {
+		c.info, c.sz = 0, 0
+		return false
+	}
+	v, sz := trie.lookup(c.src[c.pSrc:])
+	c.info, c.sz = info(v), sz
+	if c.sz == 0 {
+		if c.atEOF {
+			// A zero size means we have an incomplete rune. If we are atEOF,
+			// this means it is an illegal rune, which we will consume one
+			// byte at a time.
+			c.sz = 1
+		} else {
+			c.err = transform.ErrShortSrc
+			return false
+		}
+	}
+	return true
+}
+
+// writeBytes adds bytes to dst.
+func (c *context) writeBytes(b []byte) bool {
+	if len(c.dst)-c.pDst < len(b) {
+		c.err = transform.ErrShortDst
+		return false
+	}
+	// This loop is faster than using copy.
+	for _, ch := range b {
+		c.dst[c.pDst] = ch
+		c.pDst++
+	}
+	return true
+}
+
+// writeString writes the given string to dst.
+func (c *context) writeString(s string) bool {
+	if len(c.dst)-c.pDst < len(s) {
+		c.err = transform.ErrShortDst
+		return false
+	}
+	// This loop is faster than using copy.
+	for i := 0; i < len(s); i++ {
+		c.dst[c.pDst] = s[i]
+		c.pDst++
+	}
+	return true
+}
+
+// copy writes the current rune to dst.
+func (c *context) copy() bool {
+	return c.writeBytes(c.src[c.pSrc : c.pSrc+c.sz])
+}
+
+// copyXOR copies the current rune to dst and modifies it by applying the XOR
+// pattern of the case info. It is the responsibility of the caller to ensure
+// that this is a rune with a XOR pattern defined.
+func (c *context) copyXOR() bool {
+	if !c.copy() {
+		return false
+	}
+	if c.info&xorIndexBit == 0 {
+		// Fast path for 6-bit XOR pattern, which covers most cases.
+		c.dst[c.pDst-1] ^= byte(c.info >> xorShift)
+	} else {
+		// Interpret XOR bits as an index.
+		// TODO: test performance for unrolling this loop. Verify that we have
+		// at least two bytes and at most three.
+		idx := c.info >> xorShift
+		for p := c.pDst - 1; ; p-- {
+			c.dst[p] ^= xorData[idx]
+			idx--
+			if xorData[idx] == 0 {
+				break
+			}
+		}
+	}
+	return true
+}
+
+// hasPrefix returns true if src[pSrc:] starts with the given string.
+func (c *context) hasPrefix(s string) bool {
+	b := c.src[c.pSrc:]
+	if len(b) < len(s) {
+		return false
+	}
+	for i, c := range b[:len(s)] {
+		if c != s[i] {
+			return false
+		}
+	}
+	return true
+}
+
+// caseType returns an info with only the case bits, normalized to either
+// cLower, cUpper, cTitle or cUncased.
+func (c *context) caseType() info {
+	cm := c.info & 0x7
+	if cm < 4 {
+		return cm
+	}
+	if cm >= cXORCase {
+		// xor the last bit of the rune with the case type bits.
+		b := c.src[c.pSrc+c.sz-1]
+		return info(b&1) ^ cm&0x3
+	}
+	if cm == cIgnorableCased {
+		return cLower
+	}
+	return cUncased
+}
+
+// lower writes the lowercase version of the current rune to dst.
+func lower(c *context) bool {
+	ct := c.caseType()
+	if c.info&hasMappingMask == 0 || ct == cLower {
+		return c.copy()
+	}
+	if c.info&exceptionBit == 0 {
+		return c.copyXOR()
+	}
+	e := exceptions[c.info>>exceptionShift:]
+	offset := 2 + e[0]&lengthMask // size of header + fold string
+	if nLower := (e[1] >> lengthBits) & lengthMask; nLower != noChange {
+		return c.writeString(e[offset : offset+nLower])
+	}
+	return c.copy()
+}
+
+func isLower(c *context) bool {
+	ct := c.caseType()
+	if c.info&hasMappingMask == 0 || ct == cLower {
+		return true
+	}
+	if c.info&exceptionBit == 0 {
+		c.err = transform.ErrEndOfSpan
+		return false
+	}
+	e := exceptions[c.info>>exceptionShift:]
+	if nLower := (e[1] >> lengthBits) & lengthMask; nLower != noChange {
+		c.err = transform.ErrEndOfSpan
+		return false
+	}
+	return true
+}
+
+// upper writes the uppercase version of the current rune to dst.
+func upper(c *context) bool {
+	ct := c.caseType()
+	if c.info&hasMappingMask == 0 || ct == cUpper {
+		return c.copy()
+	}
+	if c.info&exceptionBit == 0 {
+		return c.copyXOR()
+	}
+	e := exceptions[c.info>>exceptionShift:]
+	offset := 2 + e[0]&lengthMask // size of header + fold string
+	// Get length of first special case mapping.
+	n := (e[1] >> lengthBits) & lengthMask
+	if ct == cTitle {
+		// The first special case mapping is for lower. Set n to the second.
+		if n == noChange {
+			n = 0
+		}
+		n, e = e[1]&lengthMask, e[n:]
+	}
+	if n != noChange {
+		return c.writeString(e[offset : offset+n])
+	}
+	return c.copy()
+}
+
+// isUpper reports whether the current rune is in upper case.
+func isUpper(c *context) bool {
+	ct := c.caseType()
+	if c.info&hasMappingMask == 0 || ct == cUpper {
+		return true
+	}
+	if c.info&exceptionBit == 0 {
+		c.err = transform.ErrEndOfSpan
+		return false
+	}
+	e := exceptions[c.info>>exceptionShift:]
+	// Get length of first special case mapping.
+	n := (e[1] >> lengthBits) & lengthMask
+	if ct == cTitle {
+		n = e[1] & lengthMask
+	}
+	if n != noChange {
+		c.err = transform.ErrEndOfSpan
+		return false
+	}
+	return true
+}
+
+// title writes the title case version of the current rune to dst.
+func title(c *context) bool {
+	ct := c.caseType()
+	if c.info&hasMappingMask == 0 || ct == cTitle {
+		return c.copy()
+	}
+	if c.info&exceptionBit == 0 {
+		if ct == cLower {
+			return c.copyXOR()
+		}
+		return c.copy()
+	}
+	// Get the exception data.
+	e := exceptions[c.info>>exceptionShift:]
+	offset := 2 + e[0]&lengthMask // size of header + fold string
+
+	nFirst := (e[1] >> lengthBits) & lengthMask
+	if nTitle := e[1] & lengthMask; nTitle != noChange {
+		if nFirst != noChange {
+			e = e[nFirst:]
+		}
+		return c.writeString(e[offset : offset+nTitle])
+	}
+	if ct == cLower && nFirst != noChange {
+		// Use the uppercase version instead.
+		return c.writeString(e[offset : offset+nFirst])
+	}
+	// Already in correct case.
+	return c.copy()
+}
+
+// isTitle reports whether the current rune is in title case.
+func isTitle(c *context) bool {
+	ct := c.caseType()
+	if c.info&hasMappingMask == 0 || ct == cTitle {
+		return true
+	}
+	if c.info&exceptionBit == 0 {
+		if ct == cLower {
+			c.err = transform.ErrEndOfSpan
+			return false
+		}
+		return true
+	}
+	// Get the exception data.
+	e := exceptions[c.info>>exceptionShift:]
+	if nTitle := e[1] & lengthMask; nTitle != noChange {
+		c.err = transform.ErrEndOfSpan
+		return false
+	}
+	nFirst := (e[1] >> lengthBits) & lengthMask
+	if ct == cLower && nFirst != noChange {
+		c.err = transform.ErrEndOfSpan
+		return false
+	}
+	return true
+}
+
+// foldFull writes the foldFull version of the current rune to dst.
+func foldFull(c *context) bool {
+	if c.info&hasMappingMask == 0 {
+		return c.copy()
+	}
+	ct := c.caseType()
+	if c.info&exceptionBit == 0 {
+		if ct != cLower || c.info&inverseFoldBit != 0 {
+			return c.copyXOR()
+		}
+		return c.copy()
+	}
+	e := exceptions[c.info>>exceptionShift:]
+	n := e[0] & lengthMask
+	if n == 0 {
+		if ct == cLower {
+			return c.copy()
+		}
+		n = (e[1] >> lengthBits) & lengthMask
+	}
+	return c.writeString(e[2 : 2+n])
+}
+
+// isFoldFull reports whether the current run is mapped to foldFull
+func isFoldFull(c *context) bool {
+	if c.info&hasMappingMask == 0 {
+		return true
+	}
+	ct := c.caseType()
+	if c.info&exceptionBit == 0 {
+		if ct != cLower || c.info&inverseFoldBit != 0 {
+			c.err = transform.ErrEndOfSpan
+			return false
+		}
+		return true
+	}
+	e := exceptions[c.info>>exceptionShift:]
+	n := e[0] & lengthMask
+	if n == 0 && ct == cLower {
+		return true
+	}
+	c.err = transform.ErrEndOfSpan
+	return false
+}
diff --git a/vendor/golang.org/x/text/cases/fold.go b/vendor/golang.org/x/text/cases/fold.go
new file mode 100644
index 000000000..85cc434fa
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/fold.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cases
+
+import "golang.org/x/text/transform"
+
+type caseFolder struct{ transform.NopResetter }
+
+// caseFolder implements the Transformer interface for doing case folding.
+func (t *caseFolder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	c := context{dst: dst, src: src, atEOF: atEOF}
+	for c.next() {
+		foldFull(&c)
+		c.checkpoint()
+	}
+	return c.ret()
+}
+
+func (t *caseFolder) Span(src []byte, atEOF bool) (n int, err error) {
+	c := context{src: src, atEOF: atEOF}
+	for c.next() && isFoldFull(&c) {
+		c.checkpoint()
+	}
+	return c.retSpan()
+}
+
+func makeFold(o options) transform.SpanningTransformer {
+	// TODO: Special case folding, through option Language, Special/Turkic, or
+	// both.
+	// TODO: Implement Compact options.
+	return &caseFolder{}
+}
diff --git a/vendor/golang.org/x/text/cases/icu.go b/vendor/golang.org/x/text/cases/icu.go
new file mode 100644
index 000000000..db7c237cc
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/icu.go
@@ -0,0 +1,61 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build icu
+
+package cases
+
+// Ideally these functions would be defined in a test file, but go test doesn't
+// allow CGO in tests. The build tag should ensure either way that these
+// functions will not end up in the package.
+
+// TODO: Ensure that the correct ICU version is set.
+
+/*
+#cgo LDFLAGS: -licui18n.57 -licuuc.57
+#include <stdlib.h>
+#include <unicode/ustring.h>
+#include <unicode/utypes.h>
+#include <unicode/localpointer.h>
+#include <unicode/ucasemap.h>
+*/
+import "C"
+
+import "unsafe"
+
+func doICU(tag, caser, input string) string {
+	err := C.UErrorCode(0)
+	loc := C.CString(tag)
+	cm := C.ucasemap_open(loc, C.uint32_t(0), &err)
+
+	buf := make([]byte, len(input)*4)
+	dst := (*C.char)(unsafe.Pointer(&buf[0]))
+	src := C.CString(input)
+
+	cn := C.int32_t(0)
+
+	switch caser {
+	case "fold":
+		cn = C.ucasemap_utf8FoldCase(cm,
+			dst, C.int32_t(len(buf)),
+			src, C.int32_t(len(input)),
+			&err)
+	case "lower":
+		cn = C.ucasemap_utf8ToLower(cm,
+			dst, C.int32_t(len(buf)),
+			src, C.int32_t(len(input)),
+			&err)
+	case "upper":
+		cn = C.ucasemap_utf8ToUpper(cm,
+			dst, C.int32_t(len(buf)),
+			src, C.int32_t(len(input)),
+			&err)
+	case "title":
+		cn = C.ucasemap_utf8ToTitle(cm,
+			dst, C.int32_t(len(buf)),
+			src, C.int32_t(len(input)),
+			&err)
+	}
+	return string(buf[:cn])
+}
diff --git a/vendor/golang.org/x/text/cases/info.go b/vendor/golang.org/x/text/cases/info.go
new file mode 100644
index 000000000..87a7c3e95
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/info.go
@@ -0,0 +1,82 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cases
+
+func (c info) cccVal() info {
+	if c&exceptionBit != 0 {
+		return info(exceptions[c>>exceptionShift]) & cccMask
+	}
+	return c & cccMask
+}
+
+func (c info) cccType() info {
+	ccc := c.cccVal()
+	if ccc <= cccZero {
+		return cccZero
+	}
+	return ccc
+}
+
+// TODO: Implement full Unicode breaking algorithm:
+// 1) Implement breaking in separate package.
+// 2) Use the breaker here.
+// 3) Compare table size and performance of using the more generic breaker.
+//
+// Note that we can extend the current algorithm to be much more accurate. This
+// only makes sense, though, if the performance and/or space penalty of using
+// the generic breaker is big. Extra data will only be needed for non-cased
+// runes, which means there are sufficient bits left in the caseType.
+// ICU prohibits breaking in such cases as well.
+
+// For the purpose of title casing we use an approximation of the Unicode Word
+// Breaking algorithm defined in Annex #29:
+// https://www.unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table.
+//
+// For our approximation, we group the Word Break types into the following
+// categories, with associated rules:
+//
+// 1) Letter:
+//    ALetter, Hebrew_Letter, Numeric, ExtendNumLet, Extend, Format_FE, ZWJ.
+//    Rule: Never break between consecutive runes of this category.
+//
+// 2) Mid:
+//    MidLetter, MidNumLet, Single_Quote.
+//    (Cf. case-ignorable: MidLetter, MidNumLet, Single_Quote or cat is Mn,
+//    Me, Cf, Lm or Sk).
+//    Rule: Don't break between Letter and Mid, but break between two Mids.
+//
+// 3) Break:
+//    Any other category: NewLine, MidNum, CR, LF, Double_Quote, Katakana, and
+//    Other.
+//    These categories should always result in a break between two cased letters.
+//    Rule: Always break.
+//
+// Note 1: the Katakana and MidNum categories can, in esoteric cases, result in
+// preventing a break between two cased letters. For now we will ignore this
+// (e.g. [ALetter] [ExtendNumLet] [Katakana] [ExtendNumLet] [ALetter] and
+// [ALetter] [Numeric] [MidNum] [Numeric] [ALetter].)
+//
+// Note 2: the rule for Mid is very approximate, but works in most cases. To
+// improve, we could store the categories in the trie value and use a FA to
+// manage breaks. See TODO comment above.
+//
+// Note 3: according to the spec, it is possible for the Extend category to
+// introduce breaks between other categories grouped in Letter. However, this
+// is undesirable for our purposes. ICU prevents breaks in such cases as well.
+
+// isBreak returns whether this rune should introduce a break.
+func (c info) isBreak() bool {
+	return c.cccVal() == cccBreak
+}
+
+// isLetter returns whether the rune is of break type ALetter, Hebrew_Letter,
+// Numeric, ExtendNumLet, or Extend.
+func (c info) isLetter() bool {
+	ccc := c.cccVal()
+	if ccc == cccZero {
+		return !c.isCaseIgnorable()
+	}
+	return ccc != cccBreak
+}
diff --git a/vendor/golang.org/x/text/cases/map.go b/vendor/golang.org/x/text/cases/map.go
new file mode 100644
index 000000000..51a683092
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/map.go
@@ -0,0 +1,816 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cases
+
+// This file contains the definitions of case mappings for all supported
+// languages. The rules for the language-specific tailorings were taken and
+// modified from the CLDR transform definitions in common/transforms.
+
+import (
+	"strings"
+	"unicode"
+	"unicode/utf8"
+
+	"golang.org/x/text/internal"
+	"golang.org/x/text/language"
+	"golang.org/x/text/transform"
+	"golang.org/x/text/unicode/norm"
+)
+
+// A mapFunc takes a context set to the current rune and writes the mapped
+// version to the same context. It may advance the context to the next rune. It
+// returns whether a checkpoint is possible: whether the pDst bytes written to
+// dst so far won't need changing as we see more source bytes.
+type mapFunc func(*context) bool
+
+// A spanFunc takes a context set to the current rune and returns whether this
+// rune would be altered when written to the output. It may advance the context
+// to the next rune. It returns whether a checkpoint is possible.
+type spanFunc func(*context) bool
+
+// maxIgnorable defines the maximum number of ignorables to consider for
+// lookahead operations.
+const maxIgnorable = 30
+
+// supported lists the language tags for which we have tailorings.
+const supported = "und af az el lt nl tr"
+
+func init() {
+	tags := []language.Tag{}
+	for _, s := range strings.Split(supported, " ") {
+		tags = append(tags, language.MustParse(s))
+	}
+	matcher = internal.NewInheritanceMatcher(tags)
+	Supported = language.NewCoverage(tags)
+}
+
+var (
+	matcher *internal.InheritanceMatcher
+
+	Supported language.Coverage
+
+	// We keep the following lists separate, instead of having a single per-
+	// language struct, to give the compiler a chance to remove unused code.
+
+	// Some uppercase mappers are stateless, so we can precompute the
+	// Transformers and save a bit on runtime allocations.
+	upperFunc = []struct {
+		upper mapFunc
+		span  spanFunc
+	}{
+		{nil, nil},                  // und
+		{nil, nil},                  // af
+		{aztrUpper(upper), isUpper}, // az
+		{elUpper, noSpan},           // el
+		{ltUpper(upper), noSpan},    // lt
+		{nil, nil},                  // nl
+		{aztrUpper(upper), isUpper}, // tr
+	}
+
+	undUpper            transform.SpanningTransformer = &undUpperCaser{}
+	undLower            transform.SpanningTransformer = &undLowerCaser{}
+	undLowerIgnoreSigma transform.SpanningTransformer = &undLowerIgnoreSigmaCaser{}
+
+	lowerFunc = []mapFunc{
+		nil,       // und
+		nil,       // af
+		aztrLower, // az
+		nil,       // el
+		ltLower,   // lt
+		nil,       // nl
+		aztrLower, // tr
+	}
+
+	titleInfos = []struct {
+		title     mapFunc
+		lower     mapFunc
+		titleSpan spanFunc
+		rewrite   func(*context)
+	}{
+		{title, lower, isTitle, nil},                // und
+		{title, lower, isTitle, afnlRewrite},        // af
+		{aztrUpper(title), aztrLower, isTitle, nil}, // az
+		{title, lower, isTitle, nil},                // el
+		{ltUpper(title), ltLower, noSpan, nil},      // lt
+		{nlTitle, lower, nlTitleSpan, afnlRewrite},  // nl
+		{aztrUpper(title), aztrLower, isTitle, nil}, // tr
+	}
+)
+
+func makeUpper(t language.Tag, o options) transform.SpanningTransformer {
+	_, i, _ := matcher.Match(t)
+	f := upperFunc[i].upper
+	if f == nil {
+		return undUpper
+	}
+	return &simpleCaser{f: f, span: upperFunc[i].span}
+}
+
+func makeLower(t language.Tag, o options) transform.SpanningTransformer {
+	_, i, _ := matcher.Match(t)
+	f := lowerFunc[i]
+	if f == nil {
+		if o.ignoreFinalSigma {
+			return undLowerIgnoreSigma
+		}
+		return undLower
+	}
+	if o.ignoreFinalSigma {
+		return &simpleCaser{f: f, span: isLower}
+	}
+	return &lowerCaser{
+		first:   f,
+		midWord: finalSigma(f),
+	}
+}
+
+func makeTitle(t language.Tag, o options) transform.SpanningTransformer {
+	_, i, _ := matcher.Match(t)
+	x := &titleInfos[i]
+	lower := x.lower
+	if o.noLower {
+		lower = (*context).copy
+	} else if !o.ignoreFinalSigma {
+		lower = finalSigma(lower)
+	}
+	return &titleCaser{
+		title:     x.title,
+		lower:     lower,
+		titleSpan: x.titleSpan,
+		rewrite:   x.rewrite,
+	}
+}
+
+func noSpan(c *context) bool {
+	c.err = transform.ErrEndOfSpan
+	return false
+}
+
+// TODO: consider a similar special case for the fast majority lower case. This
+// is a bit more involved so will require some more precise benchmarking to
+// justify it.
+
+type undUpperCaser struct{ transform.NopResetter }
+
+// undUpperCaser implements the Transformer interface for doing an upper case
+// mapping for the root locale (und). It eliminates the need for an allocation
+// as it prevents escaping by not using function pointers.
+func (t undUpperCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	c := context{dst: dst, src: src, atEOF: atEOF}
+	for c.next() {
+		upper(&c)
+		c.checkpoint()
+	}
+	return c.ret()
+}
+
+func (t undUpperCaser) Span(src []byte, atEOF bool) (n int, err error) {
+	c := context{src: src, atEOF: atEOF}
+	for c.next() && isUpper(&c) {
+		c.checkpoint()
+	}
+	return c.retSpan()
+}
+
+// undLowerIgnoreSigmaCaser implements the Transformer interface for doing
+// a lower case mapping for the root locale (und) ignoring final sigma
+// handling. This casing algorithm is used in some performance-critical packages
+// like secure/precis and x/net/http/idna, which warrants its special-casing.
+type undLowerIgnoreSigmaCaser struct{ transform.NopResetter }
+
+func (t undLowerIgnoreSigmaCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	c := context{dst: dst, src: src, atEOF: atEOF}
+	for c.next() && lower(&c) {
+		c.checkpoint()
+	}
+	return c.ret()
+
+}
+
+// Span implements a generic lower-casing. This is possible as isLower works
+// for all lowercasing variants. All lowercase variants only vary in how they
+// transform a non-lowercase letter. They will never change an already lowercase
+// letter. In addition, there is no state.
+func (t undLowerIgnoreSigmaCaser) Span(src []byte, atEOF bool) (n int, err error) {
+	c := context{src: src, atEOF: atEOF}
+	for c.next() && isLower(&c) {
+		c.checkpoint()
+	}
+	return c.retSpan()
+}
+
+type simpleCaser struct {
+	context
+	f    mapFunc
+	span spanFunc
+}
+
+// simpleCaser implements the Transformer interface for doing a case operation
+// on a rune-by-rune basis.
+func (t *simpleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	c := context{dst: dst, src: src, atEOF: atEOF}
+	for c.next() && t.f(&c) {
+		c.checkpoint()
+	}
+	return c.ret()
+}
+
+func (t *simpleCaser) Span(src []byte, atEOF bool) (n int, err error) {
+	c := context{src: src, atEOF: atEOF}
+	for c.next() && t.span(&c) {
+		c.checkpoint()
+	}
+	return c.retSpan()
+}
+
+// undLowerCaser implements the Transformer interface for doing a lower case
+// mapping for the root locale (und) ignoring final sigma handling. This casing
+// algorithm is used in some performance-critical packages like secure/precis
+// and x/net/http/idna, which warrants its special-casing.
+type undLowerCaser struct{ transform.NopResetter }
+
+func (t undLowerCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	c := context{dst: dst, src: src, atEOF: atEOF}
+
+	for isInterWord := true; c.next(); {
+		if isInterWord {
+			if c.info.isCased() {
+				if !lower(&c) {
+					break
+				}
+				isInterWord = false
+			} else if !c.copy() {
+				break
+			}
+		} else {
+			if c.info.isNotCasedAndNotCaseIgnorable() {
+				if !c.copy() {
+					break
+				}
+				isInterWord = true
+			} else if !c.hasPrefix("Σ") {
+				if !lower(&c) {
+					break
+				}
+			} else if !finalSigmaBody(&c) {
+				break
+			}
+		}
+		c.checkpoint()
+	}
+	return c.ret()
+}
+
+func (t undLowerCaser) Span(src []byte, atEOF bool) (n int, err error) {
+	c := context{src: src, atEOF: atEOF}
+	for c.next() && isLower(&c) {
+		c.checkpoint()
+	}
+	return c.retSpan()
+}
+
+// lowerCaser implements the Transformer interface. The default Unicode lower
+// casing requires different treatment for the first and subsequent characters
+// of a word, most notably to handle the Greek final Sigma.
+type lowerCaser struct {
+	undLowerIgnoreSigmaCaser
+
+	context
+
+	first, midWord mapFunc
+}
+
+func (t *lowerCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	t.context = context{dst: dst, src: src, atEOF: atEOF}
+	c := &t.context
+
+	for isInterWord := true; c.next(); {
+		if isInterWord {
+			if c.info.isCased() {
+				if !t.first(c) {
+					break
+				}
+				isInterWord = false
+			} else if !c.copy() {
+				break
+			}
+		} else {
+			if c.info.isNotCasedAndNotCaseIgnorable() {
+				if !c.copy() {
+					break
+				}
+				isInterWord = true
+			} else if !t.midWord(c) {
+				break
+			}
+		}
+		c.checkpoint()
+	}
+	return c.ret()
+}
+
+// titleCaser implements the Transformer interface. Title casing algorithms
+// distinguish between the first letter of a word and subsequent letters of the
+// same word. It uses state to avoid requiring a potentially infinite lookahead.
+type titleCaser struct {
+	context
+
+	// rune mappings used by the actual casing algorithms.
+	title     mapFunc
+	lower     mapFunc
+	titleSpan spanFunc
+
+	rewrite func(*context)
+}
+
+// Transform implements the standard Unicode title case algorithm as defined in
+// Chapter 3 of The Unicode Standard:
+// toTitlecase(X): Find the word boundaries in X according to Unicode Standard
+// Annex #29, "Unicode Text Segmentation." For each word boundary, find the
+// first cased character F following the word boundary. If F exists, map F to
+// Titlecase_Mapping(F); then map all characters C between F and the following
+// word boundary to Lowercase_Mapping(C).
+func (t *titleCaser) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	t.context = context{dst: dst, src: src, atEOF: atEOF, isMidWord: t.isMidWord}
+	c := &t.context
+
+	if !c.next() {
+		return c.ret()
+	}
+
+	for {
+		p := c.info
+		if t.rewrite != nil {
+			t.rewrite(c)
+		}
+
+		wasMid := p.isMid()
+		// Break out of this loop on failure to ensure we do not modify the
+		// state incorrectly.
+		if p.isCased() {
+			if !c.isMidWord {
+				if !t.title(c) {
+					break
+				}
+				c.isMidWord = true
+			} else if !t.lower(c) {
+				break
+			}
+		} else if !c.copy() {
+			break
+		} else if p.isBreak() {
+			c.isMidWord = false
+		}
+
+		// As we save the state of the transformer, it is safe to call
+		// checkpoint after any successful write.
+		if !(c.isMidWord && wasMid) {
+			c.checkpoint()
+		}
+
+		if !c.next() {
+			break
+		}
+		if wasMid && c.info.isMid() {
+			c.isMidWord = false
+		}
+	}
+	return c.ret()
+}
+
+func (t *titleCaser) Span(src []byte, atEOF bool) (n int, err error) {
+	t.context = context{src: src, atEOF: atEOF, isMidWord: t.isMidWord}
+	c := &t.context
+
+	if !c.next() {
+		return c.retSpan()
+	}
+
+	for {
+		p := c.info
+		if t.rewrite != nil {
+			t.rewrite(c)
+		}
+
+		wasMid := p.isMid()
+		// Break out of this loop on failure to ensure we do not modify the
+		// state incorrectly.
+		if p.isCased() {
+			if !c.isMidWord {
+				if !t.titleSpan(c) {
+					break
+				}
+				c.isMidWord = true
+			} else if !isLower(c) {
+				break
+			}
+		} else if p.isBreak() {
+			c.isMidWord = false
+		}
+		// As we save the state of the transformer, it is safe to call
+		// checkpoint after any successful write.
+		if !(c.isMidWord && wasMid) {
+			c.checkpoint()
+		}
+
+		if !c.next() {
+			break
+		}
+		if wasMid && c.info.isMid() {
+			c.isMidWord = false
+		}
+	}
+	return c.retSpan()
+}
+
+// finalSigma adds Greek final Sigma handing to another casing function. It
+// determines whether a lowercased sigma should be σ or ς, by looking ahead for
+// case-ignorables and a cased letters.
+func finalSigma(f mapFunc) mapFunc {
+	return func(c *context) bool {
+		if !c.hasPrefix("Σ") {
+			return f(c)
+		}
+		return finalSigmaBody(c)
+	}
+}
+
+func finalSigmaBody(c *context) bool {
+	// Current rune must be ∑.
+
+	// ::NFD();
+	// # 03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA
+	// Σ } [:case-ignorable:]* [:cased:] → σ;
+	// [:cased:] [:case-ignorable:]* { Σ → ς;
+	// ::Any-Lower;
+	// ::NFC();
+
+	p := c.pDst
+	c.writeString("ς")
+
+	// TODO: we should do this here, but right now this will never have an
+	// effect as this is called when the prefix is Sigma, whereas Dutch and
+	// Afrikaans only test for an apostrophe.
+	//
+	// if t.rewrite != nil {
+	// 	t.rewrite(c)
+	// }
+
+	// We need to do one more iteration after maxIgnorable, as a cased
+	// letter is not an ignorable and may modify the result.
+	wasMid := false
+	for i := 0; i < maxIgnorable+1; i++ {
+		if !c.next() {
+			return false
+		}
+		if !c.info.isCaseIgnorable() {
+			// All Midword runes are also case ignorable, so we are
+			// guaranteed to have a letter or word break here. As we are
+			// unreading the run, there is no need to unset c.isMidWord;
+			// the title caser will handle this.
+			if c.info.isCased() {
+				// p+1 is guaranteed to be in bounds: if writing ς was
+				// successful, p+1 will contain the second byte of ς. If not,
+				// this function will have returned after c.next returned false.
+				c.dst[p+1]++ // ς → σ
+			}
+			c.unreadRune()
+			return true
+		}
+		// A case ignorable may also introduce a word break, so we may need
+		// to continue searching even after detecting a break.
+		isMid := c.info.isMid()
+		if (wasMid && isMid) || c.info.isBreak() {
+			c.isMidWord = false
+		}
+		wasMid = isMid
+		c.copy()
+	}
+	return true
+}
+
+// finalSigmaSpan would be the same as isLower.
+
+// elUpper implements Greek upper casing, which entails removing a predefined
+// set of non-blocked modifiers. Note that these accents should not be removed
+// for title casing!
+// Example: "Οδός" -> "ΟΔΟΣ".
+func elUpper(c *context) bool {
+	// From CLDR:
+	// [:Greek:] [^[:ccc=Not_Reordered:][:ccc=Above:]]*? { [\u0313\u0314\u0301\u0300\u0306\u0342\u0308\u0304] → ;
+	// [:Greek:] [^[:ccc=Not_Reordered:][:ccc=Iota_Subscript:]]*? { \u0345 → ;
+
+	r, _ := utf8.DecodeRune(c.src[c.pSrc:])
+	oldPDst := c.pDst
+	if !upper(c) {
+		return false
+	}
+	if !unicode.Is(unicode.Greek, r) {
+		return true
+	}
+	i := 0
+	// Take the properties of the uppercased rune that is already written to the
+	// destination. This saves us the trouble of having to uppercase the
+	// decomposed rune again.
+	if b := norm.NFD.Properties(c.dst[oldPDst:]).Decomposition(); b != nil {
+		// Restore the destination position and process the decomposed rune.
+		r, sz := utf8.DecodeRune(b)
+		if r <= 0xFF { // See A.6.1
+			return true
+		}
+		c.pDst = oldPDst
+		// Insert the first rune and ignore the modifiers. See A.6.2.
+		c.writeBytes(b[:sz])
+		i = len(b[sz:]) / 2 // Greek modifiers are always of length 2.
+	}
+
+	for ; i < maxIgnorable && c.next(); i++ {
+		switch r, _ := utf8.DecodeRune(c.src[c.pSrc:]); r {
+		// Above and Iota Subscript
+		case 0x0300, // U+0300 COMBINING GRAVE ACCENT
+			0x0301, // U+0301 COMBINING ACUTE ACCENT
+			0x0304, // U+0304 COMBINING MACRON
+			0x0306, // U+0306 COMBINING BREVE
+			0x0308, // U+0308 COMBINING DIAERESIS
+			0x0313, // U+0313 COMBINING COMMA ABOVE
+			0x0314, // U+0314 COMBINING REVERSED COMMA ABOVE
+			0x0342, // U+0342 COMBINING GREEK PERISPOMENI
+			0x0345: // U+0345 COMBINING GREEK YPOGEGRAMMENI
+			// No-op. Gobble the modifier.
+
+		default:
+			switch v, _ := trie.lookup(c.src[c.pSrc:]); info(v).cccType() {
+			case cccZero:
+				c.unreadRune()
+				return true
+
+			// We don't need to test for IotaSubscript as the only rune that
+			// qualifies (U+0345) was already excluded in the switch statement
+			// above. See A.4.
+
+			case cccAbove:
+				return c.copy()
+			default:
+				// Some other modifier. We're still allowed to gobble Greek
+				// modifiers after this.
+				c.copy()
+			}
+		}
+	}
+	return i == maxIgnorable
+}
+
+// TODO: implement elUpperSpan (low-priority: complex and infrequent).
+
+func ltLower(c *context) bool {
+	// From CLDR:
+	// # Introduce an explicit dot above when lowercasing capital I's and J's
+	// # whenever there are more accents above.
+	// # (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek)
+	// # 0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I
+	// # 004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J
+	// # 012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK
+	// # 00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE
+	// # 00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE
+	// # 0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE
+	// ::NFD();
+	// I } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0307;
+	// J } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → j \u0307;
+	// I \u0328 (Į) } [^[:ccc=Not_Reordered:][:ccc=Above:]]* [:ccc=Above:] → i \u0328 \u0307;
+	// I \u0300 (Ì) → i \u0307 \u0300;
+	// I \u0301 (Í) → i \u0307 \u0301;
+	// I \u0303 (Ĩ) → i \u0307 \u0303;
+	// ::Any-Lower();
+	// ::NFC();
+
+	i := 0
+	if r := c.src[c.pSrc]; r < utf8.RuneSelf {
+		lower(c)
+		if r != 'I' && r != 'J' {
+			return true
+		}
+	} else {
+		p := norm.NFD.Properties(c.src[c.pSrc:])
+		if d := p.Decomposition(); len(d) >= 3 && (d[0] == 'I' || d[0] == 'J') {
+			// UTF-8 optimization: the decomposition will only have an above
+			// modifier if the last rune of the decomposition is in [U+300-U+311].
+			// In all other cases, a decomposition starting with I is always
+			// an I followed by modifiers that are not cased themselves. See A.2.
+			if d[1] == 0xCC && d[2] <= 0x91 { // A.2.4.
+				if !c.writeBytes(d[:1]) {
+					return false
+				}
+				c.dst[c.pDst-1] += 'a' - 'A' // lower
+
+				// Assumption: modifier never changes on lowercase. See A.1.
+				// Assumption: all modifiers added have CCC = Above. See A.2.3.
+				return c.writeString("\u0307") && c.writeBytes(d[1:])
+			}
+			// In all other cases the additional modifiers will have a CCC
+			// that is less than 230 (Above). We will insert the U+0307, if
+			// needed, after these modifiers so that a string in FCD form
+			// will remain so. See A.2.2.
+			lower(c)
+			i = 1
+		} else {
+			return lower(c)
+		}
+	}
+
+	for ; i < maxIgnorable && c.next(); i++ {
+		switch c.info.cccType() {
+		case cccZero:
+			c.unreadRune()
+			return true
+		case cccAbove:
+			return c.writeString("\u0307") && c.copy() // See A.1.
+		default:
+			c.copy() // See A.1.
+		}
+	}
+	return i == maxIgnorable
+}
+
+// ltLowerSpan would be the same as isLower.
+
+func ltUpper(f mapFunc) mapFunc {
+	return func(c *context) bool {
+		// Unicode:
+		// 0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE
+		//
+		// From CLDR:
+		// # Remove \u0307 following soft-dotteds (i, j, and the like), with possible
+		// # intervening non-230 marks.
+		// ::NFD();
+		// [:Soft_Dotted:] [^[:ccc=Not_Reordered:][:ccc=Above:]]* { \u0307 → ;
+		// ::Any-Upper();
+		// ::NFC();
+
+		// TODO: See A.5. A soft-dotted rune never has an exception. This would
+		// allow us to overload the exception bit and encode this property in
+		// info. Need to measure performance impact of this.
+		r, _ := utf8.DecodeRune(c.src[c.pSrc:])
+		oldPDst := c.pDst
+		if !f(c) {
+			return false
+		}
+		if !unicode.Is(unicode.Soft_Dotted, r) {
+			return true
+		}
+
+		// We don't need to do an NFD normalization, as a soft-dotted rune never
+		// contains U+0307. See A.3.
+
+		i := 0
+		for ; i < maxIgnorable && c.next(); i++ {
+			switch c.info.cccType() {
+			case cccZero:
+				c.unreadRune()
+				return true
+			case cccAbove:
+				if c.hasPrefix("\u0307") {
+					// We don't do a full NFC, but rather combine runes for
+					// some of the common cases. (Returning NFC or
+					// preserving normal form is neither a requirement nor
+					// a possibility anyway).
+					if !c.next() {
+						return false
+					}
+					if c.dst[oldPDst] == 'I' && c.pDst == oldPDst+1 && c.src[c.pSrc] == 0xcc {
+						s := ""
+						switch c.src[c.pSrc+1] {
+						case 0x80: // U+0300 COMBINING GRAVE ACCENT
+							s = "\u00cc" // U+00CC LATIN CAPITAL LETTER I WITH GRAVE
+						case 0x81: // U+0301 COMBINING ACUTE ACCENT
+							s = "\u00cd" // U+00CD LATIN CAPITAL LETTER I WITH ACUTE
+						case 0x83: // U+0303 COMBINING TILDE
+							s = "\u0128" // U+0128 LATIN CAPITAL LETTER I WITH TILDE
+						case 0x88: // U+0308 COMBINING DIAERESIS
+							s = "\u00cf" // U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS
+						default:
+						}
+						if s != "" {
+							c.pDst = oldPDst
+							return c.writeString(s)
+						}
+					}
+				}
+				return c.copy()
+			default:
+				c.copy()
+			}
+		}
+		return i == maxIgnorable
+	}
+}
+
+// TODO: implement ltUpperSpan (low priority: complex and infrequent).
+
+func aztrUpper(f mapFunc) mapFunc {
+	return func(c *context) bool {
+		// i→İ;
+		if c.src[c.pSrc] == 'i' {
+			return c.writeString("İ")
+		}
+		return f(c)
+	}
+}
+
+func aztrLower(c *context) (done bool) {
+	// From CLDR:
+	// # I and i-dotless; I-dot and i are case pairs in Turkish and Azeri
+	// # 0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+	// İ→i;
+	// # When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i.
+	// # This matches the behavior of the canonically equivalent I-dot_above
+	// # 0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE
+	// # When lowercasing, unless an I is before a dot_above, it turns into a dotless i.
+	// # 0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I
+	// I([^[:ccc=Not_Reordered:][:ccc=Above:]]*)\u0307 → i$1 ;
+	// I→ı ;
+	// ::Any-Lower();
+	if c.hasPrefix("\u0130") { // İ
+		return c.writeString("i")
+	}
+	if c.src[c.pSrc] != 'I' {
+		return lower(c)
+	}
+
+	// We ignore the lower-case I for now, but insert it later when we know
+	// which form we need.
+	start := c.pSrc + c.sz
+
+	i := 0
+Loop:
+	// We check for up to n ignorables before \u0307. As \u0307 is an
+	// ignorable as well, n is maxIgnorable-1.
+	for ; i < maxIgnorable && c.next(); i++ {
+		switch c.info.cccType() {
+		case cccAbove:
+			if c.hasPrefix("\u0307") {
+				return c.writeString("i") && c.writeBytes(c.src[start:c.pSrc]) // ignore U+0307
+			}
+			done = true
+			break Loop
+		case cccZero:
+			c.unreadRune()
+			done = true
+			break Loop
+		default:
+			// We'll write this rune after we know which starter to use.
+		}
+	}
+	if i == maxIgnorable {
+		done = true
+	}
+	return c.writeString("ı") && c.writeBytes(c.src[start:c.pSrc+c.sz]) && done
+}
+
+// aztrLowerSpan would be the same as isLower.
+
+func nlTitle(c *context) bool {
+	// From CLDR:
+	// # Special titlecasing for Dutch initial "ij".
+	// ::Any-Title();
+	// # Fix up Ij at the beginning of a "word" (per Any-Title, not UAX #29)
+	// [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ;
+	if c.src[c.pSrc] != 'I' && c.src[c.pSrc] != 'i' {
+		return title(c)
+	}
+
+	if !c.writeString("I") || !c.next() {
+		return false
+	}
+	if c.src[c.pSrc] == 'j' || c.src[c.pSrc] == 'J' {
+		return c.writeString("J")
+	}
+	c.unreadRune()
+	return true
+}
+
+func nlTitleSpan(c *context) bool {
+	// From CLDR:
+	// # Special titlecasing for Dutch initial "ij".
+	// ::Any-Title();
+	// # Fix up Ij at the beginning of a "word" (per Any-Title, not UAX #29)
+	// [:^WB=ALetter:] [:WB=Extend:]* [[:WB=MidLetter:][:WB=MidNumLet:]]? { Ij } → IJ ;
+	if c.src[c.pSrc] != 'I' {
+		return isTitle(c)
+	}
+	if !c.next() || c.src[c.pSrc] == 'j' {
+		return false
+	}
+	if c.src[c.pSrc] != 'J' {
+		c.unreadRune()
+	}
+	return true
+}
+
+// Not part of CLDR, but see https://unicode.org/cldr/trac/ticket/7078.
+func afnlRewrite(c *context) {
+	if c.hasPrefix("'") || c.hasPrefix("’") {
+		c.isMidWord = true
+	}
+}
diff --git a/vendor/golang.org/x/text/cases/tables15.0.0.go b/vendor/golang.org/x/text/cases/tables15.0.0.go
new file mode 100644
index 000000000..6aa111610
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/tables15.0.0.go
@@ -0,0 +1,2527 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+//go:build !go1.27
+
+package cases
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "15.0.0"
+
+var xorData string = "" + // Size: 213 bytes
+	"\x00\x06\x07\x00\x01?\x00\x0f\x03\x00\x0f\x12\x00\x0f\x1f\x00\x0f\x1d" +
+	"\x00\x01\x13\x00\x0f\x16\x00\x0f\x0b\x00\x0f3\x00\x0f7\x00\x01#\x00\x0f?" +
+	"\x00\x0e'\x00\x0f/\x00\x0e>\x00\x0f*\x00\x0c&\x00\x0c*\x00\x0c;\x00\x0c9" +
+	"\x00\x0c%\x00\x01\x08\x00\x03\x0d\x00\x03\x09\x00\x02\x06\x00\x02\x02" +
+	"\x00\x02\x0c\x00\x01\x00\x00\x01\x03\x00\x01\x01\x00\x01 \x00\x01\x0c" +
+	"\x00\x01\x10\x00\x03\x10\x00\x036 \x00\x037 \x00\x0b#\x10\x00\x0b 0\x00" +
+	"\x0b!\x10\x00\x0b!0\x001\x00\x00\x0b(\x04\x00\x03\x04\x1e\x00\x0b)\x08" +
+	"\x00\x03\x0a\x00\x02:\x00\x02>\x00\x02,\x00\x02\x00\x00\x02\x10\x00\x01<" +
+	"\x00\x01&\x00\x01*\x00\x01.\x00\x010\x003 \x00\x01\x18\x00\x01(\x00\x03'" +
+	"\x00\x03)\x00\x03+\x00\x03/\x00\x03\x19\x00\x03\x1b\x00\x03\x1f\x00\x01" +
+	"\x1e\x00\x01\x22"
+
+var exceptions string = "" + // Size: 2450 bytes
+	"\x00\x12\x12μΜΜ\x12\x12ssSSSs\x13\x18i̇i̇\x10\x09II\x13\x1bʼnʼNʼN\x11" +
+	"\x09sSS\x12\x12ǆǆǅ\x12\x12ǆǆǄ\x10\x12Ǆǅ\x12\x12ǉǉǈ\x12\x12ǉǉǇ\x10\x12Ǉǈ" +
+	"\x12\x12ǌǌǋ\x12\x12ǌǌǊ\x10\x12Ǌǋ\x13\x1bǰJ̌J̌\x12\x12ǳǳǲ\x12\x12ǳǳǱ\x10" +
+	"\x12Ǳǲ\x13\x18ⱥⱥ\x13\x18ⱦⱦ\x10\x1bⱾⱾ\x10\x1bⱿⱿ\x10\x1bⱯⱯ\x10\x1bⱭⱭ\x10" +
+	"\x1bⱰⱰ\x10\x1bꞫꞫ\x10\x1bꞬꞬ\x10\x1bꞍꞍ\x10\x1bꞪꞪ\x10\x1bꞮꞮ\x10\x1bⱢⱢ\x10" +
+	"\x1bꞭꞭ\x10\x1bⱮⱮ\x10\x1bⱤⱤ\x10\x1bꟅꟅ\x10\x1bꞱꞱ\x10\x1bꞲꞲ\x10\x1bꞰꞰ2\x12ι" +
+	"ΙΙ\x166ΐΪ́Ϊ́\x166ΰΫ́Ϋ́\x12\x12σΣΣ\x12\x12βΒΒ\x12\x12θΘΘ\x12\x12" +
+	"φΦΦ\x12\x12πΠΠ\x12\x12κΚΚ\x12\x12ρΡΡ\x12\x12εΕΕ\x14$եւԵՒԵւ\x10\x1bᲐა" +
+	"\x10\x1bᲑბ\x10\x1bᲒგ\x10\x1bᲓდ\x10\x1bᲔე\x10\x1bᲕვ\x10\x1bᲖზ\x10\x1bᲗთ" +
+	"\x10\x1bᲘი\x10\x1bᲙკ\x10\x1bᲚლ\x10\x1bᲛმ\x10\x1bᲜნ\x10\x1bᲝო\x10\x1bᲞპ" +
+	"\x10\x1bᲟჟ\x10\x1bᲠრ\x10\x1bᲡს\x10\x1bᲢტ\x10\x1bᲣუ\x10\x1bᲤფ\x10\x1bᲥქ" +
+	"\x10\x1bᲦღ\x10\x1bᲧყ\x10\x1bᲨშ\x10\x1bᲩჩ\x10\x1bᲪც\x10\x1bᲫძ\x10\x1bᲬწ" +
+	"\x10\x1bᲭჭ\x10\x1bᲮხ\x10\x1bᲯჯ\x10\x1bᲰჰ\x10\x1bᲱჱ\x10\x1bᲲჲ\x10\x1bᲳჳ" +
+	"\x10\x1bᲴჴ\x10\x1bᲵჵ\x10\x1bᲶჶ\x10\x1bᲷჷ\x10\x1bᲸჸ\x10\x1bᲹჹ\x10\x1bᲺჺ" +
+	"\x10\x1bᲽჽ\x10\x1bᲾჾ\x10\x1bᲿჿ\x12\x12вВВ\x12\x12дДД\x12\x12оОО\x12\x12с" +
+	"СС\x12\x12тТТ\x12\x12тТТ\x12\x12ъЪЪ\x12\x12ѣѢѢ\x13\x1bꙋꙊꙊ\x13\x1bẖH̱H̱" +
+	"\x13\x1bẗT̈T̈\x13\x1bẘW̊W̊\x13\x1bẙY̊Y̊\x13\x1baʾAʾAʾ\x13\x1bṡṠṠ\x12" +
+	"\x10ssß\x14$ὐΥ̓Υ̓\x166ὒΥ̓̀Υ̓̀\x166ὔΥ̓́Υ̓́\x166ὖΥ̓͂Υ̓͂\x15+ἀιἈΙᾈ" +
+	"\x15+ἁιἉΙᾉ\x15+ἂιἊΙᾊ\x15+ἃιἋΙᾋ\x15+ἄιἌΙᾌ\x15+ἅιἍΙᾍ\x15+ἆιἎΙᾎ\x15+ἇιἏΙᾏ" +
+	"\x15\x1dἀιᾀἈΙ\x15\x1dἁιᾁἉΙ\x15\x1dἂιᾂἊΙ\x15\x1dἃιᾃἋΙ\x15\x1dἄιᾄἌΙ\x15" +
+	"\x1dἅιᾅἍΙ\x15\x1dἆιᾆἎΙ\x15\x1dἇιᾇἏΙ\x15+ἠιἨΙᾘ\x15+ἡιἩΙᾙ\x15+ἢιἪΙᾚ\x15+ἣι" +
+	"ἫΙᾛ\x15+ἤιἬΙᾜ\x15+ἥιἭΙᾝ\x15+ἦιἮΙᾞ\x15+ἧιἯΙᾟ\x15\x1dἠιᾐἨΙ\x15\x1dἡιᾑἩΙ" +
+	"\x15\x1dἢιᾒἪΙ\x15\x1dἣιᾓἫΙ\x15\x1dἤιᾔἬΙ\x15\x1dἥιᾕἭΙ\x15\x1dἦιᾖἮΙ\x15" +
+	"\x1dἧιᾗἯΙ\x15+ὠιὨΙᾨ\x15+ὡιὩΙᾩ\x15+ὢιὪΙᾪ\x15+ὣιὫΙᾫ\x15+ὤιὬΙᾬ\x15+ὥιὭΙᾭ" +
+	"\x15+ὦιὮΙᾮ\x15+ὧιὯΙᾯ\x15\x1dὠιᾠὨΙ\x15\x1dὡιᾡὩΙ\x15\x1dὢιᾢὪΙ\x15\x1dὣιᾣὫΙ" +
+	"\x15\x1dὤιᾤὬΙ\x15\x1dὥιᾥὭΙ\x15\x1dὦιᾦὮΙ\x15\x1dὧιᾧὯΙ\x15-ὰιᾺΙᾺͅ\x14#αιΑΙ" +
+	"ᾼ\x14$άιΆΙΆͅ\x14$ᾶΑ͂Α͂\x166ᾶιΑ͂Ιᾼ͂\x14\x1cαιᾳΑΙ\x12\x12ιΙΙ\x15-ὴιῊΙ" +
+	"Ὴͅ\x14#ηιΗΙῌ\x14$ήιΉΙΉͅ\x14$ῆΗ͂Η͂\x166ῆιΗ͂Ιῌ͂\x14\x1cηιῃΗΙ\x166ῒΙ" +
+	"̈̀Ϊ̀\x166ΐΪ́Ϊ́\x14$ῖΙ͂Ι͂\x166ῗΪ͂Ϊ͂\x166ῢΫ̀Ϋ̀\x166ΰΫ́Ϋ" +
+	"́\x14$ῤΡ̓Ρ̓\x14$ῦΥ͂Υ͂\x166ῧΫ͂Ϋ͂\x15-ὼιῺΙῺͅ\x14#ωιΩΙῼ\x14$ώιΏΙΏͅ" +
+	"\x14$ῶΩ͂Ω͂\x166ῶιΩ͂Ιῼ͂\x14\x1cωιῳΩΙ\x12\x10ωω\x11\x08kk\x12\x10åå\x12" +
+	"\x10ɫɫ\x12\x10ɽɽ\x10\x12ȺȺ\x10\x12ȾȾ\x12\x10ɑɑ\x12\x10ɱɱ\x12\x10ɐɐ\x12" +
+	"\x10ɒɒ\x12\x10ȿȿ\x12\x10ɀɀ\x12\x10ɥɥ\x12\x10ɦɦ\x12\x10ɜɜ\x12\x10ɡɡ\x12" +
+	"\x10ɬɬ\x12\x10ɪɪ\x12\x10ʞʞ\x12\x10ʇʇ\x12\x10ʝʝ\x12\x10ʂʂ\x12\x12ffFFFf" +
+	"\x12\x12fiFIFi\x12\x12flFLFl\x13\x1bffiFFIFfi\x13\x1bfflFFLFfl\x12\x12st" +
+	"STSt\x12\x12stSTSt\x14$մնՄՆՄն\x14$մեՄԵՄե\x14$միՄԻՄի\x14$վնՎՆՎն\x14$մխՄԽՄ" +
+	"խ"
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *caseTrie) lookup(s []byte) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return caseValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = caseIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = caseIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = caseIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *caseTrie) lookupUnsafe(s []byte) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return caseValues[c0]
+	}
+	i := caseIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = caseIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = caseIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *caseTrie) lookupString(s string) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return caseValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = caseIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = caseIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = caseIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *caseTrie) lookupStringUnsafe(s string) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return caseValues[c0]
+	}
+	i := caseIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = caseIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = caseIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// caseTrie. Total size: 13398 bytes (13.08 KiB). Checksum: 544af6e6b1b70931.
+type caseTrie struct{}
+
+func newCaseTrie(i int) *caseTrie {
+	return &caseTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *caseTrie) lookupValue(n uint32, b byte) uint16 {
+	switch {
+	case n < 22:
+		return uint16(caseValues[n<<6+uint32(b)])
+	default:
+		n -= 22
+		return uint16(sparse.lookup(n, b))
+	}
+}
+
+// caseValues: 24 blocks, 1536 entries, 3072 bytes
+// The third block is the zero block.
+var caseValues = [1536]uint16{
+	// Block 0x0, offset 0x0
+	0x27: 0x0054,
+	0x2e: 0x0054,
+	0x30: 0x0010, 0x31: 0x0010, 0x32: 0x0010, 0x33: 0x0010, 0x34: 0x0010, 0x35: 0x0010,
+	0x36: 0x0010, 0x37: 0x0010, 0x38: 0x0010, 0x39: 0x0010, 0x3a: 0x0054,
+	// Block 0x1, offset 0x40
+	0x41: 0x2013, 0x42: 0x2013, 0x43: 0x2013, 0x44: 0x2013, 0x45: 0x2013,
+	0x46: 0x2013, 0x47: 0x2013, 0x48: 0x2013, 0x49: 0x2013, 0x4a: 0x2013, 0x4b: 0x2013,
+	0x4c: 0x2013, 0x4d: 0x2013, 0x4e: 0x2013, 0x4f: 0x2013, 0x50: 0x2013, 0x51: 0x2013,
+	0x52: 0x2013, 0x53: 0x2013, 0x54: 0x2013, 0x55: 0x2013, 0x56: 0x2013, 0x57: 0x2013,
+	0x58: 0x2013, 0x59: 0x2013, 0x5a: 0x2013,
+	0x5e: 0x0004, 0x5f: 0x0010, 0x60: 0x0004, 0x61: 0x2012, 0x62: 0x2012, 0x63: 0x2012,
+	0x64: 0x2012, 0x65: 0x2012, 0x66: 0x2012, 0x67: 0x2012, 0x68: 0x2012, 0x69: 0x2012,
+	0x6a: 0x2012, 0x6b: 0x2012, 0x6c: 0x2012, 0x6d: 0x2012, 0x6e: 0x2012, 0x6f: 0x2012,
+	0x70: 0x2012, 0x71: 0x2012, 0x72: 0x2012, 0x73: 0x2012, 0x74: 0x2012, 0x75: 0x2012,
+	0x76: 0x2012, 0x77: 0x2012, 0x78: 0x2012, 0x79: 0x2012, 0x7a: 0x2012,
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc0: 0x0852, 0xc1: 0x0b53, 0xc2: 0x0113, 0xc3: 0x0112, 0xc4: 0x0113, 0xc5: 0x0112,
+	0xc6: 0x0b53, 0xc7: 0x0f13, 0xc8: 0x0f12, 0xc9: 0x0e53, 0xca: 0x1153, 0xcb: 0x0713,
+	0xcc: 0x0712, 0xcd: 0x0012, 0xce: 0x1453, 0xcf: 0x1753, 0xd0: 0x1a53, 0xd1: 0x0313,
+	0xd2: 0x0312, 0xd3: 0x1d53, 0xd4: 0x2053, 0xd5: 0x2352, 0xd6: 0x2653, 0xd7: 0x2653,
+	0xd8: 0x0113, 0xd9: 0x0112, 0xda: 0x2952, 0xdb: 0x0012, 0xdc: 0x1d53, 0xdd: 0x2c53,
+	0xde: 0x2f52, 0xdf: 0x3253, 0xe0: 0x0113, 0xe1: 0x0112, 0xe2: 0x0113, 0xe3: 0x0112,
+	0xe4: 0x0113, 0xe5: 0x0112, 0xe6: 0x3553, 0xe7: 0x0f13, 0xe8: 0x0f12, 0xe9: 0x3853,
+	0xea: 0x0012, 0xeb: 0x0012, 0xec: 0x0113, 0xed: 0x0112, 0xee: 0x3553, 0xef: 0x1f13,
+	0xf0: 0x1f12, 0xf1: 0x3b53, 0xf2: 0x3e53, 0xf3: 0x0713, 0xf4: 0x0712, 0xf5: 0x0313,
+	0xf6: 0x0312, 0xf7: 0x4153, 0xf8: 0x0113, 0xf9: 0x0112, 0xfa: 0x0012, 0xfb: 0x0010,
+	0xfc: 0x0113, 0xfd: 0x0112, 0xfe: 0x0012, 0xff: 0x4452,
+	// Block 0x4, offset 0x100
+	0x100: 0x0010, 0x101: 0x0010, 0x102: 0x0010, 0x103: 0x0010, 0x104: 0x02db, 0x105: 0x0359,
+	0x106: 0x03da, 0x107: 0x043b, 0x108: 0x04b9, 0x109: 0x053a, 0x10a: 0x059b, 0x10b: 0x0619,
+	0x10c: 0x069a, 0x10d: 0x0313, 0x10e: 0x0312, 0x10f: 0x1f13, 0x110: 0x1f12, 0x111: 0x0313,
+	0x112: 0x0312, 0x113: 0x0713, 0x114: 0x0712, 0x115: 0x0313, 0x116: 0x0312, 0x117: 0x0f13,
+	0x118: 0x0f12, 0x119: 0x0313, 0x11a: 0x0312, 0x11b: 0x0713, 0x11c: 0x0712, 0x11d: 0x1452,
+	0x11e: 0x0113, 0x11f: 0x0112, 0x120: 0x0113, 0x121: 0x0112, 0x122: 0x0113, 0x123: 0x0112,
+	0x124: 0x0113, 0x125: 0x0112, 0x126: 0x0113, 0x127: 0x0112, 0x128: 0x0113, 0x129: 0x0112,
+	0x12a: 0x0113, 0x12b: 0x0112, 0x12c: 0x0113, 0x12d: 0x0112, 0x12e: 0x0113, 0x12f: 0x0112,
+	0x130: 0x06fa, 0x131: 0x07ab, 0x132: 0x0829, 0x133: 0x08aa, 0x134: 0x0113, 0x135: 0x0112,
+	0x136: 0x2353, 0x137: 0x4453, 0x138: 0x0113, 0x139: 0x0112, 0x13a: 0x0113, 0x13b: 0x0112,
+	0x13c: 0x0113, 0x13d: 0x0112, 0x13e: 0x0113, 0x13f: 0x0112,
+	// Block 0x5, offset 0x140
+	0x140: 0x0a8a, 0x141: 0x0313, 0x142: 0x0312, 0x143: 0x0853, 0x144: 0x4753, 0x145: 0x4a53,
+	0x146: 0x0113, 0x147: 0x0112, 0x148: 0x0113, 0x149: 0x0112, 0x14a: 0x0113, 0x14b: 0x0112,
+	0x14c: 0x0113, 0x14d: 0x0112, 0x14e: 0x0113, 0x14f: 0x0112, 0x150: 0x0b0a, 0x151: 0x0b8a,
+	0x152: 0x0c0a, 0x153: 0x0b52, 0x154: 0x0b52, 0x155: 0x0012, 0x156: 0x0e52, 0x157: 0x1152,
+	0x158: 0x0012, 0x159: 0x1752, 0x15a: 0x0012, 0x15b: 0x1a52, 0x15c: 0x0c8a, 0x15d: 0x0012,
+	0x15e: 0x0012, 0x15f: 0x0012, 0x160: 0x1d52, 0x161: 0x0d0a, 0x162: 0x0012, 0x163: 0x2052,
+	0x164: 0x0012, 0x165: 0x0d8a, 0x166: 0x0e0a, 0x167: 0x0012, 0x168: 0x2652, 0x169: 0x2652,
+	0x16a: 0x0e8a, 0x16b: 0x0f0a, 0x16c: 0x0f8a, 0x16d: 0x0012, 0x16e: 0x0012, 0x16f: 0x1d52,
+	0x170: 0x0012, 0x171: 0x100a, 0x172: 0x2c52, 0x173: 0x0012, 0x174: 0x0012, 0x175: 0x3252,
+	0x176: 0x0012, 0x177: 0x0012, 0x178: 0x0012, 0x179: 0x0012, 0x17a: 0x0012, 0x17b: 0x0012,
+	0x17c: 0x0012, 0x17d: 0x108a, 0x17e: 0x0012, 0x17f: 0x0012,
+	// Block 0x6, offset 0x180
+	0x180: 0x3552, 0x181: 0x0012, 0x182: 0x110a, 0x183: 0x3852, 0x184: 0x0012, 0x185: 0x0012,
+	0x186: 0x0012, 0x187: 0x118a, 0x188: 0x3552, 0x189: 0x4752, 0x18a: 0x3b52, 0x18b: 0x3e52,
+	0x18c: 0x4a52, 0x18d: 0x0012, 0x18e: 0x0012, 0x18f: 0x0012, 0x190: 0x0012, 0x191: 0x0012,
+	0x192: 0x4152, 0x193: 0x0012, 0x194: 0x0010, 0x195: 0x0012, 0x196: 0x0012, 0x197: 0x0012,
+	0x198: 0x0012, 0x199: 0x0012, 0x19a: 0x0012, 0x19b: 0x0012, 0x19c: 0x0012, 0x19d: 0x120a,
+	0x19e: 0x128a, 0x19f: 0x0012, 0x1a0: 0x0012, 0x1a1: 0x0012, 0x1a2: 0x0012, 0x1a3: 0x0012,
+	0x1a4: 0x0012, 0x1a5: 0x0012, 0x1a6: 0x0012, 0x1a7: 0x0012, 0x1a8: 0x0012, 0x1a9: 0x0012,
+	0x1aa: 0x0012, 0x1ab: 0x0012, 0x1ac: 0x0012, 0x1ad: 0x0012, 0x1ae: 0x0012, 0x1af: 0x0012,
+	0x1b0: 0x0015, 0x1b1: 0x0015, 0x1b2: 0x0015, 0x1b3: 0x0015, 0x1b4: 0x0015, 0x1b5: 0x0015,
+	0x1b6: 0x0015, 0x1b7: 0x0015, 0x1b8: 0x0015, 0x1b9: 0x0014, 0x1ba: 0x0014, 0x1bb: 0x0014,
+	0x1bc: 0x0014, 0x1bd: 0x0014, 0x1be: 0x0014, 0x1bf: 0x0014,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x0024, 0x1c1: 0x0024, 0x1c2: 0x0024, 0x1c3: 0x0024, 0x1c4: 0x0024, 0x1c5: 0x130d,
+	0x1c6: 0x0024, 0x1c7: 0x0034, 0x1c8: 0x0034, 0x1c9: 0x0034, 0x1ca: 0x0024, 0x1cb: 0x0024,
+	0x1cc: 0x0024, 0x1cd: 0x0034, 0x1ce: 0x0034, 0x1cf: 0x0014, 0x1d0: 0x0024, 0x1d1: 0x0024,
+	0x1d2: 0x0024, 0x1d3: 0x0034, 0x1d4: 0x0034, 0x1d5: 0x0034, 0x1d6: 0x0034, 0x1d7: 0x0024,
+	0x1d8: 0x0034, 0x1d9: 0x0034, 0x1da: 0x0034, 0x1db: 0x0024, 0x1dc: 0x0034, 0x1dd: 0x0034,
+	0x1de: 0x0034, 0x1df: 0x0034, 0x1e0: 0x0034, 0x1e1: 0x0034, 0x1e2: 0x0034, 0x1e3: 0x0024,
+	0x1e4: 0x0024, 0x1e5: 0x0024, 0x1e6: 0x0024, 0x1e7: 0x0024, 0x1e8: 0x0024, 0x1e9: 0x0024,
+	0x1ea: 0x0024, 0x1eb: 0x0024, 0x1ec: 0x0024, 0x1ed: 0x0024, 0x1ee: 0x0024, 0x1ef: 0x0024,
+	0x1f0: 0x0113, 0x1f1: 0x0112, 0x1f2: 0x0113, 0x1f3: 0x0112, 0x1f4: 0x0014, 0x1f5: 0x0004,
+	0x1f6: 0x0113, 0x1f7: 0x0112, 0x1fa: 0x0015, 0x1fb: 0x4d52,
+	0x1fc: 0x5052, 0x1fd: 0x5052, 0x1ff: 0x5353,
+	// Block 0x8, offset 0x200
+	0x204: 0x0004, 0x205: 0x0004,
+	0x206: 0x2a13, 0x207: 0x0054, 0x208: 0x2513, 0x209: 0x2713, 0x20a: 0x2513,
+	0x20c: 0x5653, 0x20e: 0x5953, 0x20f: 0x5c53, 0x210: 0x138a, 0x211: 0x2013,
+	0x212: 0x2013, 0x213: 0x2013, 0x214: 0x2013, 0x215: 0x2013, 0x216: 0x2013, 0x217: 0x2013,
+	0x218: 0x2013, 0x219: 0x2013, 0x21a: 0x2013, 0x21b: 0x2013, 0x21c: 0x2013, 0x21d: 0x2013,
+	0x21e: 0x2013, 0x21f: 0x2013, 0x220: 0x5f53, 0x221: 0x5f53, 0x223: 0x5f53,
+	0x224: 0x5f53, 0x225: 0x5f53, 0x226: 0x5f53, 0x227: 0x5f53, 0x228: 0x5f53, 0x229: 0x5f53,
+	0x22a: 0x5f53, 0x22b: 0x5f53, 0x22c: 0x2a12, 0x22d: 0x2512, 0x22e: 0x2712, 0x22f: 0x2512,
+	0x230: 0x14ca, 0x231: 0x2012, 0x232: 0x2012, 0x233: 0x2012, 0x234: 0x2012, 0x235: 0x2012,
+	0x236: 0x2012, 0x237: 0x2012, 0x238: 0x2012, 0x239: 0x2012, 0x23a: 0x2012, 0x23b: 0x2012,
+	0x23c: 0x2012, 0x23d: 0x2012, 0x23e: 0x2012, 0x23f: 0x2012,
+	// Block 0x9, offset 0x240
+	0x240: 0x5f52, 0x241: 0x5f52, 0x242: 0x160a, 0x243: 0x5f52, 0x244: 0x5f52, 0x245: 0x5f52,
+	0x246: 0x5f52, 0x247: 0x5f52, 0x248: 0x5f52, 0x249: 0x5f52, 0x24a: 0x5f52, 0x24b: 0x5f52,
+	0x24c: 0x5652, 0x24d: 0x5952, 0x24e: 0x5c52, 0x24f: 0x1813, 0x250: 0x168a, 0x251: 0x170a,
+	0x252: 0x0013, 0x253: 0x0013, 0x254: 0x0013, 0x255: 0x178a, 0x256: 0x180a, 0x257: 0x1812,
+	0x258: 0x0113, 0x259: 0x0112, 0x25a: 0x0113, 0x25b: 0x0112, 0x25c: 0x0113, 0x25d: 0x0112,
+	0x25e: 0x0113, 0x25f: 0x0112, 0x260: 0x0113, 0x261: 0x0112, 0x262: 0x0113, 0x263: 0x0112,
+	0x264: 0x0113, 0x265: 0x0112, 0x266: 0x0113, 0x267: 0x0112, 0x268: 0x0113, 0x269: 0x0112,
+	0x26a: 0x0113, 0x26b: 0x0112, 0x26c: 0x0113, 0x26d: 0x0112, 0x26e: 0x0113, 0x26f: 0x0112,
+	0x270: 0x188a, 0x271: 0x190a, 0x272: 0x0b12, 0x273: 0x5352, 0x274: 0x6253, 0x275: 0x198a,
+	0x277: 0x0f13, 0x278: 0x0f12, 0x279: 0x0b13, 0x27a: 0x0113, 0x27b: 0x0112,
+	0x27c: 0x0012, 0x27d: 0x4d53, 0x27e: 0x5053, 0x27f: 0x5053,
+	// Block 0xa, offset 0x280
+	0x280: 0x6852, 0x281: 0x6852, 0x282: 0x6852, 0x283: 0x6852, 0x284: 0x6852, 0x285: 0x6852,
+	0x286: 0x6852, 0x287: 0x1a0a, 0x288: 0x0012, 0x28a: 0x0010,
+	0x291: 0x0034,
+	0x292: 0x0024, 0x293: 0x0024, 0x294: 0x0024, 0x295: 0x0024, 0x296: 0x0034, 0x297: 0x0024,
+	0x298: 0x0024, 0x299: 0x0024, 0x29a: 0x0034, 0x29b: 0x0034, 0x29c: 0x0024, 0x29d: 0x0024,
+	0x29e: 0x0024, 0x29f: 0x0024, 0x2a0: 0x0024, 0x2a1: 0x0024, 0x2a2: 0x0034, 0x2a3: 0x0034,
+	0x2a4: 0x0034, 0x2a5: 0x0034, 0x2a6: 0x0034, 0x2a7: 0x0034, 0x2a8: 0x0024, 0x2a9: 0x0024,
+	0x2aa: 0x0034, 0x2ab: 0x0024, 0x2ac: 0x0024, 0x2ad: 0x0034, 0x2ae: 0x0034, 0x2af: 0x0024,
+	0x2b0: 0x0034, 0x2b1: 0x0034, 0x2b2: 0x0034, 0x2b3: 0x0034, 0x2b4: 0x0034, 0x2b5: 0x0034,
+	0x2b6: 0x0034, 0x2b7: 0x0034, 0x2b8: 0x0034, 0x2b9: 0x0034, 0x2ba: 0x0034, 0x2bb: 0x0034,
+	0x2bc: 0x0034, 0x2bd: 0x0034, 0x2bf: 0x0034,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x0010, 0x2c1: 0x0010, 0x2c2: 0x0010, 0x2c3: 0x0010, 0x2c4: 0x0010, 0x2c5: 0x0010,
+	0x2c6: 0x0010, 0x2c7: 0x0010, 0x2c8: 0x0010, 0x2c9: 0x0014, 0x2ca: 0x0024, 0x2cb: 0x0024,
+	0x2cc: 0x0024, 0x2cd: 0x0024, 0x2ce: 0x0024, 0x2cf: 0x0034, 0x2d0: 0x0034, 0x2d1: 0x0034,
+	0x2d2: 0x0034, 0x2d3: 0x0034, 0x2d4: 0x0024, 0x2d5: 0x0024, 0x2d6: 0x0024, 0x2d7: 0x0024,
+	0x2d8: 0x0024, 0x2d9: 0x0024, 0x2da: 0x0024, 0x2db: 0x0024, 0x2dc: 0x0024, 0x2dd: 0x0024,
+	0x2de: 0x0024, 0x2df: 0x0024, 0x2e0: 0x0024, 0x2e1: 0x0024, 0x2e2: 0x0014, 0x2e3: 0x0034,
+	0x2e4: 0x0024, 0x2e5: 0x0024, 0x2e6: 0x0034, 0x2e7: 0x0024, 0x2e8: 0x0024, 0x2e9: 0x0034,
+	0x2ea: 0x0024, 0x2eb: 0x0024, 0x2ec: 0x0024, 0x2ed: 0x0034, 0x2ee: 0x0034, 0x2ef: 0x0034,
+	0x2f0: 0x0034, 0x2f1: 0x0034, 0x2f2: 0x0034, 0x2f3: 0x0024, 0x2f4: 0x0024, 0x2f5: 0x0024,
+	0x2f6: 0x0034, 0x2f7: 0x0024, 0x2f8: 0x0024, 0x2f9: 0x0034, 0x2fa: 0x0034, 0x2fb: 0x0024,
+	0x2fc: 0x0024, 0x2fd: 0x0024, 0x2fe: 0x0024, 0x2ff: 0x0024,
+	// Block 0xc, offset 0x300
+	0x300: 0x7053, 0x301: 0x7053, 0x302: 0x7053, 0x303: 0x7053, 0x304: 0x7053, 0x305: 0x7053,
+	0x307: 0x7053,
+	0x30d: 0x7053, 0x310: 0x1aea, 0x311: 0x1b6a,
+	0x312: 0x1bea, 0x313: 0x1c6a, 0x314: 0x1cea, 0x315: 0x1d6a, 0x316: 0x1dea, 0x317: 0x1e6a,
+	0x318: 0x1eea, 0x319: 0x1f6a, 0x31a: 0x1fea, 0x31b: 0x206a, 0x31c: 0x20ea, 0x31d: 0x216a,
+	0x31e: 0x21ea, 0x31f: 0x226a, 0x320: 0x22ea, 0x321: 0x236a, 0x322: 0x23ea, 0x323: 0x246a,
+	0x324: 0x24ea, 0x325: 0x256a, 0x326: 0x25ea, 0x327: 0x266a, 0x328: 0x26ea, 0x329: 0x276a,
+	0x32a: 0x27ea, 0x32b: 0x286a, 0x32c: 0x28ea, 0x32d: 0x296a, 0x32e: 0x29ea, 0x32f: 0x2a6a,
+	0x330: 0x2aea, 0x331: 0x2b6a, 0x332: 0x2bea, 0x333: 0x2c6a, 0x334: 0x2cea, 0x335: 0x2d6a,
+	0x336: 0x2dea, 0x337: 0x2e6a, 0x338: 0x2eea, 0x339: 0x2f6a, 0x33a: 0x2fea,
+	0x33c: 0x0015, 0x33d: 0x306a, 0x33e: 0x30ea, 0x33f: 0x316a,
+	// Block 0xd, offset 0x340
+	0x340: 0x0812, 0x341: 0x0812, 0x342: 0x0812, 0x343: 0x0812, 0x344: 0x0812, 0x345: 0x0812,
+	0x348: 0x0813, 0x349: 0x0813, 0x34a: 0x0813, 0x34b: 0x0813,
+	0x34c: 0x0813, 0x34d: 0x0813, 0x350: 0x3b1a, 0x351: 0x0812,
+	0x352: 0x3bfa, 0x353: 0x0812, 0x354: 0x3d3a, 0x355: 0x0812, 0x356: 0x3e7a, 0x357: 0x0812,
+	0x359: 0x0813, 0x35b: 0x0813, 0x35d: 0x0813,
+	0x35f: 0x0813, 0x360: 0x0812, 0x361: 0x0812, 0x362: 0x0812, 0x363: 0x0812,
+	0x364: 0x0812, 0x365: 0x0812, 0x366: 0x0812, 0x367: 0x0812, 0x368: 0x0813, 0x369: 0x0813,
+	0x36a: 0x0813, 0x36b: 0x0813, 0x36c: 0x0813, 0x36d: 0x0813, 0x36e: 0x0813, 0x36f: 0x0813,
+	0x370: 0x9252, 0x371: 0x9252, 0x372: 0x9552, 0x373: 0x9552, 0x374: 0x9852, 0x375: 0x9852,
+	0x376: 0x9b52, 0x377: 0x9b52, 0x378: 0x9e52, 0x379: 0x9e52, 0x37a: 0xa152, 0x37b: 0xa152,
+	0x37c: 0x4d52, 0x37d: 0x4d52,
+	// Block 0xe, offset 0x380
+	0x380: 0x3fba, 0x381: 0x40aa, 0x382: 0x419a, 0x383: 0x428a, 0x384: 0x437a, 0x385: 0x446a,
+	0x386: 0x455a, 0x387: 0x464a, 0x388: 0x4739, 0x389: 0x4829, 0x38a: 0x4919, 0x38b: 0x4a09,
+	0x38c: 0x4af9, 0x38d: 0x4be9, 0x38e: 0x4cd9, 0x38f: 0x4dc9, 0x390: 0x4eba, 0x391: 0x4faa,
+	0x392: 0x509a, 0x393: 0x518a, 0x394: 0x527a, 0x395: 0x536a, 0x396: 0x545a, 0x397: 0x554a,
+	0x398: 0x5639, 0x399: 0x5729, 0x39a: 0x5819, 0x39b: 0x5909, 0x39c: 0x59f9, 0x39d: 0x5ae9,
+	0x39e: 0x5bd9, 0x39f: 0x5cc9, 0x3a0: 0x5dba, 0x3a1: 0x5eaa, 0x3a2: 0x5f9a, 0x3a3: 0x608a,
+	0x3a4: 0x617a, 0x3a5: 0x626a, 0x3a6: 0x635a, 0x3a7: 0x644a, 0x3a8: 0x6539, 0x3a9: 0x6629,
+	0x3aa: 0x6719, 0x3ab: 0x6809, 0x3ac: 0x68f9, 0x3ad: 0x69e9, 0x3ae: 0x6ad9, 0x3af: 0x6bc9,
+	0x3b0: 0x0812, 0x3b1: 0x0812, 0x3b2: 0x6cba, 0x3b3: 0x6dca, 0x3b4: 0x6e9a,
+	0x3b6: 0x6f7a, 0x3b7: 0x705a, 0x3b8: 0x0813, 0x3b9: 0x0813, 0x3ba: 0x9253, 0x3bb: 0x9253,
+	0x3bc: 0x7199, 0x3bd: 0x0004, 0x3be: 0x726a, 0x3bf: 0x0004,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x0004, 0x3c1: 0x0004, 0x3c2: 0x72ea, 0x3c3: 0x73fa, 0x3c4: 0x74ca,
+	0x3c6: 0x75aa, 0x3c7: 0x768a, 0x3c8: 0x9553, 0x3c9: 0x9553, 0x3ca: 0x9853, 0x3cb: 0x9853,
+	0x3cc: 0x77c9, 0x3cd: 0x0004, 0x3ce: 0x0004, 0x3cf: 0x0004, 0x3d0: 0x0812, 0x3d1: 0x0812,
+	0x3d2: 0x789a, 0x3d3: 0x79da, 0x3d6: 0x7b1a, 0x3d7: 0x7bfa,
+	0x3d8: 0x0813, 0x3d9: 0x0813, 0x3da: 0x9b53, 0x3db: 0x9b53, 0x3dd: 0x0004,
+	0x3de: 0x0004, 0x3df: 0x0004, 0x3e0: 0x0812, 0x3e1: 0x0812, 0x3e2: 0x7d3a, 0x3e3: 0x7e7a,
+	0x3e4: 0x7fba, 0x3e5: 0x0912, 0x3e6: 0x809a, 0x3e7: 0x817a, 0x3e8: 0x0813, 0x3e9: 0x0813,
+	0x3ea: 0xa153, 0x3eb: 0xa153, 0x3ec: 0x0913, 0x3ed: 0x0004, 0x3ee: 0x0004, 0x3ef: 0x0004,
+	0x3f2: 0x82ba, 0x3f3: 0x83ca, 0x3f4: 0x849a,
+	0x3f6: 0x857a, 0x3f7: 0x865a, 0x3f8: 0x9e53, 0x3f9: 0x9e53, 0x3fa: 0x4d53, 0x3fb: 0x4d53,
+	0x3fc: 0x8799, 0x3fd: 0x0004, 0x3fe: 0x0004,
+	// Block 0x10, offset 0x400
+	0x402: 0x0013,
+	0x407: 0x0013, 0x40a: 0x0012, 0x40b: 0x0013,
+	0x40c: 0x0013, 0x40d: 0x0013, 0x40e: 0x0012, 0x40f: 0x0012, 0x410: 0x0013, 0x411: 0x0013,
+	0x412: 0x0013, 0x413: 0x0012, 0x415: 0x0013,
+	0x419: 0x0013, 0x41a: 0x0013, 0x41b: 0x0013, 0x41c: 0x0013, 0x41d: 0x0013,
+	0x424: 0x0013, 0x426: 0x886b, 0x428: 0x0013,
+	0x42a: 0x88cb, 0x42b: 0x890b, 0x42c: 0x0013, 0x42d: 0x0013, 0x42f: 0x0012,
+	0x430: 0x0013, 0x431: 0x0013, 0x432: 0xa453, 0x433: 0x0013, 0x434: 0x0012, 0x435: 0x0010,
+	0x436: 0x0010, 0x437: 0x0010, 0x438: 0x0010, 0x439: 0x0012,
+	0x43c: 0x0012, 0x43d: 0x0012, 0x43e: 0x0013, 0x43f: 0x0013,
+	// Block 0x11, offset 0x440
+	0x440: 0x1a13, 0x441: 0x1a13, 0x442: 0x1e13, 0x443: 0x1e13, 0x444: 0x1a13, 0x445: 0x1a13,
+	0x446: 0x2613, 0x447: 0x2613, 0x448: 0x2a13, 0x449: 0x2a13, 0x44a: 0x2e13, 0x44b: 0x2e13,
+	0x44c: 0x2a13, 0x44d: 0x2a13, 0x44e: 0x2613, 0x44f: 0x2613, 0x450: 0xa752, 0x451: 0xa752,
+	0x452: 0xaa52, 0x453: 0xaa52, 0x454: 0xad52, 0x455: 0xad52, 0x456: 0xaa52, 0x457: 0xaa52,
+	0x458: 0xa752, 0x459: 0xa752, 0x45a: 0x1a12, 0x45b: 0x1a12, 0x45c: 0x1e12, 0x45d: 0x1e12,
+	0x45e: 0x1a12, 0x45f: 0x1a12, 0x460: 0x2612, 0x461: 0x2612, 0x462: 0x2a12, 0x463: 0x2a12,
+	0x464: 0x2e12, 0x465: 0x2e12, 0x466: 0x2a12, 0x467: 0x2a12, 0x468: 0x2612, 0x469: 0x2612,
+	// Block 0x12, offset 0x480
+	0x480: 0x6552, 0x481: 0x6552, 0x482: 0x6552, 0x483: 0x6552, 0x484: 0x6552, 0x485: 0x6552,
+	0x486: 0x6552, 0x487: 0x6552, 0x488: 0x6552, 0x489: 0x6552, 0x48a: 0x6552, 0x48b: 0x6552,
+	0x48c: 0x6552, 0x48d: 0x6552, 0x48e: 0x6552, 0x48f: 0x6552, 0x490: 0xb052, 0x491: 0xb052,
+	0x492: 0xb052, 0x493: 0xb052, 0x494: 0xb052, 0x495: 0xb052, 0x496: 0xb052, 0x497: 0xb052,
+	0x498: 0xb052, 0x499: 0xb052, 0x49a: 0xb052, 0x49b: 0xb052, 0x49c: 0xb052, 0x49d: 0xb052,
+	0x49e: 0xb052, 0x49f: 0xb052, 0x4a0: 0x0113, 0x4a1: 0x0112, 0x4a2: 0x896b, 0x4a3: 0x8b53,
+	0x4a4: 0x89cb, 0x4a5: 0x8a2a, 0x4a6: 0x8a8a, 0x4a7: 0x0f13, 0x4a8: 0x0f12, 0x4a9: 0x0313,
+	0x4aa: 0x0312, 0x4ab: 0x0713, 0x4ac: 0x0712, 0x4ad: 0x8aeb, 0x4ae: 0x8b4b, 0x4af: 0x8bab,
+	0x4b0: 0x8c0b, 0x4b1: 0x0012, 0x4b2: 0x0113, 0x4b3: 0x0112, 0x4b4: 0x0012, 0x4b5: 0x0313,
+	0x4b6: 0x0312, 0x4b7: 0x0012, 0x4b8: 0x0012, 0x4b9: 0x0012, 0x4ba: 0x0012, 0x4bb: 0x0012,
+	0x4bc: 0x0015, 0x4bd: 0x0015, 0x4be: 0x8c6b, 0x4bf: 0x8ccb,
+	// Block 0x13, offset 0x4c0
+	0x4c0: 0x0113, 0x4c1: 0x0112, 0x4c2: 0x0113, 0x4c3: 0x0112, 0x4c4: 0x0113, 0x4c5: 0x0112,
+	0x4c6: 0x0113, 0x4c7: 0x0112, 0x4c8: 0x0014, 0x4c9: 0x0014, 0x4ca: 0x0014, 0x4cb: 0x0713,
+	0x4cc: 0x0712, 0x4cd: 0x8d2b, 0x4ce: 0x0012, 0x4cf: 0x0010, 0x4d0: 0x0113, 0x4d1: 0x0112,
+	0x4d2: 0x0113, 0x4d3: 0x0112, 0x4d4: 0x6552, 0x4d5: 0x0012, 0x4d6: 0x0113, 0x4d7: 0x0112,
+	0x4d8: 0x0113, 0x4d9: 0x0112, 0x4da: 0x0113, 0x4db: 0x0112, 0x4dc: 0x0113, 0x4dd: 0x0112,
+	0x4de: 0x0113, 0x4df: 0x0112, 0x4e0: 0x0113, 0x4e1: 0x0112, 0x4e2: 0x0113, 0x4e3: 0x0112,
+	0x4e4: 0x0113, 0x4e5: 0x0112, 0x4e6: 0x0113, 0x4e7: 0x0112, 0x4e8: 0x0113, 0x4e9: 0x0112,
+	0x4ea: 0x8d8b, 0x4eb: 0x8deb, 0x4ec: 0x8e4b, 0x4ed: 0x8eab, 0x4ee: 0x8f0b, 0x4ef: 0x0012,
+	0x4f0: 0x8f6b, 0x4f1: 0x8fcb, 0x4f2: 0x902b, 0x4f3: 0xb353, 0x4f4: 0x0113, 0x4f5: 0x0112,
+	0x4f6: 0x0113, 0x4f7: 0x0112, 0x4f8: 0x0113, 0x4f9: 0x0112, 0x4fa: 0x0113, 0x4fb: 0x0112,
+	0x4fc: 0x0113, 0x4fd: 0x0112, 0x4fe: 0x0113, 0x4ff: 0x0112,
+	// Block 0x14, offset 0x500
+	0x500: 0x90ea, 0x501: 0x916a, 0x502: 0x91ea, 0x503: 0x926a, 0x504: 0x931a, 0x505: 0x93ca,
+	0x506: 0x944a,
+	0x513: 0x94ca, 0x514: 0x95aa, 0x515: 0x968a, 0x516: 0x976a, 0x517: 0x984a,
+	0x51d: 0x0010,
+	0x51e: 0x0034, 0x51f: 0x0010, 0x520: 0x0010, 0x521: 0x0010, 0x522: 0x0010, 0x523: 0x0010,
+	0x524: 0x0010, 0x525: 0x0010, 0x526: 0x0010, 0x527: 0x0010, 0x528: 0x0010,
+	0x52a: 0x0010, 0x52b: 0x0010, 0x52c: 0x0010, 0x52d: 0x0010, 0x52e: 0x0010, 0x52f: 0x0010,
+	0x530: 0x0010, 0x531: 0x0010, 0x532: 0x0010, 0x533: 0x0010, 0x534: 0x0010, 0x535: 0x0010,
+	0x536: 0x0010, 0x538: 0x0010, 0x539: 0x0010, 0x53a: 0x0010, 0x53b: 0x0010,
+	0x53c: 0x0010, 0x53e: 0x0010,
+	// Block 0x15, offset 0x540
+	0x540: 0x2713, 0x541: 0x2913, 0x542: 0x2b13, 0x543: 0x2913, 0x544: 0x2f13, 0x545: 0x2913,
+	0x546: 0x2b13, 0x547: 0x2913, 0x548: 0x2713, 0x549: 0x3913, 0x54a: 0x3b13,
+	0x54c: 0x3f13, 0x54d: 0x3913, 0x54e: 0x3b13, 0x54f: 0x3913, 0x550: 0x2713, 0x551: 0x2913,
+	0x552: 0x2b13, 0x554: 0x2f13, 0x555: 0x2913, 0x557: 0xbc52,
+	0x558: 0xbf52, 0x559: 0xc252, 0x55a: 0xbf52, 0x55b: 0xc552, 0x55c: 0xbf52, 0x55d: 0xc252,
+	0x55e: 0xbf52, 0x55f: 0xbc52, 0x560: 0xc852, 0x561: 0xcb52, 0x563: 0xce52,
+	0x564: 0xc852, 0x565: 0xcb52, 0x566: 0xc852, 0x567: 0x2712, 0x568: 0x2912, 0x569: 0x2b12,
+	0x56a: 0x2912, 0x56b: 0x2f12, 0x56c: 0x2912, 0x56d: 0x2b12, 0x56e: 0x2912, 0x56f: 0x2712,
+	0x570: 0x3912, 0x571: 0x3b12, 0x573: 0x3f12, 0x574: 0x3912, 0x575: 0x3b12,
+	0x576: 0x3912, 0x577: 0x2712, 0x578: 0x2912, 0x579: 0x2b12, 0x57b: 0x2f12,
+	0x57c: 0x2912,
+	// Block 0x16, offset 0x580
+	0x580: 0x2213, 0x581: 0x2213, 0x582: 0x2613, 0x583: 0x2613, 0x584: 0x2213, 0x585: 0x2213,
+	0x586: 0x2e13, 0x587: 0x2e13, 0x588: 0x2213, 0x589: 0x2213, 0x58a: 0x2613, 0x58b: 0x2613,
+	0x58c: 0x2213, 0x58d: 0x2213, 0x58e: 0x3e13, 0x58f: 0x3e13, 0x590: 0x2213, 0x591: 0x2213,
+	0x592: 0x2613, 0x593: 0x2613, 0x594: 0x2213, 0x595: 0x2213, 0x596: 0x2e13, 0x597: 0x2e13,
+	0x598: 0x2213, 0x599: 0x2213, 0x59a: 0x2613, 0x59b: 0x2613, 0x59c: 0x2213, 0x59d: 0x2213,
+	0x59e: 0xd153, 0x59f: 0xd153, 0x5a0: 0xd453, 0x5a1: 0xd453, 0x5a2: 0x2212, 0x5a3: 0x2212,
+	0x5a4: 0x2612, 0x5a5: 0x2612, 0x5a6: 0x2212, 0x5a7: 0x2212, 0x5a8: 0x2e12, 0x5a9: 0x2e12,
+	0x5aa: 0x2212, 0x5ab: 0x2212, 0x5ac: 0x2612, 0x5ad: 0x2612, 0x5ae: 0x2212, 0x5af: 0x2212,
+	0x5b0: 0x3e12, 0x5b1: 0x3e12, 0x5b2: 0x2212, 0x5b3: 0x2212, 0x5b4: 0x2612, 0x5b5: 0x2612,
+	0x5b6: 0x2212, 0x5b7: 0x2212, 0x5b8: 0x2e12, 0x5b9: 0x2e12, 0x5ba: 0x2212, 0x5bb: 0x2212,
+	0x5bc: 0x2612, 0x5bd: 0x2612, 0x5be: 0x2212, 0x5bf: 0x2212,
+	// Block 0x17, offset 0x5c0
+	0x5c2: 0x0010,
+	0x5c7: 0x0010, 0x5c9: 0x0010, 0x5cb: 0x0010,
+	0x5cd: 0x0010, 0x5ce: 0x0010, 0x5cf: 0x0010, 0x5d1: 0x0010,
+	0x5d2: 0x0010, 0x5d4: 0x0010, 0x5d7: 0x0010,
+	0x5d9: 0x0010, 0x5db: 0x0010, 0x5dd: 0x0010,
+	0x5df: 0x0010, 0x5e1: 0x0010, 0x5e2: 0x0010,
+	0x5e4: 0x0010, 0x5e7: 0x0010, 0x5e8: 0x0010, 0x5e9: 0x0010,
+	0x5ea: 0x0010, 0x5ec: 0x0010, 0x5ed: 0x0010, 0x5ee: 0x0010, 0x5ef: 0x0010,
+	0x5f0: 0x0010, 0x5f1: 0x0010, 0x5f2: 0x0010, 0x5f4: 0x0010, 0x5f5: 0x0010,
+	0x5f6: 0x0010, 0x5f7: 0x0010, 0x5f9: 0x0010, 0x5fa: 0x0010, 0x5fb: 0x0010,
+	0x5fc: 0x0010, 0x5fe: 0x0010,
+}
+
+// caseIndex: 27 blocks, 1728 entries, 3456 bytes
+// Block 0 is the zero block.
+var caseIndex = [1728]uint16{
+	// Block 0x0, offset 0x0
+	// Block 0x1, offset 0x40
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc2: 0x16, 0xc3: 0x17, 0xc4: 0x18, 0xc5: 0x19, 0xc6: 0x01, 0xc7: 0x02,
+	0xc8: 0x1a, 0xc9: 0x03, 0xca: 0x04, 0xcb: 0x1b, 0xcc: 0x1c, 0xcd: 0x05, 0xce: 0x06, 0xcf: 0x07,
+	0xd0: 0x1d, 0xd1: 0x1e, 0xd2: 0x1f, 0xd3: 0x20, 0xd4: 0x21, 0xd5: 0x22, 0xd6: 0x08, 0xd7: 0x23,
+	0xd8: 0x24, 0xd9: 0x25, 0xda: 0x26, 0xdb: 0x27, 0xdc: 0x28, 0xdd: 0x29, 0xde: 0x2a, 0xdf: 0x2b,
+	0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
+	0xea: 0x06, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x08, 0xef: 0x09,
+	0xf0: 0x16, 0xf3: 0x18,
+	// Block 0x4, offset 0x100
+	0x120: 0x2c, 0x121: 0x2d, 0x122: 0x2e, 0x123: 0x09, 0x124: 0x2f, 0x125: 0x30, 0x126: 0x31, 0x127: 0x32,
+	0x128: 0x33, 0x129: 0x34, 0x12a: 0x35, 0x12b: 0x36, 0x12c: 0x37, 0x12d: 0x38, 0x12e: 0x39, 0x12f: 0x3a,
+	0x130: 0x3b, 0x131: 0x3c, 0x132: 0x3d, 0x133: 0x3e, 0x134: 0x3f, 0x135: 0x40, 0x136: 0x41, 0x137: 0x42,
+	0x138: 0x43, 0x139: 0x44, 0x13a: 0x45, 0x13b: 0x46, 0x13c: 0x47, 0x13d: 0x48, 0x13e: 0x49, 0x13f: 0x4a,
+	// Block 0x5, offset 0x140
+	0x140: 0x4b, 0x141: 0x4c, 0x142: 0x4d, 0x143: 0x0a, 0x144: 0x26, 0x145: 0x26, 0x146: 0x26, 0x147: 0x26,
+	0x148: 0x26, 0x149: 0x4e, 0x14a: 0x4f, 0x14b: 0x50, 0x14c: 0x51, 0x14d: 0x52, 0x14e: 0x53, 0x14f: 0x54,
+	0x150: 0x55, 0x151: 0x26, 0x152: 0x26, 0x153: 0x26, 0x154: 0x26, 0x155: 0x26, 0x156: 0x26, 0x157: 0x26,
+	0x158: 0x26, 0x159: 0x56, 0x15a: 0x57, 0x15b: 0x58, 0x15c: 0x59, 0x15d: 0x5a, 0x15e: 0x5b, 0x15f: 0x5c,
+	0x160: 0x5d, 0x161: 0x5e, 0x162: 0x5f, 0x163: 0x60, 0x164: 0x61, 0x165: 0x62, 0x167: 0x63,
+	0x168: 0x64, 0x169: 0x65, 0x16a: 0x66, 0x16b: 0x67, 0x16c: 0x68, 0x16d: 0x69, 0x16e: 0x6a, 0x16f: 0x6b,
+	0x170: 0x6c, 0x171: 0x6d, 0x172: 0x6e, 0x173: 0x6f, 0x174: 0x70, 0x175: 0x71, 0x176: 0x72, 0x177: 0x73,
+	0x178: 0x74, 0x179: 0x74, 0x17a: 0x75, 0x17b: 0x74, 0x17c: 0x76, 0x17d: 0x0b, 0x17e: 0x0c, 0x17f: 0x0d,
+	// Block 0x6, offset 0x180
+	0x180: 0x77, 0x181: 0x78, 0x182: 0x79, 0x183: 0x7a, 0x184: 0x0e, 0x185: 0x7b, 0x186: 0x7c,
+	0x192: 0x7d, 0x193: 0x0f,
+	0x1b0: 0x7e, 0x1b1: 0x10, 0x1b2: 0x74, 0x1b3: 0x7f, 0x1b4: 0x80, 0x1b5: 0x81, 0x1b6: 0x82, 0x1b7: 0x83,
+	0x1b8: 0x84,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x85, 0x1c2: 0x86, 0x1c3: 0x87, 0x1c4: 0x88, 0x1c5: 0x26, 0x1c6: 0x89,
+	// Block 0x8, offset 0x200
+	0x200: 0x8a, 0x201: 0x26, 0x202: 0x26, 0x203: 0x26, 0x204: 0x26, 0x205: 0x26, 0x206: 0x26, 0x207: 0x26,
+	0x208: 0x26, 0x209: 0x26, 0x20a: 0x26, 0x20b: 0x26, 0x20c: 0x26, 0x20d: 0x26, 0x20e: 0x26, 0x20f: 0x26,
+	0x210: 0x26, 0x211: 0x26, 0x212: 0x8b, 0x213: 0x8c, 0x214: 0x26, 0x215: 0x26, 0x216: 0x26, 0x217: 0x26,
+	0x218: 0x8d, 0x219: 0x8e, 0x21a: 0x8f, 0x21b: 0x90, 0x21c: 0x91, 0x21d: 0x92, 0x21e: 0x11, 0x21f: 0x93,
+	0x220: 0x94, 0x221: 0x95, 0x222: 0x26, 0x223: 0x96, 0x224: 0x97, 0x225: 0x98, 0x226: 0x99, 0x227: 0x9a,
+	0x228: 0x9b, 0x229: 0x9c, 0x22a: 0x9d, 0x22b: 0x9e, 0x22c: 0x9f, 0x22d: 0xa0, 0x22e: 0xa1, 0x22f: 0xa2,
+	0x230: 0x26, 0x231: 0x26, 0x232: 0x26, 0x233: 0x26, 0x234: 0x26, 0x235: 0x26, 0x236: 0x26, 0x237: 0x26,
+	0x238: 0x26, 0x239: 0x26, 0x23a: 0x26, 0x23b: 0x26, 0x23c: 0x26, 0x23d: 0x26, 0x23e: 0x26, 0x23f: 0x26,
+	// Block 0x9, offset 0x240
+	0x240: 0x26, 0x241: 0x26, 0x242: 0x26, 0x243: 0x26, 0x244: 0x26, 0x245: 0x26, 0x246: 0x26, 0x247: 0x26,
+	0x248: 0x26, 0x249: 0x26, 0x24a: 0x26, 0x24b: 0x26, 0x24c: 0x26, 0x24d: 0x26, 0x24e: 0x26, 0x24f: 0x26,
+	0x250: 0x26, 0x251: 0x26, 0x252: 0x26, 0x253: 0x26, 0x254: 0x26, 0x255: 0x26, 0x256: 0x26, 0x257: 0x26,
+	0x258: 0x26, 0x259: 0x26, 0x25a: 0x26, 0x25b: 0x26, 0x25c: 0x26, 0x25d: 0x26, 0x25e: 0x26, 0x25f: 0x26,
+	0x260: 0x26, 0x261: 0x26, 0x262: 0x26, 0x263: 0x26, 0x264: 0x26, 0x265: 0x26, 0x266: 0x26, 0x267: 0x26,
+	0x268: 0x26, 0x269: 0x26, 0x26a: 0x26, 0x26b: 0x26, 0x26c: 0x26, 0x26d: 0x26, 0x26e: 0x26, 0x26f: 0x26,
+	0x270: 0x26, 0x271: 0x26, 0x272: 0x26, 0x273: 0x26, 0x274: 0x26, 0x275: 0x26, 0x276: 0x26, 0x277: 0x26,
+	0x278: 0x26, 0x279: 0x26, 0x27a: 0x26, 0x27b: 0x26, 0x27c: 0x26, 0x27d: 0x26, 0x27e: 0x26, 0x27f: 0x26,
+	// Block 0xa, offset 0x280
+	0x280: 0x26, 0x281: 0x26, 0x282: 0x26, 0x283: 0x26, 0x284: 0x26, 0x285: 0x26, 0x286: 0x26, 0x287: 0x26,
+	0x288: 0x26, 0x289: 0x26, 0x28a: 0x26, 0x28b: 0x26, 0x28c: 0x26, 0x28d: 0x26, 0x28e: 0x26, 0x28f: 0x26,
+	0x290: 0x26, 0x291: 0x26, 0x292: 0x26, 0x293: 0x26, 0x294: 0x26, 0x295: 0x26, 0x296: 0x26, 0x297: 0x26,
+	0x298: 0x26, 0x299: 0x26, 0x29a: 0x26, 0x29b: 0x26, 0x29c: 0x26, 0x29d: 0x26, 0x29e: 0xa3, 0x29f: 0xa4,
+	// Block 0xb, offset 0x2c0
+	0x2ec: 0x12, 0x2ed: 0xa5, 0x2ee: 0xa6, 0x2ef: 0xa7,
+	0x2f0: 0x26, 0x2f1: 0x26, 0x2f2: 0x26, 0x2f3: 0x26, 0x2f4: 0xa8, 0x2f5: 0xa9, 0x2f6: 0xaa, 0x2f7: 0xab,
+	0x2f8: 0xac, 0x2f9: 0xad, 0x2fa: 0x26, 0x2fb: 0xae, 0x2fc: 0xaf, 0x2fd: 0xb0, 0x2fe: 0xb1, 0x2ff: 0xb2,
+	// Block 0xc, offset 0x300
+	0x300: 0xb3, 0x301: 0xb4, 0x302: 0x26, 0x303: 0xb5, 0x305: 0xb6, 0x307: 0xb7,
+	0x30a: 0xb8, 0x30b: 0xb9, 0x30c: 0xba, 0x30d: 0xbb, 0x30e: 0xbc, 0x30f: 0xbd,
+	0x310: 0xbe, 0x311: 0xbf, 0x312: 0xc0, 0x313: 0xc1, 0x314: 0xc2, 0x315: 0xc3, 0x316: 0x13,
+	0x318: 0x26, 0x319: 0x26, 0x31a: 0x26, 0x31b: 0x26, 0x31c: 0xc4, 0x31d: 0xc5, 0x31e: 0xc6,
+	0x320: 0xc7, 0x321: 0xc8, 0x322: 0xc9, 0x323: 0xca, 0x324: 0xcb, 0x326: 0xcc,
+	0x328: 0xcd, 0x329: 0xce, 0x32a: 0xcf, 0x32b: 0xd0, 0x32c: 0x60, 0x32d: 0xd1, 0x32e: 0xd2,
+	0x330: 0x26, 0x331: 0xd3, 0x332: 0xd4, 0x333: 0xd5, 0x334: 0xd6,
+	0x33a: 0xd7, 0x33b: 0xd8, 0x33c: 0xd9, 0x33d: 0xda, 0x33e: 0xdb, 0x33f: 0xdc,
+	// Block 0xd, offset 0x340
+	0x340: 0xdd, 0x341: 0xde, 0x342: 0xdf, 0x343: 0xe0, 0x344: 0xe1, 0x345: 0xe2, 0x346: 0xe3, 0x347: 0xe4,
+	0x348: 0xe5, 0x349: 0xe6, 0x34a: 0xe7, 0x34b: 0xe8, 0x34c: 0xe9, 0x34d: 0xea,
+	0x350: 0xeb, 0x351: 0xec, 0x352: 0xed, 0x353: 0xee, 0x356: 0xef, 0x357: 0xf0,
+	0x358: 0xf1, 0x359: 0xf2, 0x35a: 0xf3, 0x35b: 0xf4, 0x35c: 0xf5,
+	0x360: 0xf6, 0x362: 0xf7, 0x363: 0xf8, 0x364: 0xf9, 0x365: 0xfa, 0x366: 0xfb, 0x367: 0xfc,
+	0x368: 0xfd, 0x369: 0xfe, 0x36a: 0xff, 0x36b: 0x100,
+	0x370: 0x101, 0x371: 0x102, 0x372: 0x103, 0x374: 0x104, 0x375: 0x105, 0x376: 0x106,
+	0x37b: 0x107, 0x37c: 0x108, 0x37d: 0x109, 0x37e: 0x10a,
+	// Block 0xe, offset 0x380
+	0x380: 0x26, 0x381: 0x26, 0x382: 0x26, 0x383: 0x26, 0x384: 0x26, 0x385: 0x26, 0x386: 0x26, 0x387: 0x26,
+	0x388: 0x26, 0x389: 0x26, 0x38a: 0x26, 0x38b: 0x26, 0x38c: 0x26, 0x38d: 0x26, 0x38e: 0x10b,
+	0x390: 0x26, 0x391: 0x10c, 0x392: 0x26, 0x393: 0x26, 0x394: 0x26, 0x395: 0x10d,
+	0x3be: 0xa9, 0x3bf: 0x10e,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x26, 0x3c1: 0x26, 0x3c2: 0x26, 0x3c3: 0x26, 0x3c4: 0x26, 0x3c5: 0x26, 0x3c6: 0x26, 0x3c7: 0x26,
+	0x3c8: 0x26, 0x3c9: 0x26, 0x3ca: 0x26, 0x3cb: 0x26, 0x3cc: 0x26, 0x3cd: 0x26, 0x3ce: 0x26, 0x3cf: 0x26,
+	0x3d0: 0x10f, 0x3d1: 0x110,
+	// Block 0x10, offset 0x400
+	0x410: 0x26, 0x411: 0x26, 0x412: 0x26, 0x413: 0x26, 0x414: 0x26, 0x415: 0x26, 0x416: 0x26, 0x417: 0x26,
+	0x418: 0x26, 0x419: 0x111,
+	// Block 0x11, offset 0x440
+	0x460: 0x26, 0x461: 0x26, 0x462: 0x26, 0x463: 0x26, 0x464: 0x26, 0x465: 0x26, 0x466: 0x26, 0x467: 0x26,
+	0x468: 0x100, 0x469: 0x112, 0x46a: 0x113, 0x46b: 0x114, 0x46c: 0x115, 0x46d: 0x116, 0x46e: 0x117,
+	0x479: 0x118, 0x47c: 0x26, 0x47d: 0x119, 0x47e: 0x11a, 0x47f: 0x11b,
+	// Block 0x12, offset 0x480
+	0x4bf: 0x11c,
+	// Block 0x13, offset 0x4c0
+	0x4f0: 0x26, 0x4f1: 0x11d, 0x4f2: 0x11e,
+	// Block 0x14, offset 0x500
+	0x53c: 0x11f, 0x53d: 0x120,
+	// Block 0x15, offset 0x540
+	0x545: 0x121, 0x546: 0x122,
+	0x549: 0x123,
+	0x550: 0x124, 0x551: 0x125, 0x552: 0x126, 0x553: 0x127, 0x554: 0x128, 0x555: 0x129, 0x556: 0x12a, 0x557: 0x12b,
+	0x558: 0x12c, 0x559: 0x12d, 0x55a: 0x12e, 0x55b: 0x12f, 0x55c: 0x130, 0x55d: 0x131, 0x55e: 0x132, 0x55f: 0x133,
+	0x568: 0x134, 0x569: 0x135, 0x56a: 0x136,
+	0x57c: 0x137,
+	// Block 0x16, offset 0x580
+	0x580: 0x138, 0x581: 0x139, 0x582: 0x13a, 0x584: 0x13b, 0x585: 0x13c,
+	0x58a: 0x13d, 0x58b: 0x13e,
+	0x593: 0x13f,
+	0x59f: 0x140,
+	0x5a0: 0x26, 0x5a1: 0x26, 0x5a2: 0x26, 0x5a3: 0x141, 0x5a4: 0x14, 0x5a5: 0x142,
+	0x5b8: 0x143, 0x5b9: 0x15, 0x5ba: 0x144,
+	// Block 0x17, offset 0x5c0
+	0x5c4: 0x145, 0x5c5: 0x146, 0x5c6: 0x147,
+	0x5cf: 0x148,
+	0x5ef: 0x149,
+	// Block 0x18, offset 0x600
+	0x610: 0x0a, 0x611: 0x0b, 0x612: 0x0c, 0x613: 0x0d, 0x614: 0x0e, 0x616: 0x0f,
+	0x61a: 0x10, 0x61b: 0x11, 0x61c: 0x12, 0x61d: 0x13, 0x61e: 0x14, 0x61f: 0x15,
+	// Block 0x19, offset 0x640
+	0x640: 0x14a, 0x641: 0x14b, 0x644: 0x14b, 0x645: 0x14b, 0x646: 0x14b, 0x647: 0x14c,
+	// Block 0x1a, offset 0x680
+	0x6a0: 0x17,
+}
+
+// sparseOffsets: 312 entries, 624 bytes
+var sparseOffsets = []uint16{0x0, 0x9, 0xf, 0x18, 0x24, 0x2e, 0x34, 0x37, 0x3b, 0x3e, 0x42, 0x4c, 0x4e, 0x57, 0x5e, 0x63, 0x71, 0x72, 0x80, 0x8f, 0x99, 0x9c, 0xa3, 0xab, 0xaf, 0xb7, 0xbd, 0xcb, 0xd6, 0xe3, 0xee, 0xfa, 0x104, 0x110, 0x11b, 0x127, 0x133, 0x13b, 0x145, 0x150, 0x15b, 0x167, 0x16d, 0x178, 0x17e, 0x186, 0x189, 0x18e, 0x192, 0x196, 0x19d, 0x1a6, 0x1ae, 0x1af, 0x1b8, 0x1bf, 0x1c7, 0x1cd, 0x1d2, 0x1d6, 0x1d9, 0x1db, 0x1de, 0x1e3, 0x1e4, 0x1e6, 0x1e8, 0x1ea, 0x1f1, 0x1f6, 0x1fa, 0x203, 0x206, 0x209, 0x20f, 0x210, 0x21b, 0x21c, 0x21d, 0x222, 0x22f, 0x238, 0x23e, 0x246, 0x24f, 0x258, 0x261, 0x266, 0x269, 0x274, 0x282, 0x284, 0x28b, 0x28f, 0x29b, 0x29c, 0x2a7, 0x2af, 0x2b7, 0x2bd, 0x2be, 0x2cc, 0x2d1, 0x2d4, 0x2d9, 0x2dd, 0x2e3, 0x2e8, 0x2eb, 0x2f0, 0x2f5, 0x2f6, 0x2fc, 0x2fe, 0x2ff, 0x301, 0x303, 0x306, 0x307, 0x309, 0x30c, 0x312, 0x316, 0x318, 0x31d, 0x324, 0x334, 0x33e, 0x33f, 0x348, 0x34c, 0x351, 0x359, 0x35f, 0x365, 0x36f, 0x374, 0x37d, 0x383, 0x38c, 0x390, 0x398, 0x39a, 0x39c, 0x39f, 0x3a1, 0x3a3, 0x3a4, 0x3a5, 0x3a7, 0x3a9, 0x3af, 0x3b4, 0x3b6, 0x3bd, 0x3c0, 0x3c2, 0x3c8, 0x3cd, 0x3cf, 0x3d0, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3db, 0x3dd, 0x3e0, 0x3e8, 0x3eb, 0x3ef, 0x3f7, 0x3f9, 0x409, 0x40a, 0x40c, 0x411, 0x417, 0x419, 0x41a, 0x41c, 0x41e, 0x420, 0x42d, 0x42e, 0x42f, 0x433, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43c, 0x43f, 0x440, 0x443, 0x44a, 0x450, 0x452, 0x456, 0x45e, 0x464, 0x468, 0x46f, 0x473, 0x477, 0x480, 0x48a, 0x48c, 0x492, 0x498, 0x4a2, 0x4ac, 0x4ae, 0x4b7, 0x4bd, 0x4c3, 0x4c9, 0x4cc, 0x4d2, 0x4d5, 0x4de, 0x4df, 0x4e6, 0x4ea, 0x4eb, 0x4ee, 0x4f8, 0x4fb, 0x4fd, 0x504, 0x50c, 0x512, 0x519, 0x51a, 0x520, 0x523, 0x52b, 0x532, 0x53c, 0x544, 0x547, 0x54c, 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x557, 0x55a, 0x55b, 0x55e, 0x55f, 0x562, 0x564, 0x568, 0x569, 0x56b, 0x56e, 0x570, 0x573, 0x576, 0x578, 0x57d, 0x57f, 0x580, 0x585, 0x589, 0x58a, 0x58d, 0x591, 0x59c, 0x5a0, 0x5a8, 0x5ad, 0x5b1, 0x5b4, 0x5b8, 0x5bb, 0x5be, 0x5c3, 0x5c7, 0x5cb, 0x5cf, 0x5d3, 0x5d5, 0x5d7, 0x5da, 0x5de, 0x5e4, 0x5e5, 0x5e6, 0x5e9, 0x5eb, 0x5ed, 0x5f0, 0x5f5, 0x5f9, 0x5fb, 0x601, 0x60a, 0x60f, 0x610, 0x613, 0x614, 0x615, 0x616, 0x618, 0x619, 0x61a}
+
+// sparseValues: 1562 entries, 6248 bytes
+var sparseValues = [1562]valueRange{
+	// Block 0x0, offset 0x0
+	{value: 0x0004, lo: 0xa8, hi: 0xa8},
+	{value: 0x0012, lo: 0xaa, hi: 0xaa},
+	{value: 0x0014, lo: 0xad, hi: 0xad},
+	{value: 0x0004, lo: 0xaf, hi: 0xaf},
+	{value: 0x0004, lo: 0xb4, hi: 0xb4},
+	{value: 0x001a, lo: 0xb5, hi: 0xb5},
+	{value: 0x0054, lo: 0xb7, hi: 0xb7},
+	{value: 0x0004, lo: 0xb8, hi: 0xb8},
+	{value: 0x0012, lo: 0xba, hi: 0xba},
+	// Block 0x1, offset 0x9
+	{value: 0x2013, lo: 0x80, hi: 0x96},
+	{value: 0x2013, lo: 0x98, hi: 0x9e},
+	{value: 0x009a, lo: 0x9f, hi: 0x9f},
+	{value: 0x2012, lo: 0xa0, hi: 0xb6},
+	{value: 0x2012, lo: 0xb8, hi: 0xbe},
+	{value: 0x0252, lo: 0xbf, hi: 0xbf},
+	// Block 0x2, offset 0xf
+	{value: 0x0117, lo: 0x80, hi: 0xaf},
+	{value: 0x011b, lo: 0xb0, hi: 0xb0},
+	{value: 0x019a, lo: 0xb1, hi: 0xb1},
+	{value: 0x0117, lo: 0xb2, hi: 0xb7},
+	{value: 0x0012, lo: 0xb8, hi: 0xb8},
+	{value: 0x0316, lo: 0xb9, hi: 0xba},
+	{value: 0x0716, lo: 0xbb, hi: 0xbc},
+	{value: 0x0316, lo: 0xbd, hi: 0xbe},
+	{value: 0x0553, lo: 0xbf, hi: 0xbf},
+	// Block 0x3, offset 0x18
+	{value: 0x0552, lo: 0x80, hi: 0x80},
+	{value: 0x0316, lo: 0x81, hi: 0x82},
+	{value: 0x0716, lo: 0x83, hi: 0x84},
+	{value: 0x0316, lo: 0x85, hi: 0x86},
+	{value: 0x0f16, lo: 0x87, hi: 0x88},
+	{value: 0x01da, lo: 0x89, hi: 0x89},
+	{value: 0x0117, lo: 0x8a, hi: 0xb7},
+	{value: 0x0253, lo: 0xb8, hi: 0xb8},
+	{value: 0x0316, lo: 0xb9, hi: 0xba},
+	{value: 0x0716, lo: 0xbb, hi: 0xbc},
+	{value: 0x0316, lo: 0xbd, hi: 0xbe},
+	{value: 0x028a, lo: 0xbf, hi: 0xbf},
+	// Block 0x4, offset 0x24
+	{value: 0x0117, lo: 0x80, hi: 0x9f},
+	{value: 0x2f53, lo: 0xa0, hi: 0xa0},
+	{value: 0x0012, lo: 0xa1, hi: 0xa1},
+	{value: 0x0117, lo: 0xa2, hi: 0xb3},
+	{value: 0x0012, lo: 0xb4, hi: 0xb9},
+	{value: 0x090b, lo: 0xba, hi: 0xba},
+	{value: 0x0716, lo: 0xbb, hi: 0xbc},
+	{value: 0x2953, lo: 0xbd, hi: 0xbd},
+	{value: 0x098b, lo: 0xbe, hi: 0xbe},
+	{value: 0x0a0a, lo: 0xbf, hi: 0xbf},
+	// Block 0x5, offset 0x2e
+	{value: 0x0015, lo: 0x80, hi: 0x81},
+	{value: 0x0014, lo: 0x82, hi: 0x97},
+	{value: 0x0004, lo: 0x98, hi: 0x9d},
+	{value: 0x0014, lo: 0x9e, hi: 0x9f},
+	{value: 0x0015, lo: 0xa0, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xbf},
+	// Block 0x6, offset 0x34
+	{value: 0x0024, lo: 0x80, hi: 0x94},
+	{value: 0x0034, lo: 0x95, hi: 0xbc},
+	{value: 0x0024, lo: 0xbd, hi: 0xbf},
+	// Block 0x7, offset 0x37
+	{value: 0x6553, lo: 0x80, hi: 0x8f},
+	{value: 0x2013, lo: 0x90, hi: 0x9f},
+	{value: 0x5f53, lo: 0xa0, hi: 0xaf},
+	{value: 0x2012, lo: 0xb0, hi: 0xbf},
+	// Block 0x8, offset 0x3b
+	{value: 0x5f52, lo: 0x80, hi: 0x8f},
+	{value: 0x6552, lo: 0x90, hi: 0x9f},
+	{value: 0x0117, lo: 0xa0, hi: 0xbf},
+	// Block 0x9, offset 0x3e
+	{value: 0x0117, lo: 0x80, hi: 0x81},
+	{value: 0x0024, lo: 0x83, hi: 0x87},
+	{value: 0x0014, lo: 0x88, hi: 0x89},
+	{value: 0x0117, lo: 0x8a, hi: 0xbf},
+	// Block 0xa, offset 0x42
+	{value: 0x0f13, lo: 0x80, hi: 0x80},
+	{value: 0x0316, lo: 0x81, hi: 0x82},
+	{value: 0x0716, lo: 0x83, hi: 0x84},
+	{value: 0x0316, lo: 0x85, hi: 0x86},
+	{value: 0x0f16, lo: 0x87, hi: 0x88},
+	{value: 0x0316, lo: 0x89, hi: 0x8a},
+	{value: 0x0716, lo: 0x8b, hi: 0x8c},
+	{value: 0x0316, lo: 0x8d, hi: 0x8e},
+	{value: 0x0f12, lo: 0x8f, hi: 0x8f},
+	{value: 0x0117, lo: 0x90, hi: 0xbf},
+	// Block 0xb, offset 0x4c
+	{value: 0x0117, lo: 0x80, hi: 0xaf},
+	{value: 0x6553, lo: 0xb1, hi: 0xbf},
+	// Block 0xc, offset 0x4e
+	{value: 0x3013, lo: 0x80, hi: 0x8f},
+	{value: 0x6853, lo: 0x90, hi: 0x96},
+	{value: 0x0014, lo: 0x99, hi: 0x99},
+	{value: 0x0010, lo: 0x9a, hi: 0x9c},
+	{value: 0x0010, lo: 0x9e, hi: 0x9e},
+	{value: 0x0054, lo: 0x9f, hi: 0x9f},
+	{value: 0x0012, lo: 0xa0, hi: 0xa0},
+	{value: 0x6552, lo: 0xa1, hi: 0xaf},
+	{value: 0x3012, lo: 0xb0, hi: 0xbf},
+	// Block 0xd, offset 0x57
+	{value: 0x0034, lo: 0x81, hi: 0x82},
+	{value: 0x0024, lo: 0x84, hi: 0x84},
+	{value: 0x0034, lo: 0x85, hi: 0x85},
+	{value: 0x0034, lo: 0x87, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0xaa},
+	{value: 0x0010, lo: 0xaf, hi: 0xb3},
+	{value: 0x0054, lo: 0xb4, hi: 0xb4},
+	// Block 0xe, offset 0x5e
+	{value: 0x0014, lo: 0x80, hi: 0x85},
+	{value: 0x0024, lo: 0x90, hi: 0x97},
+	{value: 0x0034, lo: 0x98, hi: 0x9a},
+	{value: 0x0014, lo: 0x9c, hi: 0x9c},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0xf, offset 0x63
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x8a},
+	{value: 0x0034, lo: 0x8b, hi: 0x92},
+	{value: 0x0024, lo: 0x93, hi: 0x94},
+	{value: 0x0034, lo: 0x95, hi: 0x96},
+	{value: 0x0024, lo: 0x97, hi: 0x9b},
+	{value: 0x0034, lo: 0x9c, hi: 0x9c},
+	{value: 0x0024, lo: 0x9d, hi: 0x9e},
+	{value: 0x0034, lo: 0x9f, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0010, lo: 0xab, hi: 0xab},
+	{value: 0x0010, lo: 0xae, hi: 0xaf},
+	{value: 0x0034, lo: 0xb0, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xbf},
+	// Block 0x10, offset 0x71
+	{value: 0x0010, lo: 0x80, hi: 0xbf},
+	// Block 0x11, offset 0x72
+	{value: 0x0010, lo: 0x80, hi: 0x93},
+	{value: 0x0010, lo: 0x95, hi: 0x95},
+	{value: 0x0024, lo: 0x96, hi: 0x9c},
+	{value: 0x0014, lo: 0x9d, hi: 0x9d},
+	{value: 0x0024, lo: 0x9f, hi: 0xa2},
+	{value: 0x0034, lo: 0xa3, hi: 0xa3},
+	{value: 0x0024, lo: 0xa4, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xa6},
+	{value: 0x0024, lo: 0xa7, hi: 0xa8},
+	{value: 0x0034, lo: 0xaa, hi: 0xaa},
+	{value: 0x0024, lo: 0xab, hi: 0xac},
+	{value: 0x0034, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xbc},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x12, offset 0x80
+	{value: 0x0014, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0034, lo: 0x91, hi: 0x91},
+	{value: 0x0010, lo: 0x92, hi: 0xaf},
+	{value: 0x0024, lo: 0xb0, hi: 0xb0},
+	{value: 0x0034, lo: 0xb1, hi: 0xb1},
+	{value: 0x0024, lo: 0xb2, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0024, lo: 0xb5, hi: 0xb6},
+	{value: 0x0034, lo: 0xb7, hi: 0xb9},
+	{value: 0x0024, lo: 0xba, hi: 0xba},
+	{value: 0x0034, lo: 0xbb, hi: 0xbc},
+	{value: 0x0024, lo: 0xbd, hi: 0xbd},
+	{value: 0x0034, lo: 0xbe, hi: 0xbe},
+	{value: 0x0024, lo: 0xbf, hi: 0xbf},
+	// Block 0x13, offset 0x8f
+	{value: 0x0024, lo: 0x80, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0024, lo: 0x83, hi: 0x83},
+	{value: 0x0034, lo: 0x84, hi: 0x84},
+	{value: 0x0024, lo: 0x85, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	{value: 0x0024, lo: 0x87, hi: 0x87},
+	{value: 0x0034, lo: 0x88, hi: 0x88},
+	{value: 0x0024, lo: 0x89, hi: 0x8a},
+	{value: 0x0010, lo: 0x8d, hi: 0xbf},
+	// Block 0x14, offset 0x99
+	{value: 0x0010, lo: 0x80, hi: 0xa5},
+	{value: 0x0014, lo: 0xa6, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xb1},
+	// Block 0x15, offset 0x9c
+	{value: 0x0010, lo: 0x80, hi: 0xaa},
+	{value: 0x0024, lo: 0xab, hi: 0xb1},
+	{value: 0x0034, lo: 0xb2, hi: 0xb2},
+	{value: 0x0024, lo: 0xb3, hi: 0xb3},
+	{value: 0x0014, lo: 0xb4, hi: 0xb5},
+	{value: 0x0014, lo: 0xba, hi: 0xba},
+	{value: 0x0034, lo: 0xbd, hi: 0xbd},
+	// Block 0x16, offset 0xa3
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0024, lo: 0x96, hi: 0x99},
+	{value: 0x0014, lo: 0x9a, hi: 0x9a},
+	{value: 0x0024, lo: 0x9b, hi: 0xa3},
+	{value: 0x0014, lo: 0xa4, hi: 0xa4},
+	{value: 0x0024, lo: 0xa5, hi: 0xa7},
+	{value: 0x0014, lo: 0xa8, hi: 0xa8},
+	{value: 0x0024, lo: 0xa9, hi: 0xad},
+	// Block 0x17, offset 0xab
+	{value: 0x0010, lo: 0x80, hi: 0x98},
+	{value: 0x0034, lo: 0x99, hi: 0x9b},
+	{value: 0x0010, lo: 0xa0, hi: 0xaa},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x18, offset 0xaf
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0004, lo: 0x88, hi: 0x88},
+	{value: 0x0010, lo: 0x89, hi: 0x8e},
+	{value: 0x0014, lo: 0x90, hi: 0x91},
+	{value: 0x0024, lo: 0x98, hi: 0x98},
+	{value: 0x0034, lo: 0x99, hi: 0x9b},
+	{value: 0x0024, lo: 0x9c, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x19, offset 0xb7
+	{value: 0x0014, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0xb9},
+	{value: 0x0014, lo: 0xba, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x1a, offset 0xbd
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x88},
+	{value: 0x0010, lo: 0x89, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0024, lo: 0x91, hi: 0x91},
+	{value: 0x0034, lo: 0x92, hi: 0x92},
+	{value: 0x0024, lo: 0x93, hi: 0x94},
+	{value: 0x0014, lo: 0x95, hi: 0x97},
+	{value: 0x0010, lo: 0x98, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0014, lo: 0xb1, hi: 0xb1},
+	{value: 0x0010, lo: 0xb2, hi: 0xbf},
+	// Block 0x1b, offset 0xcb
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8f, hi: 0x90},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb2},
+	{value: 0x0010, lo: 0xb6, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x1c, offset 0xd6
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x84},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0x9c, hi: 0x9d},
+	{value: 0x0010, lo: 0x9f, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xb1},
+	{value: 0x0010, lo: 0xbc, hi: 0xbc},
+	{value: 0x0024, lo: 0xbe, hi: 0xbe},
+	// Block 0x1d, offset 0xe3
+	{value: 0x0014, lo: 0x81, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8a},
+	{value: 0x0010, lo: 0x8f, hi: 0x90},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb6},
+	{value: 0x0010, lo: 0xb8, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x1e, offset 0xee
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x82},
+	{value: 0x0014, lo: 0x87, hi: 0x88},
+	{value: 0x0014, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0014, lo: 0x91, hi: 0x91},
+	{value: 0x0010, lo: 0x99, hi: 0x9c},
+	{value: 0x0010, lo: 0x9e, hi: 0x9e},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xb1},
+	{value: 0x0010, lo: 0xb2, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb5},
+	// Block 0x1f, offset 0xfa
+	{value: 0x0014, lo: 0x81, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8d},
+	{value: 0x0010, lo: 0x8f, hi: 0x91},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x20, offset 0x104
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x85},
+	{value: 0x0014, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x89, hi: 0x89},
+	{value: 0x0010, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0010, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xb9, hi: 0xb9},
+	{value: 0x0014, lo: 0xba, hi: 0xbf},
+	// Block 0x21, offset 0x110
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8f, hi: 0x90},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x22, offset 0x11b
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x84},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0014, lo: 0x95, hi: 0x96},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0x9c, hi: 0x9d},
+	{value: 0x0010, lo: 0x9f, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xb1, hi: 0xb1},
+	// Block 0x23, offset 0x127
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8a},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0x95},
+	{value: 0x0010, lo: 0x99, hi: 0x9a},
+	{value: 0x0010, lo: 0x9c, hi: 0x9c},
+	{value: 0x0010, lo: 0x9e, hi: 0x9f},
+	{value: 0x0010, lo: 0xa3, hi: 0xa4},
+	{value: 0x0010, lo: 0xa8, hi: 0xaa},
+	{value: 0x0010, lo: 0xae, hi: 0xb9},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x24, offset 0x133
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x82},
+	{value: 0x0010, lo: 0x86, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	// Block 0x25, offset 0x13b
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x83},
+	{value: 0x0014, lo: 0x84, hi: 0x84},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbd},
+	{value: 0x0014, lo: 0xbe, hi: 0xbf},
+	// Block 0x26, offset 0x145
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x84},
+	{value: 0x0014, lo: 0x86, hi: 0x88},
+	{value: 0x0014, lo: 0x8a, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0034, lo: 0x95, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0x9a},
+	{value: 0x0010, lo: 0x9d, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	// Block 0x27, offset 0x150
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x28, offset 0x15b
+	{value: 0x0010, lo: 0x80, hi: 0x84},
+	{value: 0x0014, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x95, hi: 0x96},
+	{value: 0x0010, lo: 0x9d, hi: 0x9e},
+	{value: 0x0010, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xb1, hi: 0xb3},
+	// Block 0x29, offset 0x167
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x8c},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0xba},
+	{value: 0x0034, lo: 0xbb, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x2a, offset 0x16d
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x84},
+	{value: 0x0010, lo: 0x86, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	{value: 0x0010, lo: 0x94, hi: 0x97},
+	{value: 0x0010, lo: 0x9f, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xba, hi: 0xbf},
+	// Block 0x2b, offset 0x178
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x96},
+	{value: 0x0010, lo: 0x9a, hi: 0xb1},
+	{value: 0x0010, lo: 0xb3, hi: 0xbb},
+	{value: 0x0010, lo: 0xbd, hi: 0xbd},
+	// Block 0x2c, offset 0x17e
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0010, lo: 0x8f, hi: 0x91},
+	{value: 0x0014, lo: 0x92, hi: 0x94},
+	{value: 0x0014, lo: 0x96, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0x9f},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	// Block 0x2d, offset 0x186
+	{value: 0x0014, lo: 0xb1, hi: 0xb1},
+	{value: 0x0014, lo: 0xb4, hi: 0xb7},
+	{value: 0x0034, lo: 0xb8, hi: 0xba},
+	// Block 0x2e, offset 0x189
+	{value: 0x0004, lo: 0x86, hi: 0x86},
+	{value: 0x0014, lo: 0x87, hi: 0x87},
+	{value: 0x0034, lo: 0x88, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0x2f, offset 0x18e
+	{value: 0x0014, lo: 0xb1, hi: 0xb1},
+	{value: 0x0014, lo: 0xb4, hi: 0xb7},
+	{value: 0x0034, lo: 0xb8, hi: 0xba},
+	{value: 0x0014, lo: 0xbb, hi: 0xbc},
+	// Block 0x30, offset 0x192
+	{value: 0x0004, lo: 0x86, hi: 0x86},
+	{value: 0x0034, lo: 0x88, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0x31, offset 0x196
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0034, lo: 0x98, hi: 0x99},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0034, lo: 0xb5, hi: 0xb5},
+	{value: 0x0034, lo: 0xb7, hi: 0xb7},
+	{value: 0x0034, lo: 0xb9, hi: 0xb9},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x32, offset 0x19d
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0010, lo: 0x89, hi: 0xac},
+	{value: 0x0034, lo: 0xb1, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xba, hi: 0xbd},
+	{value: 0x0014, lo: 0xbe, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x33, offset 0x1a6
+	{value: 0x0034, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0024, lo: 0x82, hi: 0x83},
+	{value: 0x0034, lo: 0x84, hi: 0x84},
+	{value: 0x0024, lo: 0x86, hi: 0x87},
+	{value: 0x0010, lo: 0x88, hi: 0x8c},
+	{value: 0x0014, lo: 0x8d, hi: 0x97},
+	{value: 0x0014, lo: 0x99, hi: 0xbc},
+	// Block 0x34, offset 0x1ae
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	// Block 0x35, offset 0x1af
+	{value: 0x0010, lo: 0xab, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb6},
+	{value: 0x0034, lo: 0xb7, hi: 0xb7},
+	{value: 0x0010, lo: 0xb8, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbc},
+	{value: 0x0014, lo: 0xbd, hi: 0xbe},
+	// Block 0x36, offset 0x1b8
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x96, hi: 0x97},
+	{value: 0x0014, lo: 0x98, hi: 0x99},
+	{value: 0x0014, lo: 0x9e, hi: 0xa0},
+	{value: 0x0010, lo: 0xa2, hi: 0xa4},
+	{value: 0x0010, lo: 0xa7, hi: 0xad},
+	{value: 0x0014, lo: 0xb1, hi: 0xb4},
+	// Block 0x37, offset 0x1bf
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x84},
+	{value: 0x0014, lo: 0x85, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x8f, hi: 0x9c},
+	{value: 0x0014, lo: 0x9d, hi: 0x9d},
+	{value: 0x6c53, lo: 0xa0, hi: 0xbf},
+	// Block 0x38, offset 0x1c7
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0x98},
+	{value: 0x0010, lo: 0x9a, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x39, offset 0x1cd
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb5},
+	{value: 0x0010, lo: 0xb8, hi: 0xbe},
+	// Block 0x3a, offset 0x1d2
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x82, hi: 0x85},
+	{value: 0x0010, lo: 0x88, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0xbf},
+	// Block 0x3b, offset 0x1d6
+	{value: 0x0010, lo: 0x80, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0x95},
+	{value: 0x0010, lo: 0x98, hi: 0xbf},
+	// Block 0x3c, offset 0x1d9
+	{value: 0x0010, lo: 0x80, hi: 0x9a},
+	{value: 0x0024, lo: 0x9d, hi: 0x9f},
+	// Block 0x3d, offset 0x1db
+	{value: 0x0010, lo: 0x80, hi: 0x8f},
+	{value: 0x7453, lo: 0xa0, hi: 0xaf},
+	{value: 0x7853, lo: 0xb0, hi: 0xbf},
+	// Block 0x3e, offset 0x1de
+	{value: 0x7c53, lo: 0x80, hi: 0x8f},
+	{value: 0x8053, lo: 0x90, hi: 0x9f},
+	{value: 0x7c53, lo: 0xa0, hi: 0xaf},
+	{value: 0x0813, lo: 0xb0, hi: 0xb5},
+	{value: 0x0892, lo: 0xb8, hi: 0xbd},
+	// Block 0x3f, offset 0x1e3
+	{value: 0x0010, lo: 0x81, hi: 0xbf},
+	// Block 0x40, offset 0x1e4
+	{value: 0x0010, lo: 0x80, hi: 0xac},
+	{value: 0x0010, lo: 0xaf, hi: 0xbf},
+	// Block 0x41, offset 0x1e6
+	{value: 0x0010, lo: 0x81, hi: 0x9a},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x42, offset 0x1e8
+	{value: 0x0010, lo: 0x80, hi: 0xaa},
+	{value: 0x0010, lo: 0xae, hi: 0xb8},
+	// Block 0x43, offset 0x1ea
+	{value: 0x0010, lo: 0x80, hi: 0x91},
+	{value: 0x0014, lo: 0x92, hi: 0x93},
+	{value: 0x0034, lo: 0x94, hi: 0x94},
+	{value: 0x0030, lo: 0x95, hi: 0x95},
+	{value: 0x0010, lo: 0x9f, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb3},
+	{value: 0x0030, lo: 0xb4, hi: 0xb4},
+	// Block 0x44, offset 0x1f1
+	{value: 0x0010, lo: 0x80, hi: 0x91},
+	{value: 0x0014, lo: 0x92, hi: 0x93},
+	{value: 0x0010, lo: 0xa0, hi: 0xac},
+	{value: 0x0010, lo: 0xae, hi: 0xb0},
+	{value: 0x0014, lo: 0xb2, hi: 0xb3},
+	// Block 0x45, offset 0x1f6
+	{value: 0x0014, lo: 0xb4, hi: 0xb5},
+	{value: 0x0010, lo: 0xb6, hi: 0xb6},
+	{value: 0x0014, lo: 0xb7, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x46, offset 0x1fa
+	{value: 0x0010, lo: 0x80, hi: 0x85},
+	{value: 0x0014, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0014, lo: 0x89, hi: 0x91},
+	{value: 0x0034, lo: 0x92, hi: 0x92},
+	{value: 0x0014, lo: 0x93, hi: 0x93},
+	{value: 0x0004, lo: 0x97, hi: 0x97},
+	{value: 0x0024, lo: 0x9d, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	// Block 0x47, offset 0x203
+	{value: 0x0014, lo: 0x8b, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x48, offset 0x206
+	{value: 0x0010, lo: 0x80, hi: 0x82},
+	{value: 0x0014, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x84, hi: 0xb8},
+	// Block 0x49, offset 0x209
+	{value: 0x0010, lo: 0x80, hi: 0x84},
+	{value: 0x0014, lo: 0x85, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0xa8},
+	{value: 0x0034, lo: 0xa9, hi: 0xa9},
+	{value: 0x0010, lo: 0xaa, hi: 0xaa},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x4a, offset 0x20f
+	{value: 0x0010, lo: 0x80, hi: 0xb5},
+	// Block 0x4b, offset 0x210
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	{value: 0x0014, lo: 0xa0, hi: 0xa2},
+	{value: 0x0010, lo: 0xa3, hi: 0xa6},
+	{value: 0x0014, lo: 0xa7, hi: 0xa8},
+	{value: 0x0010, lo: 0xa9, hi: 0xab},
+	{value: 0x0010, lo: 0xb0, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb2},
+	{value: 0x0010, lo: 0xb3, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xb9},
+	{value: 0x0024, lo: 0xba, hi: 0xba},
+	{value: 0x0034, lo: 0xbb, hi: 0xbb},
+	// Block 0x4c, offset 0x21b
+	{value: 0x0010, lo: 0x86, hi: 0x8f},
+	// Block 0x4d, offset 0x21c
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0x4e, offset 0x21d
+	{value: 0x0010, lo: 0x80, hi: 0x96},
+	{value: 0x0024, lo: 0x97, hi: 0x97},
+	{value: 0x0034, lo: 0x98, hi: 0x98},
+	{value: 0x0010, lo: 0x99, hi: 0x9a},
+	{value: 0x0014, lo: 0x9b, hi: 0x9b},
+	// Block 0x4f, offset 0x222
+	{value: 0x0010, lo: 0x95, hi: 0x95},
+	{value: 0x0014, lo: 0x96, hi: 0x96},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0014, lo: 0x98, hi: 0x9e},
+	{value: 0x0034, lo: 0xa0, hi: 0xa0},
+	{value: 0x0010, lo: 0xa1, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa2},
+	{value: 0x0010, lo: 0xa3, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xac},
+	{value: 0x0010, lo: 0xad, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb4},
+	{value: 0x0024, lo: 0xb5, hi: 0xbc},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0x50, offset 0x22f
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0004, lo: 0xa7, hi: 0xa7},
+	{value: 0x0024, lo: 0xb0, hi: 0xb4},
+	{value: 0x0034, lo: 0xb5, hi: 0xba},
+	{value: 0x0024, lo: 0xbb, hi: 0xbc},
+	{value: 0x0034, lo: 0xbd, hi: 0xbd},
+	{value: 0x0014, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0x51, offset 0x238
+	{value: 0x0034, lo: 0x80, hi: 0x80},
+	{value: 0x0024, lo: 0x81, hi: 0x82},
+	{value: 0x0034, lo: 0x83, hi: 0x84},
+	{value: 0x0024, lo: 0x85, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0024, lo: 0x8b, hi: 0x8e},
+	// Block 0x52, offset 0x23e
+	{value: 0x0014, lo: 0x80, hi: 0x83},
+	{value: 0x0010, lo: 0x84, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x53, offset 0x246
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x83},
+	{value: 0x0030, lo: 0x84, hi: 0x84},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0024, lo: 0xab, hi: 0xab},
+	{value: 0x0034, lo: 0xac, hi: 0xac},
+	{value: 0x0024, lo: 0xad, hi: 0xb3},
+	// Block 0x54, offset 0x24f
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa5},
+	{value: 0x0010, lo: 0xa6, hi: 0xa7},
+	{value: 0x0014, lo: 0xa8, hi: 0xa9},
+	{value: 0x0030, lo: 0xaa, hi: 0xaa},
+	{value: 0x0034, lo: 0xab, hi: 0xab},
+	{value: 0x0014, lo: 0xac, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xbf},
+	// Block 0x55, offset 0x258
+	{value: 0x0010, lo: 0x80, hi: 0xa5},
+	{value: 0x0034, lo: 0xa6, hi: 0xa6},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	{value: 0x0014, lo: 0xa8, hi: 0xa9},
+	{value: 0x0010, lo: 0xaa, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xae},
+	{value: 0x0014, lo: 0xaf, hi: 0xb1},
+	{value: 0x0030, lo: 0xb2, hi: 0xb3},
+	// Block 0x56, offset 0x261
+	{value: 0x0010, lo: 0x80, hi: 0xab},
+	{value: 0x0014, lo: 0xac, hi: 0xb3},
+	{value: 0x0010, lo: 0xb4, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xb6},
+	{value: 0x0034, lo: 0xb7, hi: 0xb7},
+	// Block 0x57, offset 0x266
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8d, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xbd},
+	// Block 0x58, offset 0x269
+	{value: 0x31ea, lo: 0x80, hi: 0x80},
+	{value: 0x326a, lo: 0x81, hi: 0x81},
+	{value: 0x32ea, lo: 0x82, hi: 0x82},
+	{value: 0x336a, lo: 0x83, hi: 0x83},
+	{value: 0x33ea, lo: 0x84, hi: 0x84},
+	{value: 0x346a, lo: 0x85, hi: 0x85},
+	{value: 0x34ea, lo: 0x86, hi: 0x86},
+	{value: 0x356a, lo: 0x87, hi: 0x87},
+	{value: 0x35ea, lo: 0x88, hi: 0x88},
+	{value: 0x8353, lo: 0x90, hi: 0xba},
+	{value: 0x8353, lo: 0xbd, hi: 0xbf},
+	// Block 0x59, offset 0x274
+	{value: 0x0024, lo: 0x90, hi: 0x92},
+	{value: 0x0034, lo: 0x94, hi: 0x99},
+	{value: 0x0024, lo: 0x9a, hi: 0x9b},
+	{value: 0x0034, lo: 0x9c, hi: 0x9f},
+	{value: 0x0024, lo: 0xa0, hi: 0xa0},
+	{value: 0x0010, lo: 0xa1, hi: 0xa1},
+	{value: 0x0034, lo: 0xa2, hi: 0xa8},
+	{value: 0x0010, lo: 0xa9, hi: 0xac},
+	{value: 0x0034, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xb3},
+	{value: 0x0024, lo: 0xb4, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb7},
+	{value: 0x0024, lo: 0xb8, hi: 0xb9},
+	{value: 0x0010, lo: 0xba, hi: 0xba},
+	// Block 0x5a, offset 0x282
+	{value: 0x0012, lo: 0x80, hi: 0xab},
+	{value: 0x0015, lo: 0xac, hi: 0xbf},
+	// Block 0x5b, offset 0x284
+	{value: 0x0015, lo: 0x80, hi: 0xaa},
+	{value: 0x0012, lo: 0xab, hi: 0xb7},
+	{value: 0x0015, lo: 0xb8, hi: 0xb8},
+	{value: 0x8752, lo: 0xb9, hi: 0xb9},
+	{value: 0x0012, lo: 0xba, hi: 0xbc},
+	{value: 0x8b52, lo: 0xbd, hi: 0xbd},
+	{value: 0x0012, lo: 0xbe, hi: 0xbf},
+	// Block 0x5c, offset 0x28b
+	{value: 0x0012, lo: 0x80, hi: 0x8d},
+	{value: 0x8f52, lo: 0x8e, hi: 0x8e},
+	{value: 0x0012, lo: 0x8f, hi: 0x9a},
+	{value: 0x0015, lo: 0x9b, hi: 0xbf},
+	// Block 0x5d, offset 0x28f
+	{value: 0x0024, lo: 0x80, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0024, lo: 0x83, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0024, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x90},
+	{value: 0x0024, lo: 0x91, hi: 0xb5},
+	{value: 0x0034, lo: 0xb6, hi: 0xba},
+	{value: 0x0024, lo: 0xbb, hi: 0xbb},
+	{value: 0x0034, lo: 0xbc, hi: 0xbd},
+	{value: 0x0024, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0x5e, offset 0x29b
+	{value: 0x0117, lo: 0x80, hi: 0xbf},
+	// Block 0x5f, offset 0x29c
+	{value: 0x0117, lo: 0x80, hi: 0x95},
+	{value: 0x369a, lo: 0x96, hi: 0x96},
+	{value: 0x374a, lo: 0x97, hi: 0x97},
+	{value: 0x37fa, lo: 0x98, hi: 0x98},
+	{value: 0x38aa, lo: 0x99, hi: 0x99},
+	{value: 0x395a, lo: 0x9a, hi: 0x9a},
+	{value: 0x3a0a, lo: 0x9b, hi: 0x9b},
+	{value: 0x0012, lo: 0x9c, hi: 0x9d},
+	{value: 0x3abb, lo: 0x9e, hi: 0x9e},
+	{value: 0x0012, lo: 0x9f, hi: 0x9f},
+	{value: 0x0117, lo: 0xa0, hi: 0xbf},
+	// Block 0x60, offset 0x2a7
+	{value: 0x0812, lo: 0x80, hi: 0x87},
+	{value: 0x0813, lo: 0x88, hi: 0x8f},
+	{value: 0x0812, lo: 0x90, hi: 0x95},
+	{value: 0x0813, lo: 0x98, hi: 0x9d},
+	{value: 0x0812, lo: 0xa0, hi: 0xa7},
+	{value: 0x0813, lo: 0xa8, hi: 0xaf},
+	{value: 0x0812, lo: 0xb0, hi: 0xb7},
+	{value: 0x0813, lo: 0xb8, hi: 0xbf},
+	// Block 0x61, offset 0x2af
+	{value: 0x0004, lo: 0x8b, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8f},
+	{value: 0x0054, lo: 0x98, hi: 0x99},
+	{value: 0x0054, lo: 0xa4, hi: 0xa4},
+	{value: 0x0054, lo: 0xa7, hi: 0xa7},
+	{value: 0x0014, lo: 0xaa, hi: 0xae},
+	{value: 0x0010, lo: 0xaf, hi: 0xaf},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x62, offset 0x2b7
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x94, hi: 0x94},
+	{value: 0x0014, lo: 0xa0, hi: 0xa4},
+	{value: 0x0014, lo: 0xa6, hi: 0xaf},
+	{value: 0x0015, lo: 0xb1, hi: 0xb1},
+	{value: 0x0015, lo: 0xbf, hi: 0xbf},
+	// Block 0x63, offset 0x2bd
+	{value: 0x0015, lo: 0x90, hi: 0x9c},
+	// Block 0x64, offset 0x2be
+	{value: 0x0024, lo: 0x90, hi: 0x91},
+	{value: 0x0034, lo: 0x92, hi: 0x93},
+	{value: 0x0024, lo: 0x94, hi: 0x97},
+	{value: 0x0034, lo: 0x98, hi: 0x9a},
+	{value: 0x0024, lo: 0x9b, hi: 0x9c},
+	{value: 0x0014, lo: 0x9d, hi: 0xa0},
+	{value: 0x0024, lo: 0xa1, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa4},
+	{value: 0x0034, lo: 0xa5, hi: 0xa6},
+	{value: 0x0024, lo: 0xa7, hi: 0xa7},
+	{value: 0x0034, lo: 0xa8, hi: 0xa8},
+	{value: 0x0024, lo: 0xa9, hi: 0xa9},
+	{value: 0x0034, lo: 0xaa, hi: 0xaf},
+	{value: 0x0024, lo: 0xb0, hi: 0xb0},
+	// Block 0x65, offset 0x2cc
+	{value: 0x0016, lo: 0x85, hi: 0x86},
+	{value: 0x0012, lo: 0x87, hi: 0x89},
+	{value: 0xa452, lo: 0x8e, hi: 0x8e},
+	{value: 0x1013, lo: 0xa0, hi: 0xaf},
+	{value: 0x1012, lo: 0xb0, hi: 0xbf},
+	// Block 0x66, offset 0x2d1
+	{value: 0x0010, lo: 0x80, hi: 0x82},
+	{value: 0x0716, lo: 0x83, hi: 0x84},
+	{value: 0x0010, lo: 0x85, hi: 0x88},
+	// Block 0x67, offset 0x2d4
+	{value: 0xa753, lo: 0xb6, hi: 0xb7},
+	{value: 0xaa53, lo: 0xb8, hi: 0xb9},
+	{value: 0xad53, lo: 0xba, hi: 0xbb},
+	{value: 0xaa53, lo: 0xbc, hi: 0xbd},
+	{value: 0xa753, lo: 0xbe, hi: 0xbf},
+	// Block 0x68, offset 0x2d9
+	{value: 0x3013, lo: 0x80, hi: 0x8f},
+	{value: 0x6553, lo: 0x90, hi: 0x9f},
+	{value: 0xb053, lo: 0xa0, hi: 0xaf},
+	{value: 0x3012, lo: 0xb0, hi: 0xbf},
+	// Block 0x69, offset 0x2dd
+	{value: 0x0117, lo: 0x80, hi: 0xa3},
+	{value: 0x0012, lo: 0xa4, hi: 0xa4},
+	{value: 0x0716, lo: 0xab, hi: 0xac},
+	{value: 0x0316, lo: 0xad, hi: 0xae},
+	{value: 0x0024, lo: 0xaf, hi: 0xb1},
+	{value: 0x0117, lo: 0xb2, hi: 0xb3},
+	// Block 0x6a, offset 0x2e3
+	{value: 0x6c52, lo: 0x80, hi: 0x9f},
+	{value: 0x7052, lo: 0xa0, hi: 0xa5},
+	{value: 0x7052, lo: 0xa7, hi: 0xa7},
+	{value: 0x7052, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x6b, offset 0x2e8
+	{value: 0x0010, lo: 0x80, hi: 0xa7},
+	{value: 0x0014, lo: 0xaf, hi: 0xaf},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0x6c, offset 0x2eb
+	{value: 0x0010, lo: 0x80, hi: 0x96},
+	{value: 0x0010, lo: 0xa0, hi: 0xa6},
+	{value: 0x0010, lo: 0xa8, hi: 0xae},
+	{value: 0x0010, lo: 0xb0, hi: 0xb6},
+	{value: 0x0010, lo: 0xb8, hi: 0xbe},
+	// Block 0x6d, offset 0x2f0
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x88, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0x9e},
+	{value: 0x0024, lo: 0xa0, hi: 0xbf},
+	// Block 0x6e, offset 0x2f5
+	{value: 0x0014, lo: 0xaf, hi: 0xaf},
+	// Block 0x6f, offset 0x2f6
+	{value: 0x0014, lo: 0x85, hi: 0x85},
+	{value: 0x0034, lo: 0xaa, hi: 0xad},
+	{value: 0x0030, lo: 0xae, hi: 0xaf},
+	{value: 0x0004, lo: 0xb1, hi: 0xb5},
+	{value: 0x0014, lo: 0xbb, hi: 0xbb},
+	{value: 0x0010, lo: 0xbc, hi: 0xbc},
+	// Block 0x70, offset 0x2fc
+	{value: 0x0034, lo: 0x99, hi: 0x9a},
+	{value: 0x0004, lo: 0x9b, hi: 0x9e},
+	// Block 0x71, offset 0x2fe
+	{value: 0x0004, lo: 0xbc, hi: 0xbe},
+	// Block 0x72, offset 0x2ff
+	{value: 0x0010, lo: 0x85, hi: 0xaf},
+	{value: 0x0010, lo: 0xb1, hi: 0xbf},
+	// Block 0x73, offset 0x301
+	{value: 0x0010, lo: 0x80, hi: 0x8e},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x74, offset 0x303
+	{value: 0x0010, lo: 0x80, hi: 0x94},
+	{value: 0x0014, lo: 0x95, hi: 0x95},
+	{value: 0x0010, lo: 0x96, hi: 0xbf},
+	// Block 0x75, offset 0x306
+	{value: 0x0010, lo: 0x80, hi: 0x8c},
+	// Block 0x76, offset 0x307
+	{value: 0x0010, lo: 0x90, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xbd},
+	// Block 0x77, offset 0x309
+	{value: 0x0010, lo: 0x80, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8c},
+	{value: 0x0010, lo: 0x90, hi: 0xab},
+	// Block 0x78, offset 0x30c
+	{value: 0x0117, lo: 0x80, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xae},
+	{value: 0x0024, lo: 0xaf, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xb2},
+	{value: 0x0024, lo: 0xb4, hi: 0xbd},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x79, offset 0x312
+	{value: 0x0117, lo: 0x80, hi: 0x9b},
+	{value: 0x0015, lo: 0x9c, hi: 0x9d},
+	{value: 0x0024, lo: 0x9e, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x7a, offset 0x316
+	{value: 0x0010, lo: 0x80, hi: 0xaf},
+	{value: 0x0024, lo: 0xb0, hi: 0xb1},
+	// Block 0x7b, offset 0x318
+	{value: 0x0004, lo: 0x80, hi: 0x87},
+	{value: 0x0014, lo: 0x88, hi: 0xa1},
+	{value: 0x0117, lo: 0xa2, hi: 0xaf},
+	{value: 0x0012, lo: 0xb0, hi: 0xb1},
+	{value: 0x0117, lo: 0xb2, hi: 0xbf},
+	// Block 0x7c, offset 0x31d
+	{value: 0x0117, lo: 0x80, hi: 0xaf},
+	{value: 0x0015, lo: 0xb0, hi: 0xb0},
+	{value: 0x0012, lo: 0xb1, hi: 0xb8},
+	{value: 0x0316, lo: 0xb9, hi: 0xba},
+	{value: 0x0716, lo: 0xbb, hi: 0xbc},
+	{value: 0x8753, lo: 0xbd, hi: 0xbd},
+	{value: 0x0117, lo: 0xbe, hi: 0xbf},
+	// Block 0x7d, offset 0x324
+	{value: 0x0117, lo: 0x80, hi: 0x83},
+	{value: 0x6553, lo: 0x84, hi: 0x84},
+	{value: 0x908b, lo: 0x85, hi: 0x85},
+	{value: 0x8f53, lo: 0x86, hi: 0x86},
+	{value: 0x0f16, lo: 0x87, hi: 0x88},
+	{value: 0x0316, lo: 0x89, hi: 0x8a},
+	{value: 0x0117, lo: 0x90, hi: 0x91},
+	{value: 0x0012, lo: 0x93, hi: 0x93},
+	{value: 0x0012, lo: 0x95, hi: 0x95},
+	{value: 0x0117, lo: 0x96, hi: 0x99},
+	{value: 0x0015, lo: 0xb2, hi: 0xb4},
+	{value: 0x0316, lo: 0xb5, hi: 0xb6},
+	{value: 0x0010, lo: 0xb7, hi: 0xb7},
+	{value: 0x0015, lo: 0xb8, hi: 0xb9},
+	{value: 0x0012, lo: 0xba, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbf},
+	// Block 0x7e, offset 0x334
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x8a},
+	{value: 0x0014, lo: 0x8b, hi: 0x8b},
+	{value: 0x0010, lo: 0x8c, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xa6},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	{value: 0x0034, lo: 0xac, hi: 0xac},
+	// Block 0x7f, offset 0x33e
+	{value: 0x0010, lo: 0x80, hi: 0xb3},
+	// Block 0x80, offset 0x33f
+	{value: 0x0010, lo: 0x80, hi: 0x83},
+	{value: 0x0034, lo: 0x84, hi: 0x84},
+	{value: 0x0014, lo: 0x85, hi: 0x85},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0024, lo: 0xa0, hi: 0xb1},
+	{value: 0x0010, lo: 0xb2, hi: 0xb7},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	{value: 0x0010, lo: 0xbd, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x81, offset 0x348
+	{value: 0x0010, lo: 0x80, hi: 0xa5},
+	{value: 0x0014, lo: 0xa6, hi: 0xaa},
+	{value: 0x0034, lo: 0xab, hi: 0xad},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x82, offset 0x34c
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0014, lo: 0x87, hi: 0x91},
+	{value: 0x0010, lo: 0x92, hi: 0x92},
+	{value: 0x0030, lo: 0x93, hi: 0x93},
+	{value: 0x0010, lo: 0xa0, hi: 0xbc},
+	// Block 0x83, offset 0x351
+	{value: 0x0014, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0xb2},
+	{value: 0x0034, lo: 0xb3, hi: 0xb3},
+	{value: 0x0010, lo: 0xb4, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xb9},
+	{value: 0x0010, lo: 0xba, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x84, offset 0x359
+	{value: 0x0030, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0014, lo: 0xa5, hi: 0xa5},
+	{value: 0x0004, lo: 0xa6, hi: 0xa6},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x85, offset 0x35f
+	{value: 0x0010, lo: 0x80, hi: 0xa8},
+	{value: 0x0014, lo: 0xa9, hi: 0xae},
+	{value: 0x0010, lo: 0xaf, hi: 0xb0},
+	{value: 0x0014, lo: 0xb1, hi: 0xb2},
+	{value: 0x0010, lo: 0xb3, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb6},
+	// Block 0x86, offset 0x365
+	{value: 0x0010, lo: 0x80, hi: 0x82},
+	{value: 0x0014, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x84, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8c},
+	{value: 0x0010, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0004, lo: 0xb0, hi: 0xb0},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbd},
+	// Block 0x87, offset 0x36f
+	{value: 0x0024, lo: 0xb0, hi: 0xb0},
+	{value: 0x0024, lo: 0xb2, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0024, lo: 0xb7, hi: 0xb8},
+	{value: 0x0024, lo: 0xbe, hi: 0xbf},
+	// Block 0x88, offset 0x374
+	{value: 0x0024, lo: 0x81, hi: 0x81},
+	{value: 0x0004, lo: 0x9d, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xab},
+	{value: 0x0014, lo: 0xac, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xaf},
+	{value: 0x0010, lo: 0xb2, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb5},
+	{value: 0x0034, lo: 0xb6, hi: 0xb6},
+	// Block 0x89, offset 0x37d
+	{value: 0x0010, lo: 0x81, hi: 0x86},
+	{value: 0x0010, lo: 0x89, hi: 0x8e},
+	{value: 0x0010, lo: 0x91, hi: 0x96},
+	{value: 0x0010, lo: 0xa0, hi: 0xa6},
+	{value: 0x0010, lo: 0xa8, hi: 0xae},
+	{value: 0x0012, lo: 0xb0, hi: 0xbf},
+	// Block 0x8a, offset 0x383
+	{value: 0x0012, lo: 0x80, hi: 0x92},
+	{value: 0xb352, lo: 0x93, hi: 0x93},
+	{value: 0x0012, lo: 0x94, hi: 0x9a},
+	{value: 0x0014, lo: 0x9b, hi: 0x9b},
+	{value: 0x0015, lo: 0x9c, hi: 0x9f},
+	{value: 0x0012, lo: 0xa0, hi: 0xa8},
+	{value: 0x0015, lo: 0xa9, hi: 0xa9},
+	{value: 0x0004, lo: 0xaa, hi: 0xab},
+	{value: 0x74d2, lo: 0xb0, hi: 0xbf},
+	// Block 0x8b, offset 0x38c
+	{value: 0x78d2, lo: 0x80, hi: 0x8f},
+	{value: 0x7cd2, lo: 0x90, hi: 0x9f},
+	{value: 0x80d2, lo: 0xa0, hi: 0xaf},
+	{value: 0x7cd2, lo: 0xb0, hi: 0xbf},
+	// Block 0x8c, offset 0x390
+	{value: 0x0010, lo: 0x80, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xa5},
+	{value: 0x0010, lo: 0xa6, hi: 0xa7},
+	{value: 0x0014, lo: 0xa8, hi: 0xa8},
+	{value: 0x0010, lo: 0xa9, hi: 0xaa},
+	{value: 0x0010, lo: 0xac, hi: 0xac},
+	{value: 0x0034, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x8d, offset 0x398
+	{value: 0x0010, lo: 0x80, hi: 0xa3},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x8e, offset 0x39a
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x8b, hi: 0xbb},
+	// Block 0x8f, offset 0x39c
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x83, hi: 0x84},
+	{value: 0x0010, lo: 0x86, hi: 0xbf},
+	// Block 0x90, offset 0x39f
+	{value: 0x0010, lo: 0x80, hi: 0xb1},
+	{value: 0x0004, lo: 0xb2, hi: 0xbf},
+	// Block 0x91, offset 0x3a1
+	{value: 0x0004, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x93, hi: 0xbf},
+	// Block 0x92, offset 0x3a3
+	{value: 0x0010, lo: 0x80, hi: 0xbd},
+	// Block 0x93, offset 0x3a4
+	{value: 0x0010, lo: 0x90, hi: 0xbf},
+	// Block 0x94, offset 0x3a5
+	{value: 0x0010, lo: 0x80, hi: 0x8f},
+	{value: 0x0010, lo: 0x92, hi: 0xbf},
+	// Block 0x95, offset 0x3a7
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0010, lo: 0xb0, hi: 0xbb},
+	// Block 0x96, offset 0x3a9
+	{value: 0x0014, lo: 0x80, hi: 0x8f},
+	{value: 0x0054, lo: 0x93, hi: 0x93},
+	{value: 0x0024, lo: 0xa0, hi: 0xa6},
+	{value: 0x0034, lo: 0xa7, hi: 0xad},
+	{value: 0x0024, lo: 0xae, hi: 0xaf},
+	{value: 0x0010, lo: 0xb3, hi: 0xb4},
+	// Block 0x97, offset 0x3af
+	{value: 0x0010, lo: 0x8d, hi: 0x8f},
+	{value: 0x0054, lo: 0x92, hi: 0x92},
+	{value: 0x0054, lo: 0x95, hi: 0x95},
+	{value: 0x0010, lo: 0xb0, hi: 0xb4},
+	{value: 0x0010, lo: 0xb6, hi: 0xbf},
+	// Block 0x98, offset 0x3b4
+	{value: 0x0010, lo: 0x80, hi: 0xbc},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x99, offset 0x3b6
+	{value: 0x0054, lo: 0x87, hi: 0x87},
+	{value: 0x0054, lo: 0x8e, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0054, lo: 0x9a, hi: 0x9a},
+	{value: 0x5f53, lo: 0xa1, hi: 0xba},
+	{value: 0x0004, lo: 0xbe, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x9a, offset 0x3bd
+	{value: 0x0004, lo: 0x80, hi: 0x80},
+	{value: 0x5f52, lo: 0x81, hi: 0x9a},
+	{value: 0x0004, lo: 0xb0, hi: 0xb0},
+	// Block 0x9b, offset 0x3c0
+	{value: 0x0014, lo: 0x9e, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xbe},
+	// Block 0x9c, offset 0x3c2
+	{value: 0x0010, lo: 0x82, hi: 0x87},
+	{value: 0x0010, lo: 0x8a, hi: 0x8f},
+	{value: 0x0010, lo: 0x92, hi: 0x97},
+	{value: 0x0010, lo: 0x9a, hi: 0x9c},
+	{value: 0x0004, lo: 0xa3, hi: 0xa3},
+	{value: 0x0014, lo: 0xb9, hi: 0xbb},
+	// Block 0x9d, offset 0x3c8
+	{value: 0x0010, lo: 0x80, hi: 0x8b},
+	{value: 0x0010, lo: 0x8d, hi: 0xa6},
+	{value: 0x0010, lo: 0xa8, hi: 0xba},
+	{value: 0x0010, lo: 0xbc, hi: 0xbd},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x9e, offset 0x3cd
+	{value: 0x0010, lo: 0x80, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x9d},
+	// Block 0x9f, offset 0x3cf
+	{value: 0x0010, lo: 0x80, hi: 0xba},
+	// Block 0xa0, offset 0x3d0
+	{value: 0x0010, lo: 0x80, hi: 0xb4},
+	// Block 0xa1, offset 0x3d1
+	{value: 0x0034, lo: 0xbd, hi: 0xbd},
+	// Block 0xa2, offset 0x3d2
+	{value: 0x0010, lo: 0x80, hi: 0x9c},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0xa3, offset 0x3d4
+	{value: 0x0010, lo: 0x80, hi: 0x90},
+	{value: 0x0034, lo: 0xa0, hi: 0xa0},
+	// Block 0xa4, offset 0x3d6
+	{value: 0x0010, lo: 0x80, hi: 0x9f},
+	{value: 0x0010, lo: 0xad, hi: 0xbf},
+	// Block 0xa5, offset 0x3d8
+	{value: 0x0010, lo: 0x80, hi: 0x8a},
+	{value: 0x0010, lo: 0x90, hi: 0xb5},
+	{value: 0x0024, lo: 0xb6, hi: 0xba},
+	// Block 0xa6, offset 0x3db
+	{value: 0x0010, lo: 0x80, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0xa7, offset 0x3dd
+	{value: 0x0010, lo: 0x80, hi: 0x83},
+	{value: 0x0010, lo: 0x88, hi: 0x8f},
+	{value: 0x0010, lo: 0x91, hi: 0x95},
+	// Block 0xa8, offset 0x3e0
+	{value: 0x2813, lo: 0x80, hi: 0x87},
+	{value: 0x3813, lo: 0x88, hi: 0x8f},
+	{value: 0x2813, lo: 0x90, hi: 0x97},
+	{value: 0xb653, lo: 0x98, hi: 0x9f},
+	{value: 0xb953, lo: 0xa0, hi: 0xa7},
+	{value: 0x2812, lo: 0xa8, hi: 0xaf},
+	{value: 0x3812, lo: 0xb0, hi: 0xb7},
+	{value: 0x2812, lo: 0xb8, hi: 0xbf},
+	// Block 0xa9, offset 0x3e8
+	{value: 0xb652, lo: 0x80, hi: 0x87},
+	{value: 0xb952, lo: 0x88, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0xbf},
+	// Block 0xaa, offset 0x3eb
+	{value: 0x0010, lo: 0x80, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0xb953, lo: 0xb0, hi: 0xb7},
+	{value: 0xb653, lo: 0xb8, hi: 0xbf},
+	// Block 0xab, offset 0x3ef
+	{value: 0x2813, lo: 0x80, hi: 0x87},
+	{value: 0x3813, lo: 0x88, hi: 0x8f},
+	{value: 0x2813, lo: 0x90, hi: 0x93},
+	{value: 0xb952, lo: 0x98, hi: 0x9f},
+	{value: 0xb652, lo: 0xa0, hi: 0xa7},
+	{value: 0x2812, lo: 0xa8, hi: 0xaf},
+	{value: 0x3812, lo: 0xb0, hi: 0xb7},
+	{value: 0x2812, lo: 0xb8, hi: 0xbb},
+	// Block 0xac, offset 0x3f7
+	{value: 0x0010, lo: 0x80, hi: 0xa7},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xad, offset 0x3f9
+	{value: 0x0010, lo: 0x80, hi: 0xa3},
+	{value: 0xbc53, lo: 0xb0, hi: 0xb0},
+	{value: 0xbf53, lo: 0xb1, hi: 0xb1},
+	{value: 0xc253, lo: 0xb2, hi: 0xb2},
+	{value: 0xbf53, lo: 0xb3, hi: 0xb3},
+	{value: 0xc553, lo: 0xb4, hi: 0xb4},
+	{value: 0xbf53, lo: 0xb5, hi: 0xb5},
+	{value: 0xc253, lo: 0xb6, hi: 0xb6},
+	{value: 0xbf53, lo: 0xb7, hi: 0xb7},
+	{value: 0xbc53, lo: 0xb8, hi: 0xb8},
+	{value: 0xc853, lo: 0xb9, hi: 0xb9},
+	{value: 0xcb53, lo: 0xba, hi: 0xba},
+	{value: 0xce53, lo: 0xbc, hi: 0xbc},
+	{value: 0xc853, lo: 0xbd, hi: 0xbd},
+	{value: 0xcb53, lo: 0xbe, hi: 0xbe},
+	{value: 0xc853, lo: 0xbf, hi: 0xbf},
+	// Block 0xae, offset 0x409
+	{value: 0x0010, lo: 0x80, hi: 0xb6},
+	// Block 0xaf, offset 0x40a
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xa7},
+	// Block 0xb0, offset 0x40c
+	{value: 0x0015, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x82},
+	{value: 0x0015, lo: 0x83, hi: 0x85},
+	{value: 0x0015, lo: 0x87, hi: 0xb0},
+	{value: 0x0015, lo: 0xb2, hi: 0xba},
+	// Block 0xb1, offset 0x411
+	{value: 0x0010, lo: 0x80, hi: 0x85},
+	{value: 0x0010, lo: 0x88, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0xb5},
+	{value: 0x0010, lo: 0xb7, hi: 0xb8},
+	{value: 0x0010, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xb2, offset 0x417
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xb6},
+	// Block 0xb3, offset 0x419
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	// Block 0xb4, offset 0x41a
+	{value: 0x0010, lo: 0xa0, hi: 0xb2},
+	{value: 0x0010, lo: 0xb4, hi: 0xb5},
+	// Block 0xb5, offset 0x41c
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xb9},
+	// Block 0xb6, offset 0x41e
+	{value: 0x0010, lo: 0x80, hi: 0xb7},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0xb7, offset 0x420
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x83},
+	{value: 0x0014, lo: 0x85, hi: 0x86},
+	{value: 0x0014, lo: 0x8c, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0014, lo: 0x8e, hi: 0x8e},
+	{value: 0x0024, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x93},
+	{value: 0x0010, lo: 0x95, hi: 0x97},
+	{value: 0x0010, lo: 0x99, hi: 0xb5},
+	{value: 0x0024, lo: 0xb8, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xba},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xb8, offset 0x42d
+	{value: 0x0010, lo: 0xa0, hi: 0xbc},
+	// Block 0xb9, offset 0x42e
+	{value: 0x0010, lo: 0x80, hi: 0x9c},
+	// Block 0xba, offset 0x42f
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0010, lo: 0x89, hi: 0xa4},
+	{value: 0x0024, lo: 0xa5, hi: 0xa5},
+	{value: 0x0034, lo: 0xa6, hi: 0xa6},
+	// Block 0xbb, offset 0x433
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xb2},
+	// Block 0xbc, offset 0x435
+	{value: 0x0010, lo: 0x80, hi: 0x91},
+	// Block 0xbd, offset 0x436
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	// Block 0xbe, offset 0x437
+	{value: 0x5653, lo: 0x80, hi: 0xb2},
+	// Block 0xbf, offset 0x438
+	{value: 0x5652, lo: 0x80, hi: 0xb2},
+	// Block 0xc0, offset 0x439
+	{value: 0x0010, lo: 0x80, hi: 0xa3},
+	{value: 0x0024, lo: 0xa4, hi: 0xa7},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xc1, offset 0x43c
+	{value: 0x0010, lo: 0x80, hi: 0xa9},
+	{value: 0x0024, lo: 0xab, hi: 0xac},
+	{value: 0x0010, lo: 0xb0, hi: 0xb1},
+	// Block 0xc2, offset 0x43f
+	{value: 0x0034, lo: 0xbd, hi: 0xbf},
+	// Block 0xc3, offset 0x440
+	{value: 0x0010, lo: 0x80, hi: 0x9c},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xc4, offset 0x443
+	{value: 0x0010, lo: 0x80, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x87},
+	{value: 0x0024, lo: 0x88, hi: 0x8a},
+	{value: 0x0034, lo: 0x8b, hi: 0x8b},
+	{value: 0x0024, lo: 0x8c, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x90},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xc5, offset 0x44a
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0024, lo: 0x82, hi: 0x82},
+	{value: 0x0034, lo: 0x83, hi: 0x83},
+	{value: 0x0024, lo: 0x84, hi: 0x84},
+	{value: 0x0034, lo: 0x85, hi: 0x85},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xc6, offset 0x450
+	{value: 0x0010, lo: 0x80, hi: 0x84},
+	{value: 0x0010, lo: 0xa0, hi: 0xb6},
+	// Block 0xc7, offset 0x452
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xbf},
+	// Block 0xc8, offset 0x456
+	{value: 0x0014, lo: 0x80, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0034, lo: 0xb0, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb5},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xc9, offset 0x45e
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb6},
+	{value: 0x0010, lo: 0xb7, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xba},
+	{value: 0x0014, lo: 0xbd, hi: 0xbd},
+	// Block 0xca, offset 0x464
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0014, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0xa8},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xcb, offset 0x468
+	{value: 0x0024, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0xa6},
+	{value: 0x0014, lo: 0xa7, hi: 0xab},
+	{value: 0x0010, lo: 0xac, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xb2},
+	{value: 0x0034, lo: 0xb3, hi: 0xb4},
+	{value: 0x0010, lo: 0xb6, hi: 0xbf},
+	// Block 0xcc, offset 0x46f
+	{value: 0x0010, lo: 0x84, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0xb2},
+	{value: 0x0034, lo: 0xb3, hi: 0xb3},
+	{value: 0x0010, lo: 0xb6, hi: 0xb6},
+	// Block 0xcd, offset 0x473
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xce, offset 0x477
+	{value: 0x0030, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x84},
+	{value: 0x0014, lo: 0x89, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0014, lo: 0x8b, hi: 0x8c},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	{value: 0x0014, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x9a},
+	{value: 0x0010, lo: 0x9c, hi: 0x9c},
+	// Block 0xcf, offset 0x480
+	{value: 0x0010, lo: 0x80, hi: 0x91},
+	{value: 0x0010, lo: 0x93, hi: 0xae},
+	{value: 0x0014, lo: 0xaf, hi: 0xb1},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0014, lo: 0xb4, hi: 0xb4},
+	{value: 0x0030, lo: 0xb5, hi: 0xb5},
+	{value: 0x0034, lo: 0xb6, hi: 0xb6},
+	{value: 0x0014, lo: 0xb7, hi: 0xb7},
+	{value: 0x0014, lo: 0xbe, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xd0, offset 0x48a
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	// Block 0xd1, offset 0x48c
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x88, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8d},
+	{value: 0x0010, lo: 0x8f, hi: 0x9d},
+	{value: 0x0010, lo: 0x9f, hi: 0xa8},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xd2, offset 0x492
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	{value: 0x0014, lo: 0x9f, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xa2},
+	{value: 0x0014, lo: 0xa3, hi: 0xa8},
+	{value: 0x0034, lo: 0xa9, hi: 0xaa},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xd3, offset 0x498
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8f, hi: 0x90},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xbb, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0xd4, offset 0x4a2
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x84},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x8b, hi: 0x8c},
+	{value: 0x0030, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0x9d, hi: 0xa3},
+	{value: 0x0024, lo: 0xa6, hi: 0xac},
+	{value: 0x0024, lo: 0xb0, hi: 0xb4},
+	// Block 0xd5, offset 0x4ac
+	{value: 0x0010, lo: 0x80, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xbf},
+	// Block 0xd6, offset 0x4ae
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0014, lo: 0x83, hi: 0x84},
+	{value: 0x0010, lo: 0x85, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x8a},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0024, lo: 0x9e, hi: 0x9e},
+	{value: 0x0010, lo: 0x9f, hi: 0xa1},
+	// Block 0xd7, offset 0x4b7
+	{value: 0x0010, lo: 0x80, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb8},
+	{value: 0x0010, lo: 0xb9, hi: 0xb9},
+	{value: 0x0014, lo: 0xba, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0xd8, offset 0x4bd
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x84, hi: 0x85},
+	{value: 0x0010, lo: 0x87, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0xd9, offset 0x4c3
+	{value: 0x0010, lo: 0x80, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb5},
+	{value: 0x0010, lo: 0xb8, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xda, offset 0x4c9
+	{value: 0x0034, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x98, hi: 0x9b},
+	{value: 0x0014, lo: 0x9c, hi: 0x9d},
+	// Block 0xdb, offset 0x4cc
+	{value: 0x0010, lo: 0x80, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbc},
+	{value: 0x0014, lo: 0xbd, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xdc, offset 0x4d2
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x84, hi: 0x84},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0xdd, offset 0x4d5
+	{value: 0x0010, lo: 0x80, hi: 0xaa},
+	{value: 0x0014, lo: 0xab, hi: 0xab},
+	{value: 0x0010, lo: 0xac, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xb5},
+	{value: 0x0030, lo: 0xb6, hi: 0xb6},
+	{value: 0x0034, lo: 0xb7, hi: 0xb7},
+	{value: 0x0010, lo: 0xb8, hi: 0xb8},
+	// Block 0xde, offset 0x4de
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	// Block 0xdf, offset 0x4df
+	{value: 0x0014, lo: 0x9d, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa5},
+	{value: 0x0010, lo: 0xa6, hi: 0xa6},
+	{value: 0x0014, lo: 0xa7, hi: 0xaa},
+	{value: 0x0034, lo: 0xab, hi: 0xab},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xe0, offset 0x4e6
+	{value: 0x0010, lo: 0x80, hi: 0xae},
+	{value: 0x0014, lo: 0xaf, hi: 0xb7},
+	{value: 0x0010, lo: 0xb8, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xba},
+	// Block 0xe1, offset 0x4ea
+	{value: 0x5f53, lo: 0xa0, hi: 0xbf},
+	// Block 0xe2, offset 0x4eb
+	{value: 0x5f52, lo: 0x80, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xe3, offset 0x4ee
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x89, hi: 0x89},
+	{value: 0x0010, lo: 0x8c, hi: 0x93},
+	{value: 0x0010, lo: 0x95, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0xb5},
+	{value: 0x0010, lo: 0xb7, hi: 0xb8},
+	{value: 0x0014, lo: 0xbb, hi: 0xbc},
+	{value: 0x0030, lo: 0xbd, hi: 0xbd},
+	{value: 0x0034, lo: 0xbe, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xe4, offset 0x4f8
+	{value: 0x0010, lo: 0x80, hi: 0x82},
+	{value: 0x0034, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0xe5, offset 0x4fb
+	{value: 0x0010, lo: 0xa0, hi: 0xa7},
+	{value: 0x0010, lo: 0xaa, hi: 0xbf},
+	// Block 0xe6, offset 0x4fd
+	{value: 0x0010, lo: 0x80, hi: 0x93},
+	{value: 0x0014, lo: 0x94, hi: 0x97},
+	{value: 0x0014, lo: 0x9a, hi: 0x9b},
+	{value: 0x0010, lo: 0x9c, hi: 0x9f},
+	{value: 0x0034, lo: 0xa0, hi: 0xa0},
+	{value: 0x0010, lo: 0xa1, hi: 0xa1},
+	{value: 0x0010, lo: 0xa3, hi: 0xa4},
+	// Block 0xe7, offset 0x504
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x8a},
+	{value: 0x0010, lo: 0x8b, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb8},
+	{value: 0x0010, lo: 0xb9, hi: 0xba},
+	{value: 0x0014, lo: 0xbb, hi: 0xbe},
+	// Block 0xe8, offset 0x50c
+	{value: 0x0034, lo: 0x87, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0014, lo: 0x91, hi: 0x96},
+	{value: 0x0010, lo: 0x97, hi: 0x98},
+	{value: 0x0014, lo: 0x99, hi: 0x9b},
+	{value: 0x0010, lo: 0x9c, hi: 0xbf},
+	// Block 0xe9, offset 0x512
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0014, lo: 0x8a, hi: 0x96},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0014, lo: 0x98, hi: 0x98},
+	{value: 0x0034, lo: 0x99, hi: 0x99},
+	{value: 0x0010, lo: 0x9d, hi: 0x9d},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xea, offset 0x519
+	{value: 0x0010, lo: 0x80, hi: 0xb8},
+	// Block 0xeb, offset 0x51a
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xb6},
+	{value: 0x0014, lo: 0xb8, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xec, offset 0x520
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0010, lo: 0xb2, hi: 0xbf},
+	// Block 0xed, offset 0x523
+	{value: 0x0010, lo: 0x80, hi: 0x8f},
+	{value: 0x0014, lo: 0x92, hi: 0xa7},
+	{value: 0x0010, lo: 0xa9, hi: 0xa9},
+	{value: 0x0014, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb4, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb6},
+	// Block 0xee, offset 0x52b
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x88, hi: 0x89},
+	{value: 0x0010, lo: 0x8b, hi: 0xb0},
+	{value: 0x0014, lo: 0xb1, hi: 0xb6},
+	{value: 0x0014, lo: 0xba, hi: 0xba},
+	{value: 0x0014, lo: 0xbc, hi: 0xbd},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0xef, offset 0x532
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0014, lo: 0x83, hi: 0x83},
+	{value: 0x0034, lo: 0x84, hi: 0x85},
+	{value: 0x0010, lo: 0x86, hi: 0x86},
+	{value: 0x0014, lo: 0x87, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0010, lo: 0xa0, hi: 0xa5},
+	{value: 0x0010, lo: 0xa7, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xbf},
+	// Block 0xf0, offset 0x53c
+	{value: 0x0010, lo: 0x80, hi: 0x8e},
+	{value: 0x0014, lo: 0x90, hi: 0x91},
+	{value: 0x0010, lo: 0x93, hi: 0x94},
+	{value: 0x0014, lo: 0x95, hi: 0x95},
+	{value: 0x0010, lo: 0x96, hi: 0x96},
+	{value: 0x0034, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0x98, hi: 0x98},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	// Block 0xf1, offset 0x544
+	{value: 0x0010, lo: 0xa0, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb6},
+	// Block 0xf2, offset 0x547
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xba},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0xf3, offset 0x54c
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0030, lo: 0x81, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0xf4, offset 0x550
+	{value: 0x0010, lo: 0xb0, hi: 0xb0},
+	// Block 0xf5, offset 0x551
+	{value: 0x0010, lo: 0x80, hi: 0x99},
+	// Block 0xf6, offset 0x552
+	{value: 0x0010, lo: 0x80, hi: 0xae},
+	// Block 0xf7, offset 0x553
+	{value: 0x0010, lo: 0x80, hi: 0x83},
+	// Block 0xf8, offset 0x554
+	{value: 0x0010, lo: 0x80, hi: 0xb0},
+	// Block 0xf9, offset 0x555
+	{value: 0x0010, lo: 0x80, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xbf},
+	// Block 0xfa, offset 0x557
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x86},
+	{value: 0x0014, lo: 0x87, hi: 0x95},
+	// Block 0xfb, offset 0x55a
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	// Block 0xfc, offset 0x55b
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xfd, offset 0x55e
+	{value: 0x0010, lo: 0x80, hi: 0xbe},
+	// Block 0xfe, offset 0x55f
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x90, hi: 0xad},
+	{value: 0x0034, lo: 0xb0, hi: 0xb4},
+	// Block 0xff, offset 0x562
+	{value: 0x0010, lo: 0x80, hi: 0xaf},
+	{value: 0x0024, lo: 0xb0, hi: 0xb6},
+	// Block 0x100, offset 0x564
+	{value: 0x0014, lo: 0x80, hi: 0x83},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0010, lo: 0xa3, hi: 0xb7},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x101, offset 0x568
+	{value: 0x0010, lo: 0x80, hi: 0x8f},
+	// Block 0x102, offset 0x569
+	{value: 0x2013, lo: 0x80, hi: 0x9f},
+	{value: 0x2012, lo: 0xa0, hi: 0xbf},
+	// Block 0x103, offset 0x56b
+	{value: 0x0010, lo: 0x80, hi: 0x8a},
+	{value: 0x0014, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0xbf},
+	// Block 0x104, offset 0x56e
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0014, lo: 0x8f, hi: 0x9f},
+	// Block 0x105, offset 0x570
+	{value: 0x0014, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa3, hi: 0xa4},
+	{value: 0x0030, lo: 0xb0, hi: 0xb1},
+	// Block 0x106, offset 0x573
+	{value: 0x0004, lo: 0xb0, hi: 0xb3},
+	{value: 0x0004, lo: 0xb5, hi: 0xbb},
+	{value: 0x0004, lo: 0xbd, hi: 0xbe},
+	// Block 0x107, offset 0x576
+	{value: 0x0010, lo: 0x80, hi: 0xaa},
+	{value: 0x0010, lo: 0xb0, hi: 0xbc},
+	// Block 0x108, offset 0x578
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0014, lo: 0x9d, hi: 0x9d},
+	{value: 0x0034, lo: 0x9e, hi: 0x9e},
+	{value: 0x0014, lo: 0xa0, hi: 0xa3},
+	// Block 0x109, offset 0x57d
+	{value: 0x0014, lo: 0x80, hi: 0xad},
+	{value: 0x0014, lo: 0xb0, hi: 0xbf},
+	// Block 0x10a, offset 0x57f
+	{value: 0x0014, lo: 0x80, hi: 0x86},
+	// Block 0x10b, offset 0x580
+	{value: 0x0030, lo: 0xa5, hi: 0xa6},
+	{value: 0x0034, lo: 0xa7, hi: 0xa9},
+	{value: 0x0030, lo: 0xad, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xba},
+	{value: 0x0034, lo: 0xbb, hi: 0xbf},
+	// Block 0x10c, offset 0x585
+	{value: 0x0034, lo: 0x80, hi: 0x82},
+	{value: 0x0024, lo: 0x85, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8b},
+	{value: 0x0024, lo: 0xaa, hi: 0xad},
+	// Block 0x10d, offset 0x589
+	{value: 0x0024, lo: 0x82, hi: 0x84},
+	// Block 0x10e, offset 0x58a
+	{value: 0x0013, lo: 0x80, hi: 0x99},
+	{value: 0x0012, lo: 0x9a, hi: 0xb3},
+	{value: 0x0013, lo: 0xb4, hi: 0xbf},
+	// Block 0x10f, offset 0x58d
+	{value: 0x0013, lo: 0x80, hi: 0x8d},
+	{value: 0x0012, lo: 0x8e, hi: 0x94},
+	{value: 0x0012, lo: 0x96, hi: 0xa7},
+	{value: 0x0013, lo: 0xa8, hi: 0xbf},
+	// Block 0x110, offset 0x591
+	{value: 0x0013, lo: 0x80, hi: 0x81},
+	{value: 0x0012, lo: 0x82, hi: 0x9b},
+	{value: 0x0013, lo: 0x9c, hi: 0x9c},
+	{value: 0x0013, lo: 0x9e, hi: 0x9f},
+	{value: 0x0013, lo: 0xa2, hi: 0xa2},
+	{value: 0x0013, lo: 0xa5, hi: 0xa6},
+	{value: 0x0013, lo: 0xa9, hi: 0xac},
+	{value: 0x0013, lo: 0xae, hi: 0xb5},
+	{value: 0x0012, lo: 0xb6, hi: 0xb9},
+	{value: 0x0012, lo: 0xbb, hi: 0xbb},
+	{value: 0x0012, lo: 0xbd, hi: 0xbf},
+	// Block 0x111, offset 0x59c
+	{value: 0x0012, lo: 0x80, hi: 0x83},
+	{value: 0x0012, lo: 0x85, hi: 0x8f},
+	{value: 0x0013, lo: 0x90, hi: 0xa9},
+	{value: 0x0012, lo: 0xaa, hi: 0xbf},
+	// Block 0x112, offset 0x5a0
+	{value: 0x0012, lo: 0x80, hi: 0x83},
+	{value: 0x0013, lo: 0x84, hi: 0x85},
+	{value: 0x0013, lo: 0x87, hi: 0x8a},
+	{value: 0x0013, lo: 0x8d, hi: 0x94},
+	{value: 0x0013, lo: 0x96, hi: 0x9c},
+	{value: 0x0012, lo: 0x9e, hi: 0xb7},
+	{value: 0x0013, lo: 0xb8, hi: 0xb9},
+	{value: 0x0013, lo: 0xbb, hi: 0xbe},
+	// Block 0x113, offset 0x5a8
+	{value: 0x0013, lo: 0x80, hi: 0x84},
+	{value: 0x0013, lo: 0x86, hi: 0x86},
+	{value: 0x0013, lo: 0x8a, hi: 0x90},
+	{value: 0x0012, lo: 0x92, hi: 0xab},
+	{value: 0x0013, lo: 0xac, hi: 0xbf},
+	// Block 0x114, offset 0x5ad
+	{value: 0x0013, lo: 0x80, hi: 0x85},
+	{value: 0x0012, lo: 0x86, hi: 0x9f},
+	{value: 0x0013, lo: 0xa0, hi: 0xb9},
+	{value: 0x0012, lo: 0xba, hi: 0xbf},
+	// Block 0x115, offset 0x5b1
+	{value: 0x0012, lo: 0x80, hi: 0x93},
+	{value: 0x0013, lo: 0x94, hi: 0xad},
+	{value: 0x0012, lo: 0xae, hi: 0xbf},
+	// Block 0x116, offset 0x5b4
+	{value: 0x0012, lo: 0x80, hi: 0x87},
+	{value: 0x0013, lo: 0x88, hi: 0xa1},
+	{value: 0x0012, lo: 0xa2, hi: 0xbb},
+	{value: 0x0013, lo: 0xbc, hi: 0xbf},
+	// Block 0x117, offset 0x5b8
+	{value: 0x0013, lo: 0x80, hi: 0x95},
+	{value: 0x0012, lo: 0x96, hi: 0xaf},
+	{value: 0x0013, lo: 0xb0, hi: 0xbf},
+	// Block 0x118, offset 0x5bb
+	{value: 0x0013, lo: 0x80, hi: 0x89},
+	{value: 0x0012, lo: 0x8a, hi: 0xa5},
+	{value: 0x0013, lo: 0xa8, hi: 0xbf},
+	// Block 0x119, offset 0x5be
+	{value: 0x0013, lo: 0x80, hi: 0x80},
+	{value: 0x0012, lo: 0x82, hi: 0x9a},
+	{value: 0x0012, lo: 0x9c, hi: 0xa1},
+	{value: 0x0013, lo: 0xa2, hi: 0xba},
+	{value: 0x0012, lo: 0xbc, hi: 0xbf},
+	// Block 0x11a, offset 0x5c3
+	{value: 0x0012, lo: 0x80, hi: 0x94},
+	{value: 0x0012, lo: 0x96, hi: 0x9b},
+	{value: 0x0013, lo: 0x9c, hi: 0xb4},
+	{value: 0x0012, lo: 0xb6, hi: 0xbf},
+	// Block 0x11b, offset 0x5c7
+	{value: 0x0012, lo: 0x80, hi: 0x8e},
+	{value: 0x0012, lo: 0x90, hi: 0x95},
+	{value: 0x0013, lo: 0x96, hi: 0xae},
+	{value: 0x0012, lo: 0xb0, hi: 0xbf},
+	// Block 0x11c, offset 0x5cb
+	{value: 0x0012, lo: 0x80, hi: 0x88},
+	{value: 0x0012, lo: 0x8a, hi: 0x8f},
+	{value: 0x0013, lo: 0x90, hi: 0xa8},
+	{value: 0x0012, lo: 0xaa, hi: 0xbf},
+	// Block 0x11d, offset 0x5cf
+	{value: 0x0012, lo: 0x80, hi: 0x82},
+	{value: 0x0012, lo: 0x84, hi: 0x89},
+	{value: 0x0017, lo: 0x8a, hi: 0x8b},
+	{value: 0x0010, lo: 0x8e, hi: 0xbf},
+	// Block 0x11e, offset 0x5d3
+	{value: 0x0014, lo: 0x80, hi: 0xb6},
+	{value: 0x0014, lo: 0xbb, hi: 0xbf},
+	// Block 0x11f, offset 0x5d5
+	{value: 0x0014, lo: 0x80, hi: 0xac},
+	{value: 0x0014, lo: 0xb5, hi: 0xb5},
+	// Block 0x120, offset 0x5d7
+	{value: 0x0014, lo: 0x84, hi: 0x84},
+	{value: 0x0014, lo: 0x9b, hi: 0x9f},
+	{value: 0x0014, lo: 0xa1, hi: 0xaf},
+	// Block 0x121, offset 0x5da
+	{value: 0x0012, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8a, hi: 0x8a},
+	{value: 0x0012, lo: 0x8b, hi: 0x9e},
+	{value: 0x0012, lo: 0xa5, hi: 0xaa},
+	// Block 0x122, offset 0x5de
+	{value: 0x0024, lo: 0x80, hi: 0x86},
+	{value: 0x0024, lo: 0x88, hi: 0x98},
+	{value: 0x0024, lo: 0x9b, hi: 0xa1},
+	{value: 0x0024, lo: 0xa3, hi: 0xa4},
+	{value: 0x0024, lo: 0xa6, hi: 0xaa},
+	{value: 0x0015, lo: 0xb0, hi: 0xbf},
+	// Block 0x123, offset 0x5e4
+	{value: 0x0015, lo: 0x80, hi: 0xad},
+	// Block 0x124, offset 0x5e5
+	{value: 0x0024, lo: 0x8f, hi: 0x8f},
+	// Block 0x125, offset 0x5e6
+	{value: 0x0010, lo: 0x80, hi: 0xac},
+	{value: 0x0024, lo: 0xb0, hi: 0xb6},
+	{value: 0x0014, lo: 0xb7, hi: 0xbd},
+	// Block 0x126, offset 0x5e9
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	// Block 0x127, offset 0x5eb
+	{value: 0x0010, lo: 0x90, hi: 0xad},
+	{value: 0x0024, lo: 0xae, hi: 0xae},
+	// Block 0x128, offset 0x5ed
+	{value: 0x0010, lo: 0x80, hi: 0xab},
+	{value: 0x0024, lo: 0xac, hi: 0xaf},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x129, offset 0x5f0
+	{value: 0x0010, lo: 0x90, hi: 0xaa},
+	{value: 0x0014, lo: 0xab, hi: 0xab},
+	{value: 0x0034, lo: 0xac, hi: 0xae},
+	{value: 0x0024, lo: 0xaf, hi: 0xaf},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x12a, offset 0x5f5
+	{value: 0x0010, lo: 0xa0, hi: 0xa6},
+	{value: 0x0010, lo: 0xa8, hi: 0xab},
+	{value: 0x0010, lo: 0xad, hi: 0xae},
+	{value: 0x0010, lo: 0xb0, hi: 0xbe},
+	// Block 0x12b, offset 0x5f9
+	{value: 0x0010, lo: 0x80, hi: 0x84},
+	{value: 0x0034, lo: 0x90, hi: 0x96},
+	// Block 0x12c, offset 0x5fb
+	{value: 0xd152, lo: 0x80, hi: 0x81},
+	{value: 0xd452, lo: 0x82, hi: 0x83},
+	{value: 0x0024, lo: 0x84, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0014, lo: 0x8b, hi: 0x8b},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0x12d, offset 0x601
+	{value: 0x0010, lo: 0x80, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x9f},
+	{value: 0x0010, lo: 0xa1, hi: 0xa2},
+	{value: 0x0010, lo: 0xa4, hi: 0xa4},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	{value: 0x0010, lo: 0xa9, hi: 0xb2},
+	{value: 0x0010, lo: 0xb4, hi: 0xb7},
+	{value: 0x0010, lo: 0xb9, hi: 0xb9},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	// Block 0x12e, offset 0x60a
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8b, hi: 0x9b},
+	{value: 0x0010, lo: 0xa1, hi: 0xa3},
+	{value: 0x0010, lo: 0xa5, hi: 0xa9},
+	{value: 0x0010, lo: 0xab, hi: 0xbb},
+	// Block 0x12f, offset 0x60f
+	{value: 0x0013, lo: 0xb0, hi: 0xbf},
+	// Block 0x130, offset 0x610
+	{value: 0x0013, lo: 0x80, hi: 0x89},
+	{value: 0x0013, lo: 0x90, hi: 0xa9},
+	{value: 0x0013, lo: 0xb0, hi: 0xbf},
+	// Block 0x131, offset 0x613
+	{value: 0x0013, lo: 0x80, hi: 0x89},
+	// Block 0x132, offset 0x614
+	{value: 0x0014, lo: 0xbb, hi: 0xbf},
+	// Block 0x133, offset 0x615
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x134, offset 0x616
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0014, lo: 0xa0, hi: 0xbf},
+	// Block 0x135, offset 0x618
+	{value: 0x0014, lo: 0x80, hi: 0xbf},
+	// Block 0x136, offset 0x619
+	{value: 0x0014, lo: 0x80, hi: 0xaf},
+}
+
+// Total table size 16093 bytes (15KiB); checksum: EE91C452
diff --git a/vendor/golang.org/x/text/cases/tables17.0.0.go b/vendor/golang.org/x/text/cases/tables17.0.0.go
new file mode 100644
index 000000000..cee93cbdc
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/tables17.0.0.go
@@ -0,0 +1,2642 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+//go:build go1.27
+
+package cases
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "17.0.0"
+
+var xorData string = "" + // Size: 237 bytes
+	"\x00\x06\x07\x00\x01?\x00\x0f\x03\x00\x0f\x12\x00\x0f\x1f\x00\x0f\x1d" +
+	"\x00\x01\x13\x00\x0f\x16\x00\x0f\x0b\x00\x0f3\x00\x0f7\x00\x01#\x00\x0f?" +
+	"\x00\x0e'\x00\x0f/\x00\x0e>\x00\x0f*\x00\x0c&\x00\x0c*\x00\x0c;\x00\x0c9" +
+	"\x00\x0c%\x00\x01\x08\x00\x03\x0d\x00\x03\x09\x00\x02\x06\x00\x02\x02" +
+	"\x00\x02\x0c\x00\x01\x00\x00\x01\x03\x00\x01\x01\x00\x01 \x00\x01\x0c" +
+	"\x00\x01\x10\x00\x03\x10\x00\x036 \x00\x037 \x00\x0b#\x10\x00\x0b 0\x00" +
+	"\x0b!\x10\x00\x0b!0\x001\x00\x00\x0b(\x04\x00\x03\x04\x1e\x00\x0b)\x08" +
+	"\x00\x03\x0a\x00\x02:\x00\x02>\x00\x02,\x00\x02\x00\x00\x02\x10\x00\x01<" +
+	"\x00\x01&\x00\x01*\x00\x01.\x00\x010\x003 \x00\x01\x18\x00\x01(\x00\x03'" +
+	"\x00\x03)\x00\x03+\x00\x03/\x00\x03\x19\x00\x03\x1b\x00\x03\x1f\x00\x03 " +
+	"\x00\x01%\x00\x01'\x00\x01+\x00\x01-\x00\x01/\x00\x01;\x00\x01=\x00\x01" +
+	"\x1e\x00\x01\x22"
+
+var exceptions string = "" + // Size: 2478 bytes
+	"\x00\x12\x12μΜΜ\x12\x12ssSSSs\x13\x18i̇i̇\x10\x09II\x13\x1bʼnʼNʼN\x11" +
+	"\x09sSS\x10\x1bꟜꟜ\x12\x12ǆǆǅ\x12\x12ǆǆǄ\x10\x12Ǆǅ\x12\x12ǉǉǈ\x12\x12ǉǉǇ" +
+	"\x10\x12Ǉǈ\x12\x12ǌǌǋ\x12\x12ǌǌǊ\x10\x12Ǌǋ\x13\x1bǰJ̌J̌\x12\x12ǳǳǲ\x12" +
+	"\x12ǳǳǱ\x10\x12Ǳǲ\x13\x18ⱥⱥ\x13\x18ⱦⱦ\x10\x1bⱾⱾ\x10\x1bⱿⱿ\x10\x1bⱯⱯ\x10" +
+	"\x1bⱭⱭ\x10\x1bⱰⱰ\x10\x1bꞫꞫ\x10\x1bꞬꞬ\x10\x1bꟋꟋ\x10\x1bꞍꞍ\x10\x1bꞪꞪ\x10" +
+	"\x1bꞮꞮ\x10\x1bⱢⱢ\x10\x1bꞭꞭ\x10\x1bⱮⱮ\x10\x1bⱤⱤ\x10\x1bꟅꟅ\x10\x1bꞱꞱ\x10" +
+	"\x1bꞲꞲ\x10\x1bꞰꞰ2\x12ιΙΙ\x166ΐΪ́Ϊ́\x166ΰΫ́Ϋ́\x12\x12σΣΣ\x12\x12β" +
+	"ΒΒ\x12\x12θΘΘ\x12\x12φΦΦ\x12\x12πΠΠ\x12\x12κΚΚ\x12\x12ρΡΡ\x12\x12εΕΕ" +
+	"\x14$եւԵՒԵւ\x10\x1bᲐა\x10\x1bᲑბ\x10\x1bᲒგ\x10\x1bᲓდ\x10\x1bᲔე\x10\x1bᲕვ" +
+	"\x10\x1bᲖზ\x10\x1bᲗთ\x10\x1bᲘი\x10\x1bᲙკ\x10\x1bᲚლ\x10\x1bᲛმ\x10\x1bᲜნ" +
+	"\x10\x1bᲝო\x10\x1bᲞპ\x10\x1bᲟჟ\x10\x1bᲠრ\x10\x1bᲡს\x10\x1bᲢტ\x10\x1bᲣუ" +
+	"\x10\x1bᲤფ\x10\x1bᲥქ\x10\x1bᲦღ\x10\x1bᲧყ\x10\x1bᲨშ\x10\x1bᲩჩ\x10\x1bᲪც" +
+	"\x10\x1bᲫძ\x10\x1bᲬწ\x10\x1bᲭჭ\x10\x1bᲮხ\x10\x1bᲯჯ\x10\x1bᲰჰ\x10\x1bᲱჱ" +
+	"\x10\x1bᲲჲ\x10\x1bᲳჳ\x10\x1bᲴჴ\x10\x1bᲵჵ\x10\x1bᲶჶ\x10\x1bᲷჷ\x10\x1bᲸჸ" +
+	"\x10\x1bᲹჹ\x10\x1bᲺჺ\x10\x1bᲽჽ\x10\x1bᲾჾ\x10\x1bᲿჿ\x12\x12вВВ\x12\x12дДД" +
+	"\x12\x12оОО\x12\x12сСС\x12\x12тТТ\x12\x12тТТ\x12\x12ъЪЪ\x12\x12ѣѢѢ\x13" +
+	"\x1bꙋꙊꙊ\x13\x1bẖH̱H̱\x13\x1bẗT̈T̈\x13\x1bẘW̊W̊\x13\x1bẙY̊Y̊\x13\x1ba" +
+	"ʾAʾAʾ\x13\x1bṡṠṠ\x12\x10ssß\x14$ὐΥ̓Υ̓\x166ὒΥ̓̀Υ̓̀\x166ὔΥ̓́Υ̓́\x166" +
+	"ὖΥ̓͂Υ̓͂\x15+ἀιἈΙᾈ\x15+ἁιἉΙᾉ\x15+ἂιἊΙᾊ\x15+ἃιἋΙᾋ\x15+ἄιἌΙᾌ\x15+ἅιἍΙᾍ" +
+	"\x15+ἆιἎΙᾎ\x15+ἇιἏΙᾏ\x15\x1dἀιᾀἈΙ\x15\x1dἁιᾁἉΙ\x15\x1dἂιᾂἊΙ\x15\x1dἃιᾃἋΙ" +
+	"\x15\x1dἄιᾄἌΙ\x15\x1dἅιᾅἍΙ\x15\x1dἆιᾆἎΙ\x15\x1dἇιᾇἏΙ\x15+ἠιἨΙᾘ\x15+ἡιἩΙᾙ" +
+	"\x15+ἢιἪΙᾚ\x15+ἣιἫΙᾛ\x15+ἤιἬΙᾜ\x15+ἥιἭΙᾝ\x15+ἦιἮΙᾞ\x15+ἧιἯΙᾟ\x15\x1dἠιᾐἨ" +
+	"Ι\x15\x1dἡιᾑἩΙ\x15\x1dἢιᾒἪΙ\x15\x1dἣιᾓἫΙ\x15\x1dἤιᾔἬΙ\x15\x1dἥιᾕἭΙ\x15" +
+	"\x1dἦιᾖἮΙ\x15\x1dἧιᾗἯΙ\x15+ὠιὨΙᾨ\x15+ὡιὩΙᾩ\x15+ὢιὪΙᾪ\x15+ὣιὫΙᾫ\x15+ὤιὬΙᾬ" +
+	"\x15+ὥιὭΙᾭ\x15+ὦιὮΙᾮ\x15+ὧιὯΙᾯ\x15\x1dὠιᾠὨΙ\x15\x1dὡιᾡὩΙ\x15\x1dὢιᾢὪΙ" +
+	"\x15\x1dὣιᾣὫΙ\x15\x1dὤιᾤὬΙ\x15\x1dὥιᾥὭΙ\x15\x1dὦιᾦὮΙ\x15\x1dὧιᾧὯΙ\x15-ὰι" +
+	"ᾺΙᾺͅ\x14#αιΑΙᾼ\x14$άιΆΙΆͅ\x14$ᾶΑ͂Α͂\x166ᾶιΑ͂Ιᾼ͂\x14\x1cαιᾳΑΙ\x12" +
+	"\x12ιΙΙ\x15-ὴιῊΙῊͅ\x14#ηιΗΙῌ\x14$ήιΉΙΉͅ\x14$ῆΗ͂Η͂\x166ῆιΗ͂Ιῌ͂\x14\x1c" +
+	"ηιῃΗΙ\x166ῒΪ̀Ϊ̀\x166ΐΪ́Ϊ́\x14$ῖΙ͂Ι͂\x166ῗΪ͂Ϊ͂\x166ῢΫ̀Ϋ" +
+	"̀\x166ΰΫ́Ϋ́\x14$ῤΡ̓Ρ̓\x14$ῦΥ͂Υ͂\x166ῧΫ͂Ϋ͂\x15-ὼιῺΙῺͅ\x14#ωιΩΙ" +
+	"ῼ\x14$ώιΏΙΏͅ\x14$ῶΩ͂Ω͂\x166ῶιΩ͂Ιῼ͂\x14\x1cωιῳΩΙ\x12\x10ωω\x11\x08kk" +
+	"\x12\x10åå\x12\x10ɫɫ\x12\x10ɽɽ\x10\x12ȺȺ\x10\x12ȾȾ\x12\x10ɑɑ\x12\x10ɱɱ" +
+	"\x12\x10ɐɐ\x12\x10ɒɒ\x12\x10ȿȿ\x12\x10ɀɀ\x12\x10ɥɥ\x12\x10ɦɦ\x12\x10ɜɜ" +
+	"\x12\x10ɡɡ\x12\x10ɬɬ\x12\x10ɪɪ\x12\x10ʞʞ\x12\x10ʇʇ\x12\x10ʝʝ\x12\x10ʂʂ" +
+	"\x12\x10ɤɤ\x12\x10ƛƛ\x12\x12ffFFFf\x12\x12fiFIFi\x12\x12flFLFl\x13\x1bff" +
+	"iFFIFfi\x13\x1bfflFFLFfl\x12\x12stSTSt\x12\x12stSTSt\x14$մնՄՆՄն\x14$մեՄԵ" +
+	"Մե\x14$միՄԻՄի\x14$վնՎՆՎն\x14$մխՄԽՄխ"
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *caseTrie) lookup(s []byte) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return caseValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = caseIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = caseIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = caseIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *caseTrie) lookupUnsafe(s []byte) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return caseValues[c0]
+	}
+	i := caseIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = caseIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = caseIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *caseTrie) lookupString(s string) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return caseValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = caseIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := caseIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = caseIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = caseIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *caseTrie) lookupStringUnsafe(s string) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return caseValues[c0]
+	}
+	i := caseIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = caseIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = caseIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// caseTrie. Total size: 14000 bytes (13.67 KiB). Checksum: 76c852e9b991a172.
+type caseTrie struct{}
+
+func newCaseTrie(i int) *caseTrie {
+	return &caseTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *caseTrie) lookupValue(n uint32, b byte) uint16 {
+	switch {
+	case n < 24:
+		return uint16(caseValues[n<<6+uint32(b)])
+	default:
+		n -= 24
+		return uint16(sparse.lookup(n, b))
+	}
+}
+
+// caseValues: 26 blocks, 1664 entries, 3328 bytes
+// The third block is the zero block.
+var caseValues = [1664]uint16{
+	// Block 0x0, offset 0x0
+	0x27: 0x0054,
+	0x2e: 0x0054,
+	0x30: 0x0010, 0x31: 0x0010, 0x32: 0x0010, 0x33: 0x0010, 0x34: 0x0010, 0x35: 0x0010,
+	0x36: 0x0010, 0x37: 0x0010, 0x38: 0x0010, 0x39: 0x0010, 0x3a: 0x0054,
+	// Block 0x1, offset 0x40
+	0x41: 0x2013, 0x42: 0x2013, 0x43: 0x2013, 0x44: 0x2013, 0x45: 0x2013,
+	0x46: 0x2013, 0x47: 0x2013, 0x48: 0x2013, 0x49: 0x2013, 0x4a: 0x2013, 0x4b: 0x2013,
+	0x4c: 0x2013, 0x4d: 0x2013, 0x4e: 0x2013, 0x4f: 0x2013, 0x50: 0x2013, 0x51: 0x2013,
+	0x52: 0x2013, 0x53: 0x2013, 0x54: 0x2013, 0x55: 0x2013, 0x56: 0x2013, 0x57: 0x2013,
+	0x58: 0x2013, 0x59: 0x2013, 0x5a: 0x2013,
+	0x5e: 0x0004, 0x5f: 0x0010, 0x60: 0x0004, 0x61: 0x2012, 0x62: 0x2012, 0x63: 0x2012,
+	0x64: 0x2012, 0x65: 0x2012, 0x66: 0x2012, 0x67: 0x2012, 0x68: 0x2012, 0x69: 0x2012,
+	0x6a: 0x2012, 0x6b: 0x2012, 0x6c: 0x2012, 0x6d: 0x2012, 0x6e: 0x2012, 0x6f: 0x2012,
+	0x70: 0x2012, 0x71: 0x2012, 0x72: 0x2012, 0x73: 0x2012, 0x74: 0x2012, 0x75: 0x2012,
+	0x76: 0x2012, 0x77: 0x2012, 0x78: 0x2012, 0x79: 0x2012, 0x7a: 0x2012,
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc0: 0x0852, 0xc1: 0x0b53, 0xc2: 0x0113, 0xc3: 0x0112, 0xc4: 0x0113, 0xc5: 0x0112,
+	0xc6: 0x0b53, 0xc7: 0x0f13, 0xc8: 0x0f12, 0xc9: 0x0e53, 0xca: 0x1153, 0xcb: 0x0713,
+	0xcc: 0x0712, 0xcd: 0x0012, 0xce: 0x1453, 0xcf: 0x1753, 0xd0: 0x1a53, 0xd1: 0x0313,
+	0xd2: 0x0312, 0xd3: 0x1d53, 0xd4: 0x2053, 0xd5: 0x2352, 0xd6: 0x2653, 0xd7: 0x2653,
+	0xd8: 0x0113, 0xd9: 0x0112, 0xda: 0x2952, 0xdb: 0x02da, 0xdc: 0x1d53, 0xdd: 0x2c53,
+	0xde: 0x2f52, 0xdf: 0x3253, 0xe0: 0x0113, 0xe1: 0x0112, 0xe2: 0x0113, 0xe3: 0x0112,
+	0xe4: 0x0113, 0xe5: 0x0112, 0xe6: 0x3553, 0xe7: 0x0f13, 0xe8: 0x0f12, 0xe9: 0x3853,
+	0xea: 0x0012, 0xeb: 0x0012, 0xec: 0x0113, 0xed: 0x0112, 0xee: 0x3553, 0xef: 0x1f13,
+	0xf0: 0x1f12, 0xf1: 0x3b53, 0xf2: 0x3e53, 0xf3: 0x0713, 0xf4: 0x0712, 0xf5: 0x0313,
+	0xf6: 0x0312, 0xf7: 0x4153, 0xf8: 0x0113, 0xf9: 0x0112, 0xfa: 0x0012, 0xfb: 0x0010,
+	0xfc: 0x0113, 0xfd: 0x0112, 0xfe: 0x0012, 0xff: 0x4452,
+	// Block 0x4, offset 0x100
+	0x100: 0x0010, 0x101: 0x0010, 0x102: 0x0010, 0x103: 0x0010, 0x104: 0x035b, 0x105: 0x03d9,
+	0x106: 0x045a, 0x107: 0x04bb, 0x108: 0x0539, 0x109: 0x05ba, 0x10a: 0x061b, 0x10b: 0x0699,
+	0x10c: 0x071a, 0x10d: 0x0313, 0x10e: 0x0312, 0x10f: 0x1f13, 0x110: 0x1f12, 0x111: 0x0313,
+	0x112: 0x0312, 0x113: 0x0713, 0x114: 0x0712, 0x115: 0x0313, 0x116: 0x0312, 0x117: 0x0f13,
+	0x118: 0x0f12, 0x119: 0x0313, 0x11a: 0x0312, 0x11b: 0x0713, 0x11c: 0x0712, 0x11d: 0x1452,
+	0x11e: 0x0113, 0x11f: 0x0112, 0x120: 0x0113, 0x121: 0x0112, 0x122: 0x0113, 0x123: 0x0112,
+	0x124: 0x0113, 0x125: 0x0112, 0x126: 0x0113, 0x127: 0x0112, 0x128: 0x0113, 0x129: 0x0112,
+	0x12a: 0x0113, 0x12b: 0x0112, 0x12c: 0x0113, 0x12d: 0x0112, 0x12e: 0x0113, 0x12f: 0x0112,
+	0x130: 0x077a, 0x131: 0x082b, 0x132: 0x08a9, 0x133: 0x092a, 0x134: 0x0113, 0x135: 0x0112,
+	0x136: 0x2353, 0x137: 0x4453, 0x138: 0x0113, 0x139: 0x0112, 0x13a: 0x0113, 0x13b: 0x0112,
+	0x13c: 0x0113, 0x13d: 0x0112, 0x13e: 0x0113, 0x13f: 0x0112,
+	// Block 0x5, offset 0x140
+	0x140: 0x0b0a, 0x141: 0x0313, 0x142: 0x0312, 0x143: 0x0853, 0x144: 0x4753, 0x145: 0x4a53,
+	0x146: 0x0113, 0x147: 0x0112, 0x148: 0x0113, 0x149: 0x0112, 0x14a: 0x0113, 0x14b: 0x0112,
+	0x14c: 0x0113, 0x14d: 0x0112, 0x14e: 0x0113, 0x14f: 0x0112, 0x150: 0x0b8a, 0x151: 0x0c0a,
+	0x152: 0x0c8a, 0x153: 0x0b52, 0x154: 0x0b52, 0x155: 0x0012, 0x156: 0x0e52, 0x157: 0x1152,
+	0x158: 0x0012, 0x159: 0x1752, 0x15a: 0x0012, 0x15b: 0x1a52, 0x15c: 0x0d0a, 0x15d: 0x0012,
+	0x15e: 0x0012, 0x15f: 0x0012, 0x160: 0x1d52, 0x161: 0x0d8a, 0x162: 0x0012, 0x163: 0x2052,
+	0x164: 0x0e0a, 0x165: 0x0e8a, 0x166: 0x0f0a, 0x167: 0x0012, 0x168: 0x2652, 0x169: 0x2652,
+	0x16a: 0x0f8a, 0x16b: 0x100a, 0x16c: 0x108a, 0x16d: 0x0012, 0x16e: 0x0012, 0x16f: 0x1d52,
+	0x170: 0x0012, 0x171: 0x110a, 0x172: 0x2c52, 0x173: 0x0012, 0x174: 0x0012, 0x175: 0x3252,
+	0x176: 0x0012, 0x177: 0x0012, 0x178: 0x0012, 0x179: 0x0012, 0x17a: 0x0012, 0x17b: 0x0012,
+	0x17c: 0x0012, 0x17d: 0x118a, 0x17e: 0x0012, 0x17f: 0x0012,
+	// Block 0x6, offset 0x180
+	0x180: 0x3552, 0x181: 0x0012, 0x182: 0x120a, 0x183: 0x3852, 0x184: 0x0012, 0x185: 0x0012,
+	0x186: 0x0012, 0x187: 0x128a, 0x188: 0x3552, 0x189: 0x4752, 0x18a: 0x3b52, 0x18b: 0x3e52,
+	0x18c: 0x4a52, 0x18d: 0x0012, 0x18e: 0x0012, 0x18f: 0x0012, 0x190: 0x0012, 0x191: 0x0012,
+	0x192: 0x4152, 0x193: 0x0012, 0x194: 0x0010, 0x195: 0x0010, 0x196: 0x0012, 0x197: 0x0012,
+	0x198: 0x0012, 0x199: 0x0012, 0x19a: 0x0012, 0x19b: 0x0012, 0x19c: 0x0012, 0x19d: 0x130a,
+	0x19e: 0x138a, 0x19f: 0x0012, 0x1a0: 0x0012, 0x1a1: 0x0012, 0x1a2: 0x0012, 0x1a3: 0x0012,
+	0x1a4: 0x0012, 0x1a5: 0x0012, 0x1a6: 0x0012, 0x1a7: 0x0012, 0x1a8: 0x0012, 0x1a9: 0x0012,
+	0x1aa: 0x0012, 0x1ab: 0x0012, 0x1ac: 0x0012, 0x1ad: 0x0012, 0x1ae: 0x0012, 0x1af: 0x0012,
+	0x1b0: 0x0015, 0x1b1: 0x0015, 0x1b2: 0x0015, 0x1b3: 0x0015, 0x1b4: 0x0015, 0x1b5: 0x0015,
+	0x1b6: 0x0015, 0x1b7: 0x0015, 0x1b8: 0x0015, 0x1b9: 0x0014, 0x1ba: 0x0014, 0x1bb: 0x0014,
+	0x1bc: 0x0014, 0x1bd: 0x0014, 0x1be: 0x0014, 0x1bf: 0x0014,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x0024, 0x1c1: 0x0024, 0x1c2: 0x0024, 0x1c3: 0x0024, 0x1c4: 0x0024, 0x1c5: 0x140d,
+	0x1c6: 0x0024, 0x1c7: 0x0034, 0x1c8: 0x0034, 0x1c9: 0x0034, 0x1ca: 0x0024, 0x1cb: 0x0024,
+	0x1cc: 0x0024, 0x1cd: 0x0034, 0x1ce: 0x0034, 0x1cf: 0x0014, 0x1d0: 0x0024, 0x1d1: 0x0024,
+	0x1d2: 0x0024, 0x1d3: 0x0034, 0x1d4: 0x0034, 0x1d5: 0x0034, 0x1d6: 0x0034, 0x1d7: 0x0024,
+	0x1d8: 0x0034, 0x1d9: 0x0034, 0x1da: 0x0034, 0x1db: 0x0024, 0x1dc: 0x0034, 0x1dd: 0x0034,
+	0x1de: 0x0034, 0x1df: 0x0034, 0x1e0: 0x0034, 0x1e1: 0x0034, 0x1e2: 0x0034, 0x1e3: 0x0024,
+	0x1e4: 0x0024, 0x1e5: 0x0024, 0x1e6: 0x0024, 0x1e7: 0x0024, 0x1e8: 0x0024, 0x1e9: 0x0024,
+	0x1ea: 0x0024, 0x1eb: 0x0024, 0x1ec: 0x0024, 0x1ed: 0x0024, 0x1ee: 0x0024, 0x1ef: 0x0024,
+	0x1f0: 0x0113, 0x1f1: 0x0112, 0x1f2: 0x0113, 0x1f3: 0x0112, 0x1f4: 0x0014, 0x1f5: 0x0004,
+	0x1f6: 0x0113, 0x1f7: 0x0112, 0x1fa: 0x0015, 0x1fb: 0x4d52,
+	0x1fc: 0x5052, 0x1fd: 0x5052, 0x1ff: 0x5353,
+	// Block 0x8, offset 0x200
+	0x204: 0x0004, 0x205: 0x0004,
+	0x206: 0x2a13, 0x207: 0x0054, 0x208: 0x2513, 0x209: 0x2713, 0x20a: 0x2513,
+	0x20c: 0x5653, 0x20e: 0x5953, 0x20f: 0x5c53, 0x210: 0x148a, 0x211: 0x2013,
+	0x212: 0x2013, 0x213: 0x2013, 0x214: 0x2013, 0x215: 0x2013, 0x216: 0x2013, 0x217: 0x2013,
+	0x218: 0x2013, 0x219: 0x2013, 0x21a: 0x2013, 0x21b: 0x2013, 0x21c: 0x2013, 0x21d: 0x2013,
+	0x21e: 0x2013, 0x21f: 0x2013, 0x220: 0x5f53, 0x221: 0x5f53, 0x223: 0x5f53,
+	0x224: 0x5f53, 0x225: 0x5f53, 0x226: 0x5f53, 0x227: 0x5f53, 0x228: 0x5f53, 0x229: 0x5f53,
+	0x22a: 0x5f53, 0x22b: 0x5f53, 0x22c: 0x2a12, 0x22d: 0x2512, 0x22e: 0x2712, 0x22f: 0x2512,
+	0x230: 0x15ca, 0x231: 0x2012, 0x232: 0x2012, 0x233: 0x2012, 0x234: 0x2012, 0x235: 0x2012,
+	0x236: 0x2012, 0x237: 0x2012, 0x238: 0x2012, 0x239: 0x2012, 0x23a: 0x2012, 0x23b: 0x2012,
+	0x23c: 0x2012, 0x23d: 0x2012, 0x23e: 0x2012, 0x23f: 0x2012,
+	// Block 0x9, offset 0x240
+	0x240: 0x5f52, 0x241: 0x5f52, 0x242: 0x170a, 0x243: 0x5f52, 0x244: 0x5f52, 0x245: 0x5f52,
+	0x246: 0x5f52, 0x247: 0x5f52, 0x248: 0x5f52, 0x249: 0x5f52, 0x24a: 0x5f52, 0x24b: 0x5f52,
+	0x24c: 0x5652, 0x24d: 0x5952, 0x24e: 0x5c52, 0x24f: 0x1813, 0x250: 0x178a, 0x251: 0x180a,
+	0x252: 0x0013, 0x253: 0x0013, 0x254: 0x0013, 0x255: 0x188a, 0x256: 0x190a, 0x257: 0x1812,
+	0x258: 0x0113, 0x259: 0x0112, 0x25a: 0x0113, 0x25b: 0x0112, 0x25c: 0x0113, 0x25d: 0x0112,
+	0x25e: 0x0113, 0x25f: 0x0112, 0x260: 0x0113, 0x261: 0x0112, 0x262: 0x0113, 0x263: 0x0112,
+	0x264: 0x0113, 0x265: 0x0112, 0x266: 0x0113, 0x267: 0x0112, 0x268: 0x0113, 0x269: 0x0112,
+	0x26a: 0x0113, 0x26b: 0x0112, 0x26c: 0x0113, 0x26d: 0x0112, 0x26e: 0x0113, 0x26f: 0x0112,
+	0x270: 0x198a, 0x271: 0x1a0a, 0x272: 0x0b12, 0x273: 0x5352, 0x274: 0x6253, 0x275: 0x1a8a,
+	0x277: 0x0f13, 0x278: 0x0f12, 0x279: 0x0b13, 0x27a: 0x0113, 0x27b: 0x0112,
+	0x27c: 0x0012, 0x27d: 0x4d53, 0x27e: 0x5053, 0x27f: 0x5053,
+	// Block 0xa, offset 0x280
+	0x280: 0x6852, 0x281: 0x6852, 0x282: 0x6852, 0x283: 0x6852, 0x284: 0x6852, 0x285: 0x6852,
+	0x286: 0x6852, 0x287: 0x1b0a, 0x288: 0x0012, 0x28a: 0x0010,
+	0x291: 0x0034,
+	0x292: 0x0024, 0x293: 0x0024, 0x294: 0x0024, 0x295: 0x0024, 0x296: 0x0034, 0x297: 0x0024,
+	0x298: 0x0024, 0x299: 0x0024, 0x29a: 0x0034, 0x29b: 0x0034, 0x29c: 0x0024, 0x29d: 0x0024,
+	0x29e: 0x0024, 0x29f: 0x0024, 0x2a0: 0x0024, 0x2a1: 0x0024, 0x2a2: 0x0034, 0x2a3: 0x0034,
+	0x2a4: 0x0034, 0x2a5: 0x0034, 0x2a6: 0x0034, 0x2a7: 0x0034, 0x2a8: 0x0024, 0x2a9: 0x0024,
+	0x2aa: 0x0034, 0x2ab: 0x0024, 0x2ac: 0x0024, 0x2ad: 0x0034, 0x2ae: 0x0034, 0x2af: 0x0024,
+	0x2b0: 0x0034, 0x2b1: 0x0034, 0x2b2: 0x0034, 0x2b3: 0x0034, 0x2b4: 0x0034, 0x2b5: 0x0034,
+	0x2b6: 0x0034, 0x2b7: 0x0034, 0x2b8: 0x0034, 0x2b9: 0x0034, 0x2ba: 0x0034, 0x2bb: 0x0034,
+	0x2bc: 0x0034, 0x2bd: 0x0034, 0x2bf: 0x0034,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x0010, 0x2c1: 0x0010, 0x2c2: 0x0010, 0x2c3: 0x0010, 0x2c4: 0x0010, 0x2c5: 0x0010,
+	0x2c6: 0x0010, 0x2c7: 0x0010, 0x2c8: 0x0010, 0x2c9: 0x0014, 0x2ca: 0x0024, 0x2cb: 0x0024,
+	0x2cc: 0x0024, 0x2cd: 0x0024, 0x2ce: 0x0024, 0x2cf: 0x0034, 0x2d0: 0x0034, 0x2d1: 0x0034,
+	0x2d2: 0x0034, 0x2d3: 0x0034, 0x2d4: 0x0024, 0x2d5: 0x0024, 0x2d6: 0x0024, 0x2d7: 0x0024,
+	0x2d8: 0x0024, 0x2d9: 0x0024, 0x2da: 0x0024, 0x2db: 0x0024, 0x2dc: 0x0024, 0x2dd: 0x0024,
+	0x2de: 0x0024, 0x2df: 0x0024, 0x2e0: 0x0024, 0x2e1: 0x0024, 0x2e2: 0x0014, 0x2e3: 0x0034,
+	0x2e4: 0x0024, 0x2e5: 0x0024, 0x2e6: 0x0034, 0x2e7: 0x0024, 0x2e8: 0x0024, 0x2e9: 0x0034,
+	0x2ea: 0x0024, 0x2eb: 0x0024, 0x2ec: 0x0024, 0x2ed: 0x0034, 0x2ee: 0x0034, 0x2ef: 0x0034,
+	0x2f0: 0x0034, 0x2f1: 0x0034, 0x2f2: 0x0034, 0x2f3: 0x0024, 0x2f4: 0x0024, 0x2f5: 0x0024,
+	0x2f6: 0x0034, 0x2f7: 0x0024, 0x2f8: 0x0024, 0x2f9: 0x0034, 0x2fa: 0x0034, 0x2fb: 0x0024,
+	0x2fc: 0x0024, 0x2fd: 0x0024, 0x2fe: 0x0024, 0x2ff: 0x0024,
+	// Block 0xc, offset 0x300
+	0x300: 0x7053, 0x301: 0x7053, 0x302: 0x7053, 0x303: 0x7053, 0x304: 0x7053, 0x305: 0x7053,
+	0x307: 0x7053,
+	0x30d: 0x7053, 0x310: 0x1bea, 0x311: 0x1c6a,
+	0x312: 0x1cea, 0x313: 0x1d6a, 0x314: 0x1dea, 0x315: 0x1e6a, 0x316: 0x1eea, 0x317: 0x1f6a,
+	0x318: 0x1fea, 0x319: 0x206a, 0x31a: 0x20ea, 0x31b: 0x216a, 0x31c: 0x21ea, 0x31d: 0x226a,
+	0x31e: 0x22ea, 0x31f: 0x236a, 0x320: 0x23ea, 0x321: 0x246a, 0x322: 0x24ea, 0x323: 0x256a,
+	0x324: 0x25ea, 0x325: 0x266a, 0x326: 0x26ea, 0x327: 0x276a, 0x328: 0x27ea, 0x329: 0x286a,
+	0x32a: 0x28ea, 0x32b: 0x296a, 0x32c: 0x29ea, 0x32d: 0x2a6a, 0x32e: 0x2aea, 0x32f: 0x2b6a,
+	0x330: 0x2bea, 0x331: 0x2c6a, 0x332: 0x2cea, 0x333: 0x2d6a, 0x334: 0x2dea, 0x335: 0x2e6a,
+	0x336: 0x2eea, 0x337: 0x2f6a, 0x338: 0x2fea, 0x339: 0x306a, 0x33a: 0x30ea,
+	0x33c: 0x0015, 0x33d: 0x316a, 0x33e: 0x31ea, 0x33f: 0x326a,
+	// Block 0xd, offset 0x340
+	0x340: 0x0812, 0x341: 0x0812, 0x342: 0x0812, 0x343: 0x0812, 0x344: 0x0812, 0x345: 0x0812,
+	0x348: 0x0813, 0x349: 0x0813, 0x34a: 0x0813, 0x34b: 0x0813,
+	0x34c: 0x0813, 0x34d: 0x0813, 0x350: 0x3c1a, 0x351: 0x0812,
+	0x352: 0x3cfa, 0x353: 0x0812, 0x354: 0x3e3a, 0x355: 0x0812, 0x356: 0x3f7a, 0x357: 0x0812,
+	0x359: 0x0813, 0x35b: 0x0813, 0x35d: 0x0813,
+	0x35f: 0x0813, 0x360: 0x0812, 0x361: 0x0812, 0x362: 0x0812, 0x363: 0x0812,
+	0x364: 0x0812, 0x365: 0x0812, 0x366: 0x0812, 0x367: 0x0812, 0x368: 0x0813, 0x369: 0x0813,
+	0x36a: 0x0813, 0x36b: 0x0813, 0x36c: 0x0813, 0x36d: 0x0813, 0x36e: 0x0813, 0x36f: 0x0813,
+	0x370: 0x9252, 0x371: 0x9252, 0x372: 0x9552, 0x373: 0x9552, 0x374: 0x9852, 0x375: 0x9852,
+	0x376: 0x9b52, 0x377: 0x9b52, 0x378: 0x9e52, 0x379: 0x9e52, 0x37a: 0xa152, 0x37b: 0xa152,
+	0x37c: 0x4d52, 0x37d: 0x4d52,
+	// Block 0xe, offset 0x380
+	0x380: 0x40ba, 0x381: 0x41aa, 0x382: 0x429a, 0x383: 0x438a, 0x384: 0x447a, 0x385: 0x456a,
+	0x386: 0x465a, 0x387: 0x474a, 0x388: 0x4839, 0x389: 0x4929, 0x38a: 0x4a19, 0x38b: 0x4b09,
+	0x38c: 0x4bf9, 0x38d: 0x4ce9, 0x38e: 0x4dd9, 0x38f: 0x4ec9, 0x390: 0x4fba, 0x391: 0x50aa,
+	0x392: 0x519a, 0x393: 0x528a, 0x394: 0x537a, 0x395: 0x546a, 0x396: 0x555a, 0x397: 0x564a,
+	0x398: 0x5739, 0x399: 0x5829, 0x39a: 0x5919, 0x39b: 0x5a09, 0x39c: 0x5af9, 0x39d: 0x5be9,
+	0x39e: 0x5cd9, 0x39f: 0x5dc9, 0x3a0: 0x5eba, 0x3a1: 0x5faa, 0x3a2: 0x609a, 0x3a3: 0x618a,
+	0x3a4: 0x627a, 0x3a5: 0x636a, 0x3a6: 0x645a, 0x3a7: 0x654a, 0x3a8: 0x6639, 0x3a9: 0x6729,
+	0x3aa: 0x6819, 0x3ab: 0x6909, 0x3ac: 0x69f9, 0x3ad: 0x6ae9, 0x3ae: 0x6bd9, 0x3af: 0x6cc9,
+	0x3b0: 0x0812, 0x3b1: 0x0812, 0x3b2: 0x6dba, 0x3b3: 0x6eca, 0x3b4: 0x6f9a,
+	0x3b6: 0x707a, 0x3b7: 0x715a, 0x3b8: 0x0813, 0x3b9: 0x0813, 0x3ba: 0x9253, 0x3bb: 0x9253,
+	0x3bc: 0x7299, 0x3bd: 0x0004, 0x3be: 0x736a, 0x3bf: 0x0004,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x0004, 0x3c1: 0x0004, 0x3c2: 0x73ea, 0x3c3: 0x74fa, 0x3c4: 0x75ca,
+	0x3c6: 0x76aa, 0x3c7: 0x778a, 0x3c8: 0x9553, 0x3c9: 0x9553, 0x3ca: 0x9853, 0x3cb: 0x9853,
+	0x3cc: 0x78c9, 0x3cd: 0x0004, 0x3ce: 0x0004, 0x3cf: 0x0004, 0x3d0: 0x0812, 0x3d1: 0x0812,
+	0x3d2: 0x799a, 0x3d3: 0x7ada, 0x3d6: 0x7c1a, 0x3d7: 0x7cfa,
+	0x3d8: 0x0813, 0x3d9: 0x0813, 0x3da: 0x9b53, 0x3db: 0x9b53, 0x3dd: 0x0004,
+	0x3de: 0x0004, 0x3df: 0x0004, 0x3e0: 0x0812, 0x3e1: 0x0812, 0x3e2: 0x7e3a, 0x3e3: 0x7f7a,
+	0x3e4: 0x80ba, 0x3e5: 0x0912, 0x3e6: 0x819a, 0x3e7: 0x827a, 0x3e8: 0x0813, 0x3e9: 0x0813,
+	0x3ea: 0xa153, 0x3eb: 0xa153, 0x3ec: 0x0913, 0x3ed: 0x0004, 0x3ee: 0x0004, 0x3ef: 0x0004,
+	0x3f2: 0x83ba, 0x3f3: 0x84ca, 0x3f4: 0x859a,
+	0x3f6: 0x867a, 0x3f7: 0x875a, 0x3f8: 0x9e53, 0x3f9: 0x9e53, 0x3fa: 0x4d53, 0x3fb: 0x4d53,
+	0x3fc: 0x8899, 0x3fd: 0x0004, 0x3fe: 0x0004,
+	// Block 0x10, offset 0x400
+	0x402: 0x0013,
+	0x407: 0x0013, 0x40a: 0x0012, 0x40b: 0x0013,
+	0x40c: 0x0013, 0x40d: 0x0013, 0x40e: 0x0012, 0x40f: 0x0012, 0x410: 0x0013, 0x411: 0x0013,
+	0x412: 0x0013, 0x413: 0x0012, 0x415: 0x0013,
+	0x419: 0x0013, 0x41a: 0x0013, 0x41b: 0x0013, 0x41c: 0x0013, 0x41d: 0x0013,
+	0x424: 0x0013, 0x426: 0x896b, 0x428: 0x0013,
+	0x42a: 0x89cb, 0x42b: 0x8a0b, 0x42c: 0x0013, 0x42d: 0x0013, 0x42f: 0x0012,
+	0x430: 0x0013, 0x431: 0x0013, 0x432: 0xa453, 0x433: 0x0013, 0x434: 0x0012, 0x435: 0x0010,
+	0x436: 0x0010, 0x437: 0x0010, 0x438: 0x0010, 0x439: 0x0012,
+	0x43c: 0x0012, 0x43d: 0x0012, 0x43e: 0x0013, 0x43f: 0x0013,
+	// Block 0x11, offset 0x440
+	0x440: 0x1a13, 0x441: 0x1a13, 0x442: 0x1e13, 0x443: 0x1e13, 0x444: 0x1a13, 0x445: 0x1a13,
+	0x446: 0x2613, 0x447: 0x2613, 0x448: 0x2a13, 0x449: 0x2a13, 0x44a: 0x2e13, 0x44b: 0x2e13,
+	0x44c: 0x2a13, 0x44d: 0x2a13, 0x44e: 0x2613, 0x44f: 0x2613, 0x450: 0xa752, 0x451: 0xa752,
+	0x452: 0xaa52, 0x453: 0xaa52, 0x454: 0xad52, 0x455: 0xad52, 0x456: 0xaa52, 0x457: 0xaa52,
+	0x458: 0xa752, 0x459: 0xa752, 0x45a: 0x1a12, 0x45b: 0x1a12, 0x45c: 0x1e12, 0x45d: 0x1e12,
+	0x45e: 0x1a12, 0x45f: 0x1a12, 0x460: 0x2612, 0x461: 0x2612, 0x462: 0x2a12, 0x463: 0x2a12,
+	0x464: 0x2e12, 0x465: 0x2e12, 0x466: 0x2a12, 0x467: 0x2a12, 0x468: 0x2612, 0x469: 0x2612,
+	// Block 0x12, offset 0x480
+	0x480: 0x6552, 0x481: 0x6552, 0x482: 0x6552, 0x483: 0x6552, 0x484: 0x6552, 0x485: 0x6552,
+	0x486: 0x6552, 0x487: 0x6552, 0x488: 0x6552, 0x489: 0x6552, 0x48a: 0x6552, 0x48b: 0x6552,
+	0x48c: 0x6552, 0x48d: 0x6552, 0x48e: 0x6552, 0x48f: 0x6552, 0x490: 0xb052, 0x491: 0xb052,
+	0x492: 0xb052, 0x493: 0xb052, 0x494: 0xb052, 0x495: 0xb052, 0x496: 0xb052, 0x497: 0xb052,
+	0x498: 0xb052, 0x499: 0xb052, 0x49a: 0xb052, 0x49b: 0xb052, 0x49c: 0xb052, 0x49d: 0xb052,
+	0x49e: 0xb052, 0x49f: 0xb052, 0x4a0: 0x0113, 0x4a1: 0x0112, 0x4a2: 0x8a6b, 0x4a3: 0x8b53,
+	0x4a4: 0x8acb, 0x4a5: 0x8b2a, 0x4a6: 0x8b8a, 0x4a7: 0x0f13, 0x4a8: 0x0f12, 0x4a9: 0x0313,
+	0x4aa: 0x0312, 0x4ab: 0x0713, 0x4ac: 0x0712, 0x4ad: 0x8beb, 0x4ae: 0x8c4b, 0x4af: 0x8cab,
+	0x4b0: 0x8d0b, 0x4b1: 0x0012, 0x4b2: 0x0113, 0x4b3: 0x0112, 0x4b4: 0x0012, 0x4b5: 0x0313,
+	0x4b6: 0x0312, 0x4b7: 0x0012, 0x4b8: 0x0012, 0x4b9: 0x0012, 0x4ba: 0x0012, 0x4bb: 0x0012,
+	0x4bc: 0x0015, 0x4bd: 0x0015, 0x4be: 0x8d6b, 0x4bf: 0x8dcb,
+	// Block 0x13, offset 0x4c0
+	0x4c0: 0x0113, 0x4c1: 0x0112, 0x4c2: 0x0113, 0x4c3: 0x0112, 0x4c4: 0x0113, 0x4c5: 0x0112,
+	0x4c6: 0x0113, 0x4c7: 0x0112, 0x4c8: 0x0014, 0x4c9: 0x0014, 0x4ca: 0x0014, 0x4cb: 0x0713,
+	0x4cc: 0x0712, 0x4cd: 0x8e2b, 0x4ce: 0x0012, 0x4cf: 0x0010, 0x4d0: 0x0113, 0x4d1: 0x0112,
+	0x4d2: 0x0113, 0x4d3: 0x0112, 0x4d4: 0x6552, 0x4d5: 0x0012, 0x4d6: 0x0113, 0x4d7: 0x0112,
+	0x4d8: 0x0113, 0x4d9: 0x0112, 0x4da: 0x0113, 0x4db: 0x0112, 0x4dc: 0x0113, 0x4dd: 0x0112,
+	0x4de: 0x0113, 0x4df: 0x0112, 0x4e0: 0x0113, 0x4e1: 0x0112, 0x4e2: 0x0113, 0x4e3: 0x0112,
+	0x4e4: 0x0113, 0x4e5: 0x0112, 0x4e6: 0x0113, 0x4e7: 0x0112, 0x4e8: 0x0113, 0x4e9: 0x0112,
+	0x4ea: 0x8e8b, 0x4eb: 0x8eeb, 0x4ec: 0x8f4b, 0x4ed: 0x8fab, 0x4ee: 0x900b, 0x4ef: 0x0012,
+	0x4f0: 0x906b, 0x4f1: 0x90cb, 0x4f2: 0x912b, 0x4f3: 0xb353, 0x4f4: 0x0113, 0x4f5: 0x0112,
+	0x4f6: 0x0113, 0x4f7: 0x0112, 0x4f8: 0x0113, 0x4f9: 0x0112, 0x4fa: 0x0113, 0x4fb: 0x0112,
+	0x4fc: 0x0113, 0x4fd: 0x0112, 0x4fe: 0x0113, 0x4ff: 0x0112,
+	// Block 0x14, offset 0x500
+	0x500: 0x92aa, 0x501: 0x932a, 0x502: 0x93aa, 0x503: 0x942a, 0x504: 0x94da, 0x505: 0x958a,
+	0x506: 0x960a,
+	0x513: 0x968a, 0x514: 0x976a, 0x515: 0x984a, 0x516: 0x992a, 0x517: 0x9a0a,
+	0x51d: 0x0010,
+	0x51e: 0x0034, 0x51f: 0x0010, 0x520: 0x0010, 0x521: 0x0010, 0x522: 0x0010, 0x523: 0x0010,
+	0x524: 0x0010, 0x525: 0x0010, 0x526: 0x0010, 0x527: 0x0010, 0x528: 0x0010,
+	0x52a: 0x0010, 0x52b: 0x0010, 0x52c: 0x0010, 0x52d: 0x0010, 0x52e: 0x0010, 0x52f: 0x0010,
+	0x530: 0x0010, 0x531: 0x0010, 0x532: 0x0010, 0x533: 0x0010, 0x534: 0x0010, 0x535: 0x0010,
+	0x536: 0x0010, 0x538: 0x0010, 0x539: 0x0010, 0x53a: 0x0010, 0x53b: 0x0010,
+	0x53c: 0x0010, 0x53e: 0x0010,
+	// Block 0x15, offset 0x540
+	0x540: 0x2713, 0x541: 0x2913, 0x542: 0x2b13, 0x543: 0x2913, 0x544: 0x2f13, 0x545: 0x2913,
+	0x546: 0x2b13, 0x547: 0x2913, 0x548: 0x2713, 0x549: 0x3913, 0x54a: 0x3b13,
+	0x54c: 0x3f13, 0x54d: 0x3913, 0x54e: 0x3b13, 0x54f: 0x3913, 0x550: 0x2713, 0x551: 0x2913,
+	0x552: 0x2b13, 0x554: 0x2f13, 0x555: 0x2913, 0x557: 0xbc52,
+	0x558: 0xbf52, 0x559: 0xc252, 0x55a: 0xbf52, 0x55b: 0xc552, 0x55c: 0xbf52, 0x55d: 0xc252,
+	0x55e: 0xbf52, 0x55f: 0xbc52, 0x560: 0xc852, 0x561: 0xcb52, 0x563: 0xce52,
+	0x564: 0xc852, 0x565: 0xcb52, 0x566: 0xc852, 0x567: 0x2712, 0x568: 0x2912, 0x569: 0x2b12,
+	0x56a: 0x2912, 0x56b: 0x2f12, 0x56c: 0x2912, 0x56d: 0x2b12, 0x56e: 0x2912, 0x56f: 0x2712,
+	0x570: 0x3912, 0x571: 0x3b12, 0x573: 0x3f12, 0x574: 0x3912, 0x575: 0x3b12,
+	0x576: 0x3912, 0x577: 0x2712, 0x578: 0x2912, 0x579: 0x2b12, 0x57b: 0x2f12,
+	0x57c: 0x2912,
+	// Block 0x16, offset 0x580
+	0x5a0: 0x1b13, 0x5a1: 0x1d13, 0x5a2: 0x1f13, 0x5a3: 0x1d13,
+	0x5a4: 0x1b13, 0x5a5: 0xd453, 0x5a6: 0xd753, 0x5a7: 0xd453, 0x5a8: 0xda53, 0x5a9: 0xdd53,
+	0x5aa: 0xe053, 0x5ab: 0xdd53, 0x5ac: 0xda53, 0x5ad: 0xd453, 0x5ae: 0xd753, 0x5af: 0xd453,
+	0x5b0: 0xe353, 0x5b1: 0xe653, 0x5b2: 0x0553, 0x5b3: 0xe653, 0x5b4: 0xe353, 0x5b5: 0xd453,
+	0x5b6: 0xd753, 0x5b7: 0xd453, 0x5b8: 0xda53, 0x5bb: 0x1b12,
+	0x5bc: 0x1d12, 0x5bd: 0x1f12, 0x5be: 0x1d12, 0x5bf: 0x1b12,
+	// Block 0x17, offset 0x5c0
+	0x5c0: 0xd452, 0x5c1: 0xd752, 0x5c2: 0xd452, 0x5c3: 0xda52, 0x5c4: 0xdd52, 0x5c5: 0xe052,
+	0x5c6: 0xdd52, 0x5c7: 0xda52, 0x5c8: 0xd452, 0x5c9: 0xd752, 0x5ca: 0xd452, 0x5cb: 0xe352,
+	0x5cc: 0xe652, 0x5cd: 0x0552, 0x5ce: 0xe652, 0x5cf: 0xe352, 0x5d0: 0xd452, 0x5d1: 0xd752,
+	0x5d2: 0xd452, 0x5d3: 0xda52,
+	// Block 0x18, offset 0x600
+	0x600: 0x2213, 0x601: 0x2213, 0x602: 0x2613, 0x603: 0x2613, 0x604: 0x2213, 0x605: 0x2213,
+	0x606: 0x2e13, 0x607: 0x2e13, 0x608: 0x2213, 0x609: 0x2213, 0x60a: 0x2613, 0x60b: 0x2613,
+	0x60c: 0x2213, 0x60d: 0x2213, 0x60e: 0x3e13, 0x60f: 0x3e13, 0x610: 0x2213, 0x611: 0x2213,
+	0x612: 0x2613, 0x613: 0x2613, 0x614: 0x2213, 0x615: 0x2213, 0x616: 0x2e13, 0x617: 0x2e13,
+	0x618: 0x2213, 0x619: 0x2213, 0x61a: 0x2613, 0x61b: 0x2613, 0x61c: 0x2213, 0x61d: 0x2213,
+	0x61e: 0xe953, 0x61f: 0xe953, 0x620: 0xec53, 0x621: 0xec53, 0x622: 0x2212, 0x623: 0x2212,
+	0x624: 0x2612, 0x625: 0x2612, 0x626: 0x2212, 0x627: 0x2212, 0x628: 0x2e12, 0x629: 0x2e12,
+	0x62a: 0x2212, 0x62b: 0x2212, 0x62c: 0x2612, 0x62d: 0x2612, 0x62e: 0x2212, 0x62f: 0x2212,
+	0x630: 0x3e12, 0x631: 0x3e12, 0x632: 0x2212, 0x633: 0x2212, 0x634: 0x2612, 0x635: 0x2612,
+	0x636: 0x2212, 0x637: 0x2212, 0x638: 0x2e12, 0x639: 0x2e12, 0x63a: 0x2212, 0x63b: 0x2212,
+	0x63c: 0x2612, 0x63d: 0x2612, 0x63e: 0x2212, 0x63f: 0x2212,
+	// Block 0x19, offset 0x640
+	0x642: 0x0010,
+	0x647: 0x0010, 0x649: 0x0010, 0x64b: 0x0010,
+	0x64d: 0x0010, 0x64e: 0x0010, 0x64f: 0x0010, 0x651: 0x0010,
+	0x652: 0x0010, 0x654: 0x0010, 0x657: 0x0010,
+	0x659: 0x0010, 0x65b: 0x0010, 0x65d: 0x0010,
+	0x65f: 0x0010, 0x661: 0x0010, 0x662: 0x0010,
+	0x664: 0x0010, 0x667: 0x0010, 0x668: 0x0010, 0x669: 0x0010,
+	0x66a: 0x0010, 0x66c: 0x0010, 0x66d: 0x0010, 0x66e: 0x0010, 0x66f: 0x0010,
+	0x670: 0x0010, 0x671: 0x0010, 0x672: 0x0010, 0x674: 0x0010, 0x675: 0x0010,
+	0x676: 0x0010, 0x677: 0x0010, 0x679: 0x0010, 0x67a: 0x0010, 0x67b: 0x0010,
+	0x67c: 0x0010, 0x67e: 0x0010,
+}
+
+// caseIndex: 27 blocks, 1728 entries, 3456 bytes
+// Block 0 is the zero block.
+var caseIndex = [1728]uint16{
+	// Block 0x0, offset 0x0
+	// Block 0x1, offset 0x40
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc2: 0x18, 0xc3: 0x19, 0xc4: 0x1a, 0xc5: 0x1b, 0xc6: 0x01, 0xc7: 0x02,
+	0xc8: 0x1c, 0xc9: 0x03, 0xca: 0x04, 0xcb: 0x1d, 0xcc: 0x1e, 0xcd: 0x05, 0xce: 0x06, 0xcf: 0x07,
+	0xd0: 0x1f, 0xd1: 0x20, 0xd2: 0x21, 0xd3: 0x22, 0xd4: 0x23, 0xd5: 0x24, 0xd6: 0x08, 0xd7: 0x25,
+	0xd8: 0x26, 0xd9: 0x27, 0xda: 0x28, 0xdb: 0x29, 0xdc: 0x2a, 0xdd: 0x2b, 0xde: 0x2c, 0xdf: 0x2d,
+	0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
+	0xea: 0x06, 0xeb: 0x07, 0xec: 0x07, 0xed: 0x08, 0xef: 0x09,
+	0xf0: 0x16, 0xf3: 0x18,
+	// Block 0x4, offset 0x100
+	0x120: 0x2e, 0x121: 0x2f, 0x122: 0x30, 0x123: 0x09, 0x124: 0x31, 0x125: 0x32, 0x126: 0x33, 0x127: 0x34,
+	0x128: 0x35, 0x129: 0x36, 0x12a: 0x37, 0x12b: 0x38, 0x12c: 0x39, 0x12d: 0x3a, 0x12e: 0x3b, 0x12f: 0x3c,
+	0x130: 0x3d, 0x131: 0x3e, 0x132: 0x3f, 0x133: 0x40, 0x134: 0x41, 0x135: 0x42, 0x136: 0x43, 0x137: 0x44,
+	0x138: 0x45, 0x139: 0x46, 0x13a: 0x47, 0x13b: 0x48, 0x13c: 0x49, 0x13d: 0x4a, 0x13e: 0x4b, 0x13f: 0x4c,
+	// Block 0x5, offset 0x140
+	0x140: 0x4d, 0x141: 0x4e, 0x142: 0x4f, 0x143: 0x0a, 0x144: 0x28, 0x145: 0x28, 0x146: 0x28, 0x147: 0x28,
+	0x148: 0x28, 0x149: 0x50, 0x14a: 0x51, 0x14b: 0x52, 0x14c: 0x53, 0x14d: 0x54, 0x14e: 0x55, 0x14f: 0x56,
+	0x150: 0x57, 0x151: 0x28, 0x152: 0x28, 0x153: 0x28, 0x154: 0x28, 0x155: 0x28, 0x156: 0x28, 0x157: 0x28,
+	0x158: 0x28, 0x159: 0x58, 0x15a: 0x59, 0x15b: 0x5a, 0x15c: 0x5b, 0x15d: 0x5c, 0x15e: 0x5d, 0x15f: 0x5e,
+	0x160: 0x5f, 0x161: 0x60, 0x162: 0x61, 0x163: 0x62, 0x164: 0x63, 0x165: 0x64, 0x167: 0x65,
+	0x168: 0x66, 0x169: 0x67, 0x16a: 0x68, 0x16b: 0x69, 0x16c: 0x6a, 0x16d: 0x6b, 0x16e: 0x6c, 0x16f: 0x6d,
+	0x170: 0x6e, 0x171: 0x6f, 0x172: 0x70, 0x173: 0x71, 0x174: 0x72, 0x175: 0x73, 0x176: 0x74, 0x177: 0x75,
+	0x178: 0x76, 0x179: 0x76, 0x17a: 0x77, 0x17b: 0x76, 0x17c: 0x78, 0x17d: 0x0b, 0x17e: 0x0c, 0x17f: 0x0d,
+	// Block 0x6, offset 0x180
+	0x180: 0x79, 0x181: 0x7a, 0x182: 0x7b, 0x183: 0x7c, 0x184: 0x0e, 0x185: 0x7d, 0x186: 0x7e,
+	0x192: 0x7f, 0x193: 0x0f,
+	0x1b0: 0x80, 0x1b1: 0x10, 0x1b2: 0x76, 0x1b3: 0x81, 0x1b4: 0x82, 0x1b5: 0x83, 0x1b6: 0x84, 0x1b7: 0x85,
+	0x1b8: 0x86,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x87, 0x1c2: 0x88, 0x1c3: 0x89, 0x1c4: 0x8a, 0x1c5: 0x28, 0x1c6: 0x8b,
+	// Block 0x8, offset 0x200
+	0x200: 0x8c, 0x201: 0x28, 0x202: 0x28, 0x203: 0x28, 0x204: 0x28, 0x205: 0x28, 0x206: 0x28, 0x207: 0x28,
+	0x208: 0x28, 0x209: 0x28, 0x20a: 0x28, 0x20b: 0x28, 0x20c: 0x28, 0x20d: 0x28, 0x20e: 0x28, 0x20f: 0x28,
+	0x210: 0x28, 0x211: 0x28, 0x212: 0x8d, 0x213: 0x8e, 0x214: 0x28, 0x215: 0x28, 0x216: 0x28, 0x217: 0x28,
+	0x218: 0x8f, 0x219: 0x90, 0x21a: 0x91, 0x21b: 0x92, 0x21c: 0x93, 0x21d: 0x94, 0x21e: 0x11, 0x21f: 0x95,
+	0x220: 0x96, 0x221: 0x97, 0x222: 0x28, 0x223: 0x98, 0x224: 0x99, 0x225: 0x9a, 0x226: 0x9b, 0x227: 0x9c,
+	0x228: 0x9d, 0x229: 0x9e, 0x22a: 0x9f, 0x22b: 0xa0, 0x22c: 0xa1, 0x22d: 0xa2, 0x22e: 0xa3, 0x22f: 0xa4,
+	0x230: 0x28, 0x231: 0x28, 0x232: 0x28, 0x233: 0x28, 0x234: 0x28, 0x235: 0x28, 0x236: 0x28, 0x237: 0x28,
+	0x238: 0x28, 0x239: 0x28, 0x23a: 0x28, 0x23b: 0x28, 0x23c: 0x28, 0x23d: 0x28, 0x23e: 0x28, 0x23f: 0x28,
+	// Block 0x9, offset 0x240
+	0x240: 0x28, 0x241: 0x28, 0x242: 0x28, 0x243: 0x28, 0x244: 0x28, 0x245: 0x28, 0x246: 0x28, 0x247: 0x28,
+	0x248: 0x28, 0x249: 0x28, 0x24a: 0x28, 0x24b: 0x28, 0x24c: 0x28, 0x24d: 0x28, 0x24e: 0x28, 0x24f: 0x28,
+	0x250: 0x28, 0x251: 0x28, 0x252: 0x28, 0x253: 0x28, 0x254: 0x28, 0x255: 0x28, 0x256: 0x28, 0x257: 0x28,
+	0x258: 0x28, 0x259: 0x28, 0x25a: 0x28, 0x25b: 0x28, 0x25c: 0x28, 0x25d: 0x28, 0x25e: 0x28, 0x25f: 0x28,
+	0x260: 0x28, 0x261: 0x28, 0x262: 0x28, 0x263: 0x28, 0x264: 0x28, 0x265: 0x28, 0x266: 0x28, 0x267: 0x28,
+	0x268: 0x28, 0x269: 0x28, 0x26a: 0x28, 0x26b: 0x28, 0x26c: 0x28, 0x26d: 0x28, 0x26e: 0x28, 0x26f: 0x28,
+	0x270: 0x28, 0x271: 0x28, 0x272: 0x28, 0x273: 0x28, 0x274: 0x28, 0x275: 0x28, 0x276: 0x28, 0x277: 0x28,
+	0x278: 0x28, 0x279: 0x28, 0x27a: 0x28, 0x27b: 0x28, 0x27c: 0x28, 0x27d: 0x28, 0x27e: 0x28, 0x27f: 0x28,
+	// Block 0xa, offset 0x280
+	0x280: 0x28, 0x281: 0x28, 0x282: 0x28, 0x283: 0x28, 0x284: 0x28, 0x285: 0x28, 0x286: 0x28, 0x287: 0x28,
+	0x288: 0x28, 0x289: 0x28, 0x28a: 0x28, 0x28b: 0x28, 0x28c: 0x28, 0x28d: 0x28, 0x28e: 0x28, 0x28f: 0x28,
+	0x290: 0x28, 0x291: 0x28, 0x292: 0x28, 0x293: 0x28, 0x294: 0x28, 0x295: 0x28, 0x296: 0x28, 0x297: 0x28,
+	0x298: 0x28, 0x299: 0x28, 0x29a: 0x28, 0x29b: 0x28, 0x29c: 0x28, 0x29d: 0x28, 0x29e: 0xa5, 0x29f: 0xa6,
+	// Block 0xb, offset 0x2c0
+	0x2ec: 0x12, 0x2ed: 0xa7, 0x2ee: 0xa8, 0x2ef: 0xa9,
+	0x2f0: 0x28, 0x2f1: 0x28, 0x2f2: 0x28, 0x2f3: 0x28, 0x2f4: 0xaa, 0x2f5: 0xab, 0x2f6: 0xac, 0x2f7: 0xad,
+	0x2f8: 0xae, 0x2f9: 0xaf, 0x2fa: 0x28, 0x2fb: 0xb0, 0x2fc: 0xb1, 0x2fd: 0xb2, 0x2fe: 0xb3, 0x2ff: 0xb4,
+	// Block 0xc, offset 0x300
+	0x300: 0xb5, 0x301: 0xb6, 0x302: 0x28, 0x303: 0xb7, 0x305: 0xb8, 0x307: 0xb9,
+	0x30a: 0xba, 0x30b: 0xbb, 0x30c: 0xbc, 0x30d: 0xbd, 0x30e: 0xbe, 0x30f: 0xbf,
+	0x310: 0xc0, 0x311: 0xc1, 0x312: 0xc2, 0x313: 0xc3, 0x314: 0xc4, 0x315: 0xc5, 0x316: 0x13, 0x317: 0x97,
+	0x318: 0x28, 0x319: 0x28, 0x31a: 0x28, 0x31b: 0x28, 0x31c: 0xc6, 0x31d: 0xc7, 0x31e: 0xc8,
+	0x320: 0xc9, 0x321: 0xca, 0x322: 0xcb, 0x323: 0xcc, 0x324: 0xcd, 0x325: 0xce, 0x326: 0xcf,
+	0x328: 0xd0, 0x329: 0xd1, 0x32a: 0xd2, 0x32b: 0xd3, 0x32c: 0x62, 0x32d: 0xd4, 0x32e: 0xd5,
+	0x330: 0x28, 0x331: 0xd6, 0x332: 0xd7, 0x333: 0xd8, 0x334: 0xd9, 0x335: 0xda, 0x336: 0xdb,
+	0x33a: 0xdc, 0x33b: 0xdd, 0x33c: 0xde, 0x33d: 0xdf, 0x33e: 0xe0, 0x33f: 0xe1,
+	// Block 0xd, offset 0x340
+	0x340: 0xe2, 0x341: 0xe3, 0x342: 0xe4, 0x343: 0xe5, 0x344: 0xe6, 0x345: 0xe7, 0x346: 0xe8, 0x347: 0xe9,
+	0x348: 0xea, 0x349: 0xeb, 0x34a: 0xec, 0x34b: 0xed, 0x34c: 0xee, 0x34d: 0xef, 0x34e: 0xf0, 0x34f: 0xf1,
+	0x350: 0xf2, 0x351: 0xf3, 0x352: 0xf4, 0x353: 0xf5, 0x356: 0xf6, 0x357: 0xf7,
+	0x358: 0xf8, 0x359: 0xf9, 0x35a: 0xfa, 0x35b: 0xfb, 0x35c: 0xfc,
+	0x360: 0xfd, 0x362: 0xfe, 0x363: 0xff, 0x364: 0x100, 0x365: 0x101, 0x366: 0x102, 0x367: 0x103,
+	0x368: 0x104, 0x369: 0x105, 0x36a: 0x106, 0x36b: 0x107, 0x36d: 0x108, 0x36f: 0x109,
+	0x370: 0x10a, 0x371: 0x10b, 0x372: 0x10c, 0x374: 0x10d, 0x375: 0x10e, 0x376: 0x10f, 0x377: 0x110,
+	0x37b: 0x111, 0x37c: 0x112, 0x37d: 0x113, 0x37e: 0x114,
+	// Block 0xe, offset 0x380
+	0x380: 0x28, 0x381: 0x28, 0x382: 0x28, 0x383: 0x28, 0x384: 0x28, 0x385: 0x28, 0x386: 0x28, 0x387: 0x28,
+	0x388: 0x28, 0x389: 0x28, 0x38a: 0x28, 0x38b: 0x28, 0x38c: 0x28, 0x38d: 0x28, 0x38e: 0xce,
+	0x390: 0x28, 0x391: 0x115, 0x392: 0x28, 0x393: 0x28, 0x394: 0x28, 0x395: 0x116,
+	0x3be: 0xab, 0x3bf: 0x117,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x28, 0x3c1: 0x28, 0x3c2: 0x28, 0x3c3: 0x28, 0x3c4: 0x28, 0x3c5: 0x28, 0x3c6: 0x28, 0x3c7: 0x28,
+	0x3c8: 0x28, 0x3c9: 0x28, 0x3ca: 0x28, 0x3cb: 0x28, 0x3cc: 0x28, 0x3cd: 0x28, 0x3ce: 0x28, 0x3cf: 0x28,
+	0x3d0: 0x118, 0x3d1: 0x119, 0x3d2: 0x28, 0x3d3: 0x28, 0x3d4: 0x28, 0x3d5: 0x28, 0x3d6: 0x28, 0x3d7: 0x28,
+	0x3d8: 0x28, 0x3d9: 0x28, 0x3da: 0x28, 0x3db: 0x28, 0x3dc: 0x28, 0x3dd: 0x28, 0x3de: 0x28, 0x3df: 0x28,
+	0x3e0: 0x28, 0x3e1: 0x28, 0x3e2: 0x28, 0x3e3: 0x28, 0x3e4: 0x28, 0x3e5: 0x28, 0x3e6: 0x28, 0x3e7: 0x28,
+	0x3e8: 0x28, 0x3e9: 0x28, 0x3ea: 0x28, 0x3eb: 0x28, 0x3ec: 0x28, 0x3ed: 0x28, 0x3ee: 0x28, 0x3ef: 0x28,
+	0x3f0: 0x28, 0x3f1: 0x28, 0x3f2: 0x28, 0x3f3: 0x28, 0x3f4: 0x28, 0x3f5: 0x28, 0x3f6: 0x28, 0x3f7: 0x28,
+	0x3f8: 0x28, 0x3f9: 0x28, 0x3fa: 0x28, 0x3fb: 0x28, 0x3fc: 0x28, 0x3fd: 0x28, 0x3fe: 0x28, 0x3ff: 0x28,
+	// Block 0x10, offset 0x400
+	0x400: 0x28, 0x401: 0x28, 0x402: 0x28, 0x403: 0x28, 0x404: 0x28, 0x405: 0x28, 0x406: 0x28, 0x407: 0x28,
+	0x408: 0x28, 0x409: 0x28, 0x40a: 0x28, 0x40b: 0x28, 0x40c: 0x28, 0x40d: 0x28, 0x40e: 0x28, 0x40f: 0xb7,
+	0x410: 0x28, 0x411: 0x28, 0x412: 0x28, 0x413: 0x28, 0x414: 0x28, 0x415: 0x28, 0x416: 0x28, 0x417: 0x28,
+	0x418: 0x28, 0x419: 0x11a,
+	// Block 0x11, offset 0x440
+	0x444: 0x11b,
+	0x460: 0x28, 0x461: 0x28, 0x462: 0x28, 0x463: 0x28, 0x464: 0x28, 0x465: 0x28, 0x466: 0x28, 0x467: 0x28,
+	0x468: 0x107, 0x469: 0x11c, 0x46a: 0x11d, 0x46b: 0x11e, 0x46c: 0x11f, 0x46d: 0x120, 0x46e: 0x121,
+	0x475: 0x122,
+	0x479: 0x123, 0x47a: 0x14, 0x47b: 0x15, 0x47c: 0x28, 0x47d: 0x124, 0x47e: 0x125, 0x47f: 0x126,
+	// Block 0x12, offset 0x480
+	0x4bf: 0x127,
+	// Block 0x13, offset 0x4c0
+	0x4f0: 0x28, 0x4f1: 0x128, 0x4f2: 0x129,
+	// Block 0x14, offset 0x500
+	0x533: 0x12a,
+	0x53c: 0x12b, 0x53d: 0x12c,
+	// Block 0x15, offset 0x540
+	0x545: 0x12d, 0x546: 0x12e,
+	0x549: 0x12f,
+	0x550: 0x130, 0x551: 0x131, 0x552: 0x132, 0x553: 0x133, 0x554: 0x134, 0x555: 0x135, 0x556: 0x136, 0x557: 0x137,
+	0x558: 0x138, 0x559: 0x139, 0x55a: 0x13a, 0x55b: 0x13b, 0x55c: 0x13c, 0x55d: 0x13d, 0x55e: 0x13e, 0x55f: 0x13f,
+	0x568: 0x140, 0x569: 0x141, 0x56a: 0x142,
+	0x57c: 0x143,
+	// Block 0x16, offset 0x580
+	0x580: 0x144, 0x581: 0x145, 0x582: 0x146, 0x584: 0x147, 0x585: 0x148,
+	0x58a: 0x149, 0x58b: 0x14a,
+	0x593: 0x14b, 0x597: 0x14c,
+	0x59b: 0x14d, 0x59f: 0x14e,
+	0x5a0: 0x28, 0x5a1: 0x28, 0x5a2: 0x28, 0x5a3: 0x14f, 0x5a4: 0x16, 0x5a5: 0x150,
+	0x5b8: 0x151, 0x5b9: 0x17, 0x5ba: 0x152,
+	// Block 0x17, offset 0x5c0
+	0x5c4: 0x153, 0x5c5: 0x154, 0x5c6: 0x155,
+	0x5cf: 0x156,
+	0x5ef: 0x12a,
+	// Block 0x18, offset 0x600
+	0x610: 0x0a, 0x611: 0x0b, 0x612: 0x0c, 0x613: 0x0d, 0x614: 0x0e, 0x616: 0x0f,
+	0x61a: 0x10, 0x61b: 0x11, 0x61c: 0x12, 0x61d: 0x13, 0x61e: 0x14, 0x61f: 0x15,
+	// Block 0x19, offset 0x640
+	0x640: 0x157, 0x641: 0x158, 0x644: 0x158, 0x645: 0x158, 0x646: 0x158, 0x647: 0x159,
+	// Block 0x1a, offset 0x680
+	0x6a0: 0x17,
+}
+
+// sparseOffsets: 323 entries, 646 bytes
+var sparseOffsets = []uint16{0x0, 0x9, 0xf, 0x18, 0x24, 0x2e, 0x34, 0x37, 0x3b, 0x3e, 0x42, 0x4c, 0x4e, 0x57, 0x5e, 0x63, 0x71, 0x72, 0x80, 0x8f, 0x99, 0x9c, 0xa3, 0xab, 0xaf, 0xb7, 0xbd, 0xcb, 0xd6, 0xe3, 0xee, 0xfa, 0x104, 0x110, 0x11b, 0x127, 0x133, 0x13b, 0x145, 0x150, 0x15b, 0x167, 0x16d, 0x178, 0x17e, 0x186, 0x189, 0x18e, 0x192, 0x196, 0x19d, 0x1a6, 0x1ae, 0x1af, 0x1b8, 0x1bf, 0x1c7, 0x1cd, 0x1d2, 0x1d6, 0x1d9, 0x1db, 0x1de, 0x1e3, 0x1e4, 0x1e6, 0x1e8, 0x1ea, 0x1f1, 0x1f6, 0x1fa, 0x203, 0x206, 0x209, 0x20f, 0x210, 0x21b, 0x21c, 0x21d, 0x222, 0x22f, 0x238, 0x243, 0x24b, 0x254, 0x25d, 0x266, 0x26b, 0x26e, 0x27a, 0x288, 0x28a, 0x291, 0x295, 0x2a1, 0x2a2, 0x2ad, 0x2b5, 0x2bd, 0x2c3, 0x2c4, 0x2d2, 0x2d7, 0x2da, 0x2df, 0x2e3, 0x2e9, 0x2ee, 0x2f1, 0x2f6, 0x2fb, 0x2fc, 0x302, 0x304, 0x305, 0x307, 0x309, 0x30c, 0x30d, 0x30f, 0x312, 0x318, 0x31c, 0x31e, 0x323, 0x32a, 0x339, 0x343, 0x344, 0x34d, 0x351, 0x356, 0x35e, 0x364, 0x36a, 0x374, 0x379, 0x382, 0x388, 0x391, 0x395, 0x39d, 0x39f, 0x3a1, 0x3a4, 0x3a6, 0x3a8, 0x3a9, 0x3aa, 0x3ac, 0x3ae, 0x3b4, 0x3b9, 0x3bb, 0x3c2, 0x3c5, 0x3c7, 0x3cd, 0x3d2, 0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x3d9, 0x3db, 0x3dd, 0x3e0, 0x3e2, 0x3e5, 0x3ed, 0x3f0, 0x3f4, 0x3fc, 0x3fe, 0x40e, 0x40f, 0x411, 0x416, 0x41c, 0x41e, 0x41f, 0x421, 0x423, 0x424, 0x426, 0x433, 0x434, 0x435, 0x439, 0x43b, 0x43c, 0x43d, 0x43e, 0x43f, 0x442, 0x44a, 0x44b, 0x44e, 0x454, 0x457, 0x45e, 0x464, 0x466, 0x46a, 0x472, 0x478, 0x47c, 0x483, 0x487, 0x48b, 0x494, 0x49e, 0x4a0, 0x4a6, 0x4ac, 0x4b6, 0x4c0, 0x4c6, 0x4d2, 0x4d4, 0x4dd, 0x4e3, 0x4e9, 0x4ef, 0x4f2, 0x4f8, 0x4fb, 0x504, 0x506, 0x50f, 0x513, 0x514, 0x517, 0x521, 0x524, 0x526, 0x52d, 0x535, 0x53b, 0x542, 0x543, 0x549, 0x54b, 0x551, 0x554, 0x55c, 0x563, 0x56d, 0x576, 0x57a, 0x57d, 0x582, 0x587, 0x588, 0x589, 0x58a, 0x58b, 0x58d, 0x591, 0x592, 0x598, 0x59b, 0x59c, 0x59f, 0x5a1, 0x5a5, 0x5a6, 0x5aa, 0x5ac, 0x5af, 0x5b1, 0x5b5, 0x5b8, 0x5ba, 0x5bf, 0x5c0, 0x5c2, 0x5c3, 0x5c8, 0x5cc, 0x5cd, 0x5d0, 0x5d4, 0x5df, 0x5e3, 0x5eb, 0x5f0, 0x5f4, 0x5f7, 0x5fb, 0x5fe, 0x601, 0x606, 0x60a, 0x60e, 0x612, 0x616, 0x618, 0x61a, 0x61d, 0x621, 0x627, 0x628, 0x629, 0x62c, 0x62e, 0x630, 0x633, 0x638, 0x63c, 0x647, 0x64b, 0x64d, 0x653, 0x65c, 0x661, 0x662, 0x665, 0x666, 0x667, 0x669, 0x66a, 0x66b}
+
+// sparseValues: 1643 entries, 6572 bytes
+var sparseValues = [1643]valueRange{
+	// Block 0x0, offset 0x0
+	{value: 0x0004, lo: 0xa8, hi: 0xa8},
+	{value: 0x0012, lo: 0xaa, hi: 0xaa},
+	{value: 0x0014, lo: 0xad, hi: 0xad},
+	{value: 0x0004, lo: 0xaf, hi: 0xaf},
+	{value: 0x0004, lo: 0xb4, hi: 0xb4},
+	{value: 0x001a, lo: 0xb5, hi: 0xb5},
+	{value: 0x0054, lo: 0xb7, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xb8},
+	{value: 0x0012, lo: 0xba, hi: 0xba},
+	// Block 0x1, offset 0x9
+	{value: 0x2013, lo: 0x80, hi: 0x96},
+	{value: 0x2013, lo: 0x98, hi: 0x9e},
+	{value: 0x009a, lo: 0x9f, hi: 0x9f},
+	{value: 0x2012, lo: 0xa0, hi: 0xb6},
+	{value: 0x2012, lo: 0xb8, hi: 0xbe},
+	{value: 0x0252, lo: 0xbf, hi: 0xbf},
+	// Block 0x2, offset 0xf
+	{value: 0x0117, lo: 0x80, hi: 0xaf},
+	{value: 0x011b, lo: 0xb0, hi: 0xb0},
+	{value: 0x019a, lo: 0xb1, hi: 0xb1},
+	{value: 0x0117, lo: 0xb2, hi: 0xb7},
+	{value: 0x0012, lo: 0xb8, hi: 0xb8},
+	{value: 0x0316, lo: 0xb9, hi: 0xba},
+	{value: 0x0716, lo: 0xbb, hi: 0xbc},
+	{value: 0x0316, lo: 0xbd, hi: 0xbe},
+	{value: 0x0553, lo: 0xbf, hi: 0xbf},
+	// Block 0x3, offset 0x18
+	{value: 0x0552, lo: 0x80, hi: 0x80},
+	{value: 0x0316, lo: 0x81, hi: 0x82},
+	{value: 0x0716, lo: 0x83, hi: 0x84},
+	{value: 0x0316, lo: 0x85, hi: 0x86},
+	{value: 0x0f16, lo: 0x87, hi: 0x88},
+	{value: 0x01da, lo: 0x89, hi: 0x89},
+	{value: 0x0117, lo: 0x8a, hi: 0xb7},
+	{value: 0x0253, lo: 0xb8, hi: 0xb8},
+	{value: 0x0316, lo: 0xb9, hi: 0xba},
+	{value: 0x0716, lo: 0xbb, hi: 0xbc},
+	{value: 0x0316, lo: 0xbd, hi: 0xbe},
+	{value: 0x028a, lo: 0xbf, hi: 0xbf},
+	// Block 0x4, offset 0x24
+	{value: 0x0117, lo: 0x80, hi: 0x9f},
+	{value: 0x2f53, lo: 0xa0, hi: 0xa0},
+	{value: 0x0012, lo: 0xa1, hi: 0xa1},
+	{value: 0x0117, lo: 0xa2, hi: 0xb3},
+	{value: 0x0012, lo: 0xb4, hi: 0xb9},
+	{value: 0x098b, lo: 0xba, hi: 0xba},
+	{value: 0x0716, lo: 0xbb, hi: 0xbc},
+	{value: 0x2953, lo: 0xbd, hi: 0xbd},
+	{value: 0x0a0b, lo: 0xbe, hi: 0xbe},
+	{value: 0x0a8a, lo: 0xbf, hi: 0xbf},
+	// Block 0x5, offset 0x2e
+	{value: 0x0015, lo: 0x80, hi: 0x81},
+	{value: 0x0014, lo: 0x82, hi: 0x97},
+	{value: 0x0004, lo: 0x98, hi: 0x9d},
+	{value: 0x0014, lo: 0x9e, hi: 0x9f},
+	{value: 0x0015, lo: 0xa0, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xbf},
+	// Block 0x6, offset 0x34
+	{value: 0x0024, lo: 0x80, hi: 0x94},
+	{value: 0x0034, lo: 0x95, hi: 0xbc},
+	{value: 0x0024, lo: 0xbd, hi: 0xbf},
+	// Block 0x7, offset 0x37
+	{value: 0x6553, lo: 0x80, hi: 0x8f},
+	{value: 0x2013, lo: 0x90, hi: 0x9f},
+	{value: 0x5f53, lo: 0xa0, hi: 0xaf},
+	{value: 0x2012, lo: 0xb0, hi: 0xbf},
+	// Block 0x8, offset 0x3b
+	{value: 0x5f52, lo: 0x80, hi: 0x8f},
+	{value: 0x6552, lo: 0x90, hi: 0x9f},
+	{value: 0x0117, lo: 0xa0, hi: 0xbf},
+	// Block 0x9, offset 0x3e
+	{value: 0x0117, lo: 0x80, hi: 0x81},
+	{value: 0x0024, lo: 0x83, hi: 0x87},
+	{value: 0x0014, lo: 0x88, hi: 0x89},
+	{value: 0x0117, lo: 0x8a, hi: 0xbf},
+	// Block 0xa, offset 0x42
+	{value: 0x0f13, lo: 0x80, hi: 0x80},
+	{value: 0x0316, lo: 0x81, hi: 0x82},
+	{value: 0x0716, lo: 0x83, hi: 0x84},
+	{value: 0x0316, lo: 0x85, hi: 0x86},
+	{value: 0x0f16, lo: 0x87, hi: 0x88},
+	{value: 0x0316, lo: 0x89, hi: 0x8a},
+	{value: 0x0716, lo: 0x8b, hi: 0x8c},
+	{value: 0x0316, lo: 0x8d, hi: 0x8e},
+	{value: 0x0f12, lo: 0x8f, hi: 0x8f},
+	{value: 0x0117, lo: 0x90, hi: 0xbf},
+	// Block 0xb, offset 0x4c
+	{value: 0x0117, lo: 0x80, hi: 0xaf},
+	{value: 0x6553, lo: 0xb1, hi: 0xbf},
+	// Block 0xc, offset 0x4e
+	{value: 0x3013, lo: 0x80, hi: 0x8f},
+	{value: 0x6853, lo: 0x90, hi: 0x96},
+	{value: 0x0014, lo: 0x99, hi: 0x99},
+	{value: 0x0010, lo: 0x9a, hi: 0x9c},
+	{value: 0x0010, lo: 0x9e, hi: 0x9e},
+	{value: 0x0054, lo: 0x9f, hi: 0x9f},
+	{value: 0x0012, lo: 0xa0, hi: 0xa0},
+	{value: 0x6552, lo: 0xa1, hi: 0xaf},
+	{value: 0x3012, lo: 0xb0, hi: 0xbf},
+	// Block 0xd, offset 0x57
+	{value: 0x0034, lo: 0x81, hi: 0x82},
+	{value: 0x0024, lo: 0x84, hi: 0x84},
+	{value: 0x0034, lo: 0x85, hi: 0x85},
+	{value: 0x0034, lo: 0x87, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0xaa},
+	{value: 0x0010, lo: 0xaf, hi: 0xb3},
+	{value: 0x0054, lo: 0xb4, hi: 0xb4},
+	// Block 0xe, offset 0x5e
+	{value: 0x0014, lo: 0x80, hi: 0x85},
+	{value: 0x0024, lo: 0x90, hi: 0x97},
+	{value: 0x0034, lo: 0x98, hi: 0x9a},
+	{value: 0x0014, lo: 0x9c, hi: 0x9c},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0xf, offset 0x63
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x8a},
+	{value: 0x0034, lo: 0x8b, hi: 0x92},
+	{value: 0x0024, lo: 0x93, hi: 0x94},
+	{value: 0x0034, lo: 0x95, hi: 0x96},
+	{value: 0x0024, lo: 0x97, hi: 0x9b},
+	{value: 0x0034, lo: 0x9c, hi: 0x9c},
+	{value: 0x0024, lo: 0x9d, hi: 0x9e},
+	{value: 0x0034, lo: 0x9f, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0010, lo: 0xab, hi: 0xab},
+	{value: 0x0010, lo: 0xae, hi: 0xaf},
+	{value: 0x0034, lo: 0xb0, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xbf},
+	// Block 0x10, offset 0x71
+	{value: 0x0010, lo: 0x80, hi: 0xbf},
+	// Block 0x11, offset 0x72
+	{value: 0x0010, lo: 0x80, hi: 0x93},
+	{value: 0x0010, lo: 0x95, hi: 0x95},
+	{value: 0x0024, lo: 0x96, hi: 0x9c},
+	{value: 0x0014, lo: 0x9d, hi: 0x9d},
+	{value: 0x0024, lo: 0x9f, hi: 0xa2},
+	{value: 0x0034, lo: 0xa3, hi: 0xa3},
+	{value: 0x0024, lo: 0xa4, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xa6},
+	{value: 0x0024, lo: 0xa7, hi: 0xa8},
+	{value: 0x0034, lo: 0xaa, hi: 0xaa},
+	{value: 0x0024, lo: 0xab, hi: 0xac},
+	{value: 0x0034, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xbc},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x12, offset 0x80
+	{value: 0x0014, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0034, lo: 0x91, hi: 0x91},
+	{value: 0x0010, lo: 0x92, hi: 0xaf},
+	{value: 0x0024, lo: 0xb0, hi: 0xb0},
+	{value: 0x0034, lo: 0xb1, hi: 0xb1},
+	{value: 0x0024, lo: 0xb2, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0024, lo: 0xb5, hi: 0xb6},
+	{value: 0x0034, lo: 0xb7, hi: 0xb9},
+	{value: 0x0024, lo: 0xba, hi: 0xba},
+	{value: 0x0034, lo: 0xbb, hi: 0xbc},
+	{value: 0x0024, lo: 0xbd, hi: 0xbd},
+	{value: 0x0034, lo: 0xbe, hi: 0xbe},
+	{value: 0x0024, lo: 0xbf, hi: 0xbf},
+	// Block 0x13, offset 0x8f
+	{value: 0x0024, lo: 0x80, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0024, lo: 0x83, hi: 0x83},
+	{value: 0x0034, lo: 0x84, hi: 0x84},
+	{value: 0x0024, lo: 0x85, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	{value: 0x0024, lo: 0x87, hi: 0x87},
+	{value: 0x0034, lo: 0x88, hi: 0x88},
+	{value: 0x0024, lo: 0x89, hi: 0x8a},
+	{value: 0x0010, lo: 0x8d, hi: 0xbf},
+	// Block 0x14, offset 0x99
+	{value: 0x0010, lo: 0x80, hi: 0xa5},
+	{value: 0x0014, lo: 0xa6, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xb1},
+	// Block 0x15, offset 0x9c
+	{value: 0x0010, lo: 0x80, hi: 0xaa},
+	{value: 0x0024, lo: 0xab, hi: 0xb1},
+	{value: 0x0034, lo: 0xb2, hi: 0xb2},
+	{value: 0x0024, lo: 0xb3, hi: 0xb3},
+	{value: 0x0014, lo: 0xb4, hi: 0xb5},
+	{value: 0x0014, lo: 0xba, hi: 0xba},
+	{value: 0x0034, lo: 0xbd, hi: 0xbd},
+	// Block 0x16, offset 0xa3
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0024, lo: 0x96, hi: 0x99},
+	{value: 0x0014, lo: 0x9a, hi: 0x9a},
+	{value: 0x0024, lo: 0x9b, hi: 0xa3},
+	{value: 0x0014, lo: 0xa4, hi: 0xa4},
+	{value: 0x0024, lo: 0xa5, hi: 0xa7},
+	{value: 0x0014, lo: 0xa8, hi: 0xa8},
+	{value: 0x0024, lo: 0xa9, hi: 0xad},
+	// Block 0x17, offset 0xab
+	{value: 0x0010, lo: 0x80, hi: 0x98},
+	{value: 0x0034, lo: 0x99, hi: 0x9b},
+	{value: 0x0010, lo: 0xa0, hi: 0xaa},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x18, offset 0xaf
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0004, lo: 0x88, hi: 0x88},
+	{value: 0x0010, lo: 0x89, hi: 0x8f},
+	{value: 0x0014, lo: 0x90, hi: 0x91},
+	{value: 0x0024, lo: 0x97, hi: 0x98},
+	{value: 0x0034, lo: 0x99, hi: 0x9b},
+	{value: 0x0024, lo: 0x9c, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x19, offset 0xb7
+	{value: 0x0014, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0xb9},
+	{value: 0x0014, lo: 0xba, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x1a, offset 0xbd
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x88},
+	{value: 0x0010, lo: 0x89, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0024, lo: 0x91, hi: 0x91},
+	{value: 0x0034, lo: 0x92, hi: 0x92},
+	{value: 0x0024, lo: 0x93, hi: 0x94},
+	{value: 0x0014, lo: 0x95, hi: 0x97},
+	{value: 0x0010, lo: 0x98, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0014, lo: 0xb1, hi: 0xb1},
+	{value: 0x0010, lo: 0xb2, hi: 0xbf},
+	// Block 0x1b, offset 0xcb
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8f, hi: 0x90},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb2},
+	{value: 0x0010, lo: 0xb6, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x1c, offset 0xd6
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x84},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0x9c, hi: 0x9d},
+	{value: 0x0010, lo: 0x9f, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xb1},
+	{value: 0x0010, lo: 0xbc, hi: 0xbc},
+	{value: 0x0024, lo: 0xbe, hi: 0xbe},
+	// Block 0x1d, offset 0xe3
+	{value: 0x0014, lo: 0x81, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8a},
+	{value: 0x0010, lo: 0x8f, hi: 0x90},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb6},
+	{value: 0x0010, lo: 0xb8, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x1e, offset 0xee
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x82},
+	{value: 0x0014, lo: 0x87, hi: 0x88},
+	{value: 0x0014, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0014, lo: 0x91, hi: 0x91},
+	{value: 0x0010, lo: 0x99, hi: 0x9c},
+	{value: 0x0010, lo: 0x9e, hi: 0x9e},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xb1},
+	{value: 0x0010, lo: 0xb2, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb5},
+	// Block 0x1f, offset 0xfa
+	{value: 0x0014, lo: 0x81, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8d},
+	{value: 0x0010, lo: 0x8f, hi: 0x91},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x20, offset 0x104
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x85},
+	{value: 0x0014, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x89, hi: 0x89},
+	{value: 0x0010, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0010, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xb9, hi: 0xb9},
+	{value: 0x0014, lo: 0xba, hi: 0xbf},
+	// Block 0x21, offset 0x110
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8f, hi: 0x90},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x22, offset 0x11b
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x84},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0014, lo: 0x95, hi: 0x96},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0x9c, hi: 0x9d},
+	{value: 0x0010, lo: 0x9f, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xb1, hi: 0xb1},
+	// Block 0x23, offset 0x127
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8a},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0x95},
+	{value: 0x0010, lo: 0x99, hi: 0x9a},
+	{value: 0x0010, lo: 0x9c, hi: 0x9c},
+	{value: 0x0010, lo: 0x9e, hi: 0x9f},
+	{value: 0x0010, lo: 0xa3, hi: 0xa4},
+	{value: 0x0010, lo: 0xa8, hi: 0xaa},
+	{value: 0x0010, lo: 0xae, hi: 0xb9},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x24, offset 0x133
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x82},
+	{value: 0x0010, lo: 0x86, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	// Block 0x25, offset 0x13b
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x83},
+	{value: 0x0014, lo: 0x84, hi: 0x84},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbd},
+	{value: 0x0014, lo: 0xbe, hi: 0xbf},
+	// Block 0x26, offset 0x145
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x84},
+	{value: 0x0014, lo: 0x86, hi: 0x88},
+	{value: 0x0014, lo: 0x8a, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0034, lo: 0x95, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0x9a},
+	{value: 0x0010, lo: 0x9c, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	// Block 0x27, offset 0x150
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x28, offset 0x15b
+	{value: 0x0010, lo: 0x80, hi: 0x84},
+	{value: 0x0014, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x95, hi: 0x96},
+	{value: 0x0010, lo: 0x9c, hi: 0x9e},
+	{value: 0x0010, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xb1, hi: 0xb3},
+	// Block 0x29, offset 0x167
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x8c},
+	{value: 0x0010, lo: 0x8e, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0xba},
+	{value: 0x0034, lo: 0xbb, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x2a, offset 0x16d
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x84},
+	{value: 0x0010, lo: 0x86, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	{value: 0x0010, lo: 0x94, hi: 0x97},
+	{value: 0x0010, lo: 0x9f, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa3},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xba, hi: 0xbf},
+	// Block 0x2b, offset 0x178
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x96},
+	{value: 0x0010, lo: 0x9a, hi: 0xb1},
+	{value: 0x0010, lo: 0xb3, hi: 0xbb},
+	{value: 0x0010, lo: 0xbd, hi: 0xbd},
+	// Block 0x2c, offset 0x17e
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0010, lo: 0x8f, hi: 0x91},
+	{value: 0x0014, lo: 0x92, hi: 0x94},
+	{value: 0x0014, lo: 0x96, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0x9f},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	// Block 0x2d, offset 0x186
+	{value: 0x0014, lo: 0xb1, hi: 0xb1},
+	{value: 0x0014, lo: 0xb4, hi: 0xb7},
+	{value: 0x0034, lo: 0xb8, hi: 0xba},
+	// Block 0x2e, offset 0x189
+	{value: 0x0004, lo: 0x86, hi: 0x86},
+	{value: 0x0014, lo: 0x87, hi: 0x87},
+	{value: 0x0034, lo: 0x88, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0x2f, offset 0x18e
+	{value: 0x0014, lo: 0xb1, hi: 0xb1},
+	{value: 0x0014, lo: 0xb4, hi: 0xb7},
+	{value: 0x0034, lo: 0xb8, hi: 0xba},
+	{value: 0x0014, lo: 0xbb, hi: 0xbc},
+	// Block 0x30, offset 0x192
+	{value: 0x0004, lo: 0x86, hi: 0x86},
+	{value: 0x0034, lo: 0x88, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0x31, offset 0x196
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0034, lo: 0x98, hi: 0x99},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0034, lo: 0xb5, hi: 0xb5},
+	{value: 0x0034, lo: 0xb7, hi: 0xb7},
+	{value: 0x0034, lo: 0xb9, hi: 0xb9},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x32, offset 0x19d
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0010, lo: 0x89, hi: 0xac},
+	{value: 0x0034, lo: 0xb1, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xba, hi: 0xbd},
+	{value: 0x0014, lo: 0xbe, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x33, offset 0x1a6
+	{value: 0x0034, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0024, lo: 0x82, hi: 0x83},
+	{value: 0x0034, lo: 0x84, hi: 0x84},
+	{value: 0x0024, lo: 0x86, hi: 0x87},
+	{value: 0x0010, lo: 0x88, hi: 0x8c},
+	{value: 0x0014, lo: 0x8d, hi: 0x97},
+	{value: 0x0014, lo: 0x99, hi: 0xbc},
+	// Block 0x34, offset 0x1ae
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	// Block 0x35, offset 0x1af
+	{value: 0x0010, lo: 0xab, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb6},
+	{value: 0x0034, lo: 0xb7, hi: 0xb7},
+	{value: 0x0010, lo: 0xb8, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbc},
+	{value: 0x0014, lo: 0xbd, hi: 0xbe},
+	// Block 0x36, offset 0x1b8
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x96, hi: 0x97},
+	{value: 0x0014, lo: 0x98, hi: 0x99},
+	{value: 0x0014, lo: 0x9e, hi: 0xa0},
+	{value: 0x0010, lo: 0xa2, hi: 0xa4},
+	{value: 0x0010, lo: 0xa7, hi: 0xad},
+	{value: 0x0014, lo: 0xb1, hi: 0xb4},
+	// Block 0x37, offset 0x1bf
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x84},
+	{value: 0x0014, lo: 0x85, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x8f, hi: 0x9c},
+	{value: 0x0014, lo: 0x9d, hi: 0x9d},
+	{value: 0x6c53, lo: 0xa0, hi: 0xbf},
+	// Block 0x38, offset 0x1c7
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0x98},
+	{value: 0x0010, lo: 0x9a, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x39, offset 0x1cd
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb5},
+	{value: 0x0010, lo: 0xb8, hi: 0xbe},
+	// Block 0x3a, offset 0x1d2
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x82, hi: 0x85},
+	{value: 0x0010, lo: 0x88, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0xbf},
+	// Block 0x3b, offset 0x1d6
+	{value: 0x0010, lo: 0x80, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0x95},
+	{value: 0x0010, lo: 0x98, hi: 0xbf},
+	// Block 0x3c, offset 0x1d9
+	{value: 0x0010, lo: 0x80, hi: 0x9a},
+	{value: 0x0024, lo: 0x9d, hi: 0x9f},
+	// Block 0x3d, offset 0x1db
+	{value: 0x0010, lo: 0x80, hi: 0x8f},
+	{value: 0x7453, lo: 0xa0, hi: 0xaf},
+	{value: 0x7853, lo: 0xb0, hi: 0xbf},
+	// Block 0x3e, offset 0x1de
+	{value: 0x7c53, lo: 0x80, hi: 0x8f},
+	{value: 0x8053, lo: 0x90, hi: 0x9f},
+	{value: 0x7c53, lo: 0xa0, hi: 0xaf},
+	{value: 0x0813, lo: 0xb0, hi: 0xb5},
+	{value: 0x0892, lo: 0xb8, hi: 0xbd},
+	// Block 0x3f, offset 0x1e3
+	{value: 0x0010, lo: 0x81, hi: 0xbf},
+	// Block 0x40, offset 0x1e4
+	{value: 0x0010, lo: 0x80, hi: 0xac},
+	{value: 0x0010, lo: 0xaf, hi: 0xbf},
+	// Block 0x41, offset 0x1e6
+	{value: 0x0010, lo: 0x81, hi: 0x9a},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x42, offset 0x1e8
+	{value: 0x0010, lo: 0x80, hi: 0xaa},
+	{value: 0x0010, lo: 0xae, hi: 0xb8},
+	// Block 0x43, offset 0x1ea
+	{value: 0x0010, lo: 0x80, hi: 0x91},
+	{value: 0x0014, lo: 0x92, hi: 0x93},
+	{value: 0x0034, lo: 0x94, hi: 0x94},
+	{value: 0x0030, lo: 0x95, hi: 0x95},
+	{value: 0x0010, lo: 0x9f, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb3},
+	{value: 0x0030, lo: 0xb4, hi: 0xb4},
+	// Block 0x44, offset 0x1f1
+	{value: 0x0010, lo: 0x80, hi: 0x91},
+	{value: 0x0014, lo: 0x92, hi: 0x93},
+	{value: 0x0010, lo: 0xa0, hi: 0xac},
+	{value: 0x0010, lo: 0xae, hi: 0xb0},
+	{value: 0x0014, lo: 0xb2, hi: 0xb3},
+	// Block 0x45, offset 0x1f6
+	{value: 0x0014, lo: 0xb4, hi: 0xb5},
+	{value: 0x0010, lo: 0xb6, hi: 0xb6},
+	{value: 0x0014, lo: 0xb7, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x46, offset 0x1fa
+	{value: 0x0010, lo: 0x80, hi: 0x85},
+	{value: 0x0014, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0014, lo: 0x89, hi: 0x91},
+	{value: 0x0034, lo: 0x92, hi: 0x92},
+	{value: 0x0014, lo: 0x93, hi: 0x93},
+	{value: 0x0004, lo: 0x97, hi: 0x97},
+	{value: 0x0024, lo: 0x9d, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	// Block 0x47, offset 0x203
+	{value: 0x0014, lo: 0x8b, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x48, offset 0x206
+	{value: 0x0010, lo: 0x80, hi: 0x82},
+	{value: 0x0014, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x84, hi: 0xb8},
+	// Block 0x49, offset 0x209
+	{value: 0x0010, lo: 0x80, hi: 0x84},
+	{value: 0x0014, lo: 0x85, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0xa8},
+	{value: 0x0034, lo: 0xa9, hi: 0xa9},
+	{value: 0x0010, lo: 0xaa, hi: 0xaa},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x4a, offset 0x20f
+	{value: 0x0010, lo: 0x80, hi: 0xb5},
+	// Block 0x4b, offset 0x210
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	{value: 0x0014, lo: 0xa0, hi: 0xa2},
+	{value: 0x0010, lo: 0xa3, hi: 0xa6},
+	{value: 0x0014, lo: 0xa7, hi: 0xa8},
+	{value: 0x0010, lo: 0xa9, hi: 0xab},
+	{value: 0x0010, lo: 0xb0, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb2},
+	{value: 0x0010, lo: 0xb3, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xb9},
+	{value: 0x0024, lo: 0xba, hi: 0xba},
+	{value: 0x0034, lo: 0xbb, hi: 0xbb},
+	// Block 0x4c, offset 0x21b
+	{value: 0x0010, lo: 0x86, hi: 0x8f},
+	// Block 0x4d, offset 0x21c
+	{value: 0x0010, lo: 0x90, hi: 0x9a},
+	// Block 0x4e, offset 0x21d
+	{value: 0x0010, lo: 0x80, hi: 0x96},
+	{value: 0x0024, lo: 0x97, hi: 0x97},
+	{value: 0x0034, lo: 0x98, hi: 0x98},
+	{value: 0x0010, lo: 0x99, hi: 0x9a},
+	{value: 0x0014, lo: 0x9b, hi: 0x9b},
+	// Block 0x4f, offset 0x222
+	{value: 0x0010, lo: 0x95, hi: 0x95},
+	{value: 0x0014, lo: 0x96, hi: 0x96},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0014, lo: 0x98, hi: 0x9e},
+	{value: 0x0034, lo: 0xa0, hi: 0xa0},
+	{value: 0x0010, lo: 0xa1, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa2},
+	{value: 0x0010, lo: 0xa3, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xac},
+	{value: 0x0010, lo: 0xad, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb4},
+	{value: 0x0024, lo: 0xb5, hi: 0xbc},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0x50, offset 0x22f
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0004, lo: 0xa7, hi: 0xa7},
+	{value: 0x0024, lo: 0xb0, hi: 0xb4},
+	{value: 0x0034, lo: 0xb5, hi: 0xba},
+	{value: 0x0024, lo: 0xbb, hi: 0xbc},
+	{value: 0x0034, lo: 0xbd, hi: 0xbd},
+	{value: 0x0014, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0x51, offset 0x238
+	{value: 0x0034, lo: 0x80, hi: 0x80},
+	{value: 0x0024, lo: 0x81, hi: 0x82},
+	{value: 0x0034, lo: 0x83, hi: 0x84},
+	{value: 0x0024, lo: 0x85, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0024, lo: 0x8b, hi: 0x9c},
+	{value: 0x0034, lo: 0x9d, hi: 0x9d},
+	{value: 0x0024, lo: 0xa0, hi: 0xa5},
+	{value: 0x0034, lo: 0xa6, hi: 0xa6},
+	{value: 0x0024, lo: 0xa7, hi: 0xaa},
+	{value: 0x0034, lo: 0xab, hi: 0xab},
+	// Block 0x52, offset 0x243
+	{value: 0x0014, lo: 0x80, hi: 0x83},
+	{value: 0x0010, lo: 0x84, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x53, offset 0x24b
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x83},
+	{value: 0x0030, lo: 0x84, hi: 0x84},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0024, lo: 0xab, hi: 0xab},
+	{value: 0x0034, lo: 0xac, hi: 0xac},
+	{value: 0x0024, lo: 0xad, hi: 0xb3},
+	// Block 0x54, offset 0x254
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa5},
+	{value: 0x0010, lo: 0xa6, hi: 0xa7},
+	{value: 0x0014, lo: 0xa8, hi: 0xa9},
+	{value: 0x0030, lo: 0xaa, hi: 0xaa},
+	{value: 0x0034, lo: 0xab, hi: 0xab},
+	{value: 0x0014, lo: 0xac, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xbf},
+	// Block 0x55, offset 0x25d
+	{value: 0x0010, lo: 0x80, hi: 0xa5},
+	{value: 0x0034, lo: 0xa6, hi: 0xa6},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	{value: 0x0014, lo: 0xa8, hi: 0xa9},
+	{value: 0x0010, lo: 0xaa, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xae},
+	{value: 0x0014, lo: 0xaf, hi: 0xb1},
+	{value: 0x0030, lo: 0xb2, hi: 0xb3},
+	// Block 0x56, offset 0x266
+	{value: 0x0010, lo: 0x80, hi: 0xab},
+	{value: 0x0014, lo: 0xac, hi: 0xb3},
+	{value: 0x0010, lo: 0xb4, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xb6},
+	{value: 0x0034, lo: 0xb7, hi: 0xb7},
+	// Block 0x57, offset 0x26b
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8d, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xbd},
+	// Block 0x58, offset 0x26e
+	{value: 0x32ea, lo: 0x80, hi: 0x80},
+	{value: 0x336a, lo: 0x81, hi: 0x81},
+	{value: 0x33ea, lo: 0x82, hi: 0x82},
+	{value: 0x346a, lo: 0x83, hi: 0x83},
+	{value: 0x34ea, lo: 0x84, hi: 0x84},
+	{value: 0x356a, lo: 0x85, hi: 0x85},
+	{value: 0x35ea, lo: 0x86, hi: 0x86},
+	{value: 0x366a, lo: 0x87, hi: 0x87},
+	{value: 0x36ea, lo: 0x88, hi: 0x88},
+	{value: 0x0316, lo: 0x89, hi: 0x8a},
+	{value: 0x8353, lo: 0x90, hi: 0xba},
+	{value: 0x8353, lo: 0xbd, hi: 0xbf},
+	// Block 0x59, offset 0x27a
+	{value: 0x0024, lo: 0x90, hi: 0x92},
+	{value: 0x0034, lo: 0x94, hi: 0x99},
+	{value: 0x0024, lo: 0x9a, hi: 0x9b},
+	{value: 0x0034, lo: 0x9c, hi: 0x9f},
+	{value: 0x0024, lo: 0xa0, hi: 0xa0},
+	{value: 0x0010, lo: 0xa1, hi: 0xa1},
+	{value: 0x0034, lo: 0xa2, hi: 0xa8},
+	{value: 0x0010, lo: 0xa9, hi: 0xac},
+	{value: 0x0034, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xb3},
+	{value: 0x0024, lo: 0xb4, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb7},
+	{value: 0x0024, lo: 0xb8, hi: 0xb9},
+	{value: 0x0010, lo: 0xba, hi: 0xba},
+	// Block 0x5a, offset 0x288
+	{value: 0x0012, lo: 0x80, hi: 0xab},
+	{value: 0x0015, lo: 0xac, hi: 0xbf},
+	// Block 0x5b, offset 0x28a
+	{value: 0x0015, lo: 0x80, hi: 0xaa},
+	{value: 0x0012, lo: 0xab, hi: 0xb7},
+	{value: 0x0015, lo: 0xb8, hi: 0xb8},
+	{value: 0x8752, lo: 0xb9, hi: 0xb9},
+	{value: 0x0012, lo: 0xba, hi: 0xbc},
+	{value: 0x8b52, lo: 0xbd, hi: 0xbd},
+	{value: 0x0012, lo: 0xbe, hi: 0xbf},
+	// Block 0x5c, offset 0x291
+	{value: 0x0012, lo: 0x80, hi: 0x8d},
+	{value: 0x8f52, lo: 0x8e, hi: 0x8e},
+	{value: 0x0012, lo: 0x8f, hi: 0x9a},
+	{value: 0x0015, lo: 0x9b, hi: 0xbf},
+	// Block 0x5d, offset 0x295
+	{value: 0x0024, lo: 0x80, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0024, lo: 0x83, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0024, lo: 0x8b, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x90},
+	{value: 0x0024, lo: 0x91, hi: 0xb5},
+	{value: 0x0034, lo: 0xb6, hi: 0xba},
+	{value: 0x0024, lo: 0xbb, hi: 0xbb},
+	{value: 0x0034, lo: 0xbc, hi: 0xbd},
+	{value: 0x0024, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0x5e, offset 0x2a1
+	{value: 0x0117, lo: 0x80, hi: 0xbf},
+	// Block 0x5f, offset 0x2a2
+	{value: 0x0117, lo: 0x80, hi: 0x95},
+	{value: 0x379a, lo: 0x96, hi: 0x96},
+	{value: 0x384a, lo: 0x97, hi: 0x97},
+	{value: 0x38fa, lo: 0x98, hi: 0x98},
+	{value: 0x39aa, lo: 0x99, hi: 0x99},
+	{value: 0x3a5a, lo: 0x9a, hi: 0x9a},
+	{value: 0x3b0a, lo: 0x9b, hi: 0x9b},
+	{value: 0x0012, lo: 0x9c, hi: 0x9d},
+	{value: 0x3bbb, lo: 0x9e, hi: 0x9e},
+	{value: 0x0012, lo: 0x9f, hi: 0x9f},
+	{value: 0x0117, lo: 0xa0, hi: 0xbf},
+	// Block 0x60, offset 0x2ad
+	{value: 0x0812, lo: 0x80, hi: 0x87},
+	{value: 0x0813, lo: 0x88, hi: 0x8f},
+	{value: 0x0812, lo: 0x90, hi: 0x95},
+	{value: 0x0813, lo: 0x98, hi: 0x9d},
+	{value: 0x0812, lo: 0xa0, hi: 0xa7},
+	{value: 0x0813, lo: 0xa8, hi: 0xaf},
+	{value: 0x0812, lo: 0xb0, hi: 0xb7},
+	{value: 0x0813, lo: 0xb8, hi: 0xbf},
+	// Block 0x61, offset 0x2b5
+	{value: 0x0004, lo: 0x8b, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8f},
+	{value: 0x0054, lo: 0x98, hi: 0x99},
+	{value: 0x0054, lo: 0xa4, hi: 0xa4},
+	{value: 0x0054, lo: 0xa7, hi: 0xa7},
+	{value: 0x0014, lo: 0xaa, hi: 0xae},
+	{value: 0x0010, lo: 0xaf, hi: 0xaf},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x62, offset 0x2bd
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x94, hi: 0x94},
+	{value: 0x0014, lo: 0xa0, hi: 0xa4},
+	{value: 0x0014, lo: 0xa6, hi: 0xaf},
+	{value: 0x0015, lo: 0xb1, hi: 0xb1},
+	{value: 0x0015, lo: 0xbf, hi: 0xbf},
+	// Block 0x63, offset 0x2c3
+	{value: 0x0015, lo: 0x90, hi: 0x9c},
+	// Block 0x64, offset 0x2c4
+	{value: 0x0024, lo: 0x90, hi: 0x91},
+	{value: 0x0034, lo: 0x92, hi: 0x93},
+	{value: 0x0024, lo: 0x94, hi: 0x97},
+	{value: 0x0034, lo: 0x98, hi: 0x9a},
+	{value: 0x0024, lo: 0x9b, hi: 0x9c},
+	{value: 0x0014, lo: 0x9d, hi: 0xa0},
+	{value: 0x0024, lo: 0xa1, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa4},
+	{value: 0x0034, lo: 0xa5, hi: 0xa6},
+	{value: 0x0024, lo: 0xa7, hi: 0xa7},
+	{value: 0x0034, lo: 0xa8, hi: 0xa8},
+	{value: 0x0024, lo: 0xa9, hi: 0xa9},
+	{value: 0x0034, lo: 0xaa, hi: 0xaf},
+	{value: 0x0024, lo: 0xb0, hi: 0xb0},
+	// Block 0x65, offset 0x2d2
+	{value: 0x0016, lo: 0x85, hi: 0x86},
+	{value: 0x0012, lo: 0x87, hi: 0x89},
+	{value: 0xa452, lo: 0x8e, hi: 0x8e},
+	{value: 0x1013, lo: 0xa0, hi: 0xaf},
+	{value: 0x1012, lo: 0xb0, hi: 0xbf},
+	// Block 0x66, offset 0x2d7
+	{value: 0x0010, lo: 0x80, hi: 0x82},
+	{value: 0x0716, lo: 0x83, hi: 0x84},
+	{value: 0x0010, lo: 0x85, hi: 0x88},
+	// Block 0x67, offset 0x2da
+	{value: 0xa753, lo: 0xb6, hi: 0xb7},
+	{value: 0xaa53, lo: 0xb8, hi: 0xb9},
+	{value: 0xad53, lo: 0xba, hi: 0xbb},
+	{value: 0xaa53, lo: 0xbc, hi: 0xbd},
+	{value: 0xa753, lo: 0xbe, hi: 0xbf},
+	// Block 0x68, offset 0x2df
+	{value: 0x3013, lo: 0x80, hi: 0x8f},
+	{value: 0x6553, lo: 0x90, hi: 0x9f},
+	{value: 0xb053, lo: 0xa0, hi: 0xaf},
+	{value: 0x3012, lo: 0xb0, hi: 0xbf},
+	// Block 0x69, offset 0x2e3
+	{value: 0x0117, lo: 0x80, hi: 0xa3},
+	{value: 0x0012, lo: 0xa4, hi: 0xa4},
+	{value: 0x0716, lo: 0xab, hi: 0xac},
+	{value: 0x0316, lo: 0xad, hi: 0xae},
+	{value: 0x0024, lo: 0xaf, hi: 0xb1},
+	{value: 0x0117, lo: 0xb2, hi: 0xb3},
+	// Block 0x6a, offset 0x2e9
+	{value: 0x6c52, lo: 0x80, hi: 0x9f},
+	{value: 0x7052, lo: 0xa0, hi: 0xa5},
+	{value: 0x7052, lo: 0xa7, hi: 0xa7},
+	{value: 0x7052, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x6b, offset 0x2ee
+	{value: 0x0010, lo: 0x80, hi: 0xa7},
+	{value: 0x0014, lo: 0xaf, hi: 0xaf},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0x6c, offset 0x2f1
+	{value: 0x0010, lo: 0x80, hi: 0x96},
+	{value: 0x0010, lo: 0xa0, hi: 0xa6},
+	{value: 0x0010, lo: 0xa8, hi: 0xae},
+	{value: 0x0010, lo: 0xb0, hi: 0xb6},
+	{value: 0x0010, lo: 0xb8, hi: 0xbe},
+	// Block 0x6d, offset 0x2f6
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x88, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0x9e},
+	{value: 0x0024, lo: 0xa0, hi: 0xbf},
+	// Block 0x6e, offset 0x2fb
+	{value: 0x0014, lo: 0xaf, hi: 0xaf},
+	// Block 0x6f, offset 0x2fc
+	{value: 0x0014, lo: 0x85, hi: 0x85},
+	{value: 0x0034, lo: 0xaa, hi: 0xad},
+	{value: 0x0030, lo: 0xae, hi: 0xaf},
+	{value: 0x0004, lo: 0xb1, hi: 0xb5},
+	{value: 0x0014, lo: 0xbb, hi: 0xbb},
+	{value: 0x0010, lo: 0xbc, hi: 0xbc},
+	// Block 0x70, offset 0x302
+	{value: 0x0034, lo: 0x99, hi: 0x9a},
+	{value: 0x0004, lo: 0x9b, hi: 0x9e},
+	// Block 0x71, offset 0x304
+	{value: 0x0004, lo: 0xbc, hi: 0xbe},
+	// Block 0x72, offset 0x305
+	{value: 0x0010, lo: 0x85, hi: 0xaf},
+	{value: 0x0010, lo: 0xb1, hi: 0xbf},
+	// Block 0x73, offset 0x307
+	{value: 0x0010, lo: 0x80, hi: 0x8e},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x74, offset 0x309
+	{value: 0x0010, lo: 0x80, hi: 0x94},
+	{value: 0x0014, lo: 0x95, hi: 0x95},
+	{value: 0x0010, lo: 0x96, hi: 0xbf},
+	// Block 0x75, offset 0x30c
+	{value: 0x0010, lo: 0x80, hi: 0x8c},
+	// Block 0x76, offset 0x30d
+	{value: 0x0010, lo: 0x90, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xbd},
+	// Block 0x77, offset 0x30f
+	{value: 0x0010, lo: 0x80, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8c},
+	{value: 0x0010, lo: 0x90, hi: 0xab},
+	// Block 0x78, offset 0x312
+	{value: 0x0117, lo: 0x80, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xae},
+	{value: 0x0024, lo: 0xaf, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xb2},
+	{value: 0x0024, lo: 0xb4, hi: 0xbd},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x79, offset 0x318
+	{value: 0x0117, lo: 0x80, hi: 0x9b},
+	{value: 0x0015, lo: 0x9c, hi: 0x9d},
+	{value: 0x0024, lo: 0x9e, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x7a, offset 0x31c
+	{value: 0x0010, lo: 0x80, hi: 0xaf},
+	{value: 0x0024, lo: 0xb0, hi: 0xb1},
+	// Block 0x7b, offset 0x31e
+	{value: 0x0004, lo: 0x80, hi: 0x87},
+	{value: 0x0014, lo: 0x88, hi: 0xa1},
+	{value: 0x0117, lo: 0xa2, hi: 0xaf},
+	{value: 0x0012, lo: 0xb0, hi: 0xb1},
+	{value: 0x0117, lo: 0xb2, hi: 0xbf},
+	// Block 0x7c, offset 0x323
+	{value: 0x0117, lo: 0x80, hi: 0xaf},
+	{value: 0x0015, lo: 0xb0, hi: 0xb0},
+	{value: 0x0012, lo: 0xb1, hi: 0xb8},
+	{value: 0x0316, lo: 0xb9, hi: 0xba},
+	{value: 0x0716, lo: 0xbb, hi: 0xbc},
+	{value: 0x8753, lo: 0xbd, hi: 0xbd},
+	{value: 0x0117, lo: 0xbe, hi: 0xbf},
+	// Block 0x7d, offset 0x32a
+	{value: 0x0117, lo: 0x80, hi: 0x83},
+	{value: 0x6553, lo: 0x84, hi: 0x84},
+	{value: 0x918b, lo: 0x85, hi: 0x85},
+	{value: 0x8f53, lo: 0x86, hi: 0x86},
+	{value: 0x0f16, lo: 0x87, hi: 0x88},
+	{value: 0x0316, lo: 0x89, hi: 0x8a},
+	{value: 0x91eb, lo: 0x8b, hi: 0x8b},
+	{value: 0x0117, lo: 0x8c, hi: 0x9b},
+	{value: 0x924b, lo: 0x9c, hi: 0x9c},
+	{value: 0x0015, lo: 0xb1, hi: 0xb4},
+	{value: 0x0316, lo: 0xb5, hi: 0xb6},
+	{value: 0x0010, lo: 0xb7, hi: 0xb7},
+	{value: 0x0015, lo: 0xb8, hi: 0xb9},
+	{value: 0x0012, lo: 0xba, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbf},
+	// Block 0x7e, offset 0x339
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x8a},
+	{value: 0x0014, lo: 0x8b, hi: 0x8b},
+	{value: 0x0010, lo: 0x8c, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xa6},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	{value: 0x0034, lo: 0xac, hi: 0xac},
+	// Block 0x7f, offset 0x343
+	{value: 0x0010, lo: 0x80, hi: 0xb3},
+	// Block 0x80, offset 0x344
+	{value: 0x0010, lo: 0x80, hi: 0x83},
+	{value: 0x0034, lo: 0x84, hi: 0x84},
+	{value: 0x0014, lo: 0x85, hi: 0x85},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0024, lo: 0xa0, hi: 0xb1},
+	{value: 0x0010, lo: 0xb2, hi: 0xb7},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	{value: 0x0010, lo: 0xbd, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x81, offset 0x34d
+	{value: 0x0010, lo: 0x80, hi: 0xa5},
+	{value: 0x0014, lo: 0xa6, hi: 0xaa},
+	{value: 0x0034, lo: 0xab, hi: 0xad},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x82, offset 0x351
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0014, lo: 0x87, hi: 0x91},
+	{value: 0x0010, lo: 0x92, hi: 0x92},
+	{value: 0x0030, lo: 0x93, hi: 0x93},
+	{value: 0x0010, lo: 0xa0, hi: 0xbc},
+	// Block 0x83, offset 0x356
+	{value: 0x0014, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0xb2},
+	{value: 0x0034, lo: 0xb3, hi: 0xb3},
+	{value: 0x0010, lo: 0xb4, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xb9},
+	{value: 0x0010, lo: 0xba, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0x84, offset 0x35e
+	{value: 0x0030, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0014, lo: 0xa5, hi: 0xa5},
+	{value: 0x0004, lo: 0xa6, hi: 0xa6},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x85, offset 0x364
+	{value: 0x0010, lo: 0x80, hi: 0xa8},
+	{value: 0x0014, lo: 0xa9, hi: 0xae},
+	{value: 0x0010, lo: 0xaf, hi: 0xb0},
+	{value: 0x0014, lo: 0xb1, hi: 0xb2},
+	{value: 0x0010, lo: 0xb3, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb6},
+	// Block 0x86, offset 0x36a
+	{value: 0x0010, lo: 0x80, hi: 0x82},
+	{value: 0x0014, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x84, hi: 0x8b},
+	{value: 0x0014, lo: 0x8c, hi: 0x8c},
+	{value: 0x0010, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0004, lo: 0xb0, hi: 0xb0},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbd},
+	// Block 0x87, offset 0x374
+	{value: 0x0024, lo: 0xb0, hi: 0xb0},
+	{value: 0x0024, lo: 0xb2, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0024, lo: 0xb7, hi: 0xb8},
+	{value: 0x0024, lo: 0xbe, hi: 0xbf},
+	// Block 0x88, offset 0x379
+	{value: 0x0024, lo: 0x81, hi: 0x81},
+	{value: 0x0004, lo: 0x9d, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xab},
+	{value: 0x0014, lo: 0xac, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xaf},
+	{value: 0x0010, lo: 0xb2, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb5},
+	{value: 0x0034, lo: 0xb6, hi: 0xb6},
+	// Block 0x89, offset 0x382
+	{value: 0x0010, lo: 0x81, hi: 0x86},
+	{value: 0x0010, lo: 0x89, hi: 0x8e},
+	{value: 0x0010, lo: 0x91, hi: 0x96},
+	{value: 0x0010, lo: 0xa0, hi: 0xa6},
+	{value: 0x0010, lo: 0xa8, hi: 0xae},
+	{value: 0x0012, lo: 0xb0, hi: 0xbf},
+	// Block 0x8a, offset 0x388
+	{value: 0x0012, lo: 0x80, hi: 0x92},
+	{value: 0xb352, lo: 0x93, hi: 0x93},
+	{value: 0x0012, lo: 0x94, hi: 0x9a},
+	{value: 0x0014, lo: 0x9b, hi: 0x9b},
+	{value: 0x0015, lo: 0x9c, hi: 0x9f},
+	{value: 0x0012, lo: 0xa0, hi: 0xa8},
+	{value: 0x0015, lo: 0xa9, hi: 0xa9},
+	{value: 0x0004, lo: 0xaa, hi: 0xab},
+	{value: 0x74d2, lo: 0xb0, hi: 0xbf},
+	// Block 0x8b, offset 0x391
+	{value: 0x78d2, lo: 0x80, hi: 0x8f},
+	{value: 0x7cd2, lo: 0x90, hi: 0x9f},
+	{value: 0x80d2, lo: 0xa0, hi: 0xaf},
+	{value: 0x7cd2, lo: 0xb0, hi: 0xbf},
+	// Block 0x8c, offset 0x395
+	{value: 0x0010, lo: 0x80, hi: 0xa4},
+	{value: 0x0014, lo: 0xa5, hi: 0xa5},
+	{value: 0x0010, lo: 0xa6, hi: 0xa7},
+	{value: 0x0014, lo: 0xa8, hi: 0xa8},
+	{value: 0x0010, lo: 0xa9, hi: 0xaa},
+	{value: 0x0010, lo: 0xac, hi: 0xac},
+	{value: 0x0034, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x8d, offset 0x39d
+	{value: 0x0010, lo: 0x80, hi: 0xa3},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x8e, offset 0x39f
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x8b, hi: 0xbb},
+	// Block 0x8f, offset 0x3a1
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x83, hi: 0x84},
+	{value: 0x0010, lo: 0x86, hi: 0xbf},
+	// Block 0x90, offset 0x3a4
+	{value: 0x0010, lo: 0x80, hi: 0xb1},
+	{value: 0x0004, lo: 0xb2, hi: 0xbf},
+	// Block 0x91, offset 0x3a6
+	{value: 0x0004, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x93, hi: 0xbf},
+	// Block 0x92, offset 0x3a8
+	{value: 0x0010, lo: 0x80, hi: 0xbd},
+	// Block 0x93, offset 0x3a9
+	{value: 0x0010, lo: 0x90, hi: 0xbf},
+	// Block 0x94, offset 0x3aa
+	{value: 0x0010, lo: 0x80, hi: 0x8f},
+	{value: 0x0010, lo: 0x92, hi: 0xbf},
+	// Block 0x95, offset 0x3ac
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0010, lo: 0xb0, hi: 0xbb},
+	// Block 0x96, offset 0x3ae
+	{value: 0x0014, lo: 0x80, hi: 0x8f},
+	{value: 0x0054, lo: 0x93, hi: 0x93},
+	{value: 0x0024, lo: 0xa0, hi: 0xa6},
+	{value: 0x0034, lo: 0xa7, hi: 0xad},
+	{value: 0x0024, lo: 0xae, hi: 0xaf},
+	{value: 0x0010, lo: 0xb3, hi: 0xb4},
+	// Block 0x97, offset 0x3b4
+	{value: 0x0010, lo: 0x8d, hi: 0x8f},
+	{value: 0x0054, lo: 0x92, hi: 0x92},
+	{value: 0x0054, lo: 0x95, hi: 0x95},
+	{value: 0x0010, lo: 0xb0, hi: 0xb4},
+	{value: 0x0010, lo: 0xb6, hi: 0xbf},
+	// Block 0x98, offset 0x3b9
+	{value: 0x0010, lo: 0x80, hi: 0xbc},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x99, offset 0x3bb
+	{value: 0x0054, lo: 0x87, hi: 0x87},
+	{value: 0x0054, lo: 0x8e, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0054, lo: 0x9a, hi: 0x9a},
+	{value: 0x5f53, lo: 0xa1, hi: 0xba},
+	{value: 0x0004, lo: 0xbe, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x9a, offset 0x3c2
+	{value: 0x0004, lo: 0x80, hi: 0x80},
+	{value: 0x5f52, lo: 0x81, hi: 0x9a},
+	{value: 0x0004, lo: 0xb0, hi: 0xb0},
+	// Block 0x9b, offset 0x3c5
+	{value: 0x0014, lo: 0x9e, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xbe},
+	// Block 0x9c, offset 0x3c7
+	{value: 0x0010, lo: 0x82, hi: 0x87},
+	{value: 0x0010, lo: 0x8a, hi: 0x8f},
+	{value: 0x0010, lo: 0x92, hi: 0x97},
+	{value: 0x0010, lo: 0x9a, hi: 0x9c},
+	{value: 0x0004, lo: 0xa3, hi: 0xa3},
+	{value: 0x0014, lo: 0xb9, hi: 0xbb},
+	// Block 0x9d, offset 0x3cd
+	{value: 0x0010, lo: 0x80, hi: 0x8b},
+	{value: 0x0010, lo: 0x8d, hi: 0xa6},
+	{value: 0x0010, lo: 0xa8, hi: 0xba},
+	{value: 0x0010, lo: 0xbc, hi: 0xbd},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0x9e, offset 0x3d2
+	{value: 0x0010, lo: 0x80, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x9d},
+	// Block 0x9f, offset 0x3d4
+	{value: 0x0010, lo: 0x80, hi: 0xba},
+	// Block 0xa0, offset 0x3d5
+	{value: 0x0010, lo: 0x80, hi: 0xb4},
+	// Block 0xa1, offset 0x3d6
+	{value: 0x0034, lo: 0xbd, hi: 0xbd},
+	// Block 0xa2, offset 0x3d7
+	{value: 0x0010, lo: 0x80, hi: 0x9c},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0xa3, offset 0x3d9
+	{value: 0x0010, lo: 0x80, hi: 0x90},
+	{value: 0x0034, lo: 0xa0, hi: 0xa0},
+	// Block 0xa4, offset 0x3db
+	{value: 0x0010, lo: 0x80, hi: 0x9f},
+	{value: 0x0010, lo: 0xad, hi: 0xbf},
+	// Block 0xa5, offset 0x3dd
+	{value: 0x0010, lo: 0x80, hi: 0x8a},
+	{value: 0x0010, lo: 0x90, hi: 0xb5},
+	{value: 0x0024, lo: 0xb6, hi: 0xba},
+	// Block 0xa6, offset 0x3e0
+	{value: 0x0010, lo: 0x80, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0xa7, offset 0x3e2
+	{value: 0x0010, lo: 0x80, hi: 0x83},
+	{value: 0x0010, lo: 0x88, hi: 0x8f},
+	{value: 0x0010, lo: 0x91, hi: 0x95},
+	// Block 0xa8, offset 0x3e5
+	{value: 0x2813, lo: 0x80, hi: 0x87},
+	{value: 0x3813, lo: 0x88, hi: 0x8f},
+	{value: 0x2813, lo: 0x90, hi: 0x97},
+	{value: 0xb653, lo: 0x98, hi: 0x9f},
+	{value: 0xb953, lo: 0xa0, hi: 0xa7},
+	{value: 0x2812, lo: 0xa8, hi: 0xaf},
+	{value: 0x3812, lo: 0xb0, hi: 0xb7},
+	{value: 0x2812, lo: 0xb8, hi: 0xbf},
+	// Block 0xa9, offset 0x3ed
+	{value: 0xb652, lo: 0x80, hi: 0x87},
+	{value: 0xb952, lo: 0x88, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0xbf},
+	// Block 0xaa, offset 0x3f0
+	{value: 0x0010, lo: 0x80, hi: 0x9d},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0xb953, lo: 0xb0, hi: 0xb7},
+	{value: 0xb653, lo: 0xb8, hi: 0xbf},
+	// Block 0xab, offset 0x3f4
+	{value: 0x2813, lo: 0x80, hi: 0x87},
+	{value: 0x3813, lo: 0x88, hi: 0x8f},
+	{value: 0x2813, lo: 0x90, hi: 0x93},
+	{value: 0xb952, lo: 0x98, hi: 0x9f},
+	{value: 0xb652, lo: 0xa0, hi: 0xa7},
+	{value: 0x2812, lo: 0xa8, hi: 0xaf},
+	{value: 0x3812, lo: 0xb0, hi: 0xb7},
+	{value: 0x2812, lo: 0xb8, hi: 0xbb},
+	// Block 0xac, offset 0x3fc
+	{value: 0x0010, lo: 0x80, hi: 0xa7},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xad, offset 0x3fe
+	{value: 0x0010, lo: 0x80, hi: 0xa3},
+	{value: 0xbc53, lo: 0xb0, hi: 0xb0},
+	{value: 0xbf53, lo: 0xb1, hi: 0xb1},
+	{value: 0xc253, lo: 0xb2, hi: 0xb2},
+	{value: 0xbf53, lo: 0xb3, hi: 0xb3},
+	{value: 0xc553, lo: 0xb4, hi: 0xb4},
+	{value: 0xbf53, lo: 0xb5, hi: 0xb5},
+	{value: 0xc253, lo: 0xb6, hi: 0xb6},
+	{value: 0xbf53, lo: 0xb7, hi: 0xb7},
+	{value: 0xbc53, lo: 0xb8, hi: 0xb8},
+	{value: 0xc853, lo: 0xb9, hi: 0xb9},
+	{value: 0xcb53, lo: 0xba, hi: 0xba},
+	{value: 0xce53, lo: 0xbc, hi: 0xbc},
+	{value: 0xc853, lo: 0xbd, hi: 0xbd},
+	{value: 0xcb53, lo: 0xbe, hi: 0xbe},
+	{value: 0xc853, lo: 0xbf, hi: 0xbf},
+	// Block 0xae, offset 0x40e
+	{value: 0x0010, lo: 0x80, hi: 0xb6},
+	// Block 0xaf, offset 0x40f
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xa7},
+	// Block 0xb0, offset 0x411
+	{value: 0x0015, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x82},
+	{value: 0x0015, lo: 0x83, hi: 0x85},
+	{value: 0x0015, lo: 0x87, hi: 0xb0},
+	{value: 0x0015, lo: 0xb2, hi: 0xba},
+	// Block 0xb1, offset 0x416
+	{value: 0x0010, lo: 0x80, hi: 0x85},
+	{value: 0x0010, lo: 0x88, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0xb5},
+	{value: 0x0010, lo: 0xb7, hi: 0xb8},
+	{value: 0x0010, lo: 0xbc, hi: 0xbc},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xb2, offset 0x41c
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xb6},
+	// Block 0xb3, offset 0x41e
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	// Block 0xb4, offset 0x41f
+	{value: 0x0010, lo: 0xa0, hi: 0xb2},
+	{value: 0x0010, lo: 0xb4, hi: 0xb5},
+	// Block 0xb5, offset 0x421
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xb9},
+	// Block 0xb6, offset 0x423
+	{value: 0x0010, lo: 0x80, hi: 0x99},
+	// Block 0xb7, offset 0x424
+	{value: 0x0010, lo: 0x80, hi: 0xb7},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0xb8, offset 0x426
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x83},
+	{value: 0x0014, lo: 0x85, hi: 0x86},
+	{value: 0x0014, lo: 0x8c, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x8d},
+	{value: 0x0014, lo: 0x8e, hi: 0x8e},
+	{value: 0x0024, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x93},
+	{value: 0x0010, lo: 0x95, hi: 0x97},
+	{value: 0x0010, lo: 0x99, hi: 0xb5},
+	{value: 0x0024, lo: 0xb8, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xba},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xb9, offset 0x433
+	{value: 0x0010, lo: 0xa0, hi: 0xbc},
+	// Block 0xba, offset 0x434
+	{value: 0x0010, lo: 0x80, hi: 0x9c},
+	// Block 0xbb, offset 0x435
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0010, lo: 0x89, hi: 0xa4},
+	{value: 0x0024, lo: 0xa5, hi: 0xa5},
+	{value: 0x0034, lo: 0xa6, hi: 0xa6},
+	// Block 0xbc, offset 0x439
+	{value: 0x0010, lo: 0x80, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xb2},
+	// Block 0xbd, offset 0x43b
+	{value: 0x0010, lo: 0x80, hi: 0x91},
+	// Block 0xbe, offset 0x43c
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	// Block 0xbf, offset 0x43d
+	{value: 0x5653, lo: 0x80, hi: 0xb2},
+	// Block 0xc0, offset 0x43e
+	{value: 0x5652, lo: 0x80, hi: 0xb2},
+	// Block 0xc1, offset 0x43f
+	{value: 0x0010, lo: 0x80, hi: 0xa3},
+	{value: 0x0024, lo: 0xa4, hi: 0xa7},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xc2, offset 0x442
+	{value: 0x0010, lo: 0x80, hi: 0x8d},
+	{value: 0x0014, lo: 0x8e, hi: 0x8e},
+	{value: 0x0010, lo: 0x8f, hi: 0x8f},
+	{value: 0x2013, lo: 0x90, hi: 0x9f},
+	{value: 0xd153, lo: 0xa0, hi: 0xa5},
+	{value: 0x0024, lo: 0xa9, hi: 0xad},
+	{value: 0x0014, lo: 0xaf, hi: 0xaf},
+	{value: 0x2012, lo: 0xb0, hi: 0xbf},
+	// Block 0xc3, offset 0x44a
+	{value: 0xd152, lo: 0x80, hi: 0x85},
+	// Block 0xc4, offset 0x44b
+	{value: 0x0010, lo: 0x80, hi: 0xa9},
+	{value: 0x0024, lo: 0xab, hi: 0xac},
+	{value: 0x0010, lo: 0xb0, hi: 0xb1},
+	// Block 0xc5, offset 0x44e
+	{value: 0x0010, lo: 0x82, hi: 0x84},
+	{value: 0x0014, lo: 0x85, hi: 0x85},
+	{value: 0x0010, lo: 0x86, hi: 0x87},
+	{value: 0x0034, lo: 0xba, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbc},
+	{value: 0x0034, lo: 0xbd, hi: 0xbf},
+	// Block 0xc6, offset 0x454
+	{value: 0x0010, lo: 0x80, hi: 0x9c},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xc7, offset 0x457
+	{value: 0x0010, lo: 0x80, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x87},
+	{value: 0x0024, lo: 0x88, hi: 0x8a},
+	{value: 0x0034, lo: 0x8b, hi: 0x8b},
+	{value: 0x0024, lo: 0x8c, hi: 0x8c},
+	{value: 0x0034, lo: 0x8d, hi: 0x90},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xc8, offset 0x45e
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0024, lo: 0x82, hi: 0x82},
+	{value: 0x0034, lo: 0x83, hi: 0x83},
+	{value: 0x0024, lo: 0x84, hi: 0x84},
+	{value: 0x0034, lo: 0x85, hi: 0x85},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xc9, offset 0x464
+	{value: 0x0010, lo: 0x80, hi: 0x84},
+	{value: 0x0010, lo: 0xa0, hi: 0xb6},
+	// Block 0xca, offset 0x466
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xbf},
+	// Block 0xcb, offset 0x46a
+	{value: 0x0014, lo: 0x80, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0xa6, hi: 0xaf},
+	{value: 0x0034, lo: 0xb0, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb5},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xcc, offset 0x472
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb6},
+	{value: 0x0010, lo: 0xb7, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xba},
+	{value: 0x0014, lo: 0xbd, hi: 0xbd},
+	// Block 0xcd, offset 0x478
+	{value: 0x0014, lo: 0x82, hi: 0x82},
+	{value: 0x0014, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0xa8},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xce, offset 0x47c
+	{value: 0x0024, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0xa6},
+	{value: 0x0014, lo: 0xa7, hi: 0xab},
+	{value: 0x0010, lo: 0xac, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xb2},
+	{value: 0x0034, lo: 0xb3, hi: 0xb4},
+	{value: 0x0010, lo: 0xb6, hi: 0xbf},
+	// Block 0xcf, offset 0x483
+	{value: 0x0010, lo: 0x84, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0xb2},
+	{value: 0x0034, lo: 0xb3, hi: 0xb3},
+	{value: 0x0010, lo: 0xb6, hi: 0xb6},
+	// Block 0xd0, offset 0x487
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xd1, offset 0x48b
+	{value: 0x0030, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x84},
+	{value: 0x0014, lo: 0x89, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0014, lo: 0x8b, hi: 0x8c},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	{value: 0x0014, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0x9a},
+	{value: 0x0010, lo: 0x9c, hi: 0x9c},
+	// Block 0xd2, offset 0x494
+	{value: 0x0010, lo: 0x80, hi: 0x91},
+	{value: 0x0010, lo: 0x93, hi: 0xae},
+	{value: 0x0014, lo: 0xaf, hi: 0xb1},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0014, lo: 0xb4, hi: 0xb4},
+	{value: 0x0030, lo: 0xb5, hi: 0xb5},
+	{value: 0x0034, lo: 0xb6, hi: 0xb6},
+	{value: 0x0014, lo: 0xb7, hi: 0xb7},
+	{value: 0x0014, lo: 0xbe, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xd3, offset 0x49e
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	// Block 0xd4, offset 0x4a0
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x88, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0x8d},
+	{value: 0x0010, lo: 0x8f, hi: 0x9d},
+	{value: 0x0010, lo: 0x9f, hi: 0xa8},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xd5, offset 0x4a6
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	{value: 0x0014, lo: 0x9f, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xa2},
+	{value: 0x0014, lo: 0xa3, hi: 0xa8},
+	{value: 0x0034, lo: 0xa9, hi: 0xaa},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xd6, offset 0x4ac
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x8c},
+	{value: 0x0010, lo: 0x8f, hi: 0x90},
+	{value: 0x0010, lo: 0x93, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb5, hi: 0xb9},
+	{value: 0x0034, lo: 0xbb, hi: 0xbc},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0xd7, offset 0x4b6
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x84},
+	{value: 0x0010, lo: 0x87, hi: 0x88},
+	{value: 0x0010, lo: 0x8b, hi: 0x8c},
+	{value: 0x0030, lo: 0x8d, hi: 0x8d},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0x9d, hi: 0xa3},
+	{value: 0x0024, lo: 0xa6, hi: 0xac},
+	{value: 0x0024, lo: 0xb0, hi: 0xb4},
+	// Block 0xd8, offset 0x4c0
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8b, hi: 0x8b},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	{value: 0x0010, lo: 0x90, hi: 0xb5},
+	{value: 0x0010, lo: 0xb7, hi: 0xba},
+	{value: 0x0014, lo: 0xbb, hi: 0xbf},
+	// Block 0xd9, offset 0x4c6
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x85, hi: 0x85},
+	{value: 0x0010, lo: 0x87, hi: 0x8a},
+	{value: 0x0010, lo: 0x8c, hi: 0x8d},
+	{value: 0x0034, lo: 0x8e, hi: 0x8e},
+	{value: 0x0030, lo: 0x8f, hi: 0x8f},
+	{value: 0x0034, lo: 0x90, hi: 0x90},
+	{value: 0x0010, lo: 0x91, hi: 0x91},
+	{value: 0x0014, lo: 0x92, hi: 0x92},
+	{value: 0x0010, lo: 0x93, hi: 0x93},
+	{value: 0x0014, lo: 0xa1, hi: 0xa2},
+	// Block 0xda, offset 0x4d2
+	{value: 0x0010, lo: 0x80, hi: 0xb7},
+	{value: 0x0014, lo: 0xb8, hi: 0xbf},
+	// Block 0xdb, offset 0x4d4
+	{value: 0x0010, lo: 0x80, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0014, lo: 0x83, hi: 0x84},
+	{value: 0x0010, lo: 0x85, hi: 0x85},
+	{value: 0x0034, lo: 0x86, hi: 0x86},
+	{value: 0x0010, lo: 0x87, hi: 0x8a},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0024, lo: 0x9e, hi: 0x9e},
+	{value: 0x0010, lo: 0x9f, hi: 0xa1},
+	// Block 0xdc, offset 0x4dd
+	{value: 0x0010, lo: 0x80, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb8},
+	{value: 0x0010, lo: 0xb9, hi: 0xb9},
+	{value: 0x0014, lo: 0xba, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0xdd, offset 0x4e3
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x83},
+	{value: 0x0010, lo: 0x84, hi: 0x85},
+	{value: 0x0010, lo: 0x87, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0xde, offset 0x4e9
+	{value: 0x0010, lo: 0x80, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb5},
+	{value: 0x0010, lo: 0xb8, hi: 0xbb},
+	{value: 0x0014, lo: 0xbc, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xdf, offset 0x4ef
+	{value: 0x0034, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x98, hi: 0x9b},
+	{value: 0x0014, lo: 0x9c, hi: 0x9d},
+	// Block 0xe0, offset 0x4f2
+	{value: 0x0010, lo: 0x80, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xba},
+	{value: 0x0010, lo: 0xbb, hi: 0xbc},
+	{value: 0x0014, lo: 0xbd, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xe1, offset 0x4f8
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x84, hi: 0x84},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0xe2, offset 0x4fb
+	{value: 0x0010, lo: 0x80, hi: 0xaa},
+	{value: 0x0014, lo: 0xab, hi: 0xab},
+	{value: 0x0010, lo: 0xac, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xad},
+	{value: 0x0010, lo: 0xae, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xb5},
+	{value: 0x0030, lo: 0xb6, hi: 0xb6},
+	{value: 0x0034, lo: 0xb7, hi: 0xb7},
+	{value: 0x0010, lo: 0xb8, hi: 0xb8},
+	// Block 0xe3, offset 0x504
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x90, hi: 0xa3},
+	// Block 0xe4, offset 0x506
+	{value: 0x0014, lo: 0x9d, hi: 0x9d},
+	{value: 0x0010, lo: 0x9e, hi: 0x9e},
+	{value: 0x0014, lo: 0x9f, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa5},
+	{value: 0x0010, lo: 0xa6, hi: 0xa6},
+	{value: 0x0014, lo: 0xa7, hi: 0xaa},
+	{value: 0x0034, lo: 0xab, hi: 0xab},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xe5, offset 0x50f
+	{value: 0x0010, lo: 0x80, hi: 0xae},
+	{value: 0x0014, lo: 0xaf, hi: 0xb7},
+	{value: 0x0010, lo: 0xb8, hi: 0xb8},
+	{value: 0x0034, lo: 0xb9, hi: 0xba},
+	// Block 0xe6, offset 0x513
+	{value: 0x5f53, lo: 0xa0, hi: 0xbf},
+	// Block 0xe7, offset 0x514
+	{value: 0x5f52, lo: 0x80, hi: 0x9f},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xe8, offset 0x517
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x89, hi: 0x89},
+	{value: 0x0010, lo: 0x8c, hi: 0x93},
+	{value: 0x0010, lo: 0x95, hi: 0x96},
+	{value: 0x0010, lo: 0x98, hi: 0xb5},
+	{value: 0x0010, lo: 0xb7, hi: 0xb8},
+	{value: 0x0014, lo: 0xbb, hi: 0xbc},
+	{value: 0x0030, lo: 0xbd, hi: 0xbd},
+	{value: 0x0034, lo: 0xbe, hi: 0xbe},
+	{value: 0x0010, lo: 0xbf, hi: 0xbf},
+	// Block 0xe9, offset 0x521
+	{value: 0x0010, lo: 0x80, hi: 0x82},
+	{value: 0x0034, lo: 0x83, hi: 0x83},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0xea, offset 0x524
+	{value: 0x0010, lo: 0xa0, hi: 0xa7},
+	{value: 0x0010, lo: 0xaa, hi: 0xbf},
+	// Block 0xeb, offset 0x526
+	{value: 0x0010, lo: 0x80, hi: 0x93},
+	{value: 0x0014, lo: 0x94, hi: 0x97},
+	{value: 0x0014, lo: 0x9a, hi: 0x9b},
+	{value: 0x0010, lo: 0x9c, hi: 0x9f},
+	{value: 0x0034, lo: 0xa0, hi: 0xa0},
+	{value: 0x0010, lo: 0xa1, hi: 0xa1},
+	{value: 0x0010, lo: 0xa3, hi: 0xa4},
+	// Block 0xec, offset 0x52d
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0014, lo: 0x81, hi: 0x8a},
+	{value: 0x0010, lo: 0x8b, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb3},
+	{value: 0x0034, lo: 0xb4, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb8},
+	{value: 0x0010, lo: 0xb9, hi: 0xba},
+	{value: 0x0014, lo: 0xbb, hi: 0xbe},
+	// Block 0xed, offset 0x535
+	{value: 0x0034, lo: 0x87, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0x90},
+	{value: 0x0014, lo: 0x91, hi: 0x96},
+	{value: 0x0010, lo: 0x97, hi: 0x98},
+	{value: 0x0014, lo: 0x99, hi: 0x9b},
+	{value: 0x0010, lo: 0x9c, hi: 0xbf},
+	// Block 0xee, offset 0x53b
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0014, lo: 0x8a, hi: 0x96},
+	{value: 0x0010, lo: 0x97, hi: 0x97},
+	{value: 0x0014, lo: 0x98, hi: 0x98},
+	{value: 0x0034, lo: 0x99, hi: 0x99},
+	{value: 0x0010, lo: 0x9d, hi: 0x9d},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xef, offset 0x542
+	{value: 0x0010, lo: 0x80, hi: 0xb8},
+	// Block 0xf0, offset 0x543
+	{value: 0x0014, lo: 0xa0, hi: 0xa0},
+	{value: 0x0010, lo: 0xa1, hi: 0xa1},
+	{value: 0x0014, lo: 0xa2, hi: 0xa4},
+	{value: 0x0010, lo: 0xa5, hi: 0xa5},
+	{value: 0x0014, lo: 0xa6, hi: 0xa6},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	// Block 0xf1, offset 0x549
+	{value: 0x0010, lo: 0x80, hi: 0xa0},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0xf2, offset 0x54b
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	{value: 0x0010, lo: 0x8a, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xb6},
+	{value: 0x0014, lo: 0xb8, hi: 0xbd},
+	{value: 0x0010, lo: 0xbe, hi: 0xbe},
+	{value: 0x0034, lo: 0xbf, hi: 0xbf},
+	// Block 0xf3, offset 0x551
+	{value: 0x0010, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0010, lo: 0xb2, hi: 0xbf},
+	// Block 0xf4, offset 0x554
+	{value: 0x0010, lo: 0x80, hi: 0x8f},
+	{value: 0x0014, lo: 0x92, hi: 0xa7},
+	{value: 0x0010, lo: 0xa9, hi: 0xa9},
+	{value: 0x0014, lo: 0xaa, hi: 0xb0},
+	{value: 0x0010, lo: 0xb1, hi: 0xb1},
+	{value: 0x0014, lo: 0xb2, hi: 0xb3},
+	{value: 0x0010, lo: 0xb4, hi: 0xb4},
+	{value: 0x0014, lo: 0xb5, hi: 0xb6},
+	// Block 0xf5, offset 0x55c
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	{value: 0x0010, lo: 0x88, hi: 0x89},
+	{value: 0x0010, lo: 0x8b, hi: 0xb0},
+	{value: 0x0014, lo: 0xb1, hi: 0xb6},
+	{value: 0x0014, lo: 0xba, hi: 0xba},
+	{value: 0x0014, lo: 0xbc, hi: 0xbd},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0xf6, offset 0x563
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0014, lo: 0x83, hi: 0x83},
+	{value: 0x0034, lo: 0x84, hi: 0x85},
+	{value: 0x0010, lo: 0x86, hi: 0x86},
+	{value: 0x0014, lo: 0x87, hi: 0x87},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0010, lo: 0xa0, hi: 0xa5},
+	{value: 0x0010, lo: 0xa7, hi: 0xa8},
+	{value: 0x0010, lo: 0xaa, hi: 0xbf},
+	// Block 0xf7, offset 0x56d
+	{value: 0x0010, lo: 0x80, hi: 0x8e},
+	{value: 0x0014, lo: 0x90, hi: 0x91},
+	{value: 0x0010, lo: 0x93, hi: 0x94},
+	{value: 0x0014, lo: 0x95, hi: 0x95},
+	{value: 0x0010, lo: 0x96, hi: 0x96},
+	{value: 0x0034, lo: 0x97, hi: 0x97},
+	{value: 0x0010, lo: 0x98, hi: 0x98},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0xf8, offset 0x576
+	{value: 0x0010, lo: 0x80, hi: 0x98},
+	{value: 0x0014, lo: 0x99, hi: 0x99},
+	{value: 0x0010, lo: 0x9a, hi: 0x9b},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	// Block 0xf9, offset 0x57a
+	{value: 0x0010, lo: 0xa0, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xb4},
+	{value: 0x0010, lo: 0xb5, hi: 0xb6},
+	// Block 0xfa, offset 0x57d
+	{value: 0x0014, lo: 0x80, hi: 0x81},
+	{value: 0x0010, lo: 0x82, hi: 0x90},
+	{value: 0x0010, lo: 0x92, hi: 0xb5},
+	{value: 0x0014, lo: 0xb6, hi: 0xba},
+	{value: 0x0010, lo: 0xbe, hi: 0xbf},
+	// Block 0xfb, offset 0x582
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0030, lo: 0x81, hi: 0x81},
+	{value: 0x0034, lo: 0x82, hi: 0x82},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0014, lo: 0x9a, hi: 0x9a},
+	// Block 0xfc, offset 0x587
+	{value: 0x0010, lo: 0xb0, hi: 0xb0},
+	// Block 0xfd, offset 0x588
+	{value: 0x0010, lo: 0x80, hi: 0xae},
+	// Block 0xfe, offset 0x589
+	{value: 0x0010, lo: 0x80, hi: 0x83},
+	// Block 0xff, offset 0x58a
+	{value: 0x0010, lo: 0x80, hi: 0xb0},
+	// Block 0x100, offset 0x58b
+	{value: 0x0010, lo: 0x80, hi: 0xaf},
+	{value: 0x0014, lo: 0xb0, hi: 0xbf},
+	// Block 0x101, offset 0x58d
+	{value: 0x0014, lo: 0x80, hi: 0x80},
+	{value: 0x0010, lo: 0x81, hi: 0x86},
+	{value: 0x0014, lo: 0x87, hi: 0x95},
+	{value: 0x0010, lo: 0xa0, hi: 0xbf},
+	// Block 0x102, offset 0x591
+	{value: 0x0010, lo: 0x80, hi: 0x86},
+	// Block 0x103, offset 0x592
+	{value: 0x0010, lo: 0x80, hi: 0x9d},
+	{value: 0x0014, lo: 0x9e, hi: 0xa9},
+	{value: 0x0010, lo: 0xaa, hi: 0xac},
+	{value: 0x0014, lo: 0xad, hi: 0xae},
+	{value: 0x0034, lo: 0xaf, hi: 0xaf},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x104, offset 0x598
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	{value: 0x0010, lo: 0xa0, hi: 0xa9},
+	{value: 0x0010, lo: 0xb0, hi: 0xbf},
+	// Block 0x105, offset 0x59b
+	{value: 0x0010, lo: 0x80, hi: 0xbe},
+	// Block 0x106, offset 0x59c
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x90, hi: 0xad},
+	{value: 0x0034, lo: 0xb0, hi: 0xb4},
+	// Block 0x107, offset 0x59f
+	{value: 0x0010, lo: 0x80, hi: 0xaf},
+	{value: 0x0024, lo: 0xb0, hi: 0xb6},
+	// Block 0x108, offset 0x5a1
+	{value: 0x0014, lo: 0x80, hi: 0x83},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0010, lo: 0xa3, hi: 0xb7},
+	{value: 0x0010, lo: 0xbd, hi: 0xbf},
+	// Block 0x109, offset 0x5a5
+	{value: 0x0010, lo: 0x80, hi: 0x8f},
+	// Block 0x10a, offset 0x5a6
+	{value: 0x0014, lo: 0x80, hi: 0x82},
+	{value: 0x0010, lo: 0x83, hi: 0xaa},
+	{value: 0x0014, lo: 0xab, hi: 0xac},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x10b, offset 0x5aa
+	{value: 0x2013, lo: 0x80, hi: 0x9f},
+	{value: 0x2012, lo: 0xa0, hi: 0xbf},
+	// Block 0x10c, offset 0x5ac
+	{value: 0x0010, lo: 0x80, hi: 0x8a},
+	{value: 0x0014, lo: 0x8f, hi: 0x8f},
+	{value: 0x0010, lo: 0x90, hi: 0xbf},
+	// Block 0x10d, offset 0x5af
+	{value: 0x0010, lo: 0x80, hi: 0x87},
+	{value: 0x0014, lo: 0x8f, hi: 0x9f},
+	// Block 0x10e, offset 0x5b1
+	{value: 0x0014, lo: 0xa0, hi: 0xa1},
+	{value: 0x0014, lo: 0xa3, hi: 0xa4},
+	{value: 0x0030, lo: 0xb0, hi: 0xb1},
+	{value: 0x0004, lo: 0xb2, hi: 0xb3},
+	// Block 0x10f, offset 0x5b5
+	{value: 0x0004, lo: 0xb0, hi: 0xb3},
+	{value: 0x0004, lo: 0xb5, hi: 0xbb},
+	{value: 0x0004, lo: 0xbd, hi: 0xbe},
+	// Block 0x110, offset 0x5b8
+	{value: 0x0010, lo: 0x80, hi: 0xaa},
+	{value: 0x0010, lo: 0xb0, hi: 0xbc},
+	// Block 0x111, offset 0x5ba
+	{value: 0x0010, lo: 0x80, hi: 0x88},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	{value: 0x0014, lo: 0x9d, hi: 0x9d},
+	{value: 0x0034, lo: 0x9e, hi: 0x9e},
+	{value: 0x0014, lo: 0xa0, hi: 0xa3},
+	// Block 0x112, offset 0x5bf
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x113, offset 0x5c0
+	{value: 0x0014, lo: 0x80, hi: 0xad},
+	{value: 0x0014, lo: 0xb0, hi: 0xbf},
+	// Block 0x114, offset 0x5c2
+	{value: 0x0014, lo: 0x80, hi: 0x86},
+	// Block 0x115, offset 0x5c3
+	{value: 0x0030, lo: 0xa5, hi: 0xa6},
+	{value: 0x0034, lo: 0xa7, hi: 0xa9},
+	{value: 0x0030, lo: 0xad, hi: 0xb2},
+	{value: 0x0014, lo: 0xb3, hi: 0xba},
+	{value: 0x0034, lo: 0xbb, hi: 0xbf},
+	// Block 0x116, offset 0x5c8
+	{value: 0x0034, lo: 0x80, hi: 0x82},
+	{value: 0x0024, lo: 0x85, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8b},
+	{value: 0x0024, lo: 0xaa, hi: 0xad},
+	// Block 0x117, offset 0x5cc
+	{value: 0x0024, lo: 0x82, hi: 0x84},
+	// Block 0x118, offset 0x5cd
+	{value: 0x0013, lo: 0x80, hi: 0x99},
+	{value: 0x0012, lo: 0x9a, hi: 0xb3},
+	{value: 0x0013, lo: 0xb4, hi: 0xbf},
+	// Block 0x119, offset 0x5d0
+	{value: 0x0013, lo: 0x80, hi: 0x8d},
+	{value: 0x0012, lo: 0x8e, hi: 0x94},
+	{value: 0x0012, lo: 0x96, hi: 0xa7},
+	{value: 0x0013, lo: 0xa8, hi: 0xbf},
+	// Block 0x11a, offset 0x5d4
+	{value: 0x0013, lo: 0x80, hi: 0x81},
+	{value: 0x0012, lo: 0x82, hi: 0x9b},
+	{value: 0x0013, lo: 0x9c, hi: 0x9c},
+	{value: 0x0013, lo: 0x9e, hi: 0x9f},
+	{value: 0x0013, lo: 0xa2, hi: 0xa2},
+	{value: 0x0013, lo: 0xa5, hi: 0xa6},
+	{value: 0x0013, lo: 0xa9, hi: 0xac},
+	{value: 0x0013, lo: 0xae, hi: 0xb5},
+	{value: 0x0012, lo: 0xb6, hi: 0xb9},
+	{value: 0x0012, lo: 0xbb, hi: 0xbb},
+	{value: 0x0012, lo: 0xbd, hi: 0xbf},
+	// Block 0x11b, offset 0x5df
+	{value: 0x0012, lo: 0x80, hi: 0x83},
+	{value: 0x0012, lo: 0x85, hi: 0x8f},
+	{value: 0x0013, lo: 0x90, hi: 0xa9},
+	{value: 0x0012, lo: 0xaa, hi: 0xbf},
+	// Block 0x11c, offset 0x5e3
+	{value: 0x0012, lo: 0x80, hi: 0x83},
+	{value: 0x0013, lo: 0x84, hi: 0x85},
+	{value: 0x0013, lo: 0x87, hi: 0x8a},
+	{value: 0x0013, lo: 0x8d, hi: 0x94},
+	{value: 0x0013, lo: 0x96, hi: 0x9c},
+	{value: 0x0012, lo: 0x9e, hi: 0xb7},
+	{value: 0x0013, lo: 0xb8, hi: 0xb9},
+	{value: 0x0013, lo: 0xbb, hi: 0xbe},
+	// Block 0x11d, offset 0x5eb
+	{value: 0x0013, lo: 0x80, hi: 0x84},
+	{value: 0x0013, lo: 0x86, hi: 0x86},
+	{value: 0x0013, lo: 0x8a, hi: 0x90},
+	{value: 0x0012, lo: 0x92, hi: 0xab},
+	{value: 0x0013, lo: 0xac, hi: 0xbf},
+	// Block 0x11e, offset 0x5f0
+	{value: 0x0013, lo: 0x80, hi: 0x85},
+	{value: 0x0012, lo: 0x86, hi: 0x9f},
+	{value: 0x0013, lo: 0xa0, hi: 0xb9},
+	{value: 0x0012, lo: 0xba, hi: 0xbf},
+	// Block 0x11f, offset 0x5f4
+	{value: 0x0012, lo: 0x80, hi: 0x93},
+	{value: 0x0013, lo: 0x94, hi: 0xad},
+	{value: 0x0012, lo: 0xae, hi: 0xbf},
+	// Block 0x120, offset 0x5f7
+	{value: 0x0012, lo: 0x80, hi: 0x87},
+	{value: 0x0013, lo: 0x88, hi: 0xa1},
+	{value: 0x0012, lo: 0xa2, hi: 0xbb},
+	{value: 0x0013, lo: 0xbc, hi: 0xbf},
+	// Block 0x121, offset 0x5fb
+	{value: 0x0013, lo: 0x80, hi: 0x95},
+	{value: 0x0012, lo: 0x96, hi: 0xaf},
+	{value: 0x0013, lo: 0xb0, hi: 0xbf},
+	// Block 0x122, offset 0x5fe
+	{value: 0x0013, lo: 0x80, hi: 0x89},
+	{value: 0x0012, lo: 0x8a, hi: 0xa5},
+	{value: 0x0013, lo: 0xa8, hi: 0xbf},
+	// Block 0x123, offset 0x601
+	{value: 0x0013, lo: 0x80, hi: 0x80},
+	{value: 0x0012, lo: 0x82, hi: 0x9a},
+	{value: 0x0012, lo: 0x9c, hi: 0xa1},
+	{value: 0x0013, lo: 0xa2, hi: 0xba},
+	{value: 0x0012, lo: 0xbc, hi: 0xbf},
+	// Block 0x124, offset 0x606
+	{value: 0x0012, lo: 0x80, hi: 0x94},
+	{value: 0x0012, lo: 0x96, hi: 0x9b},
+	{value: 0x0013, lo: 0x9c, hi: 0xb4},
+	{value: 0x0012, lo: 0xb6, hi: 0xbf},
+	// Block 0x125, offset 0x60a
+	{value: 0x0012, lo: 0x80, hi: 0x8e},
+	{value: 0x0012, lo: 0x90, hi: 0x95},
+	{value: 0x0013, lo: 0x96, hi: 0xae},
+	{value: 0x0012, lo: 0xb0, hi: 0xbf},
+	// Block 0x126, offset 0x60e
+	{value: 0x0012, lo: 0x80, hi: 0x88},
+	{value: 0x0012, lo: 0x8a, hi: 0x8f},
+	{value: 0x0013, lo: 0x90, hi: 0xa8},
+	{value: 0x0012, lo: 0xaa, hi: 0xbf},
+	// Block 0x127, offset 0x612
+	{value: 0x0012, lo: 0x80, hi: 0x82},
+	{value: 0x0012, lo: 0x84, hi: 0x89},
+	{value: 0x0017, lo: 0x8a, hi: 0x8b},
+	{value: 0x0010, lo: 0x8e, hi: 0xbf},
+	// Block 0x128, offset 0x616
+	{value: 0x0014, lo: 0x80, hi: 0xb6},
+	{value: 0x0014, lo: 0xbb, hi: 0xbf},
+	// Block 0x129, offset 0x618
+	{value: 0x0014, lo: 0x80, hi: 0xac},
+	{value: 0x0014, lo: 0xb5, hi: 0xb5},
+	// Block 0x12a, offset 0x61a
+	{value: 0x0014, lo: 0x84, hi: 0x84},
+	{value: 0x0014, lo: 0x9b, hi: 0x9f},
+	{value: 0x0014, lo: 0xa1, hi: 0xaf},
+	// Block 0x12b, offset 0x61d
+	{value: 0x0012, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8a, hi: 0x8a},
+	{value: 0x0012, lo: 0x8b, hi: 0x9e},
+	{value: 0x0012, lo: 0xa5, hi: 0xaa},
+	// Block 0x12c, offset 0x621
+	{value: 0x0024, lo: 0x80, hi: 0x86},
+	{value: 0x0024, lo: 0x88, hi: 0x98},
+	{value: 0x0024, lo: 0x9b, hi: 0xa1},
+	{value: 0x0024, lo: 0xa3, hi: 0xa4},
+	{value: 0x0024, lo: 0xa6, hi: 0xaa},
+	{value: 0x0015, lo: 0xb0, hi: 0xbf},
+	// Block 0x12d, offset 0x627
+	{value: 0x0015, lo: 0x80, hi: 0xad},
+	// Block 0x12e, offset 0x628
+	{value: 0x0024, lo: 0x8f, hi: 0x8f},
+	// Block 0x12f, offset 0x629
+	{value: 0x0010, lo: 0x80, hi: 0xac},
+	{value: 0x0024, lo: 0xb0, hi: 0xb6},
+	{value: 0x0014, lo: 0xb7, hi: 0xbd},
+	// Block 0x130, offset 0x62c
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8e, hi: 0x8e},
+	// Block 0x131, offset 0x62e
+	{value: 0x0010, lo: 0x90, hi: 0xad},
+	{value: 0x0024, lo: 0xae, hi: 0xae},
+	// Block 0x132, offset 0x630
+	{value: 0x0010, lo: 0x80, hi: 0xab},
+	{value: 0x0024, lo: 0xac, hi: 0xaf},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x133, offset 0x633
+	{value: 0x0010, lo: 0x90, hi: 0xaa},
+	{value: 0x0014, lo: 0xab, hi: 0xab},
+	{value: 0x0034, lo: 0xac, hi: 0xae},
+	{value: 0x0024, lo: 0xaf, hi: 0xaf},
+	{value: 0x0010, lo: 0xb0, hi: 0xb9},
+	// Block 0x134, offset 0x638
+	{value: 0x0010, lo: 0x90, hi: 0xad},
+	{value: 0x0024, lo: 0xae, hi: 0xae},
+	{value: 0x0034, lo: 0xaf, hi: 0xaf},
+	{value: 0x0010, lo: 0xb0, hi: 0xba},
+	// Block 0x135, offset 0x63c
+	{value: 0x0010, lo: 0x80, hi: 0x9e},
+	{value: 0x0010, lo: 0xa0, hi: 0xa2},
+	{value: 0x0024, lo: 0xa3, hi: 0xa3},
+	{value: 0x0010, lo: 0xa4, hi: 0xa5},
+	{value: 0x0024, lo: 0xa6, hi: 0xa6},
+	{value: 0x0010, lo: 0xa7, hi: 0xad},
+	{value: 0x0024, lo: 0xae, hi: 0xaf},
+	{value: 0x0010, lo: 0xb0, hi: 0xb4},
+	{value: 0x0024, lo: 0xb5, hi: 0xb5},
+	{value: 0x0010, lo: 0xbe, hi: 0xbe},
+	{value: 0x0014, lo: 0xbf, hi: 0xbf},
+	// Block 0x136, offset 0x647
+	{value: 0x0010, lo: 0xa0, hi: 0xa6},
+	{value: 0x0010, lo: 0xa8, hi: 0xab},
+	{value: 0x0010, lo: 0xad, hi: 0xae},
+	{value: 0x0010, lo: 0xb0, hi: 0xbe},
+	// Block 0x137, offset 0x64b
+	{value: 0x0010, lo: 0x80, hi: 0x84},
+	{value: 0x0034, lo: 0x90, hi: 0x96},
+	// Block 0x138, offset 0x64d
+	{value: 0xe952, lo: 0x80, hi: 0x81},
+	{value: 0xec52, lo: 0x82, hi: 0x83},
+	{value: 0x0024, lo: 0x84, hi: 0x89},
+	{value: 0x0034, lo: 0x8a, hi: 0x8a},
+	{value: 0x0014, lo: 0x8b, hi: 0x8b},
+	{value: 0x0010, lo: 0x90, hi: 0x99},
+	// Block 0x139, offset 0x653
+	{value: 0x0010, lo: 0x80, hi: 0x83},
+	{value: 0x0010, lo: 0x85, hi: 0x9f},
+	{value: 0x0010, lo: 0xa1, hi: 0xa2},
+	{value: 0x0010, lo: 0xa4, hi: 0xa4},
+	{value: 0x0010, lo: 0xa7, hi: 0xa7},
+	{value: 0x0010, lo: 0xa9, hi: 0xb2},
+	{value: 0x0010, lo: 0xb4, hi: 0xb7},
+	{value: 0x0010, lo: 0xb9, hi: 0xb9},
+	{value: 0x0010, lo: 0xbb, hi: 0xbb},
+	// Block 0x13a, offset 0x65c
+	{value: 0x0010, lo: 0x80, hi: 0x89},
+	{value: 0x0010, lo: 0x8b, hi: 0x9b},
+	{value: 0x0010, lo: 0xa1, hi: 0xa3},
+	{value: 0x0010, lo: 0xa5, hi: 0xa9},
+	{value: 0x0010, lo: 0xab, hi: 0xbb},
+	// Block 0x13b, offset 0x661
+	{value: 0x0013, lo: 0xb0, hi: 0xbf},
+	// Block 0x13c, offset 0x662
+	{value: 0x0013, lo: 0x80, hi: 0x89},
+	{value: 0x0013, lo: 0x90, hi: 0xa9},
+	{value: 0x0013, lo: 0xb0, hi: 0xbf},
+	// Block 0x13d, offset 0x665
+	{value: 0x0013, lo: 0x80, hi: 0x89},
+	// Block 0x13e, offset 0x666
+	{value: 0x0014, lo: 0xbb, hi: 0xbf},
+	// Block 0x13f, offset 0x667
+	{value: 0x0014, lo: 0x81, hi: 0x81},
+	{value: 0x0014, lo: 0xa0, hi: 0xbf},
+	// Block 0x140, offset 0x669
+	{value: 0x0014, lo: 0x80, hi: 0xbf},
+	// Block 0x141, offset 0x66a
+	{value: 0x0014, lo: 0x80, hi: 0xaf},
+}
+
+// Total table size 16747 bytes (16KiB); checksum: D520269F
diff --git a/vendor/golang.org/x/text/cases/trieval.go b/vendor/golang.org/x/text/cases/trieval.go
new file mode 100644
index 000000000..4e4d13fe5
--- /dev/null
+++ b/vendor/golang.org/x/text/cases/trieval.go
@@ -0,0 +1,217 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package cases
+
+// This file contains definitions for interpreting the trie value of the case
+// trie generated by "go run gen*.go". It is shared by both the generator
+// program and the resultant package. Sharing is achieved by the generator
+// copying gen_trieval.go to trieval.go and changing what's above this comment.
+
+// info holds case information for a single rune. It is the value returned
+// by a trie lookup. Most mapping information can be stored in a single 16-bit
+// value. If not, for example when a rune is mapped to multiple runes, the value
+// stores some basic case data and an index into an array with additional data.
+//
+// The per-rune values have the following format:
+//
+//	if (exception) {
+//	  15..4  unsigned exception index
+//	} else {
+//	  15..8  XOR pattern or index to XOR pattern for case mapping
+//	         Only 13..8 are used for XOR patterns.
+//	      7  inverseFold (fold to upper, not to lower)
+//	      6  index: interpret the XOR pattern as an index
+//	         or isMid if case mode is cIgnorableUncased.
+//	   5..4  CCC: zero (normal or break), above or other
+//	}
+//	   3  exception: interpret this value as an exception index
+//	      (TODO: is this bit necessary? Probably implied from case mode.)
+//	2..0  case mode
+//
+// For the non-exceptional cases, a rune must be either uncased, lowercase or
+// uppercase. If the rune is cased, the XOR pattern maps either a lowercase
+// rune to uppercase or an uppercase rune to lowercase (applied to the 10
+// least-significant bits of the rune).
+//
+// See the definitions below for a more detailed description of the various
+// bits.
+type info uint16
+
+const (
+	casedMask      = 0x0003
+	fullCasedMask  = 0x0007
+	ignorableMask  = 0x0006
+	ignorableValue = 0x0004
+
+	inverseFoldBit = 1 << 7
+	isMidBit       = 1 << 6
+
+	exceptionBit     = 1 << 3
+	exceptionShift   = 4
+	numExceptionBits = 12
+
+	xorIndexBit = 1 << 6
+	xorShift    = 8
+
+	// There is no mapping if all xor bits and the exception bit are zero.
+	hasMappingMask = 0xff80 | exceptionBit
+)
+
+// The case mode bits encodes the case type of a rune. This includes uncased,
+// title, upper and lower case and case ignorable. (For a definition of these
+// terms see Chapter 3 of The Unicode Standard Core Specification.) In some rare
+// cases, a rune can be both cased and case-ignorable. This is encoded by
+// cIgnorableCased. A rune of this type is always lower case. Some runes are
+// cased while not having a mapping.
+//
+// A common pattern for scripts in the Unicode standard is for upper and lower
+// case runes to alternate for increasing rune values (e.g. the accented Latin
+// ranges starting from U+0100 and U+1E00 among others and some Cyrillic
+// characters). We use this property by defining a cXORCase mode, where the case
+// mode (always upper or lower case) is derived from the rune value. As the XOR
+// pattern for case mappings is often identical for successive runes, using
+// cXORCase can result in large series of identical trie values. This, in turn,
+// allows us to better compress the trie blocks.
+const (
+	cUncased          info = iota // 000
+	cTitle                        // 001
+	cLower                        // 010
+	cUpper                        // 011
+	cIgnorableUncased             // 100
+	cIgnorableCased               // 101 // lower case if mappings exist
+	cXORCase                      // 11x // case is cLower | ((rune&1) ^ x)
+
+	maxCaseMode = cUpper
+)
+
+func (c info) isCased() bool {
+	return c&casedMask != 0
+}
+
+func (c info) isCaseIgnorable() bool {
+	return c&ignorableMask == ignorableValue
+}
+
+func (c info) isNotCasedAndNotCaseIgnorable() bool {
+	return c&fullCasedMask == 0
+}
+
+func (c info) isCaseIgnorableAndNotCased() bool {
+	return c&fullCasedMask == cIgnorableUncased
+}
+
+func (c info) isMid() bool {
+	return c&(fullCasedMask|isMidBit) == isMidBit|cIgnorableUncased
+}
+
+// The case mapping implementation will need to know about various Canonical
+// Combining Class (CCC) values. We encode two of these in the trie value:
+// cccZero (0) and cccAbove (230). If the value is cccOther, it means that
+// CCC(r) > 0, but not 230. A value of cccBreak means that CCC(r) == 0 and that
+// the rune also has the break category Break (see below).
+const (
+	cccBreak info = iota << 4
+	cccZero
+	cccAbove
+	cccOther
+
+	cccMask = cccBreak | cccZero | cccAbove | cccOther
+)
+
+const (
+	starter       = 0
+	above         = 230
+	iotaSubscript = 240
+)
+
+// The exceptions slice holds data that does not fit in a normal info entry.
+// The entry is pointed to by the exception index in an entry. It has the
+// following format:
+//
+// Header:
+//
+//	byte 0:
+//	 7..6  unused
+//	 5..4  CCC type (same bits as entry)
+//	    3  unused
+//	 2..0  length of fold
+//
+//	byte 1:
+//	  7..6  unused
+//	  5..3  length of 1st mapping of case type
+//	  2..0  length of 2nd mapping of case type
+//
+//	  case     1st    2nd
+//	  lower -> upper, title
+//	  upper -> lower, title
+//	  title -> lower, upper
+//
+// Lengths with the value 0x7 indicate no value and implies no change.
+// A length of 0 indicates a mapping to zero-length string.
+//
+// Body bytes:
+//
+//	case folding bytes
+//	lowercase mapping bytes
+//	uppercase mapping bytes
+//	titlecase mapping bytes
+//	closure mapping bytes (for NFKC_Casefold). (TODO)
+//
+// Fallbacks:
+//
+//	missing fold  -> lower
+//	missing title -> upper
+//	all missing   -> original rune
+//
+// exceptions starts with a dummy byte to enforce that there is no zero index
+// value.
+const (
+	lengthMask = 0x07
+	lengthBits = 3
+	noChange   = 0
+)
+
+// References to generated trie.
+
+var trie = newCaseTrie(0)
+
+var sparse = sparseBlocks{
+	values:  sparseValues[:],
+	offsets: sparseOffsets[:],
+}
+
+// Sparse block lookup code.
+
+// valueRange is an entry in a sparse block.
+type valueRange struct {
+	value  uint16
+	lo, hi byte
+}
+
+type sparseBlocks struct {
+	values  []valueRange
+	offsets []uint16
+}
+
+// lookup returns the value from values block n for byte b using binary search.
+func (s *sparseBlocks) lookup(n uint32, b byte) uint16 {
+	lo := s.offsets[n]
+	hi := s.offsets[n+1]
+	for lo < hi {
+		m := lo + (hi-lo)/2
+		r := s.values[m]
+		if r.lo <= b && b <= r.hi {
+			return r.value
+		}
+		if b < r.lo {
+			hi = m
+		} else {
+			lo = m + 1
+		}
+	}
+	return 0
+}
+
+// lastRuneForTesting is the last rune used for testing. Everything after this
+// is boring.
+const lastRuneForTesting = rune(0x1FFFF)
diff --git a/vendor/golang.org/x/text/internal/internal.go b/vendor/golang.org/x/text/internal/internal.go
new file mode 100644
index 000000000..3cddbbdda
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/internal.go
@@ -0,0 +1,49 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package internal contains non-exported functionality that are used by
+// packages in the text repository.
+package internal // import "golang.org/x/text/internal"
+
+import (
+	"sort"
+
+	"golang.org/x/text/language"
+)
+
+// SortTags sorts tags in place.
+func SortTags(tags []language.Tag) {
+	sort.Sort(sorter(tags))
+}
+
+type sorter []language.Tag
+
+func (s sorter) Len() int {
+	return len(s)
+}
+
+func (s sorter) Swap(i, j int) {
+	s[i], s[j] = s[j], s[i]
+}
+
+func (s sorter) Less(i, j int) bool {
+	return s[i].String() < s[j].String()
+}
+
+// UniqueTags sorts and filters duplicate tags in place and returns a slice with
+// only unique tags.
+func UniqueTags(tags []language.Tag) []language.Tag {
+	if len(tags) <= 1 {
+		return tags
+	}
+	SortTags(tags)
+	k := 0
+	for i := 1; i < len(tags); i++ {
+		if tags[k].String() < tags[i].String() {
+			k++
+			tags[k] = tags[i]
+		}
+	}
+	return tags[:k+1]
+}
diff --git a/vendor/golang.org/x/text/internal/language/common.go b/vendor/golang.org/x/text/internal/language/common.go
new file mode 100644
index 000000000..cdfdb7497
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/common.go
@@ -0,0 +1,16 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package language
+
+// This file contains code common to the maketables.go and the package code.
+
+// AliasType is the type of an alias in AliasMap.
+type AliasType int8
+
+const (
+	Deprecated AliasType = iota
+	Macro
+	Legacy
+
+	AliasTypeUnknown AliasType = -1
+)
diff --git a/vendor/golang.org/x/text/internal/language/compact.go b/vendor/golang.org/x/text/internal/language/compact.go
new file mode 100644
index 000000000..46a001507
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/compact.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+// CompactCoreInfo is a compact integer with the three core tags encoded.
+type CompactCoreInfo uint32
+
+// GetCompactCore generates a uint32 value that is guaranteed to be unique for
+// different language, region, and script values.
+func GetCompactCore(t Tag) (cci CompactCoreInfo, ok bool) {
+	if t.LangID > langNoIndexOffset {
+		return 0, false
+	}
+	cci |= CompactCoreInfo(t.LangID) << (8 + 12)
+	cci |= CompactCoreInfo(t.ScriptID) << 12
+	cci |= CompactCoreInfo(t.RegionID)
+	return cci, true
+}
+
+// Tag generates a tag from c.
+func (c CompactCoreInfo) Tag() Tag {
+	return Tag{
+		LangID:   Language(c >> 20),
+		RegionID: Region(c & 0x3ff),
+		ScriptID: Script(c>>12) & 0xff,
+	}
+}
diff --git a/vendor/golang.org/x/text/internal/language/compact/compact.go b/vendor/golang.org/x/text/internal/language/compact/compact.go
new file mode 100644
index 000000000..1b36935ef
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/compact/compact.go
@@ -0,0 +1,61 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package compact defines a compact representation of language tags.
+//
+// Common language tags (at least all for which locale information is defined
+// in CLDR) are assigned a unique index. Each Tag is associated with such an
+// ID for selecting language-related resources (such as translations) as well
+// as one for selecting regional defaults (currency, number formatting, etc.)
+//
+// It may want to export this functionality at some point, but at this point
+// this is only available for use within x/text.
+package compact // import "golang.org/x/text/internal/language/compact"
+
+import (
+	"sort"
+	"strings"
+
+	"golang.org/x/text/internal/language"
+)
+
+// ID is an integer identifying a single tag.
+type ID uint16
+
+func getCoreIndex(t language.Tag) (id ID, ok bool) {
+	cci, ok := language.GetCompactCore(t)
+	if !ok {
+		return 0, false
+	}
+	i := sort.Search(len(coreTags), func(i int) bool {
+		return cci <= coreTags[i]
+	})
+	if i == len(coreTags) || coreTags[i] != cci {
+		return 0, false
+	}
+	return ID(i), true
+}
+
+// Parent returns the ID of the parent or the root ID if id is already the root.
+func (id ID) Parent() ID {
+	return parents[id]
+}
+
+// Tag converts id to an internal language Tag.
+func (id ID) Tag() language.Tag {
+	if int(id) >= len(coreTags) {
+		return specialTags[int(id)-len(coreTags)]
+	}
+	return coreTags[id].Tag()
+}
+
+var specialTags []language.Tag
+
+func init() {
+	tags := strings.Split(specialTagsStr, " ")
+	specialTags = make([]language.Tag, len(tags))
+	for i, t := range tags {
+		specialTags[i] = language.MustParse(t)
+	}
+}
diff --git a/vendor/golang.org/x/text/internal/language/compact/language.go b/vendor/golang.org/x/text/internal/language/compact/language.go
new file mode 100644
index 000000000..8c1b6666f
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/compact/language.go
@@ -0,0 +1,260 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go gen_index.go -output tables.go
+//go:generate go run gen_parents.go
+
+package compact
+
+// TODO: Remove above NOTE after:
+// - verifying that tables are dropped correctly (most notably matcher tables).
+
+import (
+	"strings"
+
+	"golang.org/x/text/internal/language"
+)
+
+// Tag represents a BCP 47 language tag. It is used to specify an instance of a
+// specific language or locale. All language tag values are guaranteed to be
+// well-formed.
+type Tag struct {
+	// NOTE: exported tags will become part of the public API.
+	language ID
+	locale   ID
+	full     fullTag // always a language.Tag for now.
+}
+
+const _und = 0
+
+type fullTag interface {
+	IsRoot() bool
+	Parent() language.Tag
+}
+
+// Make a compact Tag from a fully specified internal language Tag.
+func Make(t language.Tag) (tag Tag) {
+	if region := t.TypeForKey("rg"); len(region) == 6 && region[2:] == "zzzz" {
+		if r, err := language.ParseRegion(region[:2]); err == nil {
+			tFull := t
+			t, _ = t.SetTypeForKey("rg", "")
+			// TODO: should we not consider "va" for the language tag?
+			var exact1, exact2 bool
+			tag.language, exact1 = FromTag(t)
+			t.RegionID = r
+			tag.locale, exact2 = FromTag(t)
+			if !exact1 || !exact2 {
+				tag.full = tFull
+			}
+			return tag
+		}
+	}
+	lang, ok := FromTag(t)
+	tag.language = lang
+	tag.locale = lang
+	if !ok {
+		tag.full = t
+	}
+	return tag
+}
+
+// Tag returns an internal language Tag version of this tag.
+func (t Tag) Tag() language.Tag {
+	if t.full != nil {
+		return t.full.(language.Tag)
+	}
+	tag := t.language.Tag()
+	if t.language != t.locale {
+		loc := t.locale.Tag()
+		tag, _ = tag.SetTypeForKey("rg", strings.ToLower(loc.RegionID.String())+"zzzz")
+	}
+	return tag
+}
+
+// IsCompact reports whether this tag is fully defined in terms of ID.
+func (t *Tag) IsCompact() bool {
+	return t.full == nil
+}
+
+// MayHaveVariants reports whether a tag may have variants. If it returns false
+// it is guaranteed the tag does not have variants.
+func (t Tag) MayHaveVariants() bool {
+	return t.full != nil || int(t.language) >= len(coreTags)
+}
+
+// MayHaveExtensions reports whether a tag may have extensions. If it returns
+// false it is guaranteed the tag does not have them.
+func (t Tag) MayHaveExtensions() bool {
+	return t.full != nil ||
+		int(t.language) >= len(coreTags) ||
+		t.language != t.locale
+}
+
+// IsRoot returns true if t is equal to language "und".
+func (t Tag) IsRoot() bool {
+	if t.full != nil {
+		return t.full.IsRoot()
+	}
+	return t.language == _und
+}
+
+// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
+// specific language are substituted with fields from the parent language.
+// The parent for a language may change for newer versions of CLDR.
+func (t Tag) Parent() Tag {
+	if t.full != nil {
+		return Make(t.full.Parent())
+	}
+	if t.language != t.locale {
+		// Simulate stripping -u-rg-xxxxxx
+		return Tag{language: t.language, locale: t.language}
+	}
+	// TODO: use parent lookup table once cycle from internal package is
+	// removed. Probably by internalizing the table and declaring this fast
+	// enough.
+	// lang := compactID(internal.Parent(uint16(t.language)))
+	lang, _ := FromTag(t.language.Tag().Parent())
+	return Tag{language: lang, locale: lang}
+}
+
+// nextToken returns token t and the rest of the string.
+func nextToken(s string) (t, tail string) {
+	p := strings.Index(s[1:], "-")
+	if p == -1 {
+		return s[1:], ""
+	}
+	p++
+	return s[1:p], s[p:]
+}
+
+// LanguageID returns an index, where 0 <= index < NumCompactTags, for tags
+// for which data exists in the text repository.The index will change over time
+// and should not be stored in persistent storage. If t does not match a compact
+// index, exact will be false and the compact index will be returned for the
+// first match after repeatedly taking the Parent of t.
+func LanguageID(t Tag) (id ID, exact bool) {
+	return t.language, t.full == nil
+}
+
+// RegionalID returns the ID for the regional variant of this tag. This index is
+// used to indicate region-specific overrides, such as default currency, default
+// calendar and week data, default time cycle, and default measurement system
+// and unit preferences.
+//
+// For instance, the tag en-GB-u-rg-uszzzz specifies British English with US
+// settings for currency, number formatting, etc. The CompactIndex for this tag
+// will be that for en-GB, while the RegionalID will be the one corresponding to
+// en-US.
+func RegionalID(t Tag) (id ID, exact bool) {
+	return t.locale, t.full == nil
+}
+
+// LanguageTag returns t stripped of regional variant indicators.
+//
+// At the moment this means it is stripped of a regional and variant subtag "rg"
+// and "va" in the "u" extension.
+func (t Tag) LanguageTag() Tag {
+	if t.full == nil {
+		return Tag{language: t.language, locale: t.language}
+	}
+	tt := t.Tag()
+	tt.SetTypeForKey("rg", "")
+	tt.SetTypeForKey("va", "")
+	return Make(tt)
+}
+
+// RegionalTag returns the regional variant of the tag.
+//
+// At the moment this means that the region is set from the regional subtag
+// "rg" in the "u" extension.
+func (t Tag) RegionalTag() Tag {
+	rt := Tag{language: t.locale, locale: t.locale}
+	if t.full == nil {
+		return rt
+	}
+	b := language.Builder{}
+	tag := t.Tag()
+	// tag, _ = tag.SetTypeForKey("rg", "")
+	b.SetTag(t.locale.Tag())
+	if v := tag.Variants(); v != "" {
+		for _, v := range strings.Split(v, "-") {
+			b.AddVariant(v)
+		}
+	}
+	for _, e := range tag.Extensions() {
+		b.AddExt(e)
+	}
+	return t
+}
+
+// FromTag reports closest matching ID for an internal language Tag.
+func FromTag(t language.Tag) (id ID, exact bool) {
+	// TODO: perhaps give more frequent tags a lower index.
+	// TODO: we could make the indexes stable. This will excluded some
+	//       possibilities for optimization, so don't do this quite yet.
+	exact = true
+
+	b, s, r := t.Raw()
+	if t.HasString() {
+		if t.IsPrivateUse() {
+			// We have no entries for user-defined tags.
+			return 0, false
+		}
+		hasExtra := false
+		if t.HasVariants() {
+			if t.HasExtensions() {
+				build := language.Builder{}
+				build.SetTag(language.Tag{LangID: b, ScriptID: s, RegionID: r})
+				build.AddVariant(t.Variants())
+				exact = false
+				t = build.Make()
+			}
+			hasExtra = true
+		} else if _, ok := t.Extension('u'); ok {
+			// TODO: va may mean something else. Consider not considering it.
+			// Strip all but the 'va' entry.
+			old := t
+			variant := t.TypeForKey("va")
+			t = language.Tag{LangID: b, ScriptID: s, RegionID: r}
+			if variant != "" {
+				t, _ = t.SetTypeForKey("va", variant)
+				hasExtra = true
+			}
+			exact = old == t
+		} else {
+			exact = false
+		}
+		if hasExtra {
+			// We have some variants.
+			for i, s := range specialTags {
+				if s == t {
+					return ID(i + len(coreTags)), exact
+				}
+			}
+			exact = false
+		}
+	}
+	if x, ok := getCoreIndex(t); ok {
+		return x, exact
+	}
+	exact = false
+	if r != 0 && s == 0 {
+		// Deal with cases where an extra script is inserted for the region.
+		t, _ := t.Maximize()
+		if x, ok := getCoreIndex(t); ok {
+			return x, exact
+		}
+	}
+	for t = t.Parent(); t != root; t = t.Parent() {
+		// No variants specified: just compare core components.
+		// The key has the form lllssrrr, where l, s, and r are nibbles for
+		// respectively the langID, scriptID, and regionID.
+		if x, ok := getCoreIndex(t); ok {
+			return x, exact
+		}
+	}
+	return 0, exact
+}
+
+var root = language.Tag{}
diff --git a/vendor/golang.org/x/text/internal/language/compact/parents.go b/vendor/golang.org/x/text/internal/language/compact/parents.go
new file mode 100644
index 000000000..8d810723c
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/compact/parents.go
@@ -0,0 +1,120 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package compact
+
+// parents maps a compact index of a tag to the compact index of the parent of
+// this tag.
+var parents = []ID{ // 775 elements
+	// Entry 0 - 3F
+	0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0004, 0x0000, 0x0006,
+	0x0000, 0x0008, 0x0000, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
+	0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
+	0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
+	0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0000,
+	0x0000, 0x0028, 0x0000, 0x002a, 0x0000, 0x002c, 0x0000, 0x0000,
+	0x002f, 0x002e, 0x002e, 0x0000, 0x0033, 0x0000, 0x0035, 0x0000,
+	0x0037, 0x0000, 0x0039, 0x0000, 0x003b, 0x0000, 0x0000, 0x003e,
+	// Entry 40 - 7F
+	0x0000, 0x0040, 0x0040, 0x0000, 0x0043, 0x0043, 0x0000, 0x0046,
+	0x0000, 0x0048, 0x0000, 0x0000, 0x004b, 0x004a, 0x004a, 0x0000,
+	0x004f, 0x004f, 0x004f, 0x004f, 0x0000, 0x0054, 0x0054, 0x0000,
+	0x0057, 0x0000, 0x0059, 0x0000, 0x005b, 0x0000, 0x005d, 0x005d,
+	0x0000, 0x0060, 0x0000, 0x0062, 0x0000, 0x0064, 0x0000, 0x0066,
+	0x0066, 0x0000, 0x0069, 0x0000, 0x006b, 0x006b, 0x006b, 0x006b,
+	0x006b, 0x006b, 0x006b, 0x0000, 0x0073, 0x0000, 0x0075, 0x0000,
+	0x0077, 0x0000, 0x0000, 0x007a, 0x0000, 0x007c, 0x0000, 0x007e,
+	// Entry 80 - BF
+	0x0000, 0x0080, 0x0080, 0x0000, 0x0083, 0x0083, 0x0000, 0x0086,
+	0x0087, 0x0087, 0x0087, 0x0086, 0x0088, 0x0087, 0x0087, 0x0087,
+	0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088,
+	0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087, 0x0088, 0x0087,
+	0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
+	0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087,
+	0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
+	0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0086,
+	// Entry C0 - FF
+	0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
+	0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
+	0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087,
+	0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
+	0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0086, 0x0087,
+	0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0000,
+	0x00ef, 0x0000, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2,
+	0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f1, 0x00f1,
+	// Entry 100 - 13F
+	0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1,
+	0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x0000, 0x010e,
+	0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0114, 0x0000,
+	0x0117, 0x0117, 0x0117, 0x0117, 0x0000, 0x011c, 0x0000, 0x011e,
+	0x0000, 0x0120, 0x0120, 0x0000, 0x0123, 0x0123, 0x0123, 0x0123,
+	0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
+	0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
+	0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
+	// Entry 140 - 17F
+	0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
+	0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
+	0x0123, 0x0123, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156,
+	0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x015c, 0x015c,
+	0x0000, 0x0160, 0x0000, 0x0000, 0x0163, 0x0000, 0x0165, 0x0000,
+	0x0167, 0x0167, 0x0167, 0x0000, 0x016b, 0x0000, 0x016d, 0x0000,
+	0x016f, 0x0000, 0x0171, 0x0171, 0x0000, 0x0174, 0x0000, 0x0176,
+	0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e,
+	// Entry 180 - 1BF
+	0x0000, 0x0000, 0x0000, 0x0182, 0x0000, 0x0184, 0x0184, 0x0184,
+	0x0184, 0x0000, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x018e,
+	0x0000, 0x0000, 0x0191, 0x0000, 0x0000, 0x0000, 0x0195, 0x0000,
+	0x0197, 0x0000, 0x0000, 0x019a, 0x0000, 0x0000, 0x019d, 0x0000,
+	0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000,
+	0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x0000, 0x01ad, 0x0000,
+	0x01af, 0x0000, 0x01b1, 0x01b1, 0x0000, 0x01b4, 0x0000, 0x01b6,
+	0x0000, 0x01b8, 0x0000, 0x01ba, 0x0000, 0x01bc, 0x0000, 0x0000,
+	// Entry 1C0 - 1FF
+	0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x0000,
+	0x01c7, 0x0000, 0x01c9, 0x0000, 0x01cb, 0x01cb, 0x01cb, 0x01cb,
+	0x0000, 0x01d0, 0x0000, 0x01d2, 0x01d2, 0x0000, 0x01d5, 0x0000,
+	0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x0000, 0x01dd, 0x0000,
+	0x01df, 0x01df, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
+	0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee,
+	0x0000, 0x01f0, 0x0000, 0x0000, 0x01f3, 0x0000, 0x01f5, 0x01f5,
+	0x01f5, 0x0000, 0x01f9, 0x0000, 0x01fb, 0x0000, 0x01fd, 0x0000,
+	// Entry 200 - 23F
+	0x01ff, 0x0000, 0x0000, 0x0202, 0x0000, 0x0204, 0x0204, 0x0000,
+	0x0207, 0x0000, 0x0209, 0x0209, 0x0000, 0x020c, 0x020c, 0x0000,
+	0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x0000,
+	0x0217, 0x0000, 0x0219, 0x0000, 0x021b, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0221, 0x0000, 0x0000, 0x0224, 0x0000, 0x0226,
+	0x0226, 0x0000, 0x0229, 0x0000, 0x022b, 0x022b, 0x0000, 0x0000,
+	0x022f, 0x022e, 0x022e, 0x0000, 0x0000, 0x0234, 0x0000, 0x0236,
+	0x0000, 0x0238, 0x0000, 0x0244, 0x023a, 0x0244, 0x0244, 0x0244,
+	// Entry 240 - 27F
+	0x0244, 0x0244, 0x0244, 0x0244, 0x023a, 0x0244, 0x0244, 0x0000,
+	0x0247, 0x0247, 0x0247, 0x0000, 0x024b, 0x0000, 0x024d, 0x0000,
+	0x024f, 0x024f, 0x0000, 0x0252, 0x0000, 0x0254, 0x0254, 0x0254,
+	0x0254, 0x0254, 0x0254, 0x0000, 0x025b, 0x0000, 0x025d, 0x0000,
+	0x025f, 0x0000, 0x0261, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
+	0x0000, 0x0268, 0x0268, 0x0268, 0x0000, 0x026c, 0x0000, 0x026e,
+	0x0000, 0x0270, 0x0000, 0x0000, 0x0000, 0x0274, 0x0273, 0x0273,
+	0x0000, 0x0278, 0x0000, 0x027a, 0x0000, 0x027c, 0x0000, 0x0000,
+	// Entry 280 - 2BF
+	0x0000, 0x0000, 0x0281, 0x0000, 0x0000, 0x0284, 0x0000, 0x0286,
+	0x0286, 0x0286, 0x0286, 0x0000, 0x028b, 0x028b, 0x028b, 0x0000,
+	0x028f, 0x028f, 0x028f, 0x028f, 0x028f, 0x0000, 0x0295, 0x0295,
+	0x0295, 0x0295, 0x0000, 0x0000, 0x0000, 0x0000, 0x029d, 0x029d,
+	0x029d, 0x0000, 0x02a1, 0x02a1, 0x02a1, 0x02a1, 0x0000, 0x0000,
+	0x02a7, 0x02a7, 0x02a7, 0x02a7, 0x0000, 0x02ac, 0x0000, 0x02ae,
+	0x02ae, 0x0000, 0x02b1, 0x0000, 0x02b3, 0x0000, 0x02b5, 0x02b5,
+	0x0000, 0x0000, 0x02b9, 0x0000, 0x0000, 0x0000, 0x02bd, 0x0000,
+	// Entry 2C0 - 2FF
+	0x02bf, 0x02bf, 0x0000, 0x0000, 0x02c3, 0x0000, 0x02c5, 0x0000,
+	0x02c7, 0x0000, 0x02c9, 0x0000, 0x02cb, 0x0000, 0x02cd, 0x02cd,
+	0x0000, 0x0000, 0x02d1, 0x0000, 0x02d3, 0x02d0, 0x02d0, 0x0000,
+	0x0000, 0x02d8, 0x02d7, 0x02d7, 0x0000, 0x0000, 0x02dd, 0x0000,
+	0x02df, 0x0000, 0x02e1, 0x0000, 0x0000, 0x02e4, 0x0000, 0x02e6,
+	0x0000, 0x0000, 0x02e9, 0x0000, 0x02eb, 0x0000, 0x02ed, 0x0000,
+	0x02ef, 0x02ef, 0x0000, 0x0000, 0x02f3, 0x02f2, 0x02f2, 0x0000,
+	0x02f7, 0x0000, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x0000,
+	// Entry 300 - 33F
+	0x02ff, 0x0300, 0x02ff, 0x0000, 0x0303, 0x0051, 0x00e6,
+} // Size: 1574 bytes
+
+// Total table size 1574 bytes (1KiB); checksum: 895AAF0B
diff --git a/vendor/golang.org/x/text/internal/language/compact/tables.go b/vendor/golang.org/x/text/internal/language/compact/tables.go
new file mode 100644
index 000000000..a09ed198a
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/compact/tables.go
@@ -0,0 +1,1015 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package compact
+
+import "golang.org/x/text/internal/language"
+
+// CLDRVersion is the CLDR version from which the tables in this package are derived.
+const CLDRVersion = "32"
+
+// NumCompactTags is the number of common tags. The maximum tag is
+// NumCompactTags-1.
+const NumCompactTags = 775
+const (
+	undIndex          ID = 0
+	afIndex           ID = 1
+	afNAIndex         ID = 2
+	afZAIndex         ID = 3
+	agqIndex          ID = 4
+	agqCMIndex        ID = 5
+	akIndex           ID = 6
+	akGHIndex         ID = 7
+	amIndex           ID = 8
+	amETIndex         ID = 9
+	arIndex           ID = 10
+	ar001Index        ID = 11
+	arAEIndex         ID = 12
+	arBHIndex         ID = 13
+	arDJIndex         ID = 14
+	arDZIndex         ID = 15
+	arEGIndex         ID = 16
+	arEHIndex         ID = 17
+	arERIndex         ID = 18
+	arILIndex         ID = 19
+	arIQIndex         ID = 20
+	arJOIndex         ID = 21
+	arKMIndex         ID = 22
+	arKWIndex         ID = 23
+	arLBIndex         ID = 24
+	arLYIndex         ID = 25
+	arMAIndex         ID = 26
+	arMRIndex         ID = 27
+	arOMIndex         ID = 28
+	arPSIndex         ID = 29
+	arQAIndex         ID = 30
+	arSAIndex         ID = 31
+	arSDIndex         ID = 32
+	arSOIndex         ID = 33
+	arSSIndex         ID = 34
+	arSYIndex         ID = 35
+	arTDIndex         ID = 36
+	arTNIndex         ID = 37
+	arYEIndex         ID = 38
+	arsIndex          ID = 39
+	asIndex           ID = 40
+	asINIndex         ID = 41
+	asaIndex          ID = 42
+	asaTZIndex        ID = 43
+	astIndex          ID = 44
+	astESIndex        ID = 45
+	azIndex           ID = 46
+	azCyrlIndex       ID = 47
+	azCyrlAZIndex     ID = 48
+	azLatnIndex       ID = 49
+	azLatnAZIndex     ID = 50
+	basIndex          ID = 51
+	basCMIndex        ID = 52
+	beIndex           ID = 53
+	beBYIndex         ID = 54
+	bemIndex          ID = 55
+	bemZMIndex        ID = 56
+	bezIndex          ID = 57
+	bezTZIndex        ID = 58
+	bgIndex           ID = 59
+	bgBGIndex         ID = 60
+	bhIndex           ID = 61
+	bmIndex           ID = 62
+	bmMLIndex         ID = 63
+	bnIndex           ID = 64
+	bnBDIndex         ID = 65
+	bnINIndex         ID = 66
+	boIndex           ID = 67
+	boCNIndex         ID = 68
+	boINIndex         ID = 69
+	brIndex           ID = 70
+	brFRIndex         ID = 71
+	brxIndex          ID = 72
+	brxINIndex        ID = 73
+	bsIndex           ID = 74
+	bsCyrlIndex       ID = 75
+	bsCyrlBAIndex     ID = 76
+	bsLatnIndex       ID = 77
+	bsLatnBAIndex     ID = 78
+	caIndex           ID = 79
+	caADIndex         ID = 80
+	caESIndex         ID = 81
+	caFRIndex         ID = 82
+	caITIndex         ID = 83
+	ccpIndex          ID = 84
+	ccpBDIndex        ID = 85
+	ccpINIndex        ID = 86
+	ceIndex           ID = 87
+	ceRUIndex         ID = 88
+	cggIndex          ID = 89
+	cggUGIndex        ID = 90
+	chrIndex          ID = 91
+	chrUSIndex        ID = 92
+	ckbIndex          ID = 93
+	ckbIQIndex        ID = 94
+	ckbIRIndex        ID = 95
+	csIndex           ID = 96
+	csCZIndex         ID = 97
+	cuIndex           ID = 98
+	cuRUIndex         ID = 99
+	cyIndex           ID = 100
+	cyGBIndex         ID = 101
+	daIndex           ID = 102
+	daDKIndex         ID = 103
+	daGLIndex         ID = 104
+	davIndex          ID = 105
+	davKEIndex        ID = 106
+	deIndex           ID = 107
+	deATIndex         ID = 108
+	deBEIndex         ID = 109
+	deCHIndex         ID = 110
+	deDEIndex         ID = 111
+	deITIndex         ID = 112
+	deLIIndex         ID = 113
+	deLUIndex         ID = 114
+	djeIndex          ID = 115
+	djeNEIndex        ID = 116
+	dsbIndex          ID = 117
+	dsbDEIndex        ID = 118
+	duaIndex          ID = 119
+	duaCMIndex        ID = 120
+	dvIndex           ID = 121
+	dyoIndex          ID = 122
+	dyoSNIndex        ID = 123
+	dzIndex           ID = 124
+	dzBTIndex         ID = 125
+	ebuIndex          ID = 126
+	ebuKEIndex        ID = 127
+	eeIndex           ID = 128
+	eeGHIndex         ID = 129
+	eeTGIndex         ID = 130
+	elIndex           ID = 131
+	elCYIndex         ID = 132
+	elGRIndex         ID = 133
+	enIndex           ID = 134
+	en001Index        ID = 135
+	en150Index        ID = 136
+	enAGIndex         ID = 137
+	enAIIndex         ID = 138
+	enASIndex         ID = 139
+	enATIndex         ID = 140
+	enAUIndex         ID = 141
+	enBBIndex         ID = 142
+	enBEIndex         ID = 143
+	enBIIndex         ID = 144
+	enBMIndex         ID = 145
+	enBSIndex         ID = 146
+	enBWIndex         ID = 147
+	enBZIndex         ID = 148
+	enCAIndex         ID = 149
+	enCCIndex         ID = 150
+	enCHIndex         ID = 151
+	enCKIndex         ID = 152
+	enCMIndex         ID = 153
+	enCXIndex         ID = 154
+	enCYIndex         ID = 155
+	enDEIndex         ID = 156
+	enDGIndex         ID = 157
+	enDKIndex         ID = 158
+	enDMIndex         ID = 159
+	enERIndex         ID = 160
+	enFIIndex         ID = 161
+	enFJIndex         ID = 162
+	enFKIndex         ID = 163
+	enFMIndex         ID = 164
+	enGBIndex         ID = 165
+	enGDIndex         ID = 166
+	enGGIndex         ID = 167
+	enGHIndex         ID = 168
+	enGIIndex         ID = 169
+	enGMIndex         ID = 170
+	enGUIndex         ID = 171
+	enGYIndex         ID = 172
+	enHKIndex         ID = 173
+	enIEIndex         ID = 174
+	enILIndex         ID = 175
+	enIMIndex         ID = 176
+	enINIndex         ID = 177
+	enIOIndex         ID = 178
+	enJEIndex         ID = 179
+	enJMIndex         ID = 180
+	enKEIndex         ID = 181
+	enKIIndex         ID = 182
+	enKNIndex         ID = 183
+	enKYIndex         ID = 184
+	enLCIndex         ID = 185
+	enLRIndex         ID = 186
+	enLSIndex         ID = 187
+	enMGIndex         ID = 188
+	enMHIndex         ID = 189
+	enMOIndex         ID = 190
+	enMPIndex         ID = 191
+	enMSIndex         ID = 192
+	enMTIndex         ID = 193
+	enMUIndex         ID = 194
+	enMWIndex         ID = 195
+	enMYIndex         ID = 196
+	enNAIndex         ID = 197
+	enNFIndex         ID = 198
+	enNGIndex         ID = 199
+	enNLIndex         ID = 200
+	enNRIndex         ID = 201
+	enNUIndex         ID = 202
+	enNZIndex         ID = 203
+	enPGIndex         ID = 204
+	enPHIndex         ID = 205
+	enPKIndex         ID = 206
+	enPNIndex         ID = 207
+	enPRIndex         ID = 208
+	enPWIndex         ID = 209
+	enRWIndex         ID = 210
+	enSBIndex         ID = 211
+	enSCIndex         ID = 212
+	enSDIndex         ID = 213
+	enSEIndex         ID = 214
+	enSGIndex         ID = 215
+	enSHIndex         ID = 216
+	enSIIndex         ID = 217
+	enSLIndex         ID = 218
+	enSSIndex         ID = 219
+	enSXIndex         ID = 220
+	enSZIndex         ID = 221
+	enTCIndex         ID = 222
+	enTKIndex         ID = 223
+	enTOIndex         ID = 224
+	enTTIndex         ID = 225
+	enTVIndex         ID = 226
+	enTZIndex         ID = 227
+	enUGIndex         ID = 228
+	enUMIndex         ID = 229
+	enUSIndex         ID = 230
+	enVCIndex         ID = 231
+	enVGIndex         ID = 232
+	enVIIndex         ID = 233
+	enVUIndex         ID = 234
+	enWSIndex         ID = 235
+	enZAIndex         ID = 236
+	enZMIndex         ID = 237
+	enZWIndex         ID = 238
+	eoIndex           ID = 239
+	eo001Index        ID = 240
+	esIndex           ID = 241
+	es419Index        ID = 242
+	esARIndex         ID = 243
+	esBOIndex         ID = 244
+	esBRIndex         ID = 245
+	esBZIndex         ID = 246
+	esCLIndex         ID = 247
+	esCOIndex         ID = 248
+	esCRIndex         ID = 249
+	esCUIndex         ID = 250
+	esDOIndex         ID = 251
+	esEAIndex         ID = 252
+	esECIndex         ID = 253
+	esESIndex         ID = 254
+	esGQIndex         ID = 255
+	esGTIndex         ID = 256
+	esHNIndex         ID = 257
+	esICIndex         ID = 258
+	esMXIndex         ID = 259
+	esNIIndex         ID = 260
+	esPAIndex         ID = 261
+	esPEIndex         ID = 262
+	esPHIndex         ID = 263
+	esPRIndex         ID = 264
+	esPYIndex         ID = 265
+	esSVIndex         ID = 266
+	esUSIndex         ID = 267
+	esUYIndex         ID = 268
+	esVEIndex         ID = 269
+	etIndex           ID = 270
+	etEEIndex         ID = 271
+	euIndex           ID = 272
+	euESIndex         ID = 273
+	ewoIndex          ID = 274
+	ewoCMIndex        ID = 275
+	faIndex           ID = 276
+	faAFIndex         ID = 277
+	faIRIndex         ID = 278
+	ffIndex           ID = 279
+	ffCMIndex         ID = 280
+	ffGNIndex         ID = 281
+	ffMRIndex         ID = 282
+	ffSNIndex         ID = 283
+	fiIndex           ID = 284
+	fiFIIndex         ID = 285
+	filIndex          ID = 286
+	filPHIndex        ID = 287
+	foIndex           ID = 288
+	foDKIndex         ID = 289
+	foFOIndex         ID = 290
+	frIndex           ID = 291
+	frBEIndex         ID = 292
+	frBFIndex         ID = 293
+	frBIIndex         ID = 294
+	frBJIndex         ID = 295
+	frBLIndex         ID = 296
+	frCAIndex         ID = 297
+	frCDIndex         ID = 298
+	frCFIndex         ID = 299
+	frCGIndex         ID = 300
+	frCHIndex         ID = 301
+	frCIIndex         ID = 302
+	frCMIndex         ID = 303
+	frDJIndex         ID = 304
+	frDZIndex         ID = 305
+	frFRIndex         ID = 306
+	frGAIndex         ID = 307
+	frGFIndex         ID = 308
+	frGNIndex         ID = 309
+	frGPIndex         ID = 310
+	frGQIndex         ID = 311
+	frHTIndex         ID = 312
+	frKMIndex         ID = 313
+	frLUIndex         ID = 314
+	frMAIndex         ID = 315
+	frMCIndex         ID = 316
+	frMFIndex         ID = 317
+	frMGIndex         ID = 318
+	frMLIndex         ID = 319
+	frMQIndex         ID = 320
+	frMRIndex         ID = 321
+	frMUIndex         ID = 322
+	frNCIndex         ID = 323
+	frNEIndex         ID = 324
+	frPFIndex         ID = 325
+	frPMIndex         ID = 326
+	frREIndex         ID = 327
+	frRWIndex         ID = 328
+	frSCIndex         ID = 329
+	frSNIndex         ID = 330
+	frSYIndex         ID = 331
+	frTDIndex         ID = 332
+	frTGIndex         ID = 333
+	frTNIndex         ID = 334
+	frVUIndex         ID = 335
+	frWFIndex         ID = 336
+	frYTIndex         ID = 337
+	furIndex          ID = 338
+	furITIndex        ID = 339
+	fyIndex           ID = 340
+	fyNLIndex         ID = 341
+	gaIndex           ID = 342
+	gaIEIndex         ID = 343
+	gdIndex           ID = 344
+	gdGBIndex         ID = 345
+	glIndex           ID = 346
+	glESIndex         ID = 347
+	gswIndex          ID = 348
+	gswCHIndex        ID = 349
+	gswFRIndex        ID = 350
+	gswLIIndex        ID = 351
+	guIndex           ID = 352
+	guINIndex         ID = 353
+	guwIndex          ID = 354
+	guzIndex          ID = 355
+	guzKEIndex        ID = 356
+	gvIndex           ID = 357
+	gvIMIndex         ID = 358
+	haIndex           ID = 359
+	haGHIndex         ID = 360
+	haNEIndex         ID = 361
+	haNGIndex         ID = 362
+	hawIndex          ID = 363
+	hawUSIndex        ID = 364
+	heIndex           ID = 365
+	heILIndex         ID = 366
+	hiIndex           ID = 367
+	hiINIndex         ID = 368
+	hrIndex           ID = 369
+	hrBAIndex         ID = 370
+	hrHRIndex         ID = 371
+	hsbIndex          ID = 372
+	hsbDEIndex        ID = 373
+	huIndex           ID = 374
+	huHUIndex         ID = 375
+	hyIndex           ID = 376
+	hyAMIndex         ID = 377
+	idIndex           ID = 378
+	idIDIndex         ID = 379
+	igIndex           ID = 380
+	igNGIndex         ID = 381
+	iiIndex           ID = 382
+	iiCNIndex         ID = 383
+	inIndex           ID = 384
+	ioIndex           ID = 385
+	isIndex           ID = 386
+	isISIndex         ID = 387
+	itIndex           ID = 388
+	itCHIndex         ID = 389
+	itITIndex         ID = 390
+	itSMIndex         ID = 391
+	itVAIndex         ID = 392
+	iuIndex           ID = 393
+	iwIndex           ID = 394
+	jaIndex           ID = 395
+	jaJPIndex         ID = 396
+	jboIndex          ID = 397
+	jgoIndex          ID = 398
+	jgoCMIndex        ID = 399
+	jiIndex           ID = 400
+	jmcIndex          ID = 401
+	jmcTZIndex        ID = 402
+	jvIndex           ID = 403
+	jwIndex           ID = 404
+	kaIndex           ID = 405
+	kaGEIndex         ID = 406
+	kabIndex          ID = 407
+	kabDZIndex        ID = 408
+	kajIndex          ID = 409
+	kamIndex          ID = 410
+	kamKEIndex        ID = 411
+	kcgIndex          ID = 412
+	kdeIndex          ID = 413
+	kdeTZIndex        ID = 414
+	keaIndex          ID = 415
+	keaCVIndex        ID = 416
+	khqIndex          ID = 417
+	khqMLIndex        ID = 418
+	kiIndex           ID = 419
+	kiKEIndex         ID = 420
+	kkIndex           ID = 421
+	kkKZIndex         ID = 422
+	kkjIndex          ID = 423
+	kkjCMIndex        ID = 424
+	klIndex           ID = 425
+	klGLIndex         ID = 426
+	klnIndex          ID = 427
+	klnKEIndex        ID = 428
+	kmIndex           ID = 429
+	kmKHIndex         ID = 430
+	knIndex           ID = 431
+	knINIndex         ID = 432
+	koIndex           ID = 433
+	koKPIndex         ID = 434
+	koKRIndex         ID = 435
+	kokIndex          ID = 436
+	kokINIndex        ID = 437
+	ksIndex           ID = 438
+	ksINIndex         ID = 439
+	ksbIndex          ID = 440
+	ksbTZIndex        ID = 441
+	ksfIndex          ID = 442
+	ksfCMIndex        ID = 443
+	kshIndex          ID = 444
+	kshDEIndex        ID = 445
+	kuIndex           ID = 446
+	kwIndex           ID = 447
+	kwGBIndex         ID = 448
+	kyIndex           ID = 449
+	kyKGIndex         ID = 450
+	lagIndex          ID = 451
+	lagTZIndex        ID = 452
+	lbIndex           ID = 453
+	lbLUIndex         ID = 454
+	lgIndex           ID = 455
+	lgUGIndex         ID = 456
+	lktIndex          ID = 457
+	lktUSIndex        ID = 458
+	lnIndex           ID = 459
+	lnAOIndex         ID = 460
+	lnCDIndex         ID = 461
+	lnCFIndex         ID = 462
+	lnCGIndex         ID = 463
+	loIndex           ID = 464
+	loLAIndex         ID = 465
+	lrcIndex          ID = 466
+	lrcIQIndex        ID = 467
+	lrcIRIndex        ID = 468
+	ltIndex           ID = 469
+	ltLTIndex         ID = 470
+	luIndex           ID = 471
+	luCDIndex         ID = 472
+	luoIndex          ID = 473
+	luoKEIndex        ID = 474
+	luyIndex          ID = 475
+	luyKEIndex        ID = 476
+	lvIndex           ID = 477
+	lvLVIndex         ID = 478
+	masIndex          ID = 479
+	masKEIndex        ID = 480
+	masTZIndex        ID = 481
+	merIndex          ID = 482
+	merKEIndex        ID = 483
+	mfeIndex          ID = 484
+	mfeMUIndex        ID = 485
+	mgIndex           ID = 486
+	mgMGIndex         ID = 487
+	mghIndex          ID = 488
+	mghMZIndex        ID = 489
+	mgoIndex          ID = 490
+	mgoCMIndex        ID = 491
+	mkIndex           ID = 492
+	mkMKIndex         ID = 493
+	mlIndex           ID = 494
+	mlINIndex         ID = 495
+	mnIndex           ID = 496
+	mnMNIndex         ID = 497
+	moIndex           ID = 498
+	mrIndex           ID = 499
+	mrINIndex         ID = 500
+	msIndex           ID = 501
+	msBNIndex         ID = 502
+	msMYIndex         ID = 503
+	msSGIndex         ID = 504
+	mtIndex           ID = 505
+	mtMTIndex         ID = 506
+	muaIndex          ID = 507
+	muaCMIndex        ID = 508
+	myIndex           ID = 509
+	myMMIndex         ID = 510
+	mznIndex          ID = 511
+	mznIRIndex        ID = 512
+	nahIndex          ID = 513
+	naqIndex          ID = 514
+	naqNAIndex        ID = 515
+	nbIndex           ID = 516
+	nbNOIndex         ID = 517
+	nbSJIndex         ID = 518
+	ndIndex           ID = 519
+	ndZWIndex         ID = 520
+	ndsIndex          ID = 521
+	ndsDEIndex        ID = 522
+	ndsNLIndex        ID = 523
+	neIndex           ID = 524
+	neINIndex         ID = 525
+	neNPIndex         ID = 526
+	nlIndex           ID = 527
+	nlAWIndex         ID = 528
+	nlBEIndex         ID = 529
+	nlBQIndex         ID = 530
+	nlCWIndex         ID = 531
+	nlNLIndex         ID = 532
+	nlSRIndex         ID = 533
+	nlSXIndex         ID = 534
+	nmgIndex          ID = 535
+	nmgCMIndex        ID = 536
+	nnIndex           ID = 537
+	nnNOIndex         ID = 538
+	nnhIndex          ID = 539
+	nnhCMIndex        ID = 540
+	noIndex           ID = 541
+	nqoIndex          ID = 542
+	nrIndex           ID = 543
+	nsoIndex          ID = 544
+	nusIndex          ID = 545
+	nusSSIndex        ID = 546
+	nyIndex           ID = 547
+	nynIndex          ID = 548
+	nynUGIndex        ID = 549
+	omIndex           ID = 550
+	omETIndex         ID = 551
+	omKEIndex         ID = 552
+	orIndex           ID = 553
+	orINIndex         ID = 554
+	osIndex           ID = 555
+	osGEIndex         ID = 556
+	osRUIndex         ID = 557
+	paIndex           ID = 558
+	paArabIndex       ID = 559
+	paArabPKIndex     ID = 560
+	paGuruIndex       ID = 561
+	paGuruINIndex     ID = 562
+	papIndex          ID = 563
+	plIndex           ID = 564
+	plPLIndex         ID = 565
+	prgIndex          ID = 566
+	prg001Index       ID = 567
+	psIndex           ID = 568
+	psAFIndex         ID = 569
+	ptIndex           ID = 570
+	ptAOIndex         ID = 571
+	ptBRIndex         ID = 572
+	ptCHIndex         ID = 573
+	ptCVIndex         ID = 574
+	ptGQIndex         ID = 575
+	ptGWIndex         ID = 576
+	ptLUIndex         ID = 577
+	ptMOIndex         ID = 578
+	ptMZIndex         ID = 579
+	ptPTIndex         ID = 580
+	ptSTIndex         ID = 581
+	ptTLIndex         ID = 582
+	quIndex           ID = 583
+	quBOIndex         ID = 584
+	quECIndex         ID = 585
+	quPEIndex         ID = 586
+	rmIndex           ID = 587
+	rmCHIndex         ID = 588
+	rnIndex           ID = 589
+	rnBIIndex         ID = 590
+	roIndex           ID = 591
+	roMDIndex         ID = 592
+	roROIndex         ID = 593
+	rofIndex          ID = 594
+	rofTZIndex        ID = 595
+	ruIndex           ID = 596
+	ruBYIndex         ID = 597
+	ruKGIndex         ID = 598
+	ruKZIndex         ID = 599
+	ruMDIndex         ID = 600
+	ruRUIndex         ID = 601
+	ruUAIndex         ID = 602
+	rwIndex           ID = 603
+	rwRWIndex         ID = 604
+	rwkIndex          ID = 605
+	rwkTZIndex        ID = 606
+	sahIndex          ID = 607
+	sahRUIndex        ID = 608
+	saqIndex          ID = 609
+	saqKEIndex        ID = 610
+	sbpIndex          ID = 611
+	sbpTZIndex        ID = 612
+	sdIndex           ID = 613
+	sdPKIndex         ID = 614
+	sdhIndex          ID = 615
+	seIndex           ID = 616
+	seFIIndex         ID = 617
+	seNOIndex         ID = 618
+	seSEIndex         ID = 619
+	sehIndex          ID = 620
+	sehMZIndex        ID = 621
+	sesIndex          ID = 622
+	sesMLIndex        ID = 623
+	sgIndex           ID = 624
+	sgCFIndex         ID = 625
+	shIndex           ID = 626
+	shiIndex          ID = 627
+	shiLatnIndex      ID = 628
+	shiLatnMAIndex    ID = 629
+	shiTfngIndex      ID = 630
+	shiTfngMAIndex    ID = 631
+	siIndex           ID = 632
+	siLKIndex         ID = 633
+	skIndex           ID = 634
+	skSKIndex         ID = 635
+	slIndex           ID = 636
+	slSIIndex         ID = 637
+	smaIndex          ID = 638
+	smiIndex          ID = 639
+	smjIndex          ID = 640
+	smnIndex          ID = 641
+	smnFIIndex        ID = 642
+	smsIndex          ID = 643
+	snIndex           ID = 644
+	snZWIndex         ID = 645
+	soIndex           ID = 646
+	soDJIndex         ID = 647
+	soETIndex         ID = 648
+	soKEIndex         ID = 649
+	soSOIndex         ID = 650
+	sqIndex           ID = 651
+	sqALIndex         ID = 652
+	sqMKIndex         ID = 653
+	sqXKIndex         ID = 654
+	srIndex           ID = 655
+	srCyrlIndex       ID = 656
+	srCyrlBAIndex     ID = 657
+	srCyrlMEIndex     ID = 658
+	srCyrlRSIndex     ID = 659
+	srCyrlXKIndex     ID = 660
+	srLatnIndex       ID = 661
+	srLatnBAIndex     ID = 662
+	srLatnMEIndex     ID = 663
+	srLatnRSIndex     ID = 664
+	srLatnXKIndex     ID = 665
+	ssIndex           ID = 666
+	ssyIndex          ID = 667
+	stIndex           ID = 668
+	svIndex           ID = 669
+	svAXIndex         ID = 670
+	svFIIndex         ID = 671
+	svSEIndex         ID = 672
+	swIndex           ID = 673
+	swCDIndex         ID = 674
+	swKEIndex         ID = 675
+	swTZIndex         ID = 676
+	swUGIndex         ID = 677
+	syrIndex          ID = 678
+	taIndex           ID = 679
+	taINIndex         ID = 680
+	taLKIndex         ID = 681
+	taMYIndex         ID = 682
+	taSGIndex         ID = 683
+	teIndex           ID = 684
+	teINIndex         ID = 685
+	teoIndex          ID = 686
+	teoKEIndex        ID = 687
+	teoUGIndex        ID = 688
+	tgIndex           ID = 689
+	tgTJIndex         ID = 690
+	thIndex           ID = 691
+	thTHIndex         ID = 692
+	tiIndex           ID = 693
+	tiERIndex         ID = 694
+	tiETIndex         ID = 695
+	tigIndex          ID = 696
+	tkIndex           ID = 697
+	tkTMIndex         ID = 698
+	tlIndex           ID = 699
+	tnIndex           ID = 700
+	toIndex           ID = 701
+	toTOIndex         ID = 702
+	trIndex           ID = 703
+	trCYIndex         ID = 704
+	trTRIndex         ID = 705
+	tsIndex           ID = 706
+	ttIndex           ID = 707
+	ttRUIndex         ID = 708
+	twqIndex          ID = 709
+	twqNEIndex        ID = 710
+	tzmIndex          ID = 711
+	tzmMAIndex        ID = 712
+	ugIndex           ID = 713
+	ugCNIndex         ID = 714
+	ukIndex           ID = 715
+	ukUAIndex         ID = 716
+	urIndex           ID = 717
+	urINIndex         ID = 718
+	urPKIndex         ID = 719
+	uzIndex           ID = 720
+	uzArabIndex       ID = 721
+	uzArabAFIndex     ID = 722
+	uzCyrlIndex       ID = 723
+	uzCyrlUZIndex     ID = 724
+	uzLatnIndex       ID = 725
+	uzLatnUZIndex     ID = 726
+	vaiIndex          ID = 727
+	vaiLatnIndex      ID = 728
+	vaiLatnLRIndex    ID = 729
+	vaiVaiiIndex      ID = 730
+	vaiVaiiLRIndex    ID = 731
+	veIndex           ID = 732
+	viIndex           ID = 733
+	viVNIndex         ID = 734
+	voIndex           ID = 735
+	vo001Index        ID = 736
+	vunIndex          ID = 737
+	vunTZIndex        ID = 738
+	waIndex           ID = 739
+	waeIndex          ID = 740
+	waeCHIndex        ID = 741
+	woIndex           ID = 742
+	woSNIndex         ID = 743
+	xhIndex           ID = 744
+	xogIndex          ID = 745
+	xogUGIndex        ID = 746
+	yavIndex          ID = 747
+	yavCMIndex        ID = 748
+	yiIndex           ID = 749
+	yi001Index        ID = 750
+	yoIndex           ID = 751
+	yoBJIndex         ID = 752
+	yoNGIndex         ID = 753
+	yueIndex          ID = 754
+	yueHansIndex      ID = 755
+	yueHansCNIndex    ID = 756
+	yueHantIndex      ID = 757
+	yueHantHKIndex    ID = 758
+	zghIndex          ID = 759
+	zghMAIndex        ID = 760
+	zhIndex           ID = 761
+	zhHansIndex       ID = 762
+	zhHansCNIndex     ID = 763
+	zhHansHKIndex     ID = 764
+	zhHansMOIndex     ID = 765
+	zhHansSGIndex     ID = 766
+	zhHantIndex       ID = 767
+	zhHantHKIndex     ID = 768
+	zhHantMOIndex     ID = 769
+	zhHantTWIndex     ID = 770
+	zuIndex           ID = 771
+	zuZAIndex         ID = 772
+	caESvalenciaIndex ID = 773
+	enUSuvaposixIndex ID = 774
+)
+
+var coreTags = []language.CompactCoreInfo{ // 773 elements
+	// Entry 0 - 1F
+	0x00000000, 0x01600000, 0x016000d3, 0x01600162,
+	0x01c00000, 0x01c00052, 0x02100000, 0x02100081,
+	0x02700000, 0x02700070, 0x03a00000, 0x03a00001,
+	0x03a00023, 0x03a00039, 0x03a00063, 0x03a00068,
+	0x03a0006c, 0x03a0006d, 0x03a0006e, 0x03a00098,
+	0x03a0009c, 0x03a000a2, 0x03a000a9, 0x03a000ad,
+	0x03a000b1, 0x03a000ba, 0x03a000bb, 0x03a000ca,
+	0x03a000e2, 0x03a000ee, 0x03a000f4, 0x03a00109,
+	// Entry 20 - 3F
+	0x03a0010c, 0x03a00116, 0x03a00118, 0x03a0011d,
+	0x03a00121, 0x03a00129, 0x03a0015f, 0x04000000,
+	0x04300000, 0x0430009a, 0x04400000, 0x04400130,
+	0x04800000, 0x0480006f, 0x05800000, 0x05820000,
+	0x05820032, 0x0585b000, 0x0585b032, 0x05e00000,
+	0x05e00052, 0x07100000, 0x07100047, 0x07500000,
+	0x07500163, 0x07900000, 0x07900130, 0x07e00000,
+	0x07e00038, 0x08200000, 0x0a000000, 0x0a0000c4,
+	// Entry 40 - 5F
+	0x0a500000, 0x0a500035, 0x0a50009a, 0x0a900000,
+	0x0a900053, 0x0a90009a, 0x0b200000, 0x0b200079,
+	0x0b500000, 0x0b50009a, 0x0b700000, 0x0b720000,
+	0x0b720033, 0x0b75b000, 0x0b75b033, 0x0d700000,
+	0x0d700022, 0x0d70006f, 0x0d700079, 0x0d70009f,
+	0x0db00000, 0x0db00035, 0x0db0009a, 0x0dc00000,
+	0x0dc00107, 0x0df00000, 0x0df00132, 0x0e500000,
+	0x0e500136, 0x0e900000, 0x0e90009c, 0x0e90009d,
+	// Entry 60 - 7F
+	0x0fa00000, 0x0fa0005f, 0x0fe00000, 0x0fe00107,
+	0x10000000, 0x1000007c, 0x10100000, 0x10100064,
+	0x10100083, 0x10800000, 0x108000a5, 0x10d00000,
+	0x10d0002e, 0x10d00036, 0x10d0004e, 0x10d00061,
+	0x10d0009f, 0x10d000b3, 0x10d000b8, 0x11700000,
+	0x117000d5, 0x11f00000, 0x11f00061, 0x12400000,
+	0x12400052, 0x12800000, 0x12b00000, 0x12b00115,
+	0x12d00000, 0x12d00043, 0x12f00000, 0x12f000a5,
+	// Entry 80 - 9F
+	0x13000000, 0x13000081, 0x13000123, 0x13600000,
+	0x1360005e, 0x13600088, 0x13900000, 0x13900001,
+	0x1390001a, 0x13900025, 0x13900026, 0x1390002d,
+	0x1390002e, 0x1390002f, 0x13900034, 0x13900036,
+	0x1390003a, 0x1390003d, 0x13900042, 0x13900046,
+	0x13900048, 0x13900049, 0x1390004a, 0x1390004e,
+	0x13900050, 0x13900052, 0x1390005d, 0x1390005e,
+	0x13900061, 0x13900062, 0x13900064, 0x13900065,
+	// Entry A0 - BF
+	0x1390006e, 0x13900073, 0x13900074, 0x13900075,
+	0x13900076, 0x1390007c, 0x1390007d, 0x13900080,
+	0x13900081, 0x13900082, 0x13900084, 0x1390008b,
+	0x1390008d, 0x1390008e, 0x13900097, 0x13900098,
+	0x13900099, 0x1390009a, 0x1390009b, 0x139000a0,
+	0x139000a1, 0x139000a5, 0x139000a8, 0x139000aa,
+	0x139000ae, 0x139000b2, 0x139000b5, 0x139000b6,
+	0x139000c0, 0x139000c1, 0x139000c7, 0x139000c8,
+	// Entry C0 - DF
+	0x139000cb, 0x139000cc, 0x139000cd, 0x139000cf,
+	0x139000d1, 0x139000d3, 0x139000d6, 0x139000d7,
+	0x139000da, 0x139000de, 0x139000e0, 0x139000e1,
+	0x139000e7, 0x139000e8, 0x139000e9, 0x139000ec,
+	0x139000ed, 0x139000f1, 0x13900108, 0x1390010a,
+	0x1390010b, 0x1390010c, 0x1390010d, 0x1390010e,
+	0x1390010f, 0x13900110, 0x13900113, 0x13900118,
+	0x1390011c, 0x1390011e, 0x13900120, 0x13900126,
+	// Entry E0 - FF
+	0x1390012a, 0x1390012d, 0x1390012e, 0x13900130,
+	0x13900132, 0x13900134, 0x13900136, 0x1390013a,
+	0x1390013d, 0x1390013e, 0x13900140, 0x13900143,
+	0x13900162, 0x13900163, 0x13900165, 0x13c00000,
+	0x13c00001, 0x13e00000, 0x13e0001f, 0x13e0002c,
+	0x13e0003f, 0x13e00041, 0x13e00048, 0x13e00051,
+	0x13e00054, 0x13e00057, 0x13e0005a, 0x13e00066,
+	0x13e00069, 0x13e0006a, 0x13e0006f, 0x13e00087,
+	// Entry 100 - 11F
+	0x13e0008a, 0x13e00090, 0x13e00095, 0x13e000d0,
+	0x13e000d9, 0x13e000e3, 0x13e000e5, 0x13e000e8,
+	0x13e000ed, 0x13e000f2, 0x13e0011b, 0x13e00136,
+	0x13e00137, 0x13e0013c, 0x14000000, 0x1400006b,
+	0x14500000, 0x1450006f, 0x14600000, 0x14600052,
+	0x14800000, 0x14800024, 0x1480009d, 0x14e00000,
+	0x14e00052, 0x14e00085, 0x14e000ca, 0x14e00115,
+	0x15100000, 0x15100073, 0x15300000, 0x153000e8,
+	// Entry 120 - 13F
+	0x15800000, 0x15800064, 0x15800077, 0x15e00000,
+	0x15e00036, 0x15e00037, 0x15e0003a, 0x15e0003b,
+	0x15e0003c, 0x15e00049, 0x15e0004b, 0x15e0004c,
+	0x15e0004d, 0x15e0004e, 0x15e0004f, 0x15e00052,
+	0x15e00063, 0x15e00068, 0x15e00079, 0x15e0007b,
+	0x15e0007f, 0x15e00085, 0x15e00086, 0x15e00087,
+	0x15e00092, 0x15e000a9, 0x15e000b8, 0x15e000bb,
+	0x15e000bc, 0x15e000bf, 0x15e000c0, 0x15e000c4,
+	// Entry 140 - 15F
+	0x15e000c9, 0x15e000ca, 0x15e000cd, 0x15e000d4,
+	0x15e000d5, 0x15e000e6, 0x15e000eb, 0x15e00103,
+	0x15e00108, 0x15e0010b, 0x15e00115, 0x15e0011d,
+	0x15e00121, 0x15e00123, 0x15e00129, 0x15e00140,
+	0x15e00141, 0x15e00160, 0x16900000, 0x1690009f,
+	0x16d00000, 0x16d000da, 0x16e00000, 0x16e00097,
+	0x17e00000, 0x17e0007c, 0x19000000, 0x1900006f,
+	0x1a300000, 0x1a30004e, 0x1a300079, 0x1a3000b3,
+	// Entry 160 - 17F
+	0x1a400000, 0x1a40009a, 0x1a900000, 0x1ab00000,
+	0x1ab000a5, 0x1ac00000, 0x1ac00099, 0x1b400000,
+	0x1b400081, 0x1b4000d5, 0x1b4000d7, 0x1b800000,
+	0x1b800136, 0x1bc00000, 0x1bc00098, 0x1be00000,
+	0x1be0009a, 0x1d100000, 0x1d100033, 0x1d100091,
+	0x1d200000, 0x1d200061, 0x1d500000, 0x1d500093,
+	0x1d700000, 0x1d700028, 0x1e100000, 0x1e100096,
+	0x1e700000, 0x1e7000d7, 0x1ea00000, 0x1ea00053,
+	// Entry 180 - 19F
+	0x1f300000, 0x1f500000, 0x1f800000, 0x1f80009e,
+	0x1f900000, 0x1f90004e, 0x1f90009f, 0x1f900114,
+	0x1f900139, 0x1fa00000, 0x1fb00000, 0x20000000,
+	0x200000a3, 0x20300000, 0x20700000, 0x20700052,
+	0x20800000, 0x20a00000, 0x20a00130, 0x20e00000,
+	0x20f00000, 0x21000000, 0x2100007e, 0x21200000,
+	0x21200068, 0x21600000, 0x21700000, 0x217000a5,
+	0x21f00000, 0x22300000, 0x22300130, 0x22700000,
+	// Entry 1A0 - 1BF
+	0x2270005b, 0x23400000, 0x234000c4, 0x23900000,
+	0x239000a5, 0x24200000, 0x242000af, 0x24400000,
+	0x24400052, 0x24500000, 0x24500083, 0x24600000,
+	0x246000a5, 0x24a00000, 0x24a000a7, 0x25100000,
+	0x2510009a, 0x25400000, 0x254000ab, 0x254000ac,
+	0x25600000, 0x2560009a, 0x26a00000, 0x26a0009a,
+	0x26b00000, 0x26b00130, 0x26d00000, 0x26d00052,
+	0x26e00000, 0x26e00061, 0x27400000, 0x28100000,
+	// Entry 1C0 - 1DF
+	0x2810007c, 0x28a00000, 0x28a000a6, 0x29100000,
+	0x29100130, 0x29500000, 0x295000b8, 0x2a300000,
+	0x2a300132, 0x2af00000, 0x2af00136, 0x2b500000,
+	0x2b50002a, 0x2b50004b, 0x2b50004c, 0x2b50004d,
+	0x2b800000, 0x2b8000b0, 0x2bf00000, 0x2bf0009c,
+	0x2bf0009d, 0x2c000000, 0x2c0000b7, 0x2c200000,
+	0x2c20004b, 0x2c400000, 0x2c4000a5, 0x2c500000,
+	0x2c5000a5, 0x2c700000, 0x2c7000b9, 0x2d100000,
+	// Entry 1E0 - 1FF
+	0x2d1000a5, 0x2d100130, 0x2e900000, 0x2e9000a5,
+	0x2ed00000, 0x2ed000cd, 0x2f100000, 0x2f1000c0,
+	0x2f200000, 0x2f2000d2, 0x2f400000, 0x2f400052,
+	0x2ff00000, 0x2ff000c3, 0x30400000, 0x3040009a,
+	0x30b00000, 0x30b000c6, 0x31000000, 0x31b00000,
+	0x31b0009a, 0x31f00000, 0x31f0003e, 0x31f000d1,
+	0x31f0010e, 0x32000000, 0x320000cc, 0x32500000,
+	0x32500052, 0x33100000, 0x331000c5, 0x33a00000,
+	// Entry 200 - 21F
+	0x33a0009d, 0x34100000, 0x34500000, 0x345000d3,
+	0x34700000, 0x347000db, 0x34700111, 0x34e00000,
+	0x34e00165, 0x35000000, 0x35000061, 0x350000da,
+	0x35100000, 0x3510009a, 0x351000dc, 0x36700000,
+	0x36700030, 0x36700036, 0x36700040, 0x3670005c,
+	0x367000da, 0x36700117, 0x3670011c, 0x36800000,
+	0x36800052, 0x36a00000, 0x36a000db, 0x36c00000,
+	0x36c00052, 0x36f00000, 0x37500000, 0x37600000,
+	// Entry 220 - 23F
+	0x37a00000, 0x38000000, 0x38000118, 0x38700000,
+	0x38900000, 0x38900132, 0x39000000, 0x39000070,
+	0x390000a5, 0x39500000, 0x3950009a, 0x39800000,
+	0x3980007e, 0x39800107, 0x39d00000, 0x39d05000,
+	0x39d050e9, 0x39d36000, 0x39d3609a, 0x3a100000,
+	0x3b300000, 0x3b3000ea, 0x3bd00000, 0x3bd00001,
+	0x3be00000, 0x3be00024, 0x3c000000, 0x3c00002a,
+	0x3c000041, 0x3c00004e, 0x3c00005b, 0x3c000087,
+	// Entry 240 - 25F
+	0x3c00008c, 0x3c0000b8, 0x3c0000c7, 0x3c0000d2,
+	0x3c0000ef, 0x3c000119, 0x3c000127, 0x3c400000,
+	0x3c40003f, 0x3c40006a, 0x3c4000e5, 0x3d400000,
+	0x3d40004e, 0x3d900000, 0x3d90003a, 0x3dc00000,
+	0x3dc000bd, 0x3dc00105, 0x3de00000, 0x3de00130,
+	0x3e200000, 0x3e200047, 0x3e2000a6, 0x3e2000af,
+	0x3e2000bd, 0x3e200107, 0x3e200131, 0x3e500000,
+	0x3e500108, 0x3e600000, 0x3e600130, 0x3eb00000,
+	// Entry 260 - 27F
+	0x3eb00107, 0x3ec00000, 0x3ec000a5, 0x3f300000,
+	0x3f300130, 0x3fa00000, 0x3fa000e9, 0x3fc00000,
+	0x3fd00000, 0x3fd00073, 0x3fd000db, 0x3fd0010d,
+	0x3ff00000, 0x3ff000d2, 0x40100000, 0x401000c4,
+	0x40200000, 0x4020004c, 0x40700000, 0x40800000,
+	0x4085b000, 0x4085b0bb, 0x408eb000, 0x408eb0bb,
+	0x40c00000, 0x40c000b4, 0x41200000, 0x41200112,
+	0x41600000, 0x41600110, 0x41c00000, 0x41d00000,
+	// Entry 280 - 29F
+	0x41e00000, 0x41f00000, 0x41f00073, 0x42200000,
+	0x42300000, 0x42300165, 0x42900000, 0x42900063,
+	0x42900070, 0x429000a5, 0x42900116, 0x43100000,
+	0x43100027, 0x431000c3, 0x4310014e, 0x43200000,
+	0x43220000, 0x43220033, 0x432200be, 0x43220106,
+	0x4322014e, 0x4325b000, 0x4325b033, 0x4325b0be,
+	0x4325b106, 0x4325b14e, 0x43700000, 0x43a00000,
+	0x43b00000, 0x44400000, 0x44400031, 0x44400073,
+	// Entry 2A0 - 2BF
+	0x4440010d, 0x44500000, 0x4450004b, 0x445000a5,
+	0x44500130, 0x44500132, 0x44e00000, 0x45000000,
+	0x4500009a, 0x450000b4, 0x450000d1, 0x4500010e,
+	0x46100000, 0x4610009a, 0x46400000, 0x464000a5,
+	0x46400132, 0x46700000, 0x46700125, 0x46b00000,
+	0x46b00124, 0x46f00000, 0x46f0006e, 0x46f00070,
+	0x47100000, 0x47600000, 0x47600128, 0x47a00000,
+	0x48000000, 0x48200000, 0x4820012a, 0x48a00000,
+	// Entry 2C0 - 2DF
+	0x48a0005e, 0x48a0012c, 0x48e00000, 0x49400000,
+	0x49400107, 0x4a400000, 0x4a4000d5, 0x4a900000,
+	0x4a9000bb, 0x4ac00000, 0x4ac00053, 0x4ae00000,
+	0x4ae00131, 0x4b400000, 0x4b40009a, 0x4b4000e9,
+	0x4bc00000, 0x4bc05000, 0x4bc05024, 0x4bc20000,
+	0x4bc20138, 0x4bc5b000, 0x4bc5b138, 0x4be00000,
+	0x4be5b000, 0x4be5b0b5, 0x4bef4000, 0x4bef40b5,
+	0x4c000000, 0x4c300000, 0x4c30013f, 0x4c900000,
+	// Entry 2E0 - 2FF
+	0x4c900001, 0x4cc00000, 0x4cc00130, 0x4ce00000,
+	0x4cf00000, 0x4cf0004e, 0x4e500000, 0x4e500115,
+	0x4f200000, 0x4fb00000, 0x4fb00132, 0x50900000,
+	0x50900052, 0x51200000, 0x51200001, 0x51800000,
+	0x5180003b, 0x518000d7, 0x51f00000, 0x51f3b000,
+	0x51f3b053, 0x51f3c000, 0x51f3c08e, 0x52800000,
+	0x528000bb, 0x52900000, 0x5293b000, 0x5293b053,
+	0x5293b08e, 0x5293b0c7, 0x5293b10e, 0x5293c000,
+	// Entry 300 - 31F
+	0x5293c08e, 0x5293c0c7, 0x5293c12f, 0x52f00000,
+	0x52f00162,
+} // Size: 3116 bytes
+
+const specialTagsStr string = "ca-ES-valencia en-US-u-va-posix"
+
+// Total table size 3147 bytes (3KiB); checksum: 5A8FFFA5
diff --git a/vendor/golang.org/x/text/internal/language/compact/tags.go b/vendor/golang.org/x/text/internal/language/compact/tags.go
new file mode 100644
index 000000000..ca135d295
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/compact/tags.go
@@ -0,0 +1,91 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package compact
+
+var (
+	und = Tag{}
+
+	Und Tag = Tag{}
+
+	Afrikaans            Tag = Tag{language: afIndex, locale: afIndex}
+	Amharic              Tag = Tag{language: amIndex, locale: amIndex}
+	Arabic               Tag = Tag{language: arIndex, locale: arIndex}
+	ModernStandardArabic Tag = Tag{language: ar001Index, locale: ar001Index}
+	Azerbaijani          Tag = Tag{language: azIndex, locale: azIndex}
+	Bulgarian            Tag = Tag{language: bgIndex, locale: bgIndex}
+	Bengali              Tag = Tag{language: bnIndex, locale: bnIndex}
+	Catalan              Tag = Tag{language: caIndex, locale: caIndex}
+	Czech                Tag = Tag{language: csIndex, locale: csIndex}
+	Danish               Tag = Tag{language: daIndex, locale: daIndex}
+	German               Tag = Tag{language: deIndex, locale: deIndex}
+	Greek                Tag = Tag{language: elIndex, locale: elIndex}
+	English              Tag = Tag{language: enIndex, locale: enIndex}
+	AmericanEnglish      Tag = Tag{language: enUSIndex, locale: enUSIndex}
+	BritishEnglish       Tag = Tag{language: enGBIndex, locale: enGBIndex}
+	Spanish              Tag = Tag{language: esIndex, locale: esIndex}
+	EuropeanSpanish      Tag = Tag{language: esESIndex, locale: esESIndex}
+	LatinAmericanSpanish Tag = Tag{language: es419Index, locale: es419Index}
+	Estonian             Tag = Tag{language: etIndex, locale: etIndex}
+	Persian              Tag = Tag{language: faIndex, locale: faIndex}
+	Finnish              Tag = Tag{language: fiIndex, locale: fiIndex}
+	Filipino             Tag = Tag{language: filIndex, locale: filIndex}
+	French               Tag = Tag{language: frIndex, locale: frIndex}
+	CanadianFrench       Tag = Tag{language: frCAIndex, locale: frCAIndex}
+	Gujarati             Tag = Tag{language: guIndex, locale: guIndex}
+	Hebrew               Tag = Tag{language: heIndex, locale: heIndex}
+	Hindi                Tag = Tag{language: hiIndex, locale: hiIndex}
+	Croatian             Tag = Tag{language: hrIndex, locale: hrIndex}
+	Hungarian            Tag = Tag{language: huIndex, locale: huIndex}
+	Armenian             Tag = Tag{language: hyIndex, locale: hyIndex}
+	Indonesian           Tag = Tag{language: idIndex, locale: idIndex}
+	Icelandic            Tag = Tag{language: isIndex, locale: isIndex}
+	Italian              Tag = Tag{language: itIndex, locale: itIndex}
+	Japanese             Tag = Tag{language: jaIndex, locale: jaIndex}
+	Georgian             Tag = Tag{language: kaIndex, locale: kaIndex}
+	Kazakh               Tag = Tag{language: kkIndex, locale: kkIndex}
+	Khmer                Tag = Tag{language: kmIndex, locale: kmIndex}
+	Kannada              Tag = Tag{language: knIndex, locale: knIndex}
+	Korean               Tag = Tag{language: koIndex, locale: koIndex}
+	Kirghiz              Tag = Tag{language: kyIndex, locale: kyIndex}
+	Lao                  Tag = Tag{language: loIndex, locale: loIndex}
+	Lithuanian           Tag = Tag{language: ltIndex, locale: ltIndex}
+	Latvian              Tag = Tag{language: lvIndex, locale: lvIndex}
+	Macedonian           Tag = Tag{language: mkIndex, locale: mkIndex}
+	Malayalam            Tag = Tag{language: mlIndex, locale: mlIndex}
+	Mongolian            Tag = Tag{language: mnIndex, locale: mnIndex}
+	Marathi              Tag = Tag{language: mrIndex, locale: mrIndex}
+	Malay                Tag = Tag{language: msIndex, locale: msIndex}
+	Burmese              Tag = Tag{language: myIndex, locale: myIndex}
+	Nepali               Tag = Tag{language: neIndex, locale: neIndex}
+	Dutch                Tag = Tag{language: nlIndex, locale: nlIndex}
+	Norwegian            Tag = Tag{language: noIndex, locale: noIndex}
+	Punjabi              Tag = Tag{language: paIndex, locale: paIndex}
+	Polish               Tag = Tag{language: plIndex, locale: plIndex}
+	Portuguese           Tag = Tag{language: ptIndex, locale: ptIndex}
+	BrazilianPortuguese  Tag = Tag{language: ptBRIndex, locale: ptBRIndex}
+	EuropeanPortuguese   Tag = Tag{language: ptPTIndex, locale: ptPTIndex}
+	Romanian             Tag = Tag{language: roIndex, locale: roIndex}
+	Russian              Tag = Tag{language: ruIndex, locale: ruIndex}
+	Sinhala              Tag = Tag{language: siIndex, locale: siIndex}
+	Slovak               Tag = Tag{language: skIndex, locale: skIndex}
+	Slovenian            Tag = Tag{language: slIndex, locale: slIndex}
+	Albanian             Tag = Tag{language: sqIndex, locale: sqIndex}
+	Serbian              Tag = Tag{language: srIndex, locale: srIndex}
+	SerbianLatin         Tag = Tag{language: srLatnIndex, locale: srLatnIndex}
+	Swedish              Tag = Tag{language: svIndex, locale: svIndex}
+	Swahili              Tag = Tag{language: swIndex, locale: swIndex}
+	Tamil                Tag = Tag{language: taIndex, locale: taIndex}
+	Telugu               Tag = Tag{language: teIndex, locale: teIndex}
+	Thai                 Tag = Tag{language: thIndex, locale: thIndex}
+	Turkish              Tag = Tag{language: trIndex, locale: trIndex}
+	Ukrainian            Tag = Tag{language: ukIndex, locale: ukIndex}
+	Urdu                 Tag = Tag{language: urIndex, locale: urIndex}
+	Uzbek                Tag = Tag{language: uzIndex, locale: uzIndex}
+	Vietnamese           Tag = Tag{language: viIndex, locale: viIndex}
+	Chinese              Tag = Tag{language: zhIndex, locale: zhIndex}
+	SimplifiedChinese    Tag = Tag{language: zhHansIndex, locale: zhHansIndex}
+	TraditionalChinese   Tag = Tag{language: zhHantIndex, locale: zhHantIndex}
+	Zulu                 Tag = Tag{language: zuIndex, locale: zuIndex}
+)
diff --git a/vendor/golang.org/x/text/internal/language/compose.go b/vendor/golang.org/x/text/internal/language/compose.go
new file mode 100644
index 000000000..4ae78e0fa
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/compose.go
@@ -0,0 +1,167 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+import (
+	"sort"
+	"strings"
+)
+
+// A Builder allows constructing a Tag from individual components.
+// Its main user is Compose in the top-level language package.
+type Builder struct {
+	Tag Tag
+
+	private    string // the x extension
+	variants   []string
+	extensions []string
+}
+
+// Make returns a new Tag from the current settings.
+func (b *Builder) Make() Tag {
+	t := b.Tag
+
+	if len(b.extensions) > 0 || len(b.variants) > 0 {
+		sort.Sort(sortVariants(b.variants))
+		sort.Strings(b.extensions)
+
+		if b.private != "" {
+			b.extensions = append(b.extensions, b.private)
+		}
+		n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
+		buf := make([]byte, n)
+		p := t.genCoreBytes(buf)
+		t.pVariant = byte(p)
+		p += appendTokens(buf[p:], b.variants...)
+		t.pExt = uint16(p)
+		p += appendTokens(buf[p:], b.extensions...)
+		t.str = string(buf[:p])
+		// We may not always need to remake the string, but when or when not
+		// to do so is rather tricky.
+		scan := makeScanner(buf[:p])
+		t, _ = parse(&scan, "")
+		return t
+
+	} else if b.private != "" {
+		t.str = b.private
+		t.RemakeString()
+	}
+	return t
+}
+
+// SetTag copies all the settings from a given Tag. Any previously set values
+// are discarded.
+func (b *Builder) SetTag(t Tag) {
+	b.Tag.LangID = t.LangID
+	b.Tag.RegionID = t.RegionID
+	b.Tag.ScriptID = t.ScriptID
+	// TODO: optimize
+	b.variants = b.variants[:0]
+	if variants := t.Variants(); variants != "" {
+		for _, vr := range strings.Split(variants[1:], "-") {
+			b.variants = append(b.variants, vr)
+		}
+	}
+	b.extensions, b.private = b.extensions[:0], ""
+	for _, e := range t.Extensions() {
+		b.AddExt(e)
+	}
+}
+
+// AddExt adds extension e to the tag. e must be a valid extension as returned
+// by Tag.Extension. If the extension already exists, it will be discarded,
+// except for a -u extension, where non-existing key-type pairs will added.
+func (b *Builder) AddExt(e string) {
+	if e[0] == 'x' {
+		if b.private == "" {
+			b.private = e
+		}
+		return
+	}
+	for i, s := range b.extensions {
+		if s[0] == e[0] {
+			if e[0] == 'u' {
+				b.extensions[i] += e[1:]
+			}
+			return
+		}
+	}
+	b.extensions = append(b.extensions, e)
+}
+
+// SetExt sets the extension e to the tag. e must be a valid extension as
+// returned by Tag.Extension. If the extension already exists, it will be
+// overwritten, except for a -u extension, where the individual key-type pairs
+// will be set.
+func (b *Builder) SetExt(e string) {
+	if e[0] == 'x' {
+		b.private = e
+		return
+	}
+	for i, s := range b.extensions {
+		if s[0] == e[0] {
+			if e[0] == 'u' {
+				b.extensions[i] = e + s[1:]
+			} else {
+				b.extensions[i] = e
+			}
+			return
+		}
+	}
+	b.extensions = append(b.extensions, e)
+}
+
+// AddVariant adds any number of variants.
+func (b *Builder) AddVariant(v ...string) {
+	for _, v := range v {
+		if v != "" {
+			b.variants = append(b.variants, v)
+		}
+	}
+}
+
+// ClearVariants removes any variants previously added, including those
+// copied from a Tag in SetTag.
+func (b *Builder) ClearVariants() {
+	b.variants = b.variants[:0]
+}
+
+// ClearExtensions removes any extensions previously added, including those
+// copied from a Tag in SetTag.
+func (b *Builder) ClearExtensions() {
+	b.private = ""
+	b.extensions = b.extensions[:0]
+}
+
+func tokenLen(token ...string) (n int) {
+	for _, t := range token {
+		n += len(t) + 1
+	}
+	return
+}
+
+func appendTokens(b []byte, token ...string) int {
+	p := 0
+	for _, t := range token {
+		b[p] = '-'
+		copy(b[p+1:], t)
+		p += 1 + len(t)
+	}
+	return p
+}
+
+type sortVariants []string
+
+func (s sortVariants) Len() int {
+	return len(s)
+}
+
+func (s sortVariants) Swap(i, j int) {
+	s[j], s[i] = s[i], s[j]
+}
+
+func (s sortVariants) Less(i, j int) bool {
+	return variantIndex[s[i]] < variantIndex[s[j]]
+}
diff --git a/vendor/golang.org/x/text/internal/language/coverage.go b/vendor/golang.org/x/text/internal/language/coverage.go
new file mode 100644
index 000000000..9b20b88fe
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/coverage.go
@@ -0,0 +1,28 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+// BaseLanguages returns the list of all supported base languages. It generates
+// the list by traversing the internal structures.
+func BaseLanguages() []Language {
+	base := make([]Language, 0, NumLanguages)
+	for i := 0; i < langNoIndexOffset; i++ {
+		// We included "und" already for the value 0.
+		if i != nonCanonicalUnd {
+			base = append(base, Language(i))
+		}
+	}
+	i := langNoIndexOffset
+	for _, v := range langNoIndex {
+		for k := 0; k < 8; k++ {
+			if v&1 == 1 {
+				base = append(base, Language(i))
+			}
+			v >>= 1
+			i++
+		}
+	}
+	return base
+}
diff --git a/vendor/golang.org/x/text/internal/language/language.go b/vendor/golang.org/x/text/internal/language/language.go
new file mode 100644
index 000000000..09d41c736
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/language.go
@@ -0,0 +1,627 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go gen_common.go -output tables.go
+
+package language // import "golang.org/x/text/internal/language"
+
+// TODO: Remove above NOTE after:
+// - verifying that tables are dropped correctly (most notably matcher tables).
+
+import (
+	"errors"
+	"fmt"
+	"strings"
+)
+
+const (
+	// maxCoreSize is the maximum size of a BCP 47 tag without variants and
+	// extensions. Equals max lang (3) + script (4) + max reg (3) + 2 dashes.
+	maxCoreSize = 12
+
+	// max99thPercentileSize is a somewhat arbitrary buffer size that presumably
+	// is large enough to hold at least 99% of the BCP 47 tags.
+	max99thPercentileSize = 32
+
+	// maxSimpleUExtensionSize is the maximum size of a -u extension with one
+	// key-type pair. Equals len("-u-") + key (2) + dash + max value (8).
+	maxSimpleUExtensionSize = 14
+)
+
+// Tag represents a BCP 47 language tag. It is used to specify an instance of a
+// specific language or locale. All language tag values are guaranteed to be
+// well-formed. The zero value of Tag is Und.
+type Tag struct {
+	// TODO: the following fields have the form TagTypeID. This name is chosen
+	// to allow refactoring the public package without conflicting with its
+	// Base, Script, and Region methods. Once the transition is fully completed
+	// the ID can be stripped from the name.
+
+	LangID   Language
+	RegionID Region
+	// TODO: we will soon run out of positions for ScriptID. Idea: instead of
+	// storing lang, region, and ScriptID codes, store only the compact index and
+	// have a lookup table from this code to its expansion. This greatly speeds
+	// up table lookup, speed up common variant cases.
+	// This will also immediately free up 3 extra bytes. Also, the pVariant
+	// field can now be moved to the lookup table, as the compact index uniquely
+	// determines the offset of a possible variant.
+	ScriptID Script
+	pVariant byte   // offset in str, includes preceding '-'
+	pExt     uint16 // offset of first extension, includes preceding '-'
+
+	// str is the string representation of the Tag. It will only be used if the
+	// tag has variants or extensions.
+	str string
+}
+
+// Make is a convenience wrapper for Parse that omits the error.
+// In case of an error, a sensible default is returned.
+func Make(s string) Tag {
+	t, _ := Parse(s)
+	return t
+}
+
+// Raw returns the raw base language, script and region, without making an
+// attempt to infer their values.
+// TODO: consider removing
+func (t Tag) Raw() (b Language, s Script, r Region) {
+	return t.LangID, t.ScriptID, t.RegionID
+}
+
+// equalTags compares language, script and region subtags only.
+func (t Tag) equalTags(a Tag) bool {
+	return t.LangID == a.LangID && t.ScriptID == a.ScriptID && t.RegionID == a.RegionID
+}
+
+// IsRoot returns true if t is equal to language "und".
+func (t Tag) IsRoot() bool {
+	if int(t.pVariant) < len(t.str) {
+		return false
+	}
+	return t.equalTags(Und)
+}
+
+// IsPrivateUse reports whether the Tag consists solely of an IsPrivateUse use
+// tag.
+func (t Tag) IsPrivateUse() bool {
+	return t.str != "" && t.pVariant == 0
+}
+
+// RemakeString is used to update t.str in case lang, script or region changed.
+// It is assumed that pExt and pVariant still point to the start of the
+// respective parts.
+func (t *Tag) RemakeString() {
+	if t.str == "" {
+		return
+	}
+	extra := t.str[t.pVariant:]
+	if t.pVariant > 0 {
+		extra = extra[1:]
+	}
+	if t.equalTags(Und) && strings.HasPrefix(extra, "x-") {
+		t.str = extra
+		t.pVariant = 0
+		t.pExt = 0
+		return
+	}
+	var buf [max99thPercentileSize]byte // avoid extra memory allocation in most cases.
+	b := buf[:t.genCoreBytes(buf[:])]
+	if extra != "" {
+		diff := len(b) - int(t.pVariant)
+		b = append(b, '-')
+		b = append(b, extra...)
+		t.pVariant = uint8(int(t.pVariant) + diff)
+		t.pExt = uint16(int(t.pExt) + diff)
+	} else {
+		t.pVariant = uint8(len(b))
+		t.pExt = uint16(len(b))
+	}
+	t.str = string(b)
+}
+
+// genCoreBytes writes a string for the base languages, script and region tags
+// to the given buffer and returns the number of bytes written. It will never
+// write more than maxCoreSize bytes.
+func (t *Tag) genCoreBytes(buf []byte) int {
+	n := t.LangID.StringToBuf(buf[:])
+	if t.ScriptID != 0 {
+		n += copy(buf[n:], "-")
+		n += copy(buf[n:], t.ScriptID.String())
+	}
+	if t.RegionID != 0 {
+		n += copy(buf[n:], "-")
+		n += copy(buf[n:], t.RegionID.String())
+	}
+	return n
+}
+
+// String returns the canonical string representation of the language tag.
+func (t Tag) String() string {
+	if t.str != "" {
+		return t.str
+	}
+	if t.ScriptID == 0 && t.RegionID == 0 {
+		return t.LangID.String()
+	}
+	buf := [maxCoreSize]byte{}
+	return string(buf[:t.genCoreBytes(buf[:])])
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (t Tag) MarshalText() (text []byte, err error) {
+	if t.str != "" {
+		text = append(text, t.str...)
+	} else if t.ScriptID == 0 && t.RegionID == 0 {
+		text = append(text, t.LangID.String()...)
+	} else {
+		buf := [maxCoreSize]byte{}
+		text = buf[:t.genCoreBytes(buf[:])]
+	}
+	return text, nil
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (t *Tag) UnmarshalText(text []byte) error {
+	tag, err := Parse(string(text))
+	*t = tag
+	return err
+}
+
+// Variants returns the part of the tag holding all variants or the empty string
+// if there are no variants defined.
+func (t Tag) Variants() string {
+	if t.pVariant == 0 {
+		return ""
+	}
+	return t.str[t.pVariant:t.pExt]
+}
+
+// VariantOrPrivateUseTags returns variants or private use tags.
+func (t Tag) VariantOrPrivateUseTags() string {
+	if t.pExt > 0 {
+		return t.str[t.pVariant:t.pExt]
+	}
+	return t.str[t.pVariant:]
+}
+
+// HasString reports whether this tag defines more than just the raw
+// components.
+func (t Tag) HasString() bool {
+	return t.str != ""
+}
+
+// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
+// specific language are substituted with fields from the parent language.
+// The parent for a language may change for newer versions of CLDR.
+func (t Tag) Parent() Tag {
+	if t.str != "" {
+		// Strip the variants and extensions.
+		b, s, r := t.Raw()
+		t = Tag{LangID: b, ScriptID: s, RegionID: r}
+		if t.RegionID == 0 && t.ScriptID != 0 && t.LangID != 0 {
+			base, _ := addTags(Tag{LangID: t.LangID})
+			if base.ScriptID == t.ScriptID {
+				return Tag{LangID: t.LangID}
+			}
+		}
+		return t
+	}
+	if t.LangID != 0 {
+		if t.RegionID != 0 {
+			maxScript := t.ScriptID
+			if maxScript == 0 {
+				max, _ := addTags(t)
+				maxScript = max.ScriptID
+			}
+
+			for i := range parents {
+				if Language(parents[i].lang) == t.LangID && Script(parents[i].maxScript) == maxScript {
+					for _, r := range parents[i].fromRegion {
+						if Region(r) == t.RegionID {
+							return Tag{
+								LangID:   t.LangID,
+								ScriptID: Script(parents[i].script),
+								RegionID: Region(parents[i].toRegion),
+							}
+						}
+					}
+				}
+			}
+
+			// Strip the script if it is the default one.
+			base, _ := addTags(Tag{LangID: t.LangID})
+			if base.ScriptID != maxScript {
+				return Tag{LangID: t.LangID, ScriptID: maxScript}
+			}
+			return Tag{LangID: t.LangID}
+		} else if t.ScriptID != 0 {
+			// The parent for an base-script pair with a non-default script is
+			// "und" instead of the base language.
+			base, _ := addTags(Tag{LangID: t.LangID})
+			if base.ScriptID != t.ScriptID {
+				return Und
+			}
+			return Tag{LangID: t.LangID}
+		}
+	}
+	return Und
+}
+
+// ParseExtension parses s as an extension and returns it on success.
+func ParseExtension(s string) (ext string, err error) {
+	defer func() {
+		if recover() != nil {
+			ext = ""
+			err = ErrSyntax
+		}
+	}()
+
+	scan := makeScannerString(s)
+	var end int
+	if n := len(scan.token); n != 1 {
+		return "", ErrSyntax
+	}
+	scan.toLower(0, len(scan.b))
+	end = parseExtension(&scan)
+	if end != len(s) {
+		return "", ErrSyntax
+	}
+	return string(scan.b), nil
+}
+
+// HasVariants reports whether t has variants.
+func (t Tag) HasVariants() bool {
+	return uint16(t.pVariant) < t.pExt
+}
+
+// HasExtensions reports whether t has extensions.
+func (t Tag) HasExtensions() bool {
+	return int(t.pExt) < len(t.str)
+}
+
+// Extension returns the extension of type x for tag t. It will return
+// false for ok if t does not have the requested extension. The returned
+// extension will be invalid in this case.
+func (t Tag) Extension(x byte) (ext string, ok bool) {
+	for i := int(t.pExt); i < len(t.str)-1; {
+		var ext string
+		i, ext = getExtension(t.str, i)
+		if ext[0] == x {
+			return ext, true
+		}
+	}
+	return "", false
+}
+
+// Extensions returns all extensions of t.
+func (t Tag) Extensions() []string {
+	e := []string{}
+	for i := int(t.pExt); i < len(t.str)-1; {
+		var ext string
+		i, ext = getExtension(t.str, i)
+		e = append(e, ext)
+	}
+	return e
+}
+
+// TypeForKey returns the type associated with the given key, where key and type
+// are of the allowed values defined for the Unicode locale extension ('u') in
+// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
+// TypeForKey will traverse the inheritance chain to get the correct value.
+//
+// If there are multiple types associated with a key, only the first will be
+// returned. If there is no type associated with a key, it returns the empty
+// string.
+func (t Tag) TypeForKey(key string) string {
+	if _, start, end, _ := t.findTypeForKey(key); end != start {
+		s := t.str[start:end]
+		if p := strings.IndexByte(s, '-'); p >= 0 {
+			s = s[:p]
+		}
+		return s
+	}
+	return ""
+}
+
+var (
+	errPrivateUse       = errors.New("cannot set a key on a private use tag")
+	errInvalidArguments = errors.New("invalid key or type")
+)
+
+// SetTypeForKey returns a new Tag with the key set to type, where key and type
+// are of the allowed values defined for the Unicode locale extension ('u') in
+// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
+// An empty value removes an existing pair with the same key.
+func (t Tag) SetTypeForKey(key, value string) (Tag, error) {
+	if t.IsPrivateUse() {
+		return t, errPrivateUse
+	}
+	if len(key) != 2 {
+		return t, errInvalidArguments
+	}
+
+	// Remove the setting if value is "".
+	if value == "" {
+		start, sep, end, _ := t.findTypeForKey(key)
+		if start != sep {
+			// Remove a possible empty extension.
+			switch {
+			case t.str[start-2] != '-': // has previous elements.
+			case end == len(t.str), // end of string
+				end+2 < len(t.str) && t.str[end+2] == '-': // end of extension
+				start -= 2
+			}
+			if start == int(t.pVariant) && end == len(t.str) {
+				t.str = ""
+				t.pVariant, t.pExt = 0, 0
+			} else {
+				t.str = fmt.Sprintf("%s%s", t.str[:start], t.str[end:])
+			}
+		}
+		return t, nil
+	}
+
+	if len(value) < 3 || len(value) > 8 {
+		return t, errInvalidArguments
+	}
+
+	var (
+		buf    [maxCoreSize + maxSimpleUExtensionSize]byte
+		uStart int // start of the -u extension.
+	)
+
+	// Generate the tag string if needed.
+	if t.str == "" {
+		uStart = t.genCoreBytes(buf[:])
+		buf[uStart] = '-'
+		uStart++
+	}
+
+	// Create new key-type pair and parse it to verify.
+	b := buf[uStart:]
+	copy(b, "u-")
+	copy(b[2:], key)
+	b[4] = '-'
+	b = b[:5+copy(b[5:], value)]
+	scan := makeScanner(b)
+	if parseExtensions(&scan); scan.err != nil {
+		return t, scan.err
+	}
+
+	// Assemble the replacement string.
+	if t.str == "" {
+		t.pVariant, t.pExt = byte(uStart-1), uint16(uStart-1)
+		t.str = string(buf[:uStart+len(b)])
+	} else {
+		s := t.str
+		start, sep, end, hasExt := t.findTypeForKey(key)
+		if start == sep {
+			if hasExt {
+				b = b[2:]
+			}
+			t.str = fmt.Sprintf("%s-%s%s", s[:sep], b, s[end:])
+		} else {
+			t.str = fmt.Sprintf("%s-%s%s", s[:start+3], value, s[end:])
+		}
+	}
+	return t, nil
+}
+
+// findTypeForKey returns the start and end position for the type corresponding
+// to key or the point at which to insert the key-value pair if the type
+// wasn't found. The hasExt return value reports whether an -u extension was present.
+// Note: the extensions are typically very small and are likely to contain
+// only one key-type pair.
+func (t Tag) findTypeForKey(key string) (start, sep, end int, hasExt bool) {
+	p := int(t.pExt)
+	if len(key) != 2 || p == len(t.str) || p == 0 {
+		return p, p, p, false
+	}
+	s := t.str
+
+	// Find the correct extension.
+	for p++; s[p] != 'u'; p++ {
+		if s[p] > 'u' {
+			p--
+			return p, p, p, false
+		}
+		if p = nextExtension(s, p); p == len(s) {
+			return len(s), len(s), len(s), false
+		}
+	}
+	// Proceed to the hyphen following the extension name.
+	p++
+
+	// curKey is the key currently being processed.
+	curKey := ""
+
+	// Iterate over keys until we get the end of a section.
+	for {
+		end = p
+		for p++; p < len(s) && s[p] != '-'; p++ {
+		}
+		n := p - end - 1
+		if n <= 2 && curKey == key {
+			if sep < end {
+				sep++
+			}
+			return start, sep, end, true
+		}
+		switch n {
+		case 0, // invalid string
+			1: // next extension
+			return end, end, end, true
+		case 2:
+			// next key
+			curKey = s[end+1 : p]
+			if curKey > key {
+				return end, end, end, true
+			}
+			start = end
+			sep = p
+		}
+	}
+}
+
+// ParseBase parses a 2- or 3-letter ISO 639 code.
+// It returns a ValueError if s is a well-formed but unknown language identifier
+// or another error if another error occurred.
+func ParseBase(s string) (l Language, err error) {
+	defer func() {
+		if recover() != nil {
+			l = 0
+			err = ErrSyntax
+		}
+	}()
+
+	if n := len(s); n < 2 || 3 < n {
+		return 0, ErrSyntax
+	}
+	var buf [3]byte
+	return getLangID(buf[:copy(buf[:], s)])
+}
+
+// ParseScript parses a 4-letter ISO 15924 code.
+// It returns a ValueError if s is a well-formed but unknown script identifier
+// or another error if another error occurred.
+func ParseScript(s string) (scr Script, err error) {
+	defer func() {
+		if recover() != nil {
+			scr = 0
+			err = ErrSyntax
+		}
+	}()
+
+	if len(s) != 4 {
+		return 0, ErrSyntax
+	}
+	var buf [4]byte
+	return getScriptID(script, buf[:copy(buf[:], s)])
+}
+
+// EncodeM49 returns the Region for the given UN M.49 code.
+// It returns an error if r is not a valid code.
+func EncodeM49(r int) (Region, error) {
+	return getRegionM49(r)
+}
+
+// ParseRegion parses a 2- or 3-letter ISO 3166-1 or a UN M.49 code.
+// It returns a ValueError if s is a well-formed but unknown region identifier
+// or another error if another error occurred.
+func ParseRegion(s string) (r Region, err error) {
+	defer func() {
+		if recover() != nil {
+			r = 0
+			err = ErrSyntax
+		}
+	}()
+
+	if n := len(s); n < 2 || 3 < n {
+		return 0, ErrSyntax
+	}
+	var buf [3]byte
+	return getRegionID(buf[:copy(buf[:], s)])
+}
+
+// IsCountry returns whether this region is a country or autonomous area. This
+// includes non-standard definitions from CLDR.
+func (r Region) IsCountry() bool {
+	if r == 0 || r.IsGroup() || r.IsPrivateUse() && r != _XK {
+		return false
+	}
+	return true
+}
+
+// IsGroup returns whether this region defines a collection of regions. This
+// includes non-standard definitions from CLDR.
+func (r Region) IsGroup() bool {
+	if r == 0 {
+		return false
+	}
+	return int(regionInclusion[r]) < len(regionContainment)
+}
+
+// Contains returns whether Region c is contained by Region r. It returns true
+// if c == r.
+func (r Region) Contains(c Region) bool {
+	if r == c {
+		return true
+	}
+	g := regionInclusion[r]
+	if g >= nRegionGroups {
+		return false
+	}
+	m := regionContainment[g]
+
+	d := regionInclusion[c]
+	b := regionInclusionBits[d]
+
+	// A contained country may belong to multiple disjoint groups. Matching any
+	// of these indicates containment. If the contained region is a group, it
+	// must strictly be a subset.
+	if d >= nRegionGroups {
+		return b&m != 0
+	}
+	return b&^m == 0
+}
+
+var errNoTLD = errors.New("language: region is not a valid ccTLD")
+
+// TLD returns the country code top-level domain (ccTLD). UK is returned for GB.
+// In all other cases it returns either the region itself or an error.
+//
+// This method may return an error for a region for which there exists a
+// canonical form with a ccTLD. To get that ccTLD canonicalize r first. The
+// region will already be canonicalized it was obtained from a Tag that was
+// obtained using any of the default methods.
+func (r Region) TLD() (Region, error) {
+	// See http://en.wikipedia.org/wiki/Country_code_top-level_domain for the
+	// difference between ISO 3166-1 and IANA ccTLD.
+	if r == _GB {
+		r = _UK
+	}
+	if (r.typ() & ccTLD) == 0 {
+		return 0, errNoTLD
+	}
+	return r, nil
+}
+
+// Canonicalize returns the region or a possible replacement if the region is
+// deprecated. It will not return a replacement for deprecated regions that
+// are split into multiple regions.
+func (r Region) Canonicalize() Region {
+	if cr := normRegion(r); cr != 0 {
+		return cr
+	}
+	return r
+}
+
+// Variant represents a registered variant of a language as defined by BCP 47.
+type Variant struct {
+	ID  uint8
+	str string
+}
+
+// ParseVariant parses and returns a Variant. An error is returned if s is not
+// a valid variant.
+func ParseVariant(s string) (v Variant, err error) {
+	defer func() {
+		if recover() != nil {
+			v = Variant{}
+			err = ErrSyntax
+		}
+	}()
+
+	s = strings.ToLower(s)
+	if id, ok := variantIndex[s]; ok {
+		return Variant{id, s}, nil
+	}
+	return Variant{}, NewValueError([]byte(s))
+}
+
+// String returns the string representation of the variant.
+func (v Variant) String() string {
+	return v.str
+}
diff --git a/vendor/golang.org/x/text/internal/language/lookup.go b/vendor/golang.org/x/text/internal/language/lookup.go
new file mode 100644
index 000000000..231b4fbde
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/lookup.go
@@ -0,0 +1,412 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+	"strconv"
+
+	"golang.org/x/text/internal/tag"
+)
+
+// findIndex tries to find the given tag in idx and returns a standardized error
+// if it could not be found.
+func findIndex(idx tag.Index, key []byte, form string) (index int, err error) {
+	if !tag.FixCase(form, key) {
+		return 0, ErrSyntax
+	}
+	i := idx.Index(key)
+	if i == -1 {
+		return 0, NewValueError(key)
+	}
+	return i, nil
+}
+
+func searchUint(imap []uint16, key uint16) int {
+	return sort.Search(len(imap), func(i int) bool {
+		return imap[i] >= key
+	})
+}
+
+type Language uint16
+
+// getLangID returns the langID of s if s is a canonical subtag
+// or langUnknown if s is not a canonical subtag.
+func getLangID(s []byte) (Language, error) {
+	if len(s) == 2 {
+		return getLangISO2(s)
+	}
+	return getLangISO3(s)
+}
+
+// TODO language normalization as well as the AliasMaps could be moved to the
+// higher level package, but it is a bit tricky to separate the generation.
+
+func (id Language) Canonicalize() (Language, AliasType) {
+	return normLang(id)
+}
+
+// normLang returns the mapped langID of id according to mapping m.
+func normLang(id Language) (Language, AliasType) {
+	k := sort.Search(len(AliasMap), func(i int) bool {
+		return AliasMap[i].From >= uint16(id)
+	})
+	if k < len(AliasMap) && AliasMap[k].From == uint16(id) {
+		return Language(AliasMap[k].To), AliasTypes[k]
+	}
+	return id, AliasTypeUnknown
+}
+
+// getLangISO2 returns the langID for the given 2-letter ISO language code
+// or unknownLang if this does not exist.
+func getLangISO2(s []byte) (Language, error) {
+	if !tag.FixCase("zz", s) {
+		return 0, ErrSyntax
+	}
+	if i := lang.Index(s); i != -1 && lang.Elem(i)[3] != 0 {
+		return Language(i), nil
+	}
+	return 0, NewValueError(s)
+}
+
+const base = 'z' - 'a' + 1
+
+func strToInt(s []byte) uint {
+	v := uint(0)
+	for i := 0; i < len(s); i++ {
+		v *= base
+		v += uint(s[i] - 'a')
+	}
+	return v
+}
+
+// converts the given integer to the original ASCII string passed to strToInt.
+// len(s) must match the number of characters obtained.
+func intToStr(v uint, s []byte) {
+	for i := len(s) - 1; i >= 0; i-- {
+		s[i] = byte(v%base) + 'a'
+		v /= base
+	}
+}
+
+// getLangISO3 returns the langID for the given 3-letter ISO language code
+// or unknownLang if this does not exist.
+func getLangISO3(s []byte) (Language, error) {
+	if tag.FixCase("und", s) {
+		// first try to match canonical 3-letter entries
+		for i := lang.Index(s[:2]); i != -1; i = lang.Next(s[:2], i) {
+			if e := lang.Elem(i); e[3] == 0 && e[2] == s[2] {
+				// We treat "und" as special and always translate it to "unspecified".
+				// Note that ZZ and Zzzz are private use and are not treated as
+				// unspecified by default.
+				id := Language(i)
+				if id == nonCanonicalUnd {
+					return 0, nil
+				}
+				return id, nil
+			}
+		}
+		if i := altLangISO3.Index(s); i != -1 {
+			return Language(altLangIndex[altLangISO3.Elem(i)[3]]), nil
+		}
+		n := strToInt(s)
+		if langNoIndex[n/8]&(1<<(n%8)) != 0 {
+			return Language(n) + langNoIndexOffset, nil
+		}
+		// Check for non-canonical uses of ISO3.
+		for i := lang.Index(s[:1]); i != -1; i = lang.Next(s[:1], i) {
+			if e := lang.Elem(i); e[2] == s[1] && e[3] == s[2] {
+				return Language(i), nil
+			}
+		}
+		return 0, NewValueError(s)
+	}
+	return 0, ErrSyntax
+}
+
+// StringToBuf writes the string to b and returns the number of bytes
+// written.  cap(b) must be >= 3.
+func (id Language) StringToBuf(b []byte) int {
+	if id >= langNoIndexOffset {
+		intToStr(uint(id)-langNoIndexOffset, b[:3])
+		return 3
+	} else if id == 0 {
+		return copy(b, "und")
+	}
+	l := lang[id<<2:]
+	if l[3] == 0 {
+		return copy(b, l[:3])
+	}
+	return copy(b, l[:2])
+}
+
+// String returns the BCP 47 representation of the langID.
+// Use b as variable name, instead of id, to ensure the variable
+// used is consistent with that of Base in which this type is embedded.
+func (b Language) String() string {
+	if b == 0 {
+		return "und"
+	} else if b >= langNoIndexOffset {
+		b -= langNoIndexOffset
+		buf := [3]byte{}
+		intToStr(uint(b), buf[:])
+		return string(buf[:])
+	}
+	l := lang.Elem(int(b))
+	if l[3] == 0 {
+		return l[:3]
+	}
+	return l[:2]
+}
+
+// ISO3 returns the ISO 639-3 language code.
+func (b Language) ISO3() string {
+	if b == 0 || b >= langNoIndexOffset {
+		return b.String()
+	}
+	l := lang.Elem(int(b))
+	if l[3] == 0 {
+		return l[:3]
+	} else if l[2] == 0 {
+		return altLangISO3.Elem(int(l[3]))[:3]
+	}
+	// This allocation will only happen for 3-letter ISO codes
+	// that are non-canonical BCP 47 language identifiers.
+	return l[0:1] + l[2:4]
+}
+
+// IsPrivateUse reports whether this language code is reserved for private use.
+func (b Language) IsPrivateUse() bool {
+	return langPrivateStart <= b && b <= langPrivateEnd
+}
+
+// SuppressScript returns the script marked as SuppressScript in the IANA
+// language tag repository, or 0 if there is no such script.
+func (b Language) SuppressScript() Script {
+	if b < langNoIndexOffset {
+		return Script(suppressScript[b])
+	}
+	return 0
+}
+
+type Region uint16
+
+// getRegionID returns the region id for s if s is a valid 2-letter region code
+// or unknownRegion.
+func getRegionID(s []byte) (Region, error) {
+	if len(s) == 3 {
+		if isAlpha(s[0]) {
+			return getRegionISO3(s)
+		}
+		if i, err := strconv.ParseUint(string(s), 10, 10); err == nil {
+			return getRegionM49(int(i))
+		}
+	}
+	return getRegionISO2(s)
+}
+
+// getRegionISO2 returns the regionID for the given 2-letter ISO country code
+// or unknownRegion if this does not exist.
+func getRegionISO2(s []byte) (Region, error) {
+	i, err := findIndex(regionISO, s, "ZZ")
+	if err != nil {
+		return 0, err
+	}
+	return Region(i) + isoRegionOffset, nil
+}
+
+// getRegionISO3 returns the regionID for the given 3-letter ISO country code
+// or unknownRegion if this does not exist.
+func getRegionISO3(s []byte) (Region, error) {
+	if tag.FixCase("ZZZ", s) {
+		for i := regionISO.Index(s[:1]); i != -1; i = regionISO.Next(s[:1], i) {
+			if e := regionISO.Elem(i); e[2] == s[1] && e[3] == s[2] {
+				return Region(i) + isoRegionOffset, nil
+			}
+		}
+		for i := 0; i < len(altRegionISO3); i += 3 {
+			if tag.Compare(altRegionISO3[i:i+3], s) == 0 {
+				return Region(altRegionIDs[i/3]), nil
+			}
+		}
+		return 0, NewValueError(s)
+	}
+	return 0, ErrSyntax
+}
+
+func getRegionM49(n int) (Region, error) {
+	if 0 < n && n <= 999 {
+		const (
+			searchBits = 7
+			regionBits = 9
+			regionMask = 1<<regionBits - 1
+		)
+		idx := n >> searchBits
+		buf := fromM49[m49Index[idx]:m49Index[idx+1]]
+		val := uint16(n) << regionBits // we rely on bits shifting out
+		i := sort.Search(len(buf), func(i int) bool {
+			return buf[i] >= val
+		})
+		if r := fromM49[int(m49Index[idx])+i]; r&^regionMask == val {
+			return Region(r & regionMask), nil
+		}
+	}
+	var e ValueError
+	fmt.Fprint(bytes.NewBuffer([]byte(e.v[:])), n)
+	return 0, e
+}
+
+// normRegion returns a region if r is deprecated or 0 otherwise.
+// TODO: consider supporting BYS (-> BLR), CSK (-> 200 or CZ), PHI (-> PHL) and AFI (-> DJ).
+// TODO: consider mapping split up regions to new most populous one (like CLDR).
+func normRegion(r Region) Region {
+	m := regionOldMap
+	k := sort.Search(len(m), func(i int) bool {
+		return m[i].From >= uint16(r)
+	})
+	if k < len(m) && m[k].From == uint16(r) {
+		return Region(m[k].To)
+	}
+	return 0
+}
+
+const (
+	iso3166UserAssigned = 1 << iota
+	ccTLD
+	bcp47Region
+)
+
+func (r Region) typ() byte {
+	return regionTypes[r]
+}
+
+// String returns the BCP 47 representation for the region.
+// It returns "ZZ" for an unspecified region.
+func (r Region) String() string {
+	if r < isoRegionOffset {
+		if r == 0 {
+			return "ZZ"
+		}
+		return fmt.Sprintf("%03d", r.M49())
+	}
+	r -= isoRegionOffset
+	return regionISO.Elem(int(r))[:2]
+}
+
+// ISO3 returns the 3-letter ISO code of r.
+// Note that not all regions have a 3-letter ISO code.
+// In such cases this method returns "ZZZ".
+func (r Region) ISO3() string {
+	if r < isoRegionOffset {
+		return "ZZZ"
+	}
+	r -= isoRegionOffset
+	reg := regionISO.Elem(int(r))
+	switch reg[2] {
+	case 0:
+		return altRegionISO3[reg[3]:][:3]
+	case ' ':
+		return "ZZZ"
+	}
+	return reg[0:1] + reg[2:4]
+}
+
+// M49 returns the UN M.49 encoding of r, or 0 if this encoding
+// is not defined for r.
+func (r Region) M49() int {
+	return int(m49[r])
+}
+
+// IsPrivateUse reports whether r has the ISO 3166 User-assigned status. This
+// may include private-use tags that are assigned by CLDR and used in this
+// implementation. So IsPrivateUse and IsCountry can be simultaneously true.
+func (r Region) IsPrivateUse() bool {
+	return r.typ()&iso3166UserAssigned != 0
+}
+
+type Script uint16
+
+// getScriptID returns the script id for string s. It assumes that s
+// is of the format [A-Z][a-z]{3}.
+func getScriptID(idx tag.Index, s []byte) (Script, error) {
+	i, err := findIndex(idx, s, "Zzzz")
+	return Script(i), err
+}
+
+// String returns the script code in title case.
+// It returns "Zzzz" for an unspecified script.
+func (s Script) String() string {
+	if s == 0 {
+		return "Zzzz"
+	}
+	return script.Elem(int(s))
+}
+
+// IsPrivateUse reports whether this script code is reserved for private use.
+func (s Script) IsPrivateUse() bool {
+	return _Qaaa <= s && s <= _Qabx
+}
+
+const (
+	maxAltTaglen = len("en-US-POSIX")
+	maxLen       = maxAltTaglen
+)
+
+var (
+	// grandfatheredMap holds a mapping from legacy and grandfathered tags to
+	// their base language or index to more elaborate tag.
+	grandfatheredMap = map[[maxLen]byte]int16{
+		[maxLen]byte{'a', 'r', 't', '-', 'l', 'o', 'j', 'b', 'a', 'n'}: _jbo, // art-lojban
+		[maxLen]byte{'i', '-', 'a', 'm', 'i'}:                          _ami, // i-ami
+		[maxLen]byte{'i', '-', 'b', 'n', 'n'}:                          _bnn, // i-bnn
+		[maxLen]byte{'i', '-', 'h', 'a', 'k'}:                          _hak, // i-hak
+		[maxLen]byte{'i', '-', 'k', 'l', 'i', 'n', 'g', 'o', 'n'}:      _tlh, // i-klingon
+		[maxLen]byte{'i', '-', 'l', 'u', 'x'}:                          _lb,  // i-lux
+		[maxLen]byte{'i', '-', 'n', 'a', 'v', 'a', 'j', 'o'}:           _nv,  // i-navajo
+		[maxLen]byte{'i', '-', 'p', 'w', 'n'}:                          _pwn, // i-pwn
+		[maxLen]byte{'i', '-', 't', 'a', 'o'}:                          _tao, // i-tao
+		[maxLen]byte{'i', '-', 't', 'a', 'y'}:                          _tay, // i-tay
+		[maxLen]byte{'i', '-', 't', 's', 'u'}:                          _tsu, // i-tsu
+		[maxLen]byte{'n', 'o', '-', 'b', 'o', 'k'}:                     _nb,  // no-bok
+		[maxLen]byte{'n', 'o', '-', 'n', 'y', 'n'}:                     _nn,  // no-nyn
+		[maxLen]byte{'s', 'g', 'n', '-', 'b', 'e', '-', 'f', 'r'}:      _sfb, // sgn-BE-FR
+		[maxLen]byte{'s', 'g', 'n', '-', 'b', 'e', '-', 'n', 'l'}:      _vgt, // sgn-BE-NL
+		[maxLen]byte{'s', 'g', 'n', '-', 'c', 'h', '-', 'd', 'e'}:      _sgg, // sgn-CH-DE
+		[maxLen]byte{'z', 'h', '-', 'g', 'u', 'o', 'y', 'u'}:           _cmn, // zh-guoyu
+		[maxLen]byte{'z', 'h', '-', 'h', 'a', 'k', 'k', 'a'}:           _hak, // zh-hakka
+		[maxLen]byte{'z', 'h', '-', 'm', 'i', 'n', '-', 'n', 'a', 'n'}: _nan, // zh-min-nan
+		[maxLen]byte{'z', 'h', '-', 'x', 'i', 'a', 'n', 'g'}:           _hsn, // zh-xiang
+
+		// Grandfathered tags with no modern replacement will be converted as
+		// follows:
+		[maxLen]byte{'c', 'e', 'l', '-', 'g', 'a', 'u', 'l', 'i', 's', 'h'}: -1, // cel-gaulish
+		[maxLen]byte{'e', 'n', '-', 'g', 'b', '-', 'o', 'e', 'd'}:           -2, // en-GB-oed
+		[maxLen]byte{'i', '-', 'd', 'e', 'f', 'a', 'u', 'l', 't'}:           -3, // i-default
+		[maxLen]byte{'i', '-', 'e', 'n', 'o', 'c', 'h', 'i', 'a', 'n'}:      -4, // i-enochian
+		[maxLen]byte{'i', '-', 'm', 'i', 'n', 'g', 'o'}:                     -5, // i-mingo
+		[maxLen]byte{'z', 'h', '-', 'm', 'i', 'n'}:                          -6, // zh-min
+
+		// CLDR-specific tag.
+		[maxLen]byte{'r', 'o', 'o', 't'}:                                    0,  // root
+		[maxLen]byte{'e', 'n', '-', 'u', 's', '-', 'p', 'o', 's', 'i', 'x'}: -7, // en_US_POSIX"
+	}
+
+	altTagIndex = [...]uint8{0, 17, 31, 45, 61, 74, 86, 102}
+
+	altTags = "xtg-x-cel-gaulishen-GB-oxendicten-x-i-defaultund-x-i-enochiansee-x-i-mingonan-x-zh-minen-US-u-va-posix"
+)
+
+func grandfathered(s [maxAltTaglen]byte) (t Tag, ok bool) {
+	if v, ok := grandfatheredMap[s]; ok {
+		if v < 0 {
+			return Make(altTags[altTagIndex[-v-1]:altTagIndex[-v]]), true
+		}
+		t.LangID = Language(v)
+		return t, true
+	}
+	return t, false
+}
diff --git a/vendor/golang.org/x/text/internal/language/match.go b/vendor/golang.org/x/text/internal/language/match.go
new file mode 100644
index 000000000..75a2dbca7
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/match.go
@@ -0,0 +1,226 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+import "errors"
+
+type scriptRegionFlags uint8
+
+const (
+	isList = 1 << iota
+	scriptInFrom
+	regionInFrom
+)
+
+func (t *Tag) setUndefinedLang(id Language) {
+	if t.LangID == 0 {
+		t.LangID = id
+	}
+}
+
+func (t *Tag) setUndefinedScript(id Script) {
+	if t.ScriptID == 0 {
+		t.ScriptID = id
+	}
+}
+
+func (t *Tag) setUndefinedRegion(id Region) {
+	if t.RegionID == 0 || t.RegionID.Contains(id) {
+		t.RegionID = id
+	}
+}
+
+// ErrMissingLikelyTagsData indicates no information was available
+// to compute likely values of missing tags.
+var ErrMissingLikelyTagsData = errors.New("missing likely tags data")
+
+// addLikelySubtags sets subtags to their most likely value, given the locale.
+// In most cases this means setting fields for unknown values, but in some
+// cases it may alter a value.  It returns an ErrMissingLikelyTagsData error
+// if the given locale cannot be expanded.
+func (t Tag) addLikelySubtags() (Tag, error) {
+	id, err := addTags(t)
+	if err != nil {
+		return t, err
+	} else if id.equalTags(t) {
+		return t, nil
+	}
+	id.RemakeString()
+	return id, nil
+}
+
+// specializeRegion attempts to specialize a group region.
+func specializeRegion(t *Tag) bool {
+	if i := regionInclusion[t.RegionID]; i < nRegionGroups {
+		x := likelyRegionGroup[i]
+		if Language(x.lang) == t.LangID && Script(x.script) == t.ScriptID {
+			t.RegionID = Region(x.region)
+		}
+		return true
+	}
+	return false
+}
+
+// Maximize returns a new tag with missing tags filled in.
+func (t Tag) Maximize() (Tag, error) {
+	return addTags(t)
+}
+
+func addTags(t Tag) (Tag, error) {
+	// We leave private use identifiers alone.
+	if t.IsPrivateUse() {
+		return t, nil
+	}
+	if t.ScriptID != 0 && t.RegionID != 0 {
+		if t.LangID != 0 {
+			// already fully specified
+			specializeRegion(&t)
+			return t, nil
+		}
+		// Search matches for und-script-region. Note that for these cases
+		// region will never be a group so there is no need to check for this.
+		list := likelyRegion[t.RegionID : t.RegionID+1]
+		if x := list[0]; x.flags&isList != 0 {
+			list = likelyRegionList[x.lang : x.lang+uint16(x.script)]
+		}
+		for _, x := range list {
+			// Deviating from the spec. See match_test.go for details.
+			if Script(x.script) == t.ScriptID {
+				t.setUndefinedLang(Language(x.lang))
+				return t, nil
+			}
+		}
+	}
+	if t.LangID != 0 {
+		// Search matches for lang-script and lang-region, where lang != und.
+		if t.LangID < langNoIndexOffset {
+			x := likelyLang[t.LangID]
+			if x.flags&isList != 0 {
+				list := likelyLangList[x.region : x.region+uint16(x.script)]
+				if t.ScriptID != 0 {
+					for _, x := range list {
+						if Script(x.script) == t.ScriptID && x.flags&scriptInFrom != 0 {
+							t.setUndefinedRegion(Region(x.region))
+							return t, nil
+						}
+					}
+				} else if t.RegionID != 0 {
+					count := 0
+					goodScript := true
+					tt := t
+					for _, x := range list {
+						// We visit all entries for which the script was not
+						// defined, including the ones where the region was not
+						// defined. This allows for proper disambiguation within
+						// regions.
+						if x.flags&scriptInFrom == 0 && t.RegionID.Contains(Region(x.region)) {
+							tt.RegionID = Region(x.region)
+							tt.setUndefinedScript(Script(x.script))
+							goodScript = goodScript && tt.ScriptID == Script(x.script)
+							count++
+						}
+					}
+					if count == 1 {
+						return tt, nil
+					}
+					// Even if we fail to find a unique Region, we might have
+					// an unambiguous script.
+					if goodScript {
+						t.ScriptID = tt.ScriptID
+					}
+				}
+			}
+		}
+	} else {
+		// Search matches for und-script.
+		if t.ScriptID != 0 {
+			x := likelyScript[t.ScriptID]
+			if x.region != 0 {
+				t.setUndefinedRegion(Region(x.region))
+				t.setUndefinedLang(Language(x.lang))
+				return t, nil
+			}
+		}
+		// Search matches for und-region. If und-script-region exists, it would
+		// have been found earlier.
+		if t.RegionID != 0 {
+			if i := regionInclusion[t.RegionID]; i < nRegionGroups {
+				x := likelyRegionGroup[i]
+				if x.region != 0 {
+					t.setUndefinedLang(Language(x.lang))
+					t.setUndefinedScript(Script(x.script))
+					t.RegionID = Region(x.region)
+				}
+			} else {
+				x := likelyRegion[t.RegionID]
+				if x.flags&isList != 0 {
+					x = likelyRegionList[x.lang]
+				}
+				if x.script != 0 && x.flags != scriptInFrom {
+					t.setUndefinedLang(Language(x.lang))
+					t.setUndefinedScript(Script(x.script))
+					return t, nil
+				}
+			}
+		}
+	}
+
+	// Search matches for lang.
+	if t.LangID < langNoIndexOffset {
+		x := likelyLang[t.LangID]
+		if x.flags&isList != 0 {
+			x = likelyLangList[x.region]
+		}
+		if x.region != 0 {
+			t.setUndefinedScript(Script(x.script))
+			t.setUndefinedRegion(Region(x.region))
+		}
+		specializeRegion(&t)
+		if t.LangID == 0 {
+			t.LangID = _en // default language
+		}
+		return t, nil
+	}
+	return t, ErrMissingLikelyTagsData
+}
+
+func (t *Tag) setTagsFrom(id Tag) {
+	t.LangID = id.LangID
+	t.ScriptID = id.ScriptID
+	t.RegionID = id.RegionID
+}
+
+// minimize removes the region or script subtags from t such that
+// t.addLikelySubtags() == t.minimize().addLikelySubtags().
+func (t Tag) minimize() (Tag, error) {
+	t, err := minimizeTags(t)
+	if err != nil {
+		return t, err
+	}
+	t.RemakeString()
+	return t, nil
+}
+
+// minimizeTags mimics the behavior of the ICU 51 C implementation.
+func minimizeTags(t Tag) (Tag, error) {
+	if t.equalTags(Und) {
+		return t, nil
+	}
+	max, err := addTags(t)
+	if err != nil {
+		return t, err
+	}
+	for _, id := range [...]Tag{
+		{LangID: t.LangID},
+		{LangID: t.LangID, RegionID: t.RegionID},
+		{LangID: t.LangID, ScriptID: t.ScriptID},
+	} {
+		if x, err := addTags(id); err == nil && max.equalTags(x) {
+			t.setTagsFrom(id)
+			break
+		}
+	}
+	return t, nil
+}
diff --git a/vendor/golang.org/x/text/internal/language/parse.go b/vendor/golang.org/x/text/internal/language/parse.go
new file mode 100644
index 000000000..aad1e0acf
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/parse.go
@@ -0,0 +1,608 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"sort"
+
+	"golang.org/x/text/internal/tag"
+)
+
+// isAlpha returns true if the byte is not a digit.
+// b must be an ASCII letter or digit.
+func isAlpha(b byte) bool {
+	return b > '9'
+}
+
+// isAlphaNum returns true if the string contains only ASCII letters or digits.
+func isAlphaNum(s []byte) bool {
+	for _, c := range s {
+		if !('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9') {
+			return false
+		}
+	}
+	return true
+}
+
+// ErrSyntax is returned by any of the parsing functions when the
+// input is not well-formed, according to BCP 47.
+// TODO: return the position at which the syntax error occurred?
+var ErrSyntax = errors.New("language: tag is not well-formed")
+
+// ErrDuplicateKey is returned when a tag contains the same key twice with
+// different values in the -u section.
+var ErrDuplicateKey = errors.New("language: different values for same key in -u extension")
+
+// ValueError is returned by any of the parsing functions when the
+// input is well-formed but the respective subtag is not recognized
+// as a valid value.
+type ValueError struct {
+	v [8]byte
+}
+
+// NewValueError creates a new ValueError.
+func NewValueError(tag []byte) ValueError {
+	var e ValueError
+	copy(e.v[:], tag)
+	return e
+}
+
+func (e ValueError) tag() []byte {
+	n := bytes.IndexByte(e.v[:], 0)
+	if n == -1 {
+		n = 8
+	}
+	return e.v[:n]
+}
+
+// Error implements the error interface.
+func (e ValueError) Error() string {
+	return fmt.Sprintf("language: subtag %q is well-formed but unknown", e.tag())
+}
+
+// Subtag returns the subtag for which the error occurred.
+func (e ValueError) Subtag() string {
+	return string(e.tag())
+}
+
+// scanner is used to scan BCP 47 tokens, which are separated by _ or -.
+type scanner struct {
+	b     []byte
+	bytes [max99thPercentileSize]byte
+	token []byte
+	start int // start position of the current token
+	end   int // end position of the current token
+	next  int // next point for scan
+	err   error
+	done  bool
+}
+
+func makeScannerString(s string) scanner {
+	scan := scanner{}
+	if len(s) <= len(scan.bytes) {
+		scan.b = scan.bytes[:copy(scan.bytes[:], s)]
+	} else {
+		scan.b = []byte(s)
+	}
+	scan.init()
+	return scan
+}
+
+// makeScanner returns a scanner using b as the input buffer.
+// b is not copied and may be modified by the scanner routines.
+func makeScanner(b []byte) scanner {
+	scan := scanner{b: b}
+	scan.init()
+	return scan
+}
+
+func (s *scanner) init() {
+	for i, c := range s.b {
+		if c == '_' {
+			s.b[i] = '-'
+		}
+	}
+	s.scan()
+}
+
+// restToLower converts the string between start and end to lower case.
+func (s *scanner) toLower(start, end int) {
+	for i := start; i < end; i++ {
+		c := s.b[i]
+		if 'A' <= c && c <= 'Z' {
+			s.b[i] += 'a' - 'A'
+		}
+	}
+}
+
+func (s *scanner) setError(e error) {
+	if s.err == nil || (e == ErrSyntax && s.err != ErrSyntax) {
+		s.err = e
+	}
+}
+
+// resizeRange shrinks or grows the array at position oldStart such that
+// a new string of size newSize can fit between oldStart and oldEnd.
+// Sets the scan point to after the resized range.
+func (s *scanner) resizeRange(oldStart, oldEnd, newSize int) {
+	s.start = oldStart
+	if end := oldStart + newSize; end != oldEnd {
+		diff := end - oldEnd
+		var b []byte
+		if n := len(s.b) + diff; n > cap(s.b) {
+			b = make([]byte, n)
+			copy(b, s.b[:oldStart])
+		} else {
+			b = s.b[:n]
+		}
+		copy(b[end:], s.b[oldEnd:])
+		s.b = b
+		s.next = end + (s.next - s.end)
+		s.end = end
+	}
+}
+
+// replace replaces the current token with repl.
+func (s *scanner) replace(repl string) {
+	s.resizeRange(s.start, s.end, len(repl))
+	copy(s.b[s.start:], repl)
+}
+
+// gobble removes the current token from the input.
+// Caller must call scan after calling gobble.
+func (s *scanner) gobble(e error) {
+	s.setError(e)
+	if s.start == 0 {
+		s.b = s.b[:+copy(s.b, s.b[s.next:])]
+		s.end = 0
+	} else {
+		s.b = s.b[:s.start-1+copy(s.b[s.start-1:], s.b[s.end:])]
+		s.end = s.start - 1
+	}
+	s.next = s.start
+}
+
+// deleteRange removes the given range from s.b before the current token.
+func (s *scanner) deleteRange(start, end int) {
+	s.b = s.b[:start+copy(s.b[start:], s.b[end:])]
+	diff := end - start
+	s.next -= diff
+	s.start -= diff
+	s.end -= diff
+}
+
+// scan parses the next token of a BCP 47 string.  Tokens that are larger
+// than 8 characters or include non-alphanumeric characters result in an error
+// and are gobbled and removed from the output.
+// It returns the end position of the last token consumed.
+func (s *scanner) scan() (end int) {
+	end = s.end
+	s.token = nil
+	for s.start = s.next; s.next < len(s.b); {
+		i := bytes.IndexByte(s.b[s.next:], '-')
+		if i == -1 {
+			s.end = len(s.b)
+			s.next = len(s.b)
+			i = s.end - s.start
+		} else {
+			s.end = s.next + i
+			s.next = s.end + 1
+		}
+		token := s.b[s.start:s.end]
+		if i < 1 || i > 8 || !isAlphaNum(token) {
+			s.gobble(ErrSyntax)
+			continue
+		}
+		s.token = token
+		return end
+	}
+	if n := len(s.b); n > 0 && s.b[n-1] == '-' {
+		s.setError(ErrSyntax)
+		s.b = s.b[:len(s.b)-1]
+	}
+	s.done = true
+	return end
+}
+
+// acceptMinSize parses multiple tokens of the given size or greater.
+// It returns the end position of the last token consumed.
+func (s *scanner) acceptMinSize(min int) (end int) {
+	end = s.end
+	s.scan()
+	for ; len(s.token) >= min; s.scan() {
+		end = s.end
+	}
+	return end
+}
+
+// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
+// failed it returns an error and any part of the tag that could be parsed.
+// If parsing succeeded but an unknown value was found, it returns
+// ValueError. The Tag returned in this case is just stripped of the unknown
+// value. All other values are preserved. It accepts tags in the BCP 47 format
+// and extensions to this standard defined in
+// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
+func Parse(s string) (t Tag, err error) {
+	// TODO: consider supporting old-style locale key-value pairs.
+	if s == "" {
+		return Und, ErrSyntax
+	}
+	defer func() {
+		if recover() != nil {
+			t = Und
+			err = ErrSyntax
+			return
+		}
+	}()
+	if len(s) <= maxAltTaglen {
+		b := [maxAltTaglen]byte{}
+		for i, c := range s {
+			// Generating invalid UTF-8 is okay as it won't match.
+			if 'A' <= c && c <= 'Z' {
+				c += 'a' - 'A'
+			} else if c == '_' {
+				c = '-'
+			}
+			b[i] = byte(c)
+		}
+		if t, ok := grandfathered(b); ok {
+			return t, nil
+		}
+	}
+	scan := makeScannerString(s)
+	return parse(&scan, s)
+}
+
+func parse(scan *scanner, s string) (t Tag, err error) {
+	t = Und
+	var end int
+	if n := len(scan.token); n <= 1 {
+		scan.toLower(0, len(scan.b))
+		if n == 0 || scan.token[0] != 'x' {
+			return t, ErrSyntax
+		}
+		end = parseExtensions(scan)
+	} else if n >= 4 {
+		return Und, ErrSyntax
+	} else { // the usual case
+		t, end = parseTag(scan, true)
+		if n := len(scan.token); n == 1 {
+			t.pExt = uint16(end)
+			end = parseExtensions(scan)
+		} else if end < len(scan.b) {
+			scan.setError(ErrSyntax)
+			scan.b = scan.b[:end]
+		}
+	}
+	if int(t.pVariant) < len(scan.b) {
+		if end < len(s) {
+			s = s[:end]
+		}
+		if len(s) > 0 && tag.Compare(s, scan.b) == 0 {
+			t.str = s
+		} else {
+			t.str = string(scan.b)
+		}
+	} else {
+		t.pVariant, t.pExt = 0, 0
+	}
+	return t, scan.err
+}
+
+// parseTag parses language, script, region and variants.
+// It returns a Tag and the end position in the input that was parsed.
+// If doNorm is true, then <lang>-<extlang> will be normalized to <extlang>.
+func parseTag(scan *scanner, doNorm bool) (t Tag, end int) {
+	var e error
+	// TODO: set an error if an unknown lang, script or region is encountered.
+	t.LangID, e = getLangID(scan.token)
+	scan.setError(e)
+	scan.replace(t.LangID.String())
+	langStart := scan.start
+	end = scan.scan()
+	for len(scan.token) == 3 && isAlpha(scan.token[0]) {
+		// From http://tools.ietf.org/html/bcp47, <lang>-<extlang> tags are equivalent
+		// to a tag of the form <extlang>.
+		if doNorm {
+			lang, e := getLangID(scan.token)
+			if lang != 0 {
+				t.LangID = lang
+				langStr := lang.String()
+				copy(scan.b[langStart:], langStr)
+				scan.b[langStart+len(langStr)] = '-'
+				scan.start = langStart + len(langStr) + 1
+			}
+			scan.gobble(e)
+		}
+		end = scan.scan()
+	}
+	if len(scan.token) == 4 && isAlpha(scan.token[0]) {
+		t.ScriptID, e = getScriptID(script, scan.token)
+		if t.ScriptID == 0 {
+			scan.gobble(e)
+		}
+		end = scan.scan()
+	}
+	if n := len(scan.token); n >= 2 && n <= 3 {
+		t.RegionID, e = getRegionID(scan.token)
+		if t.RegionID == 0 {
+			scan.gobble(e)
+		} else {
+			scan.replace(t.RegionID.String())
+		}
+		end = scan.scan()
+	}
+	scan.toLower(scan.start, len(scan.b))
+	t.pVariant = byte(end)
+	end = parseVariants(scan, end, t)
+	t.pExt = uint16(end)
+	return t, end
+}
+
+var separator = []byte{'-'}
+
+// parseVariants scans tokens as long as each token is a valid variant string.
+// Duplicate variants are removed.
+func parseVariants(scan *scanner, end int, t Tag) int {
+	start := scan.start
+	varIDBuf := [4]uint8{}
+	variantBuf := [4][]byte{}
+	varID := varIDBuf[:0]
+	variant := variantBuf[:0]
+	last := -1
+	needSort := false
+	for ; len(scan.token) >= 4; scan.scan() {
+		// TODO: measure the impact of needing this conversion and redesign
+		// the data structure if there is an issue.
+		v, ok := variantIndex[string(scan.token)]
+		if !ok {
+			// unknown variant
+			// TODO: allow user-defined variants?
+			scan.gobble(NewValueError(scan.token))
+			continue
+		}
+		varID = append(varID, v)
+		variant = append(variant, scan.token)
+		if !needSort {
+			if last < int(v) {
+				last = int(v)
+			} else {
+				needSort = true
+				// There is no legal combinations of more than 7 variants
+				// (and this is by no means a useful sequence).
+				const maxVariants = 8
+				if len(varID) > maxVariants {
+					break
+				}
+			}
+		}
+		end = scan.end
+	}
+	if needSort {
+		sort.Sort(variantsSort{varID, variant})
+		k, l := 0, -1
+		for i, v := range varID {
+			w := int(v)
+			if l == w {
+				// Remove duplicates.
+				continue
+			}
+			varID[k] = varID[i]
+			variant[k] = variant[i]
+			k++
+			l = w
+		}
+		if str := bytes.Join(variant[:k], separator); len(str) == 0 {
+			end = start - 1
+		} else {
+			scan.resizeRange(start, end, len(str))
+			copy(scan.b[scan.start:], str)
+			end = scan.end
+		}
+	}
+	return end
+}
+
+type variantsSort struct {
+	i []uint8
+	v [][]byte
+}
+
+func (s variantsSort) Len() int {
+	return len(s.i)
+}
+
+func (s variantsSort) Swap(i, j int) {
+	s.i[i], s.i[j] = s.i[j], s.i[i]
+	s.v[i], s.v[j] = s.v[j], s.v[i]
+}
+
+func (s variantsSort) Less(i, j int) bool {
+	return s.i[i] < s.i[j]
+}
+
+type bytesSort struct {
+	b [][]byte
+	n int // first n bytes to compare
+}
+
+func (b bytesSort) Len() int {
+	return len(b.b)
+}
+
+func (b bytesSort) Swap(i, j int) {
+	b.b[i], b.b[j] = b.b[j], b.b[i]
+}
+
+func (b bytesSort) Less(i, j int) bool {
+	for k := 0; k < b.n; k++ {
+		if b.b[i][k] == b.b[j][k] {
+			continue
+		}
+		return b.b[i][k] < b.b[j][k]
+	}
+	return false
+}
+
+// parseExtensions parses and normalizes the extensions in the buffer.
+// It returns the last position of scan.b that is part of any extension.
+// It also trims scan.b to remove excess parts accordingly.
+func parseExtensions(scan *scanner) int {
+	start := scan.start
+	exts := [][]byte{}
+	private := []byte{}
+	end := scan.end
+	for len(scan.token) == 1 {
+		extStart := scan.start
+		ext := scan.token[0]
+		end = parseExtension(scan)
+		extension := scan.b[extStart:end]
+		if len(extension) < 3 || (ext != 'x' && len(extension) < 4) {
+			scan.setError(ErrSyntax)
+			end = extStart
+			continue
+		} else if start == extStart && (ext == 'x' || scan.start == len(scan.b)) {
+			scan.b = scan.b[:end]
+			return end
+		} else if ext == 'x' {
+			private = extension
+			break
+		}
+		exts = append(exts, extension)
+	}
+	sort.Sort(bytesSort{exts, 1})
+	if len(private) > 0 {
+		exts = append(exts, private)
+	}
+	scan.b = scan.b[:start]
+	if len(exts) > 0 {
+		scan.b = append(scan.b, bytes.Join(exts, separator)...)
+	} else if start > 0 {
+		// Strip trailing '-'.
+		scan.b = scan.b[:start-1]
+	}
+	return end
+}
+
+// parseExtension parses a single extension and returns the position of
+// the extension end.
+func parseExtension(scan *scanner) int {
+	start, end := scan.start, scan.end
+	switch scan.token[0] {
+	case 'u': // https://www.ietf.org/rfc/rfc6067.txt
+		attrStart := end
+		scan.scan()
+		for last := []byte{}; len(scan.token) > 2; scan.scan() {
+			if bytes.Compare(scan.token, last) != -1 {
+				// Attributes are unsorted. Start over from scratch.
+				p := attrStart + 1
+				scan.next = p
+				attrs := [][]byte{}
+				for scan.scan(); len(scan.token) > 2; scan.scan() {
+					attrs = append(attrs, scan.token)
+					end = scan.end
+				}
+				sort.Sort(bytesSort{attrs, 3})
+				copy(scan.b[p:], bytes.Join(attrs, separator))
+				break
+			}
+			last = scan.token
+			end = scan.end
+		}
+		// Scan key-type sequences. A key is of length 2 and may be followed
+		// by 0 or more "type" subtags from 3 to the maximum of 8 letters.
+		var last, key []byte
+		for attrEnd := end; len(scan.token) == 2; last = key {
+			key = scan.token
+			end = scan.end
+			for scan.scan(); end < scan.end && len(scan.token) > 2; scan.scan() {
+				end = scan.end
+			}
+			// TODO: check key value validity
+			if bytes.Compare(key, last) != 1 || scan.err != nil {
+				// We have an invalid key or the keys are not sorted.
+				// Start scanning keys from scratch and reorder.
+				p := attrEnd + 1
+				scan.next = p
+				keys := [][]byte{}
+				for scan.scan(); len(scan.token) == 2; {
+					keyStart := scan.start
+					end = scan.end
+					for scan.scan(); end < scan.end && len(scan.token) > 2; scan.scan() {
+						end = scan.end
+					}
+					keys = append(keys, scan.b[keyStart:end])
+				}
+				sort.Stable(bytesSort{keys, 2})
+				if n := len(keys); n > 0 {
+					k := 0
+					for i := 1; i < n; i++ {
+						if !bytes.Equal(keys[k][:2], keys[i][:2]) {
+							k++
+							keys[k] = keys[i]
+						} else if !bytes.Equal(keys[k], keys[i]) {
+							scan.setError(ErrDuplicateKey)
+						}
+					}
+					keys = keys[:k+1]
+				}
+				reordered := bytes.Join(keys, separator)
+				if e := p + len(reordered); e < end {
+					scan.deleteRange(e, end)
+					end = e
+				}
+				copy(scan.b[p:], reordered)
+				break
+			}
+		}
+	case 't': // https://www.ietf.org/rfc/rfc6497.txt
+		scan.scan()
+		if n := len(scan.token); n >= 2 && n <= 3 && isAlpha(scan.token[1]) {
+			_, end = parseTag(scan, false)
+			scan.toLower(start, end)
+		}
+		for len(scan.token) == 2 && !isAlpha(scan.token[1]) {
+			end = scan.acceptMinSize(3)
+		}
+	case 'x':
+		end = scan.acceptMinSize(1)
+	default:
+		end = scan.acceptMinSize(2)
+	}
+	return end
+}
+
+// getExtension returns the name, body and end position of the extension.
+func getExtension(s string, p int) (end int, ext string) {
+	if s[p] == '-' {
+		p++
+	}
+	if s[p] == 'x' {
+		return len(s), s[p:]
+	}
+	end = nextExtension(s, p)
+	return end, s[p:end]
+}
+
+// nextExtension finds the next extension within the string, searching
+// for the -<char>- pattern from position p.
+// In the fast majority of cases, language tags will have at most
+// one extension and extensions tend to be small.
+func nextExtension(s string, p int) int {
+	for n := len(s) - 3; p < n; {
+		if s[p] == '-' {
+			if s[p+2] == '-' {
+				return p
+			}
+			p += 3
+		} else {
+			p++
+		}
+	}
+	return len(s)
+}
diff --git a/vendor/golang.org/x/text/internal/language/tables.go b/vendor/golang.org/x/text/internal/language/tables.go
new file mode 100644
index 000000000..14167e74e
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/tables.go
@@ -0,0 +1,3494 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package language
+
+import "golang.org/x/text/internal/tag"
+
+// CLDRVersion is the CLDR version from which the tables in this package are derived.
+const CLDRVersion = "32"
+
+const NumLanguages = 8798
+
+const NumScripts = 261
+
+const NumRegions = 358
+
+type FromTo struct {
+	From uint16
+	To   uint16
+}
+
+const nonCanonicalUnd = 1201
+const (
+	_af  = 22
+	_am  = 39
+	_ar  = 58
+	_az  = 88
+	_bg  = 126
+	_bn  = 165
+	_ca  = 215
+	_cs  = 250
+	_da  = 257
+	_de  = 269
+	_el  = 310
+	_en  = 313
+	_es  = 318
+	_et  = 320
+	_fa  = 328
+	_fi  = 337
+	_fil = 339
+	_fr  = 350
+	_gu  = 420
+	_he  = 444
+	_hi  = 446
+	_hr  = 465
+	_hu  = 469
+	_hy  = 471
+	_id  = 481
+	_is  = 504
+	_it  = 505
+	_ja  = 512
+	_ka  = 528
+	_kk  = 578
+	_km  = 586
+	_kn  = 593
+	_ko  = 596
+	_ky  = 650
+	_lo  = 696
+	_lt  = 704
+	_lv  = 711
+	_mk  = 767
+	_ml  = 772
+	_mn  = 779
+	_mo  = 784
+	_mr  = 795
+	_ms  = 799
+	_mul = 806
+	_my  = 817
+	_nb  = 839
+	_ne  = 849
+	_nl  = 871
+	_no  = 879
+	_pa  = 925
+	_pl  = 947
+	_pt  = 960
+	_ro  = 988
+	_ru  = 994
+	_sh  = 1031
+	_si  = 1036
+	_sk  = 1042
+	_sl  = 1046
+	_sq  = 1073
+	_sr  = 1074
+	_sv  = 1092
+	_sw  = 1093
+	_ta  = 1104
+	_te  = 1121
+	_th  = 1131
+	_tl  = 1146
+	_tn  = 1152
+	_tr  = 1162
+	_uk  = 1198
+	_ur  = 1204
+	_uz  = 1212
+	_vi  = 1219
+	_zh  = 1321
+	_zu  = 1327
+	_jbo = 515
+	_ami = 1650
+	_bnn = 2357
+	_hak = 438
+	_tlh = 14467
+	_lb  = 661
+	_nv  = 899
+	_pwn = 12055
+	_tao = 14188
+	_tay = 14198
+	_tsu = 14662
+	_nn  = 874
+	_sfb = 13629
+	_vgt = 15701
+	_sgg = 13660
+	_cmn = 3007
+	_nan = 835
+	_hsn = 467
+)
+
+const langPrivateStart = 0x2f72
+
+const langPrivateEnd = 0x3179
+
+// lang holds an alphabetically sorted list of ISO-639 language identifiers.
+// All entries are 4 bytes. The index of the identifier (divided by 4) is the language tag.
+// For 2-byte language identifiers, the two successive bytes have the following meaning:
+//   - if the first letter of the 2- and 3-letter ISO codes are the same:
+//     the second and third letter of the 3-letter ISO code.
+//   - otherwise: a 0 and a by 2 bits right-shifted index into altLangISO3.
+//
+// For 3-byte language identifiers the 4th byte is 0.
+const lang tag.Index = "" + // Size: 5324 bytes
+	"---\x00aaaraai\x00aak\x00aau\x00abbkabi\x00abq\x00abr\x00abt\x00aby\x00a" +
+	"cd\x00ace\x00ach\x00ada\x00ade\x00adj\x00ady\x00adz\x00aeveaeb\x00aey" +
+	"\x00affragc\x00agd\x00agg\x00agm\x00ago\x00agq\x00aha\x00ahl\x00aho\x00a" +
+	"jg\x00akkaakk\x00ala\x00ali\x00aln\x00alt\x00ammhamm\x00amn\x00amo\x00am" +
+	"p\x00anrganc\x00ank\x00ann\x00any\x00aoj\x00aom\x00aoz\x00apc\x00apd\x00" +
+	"ape\x00apr\x00aps\x00apz\x00arraarc\x00arh\x00arn\x00aro\x00arq\x00ars" +
+	"\x00ary\x00arz\x00assmasa\x00ase\x00asg\x00aso\x00ast\x00ata\x00atg\x00a" +
+	"tj\x00auy\x00avvaavl\x00avn\x00avt\x00avu\x00awa\x00awb\x00awo\x00awx" +
+	"\x00ayymayb\x00azzebaakbal\x00ban\x00bap\x00bar\x00bas\x00bav\x00bax\x00" +
+	"bba\x00bbb\x00bbc\x00bbd\x00bbj\x00bbp\x00bbr\x00bcf\x00bch\x00bci\x00bc" +
+	"m\x00bcn\x00bco\x00bcq\x00bcu\x00bdd\x00beelbef\x00beh\x00bej\x00bem\x00" +
+	"bet\x00bew\x00bex\x00bez\x00bfd\x00bfq\x00bft\x00bfy\x00bgulbgc\x00bgn" +
+	"\x00bgx\x00bhihbhb\x00bhg\x00bhi\x00bhk\x00bhl\x00bho\x00bhy\x00biisbib" +
+	"\x00big\x00bik\x00bim\x00bin\x00bio\x00biq\x00bjh\x00bji\x00bjj\x00bjn" +
+	"\x00bjo\x00bjr\x00bjt\x00bjz\x00bkc\x00bkm\x00bkq\x00bku\x00bkv\x00blt" +
+	"\x00bmambmh\x00bmk\x00bmq\x00bmu\x00bnenbng\x00bnm\x00bnp\x00boodboj\x00" +
+	"bom\x00bon\x00bpy\x00bqc\x00bqi\x00bqp\x00bqv\x00brrebra\x00brh\x00brx" +
+	"\x00brz\x00bsosbsj\x00bsq\x00bss\x00bst\x00bto\x00btt\x00btv\x00bua\x00b" +
+	"uc\x00bud\x00bug\x00buk\x00bum\x00buo\x00bus\x00buu\x00bvb\x00bwd\x00bwr" +
+	"\x00bxh\x00bye\x00byn\x00byr\x00bys\x00byv\x00byx\x00bza\x00bze\x00bzf" +
+	"\x00bzh\x00bzw\x00caatcan\x00cbj\x00cch\x00ccp\x00ceheceb\x00cfa\x00cgg" +
+	"\x00chhachk\x00chm\x00cho\x00chp\x00chr\x00cja\x00cjm\x00cjv\x00ckb\x00c" +
+	"kl\x00cko\x00cky\x00cla\x00cme\x00cmg\x00cooscop\x00cps\x00crrecrh\x00cr" +
+	"j\x00crk\x00crl\x00crm\x00crs\x00csescsb\x00csw\x00ctd\x00cuhucvhvcyymda" +
+	"andad\x00daf\x00dag\x00dah\x00dak\x00dar\x00dav\x00dbd\x00dbq\x00dcc\x00" +
+	"ddn\x00deeuded\x00den\x00dga\x00dgh\x00dgi\x00dgl\x00dgr\x00dgz\x00dia" +
+	"\x00dje\x00dnj\x00dob\x00doi\x00dop\x00dow\x00dri\x00drs\x00dsb\x00dtm" +
+	"\x00dtp\x00dts\x00dty\x00dua\x00duc\x00dud\x00dug\x00dvivdva\x00dww\x00d" +
+	"yo\x00dyu\x00dzzodzg\x00ebu\x00eeweefi\x00egl\x00egy\x00eka\x00eky\x00el" +
+	"llema\x00emi\x00enngenn\x00enq\x00eopoeri\x00es\x00\x05esu\x00etstetr" +
+	"\x00ett\x00etu\x00etx\x00euusewo\x00ext\x00faasfaa\x00fab\x00fag\x00fai" +
+	"\x00fan\x00ffulffi\x00ffm\x00fiinfia\x00fil\x00fit\x00fjijflr\x00fmp\x00" +
+	"foaofod\x00fon\x00for\x00fpe\x00fqs\x00frrafrc\x00frp\x00frr\x00frs\x00f" +
+	"ub\x00fud\x00fue\x00fuf\x00fuh\x00fuq\x00fur\x00fuv\x00fuy\x00fvr\x00fyr" +
+	"ygalegaa\x00gaf\x00gag\x00gah\x00gaj\x00gam\x00gan\x00gaw\x00gay\x00gba" +
+	"\x00gbf\x00gbm\x00gby\x00gbz\x00gcr\x00gdlagde\x00gdn\x00gdr\x00geb\x00g" +
+	"ej\x00gel\x00gez\x00gfk\x00ggn\x00ghs\x00gil\x00gim\x00gjk\x00gjn\x00gju" +
+	"\x00gkn\x00gkp\x00gllgglk\x00gmm\x00gmv\x00gnrngnd\x00gng\x00god\x00gof" +
+	"\x00goi\x00gom\x00gon\x00gor\x00gos\x00got\x00grb\x00grc\x00grt\x00grw" +
+	"\x00gsw\x00guujgub\x00guc\x00gud\x00gur\x00guw\x00gux\x00guz\x00gvlvgvf" +
+	"\x00gvr\x00gvs\x00gwc\x00gwi\x00gwt\x00gyi\x00haauhag\x00hak\x00ham\x00h" +
+	"aw\x00haz\x00hbb\x00hdy\x00heebhhy\x00hiinhia\x00hif\x00hig\x00hih\x00hi" +
+	"l\x00hla\x00hlu\x00hmd\x00hmt\x00hnd\x00hne\x00hnj\x00hnn\x00hno\x00homo" +
+	"hoc\x00hoj\x00hot\x00hrrvhsb\x00hsn\x00htathuunhui\x00hyyehzerianaian" +
+	"\x00iar\x00iba\x00ibb\x00iby\x00ica\x00ich\x00idndidd\x00idi\x00idu\x00i" +
+	"eleife\x00igboigb\x00ige\x00iiiiijj\x00ikpkikk\x00ikt\x00ikw\x00ikx\x00i" +
+	"lo\x00imo\x00inndinh\x00iodoiou\x00iri\x00isslittaiukuiw\x00\x03iwm\x00i" +
+	"ws\x00izh\x00izi\x00japnjab\x00jam\x00jbo\x00jbu\x00jen\x00jgk\x00jgo" +
+	"\x00ji\x00\x06jib\x00jmc\x00jml\x00jra\x00jut\x00jvavjwavkaatkaa\x00kab" +
+	"\x00kac\x00kad\x00kai\x00kaj\x00kam\x00kao\x00kbd\x00kbm\x00kbp\x00kbq" +
+	"\x00kbx\x00kby\x00kcg\x00kck\x00kcl\x00kct\x00kde\x00kdh\x00kdl\x00kdt" +
+	"\x00kea\x00ken\x00kez\x00kfo\x00kfr\x00kfy\x00kgonkge\x00kgf\x00kgp\x00k" +
+	"ha\x00khb\x00khn\x00khq\x00khs\x00kht\x00khw\x00khz\x00kiikkij\x00kiu" +
+	"\x00kiw\x00kjuakjd\x00kjg\x00kjs\x00kjy\x00kkazkkc\x00kkj\x00klalkln\x00" +
+	"klq\x00klt\x00klx\x00kmhmkmb\x00kmh\x00kmo\x00kms\x00kmu\x00kmw\x00knank" +
+	"nf\x00knp\x00koorkoi\x00kok\x00kol\x00kos\x00koz\x00kpe\x00kpf\x00kpo" +
+	"\x00kpr\x00kpx\x00kqb\x00kqf\x00kqs\x00kqy\x00kraukrc\x00kri\x00krj\x00k" +
+	"rl\x00krs\x00kru\x00ksasksb\x00ksd\x00ksf\x00ksh\x00ksj\x00ksr\x00ktb" +
+	"\x00ktm\x00kto\x00kuurkub\x00kud\x00kue\x00kuj\x00kum\x00kun\x00kup\x00k" +
+	"us\x00kvomkvg\x00kvr\x00kvx\x00kw\x00\x01kwj\x00kwo\x00kxa\x00kxc\x00kxm" +
+	"\x00kxp\x00kxw\x00kxz\x00kyirkye\x00kyx\x00kzr\x00laatlab\x00lad\x00lag" +
+	"\x00lah\x00laj\x00las\x00lbtzlbe\x00lbu\x00lbw\x00lcm\x00lcp\x00ldb\x00l" +
+	"ed\x00lee\x00lem\x00lep\x00leq\x00leu\x00lez\x00lguglgg\x00liimlia\x00li" +
+	"d\x00lif\x00lig\x00lih\x00lij\x00lis\x00ljp\x00lki\x00lkt\x00lle\x00lln" +
+	"\x00lmn\x00lmo\x00lmp\x00lninlns\x00lnu\x00loaoloj\x00lok\x00lol\x00lor" +
+	"\x00los\x00loz\x00lrc\x00ltitltg\x00luublua\x00luo\x00luy\x00luz\x00lvav" +
+	"lwl\x00lzh\x00lzz\x00mad\x00maf\x00mag\x00mai\x00mak\x00man\x00mas\x00ma" +
+	"w\x00maz\x00mbh\x00mbo\x00mbq\x00mbu\x00mbw\x00mci\x00mcp\x00mcq\x00mcr" +
+	"\x00mcu\x00mda\x00mde\x00mdf\x00mdh\x00mdj\x00mdr\x00mdx\x00med\x00mee" +
+	"\x00mek\x00men\x00mer\x00met\x00meu\x00mfa\x00mfe\x00mfn\x00mfo\x00mfq" +
+	"\x00mglgmgh\x00mgl\x00mgo\x00mgp\x00mgy\x00mhahmhi\x00mhl\x00mirimif\x00" +
+	"min\x00mis\x00miw\x00mkkdmki\x00mkl\x00mkp\x00mkw\x00mlalmle\x00mlp\x00m" +
+	"ls\x00mmo\x00mmu\x00mmx\x00mnonmna\x00mnf\x00mni\x00mnw\x00moolmoa\x00mo" +
+	"e\x00moh\x00mos\x00mox\x00mpp\x00mps\x00mpt\x00mpx\x00mql\x00mrarmrd\x00" +
+	"mrj\x00mro\x00mssamtltmtc\x00mtf\x00mti\x00mtr\x00mua\x00mul\x00mur\x00m" +
+	"us\x00mva\x00mvn\x00mvy\x00mwk\x00mwr\x00mwv\x00mxc\x00mxm\x00myyamyk" +
+	"\x00mym\x00myv\x00myw\x00myx\x00myz\x00mzk\x00mzm\x00mzn\x00mzp\x00mzw" +
+	"\x00mzz\x00naaunac\x00naf\x00nah\x00nak\x00nan\x00nap\x00naq\x00nas\x00n" +
+	"bobnca\x00nce\x00ncf\x00nch\x00nco\x00ncu\x00nddendc\x00nds\x00neepneb" +
+	"\x00new\x00nex\x00nfr\x00ngdonga\x00ngb\x00ngl\x00nhb\x00nhe\x00nhw\x00n" +
+	"if\x00nii\x00nij\x00nin\x00niu\x00niy\x00niz\x00njo\x00nkg\x00nko\x00nll" +
+	"dnmg\x00nmz\x00nnnonnf\x00nnh\x00nnk\x00nnm\x00noornod\x00noe\x00non\x00" +
+	"nop\x00nou\x00nqo\x00nrblnrb\x00nsk\x00nsn\x00nso\x00nss\x00ntm\x00ntr" +
+	"\x00nui\x00nup\x00nus\x00nuv\x00nux\x00nvavnwb\x00nxq\x00nxr\x00nyyanym" +
+	"\x00nyn\x00nzi\x00occiogc\x00ojjiokr\x00okv\x00omrmong\x00onn\x00ons\x00" +
+	"opm\x00orrioro\x00oru\x00osssosa\x00ota\x00otk\x00ozm\x00paanpag\x00pal" +
+	"\x00pam\x00pap\x00pau\x00pbi\x00pcd\x00pcm\x00pdc\x00pdt\x00ped\x00peo" +
+	"\x00pex\x00pfl\x00phl\x00phn\x00pilipil\x00pip\x00pka\x00pko\x00plolpla" +
+	"\x00pms\x00png\x00pnn\x00pnt\x00pon\x00ppo\x00pra\x00prd\x00prg\x00psusp" +
+	"ss\x00ptorptp\x00puu\x00pwa\x00quuequc\x00qug\x00rai\x00raj\x00rao\x00rc" +
+	"f\x00rej\x00rel\x00res\x00rgn\x00rhg\x00ria\x00rif\x00rjs\x00rkt\x00rmoh" +
+	"rmf\x00rmo\x00rmt\x00rmu\x00rnunrna\x00rng\x00roonrob\x00rof\x00roo\x00r" +
+	"ro\x00rtm\x00ruusrue\x00rug\x00rw\x00\x04rwk\x00rwo\x00ryu\x00saansaf" +
+	"\x00sah\x00saq\x00sas\x00sat\x00sav\x00saz\x00sba\x00sbe\x00sbp\x00scrds" +
+	"ck\x00scl\x00scn\x00sco\x00scs\x00sdndsdc\x00sdh\x00semesef\x00seh\x00se" +
+	"i\x00ses\x00sgagsga\x00sgs\x00sgw\x00sgz\x00sh\x00\x02shi\x00shk\x00shn" +
+	"\x00shu\x00siinsid\x00sig\x00sil\x00sim\x00sjr\x00sklkskc\x00skr\x00sks" +
+	"\x00sllvsld\x00sli\x00sll\x00sly\x00smmosma\x00smi\x00smj\x00smn\x00smp" +
+	"\x00smq\x00sms\x00snnasnc\x00snk\x00snp\x00snx\x00sny\x00soomsok\x00soq" +
+	"\x00sou\x00soy\x00spd\x00spl\x00sps\x00sqqisrrpsrb\x00srn\x00srr\x00srx" +
+	"\x00ssswssd\x00ssg\x00ssy\x00stotstk\x00stq\x00suunsua\x00sue\x00suk\x00" +
+	"sur\x00sus\x00svweswwaswb\x00swc\x00swg\x00swp\x00swv\x00sxn\x00sxw\x00s" +
+	"yl\x00syr\x00szl\x00taamtaj\x00tal\x00tan\x00taq\x00tbc\x00tbd\x00tbf" +
+	"\x00tbg\x00tbo\x00tbw\x00tbz\x00tci\x00tcy\x00tdd\x00tdg\x00tdh\x00teelt" +
+	"ed\x00tem\x00teo\x00tet\x00tfi\x00tggktgc\x00tgo\x00tgu\x00thhathl\x00th" +
+	"q\x00thr\x00tiirtif\x00tig\x00tik\x00tim\x00tio\x00tiv\x00tkuktkl\x00tkr" +
+	"\x00tkt\x00tlgltlf\x00tlx\x00tly\x00tmh\x00tmy\x00tnsntnh\x00toontof\x00" +
+	"tog\x00toq\x00tpi\x00tpm\x00tpz\x00tqo\x00trurtru\x00trv\x00trw\x00tssot" +
+	"sd\x00tsf\x00tsg\x00tsj\x00tsw\x00ttatttd\x00tte\x00ttj\x00ttr\x00tts" +
+	"\x00ttt\x00tuh\x00tul\x00tum\x00tuq\x00tvd\x00tvl\x00tvu\x00twwitwh\x00t" +
+	"wq\x00txg\x00tyahtya\x00tyv\x00tzm\x00ubu\x00udm\x00ugiguga\x00ukkruli" +
+	"\x00umb\x00und\x00unr\x00unx\x00urrduri\x00urt\x00urw\x00usa\x00utr\x00u" +
+	"vh\x00uvl\x00uzzbvag\x00vai\x00van\x00veenvec\x00vep\x00viievic\x00viv" +
+	"\x00vls\x00vmf\x00vmw\x00voolvot\x00vro\x00vun\x00vut\x00walnwae\x00waj" +
+	"\x00wal\x00wan\x00war\x00wbp\x00wbq\x00wbr\x00wci\x00wer\x00wgi\x00whg" +
+	"\x00wib\x00wiu\x00wiv\x00wja\x00wji\x00wls\x00wmo\x00wnc\x00wni\x00wnu" +
+	"\x00woolwob\x00wos\x00wrs\x00wsk\x00wtm\x00wuu\x00wuv\x00wwa\x00xav\x00x" +
+	"bi\x00xcr\x00xes\x00xhhoxla\x00xlc\x00xld\x00xmf\x00xmn\x00xmr\x00xna" +
+	"\x00xnr\x00xog\x00xon\x00xpr\x00xrb\x00xsa\x00xsi\x00xsm\x00xsr\x00xwe" +
+	"\x00yam\x00yao\x00yap\x00yas\x00yat\x00yav\x00yay\x00yaz\x00yba\x00ybb" +
+	"\x00yby\x00yer\x00ygr\x00ygw\x00yiidyko\x00yle\x00ylg\x00yll\x00yml\x00y" +
+	"ooryon\x00yrb\x00yre\x00yrl\x00yss\x00yua\x00yue\x00yuj\x00yut\x00yuw" +
+	"\x00zahazag\x00zbl\x00zdj\x00zea\x00zgh\x00zhhozhx\x00zia\x00zlm\x00zmi" +
+	"\x00zne\x00zuulzxx\x00zza\x00\xff\xff\xff\xff"
+
+const langNoIndexOffset = 1330
+
+// langNoIndex is a bit vector of all 3-letter language codes that are not used as an index
+// in lookup tables. The language ids for these language codes are derived directly
+// from the letters and are not consecutive.
+// Size: 2197 bytes, 2197 elements
+var langNoIndex = [2197]uint8{
+	// Entry 0 - 3F
+	0xff, 0xf8, 0xed, 0xfe, 0xeb, 0xd3, 0x3b, 0xd2,
+	0xfb, 0xbf, 0x7a, 0xfa, 0x37, 0x1d, 0x3c, 0x57,
+	0x6e, 0x97, 0x73, 0x38, 0xfb, 0xea, 0xbf, 0x70,
+	0xad, 0x03, 0xff, 0xff, 0xcf, 0x05, 0x84, 0x72,
+	0xe9, 0xbf, 0xfd, 0xbf, 0xbf, 0xf7, 0xfd, 0x77,
+	0x0f, 0xff, 0xef, 0x6f, 0xff, 0xfb, 0xdf, 0xe2,
+	0xc9, 0xf8, 0x7f, 0x7e, 0x4d, 0xbc, 0x0a, 0x6a,
+	0x7c, 0xea, 0xe3, 0xfa, 0x7a, 0xbf, 0x67, 0xff,
+	// Entry 40 - 7F
+	0xff, 0xff, 0xff, 0xdf, 0x2a, 0x54, 0x91, 0xc0,
+	0x5d, 0xe3, 0x97, 0x14, 0x07, 0x20, 0xdd, 0xed,
+	0x9f, 0x3f, 0xc9, 0x21, 0xf8, 0x3f, 0x94, 0x35,
+	0x7c, 0x5f, 0xff, 0x5f, 0x8e, 0x6e, 0xdf, 0xff,
+	0xff, 0xff, 0x55, 0x7c, 0xd3, 0xfd, 0xbf, 0xb5,
+	0x7b, 0xdf, 0x7f, 0xf7, 0xca, 0xfe, 0xdb, 0xa3,
+	0xa8, 0xff, 0x1f, 0x67, 0x7d, 0xeb, 0xef, 0xce,
+	0xff, 0xff, 0x9f, 0xff, 0xb7, 0xef, 0xfe, 0xcf,
+	// Entry 80 - BF
+	0xdb, 0xff, 0xf3, 0xcd, 0xfb, 0x7f, 0xff, 0xff,
+	0xbb, 0xee, 0xf7, 0xbd, 0xdb, 0xff, 0x5f, 0xf7,
+	0xfd, 0xf2, 0xfd, 0xff, 0x5e, 0x2f, 0x3b, 0xba,
+	0x7e, 0xff, 0xff, 0xfe, 0xf7, 0xff, 0xdd, 0xff,
+	0xfd, 0xdf, 0xfb, 0xfe, 0x9d, 0xb4, 0xd3, 0xff,
+	0xef, 0xff, 0xdf, 0xf7, 0x7f, 0xb7, 0xfd, 0xd5,
+	0xa5, 0x77, 0x40, 0xff, 0x9c, 0xc1, 0x41, 0x2c,
+	0x08, 0x21, 0x41, 0x00, 0x50, 0x40, 0x00, 0x80,
+	// Entry C0 - FF
+	0xfb, 0x4a, 0xf2, 0x9f, 0xb4, 0x42, 0x41, 0x96,
+	0x1b, 0x14, 0x08, 0xf3, 0x2b, 0xe7, 0x17, 0x56,
+	0x05, 0x7d, 0x0e, 0x1c, 0x37, 0x7f, 0xf3, 0xef,
+	0x97, 0xff, 0x5d, 0x38, 0x64, 0x08, 0x00, 0x10,
+	0xbc, 0x85, 0xaf, 0xdf, 0xff, 0xff, 0x7b, 0x35,
+	0x3e, 0xc7, 0xc7, 0xdf, 0xff, 0x01, 0x81, 0x00,
+	0xb0, 0x05, 0x80, 0x00, 0x20, 0x00, 0x00, 0x03,
+	0x40, 0x00, 0x40, 0x92, 0x21, 0x50, 0xb1, 0x5d,
+	// Entry 100 - 13F
+	0xfd, 0xdc, 0xbe, 0x5e, 0x00, 0x00, 0x02, 0x64,
+	0x0d, 0x19, 0x41, 0xdf, 0x79, 0x22, 0x00, 0x00,
+	0x00, 0x5e, 0x64, 0xdc, 0x24, 0xe5, 0xd9, 0xe3,
+	0xfe, 0xff, 0xfd, 0xcb, 0x9f, 0x14, 0x41, 0x0c,
+	0x86, 0x00, 0xd1, 0x00, 0xf0, 0xc7, 0x67, 0x5f,
+	0x56, 0x99, 0x5e, 0xb5, 0x6c, 0xaf, 0x03, 0x00,
+	0x02, 0x00, 0x00, 0x00, 0xc0, 0x37, 0xda, 0x56,
+	0x90, 0x6d, 0x01, 0x2e, 0x96, 0x69, 0x20, 0xfb,
+	// Entry 140 - 17F
+	0xff, 0x3f, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x16,
+	0x03, 0x00, 0x00, 0xb0, 0x14, 0x23, 0x50, 0x06,
+	0x0a, 0x00, 0x01, 0x00, 0x00, 0x10, 0x11, 0x09,
+	0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x10,
+	0x00, 0x00, 0x44, 0x00, 0x00, 0x10, 0x00, 0x05,
+	0x08, 0x00, 0x00, 0x05, 0x00, 0x80, 0x28, 0x04,
+	0x00, 0x00, 0x40, 0xd5, 0x2d, 0x00, 0x64, 0x35,
+	0x24, 0x52, 0xf4, 0xd5, 0xbf, 0x62, 0xc9, 0x03,
+	// Entry 180 - 1BF
+	0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x04, 0x13, 0x39, 0x01, 0xdd, 0x57, 0x98,
+	0x21, 0x18, 0x81, 0x08, 0x00, 0x01, 0x40, 0x82,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x40, 0x00, 0x44, 0x00, 0x00, 0x80, 0xea,
+	0xa9, 0x39, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+	// Entry 1C0 - 1FF
+	0x00, 0x03, 0x28, 0x05, 0x00, 0x00, 0x00, 0x00,
+	0x04, 0x20, 0x04, 0xa6, 0x00, 0x04, 0x00, 0x00,
+	0x81, 0x50, 0x00, 0x00, 0x00, 0x11, 0x84, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x55,
+	0x02, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x40,
+	0x30, 0x83, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x1e, 0xcd, 0xbf, 0x7a, 0xbf,
+	// Entry 200 - 23F
+	0xdf, 0xc3, 0x83, 0x82, 0xc0, 0xfb, 0x57, 0x27,
+	0xed, 0x55, 0xe7, 0x01, 0x00, 0x20, 0xb2, 0xc5,
+	0xa4, 0x45, 0x25, 0x9b, 0x02, 0xdf, 0xe1, 0xdf,
+	0x03, 0x44, 0x08, 0x90, 0x01, 0x04, 0x81, 0xe3,
+	0x92, 0x54, 0xdb, 0x28, 0xd3, 0x5f, 0xfe, 0x6d,
+	0x79, 0xed, 0x1c, 0x7f, 0x04, 0x08, 0x00, 0x01,
+	0x21, 0x12, 0x64, 0x5f, 0xdd, 0x0e, 0x85, 0x4f,
+	0x40, 0x40, 0x00, 0x04, 0xf1, 0xfd, 0x3d, 0x54,
+	// Entry 240 - 27F
+	0xe8, 0x03, 0xb4, 0x27, 0x23, 0x0d, 0x00, 0x00,
+	0x20, 0x7b, 0x78, 0x02, 0x07, 0x84, 0x00, 0xf0,
+	0xbb, 0x7e, 0x5a, 0x00, 0x18, 0x04, 0x81, 0x00,
+	0x00, 0x00, 0x80, 0x10, 0x90, 0x1c, 0x01, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x04,
+	0x08, 0xa0, 0x70, 0xa5, 0x0c, 0x40, 0x00, 0x00,
+	0x91, 0x24, 0x04, 0x68, 0x00, 0x20, 0x70, 0xff,
+	0x7b, 0x7f, 0x70, 0x00, 0x05, 0x9b, 0xdd, 0x66,
+	// Entry 280 - 2BF
+	0x03, 0x00, 0x11, 0x00, 0x00, 0x00, 0x40, 0x05,
+	0xb5, 0xb6, 0x80, 0x08, 0x04, 0x00, 0x04, 0x51,
+	0xe2, 0xef, 0xfd, 0x3f, 0x05, 0x09, 0x08, 0x05,
+	0x40, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+	0x0c, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x60,
+	0xe7, 0x48, 0x00, 0x81, 0x20, 0xc0, 0x05, 0x80,
+	0x03, 0x00, 0x00, 0x00, 0x8c, 0x50, 0x40, 0x04,
+	0x84, 0x47, 0x84, 0x40, 0x20, 0x10, 0x00, 0x20,
+	// Entry 2C0 - 2FF
+	0x02, 0x50, 0x80, 0x11, 0x00, 0x99, 0x6c, 0xe2,
+	0x50, 0x27, 0x1d, 0x11, 0x29, 0x0e, 0x59, 0xe9,
+	0x33, 0x08, 0x00, 0x20, 0x04, 0x40, 0x10, 0x00,
+	0x00, 0x00, 0x50, 0x44, 0x92, 0x49, 0xd6, 0x5d,
+	0xa7, 0x81, 0x47, 0x97, 0xfb, 0x00, 0x10, 0x00,
+	0x08, 0x00, 0x80, 0x00, 0x40, 0x04, 0x00, 0x01,
+	0x02, 0x00, 0x01, 0x40, 0x80, 0x00, 0x40, 0x08,
+	0xd8, 0xeb, 0xf6, 0x39, 0xc4, 0x8d, 0x12, 0x00,
+	// Entry 300 - 33F
+	0x00, 0x0c, 0x04, 0x01, 0x20, 0x20, 0xdd, 0xa0,
+	0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+	0x04, 0x10, 0xd0, 0x9d, 0x95, 0x13, 0x04, 0x80,
+	0x00, 0x01, 0xd0, 0x16, 0x40, 0x00, 0x10, 0xb0,
+	0x10, 0x62, 0x4c, 0xd2, 0x02, 0x01, 0x4a, 0x00,
+	0x46, 0x04, 0x00, 0x08, 0x02, 0x00, 0x20, 0x80,
+	0x00, 0x80, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0xf0, 0xd8, 0x6f, 0x15, 0x02, 0x08, 0x00,
+	// Entry 340 - 37F
+	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01,
+	0x00, 0x10, 0x00, 0x00, 0x00, 0xf0, 0x84, 0xe3,
+	0xdd, 0xbf, 0xf9, 0xf9, 0x3b, 0x7f, 0x7f, 0xdb,
+	0xfd, 0xfc, 0xfe, 0xdf, 0xff, 0xfd, 0xff, 0xf6,
+	0xfb, 0xfc, 0xf7, 0x1f, 0xff, 0xb3, 0x6c, 0xff,
+	0xd9, 0xad, 0xdf, 0xfe, 0xef, 0xba, 0xdf, 0xff,
+	0xff, 0xff, 0xb7, 0xdd, 0x7d, 0xbf, 0xab, 0x7f,
+	0xfd, 0xfd, 0xdf, 0x2f, 0x9c, 0xdf, 0xf3, 0x6f,
+	// Entry 380 - 3BF
+	0xdf, 0xdd, 0xff, 0xfb, 0xee, 0xd2, 0xab, 0x5f,
+	0xd5, 0xdf, 0x7f, 0xff, 0xeb, 0xff, 0xe4, 0x4d,
+	0xf9, 0xff, 0xfe, 0xf7, 0xfd, 0xdf, 0xfb, 0xbf,
+	0xee, 0xdb, 0x6f, 0xef, 0xff, 0x7f, 0xff, 0xff,
+	0xf7, 0x5f, 0xd3, 0x3b, 0xfd, 0xd9, 0xdf, 0xeb,
+	0xbc, 0x08, 0x05, 0x24, 0xff, 0x07, 0x70, 0xfe,
+	0xe6, 0x5e, 0x00, 0x08, 0x00, 0x83, 0x7d, 0x1f,
+	0x06, 0xe6, 0x72, 0x60, 0xd1, 0x3c, 0x7f, 0x44,
+	// Entry 3C0 - 3FF
+	0x02, 0x30, 0x9f, 0x7a, 0x16, 0xbd, 0x7f, 0x57,
+	0xf2, 0xff, 0x31, 0xff, 0xf2, 0x1e, 0x90, 0xf7,
+	0xf1, 0xf9, 0x45, 0x80, 0x01, 0x02, 0x00, 0x20,
+	0x40, 0x54, 0x9f, 0x8a, 0xdf, 0xf9, 0x6e, 0x11,
+	0x86, 0x51, 0xc0, 0xf3, 0xfb, 0x47, 0x40, 0x03,
+	0x05, 0xd1, 0x50, 0x5c, 0x00, 0x40, 0x00, 0x10,
+	0x04, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x17, 0xd2,
+	0xb9, 0xfd, 0xfc, 0xba, 0xfe, 0xef, 0xc7, 0xbe,
+	// Entry 400 - 43F
+	0x53, 0x6f, 0xdf, 0xe7, 0xdb, 0x65, 0xbb, 0x7f,
+	0xfa, 0xff, 0x77, 0xf3, 0xef, 0xbf, 0xfd, 0xf7,
+	0xdf, 0xdf, 0x9b, 0x7f, 0xff, 0xff, 0x7f, 0x6f,
+	0xf7, 0xfb, 0xeb, 0xdf, 0xbc, 0xff, 0xbf, 0x6b,
+	0x7b, 0xfb, 0xff, 0xce, 0x76, 0xbd, 0xf7, 0xf7,
+	0xdf, 0xdc, 0xf7, 0xf7, 0xff, 0xdf, 0xf3, 0xfe,
+	0xef, 0xff, 0xff, 0xff, 0xb6, 0x7f, 0x7f, 0xde,
+	0xf7, 0xb9, 0xeb, 0x77, 0xff, 0xfb, 0xbf, 0xdf,
+	// Entry 440 - 47F
+	0xfd, 0xfe, 0xfb, 0xff, 0xfe, 0xeb, 0x1f, 0x7d,
+	0x2f, 0xfd, 0xb6, 0xb5, 0xa5, 0xfc, 0xff, 0xfd,
+	0x7f, 0x4e, 0xbf, 0x8f, 0xae, 0xff, 0xee, 0xdf,
+	0x7f, 0xf7, 0x73, 0x02, 0x02, 0x04, 0xfc, 0xf7,
+	0xff, 0xb7, 0xd7, 0xef, 0xfe, 0xcd, 0xf5, 0xce,
+	0xe2, 0x8e, 0xe7, 0xbf, 0xb7, 0xff, 0x56, 0xfd,
+	0xcd, 0xff, 0xfb, 0xff, 0xdf, 0xd7, 0xea, 0xff,
+	0xe5, 0x5f, 0x6d, 0x0f, 0xa7, 0x51, 0x06, 0xc4,
+	// Entry 480 - 4BF
+	0x93, 0x50, 0x5d, 0xaf, 0xa6, 0xff, 0x99, 0xfb,
+	0x63, 0x1d, 0x53, 0xff, 0xef, 0xb7, 0x35, 0x20,
+	0x14, 0x00, 0x55, 0x51, 0xc2, 0x65, 0xf5, 0x41,
+	0xe2, 0xff, 0xfc, 0xdf, 0x02, 0x85, 0xc5, 0x05,
+	0x00, 0x22, 0x00, 0x74, 0x69, 0x10, 0x08, 0x05,
+	0x41, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x51, 0x20, 0x05, 0x04, 0x01, 0x00, 0x00,
+	0x06, 0x11, 0x20, 0x00, 0x18, 0x01, 0x92, 0xf1,
+	// Entry 4C0 - 4FF
+	0xfd, 0x47, 0x69, 0x06, 0x95, 0x06, 0x57, 0xed,
+	0xfb, 0x4d, 0x1c, 0x6b, 0x83, 0x04, 0x62, 0x40,
+	0x00, 0x11, 0x42, 0x00, 0x00, 0x00, 0x54, 0x83,
+	0xb8, 0x4f, 0x10, 0x8e, 0x89, 0x46, 0xde, 0xf7,
+	0x13, 0x31, 0x00, 0x20, 0x00, 0x00, 0x00, 0x90,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x10, 0x00,
+	0x01, 0x00, 0x00, 0xf0, 0x5b, 0xf4, 0xbe, 0x3d,
+	0xbe, 0xcf, 0xf7, 0xaf, 0x42, 0x04, 0x84, 0x41,
+	// Entry 500 - 53F
+	0x30, 0xff, 0x79, 0x72, 0x04, 0x00, 0x00, 0x49,
+	0x2d, 0x14, 0x27, 0x5f, 0xed, 0xf1, 0x3f, 0xe7,
+	0x3f, 0x00, 0x00, 0x02, 0xc6, 0xa0, 0x1e, 0xf8,
+	0xbb, 0xff, 0xfd, 0xfb, 0xb7, 0xfd, 0xe7, 0xf7,
+	0xfd, 0xfc, 0xd5, 0xed, 0x47, 0xf4, 0x7e, 0x10,
+	0x01, 0x01, 0x84, 0x6d, 0xff, 0xf7, 0xdd, 0xf9,
+	0x5b, 0x05, 0x86, 0xed, 0xf5, 0x77, 0xbd, 0x3c,
+	0x00, 0x00, 0x00, 0x42, 0x71, 0x42, 0x00, 0x40,
+	// Entry 540 - 57F
+	0x00, 0x00, 0x01, 0x43, 0x19, 0x24, 0x08, 0x00,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	// Entry 580 - 5BF
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xab, 0xbd, 0xe7, 0x57, 0xee, 0x13, 0x5d,
+	0x09, 0xc1, 0x40, 0x21, 0xfa, 0x17, 0x01, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0xf0, 0xce, 0xfb, 0xbf,
+	0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x30, 0x15, 0xa3, 0x10, 0x00, 0x00, 0x00,
+	0x11, 0x04, 0x16, 0x00, 0x00, 0x02, 0x20, 0x81,
+	0xa3, 0x01, 0x50, 0x00, 0x00, 0x83, 0x11, 0x40,
+	// Entry 5C0 - 5FF
+	0x00, 0x00, 0x00, 0xf0, 0xdd, 0x7b, 0xbe, 0x02,
+	0xaa, 0x10, 0x5d, 0x98, 0x52, 0x00, 0x80, 0x20,
+	0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x02,
+	0x3d, 0x40, 0x10, 0x02, 0x10, 0x61, 0x5a, 0x9d,
+	0x31, 0x00, 0x00, 0x00, 0x01, 0x18, 0x02, 0x20,
+	0x00, 0x00, 0x01, 0x00, 0x42, 0x00, 0x20, 0x00,
+	0x00, 0x1f, 0xdf, 0xd2, 0xb9, 0xff, 0xfd, 0x3f,
+	0x1f, 0x98, 0xcf, 0x9c, 0xff, 0xaf, 0x5f, 0xfe,
+	// Entry 600 - 63F
+	0x7b, 0x4b, 0x40, 0x10, 0xe1, 0xfd, 0xaf, 0xd9,
+	0xb7, 0xf6, 0xfb, 0xb3, 0xc7, 0xff, 0x6f, 0xf1,
+	0x73, 0xb1, 0x7f, 0x9f, 0x7f, 0xbd, 0xfc, 0xb7,
+	0xee, 0x1c, 0xfa, 0xcb, 0xef, 0xdd, 0xf9, 0xbd,
+	0x6e, 0xae, 0x55, 0xfd, 0x6e, 0x81, 0x76, 0x9f,
+	0xd4, 0x77, 0xf5, 0x7d, 0xfb, 0xff, 0xeb, 0xfe,
+	0xbe, 0x5f, 0x46, 0x5b, 0xe9, 0x5f, 0x50, 0x18,
+	0x02, 0xfa, 0xf7, 0x9d, 0x15, 0x97, 0x05, 0x0f,
+	// Entry 640 - 67F
+	0x75, 0xc4, 0x7d, 0x81, 0x92, 0xf5, 0x57, 0x6c,
+	0xff, 0xe4, 0xef, 0x6f, 0xff, 0xfc, 0xdd, 0xde,
+	0xfc, 0xfd, 0x76, 0x5f, 0x7a, 0x3f, 0x00, 0x98,
+	0x02, 0xfb, 0xa3, 0xef, 0xf3, 0xd6, 0xf2, 0xff,
+	0xb9, 0xda, 0x7d, 0xd0, 0x3e, 0x15, 0x7b, 0xb4,
+	0xf5, 0x3e, 0xff, 0xff, 0xf1, 0xf7, 0xff, 0xe7,
+	0x5f, 0xff, 0xff, 0x9e, 0xdf, 0xf6, 0xd7, 0xb9,
+	0xef, 0x27, 0x80, 0xbb, 0xc5, 0xff, 0xff, 0xe3,
+	// Entry 680 - 6BF
+	0x97, 0x9d, 0xbf, 0x9f, 0xf7, 0xc7, 0xfd, 0x37,
+	0xce, 0x7f, 0x44, 0x1d, 0x73, 0x7f, 0xf8, 0xda,
+	0x5d, 0xce, 0x7d, 0x06, 0xb9, 0xea, 0x79, 0xa0,
+	0x1a, 0x20, 0x00, 0x30, 0x02, 0x04, 0x24, 0x08,
+	0x04, 0x00, 0x00, 0x40, 0xd4, 0x02, 0x04, 0x00,
+	0x00, 0x04, 0x00, 0x04, 0x00, 0x20, 0x09, 0x06,
+	0x50, 0x00, 0x08, 0x00, 0x00, 0x00, 0x24, 0x00,
+	0x04, 0x00, 0x10, 0xdc, 0x58, 0xd7, 0x0d, 0x0f,
+	// Entry 6C0 - 6FF
+	0x54, 0x4d, 0xf1, 0x16, 0x44, 0xd5, 0x42, 0x08,
+	0x40, 0x02, 0x00, 0x40, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0xdc, 0xfb, 0xcb, 0x0e, 0x58, 0x48, 0x41,
+	0x24, 0x20, 0x04, 0x00, 0x30, 0x12, 0x40, 0x00,
+	0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0x80, 0x10, 0x10, 0xab,
+	0x6d, 0x93, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x80, 0x80, 0x25, 0x00, 0x00,
+	// Entry 700 - 73F
+	0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+	0x80, 0x86, 0xc2, 0x00, 0x00, 0x01, 0x00, 0x01,
+	0xff, 0x18, 0x02, 0x00, 0x02, 0xf0, 0xfd, 0x79,
+	0x3b, 0x00, 0x25, 0x00, 0x00, 0x00, 0x02, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+	0x03, 0x00, 0x09, 0x20, 0x00, 0x00, 0x01, 0x00,
+	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 740 - 77F
+	0x00, 0x00, 0x00, 0xef, 0xd5, 0xfd, 0xcf, 0x7e,
+	0xb0, 0x11, 0x00, 0x00, 0x00, 0x92, 0x01, 0x46,
+	0xcd, 0xf9, 0x5c, 0x00, 0x01, 0x00, 0x30, 0x04,
+	0x04, 0x55, 0x00, 0x01, 0x04, 0xf4, 0x3f, 0x4a,
+	0x01, 0x00, 0x00, 0xb0, 0x80, 0x20, 0x55, 0x75,
+	0x97, 0x7c, 0xdf, 0x31, 0xcc, 0x68, 0xd1, 0x03,
+	0xd5, 0x57, 0x27, 0x14, 0x01, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x2c, 0xf7, 0xcb, 0x1f, 0x14, 0x60,
+	// Entry 780 - 7BF
+	0x83, 0x68, 0x01, 0x10, 0x8b, 0x38, 0x8a, 0x01,
+	0x00, 0x00, 0x20, 0x00, 0x24, 0x44, 0x00, 0x00,
+	0x10, 0x03, 0x31, 0x02, 0x01, 0x00, 0x00, 0xf0,
+	0xf5, 0xff, 0xd5, 0x97, 0xbc, 0x70, 0xd6, 0x78,
+	0x78, 0x15, 0x50, 0x05, 0xa4, 0x84, 0xa9, 0x41,
+	0x00, 0x00, 0x00, 0x6b, 0x39, 0x52, 0x74, 0x40,
+	0xe8, 0x30, 0x90, 0x6a, 0x92, 0x00, 0x00, 0x02,
+	0xff, 0xef, 0xff, 0x4b, 0x85, 0x53, 0xf4, 0xed,
+	// Entry 7C0 - 7FF
+	0xdd, 0xbf, 0xf2, 0x5d, 0xc7, 0x0c, 0xd5, 0x42,
+	0xfc, 0xff, 0xf7, 0x1f, 0x00, 0x80, 0x40, 0x56,
+	0xcc, 0x16, 0x9e, 0xea, 0x35, 0x7d, 0xef, 0xff,
+	0xbd, 0xa4, 0xaf, 0x01, 0x44, 0x18, 0x01, 0x4d,
+	0x4e, 0x4a, 0x08, 0x50, 0x28, 0x30, 0xe0, 0x80,
+	0x10, 0x20, 0x24, 0x00, 0xff, 0x2f, 0xd3, 0x60,
+	0xfe, 0x01, 0x02, 0x88, 0x2a, 0x40, 0x16, 0x01,
+	0x01, 0x15, 0x2b, 0x3c, 0x01, 0x00, 0x00, 0x10,
+	// Entry 800 - 83F
+	0x90, 0x49, 0x41, 0x02, 0x02, 0x01, 0xe1, 0xbf,
+	0xbf, 0x03, 0x00, 0x00, 0x10, 0xdc, 0xa3, 0xd1,
+	0x40, 0x9c, 0x44, 0xdf, 0xf5, 0x8f, 0x66, 0xb3,
+	0x55, 0x20, 0xd4, 0xc1, 0xd8, 0x30, 0x3d, 0x80,
+	0x00, 0x00, 0x00, 0x04, 0xd4, 0x11, 0xc5, 0x84,
+	0x2f, 0x50, 0x00, 0x22, 0x50, 0x6e, 0xbd, 0x93,
+	0x07, 0x00, 0x20, 0x10, 0x84, 0xb2, 0x45, 0x10,
+	0x06, 0x44, 0x00, 0x00, 0x12, 0x02, 0x11, 0x00,
+	// Entry 840 - 87F
+	0xf0, 0xfb, 0xfd, 0x7f, 0x05, 0x00, 0x16, 0x89,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x03,
+	0x00, 0x00, 0x00, 0x00, 0x03, 0x30, 0x02, 0x28,
+	0x84, 0x00, 0x21, 0xc0, 0x23, 0x24, 0x00, 0x00,
+	0x00, 0xcb, 0xe4, 0x3a, 0x46, 0x88, 0x54, 0xf1,
+	0xef, 0xff, 0x7f, 0x12, 0x01, 0x01, 0x84, 0x50,
+	0x07, 0xfc, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x40,
+	0x10, 0x38, 0x01, 0x01, 0x1c, 0x12, 0x40, 0xe1,
+	// Entry 880 - 8BF
+	0x76, 0x16, 0x08, 0x03, 0x10, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x24,
+	0x0a, 0x00, 0x80, 0x00, 0x00,
+}
+
+// altLangISO3 holds an alphabetically sorted list of 3-letter language code alternatives
+// to 2-letter language codes that cannot be derived using the method described above.
+// Each 3-letter code is followed by its 1-byte langID.
+const altLangISO3 tag.Index = "---\x00cor\x00hbs\x01heb\x02kin\x03spa\x04yid\x05\xff\xff\xff\xff"
+
+// altLangIndex is used to convert indexes in altLangISO3 to langIDs.
+// Size: 12 bytes, 6 elements
+var altLangIndex = [6]uint16{
+	0x0281, 0x0407, 0x01fb, 0x03e5, 0x013e, 0x0208,
+}
+
+// AliasMap maps langIDs to their suggested replacements.
+// Size: 772 bytes, 193 elements
+var AliasMap = [193]FromTo{
+	0:   {From: 0x82, To: 0x88},
+	1:   {From: 0x187, To: 0x1ae},
+	2:   {From: 0x1f3, To: 0x1e1},
+	3:   {From: 0x1fb, To: 0x1bc},
+	4:   {From: 0x208, To: 0x512},
+	5:   {From: 0x20f, To: 0x20e},
+	6:   {From: 0x310, To: 0x3dc},
+	7:   {From: 0x347, To: 0x36f},
+	8:   {From: 0x407, To: 0x432},
+	9:   {From: 0x47a, To: 0x153},
+	10:  {From: 0x490, To: 0x451},
+	11:  {From: 0x4a2, To: 0x21},
+	12:  {From: 0x53e, To: 0x544},
+	13:  {From: 0x58f, To: 0x12d},
+	14:  {From: 0x62b, To: 0x34},
+	15:  {From: 0x62f, To: 0x14},
+	16:  {From: 0x630, To: 0x1eb1},
+	17:  {From: 0x651, To: 0x431},
+	18:  {From: 0x662, To: 0x431},
+	19:  {From: 0x6ed, To: 0x3a},
+	20:  {From: 0x6f8, To: 0x1d7},
+	21:  {From: 0x709, To: 0x3625},
+	22:  {From: 0x73e, To: 0x21a1},
+	23:  {From: 0x7b3, To: 0x56},
+	24:  {From: 0x7b9, To: 0x299b},
+	25:  {From: 0x7c5, To: 0x58},
+	26:  {From: 0x7e6, To: 0x145},
+	27:  {From: 0x80c, To: 0x5a},
+	28:  {From: 0x815, To: 0x8d},
+	29:  {From: 0x87e, To: 0x810},
+	30:  {From: 0x8a8, To: 0x8b7},
+	31:  {From: 0x8c3, To: 0xee3},
+	32:  {From: 0x8fa, To: 0x1dc},
+	33:  {From: 0x9ef, To: 0x331},
+	34:  {From: 0xa36, To: 0x2c5},
+	35:  {From: 0xa3d, To: 0xbf},
+	36:  {From: 0xabe, To: 0x3322},
+	37:  {From: 0xb38, To: 0x529},
+	38:  {From: 0xb75, To: 0x265a},
+	39:  {From: 0xb7e, To: 0xbc3},
+	40:  {From: 0xb9b, To: 0x44e},
+	41:  {From: 0xbbc, To: 0x4229},
+	42:  {From: 0xbbf, To: 0x529},
+	43:  {From: 0xbfe, To: 0x2da7},
+	44:  {From: 0xc2e, To: 0x3181},
+	45:  {From: 0xcb9, To: 0xf3},
+	46:  {From: 0xd08, To: 0xfa},
+	47:  {From: 0xdc8, To: 0x11a},
+	48:  {From: 0xdd7, To: 0x32d},
+	49:  {From: 0xdf8, To: 0xdfb},
+	50:  {From: 0xdfe, To: 0x531},
+	51:  {From: 0xe01, To: 0xdf3},
+	52:  {From: 0xedf, To: 0x205a},
+	53:  {From: 0xee9, To: 0x222e},
+	54:  {From: 0xeee, To: 0x2e9a},
+	55:  {From: 0xf39, To: 0x367},
+	56:  {From: 0x10d0, To: 0x140},
+	57:  {From: 0x1104, To: 0x2d0},
+	58:  {From: 0x11a0, To: 0x1ec},
+	59:  {From: 0x1279, To: 0x21},
+	60:  {From: 0x1424, To: 0x15e},
+	61:  {From: 0x1470, To: 0x14e},
+	62:  {From: 0x151f, To: 0xd9b},
+	63:  {From: 0x1523, To: 0x390},
+	64:  {From: 0x1532, To: 0x19f},
+	65:  {From: 0x1580, To: 0x210},
+	66:  {From: 0x1583, To: 0x10d},
+	67:  {From: 0x15a3, To: 0x3caf},
+	68:  {From: 0x1630, To: 0x222e},
+	69:  {From: 0x166a, To: 0x19b},
+	70:  {From: 0x16c8, To: 0x136},
+	71:  {From: 0x1700, To: 0x29f8},
+	72:  {From: 0x1718, To: 0x194},
+	73:  {From: 0x1727, To: 0xf3f},
+	74:  {From: 0x177a, To: 0x178},
+	75:  {From: 0x1809, To: 0x17b6},
+	76:  {From: 0x1816, To: 0x18f3},
+	77:  {From: 0x188a, To: 0x436},
+	78:  {From: 0x1979, To: 0x1d01},
+	79:  {From: 0x1a74, To: 0x2bb0},
+	80:  {From: 0x1a8a, To: 0x1f8},
+	81:  {From: 0x1b5a, To: 0x1fa},
+	82:  {From: 0x1b86, To: 0x1515},
+	83:  {From: 0x1d64, To: 0x2c9b},
+	84:  {From: 0x2038, To: 0x37b1},
+	85:  {From: 0x203d, To: 0x20dd},
+	86:  {From: 0x2042, To: 0x2e00},
+	87:  {From: 0x205a, To: 0x30b},
+	88:  {From: 0x20e3, To: 0x274},
+	89:  {From: 0x20ee, To: 0x263},
+	90:  {From: 0x20f2, To: 0x22d},
+	91:  {From: 0x20f9, To: 0x256},
+	92:  {From: 0x210f, To: 0x21eb},
+	93:  {From: 0x2135, To: 0x27d},
+	94:  {From: 0x2160, To: 0x913},
+	95:  {From: 0x2199, To: 0x121},
+	96:  {From: 0x21ce, To: 0x1561},
+	97:  {From: 0x21e6, To: 0x504},
+	98:  {From: 0x21f4, To: 0x49f},
+	99:  {From: 0x21fb, To: 0x269},
+	100: {From: 0x222d, To: 0x121},
+	101: {From: 0x2237, To: 0x121},
+	102: {From: 0x2248, To: 0x217d},
+	103: {From: 0x2262, To: 0x92a},
+	104: {From: 0x2316, To: 0x3226},
+	105: {From: 0x236a, To: 0x2835},
+	106: {From: 0x2382, To: 0x3365},
+	107: {From: 0x2472, To: 0x2c7},
+	108: {From: 0x24e4, To: 0x2ff},
+	109: {From: 0x24f0, To: 0x2fa},
+	110: {From: 0x24fa, To: 0x31f},
+	111: {From: 0x2550, To: 0xb5b},
+	112: {From: 0x25a9, To: 0xe2},
+	113: {From: 0x263e, To: 0x2d0},
+	114: {From: 0x26c9, To: 0x26b4},
+	115: {From: 0x26f9, To: 0x3c8},
+	116: {From: 0x2727, To: 0x3caf},
+	117: {From: 0x2755, To: 0x6a4},
+	118: {From: 0x2765, To: 0x26b4},
+	119: {From: 0x2789, To: 0x4358},
+	120: {From: 0x27c9, To: 0x2001},
+	121: {From: 0x28ea, To: 0x27b1},
+	122: {From: 0x28ef, To: 0x2837},
+	123: {From: 0x28fe, To: 0xaa5},
+	124: {From: 0x2914, To: 0x351},
+	125: {From: 0x2986, To: 0x2da7},
+	126: {From: 0x29f0, To: 0x96b},
+	127: {From: 0x2b1a, To: 0x38d},
+	128: {From: 0x2bfc, To: 0x395},
+	129: {From: 0x2c3f, To: 0x3caf},
+	130: {From: 0x2ce1, To: 0x2201},
+	131: {From: 0x2cfc, To: 0x3be},
+	132: {From: 0x2d13, To: 0x597},
+	133: {From: 0x2d47, To: 0x148},
+	134: {From: 0x2d48, To: 0x148},
+	135: {From: 0x2dff, To: 0x2f1},
+	136: {From: 0x2e08, To: 0x19cc},
+	137: {From: 0x2e10, To: 0xc45},
+	138: {From: 0x2e1a, To: 0x2d95},
+	139: {From: 0x2e21, To: 0x292},
+	140: {From: 0x2e54, To: 0x7d},
+	141: {From: 0x2e65, To: 0x2282},
+	142: {From: 0x2e97, To: 0x1a4},
+	143: {From: 0x2ea0, To: 0x2e9b},
+	144: {From: 0x2eef, To: 0x2ed7},
+	145: {From: 0x3193, To: 0x3c4},
+	146: {From: 0x3366, To: 0x338e},
+	147: {From: 0x342a, To: 0x3dc},
+	148: {From: 0x34ee, To: 0x18d0},
+	149: {From: 0x35c8, To: 0x2c9b},
+	150: {From: 0x35e6, To: 0x412},
+	151: {From: 0x35f5, To: 0x24b},
+	152: {From: 0x360d, To: 0x1dc},
+	153: {From: 0x3658, To: 0x246},
+	154: {From: 0x3676, To: 0x3f4},
+	155: {From: 0x36fd, To: 0x445},
+	156: {From: 0x3747, To: 0x3b42},
+	157: {From: 0x37c0, To: 0x121},
+	158: {From: 0x3816, To: 0x38f2},
+	159: {From: 0x382a, To: 0x2b48},
+	160: {From: 0x382b, To: 0x2c9b},
+	161: {From: 0x382f, To: 0xa9},
+	162: {From: 0x3832, To: 0x3228},
+	163: {From: 0x386c, To: 0x39a6},
+	164: {From: 0x3892, To: 0x3fc0},
+	165: {From: 0x38a0, To: 0x45f},
+	166: {From: 0x38a5, To: 0x39d7},
+	167: {From: 0x38b4, To: 0x1fa4},
+	168: {From: 0x38b5, To: 0x2e9a},
+	169: {From: 0x38fa, To: 0x38f1},
+	170: {From: 0x395c, To: 0x47e},
+	171: {From: 0x3b4e, To: 0xd91},
+	172: {From: 0x3b78, To: 0x137},
+	173: {From: 0x3c99, To: 0x4bc},
+	174: {From: 0x3fbd, To: 0x100},
+	175: {From: 0x4208, To: 0xa91},
+	176: {From: 0x42be, To: 0x573},
+	177: {From: 0x42f9, To: 0x3f60},
+	178: {From: 0x4378, To: 0x25a},
+	179: {From: 0x43b8, To: 0xe6c},
+	180: {From: 0x43cd, To: 0x10f},
+	181: {From: 0x43d4, To: 0x4848},
+	182: {From: 0x44af, To: 0x3322},
+	183: {From: 0x44e3, To: 0x512},
+	184: {From: 0x45ca, To: 0x2409},
+	185: {From: 0x45dd, To: 0x26dc},
+	186: {From: 0x4610, To: 0x48ae},
+	187: {From: 0x46ae, To: 0x46a0},
+	188: {From: 0x473e, To: 0x4745},
+	189: {From: 0x4817, To: 0x3503},
+	190: {From: 0x483b, To: 0x208b},
+	191: {From: 0x4916, To: 0x31f},
+	192: {From: 0x49a7, To: 0x523},
+}
+
+// Size: 193 bytes, 193 elements
+var AliasTypes = [193]AliasType{
+	// Entry 0 - 3F
+	1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0, 1, 0, 0, 0, 0,
+	1, 2, 1, 1, 2, 0, 0, 1, 0, 1, 2, 1, 1, 0, 0, 0,
+	0, 2, 1, 1, 0, 2, 0, 0, 1, 0, 1, 0, 0, 1, 2, 1,
+	1, 1, 1, 0, 0, 0, 0, 2, 1, 1, 1, 1, 2, 1, 0, 1,
+	// Entry 40 - 7F
+	1, 2, 2, 0, 0, 1, 2, 0, 1, 0, 1, 1, 1, 1, 0, 0,
+	2, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 0,
+	1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+	// Entry 80 - BF
+	1, 0, 0, 1, 0, 2, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
+	0, 1, 1, 2, 0, 0, 2, 0, 0, 1, 1, 1, 0, 0, 0, 0,
+	0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 0,
+	0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1,
+	// Entry C0 - FF
+	1,
+}
+
+const (
+	_Latn = 91
+	_Hani = 57
+	_Hans = 59
+	_Hant = 60
+	_Qaaa = 149
+	_Qaai = 157
+	_Qabx = 198
+	_Zinh = 255
+	_Zyyy = 260
+	_Zzzz = 261
+)
+
+// script is an alphabetically sorted list of ISO 15924 codes. The index
+// of the script in the string, divided by 4, is the internal scriptID.
+const script tag.Index = "" + // Size: 1052 bytes
+	"----AdlmAfakAghbAhomArabAranArmiArmnAvstBaliBamuBassBatkBengBhksBlisBopo" +
+	"BrahBraiBugiBuhdCakmCansCariChamCherChrsCirtCoptCpmnCprtCyrlCyrsDevaDiak" +
+	"DogrDsrtDuplEgydEgyhEgypElbaElymEthiGeokGeorGlagGongGonmGothGranGrekGujr" +
+	"GuruHanbHangHaniHanoHansHantHatrHebrHiraHluwHmngHmnpHrktHungIndsItalJamo" +
+	"JavaJpanJurcKaliKanaKawiKharKhmrKhojKitlKitsKndaKoreKpelKthiLanaLaooLatf" +
+	"LatgLatnLekeLepcLimbLinaLinbLisuLomaLyciLydiMahjMakaMandManiMarcMayaMedf" +
+	"MendMercMeroMlymModiMongMoonMrooMteiMultMymrNagmNandNarbNbatNewaNkdbNkgb" +
+	"NkooNshuOgamOlckOrkhOryaOsgeOsmaOugrPalmPaucPcunPelmPermPhagPhliPhlpPhlv" +
+	"PhnxPiqdPlrdPrtiPsinQaaaQaabQaacQaadQaaeQaafQaagQaahQaaiQaajQaakQaalQaam" +
+	"QaanQaaoQaapQaaqQaarQaasQaatQaauQaavQaawQaaxQaayQaazQabaQabbQabcQabdQabe" +
+	"QabfQabgQabhQabiQabjQabkQablQabmQabnQaboQabpQabqQabrQabsQabtQabuQabvQabw" +
+	"QabxRanjRjngRohgRoroRunrSamrSaraSarbSaurSgnwShawShrdShuiSiddSindSinhSogd" +
+	"SogoSoraSoyoSundSunuSyloSyrcSyreSyrjSyrnTagbTakrTaleTaluTamlTangTavtTelu" +
+	"TengTfngTglgThaaThaiTibtTirhTnsaTotoUgarVaiiVispVithWaraWchoWoleXpeoXsux" +
+	"YeziYiiiZanbZinhZmthZsyeZsymZxxxZyyyZzzz\xff\xff\xff\xff"
+
+// suppressScript is an index from langID to the dominant script for that language,
+// if it exists.  If a script is given, it should be suppressed from the language tag.
+// Size: 1330 bytes, 1330 elements
+var suppressScript = [1330]uint8{
+	// Entry 0 - 3F
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 40 - 7F
+	0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+	// Entry 80 - BF
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry C0 - FF
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 100 - 13F
+	0x5b, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xed, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00,
+	0x00, 0x5b, 0x00, 0x00, 0x5b, 0x00, 0x5b, 0x00,
+	// Entry 140 - 17F
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00,
+	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x5b, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00,
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	0x00, 0x5b, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5b, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 180 - 1BF
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x5b, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x5b, 0x35, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x22, 0x00,
+	// Entry 1C0 - 1FF
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x5b, 0x5b, 0x00, 0x5b, 0x5b, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
+	0x5b, 0x5b, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
+	// Entry 200 - 23F
+	0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 240 - 27F
+	0x00, 0x00, 0x20, 0x00, 0x00, 0x5b, 0x00, 0x00,
+	0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x53, 0x00, 0x00, 0x54, 0x00, 0x22, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 280 - 2BF
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00,
+	0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 2C0 - 2FF
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+	// Entry 300 - 33F
+	0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x5b,
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	// Entry 340 - 37F
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	0x5b, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5b, 0x00,
+	0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 380 - 3BF
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
+	// Entry 3C0 - 3FF
+	0x5b, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00,
+	0x00, 0x5b, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x20, 0x00, 0x00, 0x5b, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 400 - 43F
+	0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
+	// Entry 440 - 47F
+	0x00, 0x00, 0x00, 0x00, 0x5b, 0x5b, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xe9, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x2c,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	// Entry 480 - 4BF
+	0x5b, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5b, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 4C0 - 4FF
+	0x5b, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 500 - 53F
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
+	0x00, 0x00,
+}
+
+const (
+	_001 = 1
+	_419 = 31
+	_BR  = 65
+	_CA  = 73
+	_ES  = 111
+	_GB  = 124
+	_MD  = 189
+	_PT  = 239
+	_UK  = 307
+	_US  = 310
+	_ZZ  = 358
+	_XA  = 324
+	_XC  = 326
+	_XK  = 334
+)
+
+// isoRegionOffset needs to be added to the index of regionISO to obtain the regionID
+// for 2-letter ISO codes. (The first isoRegionOffset regionIDs are reserved for
+// the UN.M49 codes used for groups.)
+const isoRegionOffset = 32
+
+// regionTypes defines the status of a region for various standards.
+// Size: 359 bytes, 359 elements
+var regionTypes = [359]uint8{
+	// Entry 0 - 3F
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	// Entry 40 - 7F
+	0x06, 0x06, 0x06, 0x06, 0x04, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06,
+	0x04, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x04, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, 0x00,
+	0x06, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x00, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06,
+	// Entry 80 - BF
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x00, 0x04, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	// Entry C0 - FF
+	0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x00, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x04,
+	0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x00, 0x06, 0x06, 0x00, 0x06, 0x05, 0x05, 0x05,
+	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+	// Entry 100 - 13F
+	0x05, 0x05, 0x05, 0x06, 0x00, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x02, 0x06, 0x04, 0x06, 0x06,
+	0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06,
+	// Entry 140 - 17F
+	0x06, 0x06, 0x00, 0x06, 0x05, 0x05, 0x05, 0x05,
+	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x06,
+	0x06, 0x04, 0x06, 0x06, 0x04, 0x06, 0x05,
+}
+
+// regionISO holds a list of alphabetically sorted 2-letter ISO region codes.
+// Each 2-letter codes is followed by two bytes with the following meaning:
+//   - [A-Z}{2}: the first letter of the 2-letter code plus these two
+//     letters form the 3-letter ISO code.
+//   - 0, n:     index into altRegionISO3.
+const regionISO tag.Index = "" + // Size: 1312 bytes
+	"AAAAACSCADNDAEREAFFGAGTGAIIAALLBAMRMANNTAOGOAQTAARRGASSMATUTAUUSAWBWAXLA" +
+	"AZZEBAIHBBRBBDGDBEELBFFABGGRBHHRBIDIBJENBLLMBMMUBNRNBOOLBQESBRRABSHSBTTN" +
+	"BUURBVVTBWWABYLRBZLZCAANCCCKCDODCFAFCGOGCHHECIIVCKOKCLHLCMMRCNHNCOOLCPPT" +
+	"CQ  CRRICS\x00\x00CTTECUUBCVPVCWUWCXXRCYYPCZZEDDDRDEEUDGGADJJIDKNKDMMADO" +
+	"OMDYHYDZZAEA  ECCUEESTEGGYEHSHERRIESSPETTHEU\x00\x03EZ  FIINFJJIFKLKFMSM" +
+	"FOROFQ\x00\x18FRRAFXXXGAABGBBRGDRDGEEOGFUFGGGYGHHAGIIBGLRLGMMBGNINGPLPGQ" +
+	"NQGRRCGS\x00\x06GTTMGUUMGWNBGYUYHKKGHMMDHNNDHRRVHTTIHUUNHVVOIC  IDDNIERL" +
+	"ILSRIMMNINNDIOOTIQRQIRRNISSLITTAJEEYJMAMJOORJPPNJTTNKEENKGGZKHHMKIIRKM" +
+	"\x00\x09KNNAKP\x00\x0cKRORKWWTKY\x00\x0fKZAZLAAOLBBNLCCALIIELKKALRBRLSSO" +
+	"LTTULUUXLVVALYBYMAARMCCOMDDAMENEMFAFMGDGMHHLMIIDMKKDMLLIMMMRMNNGMOACMPNP" +
+	"MQTQMRRTMSSRMTLTMUUSMVDVMWWIMXEXMYYSMZOZNAAMNCCLNEERNFFKNGGANHHBNIICNLLD" +
+	"NOORNPPLNQ\x00\x1eNRRUNTTZNUIUNZZLOMMNPAANPCCIPEERPFYFPGNGPHHLPKAKPLOLPM" +
+	"\x00\x12PNCNPRRIPSSEPTRTPUUSPWLWPYRYPZCZQAATQMMMQNNNQOOOQPPPQQQQQRRRQSSS" +
+	"QTTTQU\x00\x03QVVVQWWWQXXXQYYYQZZZREEURHHOROOURS\x00\x15RUUSRWWASAAUSBLB" +
+	"SCYCSDDNSEWESGGPSHHNSIVNSJJMSKVKSLLESMMRSNENSOOMSRURSSSDSTTPSUUNSVLVSXXM" +
+	"SYYRSZWZTAAATCCATDCDTF\x00\x18TGGOTHHATJJKTKKLTLLSTMKMTNUNTOONTPMPTRURTT" +
+	"TOTVUVTWWNTZZAUAKRUGGAUK  UMMIUN  USSAUYRYUZZBVAATVCCTVDDRVEENVGGBVIIRVN" +
+	"NMVUUTWFLFWKAKWSSMXAAAXBBBXCCCXDDDXEEEXFFFXGGGXHHHXIIIXJJJXKKKXLLLXMMMXN" +
+	"NNXOOOXPPPXQQQXRRRXSSSXTTTXUUUXVVVXWWWXXXXXYYYXZZZYDMDYEEMYT\x00\x1bYUUG" +
+	"ZAAFZMMBZRARZWWEZZZZ\xff\xff\xff\xff"
+
+// altRegionISO3 holds a list of 3-letter region codes that cannot be
+// mapped to 2-letter codes using the default algorithm. This is a short list.
+const altRegionISO3 string = "SCGQUUSGSCOMPRKCYMSPMSRBATFMYTATN"
+
+// altRegionIDs holds a list of regionIDs the positions of which match those
+// of the 3-letter ISO codes in altRegionISO3.
+// Size: 22 bytes, 11 elements
+var altRegionIDs = [11]uint16{
+	0x0058, 0x0071, 0x0089, 0x00a9, 0x00ab, 0x00ae, 0x00eb, 0x0106,
+	0x0122, 0x0160, 0x00dd,
+}
+
+// Size: 80 bytes, 20 elements
+var regionOldMap = [20]FromTo{
+	0:  {From: 0x44, To: 0xc5},
+	1:  {From: 0x59, To: 0xa8},
+	2:  {From: 0x60, To: 0x61},
+	3:  {From: 0x67, To: 0x3b},
+	4:  {From: 0x7a, To: 0x79},
+	5:  {From: 0x94, To: 0x37},
+	6:  {From: 0xa4, To: 0x134},
+	7:  {From: 0xc2, To: 0x134},
+	8:  {From: 0xd8, To: 0x140},
+	9:  {From: 0xdd, To: 0x2b},
+	10: {From: 0xf0, To: 0x134},
+	11: {From: 0xf3, To: 0xe3},
+	12: {From: 0xfd, To: 0x71},
+	13: {From: 0x104, To: 0x165},
+	14: {From: 0x12b, To: 0x127},
+	15: {From: 0x133, To: 0x7c},
+	16: {From: 0x13b, To: 0x13f},
+	17: {From: 0x142, To: 0x134},
+	18: {From: 0x15e, To: 0x15f},
+	19: {From: 0x164, To: 0x4b},
+}
+
+// m49 maps regionIDs to UN.M49 codes. The first isoRegionOffset entries are
+// codes indicating collections of regions.
+// Size: 718 bytes, 359 elements
+var m49 = [359]int16{
+	// Entry 0 - 3F
+	0, 1, 2, 3, 5, 9, 11, 13,
+	14, 15, 17, 18, 19, 21, 29, 30,
+	34, 35, 39, 53, 54, 57, 61, 142,
+	143, 145, 150, 151, 154, 155, 202, 419,
+	958, 0, 20, 784, 4, 28, 660, 8,
+	51, 530, 24, 10, 32, 16, 40, 36,
+	533, 248, 31, 70, 52, 50, 56, 854,
+	100, 48, 108, 204, 652, 60, 96, 68,
+	// Entry 40 - 7F
+	535, 76, 44, 64, 104, 74, 72, 112,
+	84, 124, 166, 180, 140, 178, 756, 384,
+	184, 152, 120, 156, 170, 0, 0, 188,
+	891, 296, 192, 132, 531, 162, 196, 203,
+	278, 276, 0, 262, 208, 212, 214, 204,
+	12, 0, 218, 233, 818, 732, 232, 724,
+	231, 967, 0, 246, 242, 238, 583, 234,
+	0, 250, 249, 266, 826, 308, 268, 254,
+	// Entry 80 - BF
+	831, 288, 292, 304, 270, 324, 312, 226,
+	300, 239, 320, 316, 624, 328, 344, 334,
+	340, 191, 332, 348, 854, 0, 360, 372,
+	376, 833, 356, 86, 368, 364, 352, 380,
+	832, 388, 400, 392, 581, 404, 417, 116,
+	296, 174, 659, 408, 410, 414, 136, 398,
+	418, 422, 662, 438, 144, 430, 426, 440,
+	442, 428, 434, 504, 492, 498, 499, 663,
+	// Entry C0 - FF
+	450, 584, 581, 807, 466, 104, 496, 446,
+	580, 474, 478, 500, 470, 480, 462, 454,
+	484, 458, 508, 516, 540, 562, 574, 566,
+	548, 558, 528, 578, 524, 10, 520, 536,
+	570, 554, 512, 591, 0, 604, 258, 598,
+	608, 586, 616, 666, 612, 630, 275, 620,
+	581, 585, 600, 591, 634, 959, 960, 961,
+	962, 963, 964, 965, 966, 967, 968, 969,
+	// Entry 100 - 13F
+	970, 971, 972, 638, 716, 642, 688, 643,
+	646, 682, 90, 690, 729, 752, 702, 654,
+	705, 744, 703, 694, 674, 686, 706, 740,
+	728, 678, 810, 222, 534, 760, 748, 0,
+	796, 148, 260, 768, 764, 762, 772, 626,
+	795, 788, 776, 626, 792, 780, 798, 158,
+	834, 804, 800, 826, 581, 0, 840, 858,
+	860, 336, 670, 704, 862, 92, 850, 704,
+	// Entry 140 - 17F
+	548, 876, 581, 882, 973, 974, 975, 976,
+	977, 978, 979, 980, 981, 982, 983, 984,
+	985, 986, 987, 988, 989, 990, 991, 992,
+	993, 994, 995, 996, 997, 998, 720, 887,
+	175, 891, 710, 894, 180, 716, 999,
+}
+
+// m49Index gives indexes into fromM49 based on the three most significant bits
+// of a 10-bit UN.M49 code. To search an UN.M49 code in fromM49, search in
+//
+//	fromM49[m49Index[msb39(code)]:m49Index[msb3(code)+1]]
+//
+// for an entry where the first 7 bits match the 7 lsb of the UN.M49 code.
+// The region code is stored in the 9 lsb of the indexed value.
+// Size: 18 bytes, 9 elements
+var m49Index = [9]int16{
+	0, 59, 108, 143, 181, 220, 259, 291,
+	333,
+}
+
+// fromM49 contains entries to map UN.M49 codes to regions. See m49Index for details.
+// Size: 666 bytes, 333 elements
+var fromM49 = [333]uint16{
+	// Entry 0 - 3F
+	0x0201, 0x0402, 0x0603, 0x0824, 0x0a04, 0x1027, 0x1205, 0x142b,
+	0x1606, 0x1868, 0x1a07, 0x1c08, 0x1e09, 0x202d, 0x220a, 0x240b,
+	0x260c, 0x2822, 0x2a0d, 0x302a, 0x3825, 0x3a0e, 0x3c0f, 0x3e32,
+	0x402c, 0x4410, 0x4611, 0x482f, 0x4e12, 0x502e, 0x5842, 0x6039,
+	0x6435, 0x6628, 0x6834, 0x6a13, 0x6c14, 0x7036, 0x7215, 0x783d,
+	0x7a16, 0x8043, 0x883f, 0x8c33, 0x9046, 0x9445, 0x9841, 0xa848,
+	0xac9b, 0xb50a, 0xb93d, 0xc03e, 0xc838, 0xd0c5, 0xd83a, 0xe047,
+	0xe8a7, 0xf052, 0xf849, 0x085b, 0x10ae, 0x184c, 0x1c17, 0x1e18,
+	// Entry 40 - 7F
+	0x20b4, 0x2219, 0x2921, 0x2c1a, 0x2e1b, 0x3051, 0x341c, 0x361d,
+	0x3853, 0x3d2f, 0x445d, 0x4c4a, 0x5454, 0x5ca9, 0x5f60, 0x644d,
+	0x684b, 0x7050, 0x7857, 0x7e91, 0x805a, 0x885e, 0x941e, 0x965f,
+	0x983b, 0xa064, 0xa865, 0xac66, 0xb46a, 0xbd1b, 0xc487, 0xcc70,
+	0xce70, 0xd06e, 0xd26b, 0xd477, 0xdc75, 0xde89, 0xe474, 0xec73,
+	0xf031, 0xf27a, 0xf479, 0xfc7f, 0x04e6, 0x0922, 0x0c63, 0x147b,
+	0x187e, 0x1c84, 0x26ee, 0x2861, 0x2c60, 0x3061, 0x4081, 0x4882,
+	0x50a8, 0x5888, 0x6083, 0x687d, 0x7086, 0x788b, 0x808a, 0x8885,
+	// Entry 80 - BF
+	0x908d, 0x9892, 0x9c8f, 0xa139, 0xa890, 0xb08e, 0xb893, 0xc09e,
+	0xc89a, 0xd096, 0xd89d, 0xe09c, 0xe897, 0xf098, 0xf89f, 0x004f,
+	0x08a1, 0x10a3, 0x1caf, 0x20a2, 0x28a5, 0x30ab, 0x34ac, 0x3cad,
+	0x42a6, 0x44b0, 0x461f, 0x4cb1, 0x54b6, 0x58b9, 0x5cb5, 0x64ba,
+	0x6cb3, 0x70b7, 0x74b8, 0x7cc7, 0x84c0, 0x8ccf, 0x94d1, 0x9cce,
+	0xa4c4, 0xaccc, 0xb4c9, 0xbcca, 0xc0cd, 0xc8d0, 0xd8bc, 0xe0c6,
+	0xe4bd, 0xe6be, 0xe8cb, 0xf0bb, 0xf8d2, 0x00e2, 0x08d3, 0x10de,
+	0x18dc, 0x20da, 0x2429, 0x265c, 0x2a30, 0x2d1c, 0x2e40, 0x30df,
+	// Entry C0 - FF
+	0x38d4, 0x4940, 0x54e1, 0x5cd9, 0x64d5, 0x6cd7, 0x74e0, 0x7cd6,
+	0x84db, 0x88c8, 0x8b34, 0x8e76, 0x90c1, 0x92f1, 0x94e9, 0x9ee3,
+	0xace7, 0xb0f2, 0xb8e5, 0xc0e8, 0xc8ec, 0xd0ea, 0xd8ef, 0xe08c,
+	0xe527, 0xeced, 0xf4f4, 0xfd03, 0x0505, 0x0707, 0x0d08, 0x183c,
+	0x1d0f, 0x26aa, 0x2826, 0x2cb2, 0x2ebf, 0x34eb, 0x3d3a, 0x4514,
+	0x4d19, 0x5509, 0x5d15, 0x6106, 0x650b, 0x6d13, 0x7d0e, 0x7f12,
+	0x813f, 0x8310, 0x8516, 0x8d62, 0x9965, 0xa15e, 0xa86f, 0xb118,
+	0xb30c, 0xb86d, 0xc10c, 0xc917, 0xd111, 0xd91e, 0xe10d, 0xe84e,
+	// Entry 100 - 13F
+	0xf11d, 0xf525, 0xf924, 0x0123, 0x0926, 0x112a, 0x192d, 0x2023,
+	0x2929, 0x312c, 0x3728, 0x3920, 0x3d2e, 0x4132, 0x4931, 0x4ec3,
+	0x551a, 0x646c, 0x747c, 0x7e80, 0x80a0, 0x8299, 0x8530, 0x9136,
+	0xa53e, 0xac37, 0xb537, 0xb938, 0xbd3c, 0xd941, 0xe543, 0xed5f,
+	0xef5f, 0xf658, 0xfd63, 0x7c20, 0x7ef5, 0x80f6, 0x82f7, 0x84f8,
+	0x86f9, 0x88fa, 0x8afb, 0x8cfc, 0x8e71, 0x90fe, 0x92ff, 0x9500,
+	0x9701, 0x9902, 0x9b44, 0x9d45, 0x9f46, 0xa147, 0xa348, 0xa549,
+	0xa74a, 0xa94b, 0xab4c, 0xad4d, 0xaf4e, 0xb14f, 0xb350, 0xb551,
+	// Entry 140 - 17F
+	0xb752, 0xb953, 0xbb54, 0xbd55, 0xbf56, 0xc157, 0xc358, 0xc559,
+	0xc75a, 0xc95b, 0xcb5c, 0xcd5d, 0xcf66,
+}
+
+// Size: 2128 bytes
+var variantIndex = map[string]uint8{
+	"1606nict": 0x0,
+	"1694acad": 0x1,
+	"1901":     0x2,
+	"1959acad": 0x3,
+	"1994":     0x67,
+	"1996":     0x4,
+	"abl1943":  0x5,
+	"akuapem":  0x6,
+	"alalc97":  0x69,
+	"aluku":    0x7,
+	"ao1990":   0x8,
+	"aranes":   0x9,
+	"arevela":  0xa,
+	"arevmda":  0xb,
+	"arkaika":  0xc,
+	"asante":   0xd,
+	"auvern":   0xe,
+	"baku1926": 0xf,
+	"balanka":  0x10,
+	"barla":    0x11,
+	"basiceng": 0x12,
+	"bauddha":  0x13,
+	"bciav":    0x14,
+	"bcizbl":   0x15,
+	"biscayan": 0x16,
+	"biske":    0x62,
+	"bohoric":  0x17,
+	"boont":    0x18,
+	"bornholm": 0x19,
+	"cisaup":   0x1a,
+	"colb1945": 0x1b,
+	"cornu":    0x1c,
+	"creiss":   0x1d,
+	"dajnko":   0x1e,
+	"ekavsk":   0x1f,
+	"emodeng":  0x20,
+	"fonipa":   0x6a,
+	"fonkirsh": 0x6b,
+	"fonnapa":  0x6c,
+	"fonupa":   0x6d,
+	"fonxsamp": 0x6e,
+	"gallo":    0x21,
+	"gascon":   0x22,
+	"grclass":  0x23,
+	"grital":   0x24,
+	"grmistr":  0x25,
+	"hepburn":  0x26,
+	"heploc":   0x68,
+	"hognorsk": 0x27,
+	"hsistemo": 0x28,
+	"ijekavsk": 0x29,
+	"itihasa":  0x2a,
+	"ivanchov": 0x2b,
+	"jauer":    0x2c,
+	"jyutping": 0x2d,
+	"kkcor":    0x2e,
+	"kociewie": 0x2f,
+	"kscor":    0x30,
+	"laukika":  0x31,
+	"lemosin":  0x32,
+	"lengadoc": 0x33,
+	"lipaw":    0x63,
+	"ltg1929":  0x34,
+	"ltg2007":  0x35,
+	"luna1918": 0x36,
+	"metelko":  0x37,
+	"monoton":  0x38,
+	"ndyuka":   0x39,
+	"nedis":    0x3a,
+	"newfound": 0x3b,
+	"nicard":   0x3c,
+	"njiva":    0x64,
+	"nulik":    0x3d,
+	"osojs":    0x65,
+	"oxendict": 0x3e,
+	"pahawh2":  0x3f,
+	"pahawh3":  0x40,
+	"pahawh4":  0x41,
+	"pamaka":   0x42,
+	"peano":    0x43,
+	"petr1708": 0x44,
+	"pinyin":   0x45,
+	"polyton":  0x46,
+	"provenc":  0x47,
+	"puter":    0x48,
+	"rigik":    0x49,
+	"rozaj":    0x4a,
+	"rumgr":    0x4b,
+	"scotland": 0x4c,
+	"scouse":   0x4d,
+	"simple":   0x6f,
+	"solba":    0x66,
+	"sotav":    0x4e,
+	"spanglis": 0x4f,
+	"surmiran": 0x50,
+	"sursilv":  0x51,
+	"sutsilv":  0x52,
+	"synnejyl": 0x53,
+	"tarask":   0x54,
+	"tongyong": 0x55,
+	"tunumiit": 0x56,
+	"uccor":    0x57,
+	"ucrcor":   0x58,
+	"ulster":   0x59,
+	"unifon":   0x5a,
+	"vaidika":  0x5b,
+	"valencia": 0x5c,
+	"vallader": 0x5d,
+	"vecdruka": 0x5e,
+	"vivaraup": 0x5f,
+	"wadegile": 0x60,
+	"xsistemo": 0x61,
+}
+
+// variantNumSpecialized is the number of specialized variants in variants.
+const variantNumSpecialized = 105
+
+// nRegionGroups is the number of region groups.
+const nRegionGroups = 33
+
+type likelyLangRegion struct {
+	lang   uint16
+	region uint16
+}
+
+// likelyScript is a lookup table, indexed by scriptID, for the most likely
+// languages and regions given a script.
+// Size: 1052 bytes, 263 elements
+var likelyScript = [263]likelyLangRegion{
+	1:   {lang: 0x14e, region: 0x85},
+	3:   {lang: 0x2a2, region: 0x107},
+	4:   {lang: 0x1f, region: 0x9a},
+	5:   {lang: 0x3a, region: 0x6c},
+	7:   {lang: 0x3b, region: 0x9d},
+	8:   {lang: 0x1d7, region: 0x28},
+	9:   {lang: 0x13, region: 0x9d},
+	10:  {lang: 0x5b, region: 0x96},
+	11:  {lang: 0x60, region: 0x52},
+	12:  {lang: 0xb9, region: 0xb5},
+	13:  {lang: 0x63, region: 0x96},
+	14:  {lang: 0xa5, region: 0x35},
+	15:  {lang: 0x3e9, region: 0x9a},
+	17:  {lang: 0x529, region: 0x12f},
+	18:  {lang: 0x3b1, region: 0x9a},
+	19:  {lang: 0x15e, region: 0x79},
+	20:  {lang: 0xc2, region: 0x96},
+	21:  {lang: 0x9d, region: 0xe8},
+	22:  {lang: 0xdb, region: 0x35},
+	23:  {lang: 0xf3, region: 0x49},
+	24:  {lang: 0x4f0, region: 0x12c},
+	25:  {lang: 0xe7, region: 0x13f},
+	26:  {lang: 0xe5, region: 0x136},
+	29:  {lang: 0xf1, region: 0x6c},
+	31:  {lang: 0x1a0, region: 0x5e},
+	32:  {lang: 0x3e2, region: 0x107},
+	34:  {lang: 0x1be, region: 0x9a},
+	38:  {lang: 0x15e, region: 0x79},
+	41:  {lang: 0x133, region: 0x6c},
+	42:  {lang: 0x431, region: 0x27},
+	44:  {lang: 0x27, region: 0x70},
+	46:  {lang: 0x210, region: 0x7e},
+	47:  {lang: 0xfe, region: 0x38},
+	49:  {lang: 0x19b, region: 0x9a},
+	50:  {lang: 0x19e, region: 0x131},
+	51:  {lang: 0x3e9, region: 0x9a},
+	52:  {lang: 0x136, region: 0x88},
+	53:  {lang: 0x1a4, region: 0x9a},
+	54:  {lang: 0x39d, region: 0x9a},
+	55:  {lang: 0x529, region: 0x12f},
+	56:  {lang: 0x254, region: 0xac},
+	57:  {lang: 0x529, region: 0x53},
+	58:  {lang: 0x1cb, region: 0xe8},
+	59:  {lang: 0x529, region: 0x53},
+	60:  {lang: 0x529, region: 0x12f},
+	61:  {lang: 0x2fd, region: 0x9c},
+	62:  {lang: 0x1bc, region: 0x98},
+	63:  {lang: 0x200, region: 0xa3},
+	64:  {lang: 0x1c5, region: 0x12c},
+	65:  {lang: 0x1ca, region: 0xb0},
+	68:  {lang: 0x1d5, region: 0x93},
+	70:  {lang: 0x142, region: 0x9f},
+	71:  {lang: 0x254, region: 0xac},
+	72:  {lang: 0x20e, region: 0x96},
+	73:  {lang: 0x200, region: 0xa3},
+	75:  {lang: 0x135, region: 0xc5},
+	76:  {lang: 0x200, region: 0xa3},
+	78:  {lang: 0x3bb, region: 0xe9},
+	79:  {lang: 0x24a, region: 0xa7},
+	80:  {lang: 0x3fa, region: 0x9a},
+	83:  {lang: 0x251, region: 0x9a},
+	84:  {lang: 0x254, region: 0xac},
+	86:  {lang: 0x88, region: 0x9a},
+	87:  {lang: 0x370, region: 0x124},
+	88:  {lang: 0x2b8, region: 0xb0},
+	93:  {lang: 0x29f, region: 0x9a},
+	94:  {lang: 0x2a8, region: 0x9a},
+	95:  {lang: 0x28f, region: 0x88},
+	96:  {lang: 0x1a0, region: 0x88},
+	97:  {lang: 0x2ac, region: 0x53},
+	99:  {lang: 0x4f4, region: 0x12c},
+	100: {lang: 0x4f5, region: 0x12c},
+	101: {lang: 0x1be, region: 0x9a},
+	103: {lang: 0x337, region: 0x9d},
+	104: {lang: 0x4f7, region: 0x53},
+	105: {lang: 0xa9, region: 0x53},
+	108: {lang: 0x2e8, region: 0x113},
+	109: {lang: 0x4f8, region: 0x10c},
+	110: {lang: 0x4f8, region: 0x10c},
+	111: {lang: 0x304, region: 0x9a},
+	112: {lang: 0x31b, region: 0x9a},
+	113: {lang: 0x30b, region: 0x53},
+	115: {lang: 0x31e, region: 0x35},
+	116: {lang: 0x30e, region: 0x9a},
+	117: {lang: 0x414, region: 0xe9},
+	118: {lang: 0x331, region: 0xc5},
+	121: {lang: 0x4f9, region: 0x109},
+	122: {lang: 0x3b, region: 0xa2},
+	123: {lang: 0x353, region: 0xdc},
+	126: {lang: 0x2d0, region: 0x85},
+	127: {lang: 0x52a, region: 0x53},
+	128: {lang: 0x403, region: 0x97},
+	129: {lang: 0x3ee, region: 0x9a},
+	130: {lang: 0x39b, region: 0xc6},
+	131: {lang: 0x395, region: 0x9a},
+	132: {lang: 0x399, region: 0x136},
+	133: {lang: 0x429, region: 0x116},
+	135: {lang: 0x3b, region: 0x11d},
+	136: {lang: 0xfd, region: 0xc5},
+	139: {lang: 0x27d, region: 0x107},
+	140: {lang: 0x2c9, region: 0x53},
+	141: {lang: 0x39f, region: 0x9d},
+	142: {lang: 0x39f, region: 0x53},
+	144: {lang: 0x3ad, region: 0xb1},
+	146: {lang: 0x1c6, region: 0x53},
+	147: {lang: 0x4fd, region: 0x9d},
+	200: {lang: 0x3cb, region: 0x96},
+	203: {lang: 0x372, region: 0x10d},
+	204: {lang: 0x420, region: 0x98},
+	206: {lang: 0x4ff, region: 0x15f},
+	207: {lang: 0x3f0, region: 0x9a},
+	208: {lang: 0x45, region: 0x136},
+	209: {lang: 0x139, region: 0x7c},
+	210: {lang: 0x3e9, region: 0x9a},
+	212: {lang: 0x3e9, region: 0x9a},
+	213: {lang: 0x3fa, region: 0x9a},
+	214: {lang: 0x40c, region: 0xb4},
+	217: {lang: 0x433, region: 0x9a},
+	218: {lang: 0xef, region: 0xc6},
+	219: {lang: 0x43e, region: 0x96},
+	221: {lang: 0x44d, region: 0x35},
+	222: {lang: 0x44e, region: 0x9c},
+	226: {lang: 0x45a, region: 0xe8},
+	227: {lang: 0x11a, region: 0x9a},
+	228: {lang: 0x45e, region: 0x53},
+	229: {lang: 0x232, region: 0x53},
+	230: {lang: 0x450, region: 0x9a},
+	231: {lang: 0x4a5, region: 0x53},
+	232: {lang: 0x9f, region: 0x13f},
+	233: {lang: 0x461, region: 0x9a},
+	235: {lang: 0x528, region: 0xbb},
+	236: {lang: 0x153, region: 0xe8},
+	237: {lang: 0x128, region: 0xce},
+	238: {lang: 0x46b, region: 0x124},
+	239: {lang: 0xa9, region: 0x53},
+	240: {lang: 0x2ce, region: 0x9a},
+	243: {lang: 0x4ad, region: 0x11d},
+	244: {lang: 0x4be, region: 0xb5},
+	247: {lang: 0x1ce, region: 0x9a},
+	250: {lang: 0x3a9, region: 0x9d},
+	251: {lang: 0x22, region: 0x9c},
+	253: {lang: 0x1ea, region: 0x53},
+	254: {lang: 0xef, region: 0xc6},
+}
+
+type likelyScriptRegion struct {
+	region uint16
+	script uint16
+	flags  uint8
+}
+
+// likelyLang is a lookup table, indexed by langID, for the most likely
+// scripts and regions given incomplete information. If more entries exist for a
+// given language, region and script are the index and size respectively
+// of the list in likelyLangList.
+// Size: 7980 bytes, 1330 elements
+var likelyLang = [1330]likelyScriptRegion{
+	0:    {region: 0x136, script: 0x5b, flags: 0x0},
+	1:    {region: 0x70, script: 0x5b, flags: 0x0},
+	2:    {region: 0x166, script: 0x5b, flags: 0x0},
+	3:    {region: 0x166, script: 0x5b, flags: 0x0},
+	4:    {region: 0x166, script: 0x5b, flags: 0x0},
+	5:    {region: 0x7e, script: 0x20, flags: 0x0},
+	6:    {region: 0x166, script: 0x5b, flags: 0x0},
+	7:    {region: 0x166, script: 0x20, flags: 0x0},
+	8:    {region: 0x81, script: 0x5b, flags: 0x0},
+	9:    {region: 0x166, script: 0x5b, flags: 0x0},
+	10:   {region: 0x166, script: 0x5b, flags: 0x0},
+	11:   {region: 0x166, script: 0x5b, flags: 0x0},
+	12:   {region: 0x96, script: 0x5b, flags: 0x0},
+	13:   {region: 0x132, script: 0x5b, flags: 0x0},
+	14:   {region: 0x81, script: 0x5b, flags: 0x0},
+	15:   {region: 0x166, script: 0x5b, flags: 0x0},
+	16:   {region: 0x166, script: 0x5b, flags: 0x0},
+	17:   {region: 0x107, script: 0x20, flags: 0x0},
+	18:   {region: 0x166, script: 0x5b, flags: 0x0},
+	19:   {region: 0x9d, script: 0x9, flags: 0x0},
+	20:   {region: 0x129, script: 0x5, flags: 0x0},
+	21:   {region: 0x166, script: 0x5b, flags: 0x0},
+	22:   {region: 0x162, script: 0x5b, flags: 0x0},
+	23:   {region: 0x166, script: 0x5b, flags: 0x0},
+	24:   {region: 0x166, script: 0x5b, flags: 0x0},
+	25:   {region: 0x166, script: 0x5b, flags: 0x0},
+	26:   {region: 0x166, script: 0x5b, flags: 0x0},
+	27:   {region: 0x166, script: 0x5b, flags: 0x0},
+	28:   {region: 0x52, script: 0x5b, flags: 0x0},
+	29:   {region: 0x166, script: 0x5b, flags: 0x0},
+	30:   {region: 0x166, script: 0x5b, flags: 0x0},
+	31:   {region: 0x9a, script: 0x4, flags: 0x0},
+	32:   {region: 0x166, script: 0x5b, flags: 0x0},
+	33:   {region: 0x81, script: 0x5b, flags: 0x0},
+	34:   {region: 0x9c, script: 0xfb, flags: 0x0},
+	35:   {region: 0x166, script: 0x5b, flags: 0x0},
+	36:   {region: 0x166, script: 0x5b, flags: 0x0},
+	37:   {region: 0x14e, script: 0x5b, flags: 0x0},
+	38:   {region: 0x107, script: 0x20, flags: 0x0},
+	39:   {region: 0x70, script: 0x2c, flags: 0x0},
+	40:   {region: 0x166, script: 0x5b, flags: 0x0},
+	41:   {region: 0x166, script: 0x5b, flags: 0x0},
+	42:   {region: 0xd7, script: 0x5b, flags: 0x0},
+	43:   {region: 0x166, script: 0x5b, flags: 0x0},
+	45:   {region: 0x166, script: 0x5b, flags: 0x0},
+	46:   {region: 0x166, script: 0x5b, flags: 0x0},
+	47:   {region: 0x166, script: 0x5b, flags: 0x0},
+	48:   {region: 0x166, script: 0x5b, flags: 0x0},
+	49:   {region: 0x166, script: 0x5b, flags: 0x0},
+	50:   {region: 0x166, script: 0x5b, flags: 0x0},
+	51:   {region: 0x96, script: 0x5b, flags: 0x0},
+	52:   {region: 0x166, script: 0x5, flags: 0x0},
+	53:   {region: 0x123, script: 0x5, flags: 0x0},
+	54:   {region: 0x166, script: 0x5b, flags: 0x0},
+	55:   {region: 0x166, script: 0x5b, flags: 0x0},
+	56:   {region: 0x166, script: 0x5b, flags: 0x0},
+	57:   {region: 0x166, script: 0x5b, flags: 0x0},
+	58:   {region: 0x6c, script: 0x5, flags: 0x0},
+	59:   {region: 0x0, script: 0x3, flags: 0x1},
+	60:   {region: 0x166, script: 0x5b, flags: 0x0},
+	61:   {region: 0x51, script: 0x5b, flags: 0x0},
+	62:   {region: 0x3f, script: 0x5b, flags: 0x0},
+	63:   {region: 0x68, script: 0x5, flags: 0x0},
+	65:   {region: 0xbb, script: 0x5, flags: 0x0},
+	66:   {region: 0x6c, script: 0x5, flags: 0x0},
+	67:   {region: 0x9a, script: 0xe, flags: 0x0},
+	68:   {region: 0x130, script: 0x5b, flags: 0x0},
+	69:   {region: 0x136, script: 0xd0, flags: 0x0},
+	70:   {region: 0x166, script: 0x5b, flags: 0x0},
+	71:   {region: 0x166, script: 0x5b, flags: 0x0},
+	72:   {region: 0x6f, script: 0x5b, flags: 0x0},
+	73:   {region: 0x166, script: 0x5b, flags: 0x0},
+	74:   {region: 0x166, script: 0x5b, flags: 0x0},
+	75:   {region: 0x49, script: 0x5b, flags: 0x0},
+	76:   {region: 0x166, script: 0x5b, flags: 0x0},
+	77:   {region: 0x107, script: 0x20, flags: 0x0},
+	78:   {region: 0x166, script: 0x5, flags: 0x0},
+	79:   {region: 0x166, script: 0x5b, flags: 0x0},
+	80:   {region: 0x166, script: 0x5b, flags: 0x0},
+	81:   {region: 0x166, script: 0x5b, flags: 0x0},
+	82:   {region: 0x9a, script: 0x22, flags: 0x0},
+	83:   {region: 0x166, script: 0x5b, flags: 0x0},
+	84:   {region: 0x166, script: 0x5b, flags: 0x0},
+	85:   {region: 0x166, script: 0x5b, flags: 0x0},
+	86:   {region: 0x3f, script: 0x5b, flags: 0x0},
+	87:   {region: 0x166, script: 0x5b, flags: 0x0},
+	88:   {region: 0x3, script: 0x5, flags: 0x1},
+	89:   {region: 0x107, script: 0x20, flags: 0x0},
+	90:   {region: 0xe9, script: 0x5, flags: 0x0},
+	91:   {region: 0x96, script: 0x5b, flags: 0x0},
+	92:   {region: 0xdc, script: 0x22, flags: 0x0},
+	93:   {region: 0x2e, script: 0x5b, flags: 0x0},
+	94:   {region: 0x52, script: 0x5b, flags: 0x0},
+	95:   {region: 0x166, script: 0x5b, flags: 0x0},
+	96:   {region: 0x52, script: 0xb, flags: 0x0},
+	97:   {region: 0x166, script: 0x5b, flags: 0x0},
+	98:   {region: 0x166, script: 0x5b, flags: 0x0},
+	99:   {region: 0x96, script: 0x5b, flags: 0x0},
+	100:  {region: 0x166, script: 0x5b, flags: 0x0},
+	101:  {region: 0x52, script: 0x5b, flags: 0x0},
+	102:  {region: 0x166, script: 0x5b, flags: 0x0},
+	103:  {region: 0x166, script: 0x5b, flags: 0x0},
+	104:  {region: 0x166, script: 0x5b, flags: 0x0},
+	105:  {region: 0x166, script: 0x5b, flags: 0x0},
+	106:  {region: 0x4f, script: 0x5b, flags: 0x0},
+	107:  {region: 0x166, script: 0x5b, flags: 0x0},
+	108:  {region: 0x166, script: 0x5b, flags: 0x0},
+	109:  {region: 0x166, script: 0x5b, flags: 0x0},
+	110:  {region: 0x166, script: 0x2c, flags: 0x0},
+	111:  {region: 0x166, script: 0x5b, flags: 0x0},
+	112:  {region: 0x166, script: 0x5b, flags: 0x0},
+	113:  {region: 0x47, script: 0x20, flags: 0x0},
+	114:  {region: 0x166, script: 0x5b, flags: 0x0},
+	115:  {region: 0x166, script: 0x5b, flags: 0x0},
+	116:  {region: 0x10c, script: 0x5, flags: 0x0},
+	117:  {region: 0x163, script: 0x5b, flags: 0x0},
+	118:  {region: 0x166, script: 0x5b, flags: 0x0},
+	119:  {region: 0x96, script: 0x5b, flags: 0x0},
+	120:  {region: 0x166, script: 0x5b, flags: 0x0},
+	121:  {region: 0x130, script: 0x5b, flags: 0x0},
+	122:  {region: 0x52, script: 0x5b, flags: 0x0},
+	123:  {region: 0x9a, script: 0xe6, flags: 0x0},
+	124:  {region: 0xe9, script: 0x5, flags: 0x0},
+	125:  {region: 0x9a, script: 0x22, flags: 0x0},
+	126:  {region: 0x38, script: 0x20, flags: 0x0},
+	127:  {region: 0x9a, script: 0x22, flags: 0x0},
+	128:  {region: 0xe9, script: 0x5, flags: 0x0},
+	129:  {region: 0x12c, script: 0x34, flags: 0x0},
+	131:  {region: 0x9a, script: 0x22, flags: 0x0},
+	132:  {region: 0x166, script: 0x5b, flags: 0x0},
+	133:  {region: 0x9a, script: 0x22, flags: 0x0},
+	134:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	135:  {region: 0x166, script: 0x5b, flags: 0x0},
+	136:  {region: 0x9a, script: 0x22, flags: 0x0},
+	137:  {region: 0x166, script: 0x5b, flags: 0x0},
+	138:  {region: 0x140, script: 0x5b, flags: 0x0},
+	139:  {region: 0x166, script: 0x5b, flags: 0x0},
+	140:  {region: 0x166, script: 0x5b, flags: 0x0},
+	141:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	142:  {region: 0x166, script: 0x5b, flags: 0x0},
+	143:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	144:  {region: 0x166, script: 0x5b, flags: 0x0},
+	145:  {region: 0x166, script: 0x5b, flags: 0x0},
+	146:  {region: 0x166, script: 0x5b, flags: 0x0},
+	147:  {region: 0x166, script: 0x2c, flags: 0x0},
+	148:  {region: 0x9a, script: 0x22, flags: 0x0},
+	149:  {region: 0x96, script: 0x5b, flags: 0x0},
+	150:  {region: 0x166, script: 0x5b, flags: 0x0},
+	151:  {region: 0x166, script: 0x5b, flags: 0x0},
+	152:  {region: 0x115, script: 0x5b, flags: 0x0},
+	153:  {region: 0x166, script: 0x5b, flags: 0x0},
+	154:  {region: 0x166, script: 0x5b, flags: 0x0},
+	155:  {region: 0x52, script: 0x5b, flags: 0x0},
+	156:  {region: 0x166, script: 0x5b, flags: 0x0},
+	157:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	158:  {region: 0x166, script: 0x5b, flags: 0x0},
+	159:  {region: 0x13f, script: 0xe8, flags: 0x0},
+	160:  {region: 0xc4, script: 0x5b, flags: 0x0},
+	161:  {region: 0x166, script: 0x5b, flags: 0x0},
+	162:  {region: 0x166, script: 0x5b, flags: 0x0},
+	163:  {region: 0xc4, script: 0x5b, flags: 0x0},
+	164:  {region: 0x166, script: 0x5b, flags: 0x0},
+	165:  {region: 0x35, script: 0xe, flags: 0x0},
+	166:  {region: 0x166, script: 0x5b, flags: 0x0},
+	167:  {region: 0x166, script: 0x5b, flags: 0x0},
+	168:  {region: 0x166, script: 0x5b, flags: 0x0},
+	169:  {region: 0x53, script: 0xef, flags: 0x0},
+	170:  {region: 0x166, script: 0x5b, flags: 0x0},
+	171:  {region: 0x166, script: 0x5b, flags: 0x0},
+	172:  {region: 0x166, script: 0x5b, flags: 0x0},
+	173:  {region: 0x9a, script: 0xe, flags: 0x0},
+	174:  {region: 0x166, script: 0x5b, flags: 0x0},
+	175:  {region: 0x9d, script: 0x5, flags: 0x0},
+	176:  {region: 0x166, script: 0x5b, flags: 0x0},
+	177:  {region: 0x4f, script: 0x5b, flags: 0x0},
+	178:  {region: 0x79, script: 0x5b, flags: 0x0},
+	179:  {region: 0x9a, script: 0x22, flags: 0x0},
+	180:  {region: 0xe9, script: 0x5, flags: 0x0},
+	181:  {region: 0x9a, script: 0x22, flags: 0x0},
+	182:  {region: 0x166, script: 0x5b, flags: 0x0},
+	183:  {region: 0x33, script: 0x5b, flags: 0x0},
+	184:  {region: 0x166, script: 0x5b, flags: 0x0},
+	185:  {region: 0xb5, script: 0xc, flags: 0x0},
+	186:  {region: 0x52, script: 0x5b, flags: 0x0},
+	187:  {region: 0x166, script: 0x2c, flags: 0x0},
+	188:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	189:  {region: 0x166, script: 0x5b, flags: 0x0},
+	190:  {region: 0xe9, script: 0x22, flags: 0x0},
+	191:  {region: 0x107, script: 0x20, flags: 0x0},
+	192:  {region: 0x160, script: 0x5b, flags: 0x0},
+	193:  {region: 0x166, script: 0x5b, flags: 0x0},
+	194:  {region: 0x96, script: 0x5b, flags: 0x0},
+	195:  {region: 0x166, script: 0x5b, flags: 0x0},
+	196:  {region: 0x52, script: 0x5b, flags: 0x0},
+	197:  {region: 0x166, script: 0x5b, flags: 0x0},
+	198:  {region: 0x166, script: 0x5b, flags: 0x0},
+	199:  {region: 0x166, script: 0x5b, flags: 0x0},
+	200:  {region: 0x87, script: 0x5b, flags: 0x0},
+	201:  {region: 0x166, script: 0x5b, flags: 0x0},
+	202:  {region: 0x166, script: 0x5b, flags: 0x0},
+	203:  {region: 0x166, script: 0x5b, flags: 0x0},
+	204:  {region: 0x166, script: 0x5b, flags: 0x0},
+	205:  {region: 0x6e, script: 0x2c, flags: 0x0},
+	206:  {region: 0x166, script: 0x5b, flags: 0x0},
+	207:  {region: 0x166, script: 0x5b, flags: 0x0},
+	208:  {region: 0x52, script: 0x5b, flags: 0x0},
+	209:  {region: 0x166, script: 0x5b, flags: 0x0},
+	210:  {region: 0x166, script: 0x5b, flags: 0x0},
+	211:  {region: 0xc4, script: 0x5b, flags: 0x0},
+	212:  {region: 0x166, script: 0x5b, flags: 0x0},
+	213:  {region: 0x166, script: 0x5b, flags: 0x0},
+	214:  {region: 0x166, script: 0x5b, flags: 0x0},
+	215:  {region: 0x6f, script: 0x5b, flags: 0x0},
+	216:  {region: 0x166, script: 0x5b, flags: 0x0},
+	217:  {region: 0x166, script: 0x5b, flags: 0x0},
+	218:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	219:  {region: 0x35, script: 0x16, flags: 0x0},
+	220:  {region: 0x107, script: 0x20, flags: 0x0},
+	221:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	222:  {region: 0x166, script: 0x5b, flags: 0x0},
+	223:  {region: 0x132, script: 0x5b, flags: 0x0},
+	224:  {region: 0x8b, script: 0x5b, flags: 0x0},
+	225:  {region: 0x76, script: 0x5b, flags: 0x0},
+	226:  {region: 0x107, script: 0x20, flags: 0x0},
+	227:  {region: 0x136, script: 0x5b, flags: 0x0},
+	228:  {region: 0x49, script: 0x5b, flags: 0x0},
+	229:  {region: 0x136, script: 0x1a, flags: 0x0},
+	230:  {region: 0xa7, script: 0x5, flags: 0x0},
+	231:  {region: 0x13f, script: 0x19, flags: 0x0},
+	232:  {region: 0x166, script: 0x5b, flags: 0x0},
+	233:  {region: 0x9c, script: 0x5, flags: 0x0},
+	234:  {region: 0x166, script: 0x5b, flags: 0x0},
+	235:  {region: 0x166, script: 0x5b, flags: 0x0},
+	236:  {region: 0x166, script: 0x5b, flags: 0x0},
+	237:  {region: 0x166, script: 0x5b, flags: 0x0},
+	238:  {region: 0x166, script: 0x5b, flags: 0x0},
+	239:  {region: 0xc6, script: 0xda, flags: 0x0},
+	240:  {region: 0x79, script: 0x5b, flags: 0x0},
+	241:  {region: 0x6c, script: 0x1d, flags: 0x0},
+	242:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	243:  {region: 0x49, script: 0x17, flags: 0x0},
+	244:  {region: 0x131, script: 0x20, flags: 0x0},
+	245:  {region: 0x49, script: 0x17, flags: 0x0},
+	246:  {region: 0x49, script: 0x17, flags: 0x0},
+	247:  {region: 0x49, script: 0x17, flags: 0x0},
+	248:  {region: 0x49, script: 0x17, flags: 0x0},
+	249:  {region: 0x10b, script: 0x5b, flags: 0x0},
+	250:  {region: 0x5f, script: 0x5b, flags: 0x0},
+	251:  {region: 0xea, script: 0x5b, flags: 0x0},
+	252:  {region: 0x49, script: 0x17, flags: 0x0},
+	253:  {region: 0xc5, script: 0x88, flags: 0x0},
+	254:  {region: 0x8, script: 0x2, flags: 0x1},
+	255:  {region: 0x107, script: 0x20, flags: 0x0},
+	256:  {region: 0x7c, script: 0x5b, flags: 0x0},
+	257:  {region: 0x64, script: 0x5b, flags: 0x0},
+	258:  {region: 0x166, script: 0x5b, flags: 0x0},
+	259:  {region: 0x166, script: 0x5b, flags: 0x0},
+	260:  {region: 0x166, script: 0x5b, flags: 0x0},
+	261:  {region: 0x166, script: 0x5b, flags: 0x0},
+	262:  {region: 0x136, script: 0x5b, flags: 0x0},
+	263:  {region: 0x107, script: 0x20, flags: 0x0},
+	264:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	265:  {region: 0x166, script: 0x5b, flags: 0x0},
+	266:  {region: 0x166, script: 0x5b, flags: 0x0},
+	267:  {region: 0x9a, script: 0x5, flags: 0x0},
+	268:  {region: 0x166, script: 0x5b, flags: 0x0},
+	269:  {region: 0x61, script: 0x5b, flags: 0x0},
+	270:  {region: 0x166, script: 0x5b, flags: 0x0},
+	271:  {region: 0x49, script: 0x5b, flags: 0x0},
+	272:  {region: 0x166, script: 0x5b, flags: 0x0},
+	273:  {region: 0x166, script: 0x5b, flags: 0x0},
+	274:  {region: 0x166, script: 0x5b, flags: 0x0},
+	275:  {region: 0x166, script: 0x5, flags: 0x0},
+	276:  {region: 0x49, script: 0x5b, flags: 0x0},
+	277:  {region: 0x166, script: 0x5b, flags: 0x0},
+	278:  {region: 0x166, script: 0x5b, flags: 0x0},
+	279:  {region: 0xd5, script: 0x5b, flags: 0x0},
+	280:  {region: 0x4f, script: 0x5b, flags: 0x0},
+	281:  {region: 0x166, script: 0x5b, flags: 0x0},
+	282:  {region: 0x9a, script: 0x5, flags: 0x0},
+	283:  {region: 0x166, script: 0x5b, flags: 0x0},
+	284:  {region: 0x166, script: 0x5b, flags: 0x0},
+	285:  {region: 0x166, script: 0x5b, flags: 0x0},
+	286:  {region: 0x166, script: 0x2c, flags: 0x0},
+	287:  {region: 0x61, script: 0x5b, flags: 0x0},
+	288:  {region: 0xc4, script: 0x5b, flags: 0x0},
+	289:  {region: 0xd1, script: 0x5b, flags: 0x0},
+	290:  {region: 0x166, script: 0x5b, flags: 0x0},
+	291:  {region: 0xdc, script: 0x22, flags: 0x0},
+	292:  {region: 0x52, script: 0x5b, flags: 0x0},
+	293:  {region: 0x166, script: 0x5b, flags: 0x0},
+	294:  {region: 0x166, script: 0x5b, flags: 0x0},
+	295:  {region: 0x166, script: 0x5b, flags: 0x0},
+	296:  {region: 0xce, script: 0xed, flags: 0x0},
+	297:  {region: 0x166, script: 0x5b, flags: 0x0},
+	298:  {region: 0x166, script: 0x5b, flags: 0x0},
+	299:  {region: 0x115, script: 0x5b, flags: 0x0},
+	300:  {region: 0x37, script: 0x5b, flags: 0x0},
+	301:  {region: 0x43, script: 0xef, flags: 0x0},
+	302:  {region: 0x166, script: 0x5b, flags: 0x0},
+	303:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	304:  {region: 0x81, script: 0x5b, flags: 0x0},
+	305:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	306:  {region: 0x9f, script: 0x5b, flags: 0x0},
+	307:  {region: 0x6c, script: 0x29, flags: 0x0},
+	308:  {region: 0x166, script: 0x5b, flags: 0x0},
+	309:  {region: 0xc5, script: 0x4b, flags: 0x0},
+	310:  {region: 0x88, script: 0x34, flags: 0x0},
+	311:  {region: 0x166, script: 0x5b, flags: 0x0},
+	312:  {region: 0x166, script: 0x5b, flags: 0x0},
+	313:  {region: 0xa, script: 0x2, flags: 0x1},
+	314:  {region: 0x166, script: 0x5b, flags: 0x0},
+	315:  {region: 0x166, script: 0x5b, flags: 0x0},
+	316:  {region: 0x1, script: 0x5b, flags: 0x0},
+	317:  {region: 0x166, script: 0x5b, flags: 0x0},
+	318:  {region: 0x6f, script: 0x5b, flags: 0x0},
+	319:  {region: 0x136, script: 0x5b, flags: 0x0},
+	320:  {region: 0x6b, script: 0x5b, flags: 0x0},
+	321:  {region: 0x166, script: 0x5b, flags: 0x0},
+	322:  {region: 0x9f, script: 0x46, flags: 0x0},
+	323:  {region: 0x166, script: 0x5b, flags: 0x0},
+	324:  {region: 0x166, script: 0x5b, flags: 0x0},
+	325:  {region: 0x6f, script: 0x5b, flags: 0x0},
+	326:  {region: 0x52, script: 0x5b, flags: 0x0},
+	327:  {region: 0x6f, script: 0x5b, flags: 0x0},
+	328:  {region: 0x9d, script: 0x5, flags: 0x0},
+	329:  {region: 0x166, script: 0x5b, flags: 0x0},
+	330:  {region: 0x166, script: 0x5b, flags: 0x0},
+	331:  {region: 0x166, script: 0x5b, flags: 0x0},
+	332:  {region: 0x166, script: 0x5b, flags: 0x0},
+	333:  {region: 0x87, script: 0x5b, flags: 0x0},
+	334:  {region: 0xc, script: 0x2, flags: 0x1},
+	335:  {region: 0x166, script: 0x5b, flags: 0x0},
+	336:  {region: 0xc4, script: 0x5b, flags: 0x0},
+	337:  {region: 0x73, script: 0x5b, flags: 0x0},
+	338:  {region: 0x10c, script: 0x5, flags: 0x0},
+	339:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	340:  {region: 0x10d, script: 0x5b, flags: 0x0},
+	341:  {region: 0x74, script: 0x5b, flags: 0x0},
+	342:  {region: 0x166, script: 0x5b, flags: 0x0},
+	343:  {region: 0x166, script: 0x5b, flags: 0x0},
+	344:  {region: 0x77, script: 0x5b, flags: 0x0},
+	345:  {region: 0x166, script: 0x5b, flags: 0x0},
+	346:  {region: 0x3b, script: 0x5b, flags: 0x0},
+	347:  {region: 0x166, script: 0x5b, flags: 0x0},
+	348:  {region: 0x166, script: 0x5b, flags: 0x0},
+	349:  {region: 0x166, script: 0x5b, flags: 0x0},
+	350:  {region: 0x79, script: 0x5b, flags: 0x0},
+	351:  {region: 0x136, script: 0x5b, flags: 0x0},
+	352:  {region: 0x79, script: 0x5b, flags: 0x0},
+	353:  {region: 0x61, script: 0x5b, flags: 0x0},
+	354:  {region: 0x61, script: 0x5b, flags: 0x0},
+	355:  {region: 0x52, script: 0x5, flags: 0x0},
+	356:  {region: 0x141, script: 0x5b, flags: 0x0},
+	357:  {region: 0x166, script: 0x5b, flags: 0x0},
+	358:  {region: 0x85, script: 0x5b, flags: 0x0},
+	359:  {region: 0x166, script: 0x5b, flags: 0x0},
+	360:  {region: 0xd5, script: 0x5b, flags: 0x0},
+	361:  {region: 0x9f, script: 0x5b, flags: 0x0},
+	362:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	363:  {region: 0x166, script: 0x5b, flags: 0x0},
+	364:  {region: 0x10c, script: 0x5b, flags: 0x0},
+	365:  {region: 0xda, script: 0x5b, flags: 0x0},
+	366:  {region: 0x97, script: 0x5b, flags: 0x0},
+	367:  {region: 0x81, script: 0x5b, flags: 0x0},
+	368:  {region: 0x166, script: 0x5b, flags: 0x0},
+	369:  {region: 0xbd, script: 0x5b, flags: 0x0},
+	370:  {region: 0x166, script: 0x5b, flags: 0x0},
+	371:  {region: 0x166, script: 0x5b, flags: 0x0},
+	372:  {region: 0x166, script: 0x5b, flags: 0x0},
+	373:  {region: 0x53, script: 0x3b, flags: 0x0},
+	374:  {region: 0x166, script: 0x5b, flags: 0x0},
+	375:  {region: 0x96, script: 0x5b, flags: 0x0},
+	376:  {region: 0x166, script: 0x5b, flags: 0x0},
+	377:  {region: 0x166, script: 0x5b, flags: 0x0},
+	378:  {region: 0x9a, script: 0x22, flags: 0x0},
+	379:  {region: 0x166, script: 0x5b, flags: 0x0},
+	380:  {region: 0x9d, script: 0x5, flags: 0x0},
+	381:  {region: 0x7f, script: 0x5b, flags: 0x0},
+	382:  {region: 0x7c, script: 0x5b, flags: 0x0},
+	383:  {region: 0x166, script: 0x5b, flags: 0x0},
+	384:  {region: 0x166, script: 0x5b, flags: 0x0},
+	385:  {region: 0x166, script: 0x5b, flags: 0x0},
+	386:  {region: 0x166, script: 0x5b, flags: 0x0},
+	387:  {region: 0x166, script: 0x5b, flags: 0x0},
+	388:  {region: 0x166, script: 0x5b, flags: 0x0},
+	389:  {region: 0x70, script: 0x2c, flags: 0x0},
+	390:  {region: 0x166, script: 0x5b, flags: 0x0},
+	391:  {region: 0xdc, script: 0x22, flags: 0x0},
+	392:  {region: 0x166, script: 0x5b, flags: 0x0},
+	393:  {region: 0xa8, script: 0x5b, flags: 0x0},
+	394:  {region: 0x166, script: 0x5b, flags: 0x0},
+	395:  {region: 0xe9, script: 0x5, flags: 0x0},
+	396:  {region: 0x166, script: 0x5b, flags: 0x0},
+	397:  {region: 0xe9, script: 0x5, flags: 0x0},
+	398:  {region: 0x166, script: 0x5b, flags: 0x0},
+	399:  {region: 0x166, script: 0x5b, flags: 0x0},
+	400:  {region: 0x6f, script: 0x5b, flags: 0x0},
+	401:  {region: 0x9d, script: 0x5, flags: 0x0},
+	402:  {region: 0x166, script: 0x5b, flags: 0x0},
+	403:  {region: 0x166, script: 0x2c, flags: 0x0},
+	404:  {region: 0xf2, script: 0x5b, flags: 0x0},
+	405:  {region: 0x166, script: 0x5b, flags: 0x0},
+	406:  {region: 0x166, script: 0x5b, flags: 0x0},
+	407:  {region: 0x166, script: 0x5b, flags: 0x0},
+	408:  {region: 0x166, script: 0x2c, flags: 0x0},
+	409:  {region: 0x166, script: 0x5b, flags: 0x0},
+	410:  {region: 0x9a, script: 0x22, flags: 0x0},
+	411:  {region: 0x9a, script: 0xe9, flags: 0x0},
+	412:  {region: 0x96, script: 0x5b, flags: 0x0},
+	413:  {region: 0xda, script: 0x5b, flags: 0x0},
+	414:  {region: 0x131, script: 0x32, flags: 0x0},
+	415:  {region: 0x166, script: 0x5b, flags: 0x0},
+	416:  {region: 0xe, script: 0x2, flags: 0x1},
+	417:  {region: 0x9a, script: 0xe, flags: 0x0},
+	418:  {region: 0x166, script: 0x5b, flags: 0x0},
+	419:  {region: 0x4e, script: 0x5b, flags: 0x0},
+	420:  {region: 0x9a, script: 0x35, flags: 0x0},
+	421:  {region: 0x41, script: 0x5b, flags: 0x0},
+	422:  {region: 0x54, script: 0x5b, flags: 0x0},
+	423:  {region: 0x166, script: 0x5b, flags: 0x0},
+	424:  {region: 0x81, script: 0x5b, flags: 0x0},
+	425:  {region: 0x166, script: 0x5b, flags: 0x0},
+	426:  {region: 0x166, script: 0x5b, flags: 0x0},
+	427:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	428:  {region: 0x99, script: 0x5b, flags: 0x0},
+	429:  {region: 0x166, script: 0x5b, flags: 0x0},
+	430:  {region: 0xdc, script: 0x22, flags: 0x0},
+	431:  {region: 0x166, script: 0x5b, flags: 0x0},
+	432:  {region: 0x166, script: 0x5, flags: 0x0},
+	433:  {region: 0x49, script: 0x5b, flags: 0x0},
+	434:  {region: 0x166, script: 0x5, flags: 0x0},
+	435:  {region: 0x166, script: 0x5b, flags: 0x0},
+	436:  {region: 0x10, script: 0x3, flags: 0x1},
+	437:  {region: 0x166, script: 0x5b, flags: 0x0},
+	438:  {region: 0x53, script: 0x3b, flags: 0x0},
+	439:  {region: 0x166, script: 0x5b, flags: 0x0},
+	440:  {region: 0x136, script: 0x5b, flags: 0x0},
+	441:  {region: 0x24, script: 0x5, flags: 0x0},
+	442:  {region: 0x166, script: 0x5b, flags: 0x0},
+	443:  {region: 0x166, script: 0x2c, flags: 0x0},
+	444:  {region: 0x98, script: 0x3e, flags: 0x0},
+	445:  {region: 0x166, script: 0x5b, flags: 0x0},
+	446:  {region: 0x9a, script: 0x22, flags: 0x0},
+	447:  {region: 0x166, script: 0x5b, flags: 0x0},
+	448:  {region: 0x74, script: 0x5b, flags: 0x0},
+	449:  {region: 0x166, script: 0x5b, flags: 0x0},
+	450:  {region: 0x166, script: 0x5b, flags: 0x0},
+	451:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	452:  {region: 0x166, script: 0x5b, flags: 0x0},
+	453:  {region: 0x12c, script: 0x40, flags: 0x0},
+	454:  {region: 0x53, script: 0x92, flags: 0x0},
+	455:  {region: 0x166, script: 0x5b, flags: 0x0},
+	456:  {region: 0xe9, script: 0x5, flags: 0x0},
+	457:  {region: 0x9a, script: 0x22, flags: 0x0},
+	458:  {region: 0xb0, script: 0x41, flags: 0x0},
+	459:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	460:  {region: 0xe9, script: 0x5, flags: 0x0},
+	461:  {region: 0xe7, script: 0x5b, flags: 0x0},
+	462:  {region: 0x9a, script: 0x22, flags: 0x0},
+	463:  {region: 0x9a, script: 0x22, flags: 0x0},
+	464:  {region: 0x166, script: 0x5b, flags: 0x0},
+	465:  {region: 0x91, script: 0x5b, flags: 0x0},
+	466:  {region: 0x61, script: 0x5b, flags: 0x0},
+	467:  {region: 0x53, script: 0x3b, flags: 0x0},
+	468:  {region: 0x92, script: 0x5b, flags: 0x0},
+	469:  {region: 0x93, script: 0x5b, flags: 0x0},
+	470:  {region: 0x166, script: 0x5b, flags: 0x0},
+	471:  {region: 0x28, script: 0x8, flags: 0x0},
+	472:  {region: 0xd3, script: 0x5b, flags: 0x0},
+	473:  {region: 0x79, script: 0x5b, flags: 0x0},
+	474:  {region: 0x166, script: 0x5b, flags: 0x0},
+	475:  {region: 0x166, script: 0x5b, flags: 0x0},
+	476:  {region: 0xd1, script: 0x5b, flags: 0x0},
+	477:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	478:  {region: 0x166, script: 0x5b, flags: 0x0},
+	479:  {region: 0x166, script: 0x5b, flags: 0x0},
+	480:  {region: 0x166, script: 0x5b, flags: 0x0},
+	481:  {region: 0x96, script: 0x5b, flags: 0x0},
+	482:  {region: 0x166, script: 0x5b, flags: 0x0},
+	483:  {region: 0x166, script: 0x5b, flags: 0x0},
+	484:  {region: 0x166, script: 0x5b, flags: 0x0},
+	486:  {region: 0x123, script: 0x5b, flags: 0x0},
+	487:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	488:  {region: 0x166, script: 0x5b, flags: 0x0},
+	489:  {region: 0x166, script: 0x5b, flags: 0x0},
+	490:  {region: 0x53, script: 0xfd, flags: 0x0},
+	491:  {region: 0x166, script: 0x5b, flags: 0x0},
+	492:  {region: 0x136, script: 0x5b, flags: 0x0},
+	493:  {region: 0x166, script: 0x5b, flags: 0x0},
+	494:  {region: 0x49, script: 0x5b, flags: 0x0},
+	495:  {region: 0x166, script: 0x5b, flags: 0x0},
+	496:  {region: 0x166, script: 0x5b, flags: 0x0},
+	497:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	498:  {region: 0x166, script: 0x5b, flags: 0x0},
+	499:  {region: 0x96, script: 0x5b, flags: 0x0},
+	500:  {region: 0x107, script: 0x20, flags: 0x0},
+	501:  {region: 0x1, script: 0x5b, flags: 0x0},
+	502:  {region: 0x166, script: 0x5b, flags: 0x0},
+	503:  {region: 0x166, script: 0x5b, flags: 0x0},
+	504:  {region: 0x9e, script: 0x5b, flags: 0x0},
+	505:  {region: 0x9f, script: 0x5b, flags: 0x0},
+	506:  {region: 0x49, script: 0x17, flags: 0x0},
+	507:  {region: 0x98, script: 0x3e, flags: 0x0},
+	508:  {region: 0x166, script: 0x5b, flags: 0x0},
+	509:  {region: 0x166, script: 0x5b, flags: 0x0},
+	510:  {region: 0x107, script: 0x5b, flags: 0x0},
+	511:  {region: 0x166, script: 0x5b, flags: 0x0},
+	512:  {region: 0xa3, script: 0x49, flags: 0x0},
+	513:  {region: 0x166, script: 0x5b, flags: 0x0},
+	514:  {region: 0xa1, script: 0x5b, flags: 0x0},
+	515:  {region: 0x1, script: 0x5b, flags: 0x0},
+	516:  {region: 0x166, script: 0x5b, flags: 0x0},
+	517:  {region: 0x166, script: 0x5b, flags: 0x0},
+	518:  {region: 0x166, script: 0x5b, flags: 0x0},
+	519:  {region: 0x52, script: 0x5b, flags: 0x0},
+	520:  {region: 0x131, script: 0x3e, flags: 0x0},
+	521:  {region: 0x166, script: 0x5b, flags: 0x0},
+	522:  {region: 0x130, script: 0x5b, flags: 0x0},
+	523:  {region: 0xdc, script: 0x22, flags: 0x0},
+	524:  {region: 0x166, script: 0x5b, flags: 0x0},
+	525:  {region: 0x64, script: 0x5b, flags: 0x0},
+	526:  {region: 0x96, script: 0x5b, flags: 0x0},
+	527:  {region: 0x96, script: 0x5b, flags: 0x0},
+	528:  {region: 0x7e, script: 0x2e, flags: 0x0},
+	529:  {region: 0x138, script: 0x20, flags: 0x0},
+	530:  {region: 0x68, script: 0x5b, flags: 0x0},
+	531:  {region: 0xc5, script: 0x5b, flags: 0x0},
+	532:  {region: 0x166, script: 0x5b, flags: 0x0},
+	533:  {region: 0x166, script: 0x5b, flags: 0x0},
+	534:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	535:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	536:  {region: 0xc4, script: 0x5b, flags: 0x0},
+	537:  {region: 0x107, script: 0x20, flags: 0x0},
+	538:  {region: 0x166, script: 0x5b, flags: 0x0},
+	539:  {region: 0x166, script: 0x5b, flags: 0x0},
+	540:  {region: 0x166, script: 0x5b, flags: 0x0},
+	541:  {region: 0x166, script: 0x5b, flags: 0x0},
+	542:  {region: 0xd5, script: 0x5, flags: 0x0},
+	543:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	544:  {region: 0x165, script: 0x5b, flags: 0x0},
+	545:  {region: 0x166, script: 0x5b, flags: 0x0},
+	546:  {region: 0x166, script: 0x5b, flags: 0x0},
+	547:  {region: 0x130, script: 0x5b, flags: 0x0},
+	548:  {region: 0x123, script: 0x5, flags: 0x0},
+	549:  {region: 0x166, script: 0x5b, flags: 0x0},
+	550:  {region: 0x124, script: 0xee, flags: 0x0},
+	551:  {region: 0x5b, script: 0x5b, flags: 0x0},
+	552:  {region: 0x52, script: 0x5b, flags: 0x0},
+	553:  {region: 0x166, script: 0x5b, flags: 0x0},
+	554:  {region: 0x4f, script: 0x5b, flags: 0x0},
+	555:  {region: 0x9a, script: 0x22, flags: 0x0},
+	556:  {region: 0x9a, script: 0x22, flags: 0x0},
+	557:  {region: 0x4b, script: 0x5b, flags: 0x0},
+	558:  {region: 0x96, script: 0x5b, flags: 0x0},
+	559:  {region: 0x166, script: 0x5b, flags: 0x0},
+	560:  {region: 0x41, script: 0x5b, flags: 0x0},
+	561:  {region: 0x9a, script: 0x5b, flags: 0x0},
+	562:  {region: 0x53, script: 0xe5, flags: 0x0},
+	563:  {region: 0x9a, script: 0x22, flags: 0x0},
+	564:  {region: 0xc4, script: 0x5b, flags: 0x0},
+	565:  {region: 0x166, script: 0x5b, flags: 0x0},
+	566:  {region: 0x9a, script: 0x76, flags: 0x0},
+	567:  {region: 0xe9, script: 0x5, flags: 0x0},
+	568:  {region: 0x166, script: 0x5b, flags: 0x0},
+	569:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	570:  {region: 0x166, script: 0x5b, flags: 0x0},
+	571:  {region: 0x12c, script: 0x5b, flags: 0x0},
+	572:  {region: 0x166, script: 0x5b, flags: 0x0},
+	573:  {region: 0xd3, script: 0x5b, flags: 0x0},
+	574:  {region: 0x166, script: 0x5b, flags: 0x0},
+	575:  {region: 0xb0, script: 0x58, flags: 0x0},
+	576:  {region: 0x166, script: 0x5b, flags: 0x0},
+	577:  {region: 0x166, script: 0x5b, flags: 0x0},
+	578:  {region: 0x13, script: 0x6, flags: 0x1},
+	579:  {region: 0x166, script: 0x5b, flags: 0x0},
+	580:  {region: 0x52, script: 0x5b, flags: 0x0},
+	581:  {region: 0x83, script: 0x5b, flags: 0x0},
+	582:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	583:  {region: 0x166, script: 0x5b, flags: 0x0},
+	584:  {region: 0x166, script: 0x5b, flags: 0x0},
+	585:  {region: 0x166, script: 0x5b, flags: 0x0},
+	586:  {region: 0xa7, script: 0x4f, flags: 0x0},
+	587:  {region: 0x2a, script: 0x5b, flags: 0x0},
+	588:  {region: 0x166, script: 0x5b, flags: 0x0},
+	589:  {region: 0x166, script: 0x5b, flags: 0x0},
+	590:  {region: 0x166, script: 0x5b, flags: 0x0},
+	591:  {region: 0x166, script: 0x5b, flags: 0x0},
+	592:  {region: 0x166, script: 0x5b, flags: 0x0},
+	593:  {region: 0x9a, script: 0x53, flags: 0x0},
+	594:  {region: 0x8c, script: 0x5b, flags: 0x0},
+	595:  {region: 0x166, script: 0x5b, flags: 0x0},
+	596:  {region: 0xac, script: 0x54, flags: 0x0},
+	597:  {region: 0x107, script: 0x20, flags: 0x0},
+	598:  {region: 0x9a, script: 0x22, flags: 0x0},
+	599:  {region: 0x166, script: 0x5b, flags: 0x0},
+	600:  {region: 0x76, script: 0x5b, flags: 0x0},
+	601:  {region: 0x166, script: 0x5b, flags: 0x0},
+	602:  {region: 0xb5, script: 0x5b, flags: 0x0},
+	603:  {region: 0x166, script: 0x5b, flags: 0x0},
+	604:  {region: 0x166, script: 0x5b, flags: 0x0},
+	605:  {region: 0x166, script: 0x5b, flags: 0x0},
+	606:  {region: 0x166, script: 0x5b, flags: 0x0},
+	607:  {region: 0x166, script: 0x5b, flags: 0x0},
+	608:  {region: 0x166, script: 0x5b, flags: 0x0},
+	609:  {region: 0x166, script: 0x5b, flags: 0x0},
+	610:  {region: 0x166, script: 0x2c, flags: 0x0},
+	611:  {region: 0x166, script: 0x5b, flags: 0x0},
+	612:  {region: 0x107, script: 0x20, flags: 0x0},
+	613:  {region: 0x113, script: 0x5b, flags: 0x0},
+	614:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	615:  {region: 0x107, script: 0x5b, flags: 0x0},
+	616:  {region: 0x166, script: 0x5b, flags: 0x0},
+	617:  {region: 0x9a, script: 0x22, flags: 0x0},
+	618:  {region: 0x9a, script: 0x5, flags: 0x0},
+	619:  {region: 0x130, script: 0x5b, flags: 0x0},
+	620:  {region: 0x166, script: 0x5b, flags: 0x0},
+	621:  {region: 0x52, script: 0x5b, flags: 0x0},
+	622:  {region: 0x61, script: 0x5b, flags: 0x0},
+	623:  {region: 0x166, script: 0x5b, flags: 0x0},
+	624:  {region: 0x166, script: 0x5b, flags: 0x0},
+	625:  {region: 0x166, script: 0x2c, flags: 0x0},
+	626:  {region: 0x166, script: 0x5b, flags: 0x0},
+	627:  {region: 0x166, script: 0x5b, flags: 0x0},
+	628:  {region: 0x19, script: 0x3, flags: 0x1},
+	629:  {region: 0x166, script: 0x5b, flags: 0x0},
+	630:  {region: 0x166, script: 0x5b, flags: 0x0},
+	631:  {region: 0x166, script: 0x5b, flags: 0x0},
+	632:  {region: 0x166, script: 0x5b, flags: 0x0},
+	633:  {region: 0x107, script: 0x20, flags: 0x0},
+	634:  {region: 0x166, script: 0x5b, flags: 0x0},
+	635:  {region: 0x166, script: 0x5b, flags: 0x0},
+	636:  {region: 0x166, script: 0x5b, flags: 0x0},
+	637:  {region: 0x107, script: 0x20, flags: 0x0},
+	638:  {region: 0x166, script: 0x5b, flags: 0x0},
+	639:  {region: 0x96, script: 0x5b, flags: 0x0},
+	640:  {region: 0xe9, script: 0x5, flags: 0x0},
+	641:  {region: 0x7c, script: 0x5b, flags: 0x0},
+	642:  {region: 0x166, script: 0x5b, flags: 0x0},
+	643:  {region: 0x166, script: 0x5b, flags: 0x0},
+	644:  {region: 0x166, script: 0x5b, flags: 0x0},
+	645:  {region: 0x166, script: 0x2c, flags: 0x0},
+	646:  {region: 0x124, script: 0xee, flags: 0x0},
+	647:  {region: 0xe9, script: 0x5, flags: 0x0},
+	648:  {region: 0x166, script: 0x5b, flags: 0x0},
+	649:  {region: 0x166, script: 0x5b, flags: 0x0},
+	650:  {region: 0x1c, script: 0x5, flags: 0x1},
+	651:  {region: 0x166, script: 0x5b, flags: 0x0},
+	652:  {region: 0x166, script: 0x5b, flags: 0x0},
+	653:  {region: 0x166, script: 0x5b, flags: 0x0},
+	654:  {region: 0x139, script: 0x5b, flags: 0x0},
+	655:  {region: 0x88, script: 0x5f, flags: 0x0},
+	656:  {region: 0x98, script: 0x3e, flags: 0x0},
+	657:  {region: 0x130, script: 0x5b, flags: 0x0},
+	658:  {region: 0xe9, script: 0x5, flags: 0x0},
+	659:  {region: 0x132, script: 0x5b, flags: 0x0},
+	660:  {region: 0x166, script: 0x5b, flags: 0x0},
+	661:  {region: 0xb8, script: 0x5b, flags: 0x0},
+	662:  {region: 0x107, script: 0x20, flags: 0x0},
+	663:  {region: 0x166, script: 0x5b, flags: 0x0},
+	664:  {region: 0x96, script: 0x5b, flags: 0x0},
+	665:  {region: 0x166, script: 0x5b, flags: 0x0},
+	666:  {region: 0x53, script: 0xee, flags: 0x0},
+	667:  {region: 0x166, script: 0x5b, flags: 0x0},
+	668:  {region: 0x166, script: 0x5b, flags: 0x0},
+	669:  {region: 0x166, script: 0x5b, flags: 0x0},
+	670:  {region: 0x166, script: 0x5b, flags: 0x0},
+	671:  {region: 0x9a, script: 0x5d, flags: 0x0},
+	672:  {region: 0x166, script: 0x5b, flags: 0x0},
+	673:  {region: 0x166, script: 0x5b, flags: 0x0},
+	674:  {region: 0x107, script: 0x20, flags: 0x0},
+	675:  {region: 0x132, script: 0x5b, flags: 0x0},
+	676:  {region: 0x166, script: 0x5b, flags: 0x0},
+	677:  {region: 0xda, script: 0x5b, flags: 0x0},
+	678:  {region: 0x166, script: 0x5b, flags: 0x0},
+	679:  {region: 0x166, script: 0x5b, flags: 0x0},
+	680:  {region: 0x21, script: 0x2, flags: 0x1},
+	681:  {region: 0x166, script: 0x5b, flags: 0x0},
+	682:  {region: 0x166, script: 0x5b, flags: 0x0},
+	683:  {region: 0x9f, script: 0x5b, flags: 0x0},
+	684:  {region: 0x53, script: 0x61, flags: 0x0},
+	685:  {region: 0x96, script: 0x5b, flags: 0x0},
+	686:  {region: 0x9d, script: 0x5, flags: 0x0},
+	687:  {region: 0x136, script: 0x5b, flags: 0x0},
+	688:  {region: 0x166, script: 0x5b, flags: 0x0},
+	689:  {region: 0x166, script: 0x5b, flags: 0x0},
+	690:  {region: 0x9a, script: 0xe9, flags: 0x0},
+	691:  {region: 0x9f, script: 0x5b, flags: 0x0},
+	692:  {region: 0x166, script: 0x5b, flags: 0x0},
+	693:  {region: 0x4b, script: 0x5b, flags: 0x0},
+	694:  {region: 0x166, script: 0x5b, flags: 0x0},
+	695:  {region: 0x166, script: 0x5b, flags: 0x0},
+	696:  {region: 0xb0, script: 0x58, flags: 0x0},
+	697:  {region: 0x166, script: 0x5b, flags: 0x0},
+	698:  {region: 0x166, script: 0x5b, flags: 0x0},
+	699:  {region: 0x4b, script: 0x5b, flags: 0x0},
+	700:  {region: 0x166, script: 0x5b, flags: 0x0},
+	701:  {region: 0x166, script: 0x5b, flags: 0x0},
+	702:  {region: 0x163, script: 0x5b, flags: 0x0},
+	703:  {region: 0x9d, script: 0x5, flags: 0x0},
+	704:  {region: 0xb7, script: 0x5b, flags: 0x0},
+	705:  {region: 0xb9, script: 0x5b, flags: 0x0},
+	706:  {region: 0x4b, script: 0x5b, flags: 0x0},
+	707:  {region: 0x4b, script: 0x5b, flags: 0x0},
+	708:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	709:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	710:  {region: 0x9d, script: 0x5, flags: 0x0},
+	711:  {region: 0xb9, script: 0x5b, flags: 0x0},
+	712:  {region: 0x124, script: 0xee, flags: 0x0},
+	713:  {region: 0x53, script: 0x3b, flags: 0x0},
+	714:  {region: 0x12c, script: 0x5b, flags: 0x0},
+	715:  {region: 0x96, script: 0x5b, flags: 0x0},
+	716:  {region: 0x52, script: 0x5b, flags: 0x0},
+	717:  {region: 0x9a, script: 0x22, flags: 0x0},
+	718:  {region: 0x9a, script: 0x22, flags: 0x0},
+	719:  {region: 0x96, script: 0x5b, flags: 0x0},
+	720:  {region: 0x23, script: 0x3, flags: 0x1},
+	721:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	722:  {region: 0x166, script: 0x5b, flags: 0x0},
+	723:  {region: 0xd0, script: 0x5b, flags: 0x0},
+	724:  {region: 0x166, script: 0x5b, flags: 0x0},
+	725:  {region: 0x166, script: 0x5b, flags: 0x0},
+	726:  {region: 0x166, script: 0x5b, flags: 0x0},
+	727:  {region: 0x166, script: 0x5b, flags: 0x0},
+	728:  {region: 0x166, script: 0x5b, flags: 0x0},
+	729:  {region: 0x166, script: 0x5b, flags: 0x0},
+	730:  {region: 0x166, script: 0x5b, flags: 0x0},
+	731:  {region: 0x166, script: 0x5b, flags: 0x0},
+	732:  {region: 0x166, script: 0x5b, flags: 0x0},
+	733:  {region: 0x166, script: 0x5b, flags: 0x0},
+	734:  {region: 0x166, script: 0x5b, flags: 0x0},
+	735:  {region: 0x166, script: 0x5, flags: 0x0},
+	736:  {region: 0x107, script: 0x20, flags: 0x0},
+	737:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	738:  {region: 0x166, script: 0x5b, flags: 0x0},
+	739:  {region: 0x96, script: 0x5b, flags: 0x0},
+	740:  {region: 0x166, script: 0x2c, flags: 0x0},
+	741:  {region: 0x166, script: 0x5b, flags: 0x0},
+	742:  {region: 0x166, script: 0x5b, flags: 0x0},
+	743:  {region: 0x166, script: 0x5b, flags: 0x0},
+	744:  {region: 0x113, script: 0x5b, flags: 0x0},
+	745:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	746:  {region: 0x166, script: 0x5b, flags: 0x0},
+	747:  {region: 0x166, script: 0x5b, flags: 0x0},
+	748:  {region: 0x124, script: 0x5, flags: 0x0},
+	749:  {region: 0xcd, script: 0x5b, flags: 0x0},
+	750:  {region: 0x166, script: 0x5b, flags: 0x0},
+	751:  {region: 0x166, script: 0x5b, flags: 0x0},
+	752:  {region: 0x166, script: 0x5b, flags: 0x0},
+	753:  {region: 0xc0, script: 0x5b, flags: 0x0},
+	754:  {region: 0xd2, script: 0x5b, flags: 0x0},
+	755:  {region: 0x166, script: 0x5b, flags: 0x0},
+	756:  {region: 0x52, script: 0x5b, flags: 0x0},
+	757:  {region: 0xdc, script: 0x22, flags: 0x0},
+	758:  {region: 0x130, script: 0x5b, flags: 0x0},
+	759:  {region: 0xc1, script: 0x5b, flags: 0x0},
+	760:  {region: 0x166, script: 0x5b, flags: 0x0},
+	761:  {region: 0x166, script: 0x5b, flags: 0x0},
+	762:  {region: 0xe1, script: 0x5b, flags: 0x0},
+	763:  {region: 0x166, script: 0x5b, flags: 0x0},
+	764:  {region: 0x96, script: 0x5b, flags: 0x0},
+	765:  {region: 0x9c, script: 0x3d, flags: 0x0},
+	766:  {region: 0x166, script: 0x5b, flags: 0x0},
+	767:  {region: 0xc3, script: 0x20, flags: 0x0},
+	768:  {region: 0x166, script: 0x5, flags: 0x0},
+	769:  {region: 0x166, script: 0x5b, flags: 0x0},
+	770:  {region: 0x166, script: 0x5b, flags: 0x0},
+	771:  {region: 0x166, script: 0x5b, flags: 0x0},
+	772:  {region: 0x9a, script: 0x6f, flags: 0x0},
+	773:  {region: 0x166, script: 0x5b, flags: 0x0},
+	774:  {region: 0x166, script: 0x5b, flags: 0x0},
+	775:  {region: 0x10c, script: 0x5b, flags: 0x0},
+	776:  {region: 0x166, script: 0x5b, flags: 0x0},
+	777:  {region: 0x166, script: 0x5b, flags: 0x0},
+	778:  {region: 0x166, script: 0x5b, flags: 0x0},
+	779:  {region: 0x26, script: 0x3, flags: 0x1},
+	780:  {region: 0x166, script: 0x5b, flags: 0x0},
+	781:  {region: 0x166, script: 0x5b, flags: 0x0},
+	782:  {region: 0x9a, script: 0xe, flags: 0x0},
+	783:  {region: 0xc5, script: 0x76, flags: 0x0},
+	785:  {region: 0x166, script: 0x5b, flags: 0x0},
+	786:  {region: 0x49, script: 0x5b, flags: 0x0},
+	787:  {region: 0x49, script: 0x5b, flags: 0x0},
+	788:  {region: 0x37, script: 0x5b, flags: 0x0},
+	789:  {region: 0x166, script: 0x5b, flags: 0x0},
+	790:  {region: 0x166, script: 0x5b, flags: 0x0},
+	791:  {region: 0x166, script: 0x5b, flags: 0x0},
+	792:  {region: 0x166, script: 0x5b, flags: 0x0},
+	793:  {region: 0x166, script: 0x5b, flags: 0x0},
+	794:  {region: 0x166, script: 0x5b, flags: 0x0},
+	795:  {region: 0x9a, script: 0x22, flags: 0x0},
+	796:  {region: 0xdc, script: 0x22, flags: 0x0},
+	797:  {region: 0x107, script: 0x20, flags: 0x0},
+	798:  {region: 0x35, script: 0x73, flags: 0x0},
+	799:  {region: 0x29, script: 0x3, flags: 0x1},
+	800:  {region: 0xcc, script: 0x5b, flags: 0x0},
+	801:  {region: 0x166, script: 0x5b, flags: 0x0},
+	802:  {region: 0x166, script: 0x5b, flags: 0x0},
+	803:  {region: 0x166, script: 0x5b, flags: 0x0},
+	804:  {region: 0x9a, script: 0x22, flags: 0x0},
+	805:  {region: 0x52, script: 0x5b, flags: 0x0},
+	807:  {region: 0x166, script: 0x5b, flags: 0x0},
+	808:  {region: 0x136, script: 0x5b, flags: 0x0},
+	809:  {region: 0x166, script: 0x5b, flags: 0x0},
+	810:  {region: 0x166, script: 0x5b, flags: 0x0},
+	811:  {region: 0xe9, script: 0x5, flags: 0x0},
+	812:  {region: 0xc4, script: 0x5b, flags: 0x0},
+	813:  {region: 0x9a, script: 0x22, flags: 0x0},
+	814:  {region: 0x96, script: 0x5b, flags: 0x0},
+	815:  {region: 0x165, script: 0x5b, flags: 0x0},
+	816:  {region: 0x166, script: 0x5b, flags: 0x0},
+	817:  {region: 0xc5, script: 0x76, flags: 0x0},
+	818:  {region: 0x166, script: 0x5b, flags: 0x0},
+	819:  {region: 0x166, script: 0x2c, flags: 0x0},
+	820:  {region: 0x107, script: 0x20, flags: 0x0},
+	821:  {region: 0x166, script: 0x5b, flags: 0x0},
+	822:  {region: 0x132, script: 0x5b, flags: 0x0},
+	823:  {region: 0x9d, script: 0x67, flags: 0x0},
+	824:  {region: 0x166, script: 0x5b, flags: 0x0},
+	825:  {region: 0x166, script: 0x5b, flags: 0x0},
+	826:  {region: 0x9d, script: 0x5, flags: 0x0},
+	827:  {region: 0x166, script: 0x5b, flags: 0x0},
+	828:  {region: 0x166, script: 0x5b, flags: 0x0},
+	829:  {region: 0x166, script: 0x5b, flags: 0x0},
+	830:  {region: 0xde, script: 0x5b, flags: 0x0},
+	831:  {region: 0x166, script: 0x5b, flags: 0x0},
+	832:  {region: 0x166, script: 0x5b, flags: 0x0},
+	834:  {region: 0x166, script: 0x5b, flags: 0x0},
+	835:  {region: 0x53, script: 0x3b, flags: 0x0},
+	836:  {region: 0x9f, script: 0x5b, flags: 0x0},
+	837:  {region: 0xd3, script: 0x5b, flags: 0x0},
+	838:  {region: 0x166, script: 0x5b, flags: 0x0},
+	839:  {region: 0xdb, script: 0x5b, flags: 0x0},
+	840:  {region: 0x166, script: 0x5b, flags: 0x0},
+	841:  {region: 0x166, script: 0x5b, flags: 0x0},
+	842:  {region: 0x166, script: 0x5b, flags: 0x0},
+	843:  {region: 0xd0, script: 0x5b, flags: 0x0},
+	844:  {region: 0x166, script: 0x5b, flags: 0x0},
+	845:  {region: 0x166, script: 0x5b, flags: 0x0},
+	846:  {region: 0x165, script: 0x5b, flags: 0x0},
+	847:  {region: 0xd2, script: 0x5b, flags: 0x0},
+	848:  {region: 0x61, script: 0x5b, flags: 0x0},
+	849:  {region: 0xdc, script: 0x22, flags: 0x0},
+	850:  {region: 0x166, script: 0x5b, flags: 0x0},
+	851:  {region: 0xdc, script: 0x22, flags: 0x0},
+	852:  {region: 0x166, script: 0x5b, flags: 0x0},
+	853:  {region: 0x166, script: 0x5b, flags: 0x0},
+	854:  {region: 0xd3, script: 0x5b, flags: 0x0},
+	855:  {region: 0x166, script: 0x5b, flags: 0x0},
+	856:  {region: 0x166, script: 0x5b, flags: 0x0},
+	857:  {region: 0xd2, script: 0x5b, flags: 0x0},
+	858:  {region: 0x166, script: 0x5b, flags: 0x0},
+	859:  {region: 0xd0, script: 0x5b, flags: 0x0},
+	860:  {region: 0xd0, script: 0x5b, flags: 0x0},
+	861:  {region: 0x166, script: 0x5b, flags: 0x0},
+	862:  {region: 0x166, script: 0x5b, flags: 0x0},
+	863:  {region: 0x96, script: 0x5b, flags: 0x0},
+	864:  {region: 0x166, script: 0x5b, flags: 0x0},
+	865:  {region: 0xe0, script: 0x5b, flags: 0x0},
+	866:  {region: 0x166, script: 0x5b, flags: 0x0},
+	867:  {region: 0x166, script: 0x5b, flags: 0x0},
+	868:  {region: 0x9a, script: 0x5b, flags: 0x0},
+	869:  {region: 0x166, script: 0x5b, flags: 0x0},
+	870:  {region: 0x166, script: 0x5b, flags: 0x0},
+	871:  {region: 0xda, script: 0x5b, flags: 0x0},
+	872:  {region: 0x52, script: 0x5b, flags: 0x0},
+	873:  {region: 0x166, script: 0x5b, flags: 0x0},
+	874:  {region: 0xdb, script: 0x5b, flags: 0x0},
+	875:  {region: 0x166, script: 0x5b, flags: 0x0},
+	876:  {region: 0x52, script: 0x5b, flags: 0x0},
+	877:  {region: 0x166, script: 0x5b, flags: 0x0},
+	878:  {region: 0x166, script: 0x5b, flags: 0x0},
+	879:  {region: 0xdb, script: 0x5b, flags: 0x0},
+	880:  {region: 0x124, script: 0x57, flags: 0x0},
+	881:  {region: 0x9a, script: 0x22, flags: 0x0},
+	882:  {region: 0x10d, script: 0xcb, flags: 0x0},
+	883:  {region: 0x166, script: 0x5b, flags: 0x0},
+	884:  {region: 0x166, script: 0x5b, flags: 0x0},
+	885:  {region: 0x85, script: 0x7e, flags: 0x0},
+	886:  {region: 0x162, script: 0x5b, flags: 0x0},
+	887:  {region: 0x166, script: 0x5b, flags: 0x0},
+	888:  {region: 0x49, script: 0x17, flags: 0x0},
+	889:  {region: 0x166, script: 0x5b, flags: 0x0},
+	890:  {region: 0x162, script: 0x5b, flags: 0x0},
+	891:  {region: 0x166, script: 0x5b, flags: 0x0},
+	892:  {region: 0x166, script: 0x5b, flags: 0x0},
+	893:  {region: 0x166, script: 0x5b, flags: 0x0},
+	894:  {region: 0x166, script: 0x5b, flags: 0x0},
+	895:  {region: 0x166, script: 0x5b, flags: 0x0},
+	896:  {region: 0x118, script: 0x5b, flags: 0x0},
+	897:  {region: 0x166, script: 0x5b, flags: 0x0},
+	898:  {region: 0x166, script: 0x5b, flags: 0x0},
+	899:  {region: 0x136, script: 0x5b, flags: 0x0},
+	900:  {region: 0x166, script: 0x5b, flags: 0x0},
+	901:  {region: 0x53, script: 0x5b, flags: 0x0},
+	902:  {region: 0x166, script: 0x5b, flags: 0x0},
+	903:  {region: 0xcf, script: 0x5b, flags: 0x0},
+	904:  {region: 0x130, script: 0x5b, flags: 0x0},
+	905:  {region: 0x132, script: 0x5b, flags: 0x0},
+	906:  {region: 0x81, script: 0x5b, flags: 0x0},
+	907:  {region: 0x79, script: 0x5b, flags: 0x0},
+	908:  {region: 0x166, script: 0x5b, flags: 0x0},
+	910:  {region: 0x166, script: 0x5b, flags: 0x0},
+	911:  {region: 0x166, script: 0x5b, flags: 0x0},
+	912:  {region: 0x70, script: 0x5b, flags: 0x0},
+	913:  {region: 0x166, script: 0x5b, flags: 0x0},
+	914:  {region: 0x166, script: 0x5b, flags: 0x0},
+	915:  {region: 0x166, script: 0x5b, flags: 0x0},
+	916:  {region: 0x166, script: 0x5b, flags: 0x0},
+	917:  {region: 0x9a, script: 0x83, flags: 0x0},
+	918:  {region: 0x166, script: 0x5b, flags: 0x0},
+	919:  {region: 0x166, script: 0x5, flags: 0x0},
+	920:  {region: 0x7e, script: 0x20, flags: 0x0},
+	921:  {region: 0x136, script: 0x84, flags: 0x0},
+	922:  {region: 0x166, script: 0x5, flags: 0x0},
+	923:  {region: 0xc6, script: 0x82, flags: 0x0},
+	924:  {region: 0x166, script: 0x5b, flags: 0x0},
+	925:  {region: 0x2c, script: 0x3, flags: 0x1},
+	926:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	927:  {region: 0x2f, script: 0x2, flags: 0x1},
+	928:  {region: 0xe8, script: 0x5b, flags: 0x0},
+	929:  {region: 0x30, script: 0x5b, flags: 0x0},
+	930:  {region: 0xf1, script: 0x5b, flags: 0x0},
+	931:  {region: 0x166, script: 0x5b, flags: 0x0},
+	932:  {region: 0x79, script: 0x5b, flags: 0x0},
+	933:  {region: 0xd7, script: 0x5b, flags: 0x0},
+	934:  {region: 0x136, script: 0x5b, flags: 0x0},
+	935:  {region: 0x49, script: 0x5b, flags: 0x0},
+	936:  {region: 0x166, script: 0x5b, flags: 0x0},
+	937:  {region: 0x9d, script: 0xfa, flags: 0x0},
+	938:  {region: 0x166, script: 0x5b, flags: 0x0},
+	939:  {region: 0x61, script: 0x5b, flags: 0x0},
+	940:  {region: 0x166, script: 0x5, flags: 0x0},
+	941:  {region: 0xb1, script: 0x90, flags: 0x0},
+	943:  {region: 0x166, script: 0x5b, flags: 0x0},
+	944:  {region: 0x166, script: 0x5b, flags: 0x0},
+	945:  {region: 0x9a, script: 0x12, flags: 0x0},
+	946:  {region: 0xa5, script: 0x5b, flags: 0x0},
+	947:  {region: 0xea, script: 0x5b, flags: 0x0},
+	948:  {region: 0x166, script: 0x5b, flags: 0x0},
+	949:  {region: 0x9f, script: 0x5b, flags: 0x0},
+	950:  {region: 0x166, script: 0x5b, flags: 0x0},
+	951:  {region: 0x166, script: 0x5b, flags: 0x0},
+	952:  {region: 0x88, script: 0x34, flags: 0x0},
+	953:  {region: 0x76, script: 0x5b, flags: 0x0},
+	954:  {region: 0x166, script: 0x5b, flags: 0x0},
+	955:  {region: 0xe9, script: 0x4e, flags: 0x0},
+	956:  {region: 0x9d, script: 0x5, flags: 0x0},
+	957:  {region: 0x1, script: 0x5b, flags: 0x0},
+	958:  {region: 0x24, script: 0x5, flags: 0x0},
+	959:  {region: 0x166, script: 0x5b, flags: 0x0},
+	960:  {region: 0x41, script: 0x5b, flags: 0x0},
+	961:  {region: 0x166, script: 0x5b, flags: 0x0},
+	962:  {region: 0x7b, script: 0x5b, flags: 0x0},
+	963:  {region: 0x166, script: 0x5b, flags: 0x0},
+	964:  {region: 0xe5, script: 0x5b, flags: 0x0},
+	965:  {region: 0x8a, script: 0x5b, flags: 0x0},
+	966:  {region: 0x6a, script: 0x5b, flags: 0x0},
+	967:  {region: 0x166, script: 0x5b, flags: 0x0},
+	968:  {region: 0x9a, script: 0x22, flags: 0x0},
+	969:  {region: 0x166, script: 0x5b, flags: 0x0},
+	970:  {region: 0x103, script: 0x5b, flags: 0x0},
+	971:  {region: 0x96, script: 0x5b, flags: 0x0},
+	972:  {region: 0x166, script: 0x5b, flags: 0x0},
+	973:  {region: 0x166, script: 0x5b, flags: 0x0},
+	974:  {region: 0x9f, script: 0x5b, flags: 0x0},
+	975:  {region: 0x166, script: 0x5, flags: 0x0},
+	976:  {region: 0x9a, script: 0x5b, flags: 0x0},
+	977:  {region: 0x31, script: 0x2, flags: 0x1},
+	978:  {region: 0xdc, script: 0x22, flags: 0x0},
+	979:  {region: 0x35, script: 0xe, flags: 0x0},
+	980:  {region: 0x4e, script: 0x5b, flags: 0x0},
+	981:  {region: 0x73, script: 0x5b, flags: 0x0},
+	982:  {region: 0x4e, script: 0x5b, flags: 0x0},
+	983:  {region: 0x9d, script: 0x5, flags: 0x0},
+	984:  {region: 0x10d, script: 0x5b, flags: 0x0},
+	985:  {region: 0x3a, script: 0x5b, flags: 0x0},
+	986:  {region: 0x166, script: 0x5b, flags: 0x0},
+	987:  {region: 0xd2, script: 0x5b, flags: 0x0},
+	988:  {region: 0x105, script: 0x5b, flags: 0x0},
+	989:  {region: 0x96, script: 0x5b, flags: 0x0},
+	990:  {region: 0x130, script: 0x5b, flags: 0x0},
+	991:  {region: 0x166, script: 0x5b, flags: 0x0},
+	992:  {region: 0x166, script: 0x5b, flags: 0x0},
+	993:  {region: 0x74, script: 0x5b, flags: 0x0},
+	994:  {region: 0x107, script: 0x20, flags: 0x0},
+	995:  {region: 0x131, script: 0x20, flags: 0x0},
+	996:  {region: 0x10a, script: 0x5b, flags: 0x0},
+	997:  {region: 0x108, script: 0x5b, flags: 0x0},
+	998:  {region: 0x130, script: 0x5b, flags: 0x0},
+	999:  {region: 0x166, script: 0x5b, flags: 0x0},
+	1000: {region: 0xa3, script: 0x4c, flags: 0x0},
+	1001: {region: 0x9a, script: 0x22, flags: 0x0},
+	1002: {region: 0x81, script: 0x5b, flags: 0x0},
+	1003: {region: 0x107, script: 0x20, flags: 0x0},
+	1004: {region: 0xa5, script: 0x5b, flags: 0x0},
+	1005: {region: 0x96, script: 0x5b, flags: 0x0},
+	1006: {region: 0x9a, script: 0x5b, flags: 0x0},
+	1007: {region: 0x115, script: 0x5b, flags: 0x0},
+	1008: {region: 0x9a, script: 0xcf, flags: 0x0},
+	1009: {region: 0x166, script: 0x5b, flags: 0x0},
+	1010: {region: 0x166, script: 0x5b, flags: 0x0},
+	1011: {region: 0x130, script: 0x5b, flags: 0x0},
+	1012: {region: 0x9f, script: 0x5b, flags: 0x0},
+	1013: {region: 0x9a, script: 0x22, flags: 0x0},
+	1014: {region: 0x166, script: 0x5, flags: 0x0},
+	1015: {region: 0x9f, script: 0x5b, flags: 0x0},
+	1016: {region: 0x7c, script: 0x5b, flags: 0x0},
+	1017: {region: 0x49, script: 0x5b, flags: 0x0},
+	1018: {region: 0x33, script: 0x4, flags: 0x1},
+	1019: {region: 0x9f, script: 0x5b, flags: 0x0},
+	1020: {region: 0x9d, script: 0x5, flags: 0x0},
+	1021: {region: 0xdb, script: 0x5b, flags: 0x0},
+	1022: {region: 0x4f, script: 0x5b, flags: 0x0},
+	1023: {region: 0xd2, script: 0x5b, flags: 0x0},
+	1024: {region: 0xd0, script: 0x5b, flags: 0x0},
+	1025: {region: 0xc4, script: 0x5b, flags: 0x0},
+	1026: {region: 0x4c, script: 0x5b, flags: 0x0},
+	1027: {region: 0x97, script: 0x80, flags: 0x0},
+	1028: {region: 0xb7, script: 0x5b, flags: 0x0},
+	1029: {region: 0x166, script: 0x2c, flags: 0x0},
+	1030: {region: 0x166, script: 0x5b, flags: 0x0},
+	1032: {region: 0xbb, script: 0xeb, flags: 0x0},
+	1033: {region: 0x166, script: 0x5b, flags: 0x0},
+	1034: {region: 0xc5, script: 0x76, flags: 0x0},
+	1035: {region: 0x166, script: 0x5, flags: 0x0},
+	1036: {region: 0xb4, script: 0xd6, flags: 0x0},
+	1037: {region: 0x70, script: 0x5b, flags: 0x0},
+	1038: {region: 0x166, script: 0x5b, flags: 0x0},
+	1039: {region: 0x166, script: 0x5b, flags: 0x0},
+	1040: {region: 0x166, script: 0x5b, flags: 0x0},
+	1041: {region: 0x166, script: 0x5b, flags: 0x0},
+	1042: {region: 0x112, script: 0x5b, flags: 0x0},
+	1043: {region: 0x166, script: 0x5b, flags: 0x0},
+	1044: {region: 0xe9, script: 0x5, flags: 0x0},
+	1045: {region: 0x166, script: 0x5b, flags: 0x0},
+	1046: {region: 0x110, script: 0x5b, flags: 0x0},
+	1047: {region: 0x166, script: 0x5b, flags: 0x0},
+	1048: {region: 0xea, script: 0x5b, flags: 0x0},
+	1049: {region: 0x166, script: 0x5b, flags: 0x0},
+	1050: {region: 0x96, script: 0x5b, flags: 0x0},
+	1051: {region: 0x143, script: 0x5b, flags: 0x0},
+	1052: {region: 0x10d, script: 0x5b, flags: 0x0},
+	1054: {region: 0x10d, script: 0x5b, flags: 0x0},
+	1055: {region: 0x73, script: 0x5b, flags: 0x0},
+	1056: {region: 0x98, script: 0xcc, flags: 0x0},
+	1057: {region: 0x166, script: 0x5b, flags: 0x0},
+	1058: {region: 0x73, script: 0x5b, flags: 0x0},
+	1059: {region: 0x165, script: 0x5b, flags: 0x0},
+	1060: {region: 0x166, script: 0x5b, flags: 0x0},
+	1061: {region: 0xc4, script: 0x5b, flags: 0x0},
+	1062: {region: 0x166, script: 0x5b, flags: 0x0},
+	1063: {region: 0x166, script: 0x5b, flags: 0x0},
+	1064: {region: 0x166, script: 0x5b, flags: 0x0},
+	1065: {region: 0x116, script: 0x5b, flags: 0x0},
+	1066: {region: 0x166, script: 0x5b, flags: 0x0},
+	1067: {region: 0x166, script: 0x5b, flags: 0x0},
+	1068: {region: 0x124, script: 0xee, flags: 0x0},
+	1069: {region: 0x166, script: 0x5b, flags: 0x0},
+	1070: {region: 0x166, script: 0x5b, flags: 0x0},
+	1071: {region: 0x166, script: 0x5b, flags: 0x0},
+	1072: {region: 0x166, script: 0x5b, flags: 0x0},
+	1073: {region: 0x27, script: 0x5b, flags: 0x0},
+	1074: {region: 0x37, script: 0x5, flags: 0x1},
+	1075: {region: 0x9a, script: 0xd9, flags: 0x0},
+	1076: {region: 0x117, script: 0x5b, flags: 0x0},
+	1077: {region: 0x115, script: 0x5b, flags: 0x0},
+	1078: {region: 0x9a, script: 0x22, flags: 0x0},
+	1079: {region: 0x162, script: 0x5b, flags: 0x0},
+	1080: {region: 0x166, script: 0x5b, flags: 0x0},
+	1081: {region: 0x166, script: 0x5b, flags: 0x0},
+	1082: {region: 0x6e, script: 0x5b, flags: 0x0},
+	1083: {region: 0x162, script: 0x5b, flags: 0x0},
+	1084: {region: 0x166, script: 0x5b, flags: 0x0},
+	1085: {region: 0x61, script: 0x5b, flags: 0x0},
+	1086: {region: 0x96, script: 0x5b, flags: 0x0},
+	1087: {region: 0x166, script: 0x5b, flags: 0x0},
+	1088: {region: 0x166, script: 0x5b, flags: 0x0},
+	1089: {region: 0x130, script: 0x5b, flags: 0x0},
+	1090: {region: 0x166, script: 0x5b, flags: 0x0},
+	1091: {region: 0x85, script: 0x5b, flags: 0x0},
+	1092: {region: 0x10d, script: 0x5b, flags: 0x0},
+	1093: {region: 0x130, script: 0x5b, flags: 0x0},
+	1094: {region: 0x160, script: 0x5, flags: 0x0},
+	1095: {region: 0x4b, script: 0x5b, flags: 0x0},
+	1096: {region: 0x61, script: 0x5b, flags: 0x0},
+	1097: {region: 0x166, script: 0x5b, flags: 0x0},
+	1098: {region: 0x9a, script: 0x22, flags: 0x0},
+	1099: {region: 0x96, script: 0x5b, flags: 0x0},
+	1100: {region: 0x166, script: 0x5b, flags: 0x0},
+	1101: {region: 0x35, script: 0xe, flags: 0x0},
+	1102: {region: 0x9c, script: 0xde, flags: 0x0},
+	1103: {region: 0xea, script: 0x5b, flags: 0x0},
+	1104: {region: 0x9a, script: 0xe6, flags: 0x0},
+	1105: {region: 0xdc, script: 0x22, flags: 0x0},
+	1106: {region: 0x166, script: 0x5b, flags: 0x0},
+	1107: {region: 0x166, script: 0x5b, flags: 0x0},
+	1108: {region: 0x166, script: 0x5b, flags: 0x0},
+	1109: {region: 0x166, script: 0x5b, flags: 0x0},
+	1110: {region: 0x166, script: 0x5b, flags: 0x0},
+	1111: {region: 0x166, script: 0x5b, flags: 0x0},
+	1112: {region: 0x166, script: 0x5b, flags: 0x0},
+	1113: {region: 0x166, script: 0x5b, flags: 0x0},
+	1114: {region: 0xe8, script: 0x5b, flags: 0x0},
+	1115: {region: 0x166, script: 0x5b, flags: 0x0},
+	1116: {region: 0x166, script: 0x5b, flags: 0x0},
+	1117: {region: 0x9a, script: 0x53, flags: 0x0},
+	1118: {region: 0x53, script: 0xe4, flags: 0x0},
+	1119: {region: 0xdc, script: 0x22, flags: 0x0},
+	1120: {region: 0xdc, script: 0x22, flags: 0x0},
+	1121: {region: 0x9a, script: 0xe9, flags: 0x0},
+	1122: {region: 0x166, script: 0x5b, flags: 0x0},
+	1123: {region: 0x113, script: 0x5b, flags: 0x0},
+	1124: {region: 0x132, script: 0x5b, flags: 0x0},
+	1125: {region: 0x127, script: 0x5b, flags: 0x0},
+	1126: {region: 0x166, script: 0x5b, flags: 0x0},
+	1127: {region: 0x3c, script: 0x3, flags: 0x1},
+	1128: {region: 0x166, script: 0x5b, flags: 0x0},
+	1129: {region: 0x166, script: 0x5b, flags: 0x0},
+	1130: {region: 0x166, script: 0x5b, flags: 0x0},
+	1131: {region: 0x124, script: 0xee, flags: 0x0},
+	1132: {region: 0xdc, script: 0x22, flags: 0x0},
+	1133: {region: 0xdc, script: 0x22, flags: 0x0},
+	1134: {region: 0xdc, script: 0x22, flags: 0x0},
+	1135: {region: 0x70, script: 0x2c, flags: 0x0},
+	1136: {region: 0x166, script: 0x5b, flags: 0x0},
+	1137: {region: 0x6e, script: 0x2c, flags: 0x0},
+	1138: {region: 0x166, script: 0x5b, flags: 0x0},
+	1139: {region: 0x166, script: 0x5b, flags: 0x0},
+	1140: {region: 0x166, script: 0x5b, flags: 0x0},
+	1141: {region: 0xd7, script: 0x5b, flags: 0x0},
+	1142: {region: 0x128, script: 0x5b, flags: 0x0},
+	1143: {region: 0x126, script: 0x5b, flags: 0x0},
+	1144: {region: 0x32, script: 0x5b, flags: 0x0},
+	1145: {region: 0xdc, script: 0x22, flags: 0x0},
+	1146: {region: 0xe8, script: 0x5b, flags: 0x0},
+	1147: {region: 0x166, script: 0x5b, flags: 0x0},
+	1148: {region: 0x166, script: 0x5b, flags: 0x0},
+	1149: {region: 0x32, script: 0x5b, flags: 0x0},
+	1150: {region: 0xd5, script: 0x5b, flags: 0x0},
+	1151: {region: 0x166, script: 0x5b, flags: 0x0},
+	1152: {region: 0x162, script: 0x5b, flags: 0x0},
+	1153: {region: 0x166, script: 0x5b, flags: 0x0},
+	1154: {region: 0x12a, script: 0x5b, flags: 0x0},
+	1155: {region: 0x166, script: 0x5b, flags: 0x0},
+	1156: {region: 0xcf, script: 0x5b, flags: 0x0},
+	1157: {region: 0x166, script: 0x5b, flags: 0x0},
+	1158: {region: 0xe7, script: 0x5b, flags: 0x0},
+	1159: {region: 0x166, script: 0x5b, flags: 0x0},
+	1160: {region: 0x166, script: 0x5b, flags: 0x0},
+	1161: {region: 0x166, script: 0x5b, flags: 0x0},
+	1162: {region: 0x12c, script: 0x5b, flags: 0x0},
+	1163: {region: 0x12c, script: 0x5b, flags: 0x0},
+	1164: {region: 0x12f, script: 0x5b, flags: 0x0},
+	1165: {region: 0x166, script: 0x5, flags: 0x0},
+	1166: {region: 0x162, script: 0x5b, flags: 0x0},
+	1167: {region: 0x88, script: 0x34, flags: 0x0},
+	1168: {region: 0xdc, script: 0x22, flags: 0x0},
+	1169: {region: 0xe8, script: 0x5b, flags: 0x0},
+	1170: {region: 0x43, script: 0xef, flags: 0x0},
+	1171: {region: 0x166, script: 0x5b, flags: 0x0},
+	1172: {region: 0x107, script: 0x20, flags: 0x0},
+	1173: {region: 0x166, script: 0x5b, flags: 0x0},
+	1174: {region: 0x166, script: 0x5b, flags: 0x0},
+	1175: {region: 0x132, script: 0x5b, flags: 0x0},
+	1176: {region: 0x166, script: 0x5b, flags: 0x0},
+	1177: {region: 0x124, script: 0xee, flags: 0x0},
+	1178: {region: 0x32, script: 0x5b, flags: 0x0},
+	1179: {region: 0x166, script: 0x5b, flags: 0x0},
+	1180: {region: 0x166, script: 0x5b, flags: 0x0},
+	1181: {region: 0xcf, script: 0x5b, flags: 0x0},
+	1182: {region: 0x166, script: 0x5b, flags: 0x0},
+	1183: {region: 0x166, script: 0x5b, flags: 0x0},
+	1184: {region: 0x12e, script: 0x5b, flags: 0x0},
+	1185: {region: 0x166, script: 0x5b, flags: 0x0},
+	1187: {region: 0x166, script: 0x5b, flags: 0x0},
+	1188: {region: 0xd5, script: 0x5b, flags: 0x0},
+	1189: {region: 0x53, script: 0xe7, flags: 0x0},
+	1190: {region: 0xe6, script: 0x5b, flags: 0x0},
+	1191: {region: 0x166, script: 0x5b, flags: 0x0},
+	1192: {region: 0x107, script: 0x20, flags: 0x0},
+	1193: {region: 0xbb, script: 0x5b, flags: 0x0},
+	1194: {region: 0x166, script: 0x5b, flags: 0x0},
+	1195: {region: 0x107, script: 0x20, flags: 0x0},
+	1196: {region: 0x3f, script: 0x4, flags: 0x1},
+	1197: {region: 0x11d, script: 0xf3, flags: 0x0},
+	1198: {region: 0x131, script: 0x20, flags: 0x0},
+	1199: {region: 0x76, script: 0x5b, flags: 0x0},
+	1200: {region: 0x2a, script: 0x5b, flags: 0x0},
+	1202: {region: 0x43, script: 0x3, flags: 0x1},
+	1203: {region: 0x9a, script: 0xe, flags: 0x0},
+	1204: {region: 0xe9, script: 0x5, flags: 0x0},
+	1205: {region: 0x166, script: 0x5b, flags: 0x0},
+	1206: {region: 0x166, script: 0x5b, flags: 0x0},
+	1207: {region: 0x166, script: 0x5b, flags: 0x0},
+	1208: {region: 0x166, script: 0x5b, flags: 0x0},
+	1209: {region: 0x166, script: 0x5b, flags: 0x0},
+	1210: {region: 0x166, script: 0x5b, flags: 0x0},
+	1211: {region: 0x166, script: 0x5b, flags: 0x0},
+	1212: {region: 0x46, script: 0x4, flags: 0x1},
+	1213: {region: 0x166, script: 0x5b, flags: 0x0},
+	1214: {region: 0xb5, script: 0xf4, flags: 0x0},
+	1215: {region: 0x166, script: 0x5b, flags: 0x0},
+	1216: {region: 0x162, script: 0x5b, flags: 0x0},
+	1217: {region: 0x9f, script: 0x5b, flags: 0x0},
+	1218: {region: 0x107, script: 0x5b, flags: 0x0},
+	1219: {region: 0x13f, script: 0x5b, flags: 0x0},
+	1220: {region: 0x11c, script: 0x5b, flags: 0x0},
+	1221: {region: 0x166, script: 0x5b, flags: 0x0},
+	1222: {region: 0x36, script: 0x5b, flags: 0x0},
+	1223: {region: 0x61, script: 0x5b, flags: 0x0},
+	1224: {region: 0xd2, script: 0x5b, flags: 0x0},
+	1225: {region: 0x1, script: 0x5b, flags: 0x0},
+	1226: {region: 0x107, script: 0x5b, flags: 0x0},
+	1227: {region: 0x6b, script: 0x5b, flags: 0x0},
+	1228: {region: 0x130, script: 0x5b, flags: 0x0},
+	1229: {region: 0x166, script: 0x5b, flags: 0x0},
+	1230: {region: 0x36, script: 0x5b, flags: 0x0},
+	1231: {region: 0x4e, script: 0x5b, flags: 0x0},
+	1232: {region: 0x166, script: 0x5b, flags: 0x0},
+	1233: {region: 0x70, script: 0x2c, flags: 0x0},
+	1234: {region: 0x166, script: 0x5b, flags: 0x0},
+	1235: {region: 0xe8, script: 0x5b, flags: 0x0},
+	1236: {region: 0x2f, script: 0x5b, flags: 0x0},
+	1237: {region: 0x9a, script: 0xe9, flags: 0x0},
+	1238: {region: 0x9a, script: 0x22, flags: 0x0},
+	1239: {region: 0x166, script: 0x5b, flags: 0x0},
+	1240: {region: 0x166, script: 0x5b, flags: 0x0},
+	1241: {region: 0x166, script: 0x5b, flags: 0x0},
+	1242: {region: 0x166, script: 0x5b, flags: 0x0},
+	1243: {region: 0x166, script: 0x5b, flags: 0x0},
+	1244: {region: 0x166, script: 0x5b, flags: 0x0},
+	1245: {region: 0x166, script: 0x5b, flags: 0x0},
+	1246: {region: 0x166, script: 0x5b, flags: 0x0},
+	1247: {region: 0x166, script: 0x5b, flags: 0x0},
+	1248: {region: 0x141, script: 0x5b, flags: 0x0},
+	1249: {region: 0x166, script: 0x5b, flags: 0x0},
+	1250: {region: 0x166, script: 0x5b, flags: 0x0},
+	1251: {region: 0xa9, script: 0x5, flags: 0x0},
+	1252: {region: 0x166, script: 0x5b, flags: 0x0},
+	1253: {region: 0x115, script: 0x5b, flags: 0x0},
+	1254: {region: 0x166, script: 0x5b, flags: 0x0},
+	1255: {region: 0x166, script: 0x5b, flags: 0x0},
+	1256: {region: 0x166, script: 0x5b, flags: 0x0},
+	1257: {region: 0x166, script: 0x5b, flags: 0x0},
+	1258: {region: 0x9a, script: 0x22, flags: 0x0},
+	1259: {region: 0x53, script: 0x3b, flags: 0x0},
+	1260: {region: 0x166, script: 0x5b, flags: 0x0},
+	1261: {region: 0x166, script: 0x5b, flags: 0x0},
+	1262: {region: 0x41, script: 0x5b, flags: 0x0},
+	1263: {region: 0x166, script: 0x5b, flags: 0x0},
+	1264: {region: 0x12c, script: 0x18, flags: 0x0},
+	1265: {region: 0x166, script: 0x5b, flags: 0x0},
+	1266: {region: 0x162, script: 0x5b, flags: 0x0},
+	1267: {region: 0x166, script: 0x5b, flags: 0x0},
+	1268: {region: 0x12c, script: 0x63, flags: 0x0},
+	1269: {region: 0x12c, script: 0x64, flags: 0x0},
+	1270: {region: 0x7e, script: 0x2e, flags: 0x0},
+	1271: {region: 0x53, script: 0x68, flags: 0x0},
+	1272: {region: 0x10c, script: 0x6d, flags: 0x0},
+	1273: {region: 0x109, script: 0x79, flags: 0x0},
+	1274: {region: 0x9a, script: 0x22, flags: 0x0},
+	1275: {region: 0x132, script: 0x5b, flags: 0x0},
+	1276: {region: 0x166, script: 0x5b, flags: 0x0},
+	1277: {region: 0x9d, script: 0x93, flags: 0x0},
+	1278: {region: 0x166, script: 0x5b, flags: 0x0},
+	1279: {region: 0x15f, script: 0xce, flags: 0x0},
+	1280: {region: 0x166, script: 0x5b, flags: 0x0},
+	1281: {region: 0x166, script: 0x5b, flags: 0x0},
+	1282: {region: 0xdc, script: 0x22, flags: 0x0},
+	1283: {region: 0x166, script: 0x5b, flags: 0x0},
+	1284: {region: 0x166, script: 0x5b, flags: 0x0},
+	1285: {region: 0xd2, script: 0x5b, flags: 0x0},
+	1286: {region: 0x76, script: 0x5b, flags: 0x0},
+	1287: {region: 0x166, script: 0x5b, flags: 0x0},
+	1288: {region: 0x166, script: 0x5b, flags: 0x0},
+	1289: {region: 0x52, script: 0x5b, flags: 0x0},
+	1290: {region: 0x166, script: 0x5b, flags: 0x0},
+	1291: {region: 0x166, script: 0x5b, flags: 0x0},
+	1292: {region: 0x166, script: 0x5b, flags: 0x0},
+	1293: {region: 0x52, script: 0x5b, flags: 0x0},
+	1294: {region: 0x166, script: 0x5b, flags: 0x0},
+	1295: {region: 0x166, script: 0x5b, flags: 0x0},
+	1296: {region: 0x166, script: 0x5b, flags: 0x0},
+	1297: {region: 0x166, script: 0x5b, flags: 0x0},
+	1298: {region: 0x1, script: 0x3e, flags: 0x0},
+	1299: {region: 0x166, script: 0x5b, flags: 0x0},
+	1300: {region: 0x166, script: 0x5b, flags: 0x0},
+	1301: {region: 0x166, script: 0x5b, flags: 0x0},
+	1302: {region: 0x166, script: 0x5b, flags: 0x0},
+	1303: {region: 0x166, script: 0x5b, flags: 0x0},
+	1304: {region: 0xd7, script: 0x5b, flags: 0x0},
+	1305: {region: 0x166, script: 0x5b, flags: 0x0},
+	1306: {region: 0x166, script: 0x5b, flags: 0x0},
+	1307: {region: 0x166, script: 0x5b, flags: 0x0},
+	1308: {region: 0x41, script: 0x5b, flags: 0x0},
+	1309: {region: 0x166, script: 0x5b, flags: 0x0},
+	1310: {region: 0xd0, script: 0x5b, flags: 0x0},
+	1311: {region: 0x4a, script: 0x3, flags: 0x1},
+	1312: {region: 0x166, script: 0x5b, flags: 0x0},
+	1313: {region: 0x166, script: 0x5b, flags: 0x0},
+	1314: {region: 0x166, script: 0x5b, flags: 0x0},
+	1315: {region: 0x53, script: 0x5b, flags: 0x0},
+	1316: {region: 0x10c, script: 0x5b, flags: 0x0},
+	1318: {region: 0xa9, script: 0x5, flags: 0x0},
+	1319: {region: 0xda, script: 0x5b, flags: 0x0},
+	1320: {region: 0xbb, script: 0xeb, flags: 0x0},
+	1321: {region: 0x4d, script: 0x14, flags: 0x1},
+	1322: {region: 0x53, script: 0x7f, flags: 0x0},
+	1323: {region: 0x166, script: 0x5b, flags: 0x0},
+	1324: {region: 0x123, script: 0x5b, flags: 0x0},
+	1325: {region: 0xd1, script: 0x5b, flags: 0x0},
+	1326: {region: 0x166, script: 0x5b, flags: 0x0},
+	1327: {region: 0x162, script: 0x5b, flags: 0x0},
+	1329: {region: 0x12c, script: 0x5b, flags: 0x0},
+}
+
+// likelyLangList holds lists info associated with likelyLang.
+// Size: 582 bytes, 97 elements
+var likelyLangList = [97]likelyScriptRegion{
+	0:  {region: 0x9d, script: 0x7, flags: 0x0},
+	1:  {region: 0xa2, script: 0x7a, flags: 0x2},
+	2:  {region: 0x11d, script: 0x87, flags: 0x2},
+	3:  {region: 0x32, script: 0x5b, flags: 0x0},
+	4:  {region: 0x9c, script: 0x5, flags: 0x4},
+	5:  {region: 0x9d, script: 0x5, flags: 0x4},
+	6:  {region: 0x107, script: 0x20, flags: 0x4},
+	7:  {region: 0x9d, script: 0x5, flags: 0x2},
+	8:  {region: 0x107, script: 0x20, flags: 0x0},
+	9:  {region: 0x38, script: 0x2f, flags: 0x2},
+	10: {region: 0x136, script: 0x5b, flags: 0x0},
+	11: {region: 0x7c, script: 0xd1, flags: 0x2},
+	12: {region: 0x115, script: 0x5b, flags: 0x0},
+	13: {region: 0x85, script: 0x1, flags: 0x2},
+	14: {region: 0x5e, script: 0x1f, flags: 0x0},
+	15: {region: 0x88, script: 0x60, flags: 0x2},
+	16: {region: 0xd7, script: 0x5b, flags: 0x0},
+	17: {region: 0x52, script: 0x5, flags: 0x4},
+	18: {region: 0x10c, script: 0x5, flags: 0x4},
+	19: {region: 0xaf, script: 0x20, flags: 0x0},
+	20: {region: 0x24, script: 0x5, flags: 0x4},
+	21: {region: 0x53, script: 0x5, flags: 0x4},
+	22: {region: 0x9d, script: 0x5, flags: 0x4},
+	23: {region: 0xc6, script: 0x5, flags: 0x4},
+	24: {region: 0x53, script: 0x5, flags: 0x2},
+	25: {region: 0x12c, script: 0x5b, flags: 0x0},
+	26: {region: 0xb1, script: 0x5, flags: 0x4},
+	27: {region: 0x9c, script: 0x5, flags: 0x2},
+	28: {region: 0xa6, script: 0x20, flags: 0x0},
+	29: {region: 0x53, script: 0x5, flags: 0x4},
+	30: {region: 0x12c, script: 0x5b, flags: 0x4},
+	31: {region: 0x53, script: 0x5, flags: 0x2},
+	32: {region: 0x12c, script: 0x5b, flags: 0x2},
+	33: {region: 0xdc, script: 0x22, flags: 0x0},
+	34: {region: 0x9a, script: 0x5e, flags: 0x2},
+	35: {region: 0x84, script: 0x5b, flags: 0x0},
+	36: {region: 0x85, script: 0x7e, flags: 0x4},
+	37: {region: 0x85, script: 0x7e, flags: 0x2},
+	38: {region: 0xc6, script: 0x20, flags: 0x0},
+	39: {region: 0x53, script: 0x71, flags: 0x4},
+	40: {region: 0x53, script: 0x71, flags: 0x2},
+	41: {region: 0xd1, script: 0x5b, flags: 0x0},
+	42: {region: 0x4a, script: 0x5, flags: 0x4},
+	43: {region: 0x96, script: 0x5, flags: 0x4},
+	44: {region: 0x9a, script: 0x36, flags: 0x0},
+	45: {region: 0xe9, script: 0x5, flags: 0x4},
+	46: {region: 0xe9, script: 0x5, flags: 0x2},
+	47: {region: 0x9d, script: 0x8d, flags: 0x0},
+	48: {region: 0x53, script: 0x8e, flags: 0x2},
+	49: {region: 0xbb, script: 0xeb, flags: 0x0},
+	50: {region: 0xda, script: 0x5b, flags: 0x4},
+	51: {region: 0xe9, script: 0x5, flags: 0x0},
+	52: {region: 0x9a, script: 0x22, flags: 0x2},
+	53: {region: 0x9a, script: 0x50, flags: 0x2},
+	54: {region: 0x9a, script: 0xd5, flags: 0x2},
+	55: {region: 0x106, script: 0x20, flags: 0x0},
+	56: {region: 0xbe, script: 0x5b, flags: 0x4},
+	57: {region: 0x105, script: 0x5b, flags: 0x4},
+	58: {region: 0x107, script: 0x5b, flags: 0x4},
+	59: {region: 0x12c, script: 0x5b, flags: 0x4},
+	60: {region: 0x125, script: 0x20, flags: 0x0},
+	61: {region: 0xe9, script: 0x5, flags: 0x4},
+	62: {region: 0xe9, script: 0x5, flags: 0x2},
+	63: {region: 0x53, script: 0x5, flags: 0x0},
+	64: {region: 0xaf, script: 0x20, flags: 0x4},
+	65: {region: 0xc6, script: 0x20, flags: 0x4},
+	66: {region: 0xaf, script: 0x20, flags: 0x2},
+	67: {region: 0x9a, script: 0xe, flags: 0x0},
+	68: {region: 0xdc, script: 0x22, flags: 0x4},
+	69: {region: 0xdc, script: 0x22, flags: 0x2},
+	70: {region: 0x138, script: 0x5b, flags: 0x0},
+	71: {region: 0x24, script: 0x5, flags: 0x4},
+	72: {region: 0x53, script: 0x20, flags: 0x4},
+	73: {region: 0x24, script: 0x5, flags: 0x2},
+	74: {region: 0x8e, script: 0x3c, flags: 0x0},
+	75: {region: 0x53, script: 0x3b, flags: 0x4},
+	76: {region: 0x53, script: 0x3b, flags: 0x2},
+	77: {region: 0x53, script: 0x3b, flags: 0x0},
+	78: {region: 0x2f, script: 0x3c, flags: 0x4},
+	79: {region: 0x3e, script: 0x3c, flags: 0x4},
+	80: {region: 0x7c, script: 0x3c, flags: 0x4},
+	81: {region: 0x7f, script: 0x3c, flags: 0x4},
+	82: {region: 0x8e, script: 0x3c, flags: 0x4},
+	83: {region: 0x96, script: 0x3c, flags: 0x4},
+	84: {region: 0xc7, script: 0x3c, flags: 0x4},
+	85: {region: 0xd1, script: 0x3c, flags: 0x4},
+	86: {region: 0xe3, script: 0x3c, flags: 0x4},
+	87: {region: 0xe6, script: 0x3c, flags: 0x4},
+	88: {region: 0xe8, script: 0x3c, flags: 0x4},
+	89: {region: 0x117, script: 0x3c, flags: 0x4},
+	90: {region: 0x124, script: 0x3c, flags: 0x4},
+	91: {region: 0x12f, script: 0x3c, flags: 0x4},
+	92: {region: 0x136, script: 0x3c, flags: 0x4},
+	93: {region: 0x13f, script: 0x3c, flags: 0x4},
+	94: {region: 0x12f, script: 0x11, flags: 0x2},
+	95: {region: 0x12f, script: 0x37, flags: 0x2},
+	96: {region: 0x12f, script: 0x3c, flags: 0x2},
+}
+
+type likelyLangScript struct {
+	lang   uint16
+	script uint16
+	flags  uint8
+}
+
+// likelyRegion is a lookup table, indexed by regionID, for the most likely
+// languages and scripts given incomplete information. If more entries exist
+// for a given regionID, lang and script are the index and size respectively
+// of the list in likelyRegionList.
+// TODO: exclude containers and user-definable regions from the list.
+// Size: 2154 bytes, 359 elements
+var likelyRegion = [359]likelyLangScript{
+	34:  {lang: 0xd7, script: 0x5b, flags: 0x0},
+	35:  {lang: 0x3a, script: 0x5, flags: 0x0},
+	36:  {lang: 0x0, script: 0x2, flags: 0x1},
+	39:  {lang: 0x2, script: 0x2, flags: 0x1},
+	40:  {lang: 0x4, script: 0x2, flags: 0x1},
+	42:  {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	43:  {lang: 0x0, script: 0x5b, flags: 0x0},
+	44:  {lang: 0x13e, script: 0x5b, flags: 0x0},
+	45:  {lang: 0x41b, script: 0x5b, flags: 0x0},
+	46:  {lang: 0x10d, script: 0x5b, flags: 0x0},
+	48:  {lang: 0x367, script: 0x5b, flags: 0x0},
+	49:  {lang: 0x444, script: 0x5b, flags: 0x0},
+	50:  {lang: 0x58, script: 0x5b, flags: 0x0},
+	51:  {lang: 0x6, script: 0x2, flags: 0x1},
+	53:  {lang: 0xa5, script: 0xe, flags: 0x0},
+	54:  {lang: 0x367, script: 0x5b, flags: 0x0},
+	55:  {lang: 0x15e, script: 0x5b, flags: 0x0},
+	56:  {lang: 0x7e, script: 0x20, flags: 0x0},
+	57:  {lang: 0x3a, script: 0x5, flags: 0x0},
+	58:  {lang: 0x3d9, script: 0x5b, flags: 0x0},
+	59:  {lang: 0x15e, script: 0x5b, flags: 0x0},
+	60:  {lang: 0x15e, script: 0x5b, flags: 0x0},
+	62:  {lang: 0x31f, script: 0x5b, flags: 0x0},
+	63:  {lang: 0x13e, script: 0x5b, flags: 0x0},
+	64:  {lang: 0x3a1, script: 0x5b, flags: 0x0},
+	65:  {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	67:  {lang: 0x8, script: 0x2, flags: 0x1},
+	69:  {lang: 0x0, script: 0x5b, flags: 0x0},
+	71:  {lang: 0x71, script: 0x20, flags: 0x0},
+	73:  {lang: 0x512, script: 0x3e, flags: 0x2},
+	74:  {lang: 0x31f, script: 0x5, flags: 0x2},
+	75:  {lang: 0x445, script: 0x5b, flags: 0x0},
+	76:  {lang: 0x15e, script: 0x5b, flags: 0x0},
+	77:  {lang: 0x15e, script: 0x5b, flags: 0x0},
+	78:  {lang: 0x10d, script: 0x5b, flags: 0x0},
+	79:  {lang: 0x15e, script: 0x5b, flags: 0x0},
+	81:  {lang: 0x13e, script: 0x5b, flags: 0x0},
+	82:  {lang: 0x15e, script: 0x5b, flags: 0x0},
+	83:  {lang: 0xa, script: 0x4, flags: 0x1},
+	84:  {lang: 0x13e, script: 0x5b, flags: 0x0},
+	85:  {lang: 0x0, script: 0x5b, flags: 0x0},
+	87:  {lang: 0x13e, script: 0x5b, flags: 0x0},
+	90:  {lang: 0x13e, script: 0x5b, flags: 0x0},
+	91:  {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	92:  {lang: 0x3a1, script: 0x5b, flags: 0x0},
+	94:  {lang: 0xe, script: 0x2, flags: 0x1},
+	95:  {lang: 0xfa, script: 0x5b, flags: 0x0},
+	97:  {lang: 0x10d, script: 0x5b, flags: 0x0},
+	99:  {lang: 0x1, script: 0x5b, flags: 0x0},
+	100: {lang: 0x101, script: 0x5b, flags: 0x0},
+	102: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	104: {lang: 0x10, script: 0x2, flags: 0x1},
+	105: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	106: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	107: {lang: 0x140, script: 0x5b, flags: 0x0},
+	108: {lang: 0x3a, script: 0x5, flags: 0x0},
+	109: {lang: 0x3a, script: 0x5, flags: 0x0},
+	110: {lang: 0x46f, script: 0x2c, flags: 0x0},
+	111: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	112: {lang: 0x12, script: 0x2, flags: 0x1},
+	114: {lang: 0x10d, script: 0x5b, flags: 0x0},
+	115: {lang: 0x151, script: 0x5b, flags: 0x0},
+	116: {lang: 0x1c0, script: 0x22, flags: 0x2},
+	119: {lang: 0x158, script: 0x5b, flags: 0x0},
+	121: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	123: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	124: {lang: 0x14, script: 0x2, flags: 0x1},
+	126: {lang: 0x16, script: 0x3, flags: 0x1},
+	127: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	129: {lang: 0x21, script: 0x5b, flags: 0x0},
+	131: {lang: 0x245, script: 0x5b, flags: 0x0},
+	133: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	134: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	135: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	136: {lang: 0x19, script: 0x2, flags: 0x1},
+	137: {lang: 0x0, script: 0x5b, flags: 0x0},
+	138: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	140: {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	142: {lang: 0x529, script: 0x3c, flags: 0x0},
+	143: {lang: 0x0, script: 0x5b, flags: 0x0},
+	144: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	145: {lang: 0x1d1, script: 0x5b, flags: 0x0},
+	146: {lang: 0x1d4, script: 0x5b, flags: 0x0},
+	147: {lang: 0x1d5, script: 0x5b, flags: 0x0},
+	149: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	150: {lang: 0x1b, script: 0x2, flags: 0x1},
+	152: {lang: 0x1bc, script: 0x3e, flags: 0x0},
+	154: {lang: 0x1d, script: 0x3, flags: 0x1},
+	156: {lang: 0x3a, script: 0x5, flags: 0x0},
+	157: {lang: 0x20, script: 0x2, flags: 0x1},
+	158: {lang: 0x1f8, script: 0x5b, flags: 0x0},
+	159: {lang: 0x1f9, script: 0x5b, flags: 0x0},
+	162: {lang: 0x3a, script: 0x5, flags: 0x0},
+	163: {lang: 0x200, script: 0x49, flags: 0x0},
+	165: {lang: 0x445, script: 0x5b, flags: 0x0},
+	166: {lang: 0x28a, script: 0x20, flags: 0x0},
+	167: {lang: 0x22, script: 0x3, flags: 0x1},
+	169: {lang: 0x25, script: 0x2, flags: 0x1},
+	171: {lang: 0x254, script: 0x54, flags: 0x0},
+	172: {lang: 0x254, script: 0x54, flags: 0x0},
+	173: {lang: 0x3a, script: 0x5, flags: 0x0},
+	175: {lang: 0x3e2, script: 0x20, flags: 0x0},
+	176: {lang: 0x27, script: 0x2, flags: 0x1},
+	177: {lang: 0x3a, script: 0x5, flags: 0x0},
+	179: {lang: 0x10d, script: 0x5b, flags: 0x0},
+	180: {lang: 0x40c, script: 0xd6, flags: 0x0},
+	182: {lang: 0x43b, script: 0x5b, flags: 0x0},
+	183: {lang: 0x2c0, script: 0x5b, flags: 0x0},
+	184: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	185: {lang: 0x2c7, script: 0x5b, flags: 0x0},
+	186: {lang: 0x3a, script: 0x5, flags: 0x0},
+	187: {lang: 0x29, script: 0x2, flags: 0x1},
+	188: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	189: {lang: 0x2b, script: 0x2, flags: 0x1},
+	190: {lang: 0x432, script: 0x5b, flags: 0x0},
+	191: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	192: {lang: 0x2f1, script: 0x5b, flags: 0x0},
+	195: {lang: 0x2d, script: 0x2, flags: 0x1},
+	196: {lang: 0xa0, script: 0x5b, flags: 0x0},
+	197: {lang: 0x2f, script: 0x2, flags: 0x1},
+	198: {lang: 0x31, script: 0x2, flags: 0x1},
+	199: {lang: 0x33, script: 0x2, flags: 0x1},
+	201: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	202: {lang: 0x35, script: 0x2, flags: 0x1},
+	204: {lang: 0x320, script: 0x5b, flags: 0x0},
+	205: {lang: 0x37, script: 0x3, flags: 0x1},
+	206: {lang: 0x128, script: 0xed, flags: 0x0},
+	208: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	209: {lang: 0x31f, script: 0x5b, flags: 0x0},
+	210: {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	211: {lang: 0x16, script: 0x5b, flags: 0x0},
+	212: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	213: {lang: 0x1b4, script: 0x5b, flags: 0x0},
+	215: {lang: 0x1b4, script: 0x5, flags: 0x2},
+	217: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	218: {lang: 0x367, script: 0x5b, flags: 0x0},
+	219: {lang: 0x347, script: 0x5b, flags: 0x0},
+	220: {lang: 0x351, script: 0x22, flags: 0x0},
+	226: {lang: 0x3a, script: 0x5, flags: 0x0},
+	227: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	229: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	230: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	231: {lang: 0x486, script: 0x5b, flags: 0x0},
+	232: {lang: 0x153, script: 0x5b, flags: 0x0},
+	233: {lang: 0x3a, script: 0x3, flags: 0x1},
+	234: {lang: 0x3b3, script: 0x5b, flags: 0x0},
+	235: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	237: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	238: {lang: 0x3a, script: 0x5, flags: 0x0},
+	239: {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	241: {lang: 0x3a2, script: 0x5b, flags: 0x0},
+	242: {lang: 0x194, script: 0x5b, flags: 0x0},
+	244: {lang: 0x3a, script: 0x5, flags: 0x0},
+	259: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	261: {lang: 0x3d, script: 0x2, flags: 0x1},
+	262: {lang: 0x432, script: 0x20, flags: 0x0},
+	263: {lang: 0x3f, script: 0x2, flags: 0x1},
+	264: {lang: 0x3e5, script: 0x5b, flags: 0x0},
+	265: {lang: 0x3a, script: 0x5, flags: 0x0},
+	267: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	268: {lang: 0x3a, script: 0x5, flags: 0x0},
+	269: {lang: 0x41, script: 0x2, flags: 0x1},
+	272: {lang: 0x416, script: 0x5b, flags: 0x0},
+	273: {lang: 0x347, script: 0x5b, flags: 0x0},
+	274: {lang: 0x43, script: 0x2, flags: 0x1},
+	276: {lang: 0x1f9, script: 0x5b, flags: 0x0},
+	277: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	278: {lang: 0x429, script: 0x5b, flags: 0x0},
+	279: {lang: 0x367, script: 0x5b, flags: 0x0},
+	281: {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	283: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	285: {lang: 0x45, script: 0x2, flags: 0x1},
+	289: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	290: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	291: {lang: 0x47, script: 0x2, flags: 0x1},
+	292: {lang: 0x49, script: 0x3, flags: 0x1},
+	293: {lang: 0x4c, script: 0x2, flags: 0x1},
+	294: {lang: 0x477, script: 0x5b, flags: 0x0},
+	295: {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	296: {lang: 0x476, script: 0x5b, flags: 0x0},
+	297: {lang: 0x4e, script: 0x2, flags: 0x1},
+	298: {lang: 0x482, script: 0x5b, flags: 0x0},
+	300: {lang: 0x50, script: 0x4, flags: 0x1},
+	302: {lang: 0x4a0, script: 0x5b, flags: 0x0},
+	303: {lang: 0x54, script: 0x2, flags: 0x1},
+	304: {lang: 0x445, script: 0x5b, flags: 0x0},
+	305: {lang: 0x56, script: 0x3, flags: 0x1},
+	306: {lang: 0x445, script: 0x5b, flags: 0x0},
+	310: {lang: 0x512, script: 0x3e, flags: 0x2},
+	311: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	312: {lang: 0x4bc, script: 0x5b, flags: 0x0},
+	313: {lang: 0x1f9, script: 0x5b, flags: 0x0},
+	316: {lang: 0x13e, script: 0x5b, flags: 0x0},
+	319: {lang: 0x4c3, script: 0x5b, flags: 0x0},
+	320: {lang: 0x8a, script: 0x5b, flags: 0x0},
+	321: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	323: {lang: 0x41b, script: 0x5b, flags: 0x0},
+	334: {lang: 0x59, script: 0x2, flags: 0x1},
+	351: {lang: 0x3a, script: 0x5, flags: 0x0},
+	352: {lang: 0x5b, script: 0x2, flags: 0x1},
+	357: {lang: 0x423, script: 0x5b, flags: 0x0},
+}
+
+// likelyRegionList holds lists info associated with likelyRegion.
+// Size: 558 bytes, 93 elements
+var likelyRegionList = [93]likelyLangScript{
+	0:  {lang: 0x148, script: 0x5, flags: 0x0},
+	1:  {lang: 0x476, script: 0x5b, flags: 0x0},
+	2:  {lang: 0x431, script: 0x5b, flags: 0x0},
+	3:  {lang: 0x2ff, script: 0x20, flags: 0x0},
+	4:  {lang: 0x1d7, script: 0x8, flags: 0x0},
+	5:  {lang: 0x274, script: 0x5b, flags: 0x0},
+	6:  {lang: 0xb7, script: 0x5b, flags: 0x0},
+	7:  {lang: 0x432, script: 0x20, flags: 0x0},
+	8:  {lang: 0x12d, script: 0xef, flags: 0x0},
+	9:  {lang: 0x351, script: 0x22, flags: 0x0},
+	10: {lang: 0x529, script: 0x3b, flags: 0x0},
+	11: {lang: 0x4ac, script: 0x5, flags: 0x0},
+	12: {lang: 0x523, script: 0x5b, flags: 0x0},
+	13: {lang: 0x29a, script: 0xee, flags: 0x0},
+	14: {lang: 0x136, script: 0x34, flags: 0x0},
+	15: {lang: 0x48a, script: 0x5b, flags: 0x0},
+	16: {lang: 0x3a, script: 0x5, flags: 0x0},
+	17: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	18: {lang: 0x27, script: 0x2c, flags: 0x0},
+	19: {lang: 0x139, script: 0x5b, flags: 0x0},
+	20: {lang: 0x26a, script: 0x5, flags: 0x2},
+	21: {lang: 0x512, script: 0x3e, flags: 0x2},
+	22: {lang: 0x210, script: 0x2e, flags: 0x0},
+	23: {lang: 0x5, script: 0x20, flags: 0x0},
+	24: {lang: 0x274, script: 0x5b, flags: 0x0},
+	25: {lang: 0x136, script: 0x34, flags: 0x0},
+	26: {lang: 0x2ff, script: 0x20, flags: 0x0},
+	27: {lang: 0x1e1, script: 0x5b, flags: 0x0},
+	28: {lang: 0x31f, script: 0x5, flags: 0x0},
+	29: {lang: 0x1be, script: 0x22, flags: 0x0},
+	30: {lang: 0x4b4, script: 0x5, flags: 0x0},
+	31: {lang: 0x236, script: 0x76, flags: 0x0},
+	32: {lang: 0x148, script: 0x5, flags: 0x0},
+	33: {lang: 0x476, script: 0x5b, flags: 0x0},
+	34: {lang: 0x24a, script: 0x4f, flags: 0x0},
+	35: {lang: 0xe6, script: 0x5, flags: 0x0},
+	36: {lang: 0x226, script: 0xee, flags: 0x0},
+	37: {lang: 0x3a, script: 0x5, flags: 0x0},
+	38: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	39: {lang: 0x2b8, script: 0x58, flags: 0x0},
+	40: {lang: 0x226, script: 0xee, flags: 0x0},
+	41: {lang: 0x3a, script: 0x5, flags: 0x0},
+	42: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	43: {lang: 0x3dc, script: 0x5b, flags: 0x0},
+	44: {lang: 0x4ae, script: 0x20, flags: 0x0},
+	45: {lang: 0x2ff, script: 0x20, flags: 0x0},
+	46: {lang: 0x431, script: 0x5b, flags: 0x0},
+	47: {lang: 0x331, script: 0x76, flags: 0x0},
+	48: {lang: 0x213, script: 0x5b, flags: 0x0},
+	49: {lang: 0x30b, script: 0x20, flags: 0x0},
+	50: {lang: 0x242, script: 0x5, flags: 0x0},
+	51: {lang: 0x529, script: 0x3c, flags: 0x0},
+	52: {lang: 0x3c0, script: 0x5b, flags: 0x0},
+	53: {lang: 0x3a, script: 0x5, flags: 0x0},
+	54: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	55: {lang: 0x2ed, script: 0x5b, flags: 0x0},
+	56: {lang: 0x4b4, script: 0x5, flags: 0x0},
+	57: {lang: 0x88, script: 0x22, flags: 0x0},
+	58: {lang: 0x4b4, script: 0x5, flags: 0x0},
+	59: {lang: 0x4b4, script: 0x5, flags: 0x0},
+	60: {lang: 0xbe, script: 0x22, flags: 0x0},
+	61: {lang: 0x3dc, script: 0x5b, flags: 0x0},
+	62: {lang: 0x7e, script: 0x20, flags: 0x0},
+	63: {lang: 0x3e2, script: 0x20, flags: 0x0},
+	64: {lang: 0x267, script: 0x5b, flags: 0x0},
+	65: {lang: 0x444, script: 0x5b, flags: 0x0},
+	66: {lang: 0x512, script: 0x3e, flags: 0x0},
+	67: {lang: 0x412, script: 0x5b, flags: 0x0},
+	68: {lang: 0x4ae, script: 0x20, flags: 0x0},
+	69: {lang: 0x3a, script: 0x5, flags: 0x0},
+	70: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	71: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	72: {lang: 0x35, script: 0x5, flags: 0x0},
+	73: {lang: 0x46b, script: 0xee, flags: 0x0},
+	74: {lang: 0x2ec, script: 0x5, flags: 0x0},
+	75: {lang: 0x30f, script: 0x76, flags: 0x0},
+	76: {lang: 0x467, script: 0x20, flags: 0x0},
+	77: {lang: 0x148, script: 0x5, flags: 0x0},
+	78: {lang: 0x3a, script: 0x5, flags: 0x0},
+	79: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	80: {lang: 0x48a, script: 0x5b, flags: 0x0},
+	81: {lang: 0x58, script: 0x5, flags: 0x0},
+	82: {lang: 0x219, script: 0x20, flags: 0x0},
+	83: {lang: 0x81, script: 0x34, flags: 0x0},
+	84: {lang: 0x529, script: 0x3c, flags: 0x0},
+	85: {lang: 0x48c, script: 0x5b, flags: 0x0},
+	86: {lang: 0x4ae, script: 0x20, flags: 0x0},
+	87: {lang: 0x512, script: 0x3e, flags: 0x0},
+	88: {lang: 0x3b3, script: 0x5b, flags: 0x0},
+	89: {lang: 0x431, script: 0x5b, flags: 0x0},
+	90: {lang: 0x432, script: 0x20, flags: 0x0},
+	91: {lang: 0x15e, script: 0x5b, flags: 0x0},
+	92: {lang: 0x446, script: 0x5, flags: 0x0},
+}
+
+type likelyTag struct {
+	lang   uint16
+	region uint16
+	script uint16
+}
+
+// Size: 198 bytes, 33 elements
+var likelyRegionGroup = [33]likelyTag{
+	1:  {lang: 0x139, region: 0xd7, script: 0x5b},
+	2:  {lang: 0x139, region: 0x136, script: 0x5b},
+	3:  {lang: 0x3c0, region: 0x41, script: 0x5b},
+	4:  {lang: 0x139, region: 0x2f, script: 0x5b},
+	5:  {lang: 0x139, region: 0xd7, script: 0x5b},
+	6:  {lang: 0x13e, region: 0xd0, script: 0x5b},
+	7:  {lang: 0x445, region: 0x130, script: 0x5b},
+	8:  {lang: 0x3a, region: 0x6c, script: 0x5},
+	9:  {lang: 0x445, region: 0x4b, script: 0x5b},
+	10: {lang: 0x139, region: 0x162, script: 0x5b},
+	11: {lang: 0x139, region: 0x136, script: 0x5b},
+	12: {lang: 0x139, region: 0x136, script: 0x5b},
+	13: {lang: 0x13e, region: 0x5a, script: 0x5b},
+	14: {lang: 0x529, region: 0x53, script: 0x3b},
+	15: {lang: 0x1be, region: 0x9a, script: 0x22},
+	16: {lang: 0x1e1, region: 0x96, script: 0x5b},
+	17: {lang: 0x1f9, region: 0x9f, script: 0x5b},
+	18: {lang: 0x139, region: 0x2f, script: 0x5b},
+	19: {lang: 0x139, region: 0xe7, script: 0x5b},
+	20: {lang: 0x139, region: 0x8b, script: 0x5b},
+	21: {lang: 0x41b, region: 0x143, script: 0x5b},
+	22: {lang: 0x529, region: 0x53, script: 0x3b},
+	23: {lang: 0x4bc, region: 0x138, script: 0x5b},
+	24: {lang: 0x3a, region: 0x109, script: 0x5},
+	25: {lang: 0x3e2, region: 0x107, script: 0x20},
+	26: {lang: 0x3e2, region: 0x107, script: 0x20},
+	27: {lang: 0x139, region: 0x7c, script: 0x5b},
+	28: {lang: 0x10d, region: 0x61, script: 0x5b},
+	29: {lang: 0x139, region: 0xd7, script: 0x5b},
+	30: {lang: 0x13e, region: 0x1f, script: 0x5b},
+	31: {lang: 0x139, region: 0x9b, script: 0x5b},
+	32: {lang: 0x139, region: 0x7c, script: 0x5b},
+}
+
+// Size: 264 bytes, 33 elements
+var regionContainment = [33]uint64{
+	// Entry 0 - 1F
+	0x00000001ffffffff, 0x00000000200007a2, 0x0000000000003044, 0x0000000000000008,
+	0x00000000803c0010, 0x0000000000000020, 0x0000000000000040, 0x0000000000000080,
+	0x0000000000000100, 0x0000000000000200, 0x0000000000000400, 0x000000004000384c,
+	0x0000000000001000, 0x0000000000002000, 0x0000000000004000, 0x0000000000008000,
+	0x0000000000010000, 0x0000000000020000, 0x0000000000040000, 0x0000000000080000,
+	0x0000000000100000, 0x0000000000200000, 0x0000000001c1c000, 0x0000000000800000,
+	0x0000000001000000, 0x000000001e020000, 0x0000000004000000, 0x0000000008000000,
+	0x0000000010000000, 0x00000000200006a0, 0x0000000040002048, 0x0000000080000000,
+	// Entry 20 - 3F
+	0x0000000100000000,
+}
+
+// regionInclusion maps region identifiers to sets of regions in regionInclusionBits,
+// where each set holds all groupings that are directly connected in a region
+// containment graph.
+// Size: 359 bytes, 359 elements
+var regionInclusion = [359]uint8{
+	// Entry 0 - 3F
+	0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+	0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+	0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+	0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+	0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x23,
+	0x24, 0x26, 0x27, 0x22, 0x28, 0x29, 0x2a, 0x2b,
+	0x26, 0x2c, 0x24, 0x23, 0x26, 0x25, 0x2a, 0x2d,
+	0x2e, 0x24, 0x2f, 0x2d, 0x26, 0x30, 0x31, 0x28,
+	// Entry 40 - 7F
+	0x26, 0x28, 0x26, 0x25, 0x31, 0x22, 0x32, 0x33,
+	0x34, 0x30, 0x22, 0x27, 0x27, 0x27, 0x35, 0x2d,
+	0x29, 0x28, 0x27, 0x36, 0x28, 0x22, 0x21, 0x34,
+	0x23, 0x21, 0x26, 0x2d, 0x26, 0x22, 0x37, 0x2e,
+	0x35, 0x2a, 0x22, 0x2f, 0x38, 0x26, 0x26, 0x21,
+	0x39, 0x39, 0x28, 0x38, 0x39, 0x39, 0x2f, 0x3a,
+	0x2f, 0x20, 0x21, 0x38, 0x3b, 0x28, 0x3c, 0x2c,
+	0x21, 0x2a, 0x35, 0x27, 0x38, 0x26, 0x24, 0x28,
+	// Entry 80 - BF
+	0x2c, 0x2d, 0x23, 0x30, 0x2d, 0x2d, 0x26, 0x27,
+	0x3a, 0x22, 0x34, 0x3c, 0x2d, 0x28, 0x36, 0x22,
+	0x34, 0x3a, 0x26, 0x2e, 0x21, 0x39, 0x31, 0x38,
+	0x24, 0x2c, 0x25, 0x22, 0x24, 0x25, 0x2c, 0x3a,
+	0x2c, 0x26, 0x24, 0x36, 0x21, 0x2f, 0x3d, 0x31,
+	0x3c, 0x2f, 0x26, 0x36, 0x36, 0x24, 0x26, 0x3d,
+	0x31, 0x24, 0x26, 0x35, 0x25, 0x2d, 0x32, 0x38,
+	0x2a, 0x38, 0x39, 0x39, 0x35, 0x33, 0x23, 0x26,
+	// Entry C0 - FF
+	0x2f, 0x3c, 0x21, 0x23, 0x2d, 0x31, 0x36, 0x36,
+	0x3c, 0x26, 0x2d, 0x26, 0x3a, 0x2f, 0x25, 0x2f,
+	0x34, 0x31, 0x2f, 0x32, 0x3b, 0x2d, 0x2b, 0x2d,
+	0x21, 0x34, 0x2a, 0x2c, 0x25, 0x21, 0x3c, 0x24,
+	0x29, 0x2b, 0x24, 0x34, 0x21, 0x28, 0x29, 0x3b,
+	0x31, 0x25, 0x2e, 0x30, 0x29, 0x26, 0x24, 0x3a,
+	0x21, 0x3c, 0x28, 0x21, 0x24, 0x21, 0x21, 0x1f,
+	0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+	// Entry 100 - 13F
+	0x21, 0x21, 0x21, 0x2f, 0x21, 0x2e, 0x23, 0x33,
+	0x2f, 0x24, 0x3b, 0x2f, 0x39, 0x38, 0x31, 0x2d,
+	0x3a, 0x2c, 0x2e, 0x2d, 0x23, 0x2d, 0x2f, 0x28,
+	0x2f, 0x27, 0x33, 0x34, 0x26, 0x24, 0x32, 0x22,
+	0x26, 0x27, 0x22, 0x2d, 0x31, 0x3d, 0x29, 0x31,
+	0x3d, 0x39, 0x29, 0x31, 0x24, 0x26, 0x29, 0x36,
+	0x2f, 0x33, 0x2f, 0x21, 0x22, 0x21, 0x30, 0x28,
+	0x3d, 0x23, 0x26, 0x21, 0x28, 0x26, 0x26, 0x31,
+	// Entry 140 - 17F
+	0x3b, 0x29, 0x21, 0x29, 0x21, 0x21, 0x21, 0x21,
+	0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x21,
+	0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+	0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24,
+	0x2f, 0x23, 0x32, 0x2f, 0x27, 0x2f, 0x21,
+}
+
+// regionInclusionBits is an array of bit vectors where every vector represents
+// a set of region groupings.  These sets are used to compute the distance
+// between two regions for the purpose of language matching.
+// Size: 584 bytes, 73 elements
+var regionInclusionBits = [73]uint64{
+	// Entry 0 - 1F
+	0x0000000102400813, 0x00000000200007a3, 0x0000000000003844, 0x0000000040000808,
+	0x00000000803c0011, 0x0000000020000022, 0x0000000040000844, 0x0000000020000082,
+	0x0000000000000102, 0x0000000020000202, 0x0000000020000402, 0x000000004000384d,
+	0x0000000000001804, 0x0000000040002804, 0x0000000000404000, 0x0000000000408000,
+	0x0000000000410000, 0x0000000002020000, 0x0000000000040010, 0x0000000000080010,
+	0x0000000000100010, 0x0000000000200010, 0x0000000001c1c001, 0x0000000000c00000,
+	0x0000000001400000, 0x000000001e020001, 0x0000000006000000, 0x000000000a000000,
+	0x0000000012000000, 0x00000000200006a2, 0x0000000040002848, 0x0000000080000010,
+	// Entry 20 - 3F
+	0x0000000100000001, 0x0000000000000001, 0x0000000080000000, 0x0000000000020000,
+	0x0000000001000000, 0x0000000000008000, 0x0000000000002000, 0x0000000000000200,
+	0x0000000000000008, 0x0000000000200000, 0x0000000110000000, 0x0000000000040000,
+	0x0000000008000000, 0x0000000000000020, 0x0000000104000000, 0x0000000000000080,
+	0x0000000000001000, 0x0000000000010000, 0x0000000000000400, 0x0000000004000000,
+	0x0000000000000040, 0x0000000010000000, 0x0000000000004000, 0x0000000101000000,
+	0x0000000108000000, 0x0000000000000100, 0x0000000100020000, 0x0000000000080000,
+	0x0000000000100000, 0x0000000000800000, 0x00000001ffffffff, 0x0000000122400fb3,
+	// Entry 40 - 5F
+	0x00000001827c0813, 0x000000014240385f, 0x0000000103c1c813, 0x000000011e420813,
+	0x0000000112000001, 0x0000000106000001, 0x0000000101400001, 0x000000010a000001,
+	0x0000000102020001,
+}
+
+// regionInclusionNext marks, for each entry in regionInclusionBits, the set of
+// all groups that are reachable from the groups set in the respective entry.
+// Size: 73 bytes, 73 elements
+var regionInclusionNext = [73]uint8{
+	// Entry 0 - 3F
+	0x3e, 0x3f, 0x0b, 0x0b, 0x40, 0x01, 0x0b, 0x01,
+	0x01, 0x01, 0x01, 0x41, 0x0b, 0x0b, 0x16, 0x16,
+	0x16, 0x19, 0x04, 0x04, 0x04, 0x04, 0x42, 0x16,
+	0x16, 0x43, 0x19, 0x19, 0x19, 0x01, 0x0b, 0x04,
+	0x00, 0x00, 0x1f, 0x11, 0x18, 0x0f, 0x0d, 0x09,
+	0x03, 0x15, 0x44, 0x12, 0x1b, 0x05, 0x45, 0x07,
+	0x0c, 0x10, 0x0a, 0x1a, 0x06, 0x1c, 0x0e, 0x46,
+	0x47, 0x08, 0x48, 0x13, 0x14, 0x17, 0x3e, 0x3e,
+	// Entry 40 - 7F
+	0x3e, 0x3e, 0x3e, 0x3e, 0x43, 0x43, 0x42, 0x43,
+	0x43,
+}
+
+type parentRel struct {
+	lang       uint16
+	script     uint16
+	maxScript  uint16
+	toRegion   uint16
+	fromRegion []uint16
+}
+
+// Size: 414 bytes, 5 elements
+var parents = [5]parentRel{
+	0: {lang: 0x139, script: 0x0, maxScript: 0x5b, toRegion: 0x1, fromRegion: []uint16{0x1a, 0x25, 0x26, 0x2f, 0x34, 0x36, 0x3d, 0x42, 0x46, 0x48, 0x49, 0x4a, 0x50, 0x52, 0x5d, 0x5e, 0x62, 0x65, 0x6e, 0x74, 0x75, 0x76, 0x7c, 0x7d, 0x80, 0x81, 0x82, 0x84, 0x8d, 0x8e, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0xa0, 0xa1, 0xa5, 0xa8, 0xaa, 0xae, 0xb2, 0xb5, 0xb6, 0xc0, 0xc7, 0xcb, 0xcc, 0xcd, 0xcf, 0xd1, 0xd3, 0xd6, 0xd7, 0xde, 0xe0, 0xe1, 0xe7, 0xe8, 0xe9, 0xec, 0xf1, 0x108, 0x10a, 0x10b, 0x10c, 0x10e, 0x10f, 0x113, 0x118, 0x11c, 0x11e, 0x120, 0x126, 0x12a, 0x12d, 0x12e, 0x130, 0x132, 0x13a, 0x13d, 0x140, 0x143, 0x162, 0x163, 0x165}},
+	1: {lang: 0x139, script: 0x0, maxScript: 0x5b, toRegion: 0x1a, fromRegion: []uint16{0x2e, 0x4e, 0x61, 0x64, 0x73, 0xda, 0x10d, 0x110}},
+	2: {lang: 0x13e, script: 0x0, maxScript: 0x5b, toRegion: 0x1f, fromRegion: []uint16{0x2c, 0x3f, 0x41, 0x48, 0x51, 0x54, 0x57, 0x5a, 0x66, 0x6a, 0x8a, 0x90, 0xd0, 0xd9, 0xe3, 0xe5, 0xed, 0xf2, 0x11b, 0x136, 0x137, 0x13c}},
+	3: {lang: 0x3c0, script: 0x0, maxScript: 0x5b, toRegion: 0xef, fromRegion: []uint16{0x2a, 0x4e, 0x5b, 0x87, 0x8c, 0xb8, 0xc7, 0xd2, 0x119, 0x127}},
+	4: {lang: 0x529, script: 0x3c, maxScript: 0x3c, toRegion: 0x8e, fromRegion: []uint16{0xc7}},
+}
+
+// Total table size 30466 bytes (29KiB); checksum: 7544152B
diff --git a/vendor/golang.org/x/text/internal/language/tags.go b/vendor/golang.org/x/text/internal/language/tags.go
new file mode 100644
index 000000000..e7afd3188
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/language/tags.go
@@ -0,0 +1,48 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+// MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed.
+// It simplifies safe initialization of Tag values.
+func MustParse(s string) Tag {
+	t, err := Parse(s)
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+// MustParseBase is like ParseBase, but panics if the given base cannot be parsed.
+// It simplifies safe initialization of Base values.
+func MustParseBase(s string) Language {
+	b, err := ParseBase(s)
+	if err != nil {
+		panic(err)
+	}
+	return b
+}
+
+// MustParseScript is like ParseScript, but panics if the given script cannot be
+// parsed. It simplifies safe initialization of Script values.
+func MustParseScript(s string) Script {
+	scr, err := ParseScript(s)
+	if err != nil {
+		panic(err)
+	}
+	return scr
+}
+
+// MustParseRegion is like ParseRegion, but panics if the given region cannot be
+// parsed. It simplifies safe initialization of Region values.
+func MustParseRegion(s string) Region {
+	r, err := ParseRegion(s)
+	if err != nil {
+		panic(err)
+	}
+	return r
+}
+
+// Und is the root language.
+var Und Tag
diff --git a/vendor/golang.org/x/text/internal/match.go b/vendor/golang.org/x/text/internal/match.go
new file mode 100644
index 000000000..1cc004a6d
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/match.go
@@ -0,0 +1,67 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+// This file contains matchers that implement CLDR inheritance.
+//
+//     See https://unicode.org/reports/tr35/#Locale_Inheritance.
+//
+// Some of the inheritance described in this document is already handled by
+// the cldr package.
+
+import (
+	"golang.org/x/text/language"
+)
+
+// TODO: consider if (some of the) matching algorithm needs to be public after
+// getting some feel about what is generic and what is specific.
+
+// NewInheritanceMatcher returns a matcher that matches based on the inheritance
+// chain.
+//
+// The matcher uses canonicalization and the parent relationship to find a
+// match. The resulting match will always be either Und or a language with the
+// same language and script as the requested language. It will not match
+// languages for which there is understood to be mutual or one-directional
+// intelligibility.
+//
+// A Match will indicate an Exact match if the language matches after
+// canonicalization and High if the matched tag is a parent.
+func NewInheritanceMatcher(t []language.Tag) *InheritanceMatcher {
+	tags := &InheritanceMatcher{make(map[language.Tag]int)}
+	for i, tag := range t {
+		ct, err := language.All.Canonicalize(tag)
+		if err != nil {
+			ct = tag
+		}
+		tags.index[ct] = i
+	}
+	return tags
+}
+
+type InheritanceMatcher struct {
+	index map[language.Tag]int
+}
+
+func (m InheritanceMatcher) Match(want ...language.Tag) (language.Tag, int, language.Confidence) {
+	for _, t := range want {
+		ct, err := language.All.Canonicalize(t)
+		if err != nil {
+			ct = t
+		}
+		conf := language.Exact
+		for {
+			if index, ok := m.index[ct]; ok {
+				return ct, index, conf
+			}
+			if ct == language.Und {
+				break
+			}
+			ct = ct.Parent()
+			conf = language.High
+		}
+	}
+	return language.Und, 0, language.No
+}
diff --git a/vendor/golang.org/x/text/internal/tag/tag.go b/vendor/golang.org/x/text/internal/tag/tag.go
new file mode 100644
index 000000000..b5d348891
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/tag/tag.go
@@ -0,0 +1,100 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tag contains functionality handling tags and related data.
+package tag // import "golang.org/x/text/internal/tag"
+
+import "sort"
+
+// An Index converts tags to a compact numeric value.
+//
+// All elements are of size 4. Tags may be up to 4 bytes long. Excess bytes can
+// be used to store additional information about the tag.
+type Index string
+
+// Elem returns the element data at the given index.
+func (s Index) Elem(x int) string {
+	return string(s[x*4 : x*4+4])
+}
+
+// Index reports the index of the given key or -1 if it could not be found.
+// Only the first len(key) bytes from the start of the 4-byte entries will be
+// considered for the search and the first match in Index will be returned.
+func (s Index) Index(key []byte) int {
+	n := len(key)
+	// search the index of the first entry with an equal or higher value than
+	// key in s.
+	index := sort.Search(len(s)/4, func(i int) bool {
+		return cmp(s[i*4:i*4+n], key) != -1
+	})
+	i := index * 4
+	if cmp(s[i:i+len(key)], key) != 0 {
+		return -1
+	}
+	return index
+}
+
+// Next finds the next occurrence of key after index x, which must have been
+// obtained from a call to Index using the same key. It returns x+1 or -1.
+func (s Index) Next(key []byte, x int) int {
+	if x++; x*4 < len(s) && cmp(s[x*4:x*4+len(key)], key) == 0 {
+		return x
+	}
+	return -1
+}
+
+// cmp returns an integer comparing a and b lexicographically.
+func cmp(a Index, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+	for i, c := range b[:n] {
+		switch {
+		case a[i] > c:
+			return 1
+		case a[i] < c:
+			return -1
+		}
+	}
+	switch {
+	case len(a) < len(b):
+		return -1
+	case len(a) > len(b):
+		return 1
+	}
+	return 0
+}
+
+// Compare returns an integer comparing a and b lexicographically.
+func Compare(a string, b []byte) int {
+	return cmp(Index(a), b)
+}
+
+// FixCase reformats b to the same pattern of cases as form.
+// If returns false if string b is malformed.
+func FixCase(form string, b []byte) bool {
+	if len(form) != len(b) {
+		return false
+	}
+	for i, c := range b {
+		if form[i] <= 'Z' {
+			if c >= 'a' {
+				c -= 'z' - 'Z'
+			}
+			if c < 'A' || 'Z' < c {
+				return false
+			}
+		} else {
+			if c <= 'Z' {
+				c += 'z' - 'Z'
+			}
+			if c < 'a' || 'z' < c {
+				return false
+			}
+		}
+		b[i] = c
+	}
+	return true
+}
diff --git a/vendor/golang.org/x/text/language/coverage.go b/vendor/golang.org/x/text/language/coverage.go
new file mode 100644
index 000000000..a24fd1a4d
--- /dev/null
+++ b/vendor/golang.org/x/text/language/coverage.go
@@ -0,0 +1,187 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+import (
+	"fmt"
+	"sort"
+
+	"golang.org/x/text/internal/language"
+)
+
+// The Coverage interface is used to define the level of coverage of an
+// internationalization service. Note that not all types are supported by all
+// services. As lists may be generated on the fly, it is recommended that users
+// of a Coverage cache the results.
+type Coverage interface {
+	// Tags returns the list of supported tags.
+	Tags() []Tag
+
+	// BaseLanguages returns the list of supported base languages.
+	BaseLanguages() []Base
+
+	// Scripts returns the list of supported scripts.
+	Scripts() []Script
+
+	// Regions returns the list of supported regions.
+	Regions() []Region
+}
+
+var (
+	// Supported defines a Coverage that lists all supported subtags. Tags
+	// always returns nil.
+	Supported Coverage = allSubtags{}
+)
+
+// TODO:
+// - Support Variants, numbering systems.
+// - CLDR coverage levels.
+// - Set of common tags defined in this package.
+
+type allSubtags struct{}
+
+// Regions returns the list of supported regions. As all regions are in a
+// consecutive range, it simply returns a slice of numbers in increasing order.
+// The "undefined" region is not returned.
+func (s allSubtags) Regions() []Region {
+	reg := make([]Region, language.NumRegions)
+	for i := range reg {
+		reg[i] = Region{language.Region(i + 1)}
+	}
+	return reg
+}
+
+// Scripts returns the list of supported scripts. As all scripts are in a
+// consecutive range, it simply returns a slice of numbers in increasing order.
+// The "undefined" script is not returned.
+func (s allSubtags) Scripts() []Script {
+	scr := make([]Script, language.NumScripts)
+	for i := range scr {
+		scr[i] = Script{language.Script(i + 1)}
+	}
+	return scr
+}
+
+// BaseLanguages returns the list of all supported base languages. It generates
+// the list by traversing the internal structures.
+func (s allSubtags) BaseLanguages() []Base {
+	bs := language.BaseLanguages()
+	base := make([]Base, len(bs))
+	for i, b := range bs {
+		base[i] = Base{b}
+	}
+	return base
+}
+
+// Tags always returns nil.
+func (s allSubtags) Tags() []Tag {
+	return nil
+}
+
+// coverage is used by NewCoverage which is used as a convenient way for
+// creating Coverage implementations for partially defined data. Very often a
+// package will only need to define a subset of slices. coverage provides a
+// convenient way to do this. Moreover, packages using NewCoverage, instead of
+// their own implementation, will not break if later new slice types are added.
+type coverage struct {
+	tags    func() []Tag
+	bases   func() []Base
+	scripts func() []Script
+	regions func() []Region
+}
+
+func (s *coverage) Tags() []Tag {
+	if s.tags == nil {
+		return nil
+	}
+	return s.tags()
+}
+
+// bases implements sort.Interface and is used to sort base languages.
+type bases []Base
+
+func (b bases) Len() int {
+	return len(b)
+}
+
+func (b bases) Swap(i, j int) {
+	b[i], b[j] = b[j], b[i]
+}
+
+func (b bases) Less(i, j int) bool {
+	return b[i].langID < b[j].langID
+}
+
+// BaseLanguages returns the result from calling s.bases if it is specified or
+// otherwise derives the set of supported base languages from tags.
+func (s *coverage) BaseLanguages() []Base {
+	if s.bases == nil {
+		tags := s.Tags()
+		if len(tags) == 0 {
+			return nil
+		}
+		a := make([]Base, len(tags))
+		for i, t := range tags {
+			a[i] = Base{language.Language(t.lang())}
+		}
+		sort.Sort(bases(a))
+		k := 0
+		for i := 1; i < len(a); i++ {
+			if a[k] != a[i] {
+				k++
+				a[k] = a[i]
+			}
+		}
+		return a[:k+1]
+	}
+	return s.bases()
+}
+
+func (s *coverage) Scripts() []Script {
+	if s.scripts == nil {
+		return nil
+	}
+	return s.scripts()
+}
+
+func (s *coverage) Regions() []Region {
+	if s.regions == nil {
+		return nil
+	}
+	return s.regions()
+}
+
+// NewCoverage returns a Coverage for the given lists. It is typically used by
+// packages providing internationalization services to define their level of
+// coverage. A list may be of type []T or func() []T, where T is either Tag,
+// Base, Script or Region. The returned Coverage derives the value for Bases
+// from Tags if no func or slice for []Base is specified. For other unspecified
+// types the returned Coverage will return nil for the respective methods.
+func NewCoverage(list ...interface{}) Coverage {
+	s := &coverage{}
+	for _, x := range list {
+		switch v := x.(type) {
+		case func() []Base:
+			s.bases = v
+		case func() []Script:
+			s.scripts = v
+		case func() []Region:
+			s.regions = v
+		case func() []Tag:
+			s.tags = v
+		case []Base:
+			s.bases = func() []Base { return v }
+		case []Script:
+			s.scripts = func() []Script { return v }
+		case []Region:
+			s.regions = func() []Region { return v }
+		case []Tag:
+			s.tags = func() []Tag { return v }
+		default:
+			panic(fmt.Sprintf("language: unsupported set type %T", v))
+		}
+	}
+	return s
+}
diff --git a/vendor/golang.org/x/text/language/doc.go b/vendor/golang.org/x/text/language/doc.go
new file mode 100644
index 000000000..212b77c90
--- /dev/null
+++ b/vendor/golang.org/x/text/language/doc.go
@@ -0,0 +1,98 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package language implements BCP 47 language tags and related functionality.
+//
+// The most important function of package language is to match a list of
+// user-preferred languages to a list of supported languages.
+// It alleviates the developer of dealing with the complexity of this process
+// and provides the user with the best experience
+// (see https://blog.golang.org/matchlang).
+//
+// # Matching preferred against supported languages
+//
+// A Matcher for an application that supports English, Australian English,
+// Danish, and standard Mandarin can be created as follows:
+//
+//	var matcher = language.NewMatcher([]language.Tag{
+//	    language.English,   // The first language is used as fallback.
+//	    language.MustParse("en-AU"),
+//	    language.Danish,
+//	    language.Chinese,
+//	})
+//
+// This list of supported languages is typically implied by the languages for
+// which there exists translations of the user interface.
+//
+// User-preferred languages usually come as a comma-separated list of BCP 47
+// language tags.
+// The MatchString finds best matches for such strings:
+//
+//	handler(w http.ResponseWriter, r *http.Request) {
+//	    lang, _ := r.Cookie("lang")
+//	    accept := r.Header.Get("Accept-Language")
+//	    tag, _ := language.MatchStrings(matcher, lang.String(), accept)
+//
+//	    // tag should now be used for the initialization of any
+//	    // locale-specific service.
+//	}
+//
+// The Matcher's Match method can be used to match Tags directly.
+//
+// Matchers are aware of the intricacies of equivalence between languages, such
+// as deprecated subtags, legacy tags, macro languages, mutual
+// intelligibility between scripts and languages, and transparently passing
+// BCP 47 user configuration.
+// For instance, it will know that a reader of Bokmål Danish can read Norwegian
+// and will know that Cantonese ("yue") is a good match for "zh-HK".
+//
+// # Using match results
+//
+// To guarantee a consistent user experience to the user it is important to
+// use the same language tag for the selection of any locale-specific services.
+// For example, it is utterly confusing to substitute spelled-out numbers
+// or dates in one language in text of another language.
+// More subtly confusing is using the wrong sorting order or casing
+// algorithm for a certain language.
+//
+// All the packages in x/text that provide locale-specific services
+// (e.g. collate, cases) should be initialized with the tag that was
+// obtained at the start of an interaction with the user.
+//
+// Note that Tag that is returned by Match and MatchString may differ from any
+// of the supported languages, as it may contain carried over settings from
+// the user tags.
+// This may be inconvenient when your application has some additional
+// locale-specific data for your supported languages.
+// Match and MatchString both return the index of the matched supported tag
+// to simplify associating such data with the matched tag.
+//
+// # Canonicalization
+//
+// If one uses the Matcher to compare languages one does not need to
+// worry about canonicalization.
+//
+// The meaning of a Tag varies per application. The language package
+// therefore delays canonicalization and preserves information as much
+// as possible. The Matcher, however, will always take into account that
+// two different tags may represent the same language.
+//
+// By default, only legacy and deprecated tags are converted into their
+// canonical equivalent. All other information is preserved. This approach makes
+// the confidence scores more accurate and allows matchers to distinguish
+// between variants that are otherwise lost.
+//
+// As a consequence, two tags that should be treated as identical according to
+// BCP 47 or CLDR, like "en-Latn" and "en", will be represented differently. The
+// Matcher handles such distinctions, though, and is aware of the
+// equivalence relations. The CanonType type can be used to alter the
+// canonicalization form.
+//
+// # References
+//
+// BCP 47 - Tags for Identifying Languages http://tools.ietf.org/html/bcp47
+package language // import "golang.org/x/text/language"
+
+// TODO: explanation on how to match languages for your own locale-specific
+// service.
diff --git a/vendor/golang.org/x/text/language/language.go b/vendor/golang.org/x/text/language/language.go
new file mode 100644
index 000000000..4d9c66121
--- /dev/null
+++ b/vendor/golang.org/x/text/language/language.go
@@ -0,0 +1,605 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go -output tables.go
+
+package language
+
+// TODO: Remove above NOTE after:
+// - verifying that tables are dropped correctly (most notably matcher tables).
+
+import (
+	"strings"
+
+	"golang.org/x/text/internal/language"
+	"golang.org/x/text/internal/language/compact"
+)
+
+// Tag represents a BCP 47 language tag. It is used to specify an instance of a
+// specific language or locale. All language tag values are guaranteed to be
+// well-formed.
+type Tag compact.Tag
+
+func makeTag(t language.Tag) (tag Tag) {
+	return Tag(compact.Make(t))
+}
+
+func (t *Tag) tag() language.Tag {
+	return (*compact.Tag)(t).Tag()
+}
+
+func (t *Tag) isCompact() bool {
+	return (*compact.Tag)(t).IsCompact()
+}
+
+// TODO: improve performance.
+func (t *Tag) lang() language.Language { return t.tag().LangID }
+func (t *Tag) region() language.Region { return t.tag().RegionID }
+func (t *Tag) script() language.Script { return t.tag().ScriptID }
+
+// Make is a convenience wrapper for Parse that omits the error.
+// In case of an error, a sensible default is returned.
+func Make(s string) Tag {
+	return Default.Make(s)
+}
+
+// Make is a convenience wrapper for c.Parse that omits the error.
+// In case of an error, a sensible default is returned.
+func (c CanonType) Make(s string) Tag {
+	t, _ := c.Parse(s)
+	return t
+}
+
+// Raw returns the raw base language, script and region, without making an
+// attempt to infer their values.
+func (t Tag) Raw() (b Base, s Script, r Region) {
+	tt := t.tag()
+	return Base{tt.LangID}, Script{tt.ScriptID}, Region{tt.RegionID}
+}
+
+// IsRoot returns true if t is equal to language "und".
+func (t Tag) IsRoot() bool {
+	return compact.Tag(t).IsRoot()
+}
+
+// CanonType can be used to enable or disable various types of canonicalization.
+type CanonType int
+
+const (
+	// Replace deprecated base languages with their preferred replacements.
+	DeprecatedBase CanonType = 1 << iota
+	// Replace deprecated scripts with their preferred replacements.
+	DeprecatedScript
+	// Replace deprecated regions with their preferred replacements.
+	DeprecatedRegion
+	// Remove redundant scripts.
+	SuppressScript
+	// Normalize legacy encodings. This includes legacy languages defined in
+	// CLDR as well as bibliographic codes defined in ISO-639.
+	Legacy
+	// Map the dominant language of a macro language group to the macro language
+	// subtag. For example cmn -> zh.
+	Macro
+	// The CLDR flag should be used if full compatibility with CLDR is required.
+	// There are a few cases where language.Tag may differ from CLDR. To follow all
+	// of CLDR's suggestions, use All|CLDR.
+	CLDR
+
+	// Raw can be used to Compose or Parse without Canonicalization.
+	Raw CanonType = 0
+
+	// Replace all deprecated tags with their preferred replacements.
+	Deprecated = DeprecatedBase | DeprecatedScript | DeprecatedRegion
+
+	// All canonicalizations recommended by BCP 47.
+	BCP47 = Deprecated | SuppressScript
+
+	// All canonicalizations.
+	All = BCP47 | Legacy | Macro
+
+	// Default is the canonicalization used by Parse, Make and Compose. To
+	// preserve as much information as possible, canonicalizations that remove
+	// potentially valuable information are not included. The Matcher is
+	// designed to recognize similar tags that would be the same if
+	// they were canonicalized using All.
+	Default = Deprecated | Legacy
+
+	canonLang = DeprecatedBase | Legacy | Macro
+
+	// TODO: LikelyScript, LikelyRegion: suppress similar to ICU.
+)
+
+// canonicalize returns the canonicalized equivalent of the tag and
+// whether there was any change.
+func canonicalize(c CanonType, t language.Tag) (language.Tag, bool) {
+	if c == Raw {
+		return t, false
+	}
+	changed := false
+	if c&SuppressScript != 0 {
+		if t.LangID.SuppressScript() == t.ScriptID {
+			t.ScriptID = 0
+			changed = true
+		}
+	}
+	if c&canonLang != 0 {
+		for {
+			if l, aliasType := t.LangID.Canonicalize(); l != t.LangID {
+				switch aliasType {
+				case language.Legacy:
+					if c&Legacy != 0 {
+						if t.LangID == _sh && t.ScriptID == 0 {
+							t.ScriptID = _Latn
+						}
+						t.LangID = l
+						changed = true
+					}
+				case language.Macro:
+					if c&Macro != 0 {
+						// We deviate here from CLDR. The mapping "nb" -> "no"
+						// qualifies as a typical Macro language mapping.  However,
+						// for legacy reasons, CLDR maps "no", the macro language
+						// code for Norwegian, to the dominant variant "nb". This
+						// change is currently under consideration for CLDR as well.
+						// See https://unicode.org/cldr/trac/ticket/2698 and also
+						// https://unicode.org/cldr/trac/ticket/1790 for some of the
+						// practical implications. TODO: this check could be removed
+						// if CLDR adopts this change.
+						if c&CLDR == 0 || t.LangID != _nb {
+							changed = true
+							t.LangID = l
+						}
+					}
+				case language.Deprecated:
+					if c&DeprecatedBase != 0 {
+						if t.LangID == _mo && t.RegionID == 0 {
+							t.RegionID = _MD
+						}
+						t.LangID = l
+						changed = true
+						// Other canonicalization types may still apply.
+						continue
+					}
+				}
+			} else if c&Legacy != 0 && t.LangID == _no && c&CLDR != 0 {
+				t.LangID = _nb
+				changed = true
+			}
+			break
+		}
+	}
+	if c&DeprecatedScript != 0 {
+		if t.ScriptID == _Qaai {
+			changed = true
+			t.ScriptID = _Zinh
+		}
+	}
+	if c&DeprecatedRegion != 0 {
+		if r := t.RegionID.Canonicalize(); r != t.RegionID {
+			changed = true
+			t.RegionID = r
+		}
+	}
+	return t, changed
+}
+
+// Canonicalize returns the canonicalized equivalent of the tag.
+func (c CanonType) Canonicalize(t Tag) (Tag, error) {
+	// First try fast path.
+	if t.isCompact() {
+		if _, changed := canonicalize(c, compact.Tag(t).Tag()); !changed {
+			return t, nil
+		}
+	}
+	// It is unlikely that one will canonicalize a tag after matching. So do
+	// a slow but simple approach here.
+	if tag, changed := canonicalize(c, t.tag()); changed {
+		tag.RemakeString()
+		return makeTag(tag), nil
+	}
+	return t, nil
+
+}
+
+// Confidence indicates the level of certainty for a given return value.
+// For example, Serbian may be written in Cyrillic or Latin script.
+// The confidence level indicates whether a value was explicitly specified,
+// whether it is typically the only possible value, or whether there is
+// an ambiguity.
+type Confidence int
+
+const (
+	No    Confidence = iota // full confidence that there was no match
+	Low                     // most likely value picked out of a set of alternatives
+	High                    // value is generally assumed to be the correct match
+	Exact                   // exact match or explicitly specified value
+)
+
+var confName = []string{"No", "Low", "High", "Exact"}
+
+func (c Confidence) String() string {
+	return confName[c]
+}
+
+// String returns the canonical string representation of the language tag.
+func (t Tag) String() string {
+	return t.tag().String()
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (t Tag) MarshalText() (text []byte, err error) {
+	return t.tag().MarshalText()
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (t *Tag) UnmarshalText(text []byte) error {
+	var tag language.Tag
+	err := tag.UnmarshalText(text)
+	*t = makeTag(tag)
+	return err
+}
+
+// Base returns the base language of the language tag. If the base language is
+// unspecified, an attempt will be made to infer it from the context.
+// It uses a variant of CLDR's Add Likely Subtags algorithm. This is subject to change.
+func (t Tag) Base() (Base, Confidence) {
+	if b := t.lang(); b != 0 {
+		return Base{b}, Exact
+	}
+	tt := t.tag()
+	c := High
+	if tt.ScriptID == 0 && !tt.RegionID.IsCountry() {
+		c = Low
+	}
+	if tag, err := tt.Maximize(); err == nil && tag.LangID != 0 {
+		return Base{tag.LangID}, c
+	}
+	return Base{0}, No
+}
+
+// Script infers the script for the language tag. If it was not explicitly given, it will infer
+// a most likely candidate.
+// If more than one script is commonly used for a language, the most likely one
+// is returned with a low confidence indication. For example, it returns (Cyrl, Low)
+// for Serbian.
+// If a script cannot be inferred (Zzzz, No) is returned. We do not use Zyyy (undetermined)
+// as one would suspect from the IANA registry for BCP 47. In a Unicode context Zyyy marks
+// common characters (like 1, 2, 3, '.', etc.) and is therefore more like multiple scripts.
+// See https://www.unicode.org/reports/tr24/#Values for more details. Zzzz is also used for
+// unknown value in CLDR.  (Zzzz, Exact) is returned if Zzzz was explicitly specified.
+// Note that an inferred script is never guaranteed to be the correct one. Latin is
+// almost exclusively used for Afrikaans, but Arabic has been used for some texts
+// in the past.  Also, the script that is commonly used may change over time.
+// It uses a variant of CLDR's Add Likely Subtags algorithm. This is subject to change.
+func (t Tag) Script() (Script, Confidence) {
+	if scr := t.script(); scr != 0 {
+		return Script{scr}, Exact
+	}
+	tt := t.tag()
+	sc, c := language.Script(_Zzzz), No
+	if scr := tt.LangID.SuppressScript(); scr != 0 {
+		// Note: it is not always the case that a language with a suppress
+		// script value is only written in one script (e.g. kk, ms, pa).
+		if tt.RegionID == 0 {
+			return Script{scr}, High
+		}
+		sc, c = scr, High
+	}
+	if tag, err := tt.Maximize(); err == nil {
+		if tag.ScriptID != sc {
+			sc, c = tag.ScriptID, Low
+		}
+	} else {
+		tt, _ = canonicalize(Deprecated|Macro, tt)
+		if tag, err := tt.Maximize(); err == nil && tag.ScriptID != sc {
+			sc, c = tag.ScriptID, Low
+		}
+	}
+	return Script{sc}, c
+}
+
+// Region returns the region for the language tag. If it was not explicitly given, it will
+// infer a most likely candidate from the context.
+// It uses a variant of CLDR's Add Likely Subtags algorithm. This is subject to change.
+func (t Tag) Region() (Region, Confidence) {
+	if r := t.region(); r != 0 {
+		return Region{r}, Exact
+	}
+	tt := t.tag()
+	if tt, err := tt.Maximize(); err == nil {
+		return Region{tt.RegionID}, Low // TODO: differentiate between high and low.
+	}
+	tt, _ = canonicalize(Deprecated|Macro, tt)
+	if tag, err := tt.Maximize(); err == nil {
+		return Region{tag.RegionID}, Low
+	}
+	return Region{_ZZ}, No // TODO: return world instead of undetermined?
+}
+
+// Variants returns the variants specified explicitly for this language tag.
+// or nil if no variant was specified.
+func (t Tag) Variants() []Variant {
+	if !compact.Tag(t).MayHaveVariants() {
+		return nil
+	}
+	v := []Variant{}
+	x, str := "", t.tag().Variants()
+	for str != "" {
+		x, str = nextToken(str)
+		v = append(v, Variant{x})
+	}
+	return v
+}
+
+// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
+// specific language are substituted with fields from the parent language.
+// The parent for a language may change for newer versions of CLDR.
+//
+// Parent returns a tag for a less specific language that is mutually
+// intelligible or Und if there is no such language. This may not be the same as
+// simply stripping the last BCP 47 subtag. For instance, the parent of "zh-TW"
+// is "zh-Hant", and the parent of "zh-Hant" is "und".
+func (t Tag) Parent() Tag {
+	return Tag(compact.Tag(t).Parent())
+}
+
+// nextToken returns token t and the rest of the string.
+func nextToken(s string) (t, tail string) {
+	p := strings.Index(s[1:], "-")
+	if p == -1 {
+		return s[1:], ""
+	}
+	p++
+	return s[1:p], s[p:]
+}
+
+// Extension is a single BCP 47 extension.
+type Extension struct {
+	s string
+}
+
+// String returns the string representation of the extension, including the
+// type tag.
+func (e Extension) String() string {
+	return e.s
+}
+
+// ParseExtension parses s as an extension and returns it on success.
+func ParseExtension(s string) (e Extension, err error) {
+	ext, err := language.ParseExtension(s)
+	return Extension{ext}, err
+}
+
+// Type returns the one-byte extension type of e. It returns 0 for the zero
+// exception.
+func (e Extension) Type() byte {
+	if e.s == "" {
+		return 0
+	}
+	return e.s[0]
+}
+
+// Tokens returns the list of tokens of e.
+func (e Extension) Tokens() []string {
+	return strings.Split(e.s, "-")
+}
+
+// Extension returns the extension of type x for tag t. It will return
+// false for ok if t does not have the requested extension. The returned
+// extension will be invalid in this case.
+func (t Tag) Extension(x byte) (ext Extension, ok bool) {
+	if !compact.Tag(t).MayHaveExtensions() {
+		return Extension{}, false
+	}
+	e, ok := t.tag().Extension(x)
+	return Extension{e}, ok
+}
+
+// Extensions returns all extensions of t.
+func (t Tag) Extensions() []Extension {
+	if !compact.Tag(t).MayHaveExtensions() {
+		return nil
+	}
+	e := []Extension{}
+	for _, ext := range t.tag().Extensions() {
+		e = append(e, Extension{ext})
+	}
+	return e
+}
+
+// TypeForKey returns the type associated with the given key, where key and type
+// are of the allowed values defined for the Unicode locale extension ('u') in
+// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
+// TypeForKey will traverse the inheritance chain to get the correct value.
+//
+// If there are multiple types associated with a key, only the first will be
+// returned. If there is no type associated with a key, it returns the empty
+// string.
+func (t Tag) TypeForKey(key string) string {
+	if !compact.Tag(t).MayHaveExtensions() {
+		if key != "rg" && key != "va" {
+			return ""
+		}
+	}
+	return t.tag().TypeForKey(key)
+}
+
+// SetTypeForKey returns a new Tag with the key set to type, where key and type
+// are of the allowed values defined for the Unicode locale extension ('u') in
+// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
+// An empty value removes an existing pair with the same key.
+func (t Tag) SetTypeForKey(key, value string) (Tag, error) {
+	tt, err := t.tag().SetTypeForKey(key, value)
+	return makeTag(tt), err
+}
+
+// NumCompactTags is the number of compact tags. The maximum tag is
+// NumCompactTags-1.
+const NumCompactTags = compact.NumCompactTags
+
+// CompactIndex returns an index, where 0 <= index < NumCompactTags, for tags
+// for which data exists in the text repository.The index will change over time
+// and should not be stored in persistent storage. If t does not match a compact
+// index, exact will be false and the compact index will be returned for the
+// first match after repeatedly taking the Parent of t.
+func CompactIndex(t Tag) (index int, exact bool) {
+	id, exact := compact.LanguageID(compact.Tag(t))
+	return int(id), exact
+}
+
+var root = language.Tag{}
+
+// Base is an ISO 639 language code, used for encoding the base language
+// of a language tag.
+type Base struct {
+	langID language.Language
+}
+
+// ParseBase parses a 2- or 3-letter ISO 639 code.
+// It returns a ValueError if s is a well-formed but unknown language identifier
+// or another error if another error occurred.
+func ParseBase(s string) (Base, error) {
+	l, err := language.ParseBase(s)
+	return Base{l}, err
+}
+
+// String returns the BCP 47 representation of the base language.
+func (b Base) String() string {
+	return b.langID.String()
+}
+
+// ISO3 returns the ISO 639-3 language code.
+func (b Base) ISO3() string {
+	return b.langID.ISO3()
+}
+
+// IsPrivateUse reports whether this language code is reserved for private use.
+func (b Base) IsPrivateUse() bool {
+	return b.langID.IsPrivateUse()
+}
+
+// Script is a 4-letter ISO 15924 code for representing scripts.
+// It is idiomatically represented in title case.
+type Script struct {
+	scriptID language.Script
+}
+
+// ParseScript parses a 4-letter ISO 15924 code.
+// It returns a ValueError if s is a well-formed but unknown script identifier
+// or another error if another error occurred.
+func ParseScript(s string) (Script, error) {
+	sc, err := language.ParseScript(s)
+	return Script{sc}, err
+}
+
+// String returns the script code in title case.
+// It returns "Zzzz" for an unspecified script.
+func (s Script) String() string {
+	return s.scriptID.String()
+}
+
+// IsPrivateUse reports whether this script code is reserved for private use.
+func (s Script) IsPrivateUse() bool {
+	return s.scriptID.IsPrivateUse()
+}
+
+// Region is an ISO 3166-1 or UN M.49 code for representing countries and regions.
+type Region struct {
+	regionID language.Region
+}
+
+// EncodeM49 returns the Region for the given UN M.49 code.
+// It returns an error if r is not a valid code.
+func EncodeM49(r int) (Region, error) {
+	rid, err := language.EncodeM49(r)
+	return Region{rid}, err
+}
+
+// ParseRegion parses a 2- or 3-letter ISO 3166-1 or a UN M.49 code.
+// It returns a ValueError if s is a well-formed but unknown region identifier
+// or another error if another error occurred.
+func ParseRegion(s string) (Region, error) {
+	r, err := language.ParseRegion(s)
+	return Region{r}, err
+}
+
+// String returns the BCP 47 representation for the region.
+// It returns "ZZ" for an unspecified region.
+func (r Region) String() string {
+	return r.regionID.String()
+}
+
+// ISO3 returns the 3-letter ISO code of r.
+// Note that not all regions have a 3-letter ISO code.
+// In such cases this method returns "ZZZ".
+func (r Region) ISO3() string {
+	return r.regionID.ISO3()
+}
+
+// M49 returns the UN M.49 encoding of r, or 0 if this encoding
+// is not defined for r.
+func (r Region) M49() int {
+	return r.regionID.M49()
+}
+
+// IsPrivateUse reports whether r has the ISO 3166 User-assigned status. This
+// may include private-use tags that are assigned by CLDR and used in this
+// implementation. So IsPrivateUse and IsCountry can be simultaneously true.
+func (r Region) IsPrivateUse() bool {
+	return r.regionID.IsPrivateUse()
+}
+
+// IsCountry returns whether this region is a country or autonomous area. This
+// includes non-standard definitions from CLDR.
+func (r Region) IsCountry() bool {
+	return r.regionID.IsCountry()
+}
+
+// IsGroup returns whether this region defines a collection of regions. This
+// includes non-standard definitions from CLDR.
+func (r Region) IsGroup() bool {
+	return r.regionID.IsGroup()
+}
+
+// Contains returns whether Region c is contained by Region r. It returns true
+// if c == r.
+func (r Region) Contains(c Region) bool {
+	return r.regionID.Contains(c.regionID)
+}
+
+// TLD returns the country code top-level domain (ccTLD). UK is returned for GB.
+// In all other cases it returns either the region itself or an error.
+//
+// This method may return an error for a region for which there exists a
+// canonical form with a ccTLD. To get that ccTLD canonicalize r first. The
+// region will already be canonicalized it was obtained from a Tag that was
+// obtained using any of the default methods.
+func (r Region) TLD() (Region, error) {
+	tld, err := r.regionID.TLD()
+	return Region{tld}, err
+}
+
+// Canonicalize returns the region or a possible replacement if the region is
+// deprecated. It will not return a replacement for deprecated regions that
+// are split into multiple regions.
+func (r Region) Canonicalize() Region {
+	return Region{r.regionID.Canonicalize()}
+}
+
+// Variant represents a registered variant of a language as defined by BCP 47.
+type Variant struct {
+	variant string
+}
+
+// ParseVariant parses and returns a Variant. An error is returned if s is not
+// a valid variant.
+func ParseVariant(s string) (Variant, error) {
+	v, err := language.ParseVariant(s)
+	return Variant{v.String()}, err
+}
+
+// String returns the string representation of the variant.
+func (v Variant) String() string {
+	return v.variant
+}
diff --git a/vendor/golang.org/x/text/language/match.go b/vendor/golang.org/x/text/language/match.go
new file mode 100644
index 000000000..1153baf29
--- /dev/null
+++ b/vendor/golang.org/x/text/language/match.go
@@ -0,0 +1,735 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+import (
+	"errors"
+	"strings"
+
+	"golang.org/x/text/internal/language"
+)
+
+// A MatchOption configures a Matcher.
+type MatchOption func(*matcher)
+
+// PreferSameScript will, in the absence of a match, result in the first
+// preferred tag with the same script as a supported tag to match this supported
+// tag. The default is currently true, but this may change in the future.
+func PreferSameScript(preferSame bool) MatchOption {
+	return func(m *matcher) { m.preferSameScript = preferSame }
+}
+
+// TODO(v1.0.0): consider making Matcher a concrete type, instead of interface.
+// There doesn't seem to be too much need for multiple types.
+// Making it a concrete type allows MatchStrings to be a method, which will
+// improve its discoverability.
+
+// MatchStrings parses and matches the given strings until one of them matches
+// the language in the Matcher. A string may be an Accept-Language header as
+// handled by ParseAcceptLanguage. The default language is returned if no
+// other language matched.
+func MatchStrings(m Matcher, lang ...string) (tag Tag, index int) {
+	for _, accept := range lang {
+		desired, _, err := ParseAcceptLanguage(accept)
+		if err != nil {
+			continue
+		}
+		if tag, index, conf := m.Match(desired...); conf != No {
+			return tag, index
+		}
+	}
+	tag, index, _ = m.Match()
+	return
+}
+
+// Matcher is the interface that wraps the Match method.
+//
+// Match returns the best match for any of the given tags, along with
+// a unique index associated with the returned tag and a confidence
+// score.
+type Matcher interface {
+	Match(t ...Tag) (tag Tag, index int, c Confidence)
+}
+
+// Comprehends reports the confidence score for a speaker of a given language
+// to being able to comprehend the written form of an alternative language.
+func Comprehends(speaker, alternative Tag) Confidence {
+	_, _, c := NewMatcher([]Tag{alternative}).Match(speaker)
+	return c
+}
+
+// NewMatcher returns a Matcher that matches an ordered list of preferred tags
+// against a list of supported tags based on written intelligibility, closeness
+// of dialect, equivalence of subtags and various other rules. It is initialized
+// with the list of supported tags. The first element is used as the default
+// value in case no match is found.
+//
+// Its Match method matches the first of the given Tags to reach a certain
+// confidence threshold. The tags passed to Match should therefore be specified
+// in order of preference. Extensions are ignored for matching.
+//
+// The index returned by the Match method corresponds to the index of the
+// matched tag in t, but is augmented with the Unicode extension ('u')of the
+// corresponding preferred tag. This allows user locale options to be passed
+// transparently.
+func NewMatcher(t []Tag, options ...MatchOption) Matcher {
+	return newMatcher(t, options)
+}
+
+func (m *matcher) Match(want ...Tag) (t Tag, index int, c Confidence) {
+	var tt language.Tag
+	match, w, c := m.getBest(want...)
+	if match != nil {
+		tt, index = match.tag, match.index
+	} else {
+		// TODO: this should be an option
+		tt = m.default_.tag
+		if m.preferSameScript {
+		outer:
+			for _, w := range want {
+				script, _ := w.Script()
+				if script.scriptID == 0 {
+					// Don't do anything if there is no script, such as with
+					// private subtags.
+					continue
+				}
+				for i, h := range m.supported {
+					if script.scriptID == h.maxScript {
+						tt, index = h.tag, i
+						break outer
+					}
+				}
+			}
+		}
+		// TODO: select first language tag based on script.
+	}
+	if w.RegionID != tt.RegionID && w.RegionID != 0 {
+		if w.RegionID != 0 && tt.RegionID != 0 && tt.RegionID.Contains(w.RegionID) {
+			tt.RegionID = w.RegionID
+			tt.RemakeString()
+		} else if r := w.RegionID.String(); len(r) == 2 {
+			// TODO: also filter macro and deprecated.
+			tt, _ = tt.SetTypeForKey("rg", strings.ToLower(r)+"zzzz")
+		}
+	}
+	// Copy options from the user-provided tag into the result tag. This is hard
+	// to do after the fact, so we do it here.
+	// TODO: add in alternative variants to -u-va-.
+	// TODO: add preferred region to -u-rg-.
+	if e := w.Extensions(); len(e) > 0 {
+		b := language.Builder{}
+		b.SetTag(tt)
+		for _, e := range e {
+			b.AddExt(e)
+		}
+		tt = b.Make()
+	}
+	return makeTag(tt), index, c
+}
+
+// ErrMissingLikelyTagsData indicates no information was available
+// to compute likely values of missing tags.
+var ErrMissingLikelyTagsData = errors.New("missing likely tags data")
+
+// func (t *Tag) setTagsFrom(id Tag) {
+// 	t.LangID = id.LangID
+// 	t.ScriptID = id.ScriptID
+// 	t.RegionID = id.RegionID
+// }
+
+// Tag Matching
+// CLDR defines an algorithm for finding the best match between two sets of language
+// tags. The basic algorithm defines how to score a possible match and then find
+// the match with the best score
+// (see https://www.unicode.org/reports/tr35/#LanguageMatching).
+// Using scoring has several disadvantages. The scoring obfuscates the importance of
+// the various factors considered, making the algorithm harder to understand. Using
+// scoring also requires the full score to be computed for each pair of tags.
+//
+// We will use a different algorithm which aims to have the following properties:
+// - clarity on the precedence of the various selection factors, and
+// - improved performance by allowing early termination of a comparison.
+//
+// Matching algorithm (overview)
+// Input:
+//   - supported: a set of supported tags
+//   - default:   the default tag to return in case there is no match
+//   - desired:   list of desired tags, ordered by preference, starting with
+//                the most-preferred.
+//
+// Algorithm:
+//   1) Set the best match to the lowest confidence level
+//   2) For each tag in "desired":
+//     a) For each tag in "supported":
+//        1) compute the match between the two tags.
+//        2) if the match is better than the previous best match, replace it
+//           with the new match. (see next section)
+//     b) if the current best match is Exact and pin is true the result will be
+//        frozen to the language found thusfar, although better matches may
+//        still be found for the same language.
+//   3) If the best match so far is below a certain threshold, return "default".
+//
+// Ranking:
+// We use two phases to determine whether one pair of tags are a better match
+// than another pair of tags. First, we determine a rough confidence level. If the
+// levels are different, the one with the highest confidence wins.
+// Second, if the rough confidence levels are identical, we use a set of tie-breaker
+// rules.
+//
+// The confidence level of matching a pair of tags is determined by finding the
+// lowest confidence level of any matches of the corresponding subtags (the
+// result is deemed as good as its weakest link).
+// We define the following levels:
+//   Exact    - An exact match of a subtag, before adding likely subtags.
+//   MaxExact - An exact match of a subtag, after adding likely subtags.
+//              [See Note 2].
+//   High     - High level of mutual intelligibility between different subtag
+//              variants.
+//   Low      - Low level of mutual intelligibility between different subtag
+//              variants.
+//   No       - No mutual intelligibility.
+//
+// The following levels can occur for each type of subtag:
+//   Base:    Exact, MaxExact, High, Low, No
+//   Script:  Exact, MaxExact [see Note 3], Low, No
+//   Region:  Exact, MaxExact, High
+//   Variant: Exact, High
+//   Private: Exact, No
+//
+// Any result with a confidence level of Low or higher is deemed a possible match.
+// Once a desired tag matches any of the supported tags with a level of MaxExact
+// or higher, the next desired tag is not considered (see Step 2.b).
+// Note that CLDR provides languageMatching data that defines close equivalence
+// classes for base languages, scripts and regions.
+//
+// Tie-breaking
+// If we get the same confidence level for two matches, we apply a sequence of
+// tie-breaking rules. The first that succeeds defines the result. The rules are
+// applied in the following order.
+//   1) Original language was defined and was identical.
+//   2) Original region was defined and was identical.
+//   3) Distance between two maximized regions was the smallest.
+//   4) Original script was defined and was identical.
+//   5) Distance from want tag to have tag using the parent relation [see Note 5.]
+// If there is still no winner after these rules are applied, the first match
+// found wins.
+//
+// Notes:
+// [2] In practice, as matching of Exact is done in a separate phase from
+//     matching the other levels, we reuse the Exact level to mean MaxExact in
+//     the second phase. As a consequence, we only need the levels defined by
+//     the Confidence type. The MaxExact confidence level is mapped to High in
+//     the public API.
+// [3] We do not differentiate between maximized script values that were derived
+//     from suppressScript versus most likely tag data. We determined that in
+//     ranking the two, one ranks just after the other. Moreover, the two cannot
+//     occur concurrently. As a consequence, they are identical for practical
+//     purposes.
+// [4] In case of deprecated, macro-equivalents and legacy mappings, we assign
+//     the MaxExact level to allow iw vs he to still be a closer match than
+//     en-AU vs en-US, for example.
+// [5] In CLDR a locale inherits fields that are unspecified for this locale
+//     from its parent. Therefore, if a locale is a parent of another locale,
+//     it is a strong measure for closeness, especially when no other tie
+//     breaker rule applies. One could also argue it is inconsistent, for
+//     example, when pt-AO matches pt (which CLDR equates with pt-BR), even
+//     though its parent is pt-PT according to the inheritance rules.
+//
+// Implementation Details:
+// There are several performance considerations worth pointing out. Most notably,
+// we preprocess as much as possible (within reason) at the time of creation of a
+// matcher. This includes:
+//   - creating a per-language map, which includes data for the raw base language
+//     and its canonicalized variant (if applicable),
+//   - expanding entries for the equivalence classes defined in CLDR's
+//     languageMatch data.
+// The per-language map ensures that typically only a very small number of tags
+// need to be considered. The pre-expansion of canonicalized subtags and
+// equivalence classes reduces the amount of map lookups that need to be done at
+// runtime.
+
+// matcher keeps a set of supported language tags, indexed by language.
+type matcher struct {
+	default_         *haveTag
+	supported        []*haveTag
+	index            map[language.Language]*matchHeader
+	passSettings     bool
+	preferSameScript bool
+}
+
+// matchHeader has the lists of tags for exact matches and matches based on
+// maximized and canonicalized tags for a given language.
+type matchHeader struct {
+	haveTags []*haveTag
+	original bool
+}
+
+// haveTag holds a supported Tag and its maximized script and region. The maximized
+// or canonicalized language is not stored as it is not needed during matching.
+type haveTag struct {
+	tag language.Tag
+
+	// index of this tag in the original list of supported tags.
+	index int
+
+	// conf is the maximum confidence that can result from matching this haveTag.
+	// When conf < Exact this means it was inserted after applying a CLDR equivalence rule.
+	conf Confidence
+
+	// Maximized region and script.
+	maxRegion language.Region
+	maxScript language.Script
+
+	// altScript may be checked as an alternative match to maxScript. If altScript
+	// matches, the confidence level for this match is Low. Theoretically there
+	// could be multiple alternative scripts. This does not occur in practice.
+	altScript language.Script
+
+	// nextMax is the index of the next haveTag with the same maximized tags.
+	nextMax uint16
+}
+
+func makeHaveTag(tag language.Tag, index int) (haveTag, language.Language) {
+	max := tag
+	if tag.LangID != 0 || tag.RegionID != 0 || tag.ScriptID != 0 {
+		max, _ = canonicalize(All, max)
+		max, _ = max.Maximize()
+		max.RemakeString()
+	}
+	return haveTag{tag, index, Exact, max.RegionID, max.ScriptID, altScript(max.LangID, max.ScriptID), 0}, max.LangID
+}
+
+// altScript returns an alternative script that may match the given script with
+// a low confidence.  At the moment, the langMatch data allows for at most one
+// script to map to another and we rely on this to keep the code simple.
+func altScript(l language.Language, s language.Script) language.Script {
+	for _, alt := range matchScript {
+		// TODO: also match cases where language is not the same.
+		if (language.Language(alt.wantLang) == l || language.Language(alt.haveLang) == l) &&
+			language.Script(alt.haveScript) == s {
+			return language.Script(alt.wantScript)
+		}
+	}
+	return 0
+}
+
+// addIfNew adds a haveTag to the list of tags only if it is a unique tag.
+// Tags that have the same maximized values are linked by index.
+func (h *matchHeader) addIfNew(n haveTag, exact bool) {
+	h.original = h.original || exact
+	// Don't add new exact matches.
+	for _, v := range h.haveTags {
+		if equalsRest(v.tag, n.tag) {
+			return
+		}
+	}
+	// Allow duplicate maximized tags, but create a linked list to allow quickly
+	// comparing the equivalents and bail out.
+	for i, v := range h.haveTags {
+		if v.maxScript == n.maxScript &&
+			v.maxRegion == n.maxRegion &&
+			v.tag.VariantOrPrivateUseTags() == n.tag.VariantOrPrivateUseTags() {
+			for h.haveTags[i].nextMax != 0 {
+				i = int(h.haveTags[i].nextMax)
+			}
+			h.haveTags[i].nextMax = uint16(len(h.haveTags))
+			break
+		}
+	}
+	h.haveTags = append(h.haveTags, &n)
+}
+
+// header returns the matchHeader for the given language. It creates one if
+// it doesn't already exist.
+func (m *matcher) header(l language.Language) *matchHeader {
+	if h := m.index[l]; h != nil {
+		return h
+	}
+	h := &matchHeader{}
+	m.index[l] = h
+	return h
+}
+
+func toConf(d uint8) Confidence {
+	if d <= 10 {
+		return High
+	}
+	if d < 30 {
+		return Low
+	}
+	return No
+}
+
+// newMatcher builds an index for the given supported tags and returns it as
+// a matcher. It also expands the index by considering various equivalence classes
+// for a given tag.
+func newMatcher(supported []Tag, options []MatchOption) *matcher {
+	m := &matcher{
+		index:            make(map[language.Language]*matchHeader),
+		preferSameScript: true,
+	}
+	for _, o := range options {
+		o(m)
+	}
+	if len(supported) == 0 {
+		m.default_ = &haveTag{}
+		return m
+	}
+	// Add supported languages to the index. Add exact matches first to give
+	// them precedence.
+	for i, tag := range supported {
+		tt := tag.tag()
+		pair, _ := makeHaveTag(tt, i)
+		m.header(tt.LangID).addIfNew(pair, true)
+		m.supported = append(m.supported, &pair)
+	}
+	m.default_ = m.header(supported[0].lang()).haveTags[0]
+	// Keep these in two different loops to support the case that two equivalent
+	// languages are distinguished, such as iw and he.
+	for i, tag := range supported {
+		tt := tag.tag()
+		pair, max := makeHaveTag(tt, i)
+		if max != tt.LangID {
+			m.header(max).addIfNew(pair, true)
+		}
+	}
+
+	// update is used to add indexes in the map for equivalent languages.
+	// update will only add entries to original indexes, thus not computing any
+	// transitive relations.
+	update := func(want, have uint16, conf Confidence) {
+		if hh := m.index[language.Language(have)]; hh != nil {
+			if !hh.original {
+				return
+			}
+			hw := m.header(language.Language(want))
+			for _, ht := range hh.haveTags {
+				v := *ht
+				if conf < v.conf {
+					v.conf = conf
+				}
+				v.nextMax = 0 // this value needs to be recomputed
+				if v.altScript != 0 {
+					v.altScript = altScript(language.Language(want), v.maxScript)
+				}
+				hw.addIfNew(v, conf == Exact && hh.original)
+			}
+		}
+	}
+
+	// Add entries for languages with mutual intelligibility as defined by CLDR's
+	// languageMatch data.
+	for _, ml := range matchLang {
+		update(ml.want, ml.have, toConf(ml.distance))
+		if !ml.oneway {
+			update(ml.have, ml.want, toConf(ml.distance))
+		}
+	}
+
+	// Add entries for possible canonicalizations. This is an optimization to
+	// ensure that only one map lookup needs to be done at runtime per desired tag.
+	// First we match deprecated equivalents. If they are perfect equivalents
+	// (their canonicalization simply substitutes a different language code, but
+	// nothing else), the match confidence is Exact, otherwise it is High.
+	for i, lm := range language.AliasMap {
+		// If deprecated codes match and there is no fiddling with the script
+		// or region, we consider it an exact match.
+		conf := Exact
+		if language.AliasTypes[i] != language.Macro {
+			if !isExactEquivalent(language.Language(lm.From)) {
+				conf = High
+			}
+			update(lm.To, lm.From, conf)
+		}
+		update(lm.From, lm.To, conf)
+	}
+	return m
+}
+
+// getBest gets the best matching tag in m for any of the given tags, taking into
+// account the order of preference of the given tags.
+func (m *matcher) getBest(want ...Tag) (got *haveTag, orig language.Tag, c Confidence) {
+	best := bestMatch{}
+	for i, ww := range want {
+		w := ww.tag()
+		var max language.Tag
+		// Check for exact match first.
+		h := m.index[w.LangID]
+		if w.LangID != 0 {
+			if h == nil {
+				continue
+			}
+			// Base language is defined.
+			max, _ = canonicalize(Legacy|Deprecated|Macro, w)
+			// A region that is added through canonicalization is stronger than
+			// a maximized region: set it in the original (e.g. mo -> ro-MD).
+			if w.RegionID != max.RegionID {
+				w.RegionID = max.RegionID
+			}
+			// TODO: should we do the same for scripts?
+			// See test case: en, sr, nl ; sh ; sr
+			max, _ = max.Maximize()
+		} else {
+			// Base language is not defined.
+			if h != nil {
+				for i := range h.haveTags {
+					have := h.haveTags[i]
+					if equalsRest(have.tag, w) {
+						return have, w, Exact
+					}
+				}
+			}
+			if w.ScriptID == 0 && w.RegionID == 0 {
+				// We skip all tags matching und for approximate matching, including
+				// private tags.
+				continue
+			}
+			max, _ = w.Maximize()
+			if h = m.index[max.LangID]; h == nil {
+				continue
+			}
+		}
+		pin := true
+		for _, t := range want[i+1:] {
+			if w.LangID == t.lang() {
+				pin = false
+				break
+			}
+		}
+		// Check for match based on maximized tag.
+		for i := range h.haveTags {
+			have := h.haveTags[i]
+			best.update(have, w, max.ScriptID, max.RegionID, pin)
+			if best.conf == Exact {
+				for have.nextMax != 0 {
+					have = h.haveTags[have.nextMax]
+					best.update(have, w, max.ScriptID, max.RegionID, pin)
+				}
+				return best.have, best.want, best.conf
+			}
+		}
+	}
+	if best.conf <= No {
+		if len(want) != 0 {
+			return nil, want[0].tag(), No
+		}
+		return nil, language.Tag{}, No
+	}
+	return best.have, best.want, best.conf
+}
+
+// bestMatch accumulates the best match so far.
+type bestMatch struct {
+	have            *haveTag
+	want            language.Tag
+	conf            Confidence
+	pinnedRegion    language.Region
+	pinLanguage     bool
+	sameRegionGroup bool
+	// Cached results from applying tie-breaking rules.
+	origLang     bool
+	origReg      bool
+	paradigmReg  bool
+	regGroupDist uint8
+	origScript   bool
+}
+
+// update updates the existing best match if the new pair is considered to be a
+// better match. To determine if the given pair is a better match, it first
+// computes the rough confidence level. If this surpasses the current match, it
+// will replace it and update the tie-breaker rule cache. If there is a tie, it
+// proceeds with applying a series of tie-breaker rules. If there is no
+// conclusive winner after applying the tie-breaker rules, it leaves the current
+// match as the preferred match.
+//
+// If pin is true and have and tag are a strong match, it will henceforth only
+// consider matches for this language. This corresponds to the idea that most
+// users have a strong preference for the first defined language. A user can
+// still prefer a second language over a dialect of the preferred language by
+// explicitly specifying dialects, e.g. "en, nl, en-GB". In this case pin should
+// be false.
+func (m *bestMatch) update(have *haveTag, tag language.Tag, maxScript language.Script, maxRegion language.Region, pin bool) {
+	// Bail if the maximum attainable confidence is below that of the current best match.
+	c := have.conf
+	if c < m.conf {
+		return
+	}
+	// Don't change the language once we already have found an exact match.
+	if m.pinLanguage && tag.LangID != m.want.LangID {
+		return
+	}
+	// Pin the region group if we are comparing tags for the same language.
+	if tag.LangID == m.want.LangID && m.sameRegionGroup {
+		_, sameGroup := regionGroupDist(m.pinnedRegion, have.maxRegion, have.maxScript, m.want.LangID)
+		if !sameGroup {
+			return
+		}
+	}
+	if c == Exact && have.maxScript == maxScript {
+		// If there is another language and then another entry of this language,
+		// don't pin anything, otherwise pin the language.
+		m.pinLanguage = pin
+	}
+	if equalsRest(have.tag, tag) {
+	} else if have.maxScript != maxScript {
+		// There is usually very little comprehension between different scripts.
+		// In a few cases there may still be Low comprehension. This possibility
+		// is pre-computed and stored in have.altScript.
+		if Low < m.conf || have.altScript != maxScript {
+			return
+		}
+		c = Low
+	} else if have.maxRegion != maxRegion {
+		if High < c {
+			// There is usually a small difference between languages across regions.
+			c = High
+		}
+	}
+
+	// We store the results of the computations of the tie-breaker rules along
+	// with the best match. There is no need to do the checks once we determine
+	// we have a winner, but we do still need to do the tie-breaker computations.
+	// We use "beaten" to keep track if we still need to do the checks.
+	beaten := false // true if the new pair defeats the current one.
+	if c != m.conf {
+		if c < m.conf {
+			return
+		}
+		beaten = true
+	}
+
+	// Tie-breaker rules:
+	// We prefer if the pre-maximized language was specified and identical.
+	origLang := have.tag.LangID == tag.LangID && tag.LangID != 0
+	if !beaten && m.origLang != origLang {
+		if m.origLang {
+			return
+		}
+		beaten = true
+	}
+
+	// We prefer if the pre-maximized region was specified and identical.
+	origReg := have.tag.RegionID == tag.RegionID && tag.RegionID != 0
+	if !beaten && m.origReg != origReg {
+		if m.origReg {
+			return
+		}
+		beaten = true
+	}
+
+	regGroupDist, sameGroup := regionGroupDist(have.maxRegion, maxRegion, maxScript, tag.LangID)
+	if !beaten && m.regGroupDist != regGroupDist {
+		if regGroupDist > m.regGroupDist {
+			return
+		}
+		beaten = true
+	}
+
+	paradigmReg := isParadigmLocale(tag.LangID, have.maxRegion)
+	if !beaten && m.paradigmReg != paradigmReg {
+		if !paradigmReg {
+			return
+		}
+		beaten = true
+	}
+
+	// Next we prefer if the pre-maximized script was specified and identical.
+	origScript := have.tag.ScriptID == tag.ScriptID && tag.ScriptID != 0
+	if !beaten && m.origScript != origScript {
+		if m.origScript {
+			return
+		}
+		beaten = true
+	}
+
+	// Update m to the newly found best match.
+	if beaten {
+		m.have = have
+		m.want = tag
+		m.conf = c
+		m.pinnedRegion = maxRegion
+		m.sameRegionGroup = sameGroup
+		m.origLang = origLang
+		m.origReg = origReg
+		m.paradigmReg = paradigmReg
+		m.origScript = origScript
+		m.regGroupDist = regGroupDist
+	}
+}
+
+func isParadigmLocale(lang language.Language, r language.Region) bool {
+	for _, e := range paradigmLocales {
+		if language.Language(e[0]) == lang && (r == language.Region(e[1]) || r == language.Region(e[2])) {
+			return true
+		}
+	}
+	return false
+}
+
+// regionGroupDist computes the distance between two regions based on their
+// CLDR grouping.
+func regionGroupDist(a, b language.Region, script language.Script, lang language.Language) (dist uint8, same bool) {
+	const defaultDistance = 4
+
+	aGroup := uint(regionToGroups[a]) << 1
+	bGroup := uint(regionToGroups[b]) << 1
+	for _, ri := range matchRegion {
+		if language.Language(ri.lang) == lang && (ri.script == 0 || language.Script(ri.script) == script) {
+			group := uint(1 << (ri.group &^ 0x80))
+			if 0x80&ri.group == 0 {
+				if aGroup&bGroup&group != 0 { // Both regions are in the group.
+					return ri.distance, ri.distance == defaultDistance
+				}
+			} else {
+				if (aGroup|bGroup)&group == 0 { // Both regions are not in the group.
+					return ri.distance, ri.distance == defaultDistance
+				}
+			}
+		}
+	}
+	return defaultDistance, true
+}
+
+// equalsRest compares everything except the language.
+func equalsRest(a, b language.Tag) bool {
+	// TODO: don't include extensions in this comparison. To do this efficiently,
+	// though, we should handle private tags separately.
+	return a.ScriptID == b.ScriptID && a.RegionID == b.RegionID && a.VariantOrPrivateUseTags() == b.VariantOrPrivateUseTags()
+}
+
+// isExactEquivalent returns true if canonicalizing the language will not alter
+// the script or region of a tag.
+func isExactEquivalent(l language.Language) bool {
+	for _, o := range notEquivalent {
+		if o == l {
+			return false
+		}
+	}
+	return true
+}
+
+var notEquivalent []language.Language
+
+func init() {
+	// Create a list of all languages for which canonicalization may alter the
+	// script or region.
+	for _, lm := range language.AliasMap {
+		tag := language.Tag{LangID: language.Language(lm.From)}
+		if tag, _ = canonicalize(All, tag); tag.ScriptID != 0 || tag.RegionID != 0 {
+			notEquivalent = append(notEquivalent, language.Language(lm.From))
+		}
+	}
+	// Maximize undefined regions of paradigm locales.
+	for i, v := range paradigmLocales {
+		t := language.Tag{LangID: language.Language(v[0])}
+		max, _ := t.Maximize()
+		if v[1] == 0 {
+			paradigmLocales[i][1] = uint16(max.RegionID)
+		}
+		if v[2] == 0 {
+			paradigmLocales[i][2] = uint16(max.RegionID)
+		}
+	}
+}
diff --git a/vendor/golang.org/x/text/language/parse.go b/vendor/golang.org/x/text/language/parse.go
new file mode 100644
index 000000000..053336e28
--- /dev/null
+++ b/vendor/golang.org/x/text/language/parse.go
@@ -0,0 +1,256 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+import (
+	"errors"
+	"sort"
+	"strconv"
+	"strings"
+
+	"golang.org/x/text/internal/language"
+)
+
+// ValueError is returned by any of the parsing functions when the
+// input is well-formed but the respective subtag is not recognized
+// as a valid value.
+type ValueError interface {
+	error
+
+	// Subtag returns the subtag for which the error occurred.
+	Subtag() string
+}
+
+// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
+// failed it returns an error and any part of the tag that could be parsed.
+// If parsing succeeded but an unknown value was found, it returns
+// ValueError. The Tag returned in this case is just stripped of the unknown
+// value. All other values are preserved. It accepts tags in the BCP 47 format
+// and extensions to this standard defined in
+// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
+// The resulting tag is canonicalized using the default canonicalization type.
+func Parse(s string) (t Tag, err error) {
+	return Default.Parse(s)
+}
+
+// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
+// failed it returns an error and any part of the tag that could be parsed.
+// If parsing succeeded but an unknown value was found, it returns
+// ValueError. The Tag returned in this case is just stripped of the unknown
+// value. All other values are preserved. It accepts tags in the BCP 47 format
+// and extensions to this standard defined in
+// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
+// The resulting tag is canonicalized using the canonicalization type c.
+func (c CanonType) Parse(s string) (t Tag, err error) {
+	defer func() {
+		if recover() != nil {
+			t = Tag{}
+			err = language.ErrSyntax
+		}
+	}()
+
+	tt, err := language.Parse(s)
+	if err != nil {
+		return makeTag(tt), err
+	}
+	tt, changed := canonicalize(c, tt)
+	if changed {
+		tt.RemakeString()
+	}
+	return makeTag(tt), nil
+}
+
+// Compose creates a Tag from individual parts, which may be of type Tag, Base,
+// Script, Region, Variant, []Variant, Extension, []Extension or error. If a
+// Base, Script or Region or slice of type Variant or Extension is passed more
+// than once, the latter will overwrite the former. Variants and Extensions are
+// accumulated, but if two extensions of the same type are passed, the latter
+// will replace the former. For -u extensions, though, the key-type pairs are
+// added, where later values overwrite older ones. A Tag overwrites all former
+// values and typically only makes sense as the first argument. The resulting
+// tag is returned after canonicalizing using the Default CanonType. If one or
+// more errors are encountered, one of the errors is returned.
+func Compose(part ...interface{}) (t Tag, err error) {
+	return Default.Compose(part...)
+}
+
+// Compose creates a Tag from individual parts, which may be of type Tag, Base,
+// Script, Region, Variant, []Variant, Extension, []Extension or error. If a
+// Base, Script or Region or slice of type Variant or Extension is passed more
+// than once, the latter will overwrite the former. Variants and Extensions are
+// accumulated, but if two extensions of the same type are passed, the latter
+// will replace the former. For -u extensions, though, the key-type pairs are
+// added, where later values overwrite older ones. A Tag overwrites all former
+// values and typically only makes sense as the first argument. The resulting
+// tag is returned after canonicalizing using CanonType c. If one or more errors
+// are encountered, one of the errors is returned.
+func (c CanonType) Compose(part ...interface{}) (t Tag, err error) {
+	defer func() {
+		if recover() != nil {
+			t = Tag{}
+			err = language.ErrSyntax
+		}
+	}()
+
+	var b language.Builder
+	if err = update(&b, part...); err != nil {
+		return und, err
+	}
+	b.Tag, _ = canonicalize(c, b.Tag)
+	return makeTag(b.Make()), err
+}
+
+var errInvalidArgument = errors.New("invalid Extension or Variant")
+
+func update(b *language.Builder, part ...interface{}) (err error) {
+	for _, x := range part {
+		switch v := x.(type) {
+		case Tag:
+			b.SetTag(v.tag())
+		case Base:
+			b.Tag.LangID = v.langID
+		case Script:
+			b.Tag.ScriptID = v.scriptID
+		case Region:
+			b.Tag.RegionID = v.regionID
+		case Variant:
+			if v.variant == "" {
+				err = errInvalidArgument
+				break
+			}
+			b.AddVariant(v.variant)
+		case Extension:
+			if v.s == "" {
+				err = errInvalidArgument
+				break
+			}
+			b.SetExt(v.s)
+		case []Variant:
+			b.ClearVariants()
+			for _, v := range v {
+				b.AddVariant(v.variant)
+			}
+		case []Extension:
+			b.ClearExtensions()
+			for _, e := range v {
+				b.SetExt(e.s)
+			}
+		// TODO: support parsing of raw strings based on morphology or just extensions?
+		case error:
+			if v != nil {
+				err = v
+			}
+		}
+	}
+	return
+}
+
+var errInvalidWeight = errors.New("ParseAcceptLanguage: invalid weight")
+var errTagListTooLarge = errors.New("tag list exceeds max length")
+
+// ParseAcceptLanguage parses the contents of an Accept-Language header as
+// defined in http://www.ietf.org/rfc/rfc2616.txt and returns a list of Tags and
+// a list of corresponding quality weights. It is more permissive than RFC 2616
+// and may return non-nil slices even if the input is not valid.
+// The Tags will be sorted by highest weight first and then by first occurrence.
+// Tags with a weight of zero will be dropped. An error will be returned if the
+// input could not be parsed.
+func ParseAcceptLanguage(s string) (tag []Tag, q []float32, err error) {
+	defer func() {
+		if recover() != nil {
+			tag = nil
+			q = nil
+			err = language.ErrSyntax
+		}
+	}()
+
+	if strings.Count(s, "-") > 1000 {
+		return nil, nil, errTagListTooLarge
+	}
+
+	var entry string
+	for s != "" {
+		if entry, s = split(s, ','); entry == "" {
+			continue
+		}
+
+		entry, weight := split(entry, ';')
+
+		// Scan the language.
+		t, err := Parse(entry)
+		if err != nil {
+			id, ok := acceptFallback[entry]
+			if !ok {
+				return nil, nil, err
+			}
+			t = makeTag(language.Tag{LangID: id})
+		}
+
+		// Scan the optional weight.
+		w := 1.0
+		if weight != "" {
+			weight = consume(weight, 'q')
+			weight = consume(weight, '=')
+			// consume returns the empty string when a token could not be
+			// consumed, resulting in an error for ParseFloat.
+			if w, err = strconv.ParseFloat(weight, 32); err != nil {
+				return nil, nil, errInvalidWeight
+			}
+			// Drop tags with a quality weight of 0.
+			if w <= 0 {
+				continue
+			}
+		}
+
+		tag = append(tag, t)
+		q = append(q, float32(w))
+	}
+	sort.Stable(&tagSort{tag, q})
+	return tag, q, nil
+}
+
+// consume removes a leading token c from s and returns the result or the empty
+// string if there is no such token.
+func consume(s string, c byte) string {
+	if s == "" || s[0] != c {
+		return ""
+	}
+	return strings.TrimSpace(s[1:])
+}
+
+func split(s string, c byte) (head, tail string) {
+	if i := strings.IndexByte(s, c); i >= 0 {
+		return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+1:])
+	}
+	return strings.TrimSpace(s), ""
+}
+
+// Add hack mapping to deal with a small number of cases that occur
+// in Accept-Language (with reasonable frequency).
+var acceptFallback = map[string]language.Language{
+	"english": _en,
+	"deutsch": _de,
+	"italian": _it,
+	"french":  _fr,
+	"*":       _mul, // defined in the spec to match all languages.
+}
+
+type tagSort struct {
+	tag []Tag
+	q   []float32
+}
+
+func (s *tagSort) Len() int {
+	return len(s.q)
+}
+
+func (s *tagSort) Less(i, j int) bool {
+	return s.q[i] > s.q[j]
+}
+
+func (s *tagSort) Swap(i, j int) {
+	s.tag[i], s.tag[j] = s.tag[j], s.tag[i]
+	s.q[i], s.q[j] = s.q[j], s.q[i]
+}
diff --git a/vendor/golang.org/x/text/language/tables.go b/vendor/golang.org/x/text/language/tables.go
new file mode 100644
index 000000000..a6573dcb2
--- /dev/null
+++ b/vendor/golang.org/x/text/language/tables.go
@@ -0,0 +1,298 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package language
+
+// CLDRVersion is the CLDR version from which the tables in this package are derived.
+const CLDRVersion = "32"
+
+const (
+	_de  = 269
+	_en  = 313
+	_fr  = 350
+	_it  = 505
+	_mo  = 784
+	_no  = 879
+	_nb  = 839
+	_pt  = 960
+	_sh  = 1031
+	_mul = 806
+	_und = 0
+)
+const (
+	_001 = 1
+	_419 = 31
+	_BR  = 65
+	_CA  = 73
+	_ES  = 111
+	_GB  = 124
+	_MD  = 189
+	_PT  = 239
+	_UK  = 307
+	_US  = 310
+	_ZZ  = 358
+	_XA  = 324
+	_XC  = 326
+	_XK  = 334
+)
+const (
+	_Latn = 91
+	_Hani = 57
+	_Hans = 59
+	_Hant = 60
+	_Qaaa = 149
+	_Qaai = 157
+	_Qabx = 198
+	_Zinh = 255
+	_Zyyy = 260
+	_Zzzz = 261
+)
+
+var regionToGroups = []uint8{ // 359 elements
+	// Entry 0 - 3F
+	0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04,
+	0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00,
+	0x00, 0x04, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x04,
+	// Entry 40 - 7F
+	0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04,
+	0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00,
+	0x08, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
+	// Entry 80 - BF
+	0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00,
+	0x00, 0x00, 0x04, 0x01, 0x00, 0x04, 0x02, 0x00,
+	0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
+	0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x04,
+	// Entry C0 - FF
+	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+	0x01, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00,
+	0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	// Entry 100 - 13F
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+	0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x04,
+	0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x05, 0x00,
+	// Entry 140 - 17F
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+} // Size: 383 bytes
+
+var paradigmLocales = [][3]uint16{ // 3 elements
+	0: [3]uint16{0x139, 0x0, 0x7c},
+	1: [3]uint16{0x13e, 0x0, 0x1f},
+	2: [3]uint16{0x3c0, 0x41, 0xef},
+} // Size: 42 bytes
+
+type mutualIntelligibility struct {
+	want     uint16
+	have     uint16
+	distance uint8
+	oneway   bool
+}
+type scriptIntelligibility struct {
+	wantLang   uint16
+	haveLang   uint16
+	wantScript uint8
+	haveScript uint8
+	distance   uint8
+}
+type regionIntelligibility struct {
+	lang     uint16
+	script   uint8
+	group    uint8
+	distance uint8
+}
+
+// matchLang holds pairs of langIDs of base languages that are typically
+// mutually intelligible. Each pair is associated with a confidence and
+// whether the intelligibility goes one or both ways.
+var matchLang = []mutualIntelligibility{ // 113 elements
+	0:   {want: 0x1d1, have: 0xb7, distance: 0x4, oneway: false},
+	1:   {want: 0x407, have: 0xb7, distance: 0x4, oneway: false},
+	2:   {want: 0x407, have: 0x1d1, distance: 0x4, oneway: false},
+	3:   {want: 0x407, have: 0x432, distance: 0x4, oneway: false},
+	4:   {want: 0x43a, have: 0x1, distance: 0x4, oneway: false},
+	5:   {want: 0x1a3, have: 0x10d, distance: 0x4, oneway: true},
+	6:   {want: 0x295, have: 0x10d, distance: 0x4, oneway: true},
+	7:   {want: 0x101, have: 0x36f, distance: 0x8, oneway: false},
+	8:   {want: 0x101, have: 0x347, distance: 0x8, oneway: false},
+	9:   {want: 0x5, have: 0x3e2, distance: 0xa, oneway: true},
+	10:  {want: 0xd, have: 0x139, distance: 0xa, oneway: true},
+	11:  {want: 0x16, have: 0x367, distance: 0xa, oneway: true},
+	12:  {want: 0x21, have: 0x139, distance: 0xa, oneway: true},
+	13:  {want: 0x56, have: 0x13e, distance: 0xa, oneway: true},
+	14:  {want: 0x58, have: 0x3e2, distance: 0xa, oneway: true},
+	15:  {want: 0x71, have: 0x3e2, distance: 0xa, oneway: true},
+	16:  {want: 0x75, have: 0x139, distance: 0xa, oneway: true},
+	17:  {want: 0x82, have: 0x1be, distance: 0xa, oneway: true},
+	18:  {want: 0xa5, have: 0x139, distance: 0xa, oneway: true},
+	19:  {want: 0xb2, have: 0x15e, distance: 0xa, oneway: true},
+	20:  {want: 0xdd, have: 0x153, distance: 0xa, oneway: true},
+	21:  {want: 0xe5, have: 0x139, distance: 0xa, oneway: true},
+	22:  {want: 0xe9, have: 0x3a, distance: 0xa, oneway: true},
+	23:  {want: 0xf0, have: 0x15e, distance: 0xa, oneway: true},
+	24:  {want: 0xf9, have: 0x15e, distance: 0xa, oneway: true},
+	25:  {want: 0x100, have: 0x139, distance: 0xa, oneway: true},
+	26:  {want: 0x130, have: 0x139, distance: 0xa, oneway: true},
+	27:  {want: 0x13c, have: 0x139, distance: 0xa, oneway: true},
+	28:  {want: 0x140, have: 0x151, distance: 0xa, oneway: true},
+	29:  {want: 0x145, have: 0x13e, distance: 0xa, oneway: true},
+	30:  {want: 0x158, have: 0x101, distance: 0xa, oneway: true},
+	31:  {want: 0x16d, have: 0x367, distance: 0xa, oneway: true},
+	32:  {want: 0x16e, have: 0x139, distance: 0xa, oneway: true},
+	33:  {want: 0x16f, have: 0x139, distance: 0xa, oneway: true},
+	34:  {want: 0x17e, have: 0x139, distance: 0xa, oneway: true},
+	35:  {want: 0x190, have: 0x13e, distance: 0xa, oneway: true},
+	36:  {want: 0x194, have: 0x13e, distance: 0xa, oneway: true},
+	37:  {want: 0x1a4, have: 0x1be, distance: 0xa, oneway: true},
+	38:  {want: 0x1b4, have: 0x139, distance: 0xa, oneway: true},
+	39:  {want: 0x1b8, have: 0x139, distance: 0xa, oneway: true},
+	40:  {want: 0x1d4, have: 0x15e, distance: 0xa, oneway: true},
+	41:  {want: 0x1d7, have: 0x3e2, distance: 0xa, oneway: true},
+	42:  {want: 0x1d9, have: 0x139, distance: 0xa, oneway: true},
+	43:  {want: 0x1e7, have: 0x139, distance: 0xa, oneway: true},
+	44:  {want: 0x1f8, have: 0x139, distance: 0xa, oneway: true},
+	45:  {want: 0x20e, have: 0x1e1, distance: 0xa, oneway: true},
+	46:  {want: 0x210, have: 0x139, distance: 0xa, oneway: true},
+	47:  {want: 0x22d, have: 0x15e, distance: 0xa, oneway: true},
+	48:  {want: 0x242, have: 0x3e2, distance: 0xa, oneway: true},
+	49:  {want: 0x24a, have: 0x139, distance: 0xa, oneway: true},
+	50:  {want: 0x251, have: 0x139, distance: 0xa, oneway: true},
+	51:  {want: 0x265, have: 0x139, distance: 0xa, oneway: true},
+	52:  {want: 0x274, have: 0x48a, distance: 0xa, oneway: true},
+	53:  {want: 0x28a, have: 0x3e2, distance: 0xa, oneway: true},
+	54:  {want: 0x28e, have: 0x1f9, distance: 0xa, oneway: true},
+	55:  {want: 0x2a3, have: 0x139, distance: 0xa, oneway: true},
+	56:  {want: 0x2b5, have: 0x15e, distance: 0xa, oneway: true},
+	57:  {want: 0x2b8, have: 0x139, distance: 0xa, oneway: true},
+	58:  {want: 0x2be, have: 0x139, distance: 0xa, oneway: true},
+	59:  {want: 0x2c3, have: 0x15e, distance: 0xa, oneway: true},
+	60:  {want: 0x2ed, have: 0x139, distance: 0xa, oneway: true},
+	61:  {want: 0x2f1, have: 0x15e, distance: 0xa, oneway: true},
+	62:  {want: 0x2fa, have: 0x139, distance: 0xa, oneway: true},
+	63:  {want: 0x2ff, have: 0x7e, distance: 0xa, oneway: true},
+	64:  {want: 0x304, have: 0x139, distance: 0xa, oneway: true},
+	65:  {want: 0x30b, have: 0x3e2, distance: 0xa, oneway: true},
+	66:  {want: 0x31b, have: 0x1be, distance: 0xa, oneway: true},
+	67:  {want: 0x31f, have: 0x1e1, distance: 0xa, oneway: true},
+	68:  {want: 0x320, have: 0x139, distance: 0xa, oneway: true},
+	69:  {want: 0x331, have: 0x139, distance: 0xa, oneway: true},
+	70:  {want: 0x351, have: 0x139, distance: 0xa, oneway: true},
+	71:  {want: 0x36a, have: 0x347, distance: 0xa, oneway: false},
+	72:  {want: 0x36a, have: 0x36f, distance: 0xa, oneway: true},
+	73:  {want: 0x37a, have: 0x139, distance: 0xa, oneway: true},
+	74:  {want: 0x387, have: 0x139, distance: 0xa, oneway: true},
+	75:  {want: 0x389, have: 0x139, distance: 0xa, oneway: true},
+	76:  {want: 0x38b, have: 0x15e, distance: 0xa, oneway: true},
+	77:  {want: 0x390, have: 0x139, distance: 0xa, oneway: true},
+	78:  {want: 0x395, have: 0x139, distance: 0xa, oneway: true},
+	79:  {want: 0x39d, have: 0x139, distance: 0xa, oneway: true},
+	80:  {want: 0x3a5, have: 0x139, distance: 0xa, oneway: true},
+	81:  {want: 0x3be, have: 0x139, distance: 0xa, oneway: true},
+	82:  {want: 0x3c4, have: 0x13e, distance: 0xa, oneway: true},
+	83:  {want: 0x3d4, have: 0x10d, distance: 0xa, oneway: true},
+	84:  {want: 0x3d9, have: 0x139, distance: 0xa, oneway: true},
+	85:  {want: 0x3e5, have: 0x15e, distance: 0xa, oneway: true},
+	86:  {want: 0x3e9, have: 0x1be, distance: 0xa, oneway: true},
+	87:  {want: 0x3fa, have: 0x139, distance: 0xa, oneway: true},
+	88:  {want: 0x40c, have: 0x139, distance: 0xa, oneway: true},
+	89:  {want: 0x423, have: 0x139, distance: 0xa, oneway: true},
+	90:  {want: 0x429, have: 0x139, distance: 0xa, oneway: true},
+	91:  {want: 0x431, have: 0x139, distance: 0xa, oneway: true},
+	92:  {want: 0x43b, have: 0x139, distance: 0xa, oneway: true},
+	93:  {want: 0x43e, have: 0x1e1, distance: 0xa, oneway: true},
+	94:  {want: 0x445, have: 0x139, distance: 0xa, oneway: true},
+	95:  {want: 0x450, have: 0x139, distance: 0xa, oneway: true},
+	96:  {want: 0x461, have: 0x139, distance: 0xa, oneway: true},
+	97:  {want: 0x467, have: 0x3e2, distance: 0xa, oneway: true},
+	98:  {want: 0x46f, have: 0x139, distance: 0xa, oneway: true},
+	99:  {want: 0x476, have: 0x3e2, distance: 0xa, oneway: true},
+	100: {want: 0x3883, have: 0x139, distance: 0xa, oneway: true},
+	101: {want: 0x480, have: 0x139, distance: 0xa, oneway: true},
+	102: {want: 0x482, have: 0x139, distance: 0xa, oneway: true},
+	103: {want: 0x494, have: 0x3e2, distance: 0xa, oneway: true},
+	104: {want: 0x49d, have: 0x139, distance: 0xa, oneway: true},
+	105: {want: 0x4ac, have: 0x529, distance: 0xa, oneway: true},
+	106: {want: 0x4b4, have: 0x139, distance: 0xa, oneway: true},
+	107: {want: 0x4bc, have: 0x3e2, distance: 0xa, oneway: true},
+	108: {want: 0x4e5, have: 0x15e, distance: 0xa, oneway: true},
+	109: {want: 0x4f2, have: 0x139, distance: 0xa, oneway: true},
+	110: {want: 0x512, have: 0x139, distance: 0xa, oneway: true},
+	111: {want: 0x518, have: 0x139, distance: 0xa, oneway: true},
+	112: {want: 0x52f, have: 0x139, distance: 0xa, oneway: true},
+} // Size: 702 bytes
+
+// matchScript holds pairs of scriptIDs where readers of one script
+// can typically also read the other. Each is associated with a confidence.
+var matchScript = []scriptIntelligibility{ // 26 elements
+	0:  {wantLang: 0x432, haveLang: 0x432, wantScript: 0x5b, haveScript: 0x20, distance: 0x5},
+	1:  {wantLang: 0x432, haveLang: 0x432, wantScript: 0x20, haveScript: 0x5b, distance: 0x5},
+	2:  {wantLang: 0x58, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa},
+	3:  {wantLang: 0xa5, haveLang: 0x139, wantScript: 0xe, haveScript: 0x5b, distance: 0xa},
+	4:  {wantLang: 0x1d7, haveLang: 0x3e2, wantScript: 0x8, haveScript: 0x20, distance: 0xa},
+	5:  {wantLang: 0x210, haveLang: 0x139, wantScript: 0x2e, haveScript: 0x5b, distance: 0xa},
+	6:  {wantLang: 0x24a, haveLang: 0x139, wantScript: 0x4f, haveScript: 0x5b, distance: 0xa},
+	7:  {wantLang: 0x251, haveLang: 0x139, wantScript: 0x53, haveScript: 0x5b, distance: 0xa},
+	8:  {wantLang: 0x2b8, haveLang: 0x139, wantScript: 0x58, haveScript: 0x5b, distance: 0xa},
+	9:  {wantLang: 0x304, haveLang: 0x139, wantScript: 0x6f, haveScript: 0x5b, distance: 0xa},
+	10: {wantLang: 0x331, haveLang: 0x139, wantScript: 0x76, haveScript: 0x5b, distance: 0xa},
+	11: {wantLang: 0x351, haveLang: 0x139, wantScript: 0x22, haveScript: 0x5b, distance: 0xa},
+	12: {wantLang: 0x395, haveLang: 0x139, wantScript: 0x83, haveScript: 0x5b, distance: 0xa},
+	13: {wantLang: 0x39d, haveLang: 0x139, wantScript: 0x36, haveScript: 0x5b, distance: 0xa},
+	14: {wantLang: 0x3be, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa},
+	15: {wantLang: 0x3fa, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa},
+	16: {wantLang: 0x40c, haveLang: 0x139, wantScript: 0xd6, haveScript: 0x5b, distance: 0xa},
+	17: {wantLang: 0x450, haveLang: 0x139, wantScript: 0xe6, haveScript: 0x5b, distance: 0xa},
+	18: {wantLang: 0x461, haveLang: 0x139, wantScript: 0xe9, haveScript: 0x5b, distance: 0xa},
+	19: {wantLang: 0x46f, haveLang: 0x139, wantScript: 0x2c, haveScript: 0x5b, distance: 0xa},
+	20: {wantLang: 0x476, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa},
+	21: {wantLang: 0x4b4, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa},
+	22: {wantLang: 0x4bc, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa},
+	23: {wantLang: 0x512, haveLang: 0x139, wantScript: 0x3e, haveScript: 0x5b, distance: 0xa},
+	24: {wantLang: 0x529, haveLang: 0x529, wantScript: 0x3b, haveScript: 0x3c, distance: 0xf},
+	25: {wantLang: 0x529, haveLang: 0x529, wantScript: 0x3c, haveScript: 0x3b, distance: 0x13},
+} // Size: 232 bytes
+
+var matchRegion = []regionIntelligibility{ // 15 elements
+	0:  {lang: 0x3a, script: 0x0, group: 0x4, distance: 0x4},
+	1:  {lang: 0x3a, script: 0x0, group: 0x84, distance: 0x4},
+	2:  {lang: 0x139, script: 0x0, group: 0x1, distance: 0x4},
+	3:  {lang: 0x139, script: 0x0, group: 0x81, distance: 0x4},
+	4:  {lang: 0x13e, script: 0x0, group: 0x3, distance: 0x4},
+	5:  {lang: 0x13e, script: 0x0, group: 0x83, distance: 0x4},
+	6:  {lang: 0x3c0, script: 0x0, group: 0x3, distance: 0x4},
+	7:  {lang: 0x3c0, script: 0x0, group: 0x83, distance: 0x4},
+	8:  {lang: 0x529, script: 0x3c, group: 0x2, distance: 0x4},
+	9:  {lang: 0x529, script: 0x3c, group: 0x82, distance: 0x4},
+	10: {lang: 0x3a, script: 0x0, group: 0x80, distance: 0x5},
+	11: {lang: 0x139, script: 0x0, group: 0x80, distance: 0x5},
+	12: {lang: 0x13e, script: 0x0, group: 0x80, distance: 0x5},
+	13: {lang: 0x3c0, script: 0x0, group: 0x80, distance: 0x5},
+	14: {lang: 0x529, script: 0x3c, group: 0x80, distance: 0x5},
+} // Size: 114 bytes
+
+// Total table size 1473 bytes (1KiB); checksum: 7BB90B5C
diff --git a/vendor/golang.org/x/text/language/tags.go b/vendor/golang.org/x/text/language/tags.go
new file mode 100644
index 000000000..42ea79266
--- /dev/null
+++ b/vendor/golang.org/x/text/language/tags.go
@@ -0,0 +1,145 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package language
+
+import "golang.org/x/text/internal/language/compact"
+
+// TODO: Various sets of commonly use tags and regions.
+
+// MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed.
+// It simplifies safe initialization of Tag values.
+func MustParse(s string) Tag {
+	t, err := Parse(s)
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+// MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed.
+// It simplifies safe initialization of Tag values.
+func (c CanonType) MustParse(s string) Tag {
+	t, err := c.Parse(s)
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+// MustParseBase is like ParseBase, but panics if the given base cannot be parsed.
+// It simplifies safe initialization of Base values.
+func MustParseBase(s string) Base {
+	b, err := ParseBase(s)
+	if err != nil {
+		panic(err)
+	}
+	return b
+}
+
+// MustParseScript is like ParseScript, but panics if the given script cannot be
+// parsed. It simplifies safe initialization of Script values.
+func MustParseScript(s string) Script {
+	scr, err := ParseScript(s)
+	if err != nil {
+		panic(err)
+	}
+	return scr
+}
+
+// MustParseRegion is like ParseRegion, but panics if the given region cannot be
+// parsed. It simplifies safe initialization of Region values.
+func MustParseRegion(s string) Region {
+	r, err := ParseRegion(s)
+	if err != nil {
+		panic(err)
+	}
+	return r
+}
+
+var (
+	und = Tag{}
+
+	Und Tag = Tag{}
+
+	Afrikaans            Tag = Tag(compact.Afrikaans)
+	Amharic              Tag = Tag(compact.Amharic)
+	Arabic               Tag = Tag(compact.Arabic)
+	ModernStandardArabic Tag = Tag(compact.ModernStandardArabic)
+	Azerbaijani          Tag = Tag(compact.Azerbaijani)
+	Bulgarian            Tag = Tag(compact.Bulgarian)
+	Bengali              Tag = Tag(compact.Bengali)
+	Catalan              Tag = Tag(compact.Catalan)
+	Czech                Tag = Tag(compact.Czech)
+	Danish               Tag = Tag(compact.Danish)
+	German               Tag = Tag(compact.German)
+	Greek                Tag = Tag(compact.Greek)
+	English              Tag = Tag(compact.English)
+	AmericanEnglish      Tag = Tag(compact.AmericanEnglish)
+	BritishEnglish       Tag = Tag(compact.BritishEnglish)
+	Spanish              Tag = Tag(compact.Spanish)
+	EuropeanSpanish      Tag = Tag(compact.EuropeanSpanish)
+	LatinAmericanSpanish Tag = Tag(compact.LatinAmericanSpanish)
+	Estonian             Tag = Tag(compact.Estonian)
+	Persian              Tag = Tag(compact.Persian)
+	Finnish              Tag = Tag(compact.Finnish)
+	Filipino             Tag = Tag(compact.Filipino)
+	French               Tag = Tag(compact.French)
+	CanadianFrench       Tag = Tag(compact.CanadianFrench)
+	Gujarati             Tag = Tag(compact.Gujarati)
+	Hebrew               Tag = Tag(compact.Hebrew)
+	Hindi                Tag = Tag(compact.Hindi)
+	Croatian             Tag = Tag(compact.Croatian)
+	Hungarian            Tag = Tag(compact.Hungarian)
+	Armenian             Tag = Tag(compact.Armenian)
+	Indonesian           Tag = Tag(compact.Indonesian)
+	Icelandic            Tag = Tag(compact.Icelandic)
+	Italian              Tag = Tag(compact.Italian)
+	Japanese             Tag = Tag(compact.Japanese)
+	Georgian             Tag = Tag(compact.Georgian)
+	Kazakh               Tag = Tag(compact.Kazakh)
+	Khmer                Tag = Tag(compact.Khmer)
+	Kannada              Tag = Tag(compact.Kannada)
+	Korean               Tag = Tag(compact.Korean)
+	Kirghiz              Tag = Tag(compact.Kirghiz)
+	Lao                  Tag = Tag(compact.Lao)
+	Lithuanian           Tag = Tag(compact.Lithuanian)
+	Latvian              Tag = Tag(compact.Latvian)
+	Macedonian           Tag = Tag(compact.Macedonian)
+	Malayalam            Tag = Tag(compact.Malayalam)
+	Mongolian            Tag = Tag(compact.Mongolian)
+	Marathi              Tag = Tag(compact.Marathi)
+	Malay                Tag = Tag(compact.Malay)
+	Burmese              Tag = Tag(compact.Burmese)
+	Nepali               Tag = Tag(compact.Nepali)
+	Dutch                Tag = Tag(compact.Dutch)
+	Norwegian            Tag = Tag(compact.Norwegian)
+	Punjabi              Tag = Tag(compact.Punjabi)
+	Polish               Tag = Tag(compact.Polish)
+	Portuguese           Tag = Tag(compact.Portuguese)
+	BrazilianPortuguese  Tag = Tag(compact.BrazilianPortuguese)
+	EuropeanPortuguese   Tag = Tag(compact.EuropeanPortuguese)
+	Romanian             Tag = Tag(compact.Romanian)
+	Russian              Tag = Tag(compact.Russian)
+	Sinhala              Tag = Tag(compact.Sinhala)
+	Slovak               Tag = Tag(compact.Slovak)
+	Slovenian            Tag = Tag(compact.Slovenian)
+	Albanian             Tag = Tag(compact.Albanian)
+	Serbian              Tag = Tag(compact.Serbian)
+	SerbianLatin         Tag = Tag(compact.SerbianLatin)
+	Swedish              Tag = Tag(compact.Swedish)
+	Swahili              Tag = Tag(compact.Swahili)
+	Tamil                Tag = Tag(compact.Tamil)
+	Telugu               Tag = Tag(compact.Telugu)
+	Thai                 Tag = Tag(compact.Thai)
+	Turkish              Tag = Tag(compact.Turkish)
+	Ukrainian            Tag = Tag(compact.Ukrainian)
+	Urdu                 Tag = Tag(compact.Urdu)
+	Uzbek                Tag = Tag(compact.Uzbek)
+	Vietnamese           Tag = Tag(compact.Vietnamese)
+	Chinese              Tag = Tag(compact.Chinese)
+	SimplifiedChinese    Tag = Tag(compact.SimplifiedChinese)
+	TraditionalChinese   Tag = Tag(compact.TraditionalChinese)
+	Zulu                 Tag = Tag(compact.Zulu)
+)
diff --git a/vendor/golang.org/x/text/runes/cond.go b/vendor/golang.org/x/text/runes/cond.go
new file mode 100644
index 000000000..df7aa02db
--- /dev/null
+++ b/vendor/golang.org/x/text/runes/cond.go
@@ -0,0 +1,187 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runes
+
+import (
+	"unicode/utf8"
+
+	"golang.org/x/text/transform"
+)
+
+// Note: below we pass invalid UTF-8 to the tIn and tNotIn transformers as is.
+// This is done for various reasons:
+// - To retain the semantics of the Nop transformer: if input is passed to a Nop
+//   one would expect it to be unchanged.
+// - It would be very expensive to pass a converted RuneError to a transformer:
+//   a transformer might need more source bytes after RuneError, meaning that
+//   the only way to pass it safely is to create a new buffer and manage the
+//   intermingling of RuneErrors and normal input.
+// - Many transformers leave ill-formed UTF-8 as is, so this is not
+//   inconsistent. Generally ill-formed UTF-8 is only replaced if it is a
+//   logical consequence of the operation (as for Map) or if it otherwise would
+//   pose security concerns (as for Remove).
+// - An alternative would be to return an error on ill-formed UTF-8, but this
+//   would be inconsistent with other operations.
+
+// If returns a transformer that applies tIn to consecutive runes for which
+// s.Contains(r) and tNotIn to consecutive runes for which !s.Contains(r). Reset
+// is called on tIn and tNotIn at the start of each run. A Nop transformer will
+// substitute a nil value passed to tIn or tNotIn. Invalid UTF-8 is translated
+// to RuneError to determine which transformer to apply, but is passed as is to
+// the respective transformer.
+func If(s Set, tIn, tNotIn transform.Transformer) Transformer {
+	if tIn == nil && tNotIn == nil {
+		return Transformer{transform.Nop}
+	}
+	if tIn == nil {
+		tIn = transform.Nop
+	}
+	if tNotIn == nil {
+		tNotIn = transform.Nop
+	}
+	sIn, ok := tIn.(transform.SpanningTransformer)
+	if !ok {
+		sIn = dummySpan{tIn}
+	}
+	sNotIn, ok := tNotIn.(transform.SpanningTransformer)
+	if !ok {
+		sNotIn = dummySpan{tNotIn}
+	}
+
+	a := &cond{
+		tIn:    sIn,
+		tNotIn: sNotIn,
+		f:      s.Contains,
+	}
+	a.Reset()
+	return Transformer{a}
+}
+
+type dummySpan struct{ transform.Transformer }
+
+func (d dummySpan) Span(src []byte, atEOF bool) (n int, err error) {
+	return 0, transform.ErrEndOfSpan
+}
+
+type cond struct {
+	tIn, tNotIn transform.SpanningTransformer
+	f           func(rune) bool
+	check       func(rune) bool               // current check to perform
+	t           transform.SpanningTransformer // current transformer to use
+}
+
+// Reset implements transform.Transformer.
+func (t *cond) Reset() {
+	t.check = t.is
+	t.t = t.tIn
+	t.t.Reset() // notIn will be reset on first usage.
+}
+
+func (t *cond) is(r rune) bool {
+	if t.f(r) {
+		return true
+	}
+	t.check = t.isNot
+	t.t = t.tNotIn
+	t.tNotIn.Reset()
+	return false
+}
+
+func (t *cond) isNot(r rune) bool {
+	if !t.f(r) {
+		return true
+	}
+	t.check = t.is
+	t.t = t.tIn
+	t.tIn.Reset()
+	return false
+}
+
+// This implementation of Span doesn't help all too much, but it needs to be
+// there to satisfy this package's Transformer interface.
+// TODO: there are certainly room for improvements, though. For example, if
+// t.t == transform.Nop (which will a common occurrence) it will save a bundle
+// to special-case that loop.
+func (t *cond) Span(src []byte, atEOF bool) (n int, err error) {
+	p := 0
+	for n < len(src) && err == nil {
+		// Don't process too much at a time as the Spanner that will be
+		// called on this block may terminate early.
+		const maxChunk = 4096
+		max := len(src)
+		if v := n + maxChunk; v < max {
+			max = v
+		}
+		atEnd := false
+		size := 0
+		current := t.t
+		for ; p < max; p += size {
+			r := rune(src[p])
+			if r < utf8.RuneSelf {
+				size = 1
+			} else if r, size = utf8.DecodeRune(src[p:]); size == 1 {
+				if !atEOF && !utf8.FullRune(src[p:]) {
+					err = transform.ErrShortSrc
+					break
+				}
+			}
+			if !t.check(r) {
+				// The next rune will be the start of a new run.
+				atEnd = true
+				break
+			}
+		}
+		n2, err2 := current.Span(src[n:p], atEnd || (atEOF && p == len(src)))
+		n += n2
+		if err2 != nil {
+			return n, err2
+		}
+		// At this point either err != nil or t.check will pass for the rune at p.
+		p = n + size
+	}
+	return n, err
+}
+
+func (t *cond) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	p := 0
+	for nSrc < len(src) && err == nil {
+		// Don't process too much at a time, as the work might be wasted if the
+		// destination buffer isn't large enough to hold the result or a
+		// transform returns an error early.
+		const maxChunk = 4096
+		max := len(src)
+		if n := nSrc + maxChunk; n < len(src) {
+			max = n
+		}
+		atEnd := false
+		size := 0
+		current := t.t
+		for ; p < max; p += size {
+			r := rune(src[p])
+			if r < utf8.RuneSelf {
+				size = 1
+			} else if r, size = utf8.DecodeRune(src[p:]); size == 1 {
+				if !atEOF && !utf8.FullRune(src[p:]) {
+					err = transform.ErrShortSrc
+					break
+				}
+			}
+			if !t.check(r) {
+				// The next rune will be the start of a new run.
+				atEnd = true
+				break
+			}
+		}
+		nDst2, nSrc2, err2 := current.Transform(dst[nDst:], src[nSrc:p], atEnd || (atEOF && p == len(src)))
+		nDst += nDst2
+		nSrc += nSrc2
+		if err2 != nil {
+			return nDst, nSrc, err2
+		}
+		// At this point either err != nil or t.check will pass for the rune at p.
+		p = nSrc + size
+	}
+	return nDst, nSrc, err
+}
diff --git a/vendor/golang.org/x/text/runes/runes.go b/vendor/golang.org/x/text/runes/runes.go
new file mode 100644
index 000000000..930e87fed
--- /dev/null
+++ b/vendor/golang.org/x/text/runes/runes.go
@@ -0,0 +1,355 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package runes provide transforms for UTF-8 encoded text.
+package runes // import "golang.org/x/text/runes"
+
+import (
+	"unicode"
+	"unicode/utf8"
+
+	"golang.org/x/text/transform"
+)
+
+// A Set is a collection of runes.
+type Set interface {
+	// Contains returns true if r is contained in the set.
+	Contains(r rune) bool
+}
+
+type setFunc func(rune) bool
+
+func (s setFunc) Contains(r rune) bool {
+	return s(r)
+}
+
+// Note: using funcs here instead of wrapping types result in cleaner
+// documentation and a smaller API.
+
+// In creates a Set with a Contains method that returns true for all runes in
+// the given RangeTable.
+func In(rt *unicode.RangeTable) Set {
+	return setFunc(func(r rune) bool { return unicode.Is(rt, r) })
+}
+
+// NotIn creates a Set with a Contains method that returns true for all runes not
+// in the given RangeTable.
+func NotIn(rt *unicode.RangeTable) Set {
+	return setFunc(func(r rune) bool { return !unicode.Is(rt, r) })
+}
+
+// Predicate creates a Set with a Contains method that returns f(r).
+func Predicate(f func(rune) bool) Set {
+	return setFunc(f)
+}
+
+// Transformer implements the transform.Transformer interface.
+type Transformer struct {
+	t transform.SpanningTransformer
+}
+
+func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	return t.t.Transform(dst, src, atEOF)
+}
+
+func (t Transformer) Span(b []byte, atEOF bool) (n int, err error) {
+	return t.t.Span(b, atEOF)
+}
+
+func (t Transformer) Reset() { t.t.Reset() }
+
+// Bytes returns a new byte slice with the result of converting b using t.  It
+// calls Reset on t. It returns nil if any error was found. This can only happen
+// if an error-producing Transformer is passed to If.
+func (t Transformer) Bytes(b []byte) []byte {
+	b, _, err := transform.Bytes(t, b)
+	if err != nil {
+		return nil
+	}
+	return b
+}
+
+// String returns a string with the result of converting s using t. It calls
+// Reset on t. It returns the empty string if any error was found. This can only
+// happen if an error-producing Transformer is passed to If.
+func (t Transformer) String(s string) string {
+	s, _, err := transform.String(t, s)
+	if err != nil {
+		return ""
+	}
+	return s
+}
+
+// TODO:
+// - Copy: copying strings and bytes in whole-rune units.
+// - Validation (maybe)
+// - Well-formed-ness (maybe)
+
+const runeErrorString = string(utf8.RuneError)
+
+// Remove returns a Transformer that removes runes r for which s.Contains(r).
+// Illegal input bytes are replaced by RuneError before being passed to f.
+func Remove(s Set) Transformer {
+	if f, ok := s.(setFunc); ok {
+		// This little trick cuts the running time of BenchmarkRemove for sets
+		// created by Predicate roughly in half.
+		// TODO: special-case RangeTables as well.
+		return Transformer{remove(f)}
+	}
+	return Transformer{remove(s.Contains)}
+}
+
+// TODO: remove transform.RemoveFunc.
+
+type remove func(r rune) bool
+
+func (remove) Reset() {}
+
+// Span implements transform.Spanner.
+func (t remove) Span(src []byte, atEOF bool) (n int, err error) {
+	for r, size := rune(0), 0; n < len(src); {
+		if r = rune(src[n]); r < utf8.RuneSelf {
+			size = 1
+		} else if r, size = utf8.DecodeRune(src[n:]); size == 1 {
+			// Invalid rune.
+			if !atEOF && !utf8.FullRune(src[n:]) {
+				err = transform.ErrShortSrc
+			} else {
+				err = transform.ErrEndOfSpan
+			}
+			break
+		}
+		if t(r) {
+			err = transform.ErrEndOfSpan
+			break
+		}
+		n += size
+	}
+	return
+}
+
+// Transform implements transform.Transformer.
+func (t remove) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	for r, size := rune(0), 0; nSrc < len(src); {
+		if r = rune(src[nSrc]); r < utf8.RuneSelf {
+			size = 1
+		} else if r, size = utf8.DecodeRune(src[nSrc:]); size == 1 {
+			// Invalid rune.
+			if !atEOF && !utf8.FullRune(src[nSrc:]) {
+				err = transform.ErrShortSrc
+				break
+			}
+			// We replace illegal bytes with RuneError. Not doing so might
+			// otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
+			// The resulting byte sequence may subsequently contain runes
+			// for which t(r) is true that were passed unnoticed.
+			if !t(utf8.RuneError) {
+				if nDst+3 > len(dst) {
+					err = transform.ErrShortDst
+					break
+				}
+				dst[nDst+0] = runeErrorString[0]
+				dst[nDst+1] = runeErrorString[1]
+				dst[nDst+2] = runeErrorString[2]
+				nDst += 3
+			}
+			nSrc++
+			continue
+		}
+		if t(r) {
+			nSrc += size
+			continue
+		}
+		if nDst+size > len(dst) {
+			err = transform.ErrShortDst
+			break
+		}
+		for i := 0; i < size; i++ {
+			dst[nDst] = src[nSrc]
+			nDst++
+			nSrc++
+		}
+	}
+	return
+}
+
+// Map returns a Transformer that maps the runes in the input using the given
+// mapping. Illegal bytes in the input are converted to utf8.RuneError before
+// being passed to the mapping func.
+func Map(mapping func(rune) rune) Transformer {
+	return Transformer{mapper(mapping)}
+}
+
+type mapper func(rune) rune
+
+func (mapper) Reset() {}
+
+// Span implements transform.Spanner.
+func (t mapper) Span(src []byte, atEOF bool) (n int, err error) {
+	for r, size := rune(0), 0; n < len(src); n += size {
+		if r = rune(src[n]); r < utf8.RuneSelf {
+			size = 1
+		} else if r, size = utf8.DecodeRune(src[n:]); size == 1 {
+			// Invalid rune.
+			if !atEOF && !utf8.FullRune(src[n:]) {
+				err = transform.ErrShortSrc
+			} else {
+				err = transform.ErrEndOfSpan
+			}
+			break
+		}
+		if t(r) != r {
+			err = transform.ErrEndOfSpan
+			break
+		}
+	}
+	return n, err
+}
+
+// Transform implements transform.Transformer.
+func (t mapper) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	var replacement rune
+	var b [utf8.UTFMax]byte
+
+	for r, size := rune(0), 0; nSrc < len(src); {
+		if r = rune(src[nSrc]); r < utf8.RuneSelf {
+			if replacement = t(r); replacement < utf8.RuneSelf {
+				if nDst == len(dst) {
+					err = transform.ErrShortDst
+					break
+				}
+				dst[nDst] = byte(replacement)
+				nDst++
+				nSrc++
+				continue
+			}
+			size = 1
+		} else if r, size = utf8.DecodeRune(src[nSrc:]); size == 1 {
+			// Invalid rune.
+			if !atEOF && !utf8.FullRune(src[nSrc:]) {
+				err = transform.ErrShortSrc
+				break
+			}
+
+			if replacement = t(utf8.RuneError); replacement == utf8.RuneError {
+				if nDst+3 > len(dst) {
+					err = transform.ErrShortDst
+					break
+				}
+				dst[nDst+0] = runeErrorString[0]
+				dst[nDst+1] = runeErrorString[1]
+				dst[nDst+2] = runeErrorString[2]
+				nDst += 3
+				nSrc++
+				continue
+			}
+		} else if replacement = t(r); replacement == r {
+			if nDst+size > len(dst) {
+				err = transform.ErrShortDst
+				break
+			}
+			for i := 0; i < size; i++ {
+				dst[nDst] = src[nSrc]
+				nDst++
+				nSrc++
+			}
+			continue
+		}
+
+		n := utf8.EncodeRune(b[:], replacement)
+
+		if nDst+n > len(dst) {
+			err = transform.ErrShortDst
+			break
+		}
+		for i := 0; i < n; i++ {
+			dst[nDst] = b[i]
+			nDst++
+		}
+		nSrc += size
+	}
+	return
+}
+
+// ReplaceIllFormed returns a transformer that replaces all input bytes that are
+// not part of a well-formed UTF-8 code sequence with utf8.RuneError.
+func ReplaceIllFormed() Transformer {
+	return Transformer{&replaceIllFormed{}}
+}
+
+type replaceIllFormed struct{ transform.NopResetter }
+
+func (t replaceIllFormed) Span(src []byte, atEOF bool) (n int, err error) {
+	for n < len(src) {
+		// ASCII fast path.
+		if src[n] < utf8.RuneSelf {
+			n++
+			continue
+		}
+
+		r, size := utf8.DecodeRune(src[n:])
+
+		// Look for a valid non-ASCII rune.
+		if r != utf8.RuneError || size != 1 {
+			n += size
+			continue
+		}
+
+		// Look for short source data.
+		if !atEOF && !utf8.FullRune(src[n:]) {
+			err = transform.ErrShortSrc
+			break
+		}
+
+		// We have an invalid rune.
+		err = transform.ErrEndOfSpan
+		break
+	}
+	return n, err
+}
+
+func (t replaceIllFormed) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	for nSrc < len(src) {
+		// ASCII fast path.
+		if r := src[nSrc]; r < utf8.RuneSelf {
+			if nDst == len(dst) {
+				err = transform.ErrShortDst
+				break
+			}
+			dst[nDst] = r
+			nDst++
+			nSrc++
+			continue
+		}
+
+		// Look for a valid non-ASCII rune.
+		if _, size := utf8.DecodeRune(src[nSrc:]); size != 1 {
+			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+				err = transform.ErrShortDst
+				break
+			}
+			nDst += size
+			nSrc += size
+			continue
+		}
+
+		// Look for short source data.
+		if !atEOF && !utf8.FullRune(src[nSrc:]) {
+			err = transform.ErrShortSrc
+			break
+		}
+
+		// We have an invalid rune.
+		if nDst+3 > len(dst) {
+			err = transform.ErrShortDst
+			break
+		}
+		dst[nDst+0] = runeErrorString[0]
+		dst[nDst+1] = runeErrorString[1]
+		dst[nDst+2] = runeErrorString[2]
+		nDst += 3
+		nSrc++
+	}
+	return nDst, nSrc, err
+}
diff --git a/vendor/golang.org/x/text/secure/precis/class.go b/vendor/golang.org/x/text/secure/precis/class.go
new file mode 100644
index 000000000..f6b56413b
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/class.go
@@ -0,0 +1,36 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package precis
+
+import (
+	"unicode/utf8"
+)
+
+// TODO: Add contextual character rules from Appendix A of RFC5892.
+
+// A class is a set of characters that match certain derived properties. The
+// PRECIS framework defines two classes: The Freeform class and the Identifier
+// class. The freeform class should be used for profiles where expressiveness is
+// prioritized over safety such as nicknames or passwords. The identifier class
+// should be used for profiles where safety is the first priority such as
+// addressable network labels and usernames.
+type class struct {
+	validFrom property
+}
+
+// Contains satisfies the runes.Set interface and returns whether the given rune
+// is a member of the class.
+func (c class) Contains(r rune) bool {
+	b := make([]byte, 4)
+	n := utf8.EncodeRune(b, r)
+
+	trieval, _ := dpTrie.lookup(b[:n])
+	return c.validFrom <= property(trieval)
+}
+
+var (
+	identifier = &class{validFrom: pValid}
+	freeform   = &class{validFrom: idDisOrFreePVal}
+)
diff --git a/vendor/golang.org/x/text/secure/precis/context.go b/vendor/golang.org/x/text/secure/precis/context.go
new file mode 100644
index 000000000..2dcaf29d7
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/context.go
@@ -0,0 +1,139 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package precis
+
+import "errors"
+
+// This file contains tables and code related to context rules.
+
+type catBitmap uint16
+
+const (
+	// These bits, once set depending on the current value, are never unset.
+	bJapanese catBitmap = 1 << iota
+	bArabicIndicDigit
+	bExtendedArabicIndicDigit
+
+	// These bits are set on each iteration depending on the current value.
+	bJoinStart
+	bJoinMid
+	bJoinEnd
+	bVirama
+	bLatinSmallL
+	bGreek
+	bHebrew
+
+	// These bits indicated which of the permanent bits need to be set at the
+	// end of the checks.
+	bMustHaveJapn
+
+	permanent = bJapanese | bArabicIndicDigit | bExtendedArabicIndicDigit | bMustHaveJapn
+)
+
+const finalShift = 10
+
+var errContext = errors.New("precis: contextual rule violated")
+
+func init() {
+	// Programmatically set these required bits as, manually setting them seems
+	// too error prone.
+	for i, ct := range categoryTransitions {
+		categoryTransitions[i].keep |= permanent
+		categoryTransitions[i].accept |= ct.term
+	}
+}
+
+var categoryTransitions = []struct {
+	keep catBitmap // mask selecting which bits to keep from the previous state
+	set  catBitmap // mask for which bits to set for this transition
+
+	// These bitmaps are used for rules that require lookahead.
+	// term&accept == term must be true, which is enforced programmatically.
+	term   catBitmap // bits accepted as termination condition
+	accept catBitmap // bits that pass, but not sufficient as termination
+
+	// The rule function cannot take a *context as an argument, as it would
+	// cause the context to escape, adding significant overhead.
+	rule func(beforeBits catBitmap) (doLookahead bool, err error)
+}{
+	joiningL:          {set: bJoinStart},
+	joiningD:          {set: bJoinStart | bJoinEnd},
+	joiningT:          {keep: bJoinStart, set: bJoinMid},
+	joiningR:          {set: bJoinEnd},
+	viramaModifier:    {set: bVirama},
+	viramaJoinT:       {set: bVirama | bJoinMid},
+	latinSmallL:       {set: bLatinSmallL},
+	greek:             {set: bGreek},
+	greekJoinT:        {set: bGreek | bJoinMid},
+	hebrew:            {set: bHebrew},
+	hebrewJoinT:       {set: bHebrew | bJoinMid},
+	japanese:          {set: bJapanese},
+	katakanaMiddleDot: {set: bMustHaveJapn},
+
+	zeroWidthNonJoiner: {
+		term:   bJoinEnd,
+		accept: bJoinMid,
+		rule: func(before catBitmap) (doLookAhead bool, err error) {
+			if before&bVirama != 0 {
+				return false, nil
+			}
+			if before&bJoinStart == 0 {
+				return false, errContext
+			}
+			return true, nil
+		},
+	},
+	zeroWidthJoiner: {
+		rule: func(before catBitmap) (doLookAhead bool, err error) {
+			if before&bVirama == 0 {
+				err = errContext
+			}
+			return false, err
+		},
+	},
+	middleDot: {
+		term: bLatinSmallL,
+		rule: func(before catBitmap) (doLookAhead bool, err error) {
+			if before&bLatinSmallL == 0 {
+				return false, errContext
+			}
+			return true, nil
+		},
+	},
+	greekLowerNumeralSign: {
+		set:  bGreek,
+		term: bGreek,
+		rule: func(before catBitmap) (doLookAhead bool, err error) {
+			return true, nil
+		},
+	},
+	hebrewPreceding: {
+		set: bHebrew,
+		rule: func(before catBitmap) (doLookAhead bool, err error) {
+			if before&bHebrew == 0 {
+				err = errContext
+			}
+			return false, err
+		},
+	},
+	arabicIndicDigit: {
+		set: bArabicIndicDigit,
+		rule: func(before catBitmap) (doLookAhead bool, err error) {
+			if before&bExtendedArabicIndicDigit != 0 {
+				err = errContext
+			}
+			return false, err
+		},
+	},
+	extendedArabicIndicDigit: {
+		set: bExtendedArabicIndicDigit,
+		rule: func(before catBitmap) (doLookAhead bool, err error) {
+			if before&bArabicIndicDigit != 0 {
+				err = errContext
+			}
+			return false, err
+		},
+	},
+}
diff --git a/vendor/golang.org/x/text/secure/precis/doc.go b/vendor/golang.org/x/text/secure/precis/doc.go
new file mode 100644
index 000000000..939ff222d
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/doc.go
@@ -0,0 +1,14 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package precis contains types and functions for the preparation,
+// enforcement, and comparison of internationalized strings ("PRECIS") as
+// defined in RFC 8264. It also contains several pre-defined profiles for
+// passwords, nicknames, and usernames as defined in RFC 8265 and RFC 8266.
+//
+// BE ADVISED: This package is under construction and the API may change in
+// backwards incompatible ways and without notice.
+package precis // import "golang.org/x/text/secure/precis"
+
+//go:generate go run gen.go gen_trieval.go
diff --git a/vendor/golang.org/x/text/secure/precis/nickname.go b/vendor/golang.org/x/text/secure/precis/nickname.go
new file mode 100644
index 000000000..11e0ccbb1
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/nickname.go
@@ -0,0 +1,72 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package precis
+
+import (
+	"unicode"
+	"unicode/utf8"
+
+	"golang.org/x/text/transform"
+)
+
+type nickAdditionalMapping struct {
+	// TODO: This transformer needs to be stateless somehow…
+	notStart  bool
+	prevSpace bool
+}
+
+func (t *nickAdditionalMapping) Reset() {
+	t.prevSpace = false
+	t.notStart = false
+}
+
+func (t *nickAdditionalMapping) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	// RFC 8266 §2.1.  Rules
+	//
+	// 2.  Additional Mapping Rule: The additional mapping rule consists of
+	//     the following sub-rules.
+	//
+	//     a.  Map any instances of non-ASCII space to SPACE (U+0020); a
+	//         non-ASCII space is any Unicode code point having a general
+	//         category of "Zs", naturally with the exception of SPACE
+	//         (U+0020).  (The inclusion of only ASCII space prevents
+	//         confusion with various non-ASCII space code points, many of
+	//         which are difficult to reproduce across different input
+	//         methods.)
+	//
+	//     b.  Remove any instances of the ASCII space character at the
+	//         beginning or end of a nickname (e.g., "stpeter " is mapped to
+	//         "stpeter").
+	//
+	//     c.  Map interior sequences of more than one ASCII space character
+	//         to a single ASCII space character (e.g., "St  Peter" is
+	//         mapped to "St Peter").
+	for nSrc < len(src) {
+		r, size := utf8.DecodeRune(src[nSrc:])
+		if size == 0 { // Incomplete UTF-8 encoding
+			if !atEOF {
+				return nDst, nSrc, transform.ErrShortSrc
+			}
+			size = 1
+		}
+		if unicode.Is(unicode.Zs, r) {
+			t.prevSpace = true
+		} else {
+			if t.prevSpace && t.notStart {
+				dst[nDst] = ' '
+				nDst += 1
+			}
+			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+				nDst += size
+				return nDst, nSrc, transform.ErrShortDst
+			}
+			nDst += size
+			t.prevSpace = false
+			t.notStart = true
+		}
+		nSrc += size
+	}
+	return nDst, nSrc, nil
+}
diff --git a/vendor/golang.org/x/text/secure/precis/options.go b/vendor/golang.org/x/text/secure/precis/options.go
new file mode 100644
index 000000000..26143db75
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/options.go
@@ -0,0 +1,157 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package precis
+
+import (
+	"golang.org/x/text/cases"
+	"golang.org/x/text/language"
+	"golang.org/x/text/runes"
+	"golang.org/x/text/transform"
+	"golang.org/x/text/unicode/norm"
+)
+
+// An Option is used to define the behavior and rules of a Profile.
+type Option func(*options)
+
+type options struct {
+	// Preparation options
+	foldWidth bool
+
+	// Enforcement options
+	asciiLower    bool
+	cases         transform.SpanningTransformer
+	disallow      runes.Set
+	norm          transform.SpanningTransformer
+	additional    []func() transform.SpanningTransformer
+	width         transform.SpanningTransformer
+	disallowEmpty bool
+	bidiRule      bool
+	repeat        bool
+
+	// Comparison options
+	ignorecase bool
+}
+
+func getOpts(o ...Option) (res options) {
+	for _, f := range o {
+		f(&res)
+	}
+	// Using a SpanningTransformer, instead of norm.Form prevents an allocation
+	// down the road.
+	if res.norm == nil {
+		res.norm = norm.NFC
+	}
+	return
+}
+
+var (
+	// The IgnoreCase option causes the profile to perform a case insensitive
+	// comparison during the PRECIS comparison step.
+	IgnoreCase Option = ignoreCase
+
+	// The FoldWidth option causes the profile to map non-canonical wide and
+	// narrow variants to their decomposition mapping. This is useful for
+	// profiles that are based on the identifier class which would otherwise
+	// disallow such characters.
+	FoldWidth Option = foldWidth
+
+	// The DisallowEmpty option causes the enforcement step to return an error if
+	// the resulting string would be empty.
+	DisallowEmpty Option = disallowEmpty
+
+	// The BidiRule option causes the Bidi Rule defined in RFC 5893 to be
+	// applied.
+	BidiRule Option = bidiRule
+)
+
+var (
+	ignoreCase = func(o *options) {
+		o.ignorecase = true
+	}
+	foldWidth = func(o *options) {
+		o.foldWidth = true
+	}
+	disallowEmpty = func(o *options) {
+		o.disallowEmpty = true
+	}
+	bidiRule = func(o *options) {
+		o.bidiRule = true
+	}
+	repeat = func(o *options) {
+		o.repeat = true
+	}
+)
+
+// TODO: move this logic to package transform
+
+type spanWrap struct{ transform.Transformer }
+
+func (s spanWrap) Span(src []byte, atEOF bool) (n int, err error) {
+	return 0, transform.ErrEndOfSpan
+}
+
+// TODO: allow different types? For instance:
+//     func() transform.Transformer
+//     func() transform.SpanningTransformer
+//     func([]byte) bool  // validation only
+//
+// Also, would be great if we could detect if a transformer is reentrant.
+
+// The AdditionalMapping option defines the additional mapping rule for the
+// Profile by applying Transformer's in sequence.
+func AdditionalMapping(t ...func() transform.Transformer) Option {
+	return func(o *options) {
+		for _, f := range t {
+			sf := func() transform.SpanningTransformer {
+				return f().(transform.SpanningTransformer)
+			}
+			if _, ok := f().(transform.SpanningTransformer); !ok {
+				sf = func() transform.SpanningTransformer {
+					return spanWrap{f()}
+				}
+			}
+			o.additional = append(o.additional, sf)
+		}
+	}
+}
+
+// The Norm option defines a Profile's normalization rule. Defaults to NFC.
+func Norm(f norm.Form) Option {
+	return func(o *options) {
+		o.norm = f
+	}
+}
+
+// The FoldCase option defines a Profile's case mapping rule. Options can be
+// provided to determine the type of case folding used.
+func FoldCase(opts ...cases.Option) Option {
+	return func(o *options) {
+		o.asciiLower = true
+		o.cases = cases.Fold(opts...)
+	}
+}
+
+// The LowerCase option defines a Profile's case mapping rule. Options can be
+// provided to determine the type of case folding used.
+func LowerCase(opts ...cases.Option) Option {
+	return func(o *options) {
+		o.asciiLower = true
+		if len(opts) == 0 {
+			o.cases = cases.Lower(language.Und, cases.HandleFinalSigma(false))
+			return
+		}
+
+		opts = append([]cases.Option{cases.HandleFinalSigma(false)}, opts...)
+		o.cases = cases.Lower(language.Und, opts...)
+	}
+}
+
+// The Disallow option further restricts a Profile's allowed characters beyond
+// what is disallowed by the underlying string class.
+func Disallow(set runes.Set) Option {
+	return func(o *options) {
+		o.disallow = set
+	}
+}
diff --git a/vendor/golang.org/x/text/secure/precis/profile.go b/vendor/golang.org/x/text/secure/precis/profile.go
new file mode 100644
index 000000000..bdd991bb9
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/profile.go
@@ -0,0 +1,412 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package precis
+
+import (
+	"bytes"
+	"errors"
+	"unicode/utf8"
+
+	"golang.org/x/text/cases"
+	"golang.org/x/text/language"
+	"golang.org/x/text/runes"
+	"golang.org/x/text/secure/bidirule"
+	"golang.org/x/text/transform"
+	"golang.org/x/text/width"
+)
+
+var (
+	errDisallowedRune = errors.New("precis: disallowed rune encountered")
+)
+
+var dpTrie = newDerivedPropertiesTrie(0)
+
+// A Profile represents a set of rules for normalizing and validating strings in
+// the PRECIS framework.
+type Profile struct {
+	options
+	class *class
+}
+
+// NewIdentifier creates a new PRECIS profile based on the Identifier string
+// class. Profiles created from this class are suitable for use where safety is
+// prioritized over expressiveness like network identifiers, user accounts, chat
+// rooms, and file names.
+func NewIdentifier(opts ...Option) *Profile {
+	return &Profile{
+		options: getOpts(opts...),
+		class:   identifier,
+	}
+}
+
+// NewFreeform creates a new PRECIS profile based on the Freeform string class.
+// Profiles created from this class are suitable for use where expressiveness is
+// prioritized over safety like passwords, and display-elements such as
+// nicknames in a chat room.
+func NewFreeform(opts ...Option) *Profile {
+	return &Profile{
+		options: getOpts(opts...),
+		class:   freeform,
+	}
+}
+
+// NewRestrictedProfile creates a new PRECIS profile based on an existing
+// profile.
+// If the parent profile already had the Disallow option set, the new rule
+// overrides the parents rule.
+func NewRestrictedProfile(parent *Profile, disallow runes.Set) *Profile {
+	p := *parent
+	Disallow(disallow)(&p.options)
+	return &p
+}
+
+// NewTransformer creates a new transform.Transformer that performs the PRECIS
+// preparation and enforcement steps on the given UTF-8 encoded bytes.
+func (p *Profile) NewTransformer() *Transformer {
+	var ts []transform.Transformer
+
+	// These transforms are applied in the order defined in
+	// https://tools.ietf.org/html/rfc7564#section-7
+
+	// RFC 8266 §2.1:
+	//
+	//     Implementation experience has shown that applying the rules for the
+	//     Nickname profile is not an idempotent procedure for all code points.
+	//     Therefore, an implementation SHOULD apply the rules repeatedly until
+	//     the output string is stable; if the output string does not stabilize
+	//     after reapplying the rules three (3) additional times after the first
+	//     application, the implementation SHOULD terminate application of the
+	//     rules and reject the input string as invalid.
+	//
+	// There is no known string that will change indefinitely, so repeat 4 times
+	// and rely on the Span method to keep things relatively performant.
+	r := 1
+	if p.options.repeat {
+		r = 4
+	}
+	for ; r > 0; r-- {
+		if p.options.foldWidth {
+			ts = append(ts, width.Fold)
+		}
+
+		for _, f := range p.options.additional {
+			ts = append(ts, f())
+		}
+
+		if p.options.cases != nil {
+			ts = append(ts, p.options.cases)
+		}
+
+		ts = append(ts, p.options.norm)
+
+		if p.options.bidiRule {
+			ts = append(ts, bidirule.New())
+		}
+
+		ts = append(ts, &checker{p: p, allowed: p.Allowed()})
+	}
+
+	// TODO: Add the disallow empty rule with a dummy transformer?
+
+	return &Transformer{transform.Chain(ts...)}
+}
+
+var errEmptyString = errors.New("precis: transformation resulted in empty string")
+
+type buffers struct {
+	src  []byte
+	buf  [2][]byte
+	next int
+}
+
+func (b *buffers) apply(t transform.SpanningTransformer) (err error) {
+	n, err := t.Span(b.src, true)
+	if err != transform.ErrEndOfSpan {
+		return err
+	}
+	x := b.next & 1
+	if b.buf[x] == nil {
+		b.buf[x] = make([]byte, 0, 8+len(b.src)+len(b.src)>>2)
+	}
+	span := append(b.buf[x][:0], b.src[:n]...)
+	b.src, _, err = transform.Append(t, span, b.src[n:])
+	b.buf[x] = b.src
+	b.next++
+	return err
+}
+
+// Pre-allocate transformers when possible. In some cases this avoids allocation.
+var (
+	foldWidthT transform.SpanningTransformer = width.Fold
+	lowerCaseT transform.SpanningTransformer = cases.Lower(language.Und, cases.HandleFinalSigma(false))
+)
+
+// TODO: make this a method on profile.
+
+func (b *buffers) enforce(p *Profile, src []byte, comparing bool) (str []byte, err error) {
+	b.src = src
+
+	ascii := true
+	for _, c := range src {
+		if c >= utf8.RuneSelf {
+			ascii = false
+			break
+		}
+	}
+	// ASCII fast path.
+	if ascii {
+		for _, f := range p.options.additional {
+			if err = b.apply(f()); err != nil {
+				return nil, err
+			}
+		}
+		switch {
+		case p.options.asciiLower || (comparing && p.options.ignorecase):
+			for i, c := range b.src {
+				if 'A' <= c && c <= 'Z' {
+					b.src[i] = c ^ 1<<5
+				}
+			}
+		case p.options.cases != nil:
+			b.apply(p.options.cases)
+		}
+		c := checker{p: p}
+		if _, err := c.span(b.src, true); err != nil {
+			return nil, err
+		}
+		if p.disallow != nil {
+			for _, c := range b.src {
+				if p.disallow.Contains(rune(c)) {
+					return nil, errDisallowedRune
+				}
+			}
+		}
+		if p.options.disallowEmpty && len(b.src) == 0 {
+			return nil, errEmptyString
+		}
+		return b.src, nil
+	}
+
+	// These transforms are applied in the order defined in
+	// https://tools.ietf.org/html/rfc8264#section-7
+
+	r := 1
+	if p.options.repeat {
+		r = 4
+	}
+	for ; r > 0; r-- {
+		// TODO: allow different width transforms options.
+		if p.options.foldWidth || (p.options.ignorecase && comparing) {
+			b.apply(foldWidthT)
+		}
+		for _, f := range p.options.additional {
+			if err = b.apply(f()); err != nil {
+				return nil, err
+			}
+		}
+		if p.options.cases != nil {
+			b.apply(p.options.cases)
+		}
+		if comparing && p.options.ignorecase {
+			b.apply(lowerCaseT)
+		}
+		b.apply(p.norm)
+		if p.options.bidiRule && !bidirule.Valid(b.src) {
+			return nil, bidirule.ErrInvalid
+		}
+		c := checker{p: p}
+		if _, err := c.span(b.src, true); err != nil {
+			return nil, err
+		}
+		if p.disallow != nil {
+			for i := 0; i < len(b.src); {
+				r, size := utf8.DecodeRune(b.src[i:])
+				if p.disallow.Contains(r) {
+					return nil, errDisallowedRune
+				}
+				i += size
+			}
+		}
+		if p.options.disallowEmpty && len(b.src) == 0 {
+			return nil, errEmptyString
+		}
+	}
+	return b.src, nil
+}
+
+// Append appends the result of applying p to src writing the result to dst.
+// It returns an error if the input string is invalid.
+func (p *Profile) Append(dst, src []byte) ([]byte, error) {
+	var buf buffers
+	b, err := buf.enforce(p, src, false)
+	if err != nil {
+		return nil, err
+	}
+	return append(dst, b...), nil
+}
+
+func processBytes(p *Profile, b []byte, key bool) ([]byte, error) {
+	var buf buffers
+	b, err := buf.enforce(p, b, key)
+	if err != nil {
+		return nil, err
+	}
+	if buf.next == 0 {
+		c := make([]byte, len(b))
+		copy(c, b)
+		return c, nil
+	}
+	return b, nil
+}
+
+// Bytes returns a new byte slice with the result of applying the profile to b.
+func (p *Profile) Bytes(b []byte) ([]byte, error) {
+	return processBytes(p, b, false)
+}
+
+// AppendCompareKey appends the result of applying p to src (including any
+// optional rules to make strings comparable or useful in a map key such as
+// applying lowercasing) writing the result to dst. It returns an error if the
+// input string is invalid.
+func (p *Profile) AppendCompareKey(dst, src []byte) ([]byte, error) {
+	var buf buffers
+	b, err := buf.enforce(p, src, true)
+	if err != nil {
+		return nil, err
+	}
+	return append(dst, b...), nil
+}
+
+func processString(p *Profile, s string, key bool) (string, error) {
+	var buf buffers
+	b, err := buf.enforce(p, []byte(s), key)
+	if err != nil {
+		return "", err
+	}
+	return string(b), nil
+}
+
+// String returns a string with the result of applying the profile to s.
+func (p *Profile) String(s string) (string, error) {
+	return processString(p, s, false)
+}
+
+// CompareKey returns a string that can be used for comparison, hashing, or
+// collation.
+func (p *Profile) CompareKey(s string) (string, error) {
+	return processString(p, s, true)
+}
+
+// Compare enforces both strings, and then compares them for bit-string identity
+// (byte-for-byte equality). If either string cannot be enforced, the comparison
+// is false.
+func (p *Profile) Compare(a, b string) bool {
+	var buf buffers
+
+	akey, err := buf.enforce(p, []byte(a), true)
+	if err != nil {
+		return false
+	}
+
+	buf = buffers{}
+	bkey, err := buf.enforce(p, []byte(b), true)
+	if err != nil {
+		return false
+	}
+
+	return bytes.Equal(akey, bkey)
+}
+
+// Allowed returns a runes.Set containing every rune that is a member of the
+// underlying profile's string class and not disallowed by any profile specific
+// rules.
+func (p *Profile) Allowed() runes.Set {
+	if p.options.disallow != nil {
+		return runes.Predicate(func(r rune) bool {
+			return p.class.Contains(r) && !p.options.disallow.Contains(r)
+		})
+	}
+	return p.class
+}
+
+type checker struct {
+	p       *Profile
+	allowed runes.Set
+
+	beforeBits catBitmap
+	termBits   catBitmap
+	acceptBits catBitmap
+}
+
+func (c *checker) Reset() {
+	c.beforeBits = 0
+	c.termBits = 0
+	c.acceptBits = 0
+}
+
+func (c *checker) span(src []byte, atEOF bool) (n int, err error) {
+	for n < len(src) {
+		e, sz := dpTrie.lookup(src[n:])
+		d := categoryTransitions[category(e&catMask)]
+		if sz == 0 {
+			if !atEOF {
+				return n, transform.ErrShortSrc
+			}
+			return n, errDisallowedRune
+		}
+		doLookAhead := false
+		if property(e) < c.p.class.validFrom {
+			if d.rule == nil {
+				return n, errDisallowedRune
+			}
+			doLookAhead, err = d.rule(c.beforeBits)
+			if err != nil {
+				return n, err
+			}
+		}
+		c.beforeBits &= d.keep
+		c.beforeBits |= d.set
+		if c.termBits != 0 {
+			// We are currently in an unterminated lookahead.
+			if c.beforeBits&c.termBits != 0 {
+				c.termBits = 0
+				c.acceptBits = 0
+			} else if c.beforeBits&c.acceptBits == 0 {
+				// Invalid continuation of the unterminated lookahead sequence.
+				return n, errContext
+			}
+		}
+		if doLookAhead {
+			if c.termBits != 0 {
+				// A previous lookahead run has not been terminated yet.
+				return n, errContext
+			}
+			c.termBits = d.term
+			c.acceptBits = d.accept
+		}
+		n += sz
+	}
+	if m := c.beforeBits >> finalShift; c.beforeBits&m != m || c.termBits != 0 {
+		err = errContext
+	}
+	return n, err
+}
+
+// TODO: we may get rid of this transform if transform.Chain understands
+// something like a Spanner interface.
+func (c checker) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	short := false
+	if len(dst) < len(src) {
+		src = src[:len(dst)]
+		atEOF = false
+		short = true
+	}
+	nSrc, err = c.span(src, atEOF)
+	nDst = copy(dst, src[:nSrc])
+	if short && (err == transform.ErrShortSrc || err == nil) {
+		err = transform.ErrShortDst
+	}
+	return nDst, nSrc, err
+}
diff --git a/vendor/golang.org/x/text/secure/precis/profiles.go b/vendor/golang.org/x/text/secure/precis/profiles.go
new file mode 100644
index 000000000..061936d98
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/profiles.go
@@ -0,0 +1,78 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package precis
+
+import (
+	"unicode"
+
+	"golang.org/x/text/runes"
+	"golang.org/x/text/transform"
+	"golang.org/x/text/unicode/norm"
+)
+
+var (
+	// Implements the Nickname profile specified in RFC 8266.
+	Nickname *Profile = nickname
+
+	// Implements the UsernameCaseMapped profile specified in RFC 8265.
+	UsernameCaseMapped *Profile = usernameCaseMap
+
+	// Implements the UsernameCasePreserved profile specified in RFC 8265.
+	UsernameCasePreserved *Profile = usernameNoCaseMap
+
+	// Implements the OpaqueString profile defined in RFC 8265 for passwords and
+	// other secure labels.
+	OpaqueString *Profile = opaquestring
+)
+
+var (
+	nickname = &Profile{
+		options: getOpts(
+			AdditionalMapping(func() transform.Transformer {
+				return &nickAdditionalMapping{}
+			}),
+			IgnoreCase,
+			Norm(norm.NFKC),
+			DisallowEmpty,
+			repeat,
+		),
+		class: freeform,
+	}
+	usernameCaseMap = &Profile{
+		options: getOpts(
+			FoldWidth,
+			LowerCase(),
+			Norm(norm.NFC),
+			BidiRule,
+		),
+		class: identifier,
+	}
+	usernameNoCaseMap = &Profile{
+		options: getOpts(
+			FoldWidth,
+			Norm(norm.NFC),
+			BidiRule,
+		),
+		class: identifier,
+	}
+	opaquestring = &Profile{
+		options: getOpts(
+			AdditionalMapping(func() transform.Transformer {
+				return mapSpaces
+			}),
+			Norm(norm.NFC),
+			DisallowEmpty,
+		),
+		class: freeform,
+	}
+)
+
+// mapSpaces is a shared value of a runes.Map transformer.
+var mapSpaces transform.Transformer = runes.Map(func(r rune) rune {
+	if unicode.Is(unicode.Zs, r) {
+		return ' '
+	}
+	return r
+})
diff --git a/vendor/golang.org/x/text/secure/precis/tables15.0.0.go b/vendor/golang.org/x/text/secure/precis/tables15.0.0.go
new file mode 100644
index 000000000..b9b7481d5
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/tables15.0.0.go
@@ -0,0 +1,4315 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+//go:build !go1.27
+
+package precis
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "15.0.0"
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *derivedPropertiesTrie) lookup(s []byte) (v uint8, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return derivedPropertiesValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = derivedPropertiesIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = derivedPropertiesIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = derivedPropertiesIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *derivedPropertiesTrie) lookupUnsafe(s []byte) uint8 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return derivedPropertiesValues[c0]
+	}
+	i := derivedPropertiesIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *derivedPropertiesTrie) lookupString(s string) (v uint8, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return derivedPropertiesValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = derivedPropertiesIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = derivedPropertiesIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = derivedPropertiesIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *derivedPropertiesTrie) lookupStringUnsafe(s string) uint8 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return derivedPropertiesValues[c0]
+	}
+	i := derivedPropertiesIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// derivedPropertiesTrie. Total size: 28992 bytes (28.31 KiB). Checksum: 6ba05cbedd26c252.
+type derivedPropertiesTrie struct{}
+
+func newDerivedPropertiesTrie(i int) *derivedPropertiesTrie {
+	return &derivedPropertiesTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *derivedPropertiesTrie) lookupValue(n uint32, b byte) uint8 {
+	switch {
+	default:
+		return uint8(derivedPropertiesValues[n<<6+uint32(b)])
+	}
+}
+
+// derivedPropertiesValues: 373 blocks, 23872 entries, 23872 bytes
+// The third block is the zero block.
+var derivedPropertiesValues = [23872]uint8{
+	// Block 0x0, offset 0x0
+	0x00: 0x0040, 0x01: 0x0040, 0x02: 0x0040, 0x03: 0x0040, 0x04: 0x0040, 0x05: 0x0040,
+	0x06: 0x0040, 0x07: 0x0040, 0x08: 0x0040, 0x09: 0x0040, 0x0a: 0x0040, 0x0b: 0x0040,
+	0x0c: 0x0040, 0x0d: 0x0040, 0x0e: 0x0040, 0x0f: 0x0040, 0x10: 0x0040, 0x11: 0x0040,
+	0x12: 0x0040, 0x13: 0x0040, 0x14: 0x0040, 0x15: 0x0040, 0x16: 0x0040, 0x17: 0x0040,
+	0x18: 0x0040, 0x19: 0x0040, 0x1a: 0x0040, 0x1b: 0x0040, 0x1c: 0x0040, 0x1d: 0x0040,
+	0x1e: 0x0040, 0x1f: 0x0040, 0x20: 0x0080, 0x21: 0x00c0, 0x22: 0x00c0, 0x23: 0x00c0,
+	0x24: 0x00c0, 0x25: 0x00c0, 0x26: 0x00c0, 0x27: 0x00c0, 0x28: 0x00c0, 0x29: 0x00c0,
+	0x2a: 0x00c0, 0x2b: 0x00c0, 0x2c: 0x00c0, 0x2d: 0x00c0, 0x2e: 0x00c0, 0x2f: 0x00c0,
+	0x30: 0x00c0, 0x31: 0x00c0, 0x32: 0x00c0, 0x33: 0x00c0, 0x34: 0x00c0, 0x35: 0x00c0,
+	0x36: 0x00c0, 0x37: 0x00c0, 0x38: 0x00c0, 0x39: 0x00c0, 0x3a: 0x00c0, 0x3b: 0x00c0,
+	0x3c: 0x00c0, 0x3d: 0x00c0, 0x3e: 0x00c0, 0x3f: 0x00c0,
+	// Block 0x1, offset 0x40
+	0x40: 0x00c0, 0x41: 0x00c0, 0x42: 0x00c0, 0x43: 0x00c0, 0x44: 0x00c0, 0x45: 0x00c0,
+	0x46: 0x00c0, 0x47: 0x00c0, 0x48: 0x00c0, 0x49: 0x00c0, 0x4a: 0x00c0, 0x4b: 0x00c0,
+	0x4c: 0x00c0, 0x4d: 0x00c0, 0x4e: 0x00c0, 0x4f: 0x00c0, 0x50: 0x00c0, 0x51: 0x00c0,
+	0x52: 0x00c0, 0x53: 0x00c0, 0x54: 0x00c0, 0x55: 0x00c0, 0x56: 0x00c0, 0x57: 0x00c0,
+	0x58: 0x00c0, 0x59: 0x00c0, 0x5a: 0x00c0, 0x5b: 0x00c0, 0x5c: 0x00c0, 0x5d: 0x00c0,
+	0x5e: 0x00c0, 0x5f: 0x00c0, 0x60: 0x00c0, 0x61: 0x00c0, 0x62: 0x00c0, 0x63: 0x00c0,
+	0x64: 0x00c0, 0x65: 0x00c0, 0x66: 0x00c0, 0x67: 0x00c0, 0x68: 0x00c0, 0x69: 0x00c0,
+	0x6a: 0x00c0, 0x6b: 0x00c0, 0x6c: 0x00c7, 0x6d: 0x00c0, 0x6e: 0x00c0, 0x6f: 0x00c0,
+	0x70: 0x00c0, 0x71: 0x00c0, 0x72: 0x00c0, 0x73: 0x00c0, 0x74: 0x00c0, 0x75: 0x00c0,
+	0x76: 0x00c0, 0x77: 0x00c0, 0x78: 0x00c0, 0x79: 0x00c0, 0x7a: 0x00c0, 0x7b: 0x00c0,
+	0x7c: 0x00c0, 0x7d: 0x00c0, 0x7e: 0x00c0, 0x7f: 0x0040,
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040,
+	0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040,
+	0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040,
+	0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040,
+	0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040,
+	0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x0080, 0xe1: 0x0080, 0xe2: 0x0080, 0xe3: 0x0080,
+	0xe4: 0x0080, 0xe5: 0x0080, 0xe6: 0x0080, 0xe7: 0x0080, 0xe8: 0x0080, 0xe9: 0x0080,
+	0xea: 0x0080, 0xeb: 0x0080, 0xec: 0x0080, 0xed: 0x0040, 0xee: 0x0080, 0xef: 0x0080,
+	0xf0: 0x0080, 0xf1: 0x0080, 0xf2: 0x0080, 0xf3: 0x0080, 0xf4: 0x0080, 0xf5: 0x0080,
+	0xf6: 0x0080, 0xf7: 0x004f, 0xf8: 0x0080, 0xf9: 0x0080, 0xfa: 0x0080, 0xfb: 0x0080,
+	0xfc: 0x0080, 0xfd: 0x0080, 0xfe: 0x0080, 0xff: 0x0080,
+	// Block 0x4, offset 0x100
+	0x100: 0x00c0, 0x101: 0x00c0, 0x102: 0x00c0, 0x103: 0x00c0, 0x104: 0x00c0, 0x105: 0x00c0,
+	0x106: 0x00c0, 0x107: 0x00c0, 0x108: 0x00c0, 0x109: 0x00c0, 0x10a: 0x00c0, 0x10b: 0x00c0,
+	0x10c: 0x00c0, 0x10d: 0x00c0, 0x10e: 0x00c0, 0x10f: 0x00c0, 0x110: 0x00c0, 0x111: 0x00c0,
+	0x112: 0x00c0, 0x113: 0x00c0, 0x114: 0x00c0, 0x115: 0x00c0, 0x116: 0x00c0, 0x117: 0x0080,
+	0x118: 0x00c0, 0x119: 0x00c0, 0x11a: 0x00c0, 0x11b: 0x00c0, 0x11c: 0x00c0, 0x11d: 0x00c0,
+	0x11e: 0x00c0, 0x11f: 0x00c0, 0x120: 0x00c0, 0x121: 0x00c0, 0x122: 0x00c0, 0x123: 0x00c0,
+	0x124: 0x00c0, 0x125: 0x00c0, 0x126: 0x00c0, 0x127: 0x00c0, 0x128: 0x00c0, 0x129: 0x00c0,
+	0x12a: 0x00c0, 0x12b: 0x00c0, 0x12c: 0x00c0, 0x12d: 0x00c0, 0x12e: 0x00c0, 0x12f: 0x00c0,
+	0x130: 0x00c0, 0x131: 0x00c0, 0x132: 0x00c0, 0x133: 0x00c0, 0x134: 0x00c0, 0x135: 0x00c0,
+	0x136: 0x00c0, 0x137: 0x0080, 0x138: 0x00c0, 0x139: 0x00c0, 0x13a: 0x00c0, 0x13b: 0x00c0,
+	0x13c: 0x00c0, 0x13d: 0x00c0, 0x13e: 0x00c0, 0x13f: 0x00c0,
+	// Block 0x5, offset 0x140
+	0x140: 0x00c0, 0x141: 0x00c0, 0x142: 0x00c0, 0x143: 0x00c0, 0x144: 0x00c0, 0x145: 0x00c0,
+	0x146: 0x00c0, 0x147: 0x00c0, 0x148: 0x00c0, 0x149: 0x00c0, 0x14a: 0x00c0, 0x14b: 0x00c0,
+	0x14c: 0x00c0, 0x14d: 0x00c0, 0x14e: 0x00c0, 0x14f: 0x00c0, 0x150: 0x00c0, 0x151: 0x00c0,
+	0x152: 0x00c0, 0x153: 0x00c0, 0x154: 0x00c0, 0x155: 0x00c0, 0x156: 0x00c0, 0x157: 0x00c0,
+	0x158: 0x00c0, 0x159: 0x00c0, 0x15a: 0x00c0, 0x15b: 0x00c0, 0x15c: 0x00c0, 0x15d: 0x00c0,
+	0x15e: 0x00c0, 0x15f: 0x00c0, 0x160: 0x00c0, 0x161: 0x00c0, 0x162: 0x00c0, 0x163: 0x00c0,
+	0x164: 0x00c0, 0x165: 0x00c0, 0x166: 0x00c0, 0x167: 0x00c0, 0x168: 0x00c0, 0x169: 0x00c0,
+	0x16a: 0x00c0, 0x16b: 0x00c0, 0x16c: 0x00c0, 0x16d: 0x00c0, 0x16e: 0x00c0, 0x16f: 0x00c0,
+	0x170: 0x00c0, 0x171: 0x00c0, 0x172: 0x0080, 0x173: 0x0080, 0x174: 0x00c0, 0x175: 0x00c0,
+	0x176: 0x00c0, 0x177: 0x00c0, 0x178: 0x00c0, 0x179: 0x00c0, 0x17a: 0x00c0, 0x17b: 0x00c0,
+	0x17c: 0x00c0, 0x17d: 0x00c0, 0x17e: 0x00c0, 0x17f: 0x0080,
+	// Block 0x6, offset 0x180
+	0x180: 0x0080, 0x181: 0x00c0, 0x182: 0x00c0, 0x183: 0x00c0, 0x184: 0x00c0, 0x185: 0x00c0,
+	0x186: 0x00c0, 0x187: 0x00c0, 0x188: 0x00c0, 0x189: 0x0080, 0x18a: 0x00c0, 0x18b: 0x00c0,
+	0x18c: 0x00c0, 0x18d: 0x00c0, 0x18e: 0x00c0, 0x18f: 0x00c0, 0x190: 0x00c0, 0x191: 0x00c0,
+	0x192: 0x00c0, 0x193: 0x00c0, 0x194: 0x00c0, 0x195: 0x00c0, 0x196: 0x00c0, 0x197: 0x00c0,
+	0x198: 0x00c0, 0x199: 0x00c0, 0x19a: 0x00c0, 0x19b: 0x00c0, 0x19c: 0x00c0, 0x19d: 0x00c0,
+	0x19e: 0x00c0, 0x19f: 0x00c0, 0x1a0: 0x00c0, 0x1a1: 0x00c0, 0x1a2: 0x00c0, 0x1a3: 0x00c0,
+	0x1a4: 0x00c0, 0x1a5: 0x00c0, 0x1a6: 0x00c0, 0x1a7: 0x00c0, 0x1a8: 0x00c0, 0x1a9: 0x00c0,
+	0x1aa: 0x00c0, 0x1ab: 0x00c0, 0x1ac: 0x00c0, 0x1ad: 0x00c0, 0x1ae: 0x00c0, 0x1af: 0x00c0,
+	0x1b0: 0x00c0, 0x1b1: 0x00c0, 0x1b2: 0x00c0, 0x1b3: 0x00c0, 0x1b4: 0x00c0, 0x1b5: 0x00c0,
+	0x1b6: 0x00c0, 0x1b7: 0x00c0, 0x1b8: 0x00c0, 0x1b9: 0x00c0, 0x1ba: 0x00c0, 0x1bb: 0x00c0,
+	0x1bc: 0x00c0, 0x1bd: 0x00c0, 0x1be: 0x00c0, 0x1bf: 0x0080,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x00c0, 0x1c1: 0x00c0, 0x1c2: 0x00c0, 0x1c3: 0x00c0, 0x1c4: 0x00c0, 0x1c5: 0x00c0,
+	0x1c6: 0x00c0, 0x1c7: 0x00c0, 0x1c8: 0x00c0, 0x1c9: 0x00c0, 0x1ca: 0x00c0, 0x1cb: 0x00c0,
+	0x1cc: 0x00c0, 0x1cd: 0x00c0, 0x1ce: 0x00c0, 0x1cf: 0x00c0, 0x1d0: 0x00c0, 0x1d1: 0x00c0,
+	0x1d2: 0x00c0, 0x1d3: 0x00c0, 0x1d4: 0x00c0, 0x1d5: 0x00c0, 0x1d6: 0x00c0, 0x1d7: 0x00c0,
+	0x1d8: 0x00c0, 0x1d9: 0x00c0, 0x1da: 0x00c0, 0x1db: 0x00c0, 0x1dc: 0x00c0, 0x1dd: 0x00c0,
+	0x1de: 0x00c0, 0x1df: 0x00c0, 0x1e0: 0x00c0, 0x1e1: 0x00c0, 0x1e2: 0x00c0, 0x1e3: 0x00c0,
+	0x1e4: 0x00c0, 0x1e5: 0x00c0, 0x1e6: 0x00c0, 0x1e7: 0x00c0, 0x1e8: 0x00c0, 0x1e9: 0x00c0,
+	0x1ea: 0x00c0, 0x1eb: 0x00c0, 0x1ec: 0x00c0, 0x1ed: 0x00c0, 0x1ee: 0x00c0, 0x1ef: 0x00c0,
+	0x1f0: 0x00c0, 0x1f1: 0x00c0, 0x1f2: 0x00c0, 0x1f3: 0x00c0, 0x1f4: 0x00c0, 0x1f5: 0x00c0,
+	0x1f6: 0x00c0, 0x1f7: 0x00c0, 0x1f8: 0x00c0, 0x1f9: 0x00c0, 0x1fa: 0x00c0, 0x1fb: 0x00c0,
+	0x1fc: 0x00c0, 0x1fd: 0x00c0, 0x1fe: 0x00c0, 0x1ff: 0x00c0,
+	// Block 0x8, offset 0x200
+	0x200: 0x00c0, 0x201: 0x00c0, 0x202: 0x00c0, 0x203: 0x00c0, 0x204: 0x0080, 0x205: 0x0080,
+	0x206: 0x0080, 0x207: 0x0080, 0x208: 0x0080, 0x209: 0x0080, 0x20a: 0x0080, 0x20b: 0x0080,
+	0x20c: 0x0080, 0x20d: 0x00c0, 0x20e: 0x00c0, 0x20f: 0x00c0, 0x210: 0x00c0, 0x211: 0x00c0,
+	0x212: 0x00c0, 0x213: 0x00c0, 0x214: 0x00c0, 0x215: 0x00c0, 0x216: 0x00c0, 0x217: 0x00c0,
+	0x218: 0x00c0, 0x219: 0x00c0, 0x21a: 0x00c0, 0x21b: 0x00c0, 0x21c: 0x00c0, 0x21d: 0x00c0,
+	0x21e: 0x00c0, 0x21f: 0x00c0, 0x220: 0x00c0, 0x221: 0x00c0, 0x222: 0x00c0, 0x223: 0x00c0,
+	0x224: 0x00c0, 0x225: 0x00c0, 0x226: 0x00c0, 0x227: 0x00c0, 0x228: 0x00c0, 0x229: 0x00c0,
+	0x22a: 0x00c0, 0x22b: 0x00c0, 0x22c: 0x00c0, 0x22d: 0x00c0, 0x22e: 0x00c0, 0x22f: 0x00c0,
+	0x230: 0x00c0, 0x231: 0x0080, 0x232: 0x0080, 0x233: 0x0080, 0x234: 0x00c0, 0x235: 0x00c0,
+	0x236: 0x00c0, 0x237: 0x00c0, 0x238: 0x00c0, 0x239: 0x00c0, 0x23a: 0x00c0, 0x23b: 0x00c0,
+	0x23c: 0x00c0, 0x23d: 0x00c0, 0x23e: 0x00c0, 0x23f: 0x00c0,
+	// Block 0x9, offset 0x240
+	0x240: 0x00c0, 0x241: 0x00c0, 0x242: 0x00c0, 0x243: 0x00c0, 0x244: 0x00c0, 0x245: 0x00c0,
+	0x246: 0x00c0, 0x247: 0x00c0, 0x248: 0x00c0, 0x249: 0x00c0, 0x24a: 0x00c0, 0x24b: 0x00c0,
+	0x24c: 0x00c0, 0x24d: 0x00c0, 0x24e: 0x00c0, 0x24f: 0x00c0, 0x250: 0x00c0, 0x251: 0x00c0,
+	0x252: 0x00c0, 0x253: 0x00c0, 0x254: 0x00c0, 0x255: 0x00c0, 0x256: 0x00c0, 0x257: 0x00c0,
+	0x258: 0x00c0, 0x259: 0x00c0, 0x25a: 0x00c0, 0x25b: 0x00c0, 0x25c: 0x00c0, 0x25d: 0x00c0,
+	0x25e: 0x00c0, 0x25f: 0x00c0, 0x260: 0x00c0, 0x261: 0x00c0, 0x262: 0x00c0, 0x263: 0x00c0,
+	0x264: 0x00c0, 0x265: 0x00c0, 0x266: 0x00c0, 0x267: 0x00c0, 0x268: 0x00c0, 0x269: 0x00c0,
+	0x26a: 0x00c0, 0x26b: 0x00c0, 0x26c: 0x00c0, 0x26d: 0x00c0, 0x26e: 0x00c0, 0x26f: 0x00c0,
+	0x270: 0x0080, 0x271: 0x0080, 0x272: 0x0080, 0x273: 0x0080, 0x274: 0x0080, 0x275: 0x0080,
+	0x276: 0x0080, 0x277: 0x0080, 0x278: 0x0080, 0x279: 0x00c0, 0x27a: 0x00c0, 0x27b: 0x00c0,
+	0x27c: 0x00c0, 0x27d: 0x00c0, 0x27e: 0x00c0, 0x27f: 0x00c0,
+	// Block 0xa, offset 0x280
+	0x280: 0x00c0, 0x281: 0x00c0, 0x282: 0x0080, 0x283: 0x0080, 0x284: 0x0080, 0x285: 0x0080,
+	0x286: 0x00c0, 0x287: 0x00c0, 0x288: 0x00c0, 0x289: 0x00c0, 0x28a: 0x00c0, 0x28b: 0x00c0,
+	0x28c: 0x00c0, 0x28d: 0x00c0, 0x28e: 0x00c0, 0x28f: 0x00c0, 0x290: 0x00c0, 0x291: 0x00c0,
+	0x292: 0x0080, 0x293: 0x0080, 0x294: 0x0080, 0x295: 0x0080, 0x296: 0x0080, 0x297: 0x0080,
+	0x298: 0x0080, 0x299: 0x0080, 0x29a: 0x0080, 0x29b: 0x0080, 0x29c: 0x0080, 0x29d: 0x0080,
+	0x29e: 0x0080, 0x29f: 0x0080, 0x2a0: 0x0080, 0x2a1: 0x0080, 0x2a2: 0x0080, 0x2a3: 0x0080,
+	0x2a4: 0x0080, 0x2a5: 0x0080, 0x2a6: 0x0080, 0x2a7: 0x0080, 0x2a8: 0x0080, 0x2a9: 0x0080,
+	0x2aa: 0x0080, 0x2ab: 0x0080, 0x2ac: 0x00c0, 0x2ad: 0x0080, 0x2ae: 0x00c0, 0x2af: 0x0080,
+	0x2b0: 0x0080, 0x2b1: 0x0080, 0x2b2: 0x0080, 0x2b3: 0x0080, 0x2b4: 0x0080, 0x2b5: 0x0080,
+	0x2b6: 0x0080, 0x2b7: 0x0080, 0x2b8: 0x0080, 0x2b9: 0x0080, 0x2ba: 0x0080, 0x2bb: 0x0080,
+	0x2bc: 0x0080, 0x2bd: 0x0080, 0x2be: 0x0080, 0x2bf: 0x0080,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x00c3, 0x2c1: 0x00c3, 0x2c2: 0x00c3, 0x2c3: 0x00c3, 0x2c4: 0x00c3, 0x2c5: 0x00c3,
+	0x2c6: 0x00c3, 0x2c7: 0x00c3, 0x2c8: 0x00c3, 0x2c9: 0x00c3, 0x2ca: 0x00c3, 0x2cb: 0x00c3,
+	0x2cc: 0x00c3, 0x2cd: 0x00c3, 0x2ce: 0x00c3, 0x2cf: 0x00c3, 0x2d0: 0x00c3, 0x2d1: 0x00c3,
+	0x2d2: 0x00c3, 0x2d3: 0x00c3, 0x2d4: 0x00c3, 0x2d5: 0x00c3, 0x2d6: 0x00c3, 0x2d7: 0x00c3,
+	0x2d8: 0x00c3, 0x2d9: 0x00c3, 0x2da: 0x00c3, 0x2db: 0x00c3, 0x2dc: 0x00c3, 0x2dd: 0x00c3,
+	0x2de: 0x00c3, 0x2df: 0x00c3, 0x2e0: 0x00c3, 0x2e1: 0x00c3, 0x2e2: 0x00c3, 0x2e3: 0x00c3,
+	0x2e4: 0x00c3, 0x2e5: 0x00c3, 0x2e6: 0x00c3, 0x2e7: 0x00c3, 0x2e8: 0x00c3, 0x2e9: 0x00c3,
+	0x2ea: 0x00c3, 0x2eb: 0x00c3, 0x2ec: 0x00c3, 0x2ed: 0x00c3, 0x2ee: 0x00c3, 0x2ef: 0x00c3,
+	0x2f0: 0x00c3, 0x2f1: 0x00c3, 0x2f2: 0x00c3, 0x2f3: 0x00c3, 0x2f4: 0x00c3, 0x2f5: 0x00c3,
+	0x2f6: 0x00c3, 0x2f7: 0x00c3, 0x2f8: 0x00c3, 0x2f9: 0x00c3, 0x2fa: 0x00c3, 0x2fb: 0x00c3,
+	0x2fc: 0x00c3, 0x2fd: 0x00c3, 0x2fe: 0x00c3, 0x2ff: 0x00c3,
+	// Block 0xc, offset 0x300
+	0x300: 0x0083, 0x301: 0x0083, 0x302: 0x00c3, 0x303: 0x0083, 0x304: 0x0083, 0x305: 0x00c3,
+	0x306: 0x00c3, 0x307: 0x00c3, 0x308: 0x00c3, 0x309: 0x00c3, 0x30a: 0x00c3, 0x30b: 0x00c3,
+	0x30c: 0x00c3, 0x30d: 0x00c3, 0x30e: 0x00c3, 0x30f: 0x0040, 0x310: 0x00c3, 0x311: 0x00c3,
+	0x312: 0x00c3, 0x313: 0x00c3, 0x314: 0x00c3, 0x315: 0x00c3, 0x316: 0x00c3, 0x317: 0x00c3,
+	0x318: 0x00c3, 0x319: 0x00c3, 0x31a: 0x00c3, 0x31b: 0x00c3, 0x31c: 0x00c3, 0x31d: 0x00c3,
+	0x31e: 0x00c3, 0x31f: 0x00c3, 0x320: 0x00c3, 0x321: 0x00c3, 0x322: 0x00c3, 0x323: 0x00c3,
+	0x324: 0x00c3, 0x325: 0x00c3, 0x326: 0x00c3, 0x327: 0x00c3, 0x328: 0x00c3, 0x329: 0x00c3,
+	0x32a: 0x00c3, 0x32b: 0x00c3, 0x32c: 0x00c3, 0x32d: 0x00c3, 0x32e: 0x00c3, 0x32f: 0x00c3,
+	0x330: 0x00c8, 0x331: 0x00c8, 0x332: 0x00c8, 0x333: 0x00c8, 0x334: 0x0080, 0x335: 0x0050,
+	0x336: 0x00c8, 0x337: 0x00c8, 0x33a: 0x0088, 0x33b: 0x00c8,
+	0x33c: 0x00c8, 0x33d: 0x00c8, 0x33e: 0x0080, 0x33f: 0x00c8,
+	// Block 0xd, offset 0x340
+	0x344: 0x0088, 0x345: 0x0080,
+	0x346: 0x00c8, 0x347: 0x0080, 0x348: 0x00c8, 0x349: 0x00c8, 0x34a: 0x00c8,
+	0x34c: 0x00c8, 0x34e: 0x00c8, 0x34f: 0x00c8, 0x350: 0x00c8, 0x351: 0x00c8,
+	0x352: 0x00c8, 0x353: 0x00c8, 0x354: 0x00c8, 0x355: 0x00c8, 0x356: 0x00c8, 0x357: 0x00c8,
+	0x358: 0x00c8, 0x359: 0x00c8, 0x35a: 0x00c8, 0x35b: 0x00c8, 0x35c: 0x00c8, 0x35d: 0x00c8,
+	0x35e: 0x00c8, 0x35f: 0x00c8, 0x360: 0x00c8, 0x361: 0x00c8, 0x363: 0x00c8,
+	0x364: 0x00c8, 0x365: 0x00c8, 0x366: 0x00c8, 0x367: 0x00c8, 0x368: 0x00c8, 0x369: 0x00c8,
+	0x36a: 0x00c8, 0x36b: 0x00c8, 0x36c: 0x00c8, 0x36d: 0x00c8, 0x36e: 0x00c8, 0x36f: 0x00c8,
+	0x370: 0x00c8, 0x371: 0x00c8, 0x372: 0x00c8, 0x373: 0x00c8, 0x374: 0x00c8, 0x375: 0x00c8,
+	0x376: 0x00c8, 0x377: 0x00c8, 0x378: 0x00c8, 0x379: 0x00c8, 0x37a: 0x00c8, 0x37b: 0x00c8,
+	0x37c: 0x00c8, 0x37d: 0x00c8, 0x37e: 0x00c8, 0x37f: 0x00c8,
+	// Block 0xe, offset 0x380
+	0x380: 0x00c8, 0x381: 0x00c8, 0x382: 0x00c8, 0x383: 0x00c8, 0x384: 0x00c8, 0x385: 0x00c8,
+	0x386: 0x00c8, 0x387: 0x00c8, 0x388: 0x00c8, 0x389: 0x00c8, 0x38a: 0x00c8, 0x38b: 0x00c8,
+	0x38c: 0x00c8, 0x38d: 0x00c8, 0x38e: 0x00c8, 0x38f: 0x00c8, 0x390: 0x0088, 0x391: 0x0088,
+	0x392: 0x0088, 0x393: 0x0088, 0x394: 0x0088, 0x395: 0x0088, 0x396: 0x0088, 0x397: 0x00c8,
+	0x398: 0x00c8, 0x399: 0x00c8, 0x39a: 0x00c8, 0x39b: 0x00c8, 0x39c: 0x00c8, 0x39d: 0x00c8,
+	0x39e: 0x00c8, 0x39f: 0x00c8, 0x3a0: 0x00c8, 0x3a1: 0x00c8, 0x3a2: 0x00c0, 0x3a3: 0x00c0,
+	0x3a4: 0x00c0, 0x3a5: 0x00c0, 0x3a6: 0x00c0, 0x3a7: 0x00c0, 0x3a8: 0x00c0, 0x3a9: 0x00c0,
+	0x3aa: 0x00c0, 0x3ab: 0x00c0, 0x3ac: 0x00c0, 0x3ad: 0x00c0, 0x3ae: 0x00c0, 0x3af: 0x00c0,
+	0x3b0: 0x0088, 0x3b1: 0x0088, 0x3b2: 0x0088, 0x3b3: 0x00c8, 0x3b4: 0x0088, 0x3b5: 0x0088,
+	0x3b6: 0x0088, 0x3b7: 0x00c8, 0x3b8: 0x00c8, 0x3b9: 0x0088, 0x3ba: 0x00c8, 0x3bb: 0x00c8,
+	0x3bc: 0x00c8, 0x3bd: 0x00c8, 0x3be: 0x00c8, 0x3bf: 0x00c8,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x00c0, 0x3c1: 0x00c0, 0x3c2: 0x0080, 0x3c3: 0x00c3, 0x3c4: 0x00c3, 0x3c5: 0x00c3,
+	0x3c6: 0x00c3, 0x3c7: 0x00c3, 0x3c8: 0x0083, 0x3c9: 0x0083, 0x3ca: 0x00c0, 0x3cb: 0x00c0,
+	0x3cc: 0x00c0, 0x3cd: 0x00c0, 0x3ce: 0x00c0, 0x3cf: 0x00c0, 0x3d0: 0x00c0, 0x3d1: 0x00c0,
+	0x3d2: 0x00c0, 0x3d3: 0x00c0, 0x3d4: 0x00c0, 0x3d5: 0x00c0, 0x3d6: 0x00c0, 0x3d7: 0x00c0,
+	0x3d8: 0x00c0, 0x3d9: 0x00c0, 0x3da: 0x00c0, 0x3db: 0x00c0, 0x3dc: 0x00c0, 0x3dd: 0x00c0,
+	0x3de: 0x00c0, 0x3df: 0x00c0, 0x3e0: 0x00c0, 0x3e1: 0x00c0, 0x3e2: 0x00c0, 0x3e3: 0x00c0,
+	0x3e4: 0x00c0, 0x3e5: 0x00c0, 0x3e6: 0x00c0, 0x3e7: 0x00c0, 0x3e8: 0x00c0, 0x3e9: 0x00c0,
+	0x3ea: 0x00c0, 0x3eb: 0x00c0, 0x3ec: 0x00c0, 0x3ed: 0x00c0, 0x3ee: 0x00c0, 0x3ef: 0x00c0,
+	0x3f0: 0x00c0, 0x3f1: 0x00c0, 0x3f2: 0x00c0, 0x3f3: 0x00c0, 0x3f4: 0x00c0, 0x3f5: 0x00c0,
+	0x3f6: 0x00c0, 0x3f7: 0x00c0, 0x3f8: 0x00c0, 0x3f9: 0x00c0, 0x3fa: 0x00c0, 0x3fb: 0x00c0,
+	0x3fc: 0x00c0, 0x3fd: 0x00c0, 0x3fe: 0x00c0, 0x3ff: 0x00c0,
+	// Block 0x10, offset 0x400
+	0x400: 0x00c0, 0x401: 0x00c0, 0x402: 0x00c0, 0x403: 0x00c0, 0x404: 0x00c0, 0x405: 0x00c0,
+	0x406: 0x00c0, 0x407: 0x00c0, 0x408: 0x00c0, 0x409: 0x00c0, 0x40a: 0x00c0, 0x40b: 0x00c0,
+	0x40c: 0x00c0, 0x40d: 0x00c0, 0x40e: 0x00c0, 0x40f: 0x00c0, 0x410: 0x00c0, 0x411: 0x00c0,
+	0x412: 0x00c0, 0x413: 0x00c0, 0x414: 0x00c0, 0x415: 0x00c0, 0x416: 0x00c0, 0x417: 0x00c0,
+	0x418: 0x00c0, 0x419: 0x00c0, 0x41a: 0x00c0, 0x41b: 0x00c0, 0x41c: 0x00c0, 0x41d: 0x00c0,
+	0x41e: 0x00c0, 0x41f: 0x00c0, 0x420: 0x00c0, 0x421: 0x00c0, 0x422: 0x00c0, 0x423: 0x00c0,
+	0x424: 0x00c0, 0x425: 0x00c0, 0x426: 0x00c0, 0x427: 0x00c0, 0x428: 0x00c0, 0x429: 0x00c0,
+	0x42a: 0x00c0, 0x42b: 0x00c0, 0x42c: 0x00c0, 0x42d: 0x00c0, 0x42e: 0x00c0, 0x42f: 0x00c0,
+	0x431: 0x00c0, 0x432: 0x00c0, 0x433: 0x00c0, 0x434: 0x00c0, 0x435: 0x00c0,
+	0x436: 0x00c0, 0x437: 0x00c0, 0x438: 0x00c0, 0x439: 0x00c0, 0x43a: 0x00c0, 0x43b: 0x00c0,
+	0x43c: 0x00c0, 0x43d: 0x00c0, 0x43e: 0x00c0, 0x43f: 0x00c0,
+	// Block 0x11, offset 0x440
+	0x440: 0x00c0, 0x441: 0x00c0, 0x442: 0x00c0, 0x443: 0x00c0, 0x444: 0x00c0, 0x445: 0x00c0,
+	0x446: 0x00c0, 0x447: 0x00c0, 0x448: 0x00c0, 0x449: 0x00c0, 0x44a: 0x00c0, 0x44b: 0x00c0,
+	0x44c: 0x00c0, 0x44d: 0x00c0, 0x44e: 0x00c0, 0x44f: 0x00c0, 0x450: 0x00c0, 0x451: 0x00c0,
+	0x452: 0x00c0, 0x453: 0x00c0, 0x454: 0x00c0, 0x455: 0x00c0, 0x456: 0x00c0,
+	0x459: 0x00c0, 0x45a: 0x0080, 0x45b: 0x0080, 0x45c: 0x0080, 0x45d: 0x0080,
+	0x45e: 0x0080, 0x45f: 0x0080, 0x460: 0x00c0, 0x461: 0x00c0, 0x462: 0x00c0, 0x463: 0x00c0,
+	0x464: 0x00c0, 0x465: 0x00c0, 0x466: 0x00c0, 0x467: 0x00c0, 0x468: 0x00c0, 0x469: 0x00c0,
+	0x46a: 0x00c0, 0x46b: 0x00c0, 0x46c: 0x00c0, 0x46d: 0x00c0, 0x46e: 0x00c0, 0x46f: 0x00c0,
+	0x470: 0x00c0, 0x471: 0x00c0, 0x472: 0x00c0, 0x473: 0x00c0, 0x474: 0x00c0, 0x475: 0x00c0,
+	0x476: 0x00c0, 0x477: 0x00c0, 0x478: 0x00c0, 0x479: 0x00c0, 0x47a: 0x00c0, 0x47b: 0x00c0,
+	0x47c: 0x00c0, 0x47d: 0x00c0, 0x47e: 0x00c0, 0x47f: 0x00c0,
+	// Block 0x12, offset 0x480
+	0x480: 0x00c0, 0x481: 0x00c0, 0x482: 0x00c0, 0x483: 0x00c0, 0x484: 0x00c0, 0x485: 0x00c0,
+	0x486: 0x00c0, 0x487: 0x0080, 0x488: 0x00c0, 0x489: 0x0080, 0x48a: 0x0080,
+	0x48d: 0x0080, 0x48e: 0x0080, 0x48f: 0x0080, 0x491: 0x00cb,
+	0x492: 0x00cb, 0x493: 0x00cb, 0x494: 0x00cb, 0x495: 0x00cb, 0x496: 0x00cb, 0x497: 0x00cb,
+	0x498: 0x00cb, 0x499: 0x00cb, 0x49a: 0x00cb, 0x49b: 0x00cb, 0x49c: 0x00cb, 0x49d: 0x00cb,
+	0x49e: 0x00cb, 0x49f: 0x00cb, 0x4a0: 0x00cb, 0x4a1: 0x00cb, 0x4a2: 0x00cb, 0x4a3: 0x00cb,
+	0x4a4: 0x00cb, 0x4a5: 0x00cb, 0x4a6: 0x00cb, 0x4a7: 0x00cb, 0x4a8: 0x00cb, 0x4a9: 0x00cb,
+	0x4aa: 0x00cb, 0x4ab: 0x00cb, 0x4ac: 0x00cb, 0x4ad: 0x00cb, 0x4ae: 0x00cb, 0x4af: 0x00cb,
+	0x4b0: 0x00cb, 0x4b1: 0x00cb, 0x4b2: 0x00cb, 0x4b3: 0x00cb, 0x4b4: 0x00cb, 0x4b5: 0x00cb,
+	0x4b6: 0x00cb, 0x4b7: 0x00cb, 0x4b8: 0x00cb, 0x4b9: 0x00cb, 0x4ba: 0x00cb, 0x4bb: 0x00cb,
+	0x4bc: 0x00cb, 0x4bd: 0x00cb, 0x4be: 0x008a, 0x4bf: 0x00cb,
+	// Block 0x13, offset 0x4c0
+	0x4c0: 0x008a, 0x4c1: 0x00cb, 0x4c2: 0x00cb, 0x4c3: 0x008a, 0x4c4: 0x00cb, 0x4c5: 0x00cb,
+	0x4c6: 0x008a, 0x4c7: 0x00cb,
+	0x4d0: 0x00ca, 0x4d1: 0x00ca,
+	0x4d2: 0x00ca, 0x4d3: 0x00ca, 0x4d4: 0x00ca, 0x4d5: 0x00ca, 0x4d6: 0x00ca, 0x4d7: 0x00ca,
+	0x4d8: 0x00ca, 0x4d9: 0x00ca, 0x4da: 0x00ca, 0x4db: 0x00ca, 0x4dc: 0x00ca, 0x4dd: 0x00ca,
+	0x4de: 0x00ca, 0x4df: 0x00ca, 0x4e0: 0x00ca, 0x4e1: 0x00ca, 0x4e2: 0x00ca, 0x4e3: 0x00ca,
+	0x4e4: 0x00ca, 0x4e5: 0x00ca, 0x4e6: 0x00ca, 0x4e7: 0x00ca, 0x4e8: 0x00ca, 0x4e9: 0x00ca,
+	0x4ea: 0x00ca, 0x4ef: 0x00ca,
+	0x4f0: 0x00ca, 0x4f1: 0x00ca, 0x4f2: 0x00ca, 0x4f3: 0x0051, 0x4f4: 0x0051,
+	// Block 0x14, offset 0x500
+	0x500: 0x0040, 0x501: 0x0040, 0x502: 0x0040, 0x503: 0x0040, 0x504: 0x0040, 0x505: 0x0040,
+	0x506: 0x0080, 0x507: 0x0080, 0x508: 0x0080, 0x509: 0x0080, 0x50a: 0x0080, 0x50b: 0x0080,
+	0x50c: 0x0080, 0x50d: 0x0080, 0x50e: 0x0080, 0x50f: 0x0080, 0x510: 0x00c3, 0x511: 0x00c3,
+	0x512: 0x00c3, 0x513: 0x00c3, 0x514: 0x00c3, 0x515: 0x00c3, 0x516: 0x00c3, 0x517: 0x00c3,
+	0x518: 0x00c3, 0x519: 0x00c3, 0x51a: 0x00c3, 0x51b: 0x0080, 0x51c: 0x0040, 0x51d: 0x0080,
+	0x51e: 0x0080, 0x51f: 0x0080, 0x520: 0x00c2, 0x521: 0x00c0, 0x522: 0x00c4, 0x523: 0x00c4,
+	0x524: 0x00c4, 0x525: 0x00c4, 0x526: 0x00c2, 0x527: 0x00c4, 0x528: 0x00c2, 0x529: 0x00c4,
+	0x52a: 0x00c2, 0x52b: 0x00c2, 0x52c: 0x00c2, 0x52d: 0x00c2, 0x52e: 0x00c2, 0x52f: 0x00c4,
+	0x530: 0x00c4, 0x531: 0x00c4, 0x532: 0x00c4, 0x533: 0x00c2, 0x534: 0x00c2, 0x535: 0x00c2,
+	0x536: 0x00c2, 0x537: 0x00c2, 0x538: 0x00c2, 0x539: 0x00c2, 0x53a: 0x00c2, 0x53b: 0x00c2,
+	0x53c: 0x00c2, 0x53d: 0x00c2, 0x53e: 0x00c2, 0x53f: 0x00c2,
+	// Block 0x15, offset 0x540
+	0x540: 0x0040, 0x541: 0x00c2, 0x542: 0x00c2, 0x543: 0x00c2, 0x544: 0x00c2, 0x545: 0x00c2,
+	0x546: 0x00c2, 0x547: 0x00c2, 0x548: 0x00c4, 0x549: 0x00c2, 0x54a: 0x00c2, 0x54b: 0x00c3,
+	0x54c: 0x00c3, 0x54d: 0x00c3, 0x54e: 0x00c3, 0x54f: 0x00c3, 0x550: 0x00c3, 0x551: 0x00c3,
+	0x552: 0x00c3, 0x553: 0x00c3, 0x554: 0x00c3, 0x555: 0x00c3, 0x556: 0x00c3, 0x557: 0x00c3,
+	0x558: 0x00c3, 0x559: 0x00c3, 0x55a: 0x00c3, 0x55b: 0x00c3, 0x55c: 0x00c3, 0x55d: 0x00c3,
+	0x55e: 0x00c3, 0x55f: 0x00c3, 0x560: 0x0053, 0x561: 0x0053, 0x562: 0x0053, 0x563: 0x0053,
+	0x564: 0x0053, 0x565: 0x0053, 0x566: 0x0053, 0x567: 0x0053, 0x568: 0x0053, 0x569: 0x0053,
+	0x56a: 0x0080, 0x56b: 0x0080, 0x56c: 0x0080, 0x56d: 0x0080, 0x56e: 0x00c2, 0x56f: 0x00c2,
+	0x570: 0x00c3, 0x571: 0x00c4, 0x572: 0x00c4, 0x573: 0x00c4, 0x574: 0x00c0, 0x575: 0x0084,
+	0x576: 0x0084, 0x577: 0x0084, 0x578: 0x0082, 0x579: 0x00c2, 0x57a: 0x00c2, 0x57b: 0x00c2,
+	0x57c: 0x00c2, 0x57d: 0x00c2, 0x57e: 0x00c2, 0x57f: 0x00c2,
+	// Block 0x16, offset 0x580
+	0x580: 0x00c2, 0x581: 0x00c2, 0x582: 0x00c2, 0x583: 0x00c2, 0x584: 0x00c2, 0x585: 0x00c2,
+	0x586: 0x00c2, 0x587: 0x00c2, 0x588: 0x00c4, 0x589: 0x00c4, 0x58a: 0x00c4, 0x58b: 0x00c4,
+	0x58c: 0x00c4, 0x58d: 0x00c4, 0x58e: 0x00c4, 0x58f: 0x00c4, 0x590: 0x00c4, 0x591: 0x00c4,
+	0x592: 0x00c4, 0x593: 0x00c4, 0x594: 0x00c4, 0x595: 0x00c4, 0x596: 0x00c4, 0x597: 0x00c4,
+	0x598: 0x00c4, 0x599: 0x00c4, 0x59a: 0x00c2, 0x59b: 0x00c2, 0x59c: 0x00c2, 0x59d: 0x00c2,
+	0x59e: 0x00c2, 0x59f: 0x00c2, 0x5a0: 0x00c2, 0x5a1: 0x00c2, 0x5a2: 0x00c2, 0x5a3: 0x00c2,
+	0x5a4: 0x00c2, 0x5a5: 0x00c2, 0x5a6: 0x00c2, 0x5a7: 0x00c2, 0x5a8: 0x00c2, 0x5a9: 0x00c2,
+	0x5aa: 0x00c2, 0x5ab: 0x00c2, 0x5ac: 0x00c2, 0x5ad: 0x00c2, 0x5ae: 0x00c2, 0x5af: 0x00c2,
+	0x5b0: 0x00c2, 0x5b1: 0x00c2, 0x5b2: 0x00c2, 0x5b3: 0x00c2, 0x5b4: 0x00c2, 0x5b5: 0x00c2,
+	0x5b6: 0x00c2, 0x5b7: 0x00c2, 0x5b8: 0x00c2, 0x5b9: 0x00c2, 0x5ba: 0x00c2, 0x5bb: 0x00c2,
+	0x5bc: 0x00c2, 0x5bd: 0x00c2, 0x5be: 0x00c2, 0x5bf: 0x00c2,
+	// Block 0x17, offset 0x5c0
+	0x5c0: 0x00c4, 0x5c1: 0x00c2, 0x5c2: 0x00c2, 0x5c3: 0x00c4, 0x5c4: 0x00c4, 0x5c5: 0x00c4,
+	0x5c6: 0x00c4, 0x5c7: 0x00c4, 0x5c8: 0x00c4, 0x5c9: 0x00c4, 0x5ca: 0x00c4, 0x5cb: 0x00c4,
+	0x5cc: 0x00c2, 0x5cd: 0x00c4, 0x5ce: 0x00c2, 0x5cf: 0x00c4, 0x5d0: 0x00c2, 0x5d1: 0x00c2,
+	0x5d2: 0x00c4, 0x5d3: 0x00c4, 0x5d4: 0x0080, 0x5d5: 0x00c4, 0x5d6: 0x00c3, 0x5d7: 0x00c3,
+	0x5d8: 0x00c3, 0x5d9: 0x00c3, 0x5da: 0x00c3, 0x5db: 0x00c3, 0x5dc: 0x00c3, 0x5dd: 0x0040,
+	0x5de: 0x0080, 0x5df: 0x00c3, 0x5e0: 0x00c3, 0x5e1: 0x00c3, 0x5e2: 0x00c3, 0x5e3: 0x00c3,
+	0x5e4: 0x00c3, 0x5e5: 0x00c0, 0x5e6: 0x00c0, 0x5e7: 0x00c3, 0x5e8: 0x00c3, 0x5e9: 0x0080,
+	0x5ea: 0x00c3, 0x5eb: 0x00c3, 0x5ec: 0x00c3, 0x5ed: 0x00c3, 0x5ee: 0x00c4, 0x5ef: 0x00c4,
+	0x5f0: 0x0054, 0x5f1: 0x0054, 0x5f2: 0x0054, 0x5f3: 0x0054, 0x5f4: 0x0054, 0x5f5: 0x0054,
+	0x5f6: 0x0054, 0x5f7: 0x0054, 0x5f8: 0x0054, 0x5f9: 0x0054, 0x5fa: 0x00c2, 0x5fb: 0x00c2,
+	0x5fc: 0x00c2, 0x5fd: 0x00c0, 0x5fe: 0x00c0, 0x5ff: 0x00c2,
+	// Block 0x18, offset 0x600
+	0x600: 0x0080, 0x601: 0x0080, 0x602: 0x0080, 0x603: 0x0080, 0x604: 0x0080, 0x605: 0x0080,
+	0x606: 0x0080, 0x607: 0x0080, 0x608: 0x0080, 0x609: 0x0080, 0x60a: 0x0080, 0x60b: 0x0080,
+	0x60c: 0x0080, 0x60d: 0x0080, 0x60f: 0x0040, 0x610: 0x00c4, 0x611: 0x00c3,
+	0x612: 0x00c2, 0x613: 0x00c2, 0x614: 0x00c2, 0x615: 0x00c4, 0x616: 0x00c4, 0x617: 0x00c4,
+	0x618: 0x00c4, 0x619: 0x00c4, 0x61a: 0x00c2, 0x61b: 0x00c2, 0x61c: 0x00c2, 0x61d: 0x00c2,
+	0x61e: 0x00c4, 0x61f: 0x00c2, 0x620: 0x00c2, 0x621: 0x00c2, 0x622: 0x00c2, 0x623: 0x00c2,
+	0x624: 0x00c2, 0x625: 0x00c2, 0x626: 0x00c2, 0x627: 0x00c2, 0x628: 0x00c4, 0x629: 0x00c2,
+	0x62a: 0x00c4, 0x62b: 0x00c2, 0x62c: 0x00c4, 0x62d: 0x00c2, 0x62e: 0x00c2, 0x62f: 0x00c4,
+	0x630: 0x00c3, 0x631: 0x00c3, 0x632: 0x00c3, 0x633: 0x00c3, 0x634: 0x00c3, 0x635: 0x00c3,
+	0x636: 0x00c3, 0x637: 0x00c3, 0x638: 0x00c3, 0x639: 0x00c3, 0x63a: 0x00c3, 0x63b: 0x00c3,
+	0x63c: 0x00c3, 0x63d: 0x00c3, 0x63e: 0x00c3, 0x63f: 0x00c3,
+	// Block 0x19, offset 0x640
+	0x640: 0x00c3, 0x641: 0x00c3, 0x642: 0x00c3, 0x643: 0x00c3, 0x644: 0x00c3, 0x645: 0x00c3,
+	0x646: 0x00c3, 0x647: 0x00c3, 0x648: 0x00c3, 0x649: 0x00c3, 0x64a: 0x00c3,
+	0x64d: 0x00c4, 0x64e: 0x00c2, 0x64f: 0x00c2, 0x650: 0x00c2, 0x651: 0x00c2,
+	0x652: 0x00c2, 0x653: 0x00c2, 0x654: 0x00c2, 0x655: 0x00c2, 0x656: 0x00c2, 0x657: 0x00c2,
+	0x658: 0x00c2, 0x659: 0x00c4, 0x65a: 0x00c4, 0x65b: 0x00c4, 0x65c: 0x00c2, 0x65d: 0x00c2,
+	0x65e: 0x00c2, 0x65f: 0x00c2, 0x660: 0x00c2, 0x661: 0x00c2, 0x662: 0x00c2, 0x663: 0x00c2,
+	0x664: 0x00c2, 0x665: 0x00c2, 0x666: 0x00c2, 0x667: 0x00c2, 0x668: 0x00c2, 0x669: 0x00c2,
+	0x66a: 0x00c2, 0x66b: 0x00c4, 0x66c: 0x00c4, 0x66d: 0x00c2, 0x66e: 0x00c2, 0x66f: 0x00c2,
+	0x670: 0x00c2, 0x671: 0x00c4, 0x672: 0x00c2, 0x673: 0x00c4, 0x674: 0x00c4, 0x675: 0x00c2,
+	0x676: 0x00c2, 0x677: 0x00c2, 0x678: 0x00c4, 0x679: 0x00c4, 0x67a: 0x00c2, 0x67b: 0x00c2,
+	0x67c: 0x00c2, 0x67d: 0x00c2, 0x67e: 0x00c2, 0x67f: 0x00c2,
+	// Block 0x1a, offset 0x680
+	0x680: 0x00c0, 0x681: 0x00c0, 0x682: 0x00c0, 0x683: 0x00c0, 0x684: 0x00c0, 0x685: 0x00c0,
+	0x686: 0x00c0, 0x687: 0x00c0, 0x688: 0x00c0, 0x689: 0x00c0, 0x68a: 0x00c0, 0x68b: 0x00c0,
+	0x68c: 0x00c0, 0x68d: 0x00c0, 0x68e: 0x00c0, 0x68f: 0x00c0, 0x690: 0x00c0, 0x691: 0x00c0,
+	0x692: 0x00c0, 0x693: 0x00c0, 0x694: 0x00c0, 0x695: 0x00c0, 0x696: 0x00c0, 0x697: 0x00c0,
+	0x698: 0x00c0, 0x699: 0x00c0, 0x69a: 0x00c0, 0x69b: 0x00c0, 0x69c: 0x00c0, 0x69d: 0x00c0,
+	0x69e: 0x00c0, 0x69f: 0x00c0, 0x6a0: 0x00c0, 0x6a1: 0x00c0, 0x6a2: 0x00c0, 0x6a3: 0x00c0,
+	0x6a4: 0x00c0, 0x6a5: 0x00c0, 0x6a6: 0x00c3, 0x6a7: 0x00c3, 0x6a8: 0x00c3, 0x6a9: 0x00c3,
+	0x6aa: 0x00c3, 0x6ab: 0x00c3, 0x6ac: 0x00c3, 0x6ad: 0x00c3, 0x6ae: 0x00c3, 0x6af: 0x00c3,
+	0x6b0: 0x00c3, 0x6b1: 0x00c0,
+	// Block 0x1b, offset 0x6c0
+	0x6c0: 0x00c0, 0x6c1: 0x00c0, 0x6c2: 0x00c0, 0x6c3: 0x00c0, 0x6c4: 0x00c0, 0x6c5: 0x00c0,
+	0x6c6: 0x00c0, 0x6c7: 0x00c0, 0x6c8: 0x00c0, 0x6c9: 0x00c0, 0x6ca: 0x00c2, 0x6cb: 0x00c2,
+	0x6cc: 0x00c2, 0x6cd: 0x00c2, 0x6ce: 0x00c2, 0x6cf: 0x00c2, 0x6d0: 0x00c2, 0x6d1: 0x00c2,
+	0x6d2: 0x00c2, 0x6d3: 0x00c2, 0x6d4: 0x00c2, 0x6d5: 0x00c2, 0x6d6: 0x00c2, 0x6d7: 0x00c2,
+	0x6d8: 0x00c2, 0x6d9: 0x00c2, 0x6da: 0x00c2, 0x6db: 0x00c2, 0x6dc: 0x00c2, 0x6dd: 0x00c2,
+	0x6de: 0x00c2, 0x6df: 0x00c2, 0x6e0: 0x00c2, 0x6e1: 0x00c2, 0x6e2: 0x00c2, 0x6e3: 0x00c2,
+	0x6e4: 0x00c2, 0x6e5: 0x00c2, 0x6e6: 0x00c2, 0x6e7: 0x00c2, 0x6e8: 0x00c2, 0x6e9: 0x00c2,
+	0x6ea: 0x00c2, 0x6eb: 0x00c3, 0x6ec: 0x00c3, 0x6ed: 0x00c3, 0x6ee: 0x00c3, 0x6ef: 0x00c3,
+	0x6f0: 0x00c3, 0x6f1: 0x00c3, 0x6f2: 0x00c3, 0x6f3: 0x00c3, 0x6f4: 0x00c0, 0x6f5: 0x00c0,
+	0x6f6: 0x0080, 0x6f7: 0x0080, 0x6f8: 0x0080, 0x6f9: 0x0080, 0x6fa: 0x0040,
+	0x6fd: 0x00c3, 0x6fe: 0x0080, 0x6ff: 0x0080,
+	// Block 0x1c, offset 0x700
+	0x700: 0x00c0, 0x701: 0x00c0, 0x702: 0x00c0, 0x703: 0x00c0, 0x704: 0x00c0, 0x705: 0x00c0,
+	0x706: 0x00c0, 0x707: 0x00c0, 0x708: 0x00c0, 0x709: 0x00c0, 0x70a: 0x00c0, 0x70b: 0x00c0,
+	0x70c: 0x00c0, 0x70d: 0x00c0, 0x70e: 0x00c0, 0x70f: 0x00c0, 0x710: 0x00c0, 0x711: 0x00c0,
+	0x712: 0x00c0, 0x713: 0x00c0, 0x714: 0x00c0, 0x715: 0x00c0, 0x716: 0x00c3, 0x717: 0x00c3,
+	0x718: 0x00c3, 0x719: 0x00c3, 0x71a: 0x00c0, 0x71b: 0x00c3, 0x71c: 0x00c3, 0x71d: 0x00c3,
+	0x71e: 0x00c3, 0x71f: 0x00c3, 0x720: 0x00c3, 0x721: 0x00c3, 0x722: 0x00c3, 0x723: 0x00c3,
+	0x724: 0x00c0, 0x725: 0x00c3, 0x726: 0x00c3, 0x727: 0x00c3, 0x728: 0x00c0, 0x729: 0x00c3,
+	0x72a: 0x00c3, 0x72b: 0x00c3, 0x72c: 0x00c3, 0x72d: 0x00c3,
+	0x730: 0x0080, 0x731: 0x0080, 0x732: 0x0080, 0x733: 0x0080, 0x734: 0x0080, 0x735: 0x0080,
+	0x736: 0x0080, 0x737: 0x0080, 0x738: 0x0080, 0x739: 0x0080, 0x73a: 0x0080, 0x73b: 0x0080,
+	0x73c: 0x0080, 0x73d: 0x0080, 0x73e: 0x0080,
+	// Block 0x1d, offset 0x740
+	0x740: 0x00c4, 0x741: 0x00c2, 0x742: 0x00c2, 0x743: 0x00c2, 0x744: 0x00c2, 0x745: 0x00c2,
+	0x746: 0x00c4, 0x747: 0x00c4, 0x748: 0x00c2, 0x749: 0x00c4, 0x74a: 0x00c2, 0x74b: 0x00c2,
+	0x74c: 0x00c2, 0x74d: 0x00c2, 0x74e: 0x00c2, 0x74f: 0x00c2, 0x750: 0x00c2, 0x751: 0x00c2,
+	0x752: 0x00c2, 0x753: 0x00c2, 0x754: 0x00c4, 0x755: 0x00c2, 0x756: 0x00c4, 0x757: 0x00c4,
+	0x758: 0x00c4, 0x759: 0x00c3, 0x75a: 0x00c3, 0x75b: 0x00c3,
+	0x75e: 0x0080, 0x760: 0x00c2, 0x761: 0x00c0, 0x762: 0x00c2, 0x763: 0x00c2,
+	0x764: 0x00c2, 0x765: 0x00c2, 0x766: 0x00c0, 0x767: 0x00c4, 0x768: 0x00c2, 0x769: 0x00c4,
+	0x76a: 0x00c4,
+	0x770: 0x00c4, 0x771: 0x00c4, 0x772: 0x00c4, 0x773: 0x00c4, 0x774: 0x00c4, 0x775: 0x00c4,
+	0x776: 0x00c4, 0x777: 0x00c4, 0x778: 0x00c4, 0x779: 0x00c4, 0x77a: 0x00c4, 0x77b: 0x00c4,
+	0x77c: 0x00c4, 0x77d: 0x00c4, 0x77e: 0x00c4, 0x77f: 0x00c4,
+	// Block 0x1e, offset 0x780
+	0x780: 0x00c4, 0x781: 0x00c4, 0x782: 0x00c4, 0x783: 0x00c0, 0x784: 0x00c0, 0x785: 0x00c0,
+	0x786: 0x00c2, 0x787: 0x00c0, 0x788: 0x0080, 0x789: 0x00c2, 0x78a: 0x00c2, 0x78b: 0x00c2,
+	0x78c: 0x00c2, 0x78d: 0x00c2, 0x78e: 0x00c4, 0x790: 0x0040, 0x791: 0x0040,
+	0x798: 0x00c3, 0x799: 0x00c3, 0x79a: 0x00c3, 0x79b: 0x00c3, 0x79c: 0x00c3, 0x79d: 0x00c3,
+	0x79e: 0x00c3, 0x79f: 0x00c3, 0x7a0: 0x00c2, 0x7a1: 0x00c2, 0x7a2: 0x00c2, 0x7a3: 0x00c2,
+	0x7a4: 0x00c2, 0x7a5: 0x00c2, 0x7a6: 0x00c2, 0x7a7: 0x00c2, 0x7a8: 0x00c2, 0x7a9: 0x00c2,
+	0x7aa: 0x00c4, 0x7ab: 0x00c4, 0x7ac: 0x00c4, 0x7ad: 0x00c0, 0x7ae: 0x00c4, 0x7af: 0x00c2,
+	0x7b0: 0x00c2, 0x7b1: 0x00c4, 0x7b2: 0x00c4, 0x7b3: 0x00c2, 0x7b4: 0x00c2, 0x7b5: 0x00c2,
+	0x7b6: 0x00c2, 0x7b7: 0x00c2, 0x7b8: 0x00c2, 0x7b9: 0x00c4, 0x7ba: 0x00c2, 0x7bb: 0x00c2,
+	0x7bc: 0x00c2, 0x7bd: 0x00c2, 0x7be: 0x00c2, 0x7bf: 0x00c2,
+	// Block 0x1f, offset 0x7c0
+	0x7c0: 0x00c2, 0x7c1: 0x00c2, 0x7c2: 0x00c2, 0x7c3: 0x00c2, 0x7c4: 0x00c2, 0x7c5: 0x00c2,
+	0x7c6: 0x00c2, 0x7c7: 0x00c2, 0x7c8: 0x00c2, 0x7c9: 0x00c0, 0x7ca: 0x00c3, 0x7cb: 0x00c3,
+	0x7cc: 0x00c3, 0x7cd: 0x00c3, 0x7ce: 0x00c3, 0x7cf: 0x00c3, 0x7d0: 0x00c3, 0x7d1: 0x00c3,
+	0x7d2: 0x00c3, 0x7d3: 0x00c3, 0x7d4: 0x00c3, 0x7d5: 0x00c3, 0x7d6: 0x00c3, 0x7d7: 0x00c3,
+	0x7d8: 0x00c3, 0x7d9: 0x00c3, 0x7da: 0x00c3, 0x7db: 0x00c3, 0x7dc: 0x00c3, 0x7dd: 0x00c3,
+	0x7de: 0x00c3, 0x7df: 0x00c3, 0x7e0: 0x00c3, 0x7e1: 0x00c3, 0x7e2: 0x0040, 0x7e3: 0x00c3,
+	0x7e4: 0x00c3, 0x7e5: 0x00c3, 0x7e6: 0x00c3, 0x7e7: 0x00c3, 0x7e8: 0x00c3, 0x7e9: 0x00c3,
+	0x7ea: 0x00c3, 0x7eb: 0x00c3, 0x7ec: 0x00c3, 0x7ed: 0x00c3, 0x7ee: 0x00c3, 0x7ef: 0x00c3,
+	0x7f0: 0x00c3, 0x7f1: 0x00c3, 0x7f2: 0x00c3, 0x7f3: 0x00c3, 0x7f4: 0x00c3, 0x7f5: 0x00c3,
+	0x7f6: 0x00c3, 0x7f7: 0x00c3, 0x7f8: 0x00c3, 0x7f9: 0x00c3, 0x7fa: 0x00c3, 0x7fb: 0x00c3,
+	0x7fc: 0x00c3, 0x7fd: 0x00c3, 0x7fe: 0x00c3, 0x7ff: 0x00c3,
+	// Block 0x20, offset 0x800
+	0x800: 0x00c3, 0x801: 0x00c3, 0x802: 0x00c3, 0x803: 0x00c0, 0x804: 0x00c0, 0x805: 0x00c0,
+	0x806: 0x00c0, 0x807: 0x00c0, 0x808: 0x00c0, 0x809: 0x00c0, 0x80a: 0x00c0, 0x80b: 0x00c0,
+	0x80c: 0x00c0, 0x80d: 0x00c0, 0x80e: 0x00c0, 0x80f: 0x00c0, 0x810: 0x00c0, 0x811: 0x00c0,
+	0x812: 0x00c0, 0x813: 0x00c0, 0x814: 0x00c0, 0x815: 0x00c0, 0x816: 0x00c0, 0x817: 0x00c0,
+	0x818: 0x00c0, 0x819: 0x00c0, 0x81a: 0x00c0, 0x81b: 0x00c0, 0x81c: 0x00c0, 0x81d: 0x00c0,
+	0x81e: 0x00c0, 0x81f: 0x00c0, 0x820: 0x00c0, 0x821: 0x00c0, 0x822: 0x00c0, 0x823: 0x00c0,
+	0x824: 0x00c0, 0x825: 0x00c0, 0x826: 0x00c0, 0x827: 0x00c0, 0x828: 0x00c0, 0x829: 0x00c0,
+	0x82a: 0x00c0, 0x82b: 0x00c0, 0x82c: 0x00c0, 0x82d: 0x00c0, 0x82e: 0x00c0, 0x82f: 0x00c0,
+	0x830: 0x00c0, 0x831: 0x00c0, 0x832: 0x00c0, 0x833: 0x00c0, 0x834: 0x00c0, 0x835: 0x00c0,
+	0x836: 0x00c0, 0x837: 0x00c0, 0x838: 0x00c0, 0x839: 0x00c0, 0x83a: 0x00c3, 0x83b: 0x00c0,
+	0x83c: 0x00c3, 0x83d: 0x00c0, 0x83e: 0x00c0, 0x83f: 0x00c0,
+	// Block 0x21, offset 0x840
+	0x840: 0x00c0, 0x841: 0x00c3, 0x842: 0x00c3, 0x843: 0x00c3, 0x844: 0x00c3, 0x845: 0x00c3,
+	0x846: 0x00c3, 0x847: 0x00c3, 0x848: 0x00c3, 0x849: 0x00c0, 0x84a: 0x00c0, 0x84b: 0x00c0,
+	0x84c: 0x00c0, 0x84d: 0x00c6, 0x84e: 0x00c0, 0x84f: 0x00c0, 0x850: 0x00c0, 0x851: 0x00c3,
+	0x852: 0x00c3, 0x853: 0x00c3, 0x854: 0x00c3, 0x855: 0x00c3, 0x856: 0x00c3, 0x857: 0x00c3,
+	0x858: 0x0080, 0x859: 0x0080, 0x85a: 0x0080, 0x85b: 0x0080, 0x85c: 0x0080, 0x85d: 0x0080,
+	0x85e: 0x0080, 0x85f: 0x0080, 0x860: 0x00c0, 0x861: 0x00c0, 0x862: 0x00c3, 0x863: 0x00c3,
+	0x864: 0x0080, 0x865: 0x0080, 0x866: 0x00c0, 0x867: 0x00c0, 0x868: 0x00c0, 0x869: 0x00c0,
+	0x86a: 0x00c0, 0x86b: 0x00c0, 0x86c: 0x00c0, 0x86d: 0x00c0, 0x86e: 0x00c0, 0x86f: 0x00c0,
+	0x870: 0x0080, 0x871: 0x00c0, 0x872: 0x00c0, 0x873: 0x00c0, 0x874: 0x00c0, 0x875: 0x00c0,
+	0x876: 0x00c0, 0x877: 0x00c0, 0x878: 0x00c0, 0x879: 0x00c0, 0x87a: 0x00c0, 0x87b: 0x00c0,
+	0x87c: 0x00c0, 0x87d: 0x00c0, 0x87e: 0x00c0, 0x87f: 0x00c0,
+	// Block 0x22, offset 0x880
+	0x880: 0x00c0, 0x881: 0x00c3, 0x882: 0x00c0, 0x883: 0x00c0, 0x885: 0x00c0,
+	0x886: 0x00c0, 0x887: 0x00c0, 0x888: 0x00c0, 0x889: 0x00c0, 0x88a: 0x00c0, 0x88b: 0x00c0,
+	0x88c: 0x00c0, 0x88f: 0x00c0, 0x890: 0x00c0,
+	0x893: 0x00c0, 0x894: 0x00c0, 0x895: 0x00c0, 0x896: 0x00c0, 0x897: 0x00c0,
+	0x898: 0x00c0, 0x899: 0x00c0, 0x89a: 0x00c0, 0x89b: 0x00c0, 0x89c: 0x00c0, 0x89d: 0x00c0,
+	0x89e: 0x00c0, 0x89f: 0x00c0, 0x8a0: 0x00c0, 0x8a1: 0x00c0, 0x8a2: 0x00c0, 0x8a3: 0x00c0,
+	0x8a4: 0x00c0, 0x8a5: 0x00c0, 0x8a6: 0x00c0, 0x8a7: 0x00c0, 0x8a8: 0x00c0,
+	0x8aa: 0x00c0, 0x8ab: 0x00c0, 0x8ac: 0x00c0, 0x8ad: 0x00c0, 0x8ae: 0x00c0, 0x8af: 0x00c0,
+	0x8b0: 0x00c0, 0x8b2: 0x00c0,
+	0x8b6: 0x00c0, 0x8b7: 0x00c0, 0x8b8: 0x00c0, 0x8b9: 0x00c0,
+	0x8bc: 0x00c3, 0x8bd: 0x00c0, 0x8be: 0x00c0, 0x8bf: 0x00c0,
+	// Block 0x23, offset 0x8c0
+	0x8c0: 0x00c0, 0x8c1: 0x00c3, 0x8c2: 0x00c3, 0x8c3: 0x00c3, 0x8c4: 0x00c3,
+	0x8c7: 0x00c0, 0x8c8: 0x00c0, 0x8cb: 0x00c0,
+	0x8cc: 0x00c0, 0x8cd: 0x00c6, 0x8ce: 0x00c0,
+	0x8d7: 0x00c0,
+	0x8dc: 0x0080, 0x8dd: 0x0080,
+	0x8df: 0x0080, 0x8e0: 0x00c0, 0x8e1: 0x00c0, 0x8e2: 0x00c3, 0x8e3: 0x00c3,
+	0x8e6: 0x00c0, 0x8e7: 0x00c0, 0x8e8: 0x00c0, 0x8e9: 0x00c0,
+	0x8ea: 0x00c0, 0x8eb: 0x00c0, 0x8ec: 0x00c0, 0x8ed: 0x00c0, 0x8ee: 0x00c0, 0x8ef: 0x00c0,
+	0x8f0: 0x00c0, 0x8f1: 0x00c0, 0x8f2: 0x0080, 0x8f3: 0x0080, 0x8f4: 0x0080, 0x8f5: 0x0080,
+	0x8f6: 0x0080, 0x8f7: 0x0080, 0x8f8: 0x0080, 0x8f9: 0x0080, 0x8fa: 0x0080, 0x8fb: 0x0080,
+	0x8fc: 0x00c0, 0x8fd: 0x0080, 0x8fe: 0x00c3,
+	// Block 0x24, offset 0x900
+	0x901: 0x00c3, 0x902: 0x00c3, 0x903: 0x00c0, 0x905: 0x00c0,
+	0x906: 0x00c0, 0x907: 0x00c0, 0x908: 0x00c0, 0x909: 0x00c0, 0x90a: 0x00c0,
+	0x90f: 0x00c0, 0x910: 0x00c0,
+	0x913: 0x00c0, 0x914: 0x00c0, 0x915: 0x00c0, 0x916: 0x00c0, 0x917: 0x00c0,
+	0x918: 0x00c0, 0x919: 0x00c0, 0x91a: 0x00c0, 0x91b: 0x00c0, 0x91c: 0x00c0, 0x91d: 0x00c0,
+	0x91e: 0x00c0, 0x91f: 0x00c0, 0x920: 0x00c0, 0x921: 0x00c0, 0x922: 0x00c0, 0x923: 0x00c0,
+	0x924: 0x00c0, 0x925: 0x00c0, 0x926: 0x00c0, 0x927: 0x00c0, 0x928: 0x00c0,
+	0x92a: 0x00c0, 0x92b: 0x00c0, 0x92c: 0x00c0, 0x92d: 0x00c0, 0x92e: 0x00c0, 0x92f: 0x00c0,
+	0x930: 0x00c0, 0x932: 0x00c0, 0x933: 0x0080, 0x935: 0x00c0,
+	0x936: 0x0080, 0x938: 0x00c0, 0x939: 0x00c0,
+	0x93c: 0x00c3, 0x93e: 0x00c0, 0x93f: 0x00c0,
+	// Block 0x25, offset 0x940
+	0x940: 0x00c0, 0x941: 0x00c3, 0x942: 0x00c3,
+	0x947: 0x00c3, 0x948: 0x00c3, 0x94b: 0x00c3,
+	0x94c: 0x00c3, 0x94d: 0x00c6, 0x951: 0x00c3,
+	0x959: 0x0080, 0x95a: 0x0080, 0x95b: 0x0080, 0x95c: 0x00c0,
+	0x95e: 0x0080,
+	0x966: 0x00c0, 0x967: 0x00c0, 0x968: 0x00c0, 0x969: 0x00c0,
+	0x96a: 0x00c0, 0x96b: 0x00c0, 0x96c: 0x00c0, 0x96d: 0x00c0, 0x96e: 0x00c0, 0x96f: 0x00c0,
+	0x970: 0x00c3, 0x971: 0x00c3, 0x972: 0x00c0, 0x973: 0x00c0, 0x974: 0x00c0, 0x975: 0x00c3,
+	0x976: 0x0080,
+	// Block 0x26, offset 0x980
+	0x981: 0x00c3, 0x982: 0x00c3, 0x983: 0x00c0, 0x985: 0x00c0,
+	0x986: 0x00c0, 0x987: 0x00c0, 0x988: 0x00c0, 0x989: 0x00c0, 0x98a: 0x00c0, 0x98b: 0x00c0,
+	0x98c: 0x00c0, 0x98d: 0x00c0, 0x98f: 0x00c0, 0x990: 0x00c0, 0x991: 0x00c0,
+	0x993: 0x00c0, 0x994: 0x00c0, 0x995: 0x00c0, 0x996: 0x00c0, 0x997: 0x00c0,
+	0x998: 0x00c0, 0x999: 0x00c0, 0x99a: 0x00c0, 0x99b: 0x00c0, 0x99c: 0x00c0, 0x99d: 0x00c0,
+	0x99e: 0x00c0, 0x99f: 0x00c0, 0x9a0: 0x00c0, 0x9a1: 0x00c0, 0x9a2: 0x00c0, 0x9a3: 0x00c0,
+	0x9a4: 0x00c0, 0x9a5: 0x00c0, 0x9a6: 0x00c0, 0x9a7: 0x00c0, 0x9a8: 0x00c0,
+	0x9aa: 0x00c0, 0x9ab: 0x00c0, 0x9ac: 0x00c0, 0x9ad: 0x00c0, 0x9ae: 0x00c0, 0x9af: 0x00c0,
+	0x9b0: 0x00c0, 0x9b2: 0x00c0, 0x9b3: 0x00c0, 0x9b5: 0x00c0,
+	0x9b6: 0x00c0, 0x9b7: 0x00c0, 0x9b8: 0x00c0, 0x9b9: 0x00c0,
+	0x9bc: 0x00c3, 0x9bd: 0x00c0, 0x9be: 0x00c0, 0x9bf: 0x00c0,
+	// Block 0x27, offset 0x9c0
+	0x9c0: 0x00c0, 0x9c1: 0x00c3, 0x9c2: 0x00c3, 0x9c3: 0x00c3, 0x9c4: 0x00c3, 0x9c5: 0x00c3,
+	0x9c7: 0x00c3, 0x9c8: 0x00c3, 0x9c9: 0x00c0, 0x9cb: 0x00c0,
+	0x9cc: 0x00c0, 0x9cd: 0x00c6, 0x9d0: 0x00c0,
+	0x9e0: 0x00c0, 0x9e1: 0x00c0, 0x9e2: 0x00c3, 0x9e3: 0x00c3,
+	0x9e6: 0x00c0, 0x9e7: 0x00c0, 0x9e8: 0x00c0, 0x9e9: 0x00c0,
+	0x9ea: 0x00c0, 0x9eb: 0x00c0, 0x9ec: 0x00c0, 0x9ed: 0x00c0, 0x9ee: 0x00c0, 0x9ef: 0x00c0,
+	0x9f0: 0x0080, 0x9f1: 0x0080,
+	0x9f9: 0x00c0, 0x9fa: 0x00c3, 0x9fb: 0x00c3,
+	0x9fc: 0x00c3, 0x9fd: 0x00c3, 0x9fe: 0x00c3, 0x9ff: 0x00c3,
+	// Block 0x28, offset 0xa00
+	0xa01: 0x00c3, 0xa02: 0x00c0, 0xa03: 0x00c0, 0xa05: 0x00c0,
+	0xa06: 0x00c0, 0xa07: 0x00c0, 0xa08: 0x00c0, 0xa09: 0x00c0, 0xa0a: 0x00c0, 0xa0b: 0x00c0,
+	0xa0c: 0x00c0, 0xa0f: 0x00c0, 0xa10: 0x00c0,
+	0xa13: 0x00c0, 0xa14: 0x00c0, 0xa15: 0x00c0, 0xa16: 0x00c0, 0xa17: 0x00c0,
+	0xa18: 0x00c0, 0xa19: 0x00c0, 0xa1a: 0x00c0, 0xa1b: 0x00c0, 0xa1c: 0x00c0, 0xa1d: 0x00c0,
+	0xa1e: 0x00c0, 0xa1f: 0x00c0, 0xa20: 0x00c0, 0xa21: 0x00c0, 0xa22: 0x00c0, 0xa23: 0x00c0,
+	0xa24: 0x00c0, 0xa25: 0x00c0, 0xa26: 0x00c0, 0xa27: 0x00c0, 0xa28: 0x00c0,
+	0xa2a: 0x00c0, 0xa2b: 0x00c0, 0xa2c: 0x00c0, 0xa2d: 0x00c0, 0xa2e: 0x00c0, 0xa2f: 0x00c0,
+	0xa30: 0x00c0, 0xa32: 0x00c0, 0xa33: 0x00c0, 0xa35: 0x00c0,
+	0xa36: 0x00c0, 0xa37: 0x00c0, 0xa38: 0x00c0, 0xa39: 0x00c0,
+	0xa3c: 0x00c3, 0xa3d: 0x00c0, 0xa3e: 0x00c0, 0xa3f: 0x00c3,
+	// Block 0x29, offset 0xa40
+	0xa40: 0x00c0, 0xa41: 0x00c3, 0xa42: 0x00c3, 0xa43: 0x00c3, 0xa44: 0x00c3,
+	0xa47: 0x00c0, 0xa48: 0x00c0, 0xa4b: 0x00c0,
+	0xa4c: 0x00c0, 0xa4d: 0x00c6,
+	0xa55: 0x00c3, 0xa56: 0x00c3, 0xa57: 0x00c0,
+	0xa5c: 0x0080, 0xa5d: 0x0080,
+	0xa5f: 0x00c0, 0xa60: 0x00c0, 0xa61: 0x00c0, 0xa62: 0x00c3, 0xa63: 0x00c3,
+	0xa66: 0x00c0, 0xa67: 0x00c0, 0xa68: 0x00c0, 0xa69: 0x00c0,
+	0xa6a: 0x00c0, 0xa6b: 0x00c0, 0xa6c: 0x00c0, 0xa6d: 0x00c0, 0xa6e: 0x00c0, 0xa6f: 0x00c0,
+	0xa70: 0x0080, 0xa71: 0x00c0, 0xa72: 0x0080, 0xa73: 0x0080, 0xa74: 0x0080, 0xa75: 0x0080,
+	0xa76: 0x0080, 0xa77: 0x0080,
+	// Block 0x2a, offset 0xa80
+	0xa82: 0x00c3, 0xa83: 0x00c0, 0xa85: 0x00c0,
+	0xa86: 0x00c0, 0xa87: 0x00c0, 0xa88: 0x00c0, 0xa89: 0x00c0, 0xa8a: 0x00c0,
+	0xa8e: 0x00c0, 0xa8f: 0x00c0, 0xa90: 0x00c0,
+	0xa92: 0x00c0, 0xa93: 0x00c0, 0xa94: 0x00c0, 0xa95: 0x00c0,
+	0xa99: 0x00c0, 0xa9a: 0x00c0, 0xa9c: 0x00c0,
+	0xa9e: 0x00c0, 0xa9f: 0x00c0, 0xaa3: 0x00c0,
+	0xaa4: 0x00c0, 0xaa8: 0x00c0, 0xaa9: 0x00c0,
+	0xaaa: 0x00c0, 0xaae: 0x00c0, 0xaaf: 0x00c0,
+	0xab0: 0x00c0, 0xab1: 0x00c0, 0xab2: 0x00c0, 0xab3: 0x00c0, 0xab4: 0x00c0, 0xab5: 0x00c0,
+	0xab6: 0x00c0, 0xab7: 0x00c0, 0xab8: 0x00c0, 0xab9: 0x00c0,
+	0xabe: 0x00c0, 0xabf: 0x00c0,
+	// Block 0x2b, offset 0xac0
+	0xac0: 0x00c3, 0xac1: 0x00c0, 0xac2: 0x00c0,
+	0xac6: 0x00c0, 0xac7: 0x00c0, 0xac8: 0x00c0, 0xaca: 0x00c0, 0xacb: 0x00c0,
+	0xacc: 0x00c0, 0xacd: 0x00c6, 0xad0: 0x00c0,
+	0xad7: 0x00c0,
+	0xae6: 0x00c0, 0xae7: 0x00c0, 0xae8: 0x00c0, 0xae9: 0x00c0,
+	0xaea: 0x00c0, 0xaeb: 0x00c0, 0xaec: 0x00c0, 0xaed: 0x00c0, 0xaee: 0x00c0, 0xaef: 0x00c0,
+	0xaf0: 0x0080, 0xaf1: 0x0080, 0xaf2: 0x0080, 0xaf3: 0x0080, 0xaf4: 0x0080, 0xaf5: 0x0080,
+	0xaf6: 0x0080, 0xaf7: 0x0080, 0xaf8: 0x0080, 0xaf9: 0x0080, 0xafa: 0x0080,
+	// Block 0x2c, offset 0xb00
+	0xb00: 0x00c3, 0xb01: 0x00c0, 0xb02: 0x00c0, 0xb03: 0x00c0, 0xb04: 0x00c3, 0xb05: 0x00c0,
+	0xb06: 0x00c0, 0xb07: 0x00c0, 0xb08: 0x00c0, 0xb09: 0x00c0, 0xb0a: 0x00c0, 0xb0b: 0x00c0,
+	0xb0c: 0x00c0, 0xb0e: 0x00c0, 0xb0f: 0x00c0, 0xb10: 0x00c0,
+	0xb12: 0x00c0, 0xb13: 0x00c0, 0xb14: 0x00c0, 0xb15: 0x00c0, 0xb16: 0x00c0, 0xb17: 0x00c0,
+	0xb18: 0x00c0, 0xb19: 0x00c0, 0xb1a: 0x00c0, 0xb1b: 0x00c0, 0xb1c: 0x00c0, 0xb1d: 0x00c0,
+	0xb1e: 0x00c0, 0xb1f: 0x00c0, 0xb20: 0x00c0, 0xb21: 0x00c0, 0xb22: 0x00c0, 0xb23: 0x00c0,
+	0xb24: 0x00c0, 0xb25: 0x00c0, 0xb26: 0x00c0, 0xb27: 0x00c0, 0xb28: 0x00c0,
+	0xb2a: 0x00c0, 0xb2b: 0x00c0, 0xb2c: 0x00c0, 0xb2d: 0x00c0, 0xb2e: 0x00c0, 0xb2f: 0x00c0,
+	0xb30: 0x00c0, 0xb31: 0x00c0, 0xb32: 0x00c0, 0xb33: 0x00c0, 0xb34: 0x00c0, 0xb35: 0x00c0,
+	0xb36: 0x00c0, 0xb37: 0x00c0, 0xb38: 0x00c0, 0xb39: 0x00c0,
+	0xb3c: 0x00c3, 0xb3d: 0x00c0, 0xb3e: 0x00c3, 0xb3f: 0x00c3,
+	// Block 0x2d, offset 0xb40
+	0xb40: 0x00c3, 0xb41: 0x00c0, 0xb42: 0x00c0, 0xb43: 0x00c0, 0xb44: 0x00c0,
+	0xb46: 0x00c3, 0xb47: 0x00c3, 0xb48: 0x00c3, 0xb4a: 0x00c3, 0xb4b: 0x00c3,
+	0xb4c: 0x00c3, 0xb4d: 0x00c6,
+	0xb55: 0x00c3, 0xb56: 0x00c3,
+	0xb58: 0x00c0, 0xb59: 0x00c0, 0xb5a: 0x00c0, 0xb5d: 0x00c0,
+	0xb60: 0x00c0, 0xb61: 0x00c0, 0xb62: 0x00c3, 0xb63: 0x00c3,
+	0xb66: 0x00c0, 0xb67: 0x00c0, 0xb68: 0x00c0, 0xb69: 0x00c0,
+	0xb6a: 0x00c0, 0xb6b: 0x00c0, 0xb6c: 0x00c0, 0xb6d: 0x00c0, 0xb6e: 0x00c0, 0xb6f: 0x00c0,
+	0xb77: 0x0080, 0xb78: 0x0080, 0xb79: 0x0080, 0xb7a: 0x0080, 0xb7b: 0x0080,
+	0xb7c: 0x0080, 0xb7d: 0x0080, 0xb7e: 0x0080, 0xb7f: 0x0080,
+	// Block 0x2e, offset 0xb80
+	0xb80: 0x00c0, 0xb81: 0x00c3, 0xb82: 0x00c0, 0xb83: 0x00c0, 0xb84: 0x0080, 0xb85: 0x00c0,
+	0xb86: 0x00c0, 0xb87: 0x00c0, 0xb88: 0x00c0, 0xb89: 0x00c0, 0xb8a: 0x00c0, 0xb8b: 0x00c0,
+	0xb8c: 0x00c0, 0xb8e: 0x00c0, 0xb8f: 0x00c0, 0xb90: 0x00c0,
+	0xb92: 0x00c0, 0xb93: 0x00c0, 0xb94: 0x00c0, 0xb95: 0x00c0, 0xb96: 0x00c0, 0xb97: 0x00c0,
+	0xb98: 0x00c0, 0xb99: 0x00c0, 0xb9a: 0x00c0, 0xb9b: 0x00c0, 0xb9c: 0x00c0, 0xb9d: 0x00c0,
+	0xb9e: 0x00c0, 0xb9f: 0x00c0, 0xba0: 0x00c0, 0xba1: 0x00c0, 0xba2: 0x00c0, 0xba3: 0x00c0,
+	0xba4: 0x00c0, 0xba5: 0x00c0, 0xba6: 0x00c0, 0xba7: 0x00c0, 0xba8: 0x00c0,
+	0xbaa: 0x00c0, 0xbab: 0x00c0, 0xbac: 0x00c0, 0xbad: 0x00c0, 0xbae: 0x00c0, 0xbaf: 0x00c0,
+	0xbb0: 0x00c0, 0xbb1: 0x00c0, 0xbb2: 0x00c0, 0xbb3: 0x00c0, 0xbb5: 0x00c0,
+	0xbb6: 0x00c0, 0xbb7: 0x00c0, 0xbb8: 0x00c0, 0xbb9: 0x00c0,
+	0xbbc: 0x00c3, 0xbbd: 0x00c0, 0xbbe: 0x00c0, 0xbbf: 0x00c3,
+	// Block 0x2f, offset 0xbc0
+	0xbc0: 0x00c0, 0xbc1: 0x00c0, 0xbc2: 0x00c0, 0xbc3: 0x00c0, 0xbc4: 0x00c0,
+	0xbc6: 0x00c3, 0xbc7: 0x00c0, 0xbc8: 0x00c0, 0xbca: 0x00c0, 0xbcb: 0x00c0,
+	0xbcc: 0x00c3, 0xbcd: 0x00c6,
+	0xbd5: 0x00c0, 0xbd6: 0x00c0,
+	0xbdd: 0x00c0,
+	0xbde: 0x00c0, 0xbe0: 0x00c0, 0xbe1: 0x00c0, 0xbe2: 0x00c3, 0xbe3: 0x00c3,
+	0xbe6: 0x00c0, 0xbe7: 0x00c0, 0xbe8: 0x00c0, 0xbe9: 0x00c0,
+	0xbea: 0x00c0, 0xbeb: 0x00c0, 0xbec: 0x00c0, 0xbed: 0x00c0, 0xbee: 0x00c0, 0xbef: 0x00c0,
+	0xbf1: 0x00c0, 0xbf2: 0x00c0, 0xbf3: 0x00c0,
+	// Block 0x30, offset 0xc00
+	0xc00: 0x00c3, 0xc01: 0x00c3, 0xc02: 0x00c0, 0xc03: 0x00c0, 0xc04: 0x00c0, 0xc05: 0x00c0,
+	0xc06: 0x00c0, 0xc07: 0x00c0, 0xc08: 0x00c0, 0xc09: 0x00c0, 0xc0a: 0x00c0, 0xc0b: 0x00c0,
+	0xc0c: 0x00c0, 0xc0e: 0x00c0, 0xc0f: 0x00c0, 0xc10: 0x00c0,
+	0xc12: 0x00c0, 0xc13: 0x00c0, 0xc14: 0x00c0, 0xc15: 0x00c0, 0xc16: 0x00c0, 0xc17: 0x00c0,
+	0xc18: 0x00c0, 0xc19: 0x00c0, 0xc1a: 0x00c0, 0xc1b: 0x00c0, 0xc1c: 0x00c0, 0xc1d: 0x00c0,
+	0xc1e: 0x00c0, 0xc1f: 0x00c0, 0xc20: 0x00c0, 0xc21: 0x00c0, 0xc22: 0x00c0, 0xc23: 0x00c0,
+	0xc24: 0x00c0, 0xc25: 0x00c0, 0xc26: 0x00c0, 0xc27: 0x00c0, 0xc28: 0x00c0, 0xc29: 0x00c0,
+	0xc2a: 0x00c0, 0xc2b: 0x00c0, 0xc2c: 0x00c0, 0xc2d: 0x00c0, 0xc2e: 0x00c0, 0xc2f: 0x00c0,
+	0xc30: 0x00c0, 0xc31: 0x00c0, 0xc32: 0x00c0, 0xc33: 0x00c0, 0xc34: 0x00c0, 0xc35: 0x00c0,
+	0xc36: 0x00c0, 0xc37: 0x00c0, 0xc38: 0x00c0, 0xc39: 0x00c0, 0xc3a: 0x00c0, 0xc3b: 0x00c6,
+	0xc3c: 0x00c6, 0xc3d: 0x00c0, 0xc3e: 0x00c0, 0xc3f: 0x00c0,
+	// Block 0x31, offset 0xc40
+	0xc40: 0x00c0, 0xc41: 0x00c3, 0xc42: 0x00c3, 0xc43: 0x00c3, 0xc44: 0x00c3,
+	0xc46: 0x00c0, 0xc47: 0x00c0, 0xc48: 0x00c0, 0xc4a: 0x00c0, 0xc4b: 0x00c0,
+	0xc4c: 0x00c0, 0xc4d: 0x00c6, 0xc4e: 0x00c0, 0xc4f: 0x0080,
+	0xc54: 0x00c0, 0xc55: 0x00c0, 0xc56: 0x00c0, 0xc57: 0x00c0,
+	0xc58: 0x0080, 0xc59: 0x0080, 0xc5a: 0x0080, 0xc5b: 0x0080, 0xc5c: 0x0080, 0xc5d: 0x0080,
+	0xc5e: 0x0080, 0xc5f: 0x00c0, 0xc60: 0x00c0, 0xc61: 0x00c0, 0xc62: 0x00c3, 0xc63: 0x00c3,
+	0xc66: 0x00c0, 0xc67: 0x00c0, 0xc68: 0x00c0, 0xc69: 0x00c0,
+	0xc6a: 0x00c0, 0xc6b: 0x00c0, 0xc6c: 0x00c0, 0xc6d: 0x00c0, 0xc6e: 0x00c0, 0xc6f: 0x00c0,
+	0xc70: 0x0080, 0xc71: 0x0080, 0xc72: 0x0080, 0xc73: 0x0080, 0xc74: 0x0080, 0xc75: 0x0080,
+	0xc76: 0x0080, 0xc77: 0x0080, 0xc78: 0x0080, 0xc79: 0x0080, 0xc7a: 0x00c0, 0xc7b: 0x00c0,
+	0xc7c: 0x00c0, 0xc7d: 0x00c0, 0xc7e: 0x00c0, 0xc7f: 0x00c0,
+	// Block 0x32, offset 0xc80
+	0xc81: 0x00c3, 0xc82: 0x00c0, 0xc83: 0x00c0, 0xc85: 0x00c0,
+	0xc86: 0x00c0, 0xc87: 0x00c0, 0xc88: 0x00c0, 0xc89: 0x00c0, 0xc8a: 0x00c0, 0xc8b: 0x00c0,
+	0xc8c: 0x00c0, 0xc8d: 0x00c0, 0xc8e: 0x00c0, 0xc8f: 0x00c0, 0xc90: 0x00c0, 0xc91: 0x00c0,
+	0xc92: 0x00c0, 0xc93: 0x00c0, 0xc94: 0x00c0, 0xc95: 0x00c0, 0xc96: 0x00c0,
+	0xc9a: 0x00c0, 0xc9b: 0x00c0, 0xc9c: 0x00c0, 0xc9d: 0x00c0,
+	0xc9e: 0x00c0, 0xc9f: 0x00c0, 0xca0: 0x00c0, 0xca1: 0x00c0, 0xca2: 0x00c0, 0xca3: 0x00c0,
+	0xca4: 0x00c0, 0xca5: 0x00c0, 0xca6: 0x00c0, 0xca7: 0x00c0, 0xca8: 0x00c0, 0xca9: 0x00c0,
+	0xcaa: 0x00c0, 0xcab: 0x00c0, 0xcac: 0x00c0, 0xcad: 0x00c0, 0xcae: 0x00c0, 0xcaf: 0x00c0,
+	0xcb0: 0x00c0, 0xcb1: 0x00c0, 0xcb3: 0x00c0, 0xcb4: 0x00c0, 0xcb5: 0x00c0,
+	0xcb6: 0x00c0, 0xcb7: 0x00c0, 0xcb8: 0x00c0, 0xcb9: 0x00c0, 0xcba: 0x00c0, 0xcbb: 0x00c0,
+	0xcbd: 0x00c0,
+	// Block 0x33, offset 0xcc0
+	0xcc0: 0x00c0, 0xcc1: 0x00c0, 0xcc2: 0x00c0, 0xcc3: 0x00c0, 0xcc4: 0x00c0, 0xcc5: 0x00c0,
+	0xcc6: 0x00c0, 0xcca: 0x00c6,
+	0xccf: 0x00c0, 0xcd0: 0x00c0, 0xcd1: 0x00c0,
+	0xcd2: 0x00c3, 0xcd3: 0x00c3, 0xcd4: 0x00c3, 0xcd6: 0x00c3,
+	0xcd8: 0x00c0, 0xcd9: 0x00c0, 0xcda: 0x00c0, 0xcdb: 0x00c0, 0xcdc: 0x00c0, 0xcdd: 0x00c0,
+	0xcde: 0x00c0, 0xcdf: 0x00c0,
+	0xce6: 0x00c0, 0xce7: 0x00c0, 0xce8: 0x00c0, 0xce9: 0x00c0,
+	0xcea: 0x00c0, 0xceb: 0x00c0, 0xcec: 0x00c0, 0xced: 0x00c0, 0xcee: 0x00c0, 0xcef: 0x00c0,
+	0xcf2: 0x00c0, 0xcf3: 0x00c0, 0xcf4: 0x0080,
+	// Block 0x34, offset 0xd00
+	0xd01: 0x00c0, 0xd02: 0x00c0, 0xd03: 0x00c0, 0xd04: 0x00c0, 0xd05: 0x00c0,
+	0xd06: 0x00c0, 0xd07: 0x00c0, 0xd08: 0x00c0, 0xd09: 0x00c0, 0xd0a: 0x00c0, 0xd0b: 0x00c0,
+	0xd0c: 0x00c0, 0xd0d: 0x00c0, 0xd0e: 0x00c0, 0xd0f: 0x00c0, 0xd10: 0x00c0, 0xd11: 0x00c0,
+	0xd12: 0x00c0, 0xd13: 0x00c0, 0xd14: 0x00c0, 0xd15: 0x00c0, 0xd16: 0x00c0, 0xd17: 0x00c0,
+	0xd18: 0x00c0, 0xd19: 0x00c0, 0xd1a: 0x00c0, 0xd1b: 0x00c0, 0xd1c: 0x00c0, 0xd1d: 0x00c0,
+	0xd1e: 0x00c0, 0xd1f: 0x00c0, 0xd20: 0x00c0, 0xd21: 0x00c0, 0xd22: 0x00c0, 0xd23: 0x00c0,
+	0xd24: 0x00c0, 0xd25: 0x00c0, 0xd26: 0x00c0, 0xd27: 0x00c0, 0xd28: 0x00c0, 0xd29: 0x00c0,
+	0xd2a: 0x00c0, 0xd2b: 0x00c0, 0xd2c: 0x00c0, 0xd2d: 0x00c0, 0xd2e: 0x00c0, 0xd2f: 0x00c0,
+	0xd30: 0x00c0, 0xd31: 0x00c3, 0xd32: 0x00c0, 0xd33: 0x0080, 0xd34: 0x00c3, 0xd35: 0x00c3,
+	0xd36: 0x00c3, 0xd37: 0x00c3, 0xd38: 0x00c3, 0xd39: 0x00c3, 0xd3a: 0x00c6,
+	0xd3f: 0x0080,
+	// Block 0x35, offset 0xd40
+	0xd40: 0x00c0, 0xd41: 0x00c0, 0xd42: 0x00c0, 0xd43: 0x00c0, 0xd44: 0x00c0, 0xd45: 0x00c0,
+	0xd46: 0x00c0, 0xd47: 0x00c3, 0xd48: 0x00c3, 0xd49: 0x00c3, 0xd4a: 0x00c3, 0xd4b: 0x00c3,
+	0xd4c: 0x00c3, 0xd4d: 0x00c3, 0xd4e: 0x00c3, 0xd4f: 0x0080, 0xd50: 0x00c0, 0xd51: 0x00c0,
+	0xd52: 0x00c0, 0xd53: 0x00c0, 0xd54: 0x00c0, 0xd55: 0x00c0, 0xd56: 0x00c0, 0xd57: 0x00c0,
+	0xd58: 0x00c0, 0xd59: 0x00c0, 0xd5a: 0x0080, 0xd5b: 0x0080,
+	// Block 0x36, offset 0xd80
+	0xd81: 0x00c0, 0xd82: 0x00c0, 0xd84: 0x00c0,
+	0xd86: 0x00c0, 0xd87: 0x00c0, 0xd88: 0x00c0, 0xd89: 0x00c0, 0xd8a: 0x00c0,
+	0xd8c: 0x00c0, 0xd8d: 0x00c0, 0xd8e: 0x00c0, 0xd8f: 0x00c0, 0xd90: 0x00c0, 0xd91: 0x00c0,
+	0xd92: 0x00c0, 0xd93: 0x00c0, 0xd94: 0x00c0, 0xd95: 0x00c0, 0xd96: 0x00c0, 0xd97: 0x00c0,
+	0xd98: 0x00c0, 0xd99: 0x00c0, 0xd9a: 0x00c0, 0xd9b: 0x00c0, 0xd9c: 0x00c0, 0xd9d: 0x00c0,
+	0xd9e: 0x00c0, 0xd9f: 0x00c0, 0xda0: 0x00c0, 0xda1: 0x00c0, 0xda2: 0x00c0, 0xda3: 0x00c0,
+	0xda5: 0x00c0, 0xda7: 0x00c0, 0xda8: 0x00c0, 0xda9: 0x00c0,
+	0xdaa: 0x00c0, 0xdab: 0x00c0, 0xdac: 0x00c0, 0xdad: 0x00c0, 0xdae: 0x00c0, 0xdaf: 0x00c0,
+	0xdb0: 0x00c0, 0xdb1: 0x00c3, 0xdb2: 0x00c0, 0xdb3: 0x0080, 0xdb4: 0x00c3, 0xdb5: 0x00c3,
+	0xdb6: 0x00c3, 0xdb7: 0x00c3, 0xdb8: 0x00c3, 0xdb9: 0x00c3, 0xdba: 0x00c6, 0xdbb: 0x00c3,
+	0xdbc: 0x00c3, 0xdbd: 0x00c0,
+	// Block 0x37, offset 0xdc0
+	0xdc0: 0x00c0, 0xdc1: 0x00c0, 0xdc2: 0x00c0, 0xdc3: 0x00c0, 0xdc4: 0x00c0,
+	0xdc6: 0x00c0, 0xdc8: 0x00c3, 0xdc9: 0x00c3, 0xdca: 0x00c3, 0xdcb: 0x00c3,
+	0xdcc: 0x00c3, 0xdcd: 0x00c3, 0xdce: 0x00c3, 0xdd0: 0x00c0, 0xdd1: 0x00c0,
+	0xdd2: 0x00c0, 0xdd3: 0x00c0, 0xdd4: 0x00c0, 0xdd5: 0x00c0, 0xdd6: 0x00c0, 0xdd7: 0x00c0,
+	0xdd8: 0x00c0, 0xdd9: 0x00c0, 0xddc: 0x0080, 0xddd: 0x0080,
+	0xdde: 0x00c0, 0xddf: 0x00c0,
+	// Block 0x38, offset 0xe00
+	0xe00: 0x00c0, 0xe01: 0x0080, 0xe02: 0x0080, 0xe03: 0x0080, 0xe04: 0x0080, 0xe05: 0x0080,
+	0xe06: 0x0080, 0xe07: 0x0080, 0xe08: 0x0080, 0xe09: 0x0080, 0xe0a: 0x0080, 0xe0b: 0x00c0,
+	0xe0c: 0x0080, 0xe0d: 0x0080, 0xe0e: 0x0080, 0xe0f: 0x0080, 0xe10: 0x0080, 0xe11: 0x0080,
+	0xe12: 0x0080, 0xe13: 0x0080, 0xe14: 0x0080, 0xe15: 0x0080, 0xe16: 0x0080, 0xe17: 0x0080,
+	0xe18: 0x00c3, 0xe19: 0x00c3, 0xe1a: 0x0080, 0xe1b: 0x0080, 0xe1c: 0x0080, 0xe1d: 0x0080,
+	0xe1e: 0x0080, 0xe1f: 0x0080, 0xe20: 0x00c0, 0xe21: 0x00c0, 0xe22: 0x00c0, 0xe23: 0x00c0,
+	0xe24: 0x00c0, 0xe25: 0x00c0, 0xe26: 0x00c0, 0xe27: 0x00c0, 0xe28: 0x00c0, 0xe29: 0x00c0,
+	0xe2a: 0x0080, 0xe2b: 0x0080, 0xe2c: 0x0080, 0xe2d: 0x0080, 0xe2e: 0x0080, 0xe2f: 0x0080,
+	0xe30: 0x0080, 0xe31: 0x0080, 0xe32: 0x0080, 0xe33: 0x0080, 0xe34: 0x0080, 0xe35: 0x00c3,
+	0xe36: 0x0080, 0xe37: 0x00c3, 0xe38: 0x0080, 0xe39: 0x00c3, 0xe3a: 0x0080, 0xe3b: 0x0080,
+	0xe3c: 0x0080, 0xe3d: 0x0080, 0xe3e: 0x00c0, 0xe3f: 0x00c0,
+	// Block 0x39, offset 0xe40
+	0xe40: 0x00c0, 0xe41: 0x00c0, 0xe42: 0x00c0, 0xe43: 0x0080, 0xe44: 0x00c0, 0xe45: 0x00c0,
+	0xe46: 0x00c0, 0xe47: 0x00c0, 0xe49: 0x00c0, 0xe4a: 0x00c0, 0xe4b: 0x00c0,
+	0xe4c: 0x00c0, 0xe4d: 0x0080, 0xe4e: 0x00c0, 0xe4f: 0x00c0, 0xe50: 0x00c0, 0xe51: 0x00c0,
+	0xe52: 0x0080, 0xe53: 0x00c0, 0xe54: 0x00c0, 0xe55: 0x00c0, 0xe56: 0x00c0, 0xe57: 0x0080,
+	0xe58: 0x00c0, 0xe59: 0x00c0, 0xe5a: 0x00c0, 0xe5b: 0x00c0, 0xe5c: 0x0080, 0xe5d: 0x00c0,
+	0xe5e: 0x00c0, 0xe5f: 0x00c0, 0xe60: 0x00c0, 0xe61: 0x00c0, 0xe62: 0x00c0, 0xe63: 0x00c0,
+	0xe64: 0x00c0, 0xe65: 0x00c0, 0xe66: 0x00c0, 0xe67: 0x00c0, 0xe68: 0x00c0, 0xe69: 0x0080,
+	0xe6a: 0x00c0, 0xe6b: 0x00c0, 0xe6c: 0x00c0,
+	0xe71: 0x00c3, 0xe72: 0x00c3, 0xe73: 0x0083, 0xe74: 0x00c3, 0xe75: 0x0083,
+	0xe76: 0x0083, 0xe77: 0x0083, 0xe78: 0x0083, 0xe79: 0x0083, 0xe7a: 0x00c3, 0xe7b: 0x00c3,
+	0xe7c: 0x00c3, 0xe7d: 0x00c3, 0xe7e: 0x00c3, 0xe7f: 0x00c0,
+	// Block 0x3a, offset 0xe80
+	0xe80: 0x00c3, 0xe81: 0x0083, 0xe82: 0x00c3, 0xe83: 0x00c3, 0xe84: 0x00c6, 0xe85: 0x0080,
+	0xe86: 0x00c3, 0xe87: 0x00c3, 0xe88: 0x00c0, 0xe89: 0x00c0, 0xe8a: 0x00c0, 0xe8b: 0x00c0,
+	0xe8c: 0x00c0, 0xe8d: 0x00c3, 0xe8e: 0x00c3, 0xe8f: 0x00c3, 0xe90: 0x00c3, 0xe91: 0x00c3,
+	0xe92: 0x00c3, 0xe93: 0x0083, 0xe94: 0x00c3, 0xe95: 0x00c3, 0xe96: 0x00c3, 0xe97: 0x00c3,
+	0xe99: 0x00c3, 0xe9a: 0x00c3, 0xe9b: 0x00c3, 0xe9c: 0x00c3, 0xe9d: 0x0083,
+	0xe9e: 0x00c3, 0xe9f: 0x00c3, 0xea0: 0x00c3, 0xea1: 0x00c3, 0xea2: 0x0083, 0xea3: 0x00c3,
+	0xea4: 0x00c3, 0xea5: 0x00c3, 0xea6: 0x00c3, 0xea7: 0x0083, 0xea8: 0x00c3, 0xea9: 0x00c3,
+	0xeaa: 0x00c3, 0xeab: 0x00c3, 0xeac: 0x0083, 0xead: 0x00c3, 0xeae: 0x00c3, 0xeaf: 0x00c3,
+	0xeb0: 0x00c3, 0xeb1: 0x00c3, 0xeb2: 0x00c3, 0xeb3: 0x00c3, 0xeb4: 0x00c3, 0xeb5: 0x00c3,
+	0xeb6: 0x00c3, 0xeb7: 0x00c3, 0xeb8: 0x00c3, 0xeb9: 0x0083, 0xeba: 0x00c3, 0xebb: 0x00c3,
+	0xebc: 0x00c3, 0xebe: 0x0080, 0xebf: 0x0080,
+	// Block 0x3b, offset 0xec0
+	0xec0: 0x0080, 0xec1: 0x0080, 0xec2: 0x0080, 0xec3: 0x0080, 0xec4: 0x0080, 0xec5: 0x0080,
+	0xec6: 0x00c3, 0xec7: 0x0080, 0xec8: 0x0080, 0xec9: 0x0080, 0xeca: 0x0080, 0xecb: 0x0080,
+	0xecc: 0x0080, 0xece: 0x0080, 0xecf: 0x0080, 0xed0: 0x0080, 0xed1: 0x0080,
+	0xed2: 0x0080, 0xed3: 0x0080, 0xed4: 0x0080, 0xed5: 0x0080, 0xed6: 0x0080, 0xed7: 0x0080,
+	0xed8: 0x0080, 0xed9: 0x0080, 0xeda: 0x0080,
+	// Block 0x3c, offset 0xf00
+	0xf00: 0x00c0, 0xf01: 0x00c0, 0xf02: 0x00c0, 0xf03: 0x00c0, 0xf04: 0x00c0, 0xf05: 0x00c0,
+	0xf06: 0x00c0, 0xf07: 0x00c0, 0xf08: 0x00c0, 0xf09: 0x00c0, 0xf0a: 0x00c0, 0xf0b: 0x00c0,
+	0xf0c: 0x00c0, 0xf0d: 0x00c0, 0xf0e: 0x00c0, 0xf0f: 0x00c0, 0xf10: 0x00c0, 0xf11: 0x00c0,
+	0xf12: 0x00c0, 0xf13: 0x00c0, 0xf14: 0x00c0, 0xf15: 0x00c0, 0xf16: 0x00c0, 0xf17: 0x00c0,
+	0xf18: 0x00c0, 0xf19: 0x00c0, 0xf1a: 0x00c0, 0xf1b: 0x00c0, 0xf1c: 0x00c0, 0xf1d: 0x00c0,
+	0xf1e: 0x00c0, 0xf1f: 0x00c0, 0xf20: 0x00c0, 0xf21: 0x00c0, 0xf22: 0x00c0, 0xf23: 0x00c0,
+	0xf24: 0x00c0, 0xf25: 0x00c0, 0xf26: 0x00c0, 0xf27: 0x00c0, 0xf28: 0x00c0, 0xf29: 0x00c0,
+	0xf2a: 0x00c0, 0xf2b: 0x00c0, 0xf2c: 0x00c0, 0xf2d: 0x00c3, 0xf2e: 0x00c3, 0xf2f: 0x00c3,
+	0xf30: 0x00c3, 0xf31: 0x00c0, 0xf32: 0x00c3, 0xf33: 0x00c3, 0xf34: 0x00c3, 0xf35: 0x00c3,
+	0xf36: 0x00c3, 0xf37: 0x00c3, 0xf38: 0x00c0, 0xf39: 0x00c6, 0xf3a: 0x00c6, 0xf3b: 0x00c0,
+	0xf3c: 0x00c0, 0xf3d: 0x00c3, 0xf3e: 0x00c3, 0xf3f: 0x00c0,
+	// Block 0x3d, offset 0xf40
+	0xf40: 0x00c0, 0xf41: 0x00c0, 0xf42: 0x00c0, 0xf43: 0x00c0, 0xf44: 0x00c0, 0xf45: 0x00c0,
+	0xf46: 0x00c0, 0xf47: 0x00c0, 0xf48: 0x00c0, 0xf49: 0x00c0, 0xf4a: 0x0080, 0xf4b: 0x0080,
+	0xf4c: 0x0080, 0xf4d: 0x0080, 0xf4e: 0x0080, 0xf4f: 0x0080, 0xf50: 0x00c0, 0xf51: 0x00c0,
+	0xf52: 0x00c0, 0xf53: 0x00c0, 0xf54: 0x00c0, 0xf55: 0x00c0, 0xf56: 0x00c0, 0xf57: 0x00c0,
+	0xf58: 0x00c3, 0xf59: 0x00c3, 0xf5a: 0x00c0, 0xf5b: 0x00c0, 0xf5c: 0x00c0, 0xf5d: 0x00c0,
+	0xf5e: 0x00c3, 0xf5f: 0x00c3, 0xf60: 0x00c3, 0xf61: 0x00c0, 0xf62: 0x00c0, 0xf63: 0x00c0,
+	0xf64: 0x00c0, 0xf65: 0x00c0, 0xf66: 0x00c0, 0xf67: 0x00c0, 0xf68: 0x00c0, 0xf69: 0x00c0,
+	0xf6a: 0x00c0, 0xf6b: 0x00c0, 0xf6c: 0x00c0, 0xf6d: 0x00c0, 0xf6e: 0x00c0, 0xf6f: 0x00c0,
+	0xf70: 0x00c0, 0xf71: 0x00c3, 0xf72: 0x00c3, 0xf73: 0x00c3, 0xf74: 0x00c3, 0xf75: 0x00c0,
+	0xf76: 0x00c0, 0xf77: 0x00c0, 0xf78: 0x00c0, 0xf79: 0x00c0, 0xf7a: 0x00c0, 0xf7b: 0x00c0,
+	0xf7c: 0x00c0, 0xf7d: 0x00c0, 0xf7e: 0x00c0, 0xf7f: 0x00c0,
+	// Block 0x3e, offset 0xf80
+	0xf80: 0x00c0, 0xf81: 0x00c0, 0xf82: 0x00c3, 0xf83: 0x00c0, 0xf84: 0x00c0, 0xf85: 0x00c3,
+	0xf86: 0x00c3, 0xf87: 0x00c0, 0xf88: 0x00c0, 0xf89: 0x00c0, 0xf8a: 0x00c0, 0xf8b: 0x00c0,
+	0xf8c: 0x00c0, 0xf8d: 0x00c3, 0xf8e: 0x00c0, 0xf8f: 0x00c0, 0xf90: 0x00c0, 0xf91: 0x00c0,
+	0xf92: 0x00c0, 0xf93: 0x00c0, 0xf94: 0x00c0, 0xf95: 0x00c0, 0xf96: 0x00c0, 0xf97: 0x00c0,
+	0xf98: 0x00c0, 0xf99: 0x00c0, 0xf9a: 0x00c0, 0xf9b: 0x00c0, 0xf9c: 0x00c0, 0xf9d: 0x00c3,
+	0xf9e: 0x0080, 0xf9f: 0x0080, 0xfa0: 0x00c0, 0xfa1: 0x00c0, 0xfa2: 0x00c0, 0xfa3: 0x00c0,
+	0xfa4: 0x00c0, 0xfa5: 0x00c0, 0xfa6: 0x00c0, 0xfa7: 0x00c0, 0xfa8: 0x00c0, 0xfa9: 0x00c0,
+	0xfaa: 0x00c0, 0xfab: 0x00c0, 0xfac: 0x00c0, 0xfad: 0x00c0, 0xfae: 0x00c0, 0xfaf: 0x00c0,
+	0xfb0: 0x00c0, 0xfb1: 0x00c0, 0xfb2: 0x00c0, 0xfb3: 0x00c0, 0xfb4: 0x00c0, 0xfb5: 0x00c0,
+	0xfb6: 0x00c0, 0xfb7: 0x00c0, 0xfb8: 0x00c0, 0xfb9: 0x00c0, 0xfba: 0x00c0, 0xfbb: 0x00c0,
+	0xfbc: 0x00c0, 0xfbd: 0x00c0, 0xfbe: 0x00c0, 0xfbf: 0x00c0,
+	// Block 0x3f, offset 0xfc0
+	0xfc0: 0x00c0, 0xfc1: 0x00c0, 0xfc2: 0x00c0, 0xfc3: 0x00c0, 0xfc4: 0x00c0, 0xfc5: 0x00c0,
+	0xfc7: 0x00c0,
+	0xfcd: 0x00c0, 0xfd0: 0x00c0, 0xfd1: 0x00c0,
+	0xfd2: 0x00c0, 0xfd3: 0x00c0, 0xfd4: 0x00c0, 0xfd5: 0x00c0, 0xfd6: 0x00c0, 0xfd7: 0x00c0,
+	0xfd8: 0x00c0, 0xfd9: 0x00c0, 0xfda: 0x00c0, 0xfdb: 0x00c0, 0xfdc: 0x00c0, 0xfdd: 0x00c0,
+	0xfde: 0x00c0, 0xfdf: 0x00c0, 0xfe0: 0x00c0, 0xfe1: 0x00c0, 0xfe2: 0x00c0, 0xfe3: 0x00c0,
+	0xfe4: 0x00c0, 0xfe5: 0x00c0, 0xfe6: 0x00c0, 0xfe7: 0x00c0, 0xfe8: 0x00c0, 0xfe9: 0x00c0,
+	0xfea: 0x00c0, 0xfeb: 0x00c0, 0xfec: 0x00c0, 0xfed: 0x00c0, 0xfee: 0x00c0, 0xfef: 0x00c0,
+	0xff0: 0x00c0, 0xff1: 0x00c0, 0xff2: 0x00c0, 0xff3: 0x00c0, 0xff4: 0x00c0, 0xff5: 0x00c0,
+	0xff6: 0x00c0, 0xff7: 0x00c0, 0xff8: 0x00c0, 0xff9: 0x00c0, 0xffa: 0x00c0, 0xffb: 0x0080,
+	0xffc: 0x0080, 0xffd: 0x00c0, 0xffe: 0x00c0, 0xfff: 0x00c0,
+	// Block 0x40, offset 0x1000
+	0x1000: 0x0040, 0x1001: 0x0040, 0x1002: 0x0040, 0x1003: 0x0040, 0x1004: 0x0040, 0x1005: 0x0040,
+	0x1006: 0x0040, 0x1007: 0x0040, 0x1008: 0x0040, 0x1009: 0x0040, 0x100a: 0x0040, 0x100b: 0x0040,
+	0x100c: 0x0040, 0x100d: 0x0040, 0x100e: 0x0040, 0x100f: 0x0040, 0x1010: 0x0040, 0x1011: 0x0040,
+	0x1012: 0x0040, 0x1013: 0x0040, 0x1014: 0x0040, 0x1015: 0x0040, 0x1016: 0x0040, 0x1017: 0x0040,
+	0x1018: 0x0040, 0x1019: 0x0040, 0x101a: 0x0040, 0x101b: 0x0040, 0x101c: 0x0040, 0x101d: 0x0040,
+	0x101e: 0x0040, 0x101f: 0x0040, 0x1020: 0x0040, 0x1021: 0x0040, 0x1022: 0x0040, 0x1023: 0x0040,
+	0x1024: 0x0040, 0x1025: 0x0040, 0x1026: 0x0040, 0x1027: 0x0040, 0x1028: 0x0040, 0x1029: 0x0040,
+	0x102a: 0x0040, 0x102b: 0x0040, 0x102c: 0x0040, 0x102d: 0x0040, 0x102e: 0x0040, 0x102f: 0x0040,
+	0x1030: 0x0040, 0x1031: 0x0040, 0x1032: 0x0040, 0x1033: 0x0040, 0x1034: 0x0040, 0x1035: 0x0040,
+	0x1036: 0x0040, 0x1037: 0x0040, 0x1038: 0x0040, 0x1039: 0x0040, 0x103a: 0x0040, 0x103b: 0x0040,
+	0x103c: 0x0040, 0x103d: 0x0040, 0x103e: 0x0040, 0x103f: 0x0040,
+	// Block 0x41, offset 0x1040
+	0x1040: 0x00c0, 0x1041: 0x00c0, 0x1042: 0x00c0, 0x1043: 0x00c0, 0x1044: 0x00c0, 0x1045: 0x00c0,
+	0x1046: 0x00c0, 0x1047: 0x00c0, 0x1048: 0x00c0, 0x104a: 0x00c0, 0x104b: 0x00c0,
+	0x104c: 0x00c0, 0x104d: 0x00c0, 0x1050: 0x00c0, 0x1051: 0x00c0,
+	0x1052: 0x00c0, 0x1053: 0x00c0, 0x1054: 0x00c0, 0x1055: 0x00c0, 0x1056: 0x00c0,
+	0x1058: 0x00c0, 0x105a: 0x00c0, 0x105b: 0x00c0, 0x105c: 0x00c0, 0x105d: 0x00c0,
+	0x1060: 0x00c0, 0x1061: 0x00c0, 0x1062: 0x00c0, 0x1063: 0x00c0,
+	0x1064: 0x00c0, 0x1065: 0x00c0, 0x1066: 0x00c0, 0x1067: 0x00c0, 0x1068: 0x00c0, 0x1069: 0x00c0,
+	0x106a: 0x00c0, 0x106b: 0x00c0, 0x106c: 0x00c0, 0x106d: 0x00c0, 0x106e: 0x00c0, 0x106f: 0x00c0,
+	0x1070: 0x00c0, 0x1071: 0x00c0, 0x1072: 0x00c0, 0x1073: 0x00c0, 0x1074: 0x00c0, 0x1075: 0x00c0,
+	0x1076: 0x00c0, 0x1077: 0x00c0, 0x1078: 0x00c0, 0x1079: 0x00c0, 0x107a: 0x00c0, 0x107b: 0x00c0,
+	0x107c: 0x00c0, 0x107d: 0x00c0, 0x107e: 0x00c0, 0x107f: 0x00c0,
+	// Block 0x42, offset 0x1080
+	0x1080: 0x00c0, 0x1081: 0x00c0, 0x1082: 0x00c0, 0x1083: 0x00c0, 0x1084: 0x00c0, 0x1085: 0x00c0,
+	0x1086: 0x00c0, 0x1087: 0x00c0, 0x1088: 0x00c0, 0x108a: 0x00c0, 0x108b: 0x00c0,
+	0x108c: 0x00c0, 0x108d: 0x00c0, 0x1090: 0x00c0, 0x1091: 0x00c0,
+	0x1092: 0x00c0, 0x1093: 0x00c0, 0x1094: 0x00c0, 0x1095: 0x00c0, 0x1096: 0x00c0, 0x1097: 0x00c0,
+	0x1098: 0x00c0, 0x1099: 0x00c0, 0x109a: 0x00c0, 0x109b: 0x00c0, 0x109c: 0x00c0, 0x109d: 0x00c0,
+	0x109e: 0x00c0, 0x109f: 0x00c0, 0x10a0: 0x00c0, 0x10a1: 0x00c0, 0x10a2: 0x00c0, 0x10a3: 0x00c0,
+	0x10a4: 0x00c0, 0x10a5: 0x00c0, 0x10a6: 0x00c0, 0x10a7: 0x00c0, 0x10a8: 0x00c0, 0x10a9: 0x00c0,
+	0x10aa: 0x00c0, 0x10ab: 0x00c0, 0x10ac: 0x00c0, 0x10ad: 0x00c0, 0x10ae: 0x00c0, 0x10af: 0x00c0,
+	0x10b0: 0x00c0, 0x10b2: 0x00c0, 0x10b3: 0x00c0, 0x10b4: 0x00c0, 0x10b5: 0x00c0,
+	0x10b8: 0x00c0, 0x10b9: 0x00c0, 0x10ba: 0x00c0, 0x10bb: 0x00c0,
+	0x10bc: 0x00c0, 0x10bd: 0x00c0, 0x10be: 0x00c0,
+	// Block 0x43, offset 0x10c0
+	0x10c0: 0x00c0, 0x10c2: 0x00c0, 0x10c3: 0x00c0, 0x10c4: 0x00c0, 0x10c5: 0x00c0,
+	0x10c8: 0x00c0, 0x10c9: 0x00c0, 0x10ca: 0x00c0, 0x10cb: 0x00c0,
+	0x10cc: 0x00c0, 0x10cd: 0x00c0, 0x10ce: 0x00c0, 0x10cf: 0x00c0, 0x10d0: 0x00c0, 0x10d1: 0x00c0,
+	0x10d2: 0x00c0, 0x10d3: 0x00c0, 0x10d4: 0x00c0, 0x10d5: 0x00c0, 0x10d6: 0x00c0,
+	0x10d8: 0x00c0, 0x10d9: 0x00c0, 0x10da: 0x00c0, 0x10db: 0x00c0, 0x10dc: 0x00c0, 0x10dd: 0x00c0,
+	0x10de: 0x00c0, 0x10df: 0x00c0, 0x10e0: 0x00c0, 0x10e1: 0x00c0, 0x10e2: 0x00c0, 0x10e3: 0x00c0,
+	0x10e4: 0x00c0, 0x10e5: 0x00c0, 0x10e6: 0x00c0, 0x10e7: 0x00c0, 0x10e8: 0x00c0, 0x10e9: 0x00c0,
+	0x10ea: 0x00c0, 0x10eb: 0x00c0, 0x10ec: 0x00c0, 0x10ed: 0x00c0, 0x10ee: 0x00c0, 0x10ef: 0x00c0,
+	0x10f0: 0x00c0, 0x10f1: 0x00c0, 0x10f2: 0x00c0, 0x10f3: 0x00c0, 0x10f4: 0x00c0, 0x10f5: 0x00c0,
+	0x10f6: 0x00c0, 0x10f7: 0x00c0, 0x10f8: 0x00c0, 0x10f9: 0x00c0, 0x10fa: 0x00c0, 0x10fb: 0x00c0,
+	0x10fc: 0x00c0, 0x10fd: 0x00c0, 0x10fe: 0x00c0, 0x10ff: 0x00c0,
+	// Block 0x44, offset 0x1100
+	0x1100: 0x00c0, 0x1101: 0x00c0, 0x1102: 0x00c0, 0x1103: 0x00c0, 0x1104: 0x00c0, 0x1105: 0x00c0,
+	0x1106: 0x00c0, 0x1107: 0x00c0, 0x1108: 0x00c0, 0x1109: 0x00c0, 0x110a: 0x00c0, 0x110b: 0x00c0,
+	0x110c: 0x00c0, 0x110d: 0x00c0, 0x110e: 0x00c0, 0x110f: 0x00c0, 0x1110: 0x00c0,
+	0x1112: 0x00c0, 0x1113: 0x00c0, 0x1114: 0x00c0, 0x1115: 0x00c0,
+	0x1118: 0x00c0, 0x1119: 0x00c0, 0x111a: 0x00c0, 0x111b: 0x00c0, 0x111c: 0x00c0, 0x111d: 0x00c0,
+	0x111e: 0x00c0, 0x111f: 0x00c0, 0x1120: 0x00c0, 0x1121: 0x00c0, 0x1122: 0x00c0, 0x1123: 0x00c0,
+	0x1124: 0x00c0, 0x1125: 0x00c0, 0x1126: 0x00c0, 0x1127: 0x00c0, 0x1128: 0x00c0, 0x1129: 0x00c0,
+	0x112a: 0x00c0, 0x112b: 0x00c0, 0x112c: 0x00c0, 0x112d: 0x00c0, 0x112e: 0x00c0, 0x112f: 0x00c0,
+	0x1130: 0x00c0, 0x1131: 0x00c0, 0x1132: 0x00c0, 0x1133: 0x00c0, 0x1134: 0x00c0, 0x1135: 0x00c0,
+	0x1136: 0x00c0, 0x1137: 0x00c0, 0x1138: 0x00c0, 0x1139: 0x00c0, 0x113a: 0x00c0, 0x113b: 0x00c0,
+	0x113c: 0x00c0, 0x113d: 0x00c0, 0x113e: 0x00c0, 0x113f: 0x00c0,
+	// Block 0x45, offset 0x1140
+	0x1140: 0x00c0, 0x1141: 0x00c0, 0x1142: 0x00c0, 0x1143: 0x00c0, 0x1144: 0x00c0, 0x1145: 0x00c0,
+	0x1146: 0x00c0, 0x1147: 0x00c0, 0x1148: 0x00c0, 0x1149: 0x00c0, 0x114a: 0x00c0, 0x114b: 0x00c0,
+	0x114c: 0x00c0, 0x114d: 0x00c0, 0x114e: 0x00c0, 0x114f: 0x00c0, 0x1150: 0x00c0, 0x1151: 0x00c0,
+	0x1152: 0x00c0, 0x1153: 0x00c0, 0x1154: 0x00c0, 0x1155: 0x00c0, 0x1156: 0x00c0, 0x1157: 0x00c0,
+	0x1158: 0x00c0, 0x1159: 0x00c0, 0x115a: 0x00c0, 0x115d: 0x00c3,
+	0x115e: 0x00c3, 0x115f: 0x00c3, 0x1160: 0x0080, 0x1161: 0x0080, 0x1162: 0x0080, 0x1163: 0x0080,
+	0x1164: 0x0080, 0x1165: 0x0080, 0x1166: 0x0080, 0x1167: 0x0080, 0x1168: 0x0080, 0x1169: 0x0080,
+	0x116a: 0x0080, 0x116b: 0x0080, 0x116c: 0x0080, 0x116d: 0x0080, 0x116e: 0x0080, 0x116f: 0x0080,
+	0x1170: 0x0080, 0x1171: 0x0080, 0x1172: 0x0080, 0x1173: 0x0080, 0x1174: 0x0080, 0x1175: 0x0080,
+	0x1176: 0x0080, 0x1177: 0x0080, 0x1178: 0x0080, 0x1179: 0x0080, 0x117a: 0x0080, 0x117b: 0x0080,
+	0x117c: 0x0080,
+	// Block 0x46, offset 0x1180
+	0x1180: 0x00c0, 0x1181: 0x00c0, 0x1182: 0x00c0, 0x1183: 0x00c0, 0x1184: 0x00c0, 0x1185: 0x00c0,
+	0x1186: 0x00c0, 0x1187: 0x00c0, 0x1188: 0x00c0, 0x1189: 0x00c0, 0x118a: 0x00c0, 0x118b: 0x00c0,
+	0x118c: 0x00c0, 0x118d: 0x00c0, 0x118e: 0x00c0, 0x118f: 0x00c0, 0x1190: 0x0080, 0x1191: 0x0080,
+	0x1192: 0x0080, 0x1193: 0x0080, 0x1194: 0x0080, 0x1195: 0x0080, 0x1196: 0x0080, 0x1197: 0x0080,
+	0x1198: 0x0080, 0x1199: 0x0080,
+	0x11a0: 0x00c0, 0x11a1: 0x00c0, 0x11a2: 0x00c0, 0x11a3: 0x00c0,
+	0x11a4: 0x00c0, 0x11a5: 0x00c0, 0x11a6: 0x00c0, 0x11a7: 0x00c0, 0x11a8: 0x00c0, 0x11a9: 0x00c0,
+	0x11aa: 0x00c0, 0x11ab: 0x00c0, 0x11ac: 0x00c0, 0x11ad: 0x00c0, 0x11ae: 0x00c0, 0x11af: 0x00c0,
+	0x11b0: 0x00c0, 0x11b1: 0x00c0, 0x11b2: 0x00c0, 0x11b3: 0x00c0, 0x11b4: 0x00c0, 0x11b5: 0x00c0,
+	0x11b6: 0x00c0, 0x11b7: 0x00c0, 0x11b8: 0x00c0, 0x11b9: 0x00c0, 0x11ba: 0x00c0, 0x11bb: 0x00c0,
+	0x11bc: 0x00c0, 0x11bd: 0x00c0, 0x11be: 0x00c0, 0x11bf: 0x00c0,
+	// Block 0x47, offset 0x11c0
+	0x11c0: 0x00c0, 0x11c1: 0x00c0, 0x11c2: 0x00c0, 0x11c3: 0x00c0, 0x11c4: 0x00c0, 0x11c5: 0x00c0,
+	0x11c6: 0x00c0, 0x11c7: 0x00c0, 0x11c8: 0x00c0, 0x11c9: 0x00c0, 0x11ca: 0x00c0, 0x11cb: 0x00c0,
+	0x11cc: 0x00c0, 0x11cd: 0x00c0, 0x11ce: 0x00c0, 0x11cf: 0x00c0, 0x11d0: 0x00c0, 0x11d1: 0x00c0,
+	0x11d2: 0x00c0, 0x11d3: 0x00c0, 0x11d4: 0x00c0, 0x11d5: 0x00c0, 0x11d6: 0x00c0, 0x11d7: 0x00c0,
+	0x11d8: 0x00c0, 0x11d9: 0x00c0, 0x11da: 0x00c0, 0x11db: 0x00c0, 0x11dc: 0x00c0, 0x11dd: 0x00c0,
+	0x11de: 0x00c0, 0x11df: 0x00c0, 0x11e0: 0x00c0, 0x11e1: 0x00c0, 0x11e2: 0x00c0, 0x11e3: 0x00c0,
+	0x11e4: 0x00c0, 0x11e5: 0x00c0, 0x11e6: 0x00c0, 0x11e7: 0x00c0, 0x11e8: 0x00c0, 0x11e9: 0x00c0,
+	0x11ea: 0x00c0, 0x11eb: 0x00c0, 0x11ec: 0x00c0, 0x11ed: 0x00c0, 0x11ee: 0x00c0, 0x11ef: 0x00c0,
+	0x11f0: 0x00c0, 0x11f1: 0x00c0, 0x11f2: 0x00c0, 0x11f3: 0x00c0, 0x11f4: 0x00c0, 0x11f5: 0x00c0,
+	0x11f8: 0x00c0, 0x11f9: 0x00c0, 0x11fa: 0x00c0, 0x11fb: 0x00c0,
+	0x11fc: 0x00c0, 0x11fd: 0x00c0,
+	// Block 0x48, offset 0x1200
+	0x1200: 0x0080, 0x1201: 0x00c0, 0x1202: 0x00c0, 0x1203: 0x00c0, 0x1204: 0x00c0, 0x1205: 0x00c0,
+	0x1206: 0x00c0, 0x1207: 0x00c0, 0x1208: 0x00c0, 0x1209: 0x00c0, 0x120a: 0x00c0, 0x120b: 0x00c0,
+	0x120c: 0x00c0, 0x120d: 0x00c0, 0x120e: 0x00c0, 0x120f: 0x00c0, 0x1210: 0x00c0, 0x1211: 0x00c0,
+	0x1212: 0x00c0, 0x1213: 0x00c0, 0x1214: 0x00c0, 0x1215: 0x00c0, 0x1216: 0x00c0, 0x1217: 0x00c0,
+	0x1218: 0x00c0, 0x1219: 0x00c0, 0x121a: 0x00c0, 0x121b: 0x00c0, 0x121c: 0x00c0, 0x121d: 0x00c0,
+	0x121e: 0x00c0, 0x121f: 0x00c0, 0x1220: 0x00c0, 0x1221: 0x00c0, 0x1222: 0x00c0, 0x1223: 0x00c0,
+	0x1224: 0x00c0, 0x1225: 0x00c0, 0x1226: 0x00c0, 0x1227: 0x00c0, 0x1228: 0x00c0, 0x1229: 0x00c0,
+	0x122a: 0x00c0, 0x122b: 0x00c0, 0x122c: 0x00c0, 0x122d: 0x00c0, 0x122e: 0x00c0, 0x122f: 0x00c0,
+	0x1230: 0x00c0, 0x1231: 0x00c0, 0x1232: 0x00c0, 0x1233: 0x00c0, 0x1234: 0x00c0, 0x1235: 0x00c0,
+	0x1236: 0x00c0, 0x1237: 0x00c0, 0x1238: 0x00c0, 0x1239: 0x00c0, 0x123a: 0x00c0, 0x123b: 0x00c0,
+	0x123c: 0x00c0, 0x123d: 0x00c0, 0x123e: 0x00c0, 0x123f: 0x00c0,
+	// Block 0x49, offset 0x1240
+	0x1240: 0x00c0, 0x1241: 0x00c0, 0x1242: 0x00c0, 0x1243: 0x00c0, 0x1244: 0x00c0, 0x1245: 0x00c0,
+	0x1246: 0x00c0, 0x1247: 0x00c0, 0x1248: 0x00c0, 0x1249: 0x00c0, 0x124a: 0x00c0, 0x124b: 0x00c0,
+	0x124c: 0x00c0, 0x124d: 0x00c0, 0x124e: 0x00c0, 0x124f: 0x00c0, 0x1250: 0x00c0, 0x1251: 0x00c0,
+	0x1252: 0x00c0, 0x1253: 0x00c0, 0x1254: 0x00c0, 0x1255: 0x00c0, 0x1256: 0x00c0, 0x1257: 0x00c0,
+	0x1258: 0x00c0, 0x1259: 0x00c0, 0x125a: 0x00c0, 0x125b: 0x00c0, 0x125c: 0x00c0, 0x125d: 0x00c0,
+	0x125e: 0x00c0, 0x125f: 0x00c0, 0x1260: 0x00c0, 0x1261: 0x00c0, 0x1262: 0x00c0, 0x1263: 0x00c0,
+	0x1264: 0x00c0, 0x1265: 0x00c0, 0x1266: 0x00c0, 0x1267: 0x00c0, 0x1268: 0x00c0, 0x1269: 0x00c0,
+	0x126a: 0x00c0, 0x126b: 0x00c0, 0x126c: 0x00c0, 0x126d: 0x0080, 0x126e: 0x0080, 0x126f: 0x00c0,
+	0x1270: 0x00c0, 0x1271: 0x00c0, 0x1272: 0x00c0, 0x1273: 0x00c0, 0x1274: 0x00c0, 0x1275: 0x00c0,
+	0x1276: 0x00c0, 0x1277: 0x00c0, 0x1278: 0x00c0, 0x1279: 0x00c0, 0x127a: 0x00c0, 0x127b: 0x00c0,
+	0x127c: 0x00c0, 0x127d: 0x00c0, 0x127e: 0x00c0, 0x127f: 0x00c0,
+	// Block 0x4a, offset 0x1280
+	0x1280: 0x0080, 0x1281: 0x00c0, 0x1282: 0x00c0, 0x1283: 0x00c0, 0x1284: 0x00c0, 0x1285: 0x00c0,
+	0x1286: 0x00c0, 0x1287: 0x00c0, 0x1288: 0x00c0, 0x1289: 0x00c0, 0x128a: 0x00c0, 0x128b: 0x00c0,
+	0x128c: 0x00c0, 0x128d: 0x00c0, 0x128e: 0x00c0, 0x128f: 0x00c0, 0x1290: 0x00c0, 0x1291: 0x00c0,
+	0x1292: 0x00c0, 0x1293: 0x00c0, 0x1294: 0x00c0, 0x1295: 0x00c0, 0x1296: 0x00c0, 0x1297: 0x00c0,
+	0x1298: 0x00c0, 0x1299: 0x00c0, 0x129a: 0x00c0, 0x129b: 0x0080, 0x129c: 0x0080,
+	0x12a0: 0x00c0, 0x12a1: 0x00c0, 0x12a2: 0x00c0, 0x12a3: 0x00c0,
+	0x12a4: 0x00c0, 0x12a5: 0x00c0, 0x12a6: 0x00c0, 0x12a7: 0x00c0, 0x12a8: 0x00c0, 0x12a9: 0x00c0,
+	0x12aa: 0x00c0, 0x12ab: 0x00c0, 0x12ac: 0x00c0, 0x12ad: 0x00c0, 0x12ae: 0x00c0, 0x12af: 0x00c0,
+	0x12b0: 0x00c0, 0x12b1: 0x00c0, 0x12b2: 0x00c0, 0x12b3: 0x00c0, 0x12b4: 0x00c0, 0x12b5: 0x00c0,
+	0x12b6: 0x00c0, 0x12b7: 0x00c0, 0x12b8: 0x00c0, 0x12b9: 0x00c0, 0x12ba: 0x00c0, 0x12bb: 0x00c0,
+	0x12bc: 0x00c0, 0x12bd: 0x00c0, 0x12be: 0x00c0, 0x12bf: 0x00c0,
+	// Block 0x4b, offset 0x12c0
+	0x12c0: 0x00c0, 0x12c1: 0x00c0, 0x12c2: 0x00c0, 0x12c3: 0x00c0, 0x12c4: 0x00c0, 0x12c5: 0x00c0,
+	0x12c6: 0x00c0, 0x12c7: 0x00c0, 0x12c8: 0x00c0, 0x12c9: 0x00c0, 0x12ca: 0x00c0, 0x12cb: 0x00c0,
+	0x12cc: 0x00c0, 0x12cd: 0x00c0, 0x12ce: 0x00c0, 0x12cf: 0x00c0, 0x12d0: 0x00c0, 0x12d1: 0x00c0,
+	0x12d2: 0x00c0, 0x12d3: 0x00c0, 0x12d4: 0x00c0, 0x12d5: 0x00c0, 0x12d6: 0x00c0, 0x12d7: 0x00c0,
+	0x12d8: 0x00c0, 0x12d9: 0x00c0, 0x12da: 0x00c0, 0x12db: 0x00c0, 0x12dc: 0x00c0, 0x12dd: 0x00c0,
+	0x12de: 0x00c0, 0x12df: 0x00c0, 0x12e0: 0x00c0, 0x12e1: 0x00c0, 0x12e2: 0x00c0, 0x12e3: 0x00c0,
+	0x12e4: 0x00c0, 0x12e5: 0x00c0, 0x12e6: 0x00c0, 0x12e7: 0x00c0, 0x12e8: 0x00c0, 0x12e9: 0x00c0,
+	0x12ea: 0x00c0, 0x12eb: 0x0080, 0x12ec: 0x0080, 0x12ed: 0x0080, 0x12ee: 0x0080, 0x12ef: 0x0080,
+	0x12f0: 0x0080, 0x12f1: 0x00c0, 0x12f2: 0x00c0, 0x12f3: 0x00c0, 0x12f4: 0x00c0, 0x12f5: 0x00c0,
+	0x12f6: 0x00c0, 0x12f7: 0x00c0, 0x12f8: 0x00c0,
+	// Block 0x4c, offset 0x1300
+	0x1300: 0x00c0, 0x1301: 0x00c0, 0x1302: 0x00c0, 0x1303: 0x00c0, 0x1304: 0x00c0, 0x1305: 0x00c0,
+	0x1306: 0x00c0, 0x1307: 0x00c0, 0x1308: 0x00c0, 0x1309: 0x00c0, 0x130a: 0x00c0, 0x130b: 0x00c0,
+	0x130c: 0x00c0, 0x130d: 0x00c0, 0x130e: 0x00c0, 0x130f: 0x00c0, 0x1310: 0x00c0, 0x1311: 0x00c0,
+	0x1312: 0x00c3, 0x1313: 0x00c3, 0x1314: 0x00c6, 0x1315: 0x00c5,
+	0x131f: 0x00c0, 0x1320: 0x00c0, 0x1321: 0x00c0, 0x1322: 0x00c0, 0x1323: 0x00c0,
+	0x1324: 0x00c0, 0x1325: 0x00c0, 0x1326: 0x00c0, 0x1327: 0x00c0, 0x1328: 0x00c0, 0x1329: 0x00c0,
+	0x132a: 0x00c0, 0x132b: 0x00c0, 0x132c: 0x00c0, 0x132d: 0x00c0, 0x132e: 0x00c0, 0x132f: 0x00c0,
+	0x1330: 0x00c0, 0x1331: 0x00c0, 0x1332: 0x00c3, 0x1333: 0x00c3, 0x1334: 0x00c5, 0x1335: 0x0080,
+	0x1336: 0x0080,
+	// Block 0x4d, offset 0x1340
+	0x1340: 0x00c0, 0x1341: 0x00c0, 0x1342: 0x00c0, 0x1343: 0x00c0, 0x1344: 0x00c0, 0x1345: 0x00c0,
+	0x1346: 0x00c0, 0x1347: 0x00c0, 0x1348: 0x00c0, 0x1349: 0x00c0, 0x134a: 0x00c0, 0x134b: 0x00c0,
+	0x134c: 0x00c0, 0x134d: 0x00c0, 0x134e: 0x00c0, 0x134f: 0x00c0, 0x1350: 0x00c0, 0x1351: 0x00c0,
+	0x1352: 0x00c3, 0x1353: 0x00c3,
+	0x1360: 0x00c0, 0x1361: 0x00c0, 0x1362: 0x00c0, 0x1363: 0x00c0,
+	0x1364: 0x00c0, 0x1365: 0x00c0, 0x1366: 0x00c0, 0x1367: 0x00c0, 0x1368: 0x00c0, 0x1369: 0x00c0,
+	0x136a: 0x00c0, 0x136b: 0x00c0, 0x136c: 0x00c0, 0x136e: 0x00c0, 0x136f: 0x00c0,
+	0x1370: 0x00c0, 0x1372: 0x00c3, 0x1373: 0x00c3,
+	// Block 0x4e, offset 0x1380
+	0x1380: 0x00c0, 0x1381: 0x00c0, 0x1382: 0x00c0, 0x1383: 0x00c0, 0x1384: 0x00c0, 0x1385: 0x00c0,
+	0x1386: 0x00c0, 0x1387: 0x00c0, 0x1388: 0x00c0, 0x1389: 0x00c0, 0x138a: 0x00c0, 0x138b: 0x00c0,
+	0x138c: 0x00c0, 0x138d: 0x00c0, 0x138e: 0x00c0, 0x138f: 0x00c0, 0x1390: 0x00c0, 0x1391: 0x00c0,
+	0x1392: 0x00c0, 0x1393: 0x00c0, 0x1394: 0x00c0, 0x1395: 0x00c0, 0x1396: 0x00c0, 0x1397: 0x00c0,
+	0x1398: 0x00c0, 0x1399: 0x00c0, 0x139a: 0x00c0, 0x139b: 0x00c0, 0x139c: 0x00c0, 0x139d: 0x00c0,
+	0x139e: 0x00c0, 0x139f: 0x00c0, 0x13a0: 0x00c0, 0x13a1: 0x00c0, 0x13a2: 0x00c0, 0x13a3: 0x00c0,
+	0x13a4: 0x00c0, 0x13a5: 0x00c0, 0x13a6: 0x00c0, 0x13a7: 0x00c0, 0x13a8: 0x00c0, 0x13a9: 0x00c0,
+	0x13aa: 0x00c0, 0x13ab: 0x00c0, 0x13ac: 0x00c0, 0x13ad: 0x00c0, 0x13ae: 0x00c0, 0x13af: 0x00c0,
+	0x13b0: 0x00c0, 0x13b1: 0x00c0, 0x13b2: 0x00c0, 0x13b3: 0x00c0, 0x13b4: 0x0040, 0x13b5: 0x0040,
+	0x13b6: 0x00c0, 0x13b7: 0x00c3, 0x13b8: 0x00c3, 0x13b9: 0x00c3, 0x13ba: 0x00c3, 0x13bb: 0x00c3,
+	0x13bc: 0x00c3, 0x13bd: 0x00c3, 0x13be: 0x00c0, 0x13bf: 0x00c0,
+	// Block 0x4f, offset 0x13c0
+	0x13c0: 0x00c0, 0x13c1: 0x00c0, 0x13c2: 0x00c0, 0x13c3: 0x00c0, 0x13c4: 0x00c0, 0x13c5: 0x00c0,
+	0x13c6: 0x00c3, 0x13c7: 0x00c0, 0x13c8: 0x00c0, 0x13c9: 0x00c3, 0x13ca: 0x00c3, 0x13cb: 0x00c3,
+	0x13cc: 0x00c3, 0x13cd: 0x00c3, 0x13ce: 0x00c3, 0x13cf: 0x00c3, 0x13d0: 0x00c3, 0x13d1: 0x00c3,
+	0x13d2: 0x00c6, 0x13d3: 0x00c3, 0x13d4: 0x0080, 0x13d5: 0x0080, 0x13d6: 0x0080, 0x13d7: 0x00c0,
+	0x13d8: 0x0080, 0x13d9: 0x0080, 0x13da: 0x0080, 0x13db: 0x0080, 0x13dc: 0x00c0, 0x13dd: 0x00c3,
+	0x13e0: 0x00c0, 0x13e1: 0x00c0, 0x13e2: 0x00c0, 0x13e3: 0x00c0,
+	0x13e4: 0x00c0, 0x13e5: 0x00c0, 0x13e6: 0x00c0, 0x13e7: 0x00c0, 0x13e8: 0x00c0, 0x13e9: 0x00c0,
+	0x13f0: 0x0080, 0x13f1: 0x0080, 0x13f2: 0x0080, 0x13f3: 0x0080, 0x13f4: 0x0080, 0x13f5: 0x0080,
+	0x13f6: 0x0080, 0x13f7: 0x0080, 0x13f8: 0x0080, 0x13f9: 0x0080,
+	// Block 0x50, offset 0x1400
+	0x1400: 0x0080, 0x1401: 0x0080, 0x1402: 0x0080, 0x1403: 0x0080, 0x1404: 0x0080, 0x1405: 0x0080,
+	0x1406: 0x0080, 0x1407: 0x0082, 0x1408: 0x0080, 0x1409: 0x0080, 0x140a: 0x0080, 0x140b: 0x0040,
+	0x140c: 0x0040, 0x140d: 0x0040, 0x140e: 0x0040, 0x140f: 0x0040, 0x1410: 0x00c0, 0x1411: 0x00c0,
+	0x1412: 0x00c0, 0x1413: 0x00c0, 0x1414: 0x00c0, 0x1415: 0x00c0, 0x1416: 0x00c0, 0x1417: 0x00c0,
+	0x1418: 0x00c0, 0x1419: 0x00c0,
+	0x1420: 0x00c2, 0x1421: 0x00c2, 0x1422: 0x00c2, 0x1423: 0x00c2,
+	0x1424: 0x00c2, 0x1425: 0x00c2, 0x1426: 0x00c2, 0x1427: 0x00c2, 0x1428: 0x00c2, 0x1429: 0x00c2,
+	0x142a: 0x00c2, 0x142b: 0x00c2, 0x142c: 0x00c2, 0x142d: 0x00c2, 0x142e: 0x00c2, 0x142f: 0x00c2,
+	0x1430: 0x00c2, 0x1431: 0x00c2, 0x1432: 0x00c2, 0x1433: 0x00c2, 0x1434: 0x00c2, 0x1435: 0x00c2,
+	0x1436: 0x00c2, 0x1437: 0x00c2, 0x1438: 0x00c2, 0x1439: 0x00c2, 0x143a: 0x00c2, 0x143b: 0x00c2,
+	0x143c: 0x00c2, 0x143d: 0x00c2, 0x143e: 0x00c2, 0x143f: 0x00c2,
+	// Block 0x51, offset 0x1440
+	0x1440: 0x00c2, 0x1441: 0x00c2, 0x1442: 0x00c2, 0x1443: 0x00c2, 0x1444: 0x00c2, 0x1445: 0x00c2,
+	0x1446: 0x00c2, 0x1447: 0x00c2, 0x1448: 0x00c2, 0x1449: 0x00c2, 0x144a: 0x00c2, 0x144b: 0x00c2,
+	0x144c: 0x00c2, 0x144d: 0x00c2, 0x144e: 0x00c2, 0x144f: 0x00c2, 0x1450: 0x00c2, 0x1451: 0x00c2,
+	0x1452: 0x00c2, 0x1453: 0x00c2, 0x1454: 0x00c2, 0x1455: 0x00c2, 0x1456: 0x00c2, 0x1457: 0x00c2,
+	0x1458: 0x00c2, 0x1459: 0x00c2, 0x145a: 0x00c2, 0x145b: 0x00c2, 0x145c: 0x00c2, 0x145d: 0x00c2,
+	0x145e: 0x00c2, 0x145f: 0x00c2, 0x1460: 0x00c2, 0x1461: 0x00c2, 0x1462: 0x00c2, 0x1463: 0x00c2,
+	0x1464: 0x00c2, 0x1465: 0x00c2, 0x1466: 0x00c2, 0x1467: 0x00c2, 0x1468: 0x00c2, 0x1469: 0x00c2,
+	0x146a: 0x00c2, 0x146b: 0x00c2, 0x146c: 0x00c2, 0x146d: 0x00c2, 0x146e: 0x00c2, 0x146f: 0x00c2,
+	0x1470: 0x00c2, 0x1471: 0x00c2, 0x1472: 0x00c2, 0x1473: 0x00c2, 0x1474: 0x00c2, 0x1475: 0x00c2,
+	0x1476: 0x00c2, 0x1477: 0x00c2, 0x1478: 0x00c2,
+	// Block 0x52, offset 0x1480
+	0x1480: 0x00c0, 0x1481: 0x00c0, 0x1482: 0x00c0, 0x1483: 0x00c0, 0x1484: 0x00c0, 0x1485: 0x00c3,
+	0x1486: 0x00c3, 0x1487: 0x00c2, 0x1488: 0x00c2, 0x1489: 0x00c2, 0x148a: 0x00c2, 0x148b: 0x00c2,
+	0x148c: 0x00c2, 0x148d: 0x00c2, 0x148e: 0x00c2, 0x148f: 0x00c2, 0x1490: 0x00c2, 0x1491: 0x00c2,
+	0x1492: 0x00c2, 0x1493: 0x00c2, 0x1494: 0x00c2, 0x1495: 0x00c2, 0x1496: 0x00c2, 0x1497: 0x00c2,
+	0x1498: 0x00c2, 0x1499: 0x00c2, 0x149a: 0x00c2, 0x149b: 0x00c2, 0x149c: 0x00c2, 0x149d: 0x00c2,
+	0x149e: 0x00c2, 0x149f: 0x00c2, 0x14a0: 0x00c2, 0x14a1: 0x00c2, 0x14a2: 0x00c2, 0x14a3: 0x00c2,
+	0x14a4: 0x00c2, 0x14a5: 0x00c2, 0x14a6: 0x00c2, 0x14a7: 0x00c2, 0x14a8: 0x00c2, 0x14a9: 0x00c3,
+	0x14aa: 0x00c2,
+	0x14b0: 0x00c0, 0x14b1: 0x00c0, 0x14b2: 0x00c0, 0x14b3: 0x00c0, 0x14b4: 0x00c0, 0x14b5: 0x00c0,
+	0x14b6: 0x00c0, 0x14b7: 0x00c0, 0x14b8: 0x00c0, 0x14b9: 0x00c0, 0x14ba: 0x00c0, 0x14bb: 0x00c0,
+	0x14bc: 0x00c0, 0x14bd: 0x00c0, 0x14be: 0x00c0, 0x14bf: 0x00c0,
+	// Block 0x53, offset 0x14c0
+	0x14c0: 0x00c0, 0x14c1: 0x00c0, 0x14c2: 0x00c0, 0x14c3: 0x00c0, 0x14c4: 0x00c0, 0x14c5: 0x00c0,
+	0x14c6: 0x00c0, 0x14c7: 0x00c0, 0x14c8: 0x00c0, 0x14c9: 0x00c0, 0x14ca: 0x00c0, 0x14cb: 0x00c0,
+	0x14cc: 0x00c0, 0x14cd: 0x00c0, 0x14ce: 0x00c0, 0x14cf: 0x00c0, 0x14d0: 0x00c0, 0x14d1: 0x00c0,
+	0x14d2: 0x00c0, 0x14d3: 0x00c0, 0x14d4: 0x00c0, 0x14d5: 0x00c0, 0x14d6: 0x00c0, 0x14d7: 0x00c0,
+	0x14d8: 0x00c0, 0x14d9: 0x00c0, 0x14da: 0x00c0, 0x14db: 0x00c0, 0x14dc: 0x00c0, 0x14dd: 0x00c0,
+	0x14de: 0x00c0, 0x14df: 0x00c0, 0x14e0: 0x00c0, 0x14e1: 0x00c0, 0x14e2: 0x00c0, 0x14e3: 0x00c0,
+	0x14e4: 0x00c0, 0x14e5: 0x00c0, 0x14e6: 0x00c0, 0x14e7: 0x00c0, 0x14e8: 0x00c0, 0x14e9: 0x00c0,
+	0x14ea: 0x00c0, 0x14eb: 0x00c0, 0x14ec: 0x00c0, 0x14ed: 0x00c0, 0x14ee: 0x00c0, 0x14ef: 0x00c0,
+	0x14f0: 0x00c0, 0x14f1: 0x00c0, 0x14f2: 0x00c0, 0x14f3: 0x00c0, 0x14f4: 0x00c0, 0x14f5: 0x00c0,
+	// Block 0x54, offset 0x1500
+	0x1500: 0x00c0, 0x1501: 0x00c0, 0x1502: 0x00c0, 0x1503: 0x00c0, 0x1504: 0x00c0, 0x1505: 0x00c0,
+	0x1506: 0x00c0, 0x1507: 0x00c0, 0x1508: 0x00c0, 0x1509: 0x00c0, 0x150a: 0x00c0, 0x150b: 0x00c0,
+	0x150c: 0x00c0, 0x150d: 0x00c0, 0x150e: 0x00c0, 0x150f: 0x00c0, 0x1510: 0x00c0, 0x1511: 0x00c0,
+	0x1512: 0x00c0, 0x1513: 0x00c0, 0x1514: 0x00c0, 0x1515: 0x00c0, 0x1516: 0x00c0, 0x1517: 0x00c0,
+	0x1518: 0x00c0, 0x1519: 0x00c0, 0x151a: 0x00c0, 0x151b: 0x00c0, 0x151c: 0x00c0, 0x151d: 0x00c0,
+	0x151e: 0x00c0, 0x1520: 0x00c3, 0x1521: 0x00c3, 0x1522: 0x00c3, 0x1523: 0x00c0,
+	0x1524: 0x00c0, 0x1525: 0x00c0, 0x1526: 0x00c0, 0x1527: 0x00c3, 0x1528: 0x00c3, 0x1529: 0x00c0,
+	0x152a: 0x00c0, 0x152b: 0x00c0,
+	0x1530: 0x00c0, 0x1531: 0x00c0, 0x1532: 0x00c3, 0x1533: 0x00c0, 0x1534: 0x00c0, 0x1535: 0x00c0,
+	0x1536: 0x00c0, 0x1537: 0x00c0, 0x1538: 0x00c0, 0x1539: 0x00c3, 0x153a: 0x00c3, 0x153b: 0x00c3,
+	// Block 0x55, offset 0x1540
+	0x1540: 0x0080, 0x1544: 0x0080, 0x1545: 0x0080,
+	0x1546: 0x00c0, 0x1547: 0x00c0, 0x1548: 0x00c0, 0x1549: 0x00c0, 0x154a: 0x00c0, 0x154b: 0x00c0,
+	0x154c: 0x00c0, 0x154d: 0x00c0, 0x154e: 0x00c0, 0x154f: 0x00c0, 0x1550: 0x00c0, 0x1551: 0x00c0,
+	0x1552: 0x00c0, 0x1553: 0x00c0, 0x1554: 0x00c0, 0x1555: 0x00c0, 0x1556: 0x00c0, 0x1557: 0x00c0,
+	0x1558: 0x00c0, 0x1559: 0x00c0, 0x155a: 0x00c0, 0x155b: 0x00c0, 0x155c: 0x00c0, 0x155d: 0x00c0,
+	0x155e: 0x00c0, 0x155f: 0x00c0, 0x1560: 0x00c0, 0x1561: 0x00c0, 0x1562: 0x00c0, 0x1563: 0x00c0,
+	0x1564: 0x00c0, 0x1565: 0x00c0, 0x1566: 0x00c0, 0x1567: 0x00c0, 0x1568: 0x00c0, 0x1569: 0x00c0,
+	0x156a: 0x00c0, 0x156b: 0x00c0, 0x156c: 0x00c0, 0x156d: 0x00c0,
+	0x1570: 0x00c0, 0x1571: 0x00c0, 0x1572: 0x00c0, 0x1573: 0x00c0, 0x1574: 0x00c0,
+	// Block 0x56, offset 0x1580
+	0x1580: 0x00c0, 0x1581: 0x00c0, 0x1582: 0x00c0, 0x1583: 0x00c0, 0x1584: 0x00c0, 0x1585: 0x00c0,
+	0x1586: 0x00c0, 0x1587: 0x00c0, 0x1588: 0x00c0, 0x1589: 0x00c0, 0x158a: 0x00c0, 0x158b: 0x00c0,
+	0x158c: 0x00c0, 0x158d: 0x00c0, 0x158e: 0x00c0, 0x158f: 0x00c0, 0x1590: 0x00c0, 0x1591: 0x00c0,
+	0x1592: 0x00c0, 0x1593: 0x00c0, 0x1594: 0x00c0, 0x1595: 0x00c0, 0x1596: 0x00c0, 0x1597: 0x00c0,
+	0x1598: 0x00c0, 0x1599: 0x00c0, 0x159a: 0x00c0, 0x159b: 0x00c0, 0x159c: 0x00c0, 0x159d: 0x00c0,
+	0x159e: 0x00c0, 0x159f: 0x00c0, 0x15a0: 0x00c0, 0x15a1: 0x00c0, 0x15a2: 0x00c0, 0x15a3: 0x00c0,
+	0x15a4: 0x00c0, 0x15a5: 0x00c0, 0x15a6: 0x00c0, 0x15a7: 0x00c0, 0x15a8: 0x00c0, 0x15a9: 0x00c0,
+	0x15aa: 0x00c0, 0x15ab: 0x00c0,
+	0x15b0: 0x00c0, 0x15b1: 0x00c0, 0x15b2: 0x00c0, 0x15b3: 0x00c0, 0x15b4: 0x00c0, 0x15b5: 0x00c0,
+	0x15b6: 0x00c0, 0x15b7: 0x00c0, 0x15b8: 0x00c0, 0x15b9: 0x00c0, 0x15ba: 0x00c0, 0x15bb: 0x00c0,
+	0x15bc: 0x00c0, 0x15bd: 0x00c0, 0x15be: 0x00c0, 0x15bf: 0x00c0,
+	// Block 0x57, offset 0x15c0
+	0x15c0: 0x00c0, 0x15c1: 0x00c0, 0x15c2: 0x00c0, 0x15c3: 0x00c0, 0x15c4: 0x00c0, 0x15c5: 0x00c0,
+	0x15c6: 0x00c0, 0x15c7: 0x00c0, 0x15c8: 0x00c0, 0x15c9: 0x00c0,
+	0x15d0: 0x00c0, 0x15d1: 0x00c0,
+	0x15d2: 0x00c0, 0x15d3: 0x00c0, 0x15d4: 0x00c0, 0x15d5: 0x00c0, 0x15d6: 0x00c0, 0x15d7: 0x00c0,
+	0x15d8: 0x00c0, 0x15d9: 0x00c0, 0x15da: 0x0080,
+	0x15de: 0x0080, 0x15df: 0x0080, 0x15e0: 0x0080, 0x15e1: 0x0080, 0x15e2: 0x0080, 0x15e3: 0x0080,
+	0x15e4: 0x0080, 0x15e5: 0x0080, 0x15e6: 0x0080, 0x15e7: 0x0080, 0x15e8: 0x0080, 0x15e9: 0x0080,
+	0x15ea: 0x0080, 0x15eb: 0x0080, 0x15ec: 0x0080, 0x15ed: 0x0080, 0x15ee: 0x0080, 0x15ef: 0x0080,
+	0x15f0: 0x0080, 0x15f1: 0x0080, 0x15f2: 0x0080, 0x15f3: 0x0080, 0x15f4: 0x0080, 0x15f5: 0x0080,
+	0x15f6: 0x0080, 0x15f7: 0x0080, 0x15f8: 0x0080, 0x15f9: 0x0080, 0x15fa: 0x0080, 0x15fb: 0x0080,
+	0x15fc: 0x0080, 0x15fd: 0x0080, 0x15fe: 0x0080, 0x15ff: 0x0080,
+	// Block 0x58, offset 0x1600
+	0x1600: 0x00c0, 0x1601: 0x00c0, 0x1602: 0x00c0, 0x1603: 0x00c0, 0x1604: 0x00c0, 0x1605: 0x00c0,
+	0x1606: 0x00c0, 0x1607: 0x00c0, 0x1608: 0x00c0, 0x1609: 0x00c0, 0x160a: 0x00c0, 0x160b: 0x00c0,
+	0x160c: 0x00c0, 0x160d: 0x00c0, 0x160e: 0x00c0, 0x160f: 0x00c0, 0x1610: 0x00c0, 0x1611: 0x00c0,
+	0x1612: 0x00c0, 0x1613: 0x00c0, 0x1614: 0x00c0, 0x1615: 0x00c0, 0x1616: 0x00c0, 0x1617: 0x00c3,
+	0x1618: 0x00c3, 0x1619: 0x00c0, 0x161a: 0x00c0, 0x161b: 0x00c3,
+	0x161e: 0x0080, 0x161f: 0x0080, 0x1620: 0x00c0, 0x1621: 0x00c0, 0x1622: 0x00c0, 0x1623: 0x00c0,
+	0x1624: 0x00c0, 0x1625: 0x00c0, 0x1626: 0x00c0, 0x1627: 0x00c0, 0x1628: 0x00c0, 0x1629: 0x00c0,
+	0x162a: 0x00c0, 0x162b: 0x00c0, 0x162c: 0x00c0, 0x162d: 0x00c0, 0x162e: 0x00c0, 0x162f: 0x00c0,
+	0x1630: 0x00c0, 0x1631: 0x00c0, 0x1632: 0x00c0, 0x1633: 0x00c0, 0x1634: 0x00c0, 0x1635: 0x00c0,
+	0x1636: 0x00c0, 0x1637: 0x00c0, 0x1638: 0x00c0, 0x1639: 0x00c0, 0x163a: 0x00c0, 0x163b: 0x00c0,
+	0x163c: 0x00c0, 0x163d: 0x00c0, 0x163e: 0x00c0, 0x163f: 0x00c0,
+	// Block 0x59, offset 0x1640
+	0x1640: 0x00c0, 0x1641: 0x00c0, 0x1642: 0x00c0, 0x1643: 0x00c0, 0x1644: 0x00c0, 0x1645: 0x00c0,
+	0x1646: 0x00c0, 0x1647: 0x00c0, 0x1648: 0x00c0, 0x1649: 0x00c0, 0x164a: 0x00c0, 0x164b: 0x00c0,
+	0x164c: 0x00c0, 0x164d: 0x00c0, 0x164e: 0x00c0, 0x164f: 0x00c0, 0x1650: 0x00c0, 0x1651: 0x00c0,
+	0x1652: 0x00c0, 0x1653: 0x00c0, 0x1654: 0x00c0, 0x1655: 0x00c0, 0x1656: 0x00c3, 0x1657: 0x00c0,
+	0x1658: 0x00c3, 0x1659: 0x00c3, 0x165a: 0x00c3, 0x165b: 0x00c3, 0x165c: 0x00c3, 0x165d: 0x00c3,
+	0x165e: 0x00c3, 0x1660: 0x00c6, 0x1661: 0x00c0, 0x1662: 0x00c3, 0x1663: 0x00c0,
+	0x1664: 0x00c0, 0x1665: 0x00c3, 0x1666: 0x00c3, 0x1667: 0x00c3, 0x1668: 0x00c3, 0x1669: 0x00c3,
+	0x166a: 0x00c3, 0x166b: 0x00c3, 0x166c: 0x00c3, 0x166d: 0x00c0, 0x166e: 0x00c0, 0x166f: 0x00c0,
+	0x1670: 0x00c0, 0x1671: 0x00c0, 0x1672: 0x00c0, 0x1673: 0x00c3, 0x1674: 0x00c3, 0x1675: 0x00c3,
+	0x1676: 0x00c3, 0x1677: 0x00c3, 0x1678: 0x00c3, 0x1679: 0x00c3, 0x167a: 0x00c3, 0x167b: 0x00c3,
+	0x167c: 0x00c3, 0x167f: 0x00c3,
+	// Block 0x5a, offset 0x1680
+	0x1680: 0x00c0, 0x1681: 0x00c0, 0x1682: 0x00c0, 0x1683: 0x00c0, 0x1684: 0x00c0, 0x1685: 0x00c0,
+	0x1686: 0x00c0, 0x1687: 0x00c0, 0x1688: 0x00c0, 0x1689: 0x00c0,
+	0x1690: 0x00c0, 0x1691: 0x00c0,
+	0x1692: 0x00c0, 0x1693: 0x00c0, 0x1694: 0x00c0, 0x1695: 0x00c0, 0x1696: 0x00c0, 0x1697: 0x00c0,
+	0x1698: 0x00c0, 0x1699: 0x00c0,
+	0x16a0: 0x0080, 0x16a1: 0x0080, 0x16a2: 0x0080, 0x16a3: 0x0080,
+	0x16a4: 0x0080, 0x16a5: 0x0080, 0x16a6: 0x0080, 0x16a7: 0x00c0, 0x16a8: 0x0080, 0x16a9: 0x0080,
+	0x16aa: 0x0080, 0x16ab: 0x0080, 0x16ac: 0x0080, 0x16ad: 0x0080,
+	0x16b0: 0x00c3, 0x16b1: 0x00c3, 0x16b2: 0x00c3, 0x16b3: 0x00c3, 0x16b4: 0x00c3, 0x16b5: 0x00c3,
+	0x16b6: 0x00c3, 0x16b7: 0x00c3, 0x16b8: 0x00c3, 0x16b9: 0x00c3, 0x16ba: 0x00c3, 0x16bb: 0x00c3,
+	0x16bc: 0x00c3, 0x16bd: 0x00c3, 0x16be: 0x0083, 0x16bf: 0x00c3,
+	// Block 0x5b, offset 0x16c0
+	0x16c0: 0x00c3, 0x16c1: 0x00c3, 0x16c2: 0x00c3, 0x16c3: 0x00c3, 0x16c4: 0x00c3, 0x16c5: 0x00c3,
+	0x16c6: 0x00c3, 0x16c7: 0x00c3, 0x16c8: 0x00c3, 0x16c9: 0x00c3, 0x16ca: 0x00c3, 0x16cb: 0x00c3,
+	0x16cc: 0x00c3, 0x16cd: 0x00c3, 0x16ce: 0x00c3,
+	// Block 0x5c, offset 0x1700
+	0x1700: 0x00c3, 0x1701: 0x00c3, 0x1702: 0x00c3, 0x1703: 0x00c3, 0x1704: 0x00c0, 0x1705: 0x00c0,
+	0x1706: 0x00c0, 0x1707: 0x00c0, 0x1708: 0x00c0, 0x1709: 0x00c0, 0x170a: 0x00c0, 0x170b: 0x00c0,
+	0x170c: 0x00c0, 0x170d: 0x00c0, 0x170e: 0x00c0, 0x170f: 0x00c0, 0x1710: 0x00c0, 0x1711: 0x00c0,
+	0x1712: 0x00c0, 0x1713: 0x00c0, 0x1714: 0x00c0, 0x1715: 0x00c0, 0x1716: 0x00c0, 0x1717: 0x00c0,
+	0x1718: 0x00c0, 0x1719: 0x00c0, 0x171a: 0x00c0, 0x171b: 0x00c0, 0x171c: 0x00c0, 0x171d: 0x00c0,
+	0x171e: 0x00c0, 0x171f: 0x00c0, 0x1720: 0x00c0, 0x1721: 0x00c0, 0x1722: 0x00c0, 0x1723: 0x00c0,
+	0x1724: 0x00c0, 0x1725: 0x00c0, 0x1726: 0x00c0, 0x1727: 0x00c0, 0x1728: 0x00c0, 0x1729: 0x00c0,
+	0x172a: 0x00c0, 0x172b: 0x00c0, 0x172c: 0x00c0, 0x172d: 0x00c0, 0x172e: 0x00c0, 0x172f: 0x00c0,
+	0x1730: 0x00c0, 0x1731: 0x00c0, 0x1732: 0x00c0, 0x1733: 0x00c0, 0x1734: 0x00c3, 0x1735: 0x00c0,
+	0x1736: 0x00c3, 0x1737: 0x00c3, 0x1738: 0x00c3, 0x1739: 0x00c3, 0x173a: 0x00c3, 0x173b: 0x00c0,
+	0x173c: 0x00c3, 0x173d: 0x00c0, 0x173e: 0x00c0, 0x173f: 0x00c0,
+	// Block 0x5d, offset 0x1740
+	0x1740: 0x00c0, 0x1741: 0x00c0, 0x1742: 0x00c3, 0x1743: 0x00c0, 0x1744: 0x00c5, 0x1745: 0x00c0,
+	0x1746: 0x00c0, 0x1747: 0x00c0, 0x1748: 0x00c0, 0x1749: 0x00c0, 0x174a: 0x00c0, 0x174b: 0x00c0,
+	0x174c: 0x00c0, 0x1750: 0x00c0, 0x1751: 0x00c0,
+	0x1752: 0x00c0, 0x1753: 0x00c0, 0x1754: 0x00c0, 0x1755: 0x00c0, 0x1756: 0x00c0, 0x1757: 0x00c0,
+	0x1758: 0x00c0, 0x1759: 0x00c0, 0x175a: 0x0080, 0x175b: 0x0080, 0x175c: 0x0080, 0x175d: 0x0080,
+	0x175e: 0x0080, 0x175f: 0x0080, 0x1760: 0x0080, 0x1761: 0x0080, 0x1762: 0x0080, 0x1763: 0x0080,
+	0x1764: 0x0080, 0x1765: 0x0080, 0x1766: 0x0080, 0x1767: 0x0080, 0x1768: 0x0080, 0x1769: 0x0080,
+	0x176a: 0x0080, 0x176b: 0x00c3, 0x176c: 0x00c3, 0x176d: 0x00c3, 0x176e: 0x00c3, 0x176f: 0x00c3,
+	0x1770: 0x00c3, 0x1771: 0x00c3, 0x1772: 0x00c3, 0x1773: 0x00c3, 0x1774: 0x0080, 0x1775: 0x0080,
+	0x1776: 0x0080, 0x1777: 0x0080, 0x1778: 0x0080, 0x1779: 0x0080, 0x177a: 0x0080, 0x177b: 0x0080,
+	0x177c: 0x0080, 0x177d: 0x0080, 0x177e: 0x0080,
+	// Block 0x5e, offset 0x1780
+	0x1780: 0x00c3, 0x1781: 0x00c3, 0x1782: 0x00c0, 0x1783: 0x00c0, 0x1784: 0x00c0, 0x1785: 0x00c0,
+	0x1786: 0x00c0, 0x1787: 0x00c0, 0x1788: 0x00c0, 0x1789: 0x00c0, 0x178a: 0x00c0, 0x178b: 0x00c0,
+	0x178c: 0x00c0, 0x178d: 0x00c0, 0x178e: 0x00c0, 0x178f: 0x00c0, 0x1790: 0x00c0, 0x1791: 0x00c0,
+	0x1792: 0x00c0, 0x1793: 0x00c0, 0x1794: 0x00c0, 0x1795: 0x00c0, 0x1796: 0x00c0, 0x1797: 0x00c0,
+	0x1798: 0x00c0, 0x1799: 0x00c0, 0x179a: 0x00c0, 0x179b: 0x00c0, 0x179c: 0x00c0, 0x179d: 0x00c0,
+	0x179e: 0x00c0, 0x179f: 0x00c0, 0x17a0: 0x00c0, 0x17a1: 0x00c0, 0x17a2: 0x00c3, 0x17a3: 0x00c3,
+	0x17a4: 0x00c3, 0x17a5: 0x00c3, 0x17a6: 0x00c0, 0x17a7: 0x00c0, 0x17a8: 0x00c3, 0x17a9: 0x00c3,
+	0x17aa: 0x00c5, 0x17ab: 0x00c6, 0x17ac: 0x00c3, 0x17ad: 0x00c3, 0x17ae: 0x00c0, 0x17af: 0x00c0,
+	0x17b0: 0x00c0, 0x17b1: 0x00c0, 0x17b2: 0x00c0, 0x17b3: 0x00c0, 0x17b4: 0x00c0, 0x17b5: 0x00c0,
+	0x17b6: 0x00c0, 0x17b7: 0x00c0, 0x17b8: 0x00c0, 0x17b9: 0x00c0, 0x17ba: 0x00c0, 0x17bb: 0x00c0,
+	0x17bc: 0x00c0, 0x17bd: 0x00c0, 0x17be: 0x00c0, 0x17bf: 0x00c0,
+	// Block 0x5f, offset 0x17c0
+	0x17c0: 0x00c0, 0x17c1: 0x00c0, 0x17c2: 0x00c0, 0x17c3: 0x00c0, 0x17c4: 0x00c0, 0x17c5: 0x00c0,
+	0x17c6: 0x00c0, 0x17c7: 0x00c0, 0x17c8: 0x00c0, 0x17c9: 0x00c0, 0x17ca: 0x00c0, 0x17cb: 0x00c0,
+	0x17cc: 0x00c0, 0x17cd: 0x00c0, 0x17ce: 0x00c0, 0x17cf: 0x00c0, 0x17d0: 0x00c0, 0x17d1: 0x00c0,
+	0x17d2: 0x00c0, 0x17d3: 0x00c0, 0x17d4: 0x00c0, 0x17d5: 0x00c0, 0x17d6: 0x00c0, 0x17d7: 0x00c0,
+	0x17d8: 0x00c0, 0x17d9: 0x00c0, 0x17da: 0x00c0, 0x17db: 0x00c0, 0x17dc: 0x00c0, 0x17dd: 0x00c0,
+	0x17de: 0x00c0, 0x17df: 0x00c0, 0x17e0: 0x00c0, 0x17e1: 0x00c0, 0x17e2: 0x00c0, 0x17e3: 0x00c0,
+	0x17e4: 0x00c0, 0x17e5: 0x00c0, 0x17e6: 0x00c3, 0x17e7: 0x00c0, 0x17e8: 0x00c3, 0x17e9: 0x00c3,
+	0x17ea: 0x00c0, 0x17eb: 0x00c0, 0x17ec: 0x00c0, 0x17ed: 0x00c3, 0x17ee: 0x00c0, 0x17ef: 0x00c3,
+	0x17f0: 0x00c3, 0x17f1: 0x00c3, 0x17f2: 0x00c5, 0x17f3: 0x00c5,
+	0x17fc: 0x0080, 0x17fd: 0x0080, 0x17fe: 0x0080, 0x17ff: 0x0080,
+	// Block 0x60, offset 0x1800
+	0x1800: 0x00c0, 0x1801: 0x00c0, 0x1802: 0x00c0, 0x1803: 0x00c0, 0x1804: 0x00c0, 0x1805: 0x00c0,
+	0x1806: 0x00c0, 0x1807: 0x00c0, 0x1808: 0x00c0, 0x1809: 0x00c0, 0x180a: 0x00c0, 0x180b: 0x00c0,
+	0x180c: 0x00c0, 0x180d: 0x00c0, 0x180e: 0x00c0, 0x180f: 0x00c0, 0x1810: 0x00c0, 0x1811: 0x00c0,
+	0x1812: 0x00c0, 0x1813: 0x00c0, 0x1814: 0x00c0, 0x1815: 0x00c0, 0x1816: 0x00c0, 0x1817: 0x00c0,
+	0x1818: 0x00c0, 0x1819: 0x00c0, 0x181a: 0x00c0, 0x181b: 0x00c0, 0x181c: 0x00c0, 0x181d: 0x00c0,
+	0x181e: 0x00c0, 0x181f: 0x00c0, 0x1820: 0x00c0, 0x1821: 0x00c0, 0x1822: 0x00c0, 0x1823: 0x00c0,
+	0x1824: 0x00c0, 0x1825: 0x00c0, 0x1826: 0x00c0, 0x1827: 0x00c0, 0x1828: 0x00c0, 0x1829: 0x00c0,
+	0x182a: 0x00c0, 0x182b: 0x00c0, 0x182c: 0x00c3, 0x182d: 0x00c3, 0x182e: 0x00c3, 0x182f: 0x00c3,
+	0x1830: 0x00c3, 0x1831: 0x00c3, 0x1832: 0x00c3, 0x1833: 0x00c3, 0x1834: 0x00c0, 0x1835: 0x00c0,
+	0x1836: 0x00c3, 0x1837: 0x00c3, 0x183b: 0x0080,
+	0x183c: 0x0080, 0x183d: 0x0080, 0x183e: 0x0080, 0x183f: 0x0080,
+	// Block 0x61, offset 0x1840
+	0x1840: 0x00c0, 0x1841: 0x00c0, 0x1842: 0x00c0, 0x1843: 0x00c0, 0x1844: 0x00c0, 0x1845: 0x00c0,
+	0x1846: 0x00c0, 0x1847: 0x00c0, 0x1848: 0x00c0, 0x1849: 0x00c0,
+	0x184d: 0x00c0, 0x184e: 0x00c0, 0x184f: 0x00c0, 0x1850: 0x00c0, 0x1851: 0x00c0,
+	0x1852: 0x00c0, 0x1853: 0x00c0, 0x1854: 0x00c0, 0x1855: 0x00c0, 0x1856: 0x00c0, 0x1857: 0x00c0,
+	0x1858: 0x00c0, 0x1859: 0x00c0, 0x185a: 0x00c0, 0x185b: 0x00c0, 0x185c: 0x00c0, 0x185d: 0x00c0,
+	0x185e: 0x00c0, 0x185f: 0x00c0, 0x1860: 0x00c0, 0x1861: 0x00c0, 0x1862: 0x00c0, 0x1863: 0x00c0,
+	0x1864: 0x00c0, 0x1865: 0x00c0, 0x1866: 0x00c0, 0x1867: 0x00c0, 0x1868: 0x00c0, 0x1869: 0x00c0,
+	0x186a: 0x00c0, 0x186b: 0x00c0, 0x186c: 0x00c0, 0x186d: 0x00c0, 0x186e: 0x00c0, 0x186f: 0x00c0,
+	0x1870: 0x00c0, 0x1871: 0x00c0, 0x1872: 0x00c0, 0x1873: 0x00c0, 0x1874: 0x00c0, 0x1875: 0x00c0,
+	0x1876: 0x00c0, 0x1877: 0x00c0, 0x1878: 0x00c0, 0x1879: 0x00c0, 0x187a: 0x00c0, 0x187b: 0x00c0,
+	0x187c: 0x00c0, 0x187d: 0x00c0, 0x187e: 0x0080, 0x187f: 0x0080,
+	// Block 0x62, offset 0x1880
+	0x1880: 0x00c0, 0x1881: 0x00c0, 0x1882: 0x00c0, 0x1883: 0x00c0, 0x1884: 0x00c0, 0x1885: 0x00c0,
+	0x1886: 0x00c0, 0x1887: 0x00c0, 0x1888: 0x00c0,
+	0x1890: 0x00c0, 0x1891: 0x00c0,
+	0x1892: 0x00c0, 0x1893: 0x00c0, 0x1894: 0x00c0, 0x1895: 0x00c0, 0x1896: 0x00c0, 0x1897: 0x00c0,
+	0x1898: 0x00c0, 0x1899: 0x00c0, 0x189a: 0x00c0, 0x189b: 0x00c0, 0x189c: 0x00c0, 0x189d: 0x00c0,
+	0x189e: 0x00c0, 0x189f: 0x00c0, 0x18a0: 0x00c0, 0x18a1: 0x00c0, 0x18a2: 0x00c0, 0x18a3: 0x00c0,
+	0x18a4: 0x00c0, 0x18a5: 0x00c0, 0x18a6: 0x00c0, 0x18a7: 0x00c0, 0x18a8: 0x00c0, 0x18a9: 0x00c0,
+	0x18aa: 0x00c0, 0x18ab: 0x00c0, 0x18ac: 0x00c0, 0x18ad: 0x00c0, 0x18ae: 0x00c0, 0x18af: 0x00c0,
+	0x18b0: 0x00c0, 0x18b1: 0x00c0, 0x18b2: 0x00c0, 0x18b3: 0x00c0, 0x18b4: 0x00c0, 0x18b5: 0x00c0,
+	0x18b6: 0x00c0, 0x18b7: 0x00c0, 0x18b8: 0x00c0, 0x18b9: 0x00c0, 0x18ba: 0x00c0,
+	0x18bd: 0x00c0, 0x18be: 0x00c0, 0x18bf: 0x00c0,
+	// Block 0x63, offset 0x18c0
+	0x18c0: 0x0080, 0x18c1: 0x0080, 0x18c2: 0x0080, 0x18c3: 0x0080, 0x18c4: 0x0080, 0x18c5: 0x0080,
+	0x18c6: 0x0080, 0x18c7: 0x0080,
+	0x18d0: 0x00c3, 0x18d1: 0x00c3,
+	0x18d2: 0x00c3, 0x18d3: 0x0080, 0x18d4: 0x00c3, 0x18d5: 0x00c3, 0x18d6: 0x00c3, 0x18d7: 0x00c3,
+	0x18d8: 0x00c3, 0x18d9: 0x00c3, 0x18da: 0x00c3, 0x18db: 0x00c3, 0x18dc: 0x00c3, 0x18dd: 0x00c3,
+	0x18de: 0x00c3, 0x18df: 0x00c3, 0x18e0: 0x00c3, 0x18e1: 0x00c0, 0x18e2: 0x00c3, 0x18e3: 0x00c3,
+	0x18e4: 0x00c3, 0x18e5: 0x00c3, 0x18e6: 0x00c3, 0x18e7: 0x00c3, 0x18e8: 0x00c3, 0x18e9: 0x00c0,
+	0x18ea: 0x00c0, 0x18eb: 0x00c0, 0x18ec: 0x00c0, 0x18ed: 0x00c3, 0x18ee: 0x00c0, 0x18ef: 0x00c0,
+	0x18f0: 0x00c0, 0x18f1: 0x00c0, 0x18f2: 0x00c0, 0x18f3: 0x00c0, 0x18f4: 0x00c3, 0x18f5: 0x00c0,
+	0x18f6: 0x00c0, 0x18f7: 0x00c0, 0x18f8: 0x00c3, 0x18f9: 0x00c3, 0x18fa: 0x00c0,
+	// Block 0x64, offset 0x1900
+	0x1900: 0x00c0, 0x1901: 0x00c0, 0x1902: 0x00c0, 0x1903: 0x00c0, 0x1904: 0x00c0, 0x1905: 0x00c0,
+	0x1906: 0x00c0, 0x1907: 0x00c0, 0x1908: 0x00c0, 0x1909: 0x00c0, 0x190a: 0x00c0, 0x190b: 0x00c0,
+	0x190c: 0x00c0, 0x190d: 0x00c0, 0x190e: 0x00c0, 0x190f: 0x00c0, 0x1910: 0x00c0, 0x1911: 0x00c0,
+	0x1912: 0x00c0, 0x1913: 0x00c0, 0x1914: 0x00c0, 0x1915: 0x00c0, 0x1916: 0x00c0, 0x1917: 0x00c0,
+	0x1918: 0x00c0, 0x1919: 0x00c0, 0x191a: 0x00c0, 0x191b: 0x00c0, 0x191c: 0x00c0, 0x191d: 0x00c0,
+	0x191e: 0x00c0, 0x191f: 0x00c0, 0x1920: 0x00c0, 0x1921: 0x00c0, 0x1922: 0x00c0, 0x1923: 0x00c0,
+	0x1924: 0x00c0, 0x1925: 0x00c0, 0x1926: 0x00c8, 0x1927: 0x00c8, 0x1928: 0x00c8, 0x1929: 0x00c8,
+	0x192a: 0x00c8, 0x192b: 0x00c0, 0x192c: 0x0080, 0x192d: 0x0080, 0x192e: 0x0080, 0x192f: 0x00c0,
+	0x1930: 0x0080, 0x1931: 0x0080, 0x1932: 0x0080, 0x1933: 0x0080, 0x1934: 0x0080, 0x1935: 0x0080,
+	0x1936: 0x0080, 0x1937: 0x0080, 0x1938: 0x0080, 0x1939: 0x0080, 0x193a: 0x0080, 0x193b: 0x00c0,
+	0x193c: 0x0080, 0x193d: 0x0080, 0x193e: 0x0080, 0x193f: 0x0080,
+	// Block 0x65, offset 0x1940
+	0x1940: 0x0080, 0x1941: 0x0080, 0x1942: 0x0080, 0x1943: 0x0080, 0x1944: 0x0080, 0x1945: 0x0080,
+	0x1946: 0x0080, 0x1947: 0x0080, 0x1948: 0x0080, 0x1949: 0x0080, 0x194a: 0x0080, 0x194b: 0x0080,
+	0x194c: 0x0080, 0x194d: 0x0080, 0x194e: 0x00c0, 0x194f: 0x0080, 0x1950: 0x0080, 0x1951: 0x0080,
+	0x1952: 0x0080, 0x1953: 0x0080, 0x1954: 0x0080, 0x1955: 0x0080, 0x1956: 0x0080, 0x1957: 0x0080,
+	0x1958: 0x0080, 0x1959: 0x0080, 0x195a: 0x0080, 0x195b: 0x0080, 0x195c: 0x0080, 0x195d: 0x0088,
+	0x195e: 0x0088, 0x195f: 0x0088, 0x1960: 0x0088, 0x1961: 0x0088, 0x1962: 0x0080, 0x1963: 0x0080,
+	0x1964: 0x0080, 0x1965: 0x0080, 0x1966: 0x0088, 0x1967: 0x0088, 0x1968: 0x0088, 0x1969: 0x0088,
+	0x196a: 0x0088, 0x196b: 0x00c0, 0x196c: 0x00c0, 0x196d: 0x00c0, 0x196e: 0x00c0, 0x196f: 0x00c0,
+	0x1970: 0x00c0, 0x1971: 0x00c0, 0x1972: 0x00c0, 0x1973: 0x00c0, 0x1974: 0x00c0, 0x1975: 0x00c0,
+	0x1976: 0x00c0, 0x1977: 0x00c0, 0x1978: 0x0080, 0x1979: 0x00c0, 0x197a: 0x00c0, 0x197b: 0x00c0,
+	0x197c: 0x00c0, 0x197d: 0x00c0, 0x197e: 0x00c0, 0x197f: 0x00c0,
+	// Block 0x66, offset 0x1980
+	0x1980: 0x00c0, 0x1981: 0x00c0, 0x1982: 0x00c0, 0x1983: 0x00c0, 0x1984: 0x00c0, 0x1985: 0x00c0,
+	0x1986: 0x00c0, 0x1987: 0x00c0, 0x1988: 0x00c0, 0x1989: 0x00c0, 0x198a: 0x00c0, 0x198b: 0x00c0,
+	0x198c: 0x00c0, 0x198d: 0x00c0, 0x198e: 0x00c0, 0x198f: 0x00c0, 0x1990: 0x00c0, 0x1991: 0x00c0,
+	0x1992: 0x00c0, 0x1993: 0x00c0, 0x1994: 0x00c0, 0x1995: 0x00c0, 0x1996: 0x00c0, 0x1997: 0x00c0,
+	0x1998: 0x00c0, 0x1999: 0x00c0, 0x199a: 0x00c0, 0x199b: 0x0080, 0x199c: 0x0080, 0x199d: 0x0080,
+	0x199e: 0x0080, 0x199f: 0x0080, 0x19a0: 0x0080, 0x19a1: 0x0080, 0x19a2: 0x0080, 0x19a3: 0x0080,
+	0x19a4: 0x0080, 0x19a5: 0x0080, 0x19a6: 0x0080, 0x19a7: 0x0080, 0x19a8: 0x0080, 0x19a9: 0x0080,
+	0x19aa: 0x0080, 0x19ab: 0x0080, 0x19ac: 0x0080, 0x19ad: 0x0080, 0x19ae: 0x0080, 0x19af: 0x0080,
+	0x19b0: 0x0080, 0x19b1: 0x0080, 0x19b2: 0x0080, 0x19b3: 0x0080, 0x19b4: 0x0080, 0x19b5: 0x0080,
+	0x19b6: 0x0080, 0x19b7: 0x0080, 0x19b8: 0x0080, 0x19b9: 0x0080, 0x19ba: 0x0080, 0x19bb: 0x0080,
+	0x19bc: 0x0080, 0x19bd: 0x0080, 0x19be: 0x0080, 0x19bf: 0x0088,
+	// Block 0x67, offset 0x19c0
+	0x19c0: 0x00c0, 0x19c1: 0x00c0, 0x19c2: 0x00c0, 0x19c3: 0x00c0, 0x19c4: 0x00c0, 0x19c5: 0x00c0,
+	0x19c6: 0x00c0, 0x19c7: 0x00c0, 0x19c8: 0x00c0, 0x19c9: 0x00c0, 0x19ca: 0x00c0, 0x19cb: 0x00c0,
+	0x19cc: 0x00c0, 0x19cd: 0x00c0, 0x19ce: 0x00c0, 0x19cf: 0x00c0, 0x19d0: 0x00c0, 0x19d1: 0x00c0,
+	0x19d2: 0x00c0, 0x19d3: 0x00c0, 0x19d4: 0x00c0, 0x19d5: 0x00c0, 0x19d6: 0x00c0, 0x19d7: 0x00c0,
+	0x19d8: 0x00c0, 0x19d9: 0x00c0, 0x19da: 0x0080, 0x19db: 0x0080, 0x19dc: 0x00c0, 0x19dd: 0x00c0,
+	0x19de: 0x00c0, 0x19df: 0x00c0, 0x19e0: 0x00c0, 0x19e1: 0x00c0, 0x19e2: 0x00c0, 0x19e3: 0x00c0,
+	0x19e4: 0x00c0, 0x19e5: 0x00c0, 0x19e6: 0x00c0, 0x19e7: 0x00c0, 0x19e8: 0x00c0, 0x19e9: 0x00c0,
+	0x19ea: 0x00c0, 0x19eb: 0x00c0, 0x19ec: 0x00c0, 0x19ed: 0x00c0, 0x19ee: 0x00c0, 0x19ef: 0x00c0,
+	0x19f0: 0x00c0, 0x19f1: 0x00c0, 0x19f2: 0x00c0, 0x19f3: 0x00c0, 0x19f4: 0x00c0, 0x19f5: 0x00c0,
+	0x19f6: 0x00c0, 0x19f7: 0x00c0, 0x19f8: 0x00c0, 0x19f9: 0x00c0, 0x19fa: 0x00c0, 0x19fb: 0x00c0,
+	0x19fc: 0x00c0, 0x19fd: 0x00c0, 0x19fe: 0x00c0, 0x19ff: 0x00c0,
+	// Block 0x68, offset 0x1a00
+	0x1a00: 0x00c8, 0x1a01: 0x00c8, 0x1a02: 0x00c8, 0x1a03: 0x00c8, 0x1a04: 0x00c8, 0x1a05: 0x00c8,
+	0x1a06: 0x00c8, 0x1a07: 0x00c8, 0x1a08: 0x00c8, 0x1a09: 0x00c8, 0x1a0a: 0x00c8, 0x1a0b: 0x00c8,
+	0x1a0c: 0x00c8, 0x1a0d: 0x00c8, 0x1a0e: 0x00c8, 0x1a0f: 0x00c8, 0x1a10: 0x00c8, 0x1a11: 0x00c8,
+	0x1a12: 0x00c8, 0x1a13: 0x00c8, 0x1a14: 0x00c8, 0x1a15: 0x00c8,
+	0x1a18: 0x00c8, 0x1a19: 0x00c8, 0x1a1a: 0x00c8, 0x1a1b: 0x00c8, 0x1a1c: 0x00c8, 0x1a1d: 0x00c8,
+	0x1a20: 0x00c8, 0x1a21: 0x00c8, 0x1a22: 0x00c8, 0x1a23: 0x00c8,
+	0x1a24: 0x00c8, 0x1a25: 0x00c8, 0x1a26: 0x00c8, 0x1a27: 0x00c8, 0x1a28: 0x00c8, 0x1a29: 0x00c8,
+	0x1a2a: 0x00c8, 0x1a2b: 0x00c8, 0x1a2c: 0x00c8, 0x1a2d: 0x00c8, 0x1a2e: 0x00c8, 0x1a2f: 0x00c8,
+	0x1a30: 0x00c8, 0x1a31: 0x00c8, 0x1a32: 0x00c8, 0x1a33: 0x00c8, 0x1a34: 0x00c8, 0x1a35: 0x00c8,
+	0x1a36: 0x00c8, 0x1a37: 0x00c8, 0x1a38: 0x00c8, 0x1a39: 0x00c8, 0x1a3a: 0x00c8, 0x1a3b: 0x00c8,
+	0x1a3c: 0x00c8, 0x1a3d: 0x00c8, 0x1a3e: 0x00c8, 0x1a3f: 0x00c8,
+	// Block 0x69, offset 0x1a40
+	0x1a40: 0x00c8, 0x1a41: 0x00c8, 0x1a42: 0x00c8, 0x1a43: 0x00c8, 0x1a44: 0x00c8, 0x1a45: 0x00c8,
+	0x1a48: 0x00c8, 0x1a49: 0x00c8, 0x1a4a: 0x00c8, 0x1a4b: 0x00c8,
+	0x1a4c: 0x00c8, 0x1a4d: 0x00c8, 0x1a50: 0x00c8, 0x1a51: 0x00c8,
+	0x1a52: 0x00c8, 0x1a53: 0x00c8, 0x1a54: 0x00c8, 0x1a55: 0x00c8, 0x1a56: 0x00c8, 0x1a57: 0x00c8,
+	0x1a59: 0x00c8, 0x1a5b: 0x00c8, 0x1a5d: 0x00c8,
+	0x1a5f: 0x00c8, 0x1a60: 0x00c8, 0x1a61: 0x00c8, 0x1a62: 0x00c8, 0x1a63: 0x00c8,
+	0x1a64: 0x00c8, 0x1a65: 0x00c8, 0x1a66: 0x00c8, 0x1a67: 0x00c8, 0x1a68: 0x00c8, 0x1a69: 0x00c8,
+	0x1a6a: 0x00c8, 0x1a6b: 0x00c8, 0x1a6c: 0x00c8, 0x1a6d: 0x00c8, 0x1a6e: 0x00c8, 0x1a6f: 0x00c8,
+	0x1a70: 0x00c8, 0x1a71: 0x0088, 0x1a72: 0x00c8, 0x1a73: 0x0088, 0x1a74: 0x00c8, 0x1a75: 0x0088,
+	0x1a76: 0x00c8, 0x1a77: 0x0088, 0x1a78: 0x00c8, 0x1a79: 0x0088, 0x1a7a: 0x00c8, 0x1a7b: 0x0088,
+	0x1a7c: 0x00c8, 0x1a7d: 0x0088,
+	// Block 0x6a, offset 0x1a80
+	0x1a80: 0x00c8, 0x1a81: 0x00c8, 0x1a82: 0x00c8, 0x1a83: 0x00c8, 0x1a84: 0x00c8, 0x1a85: 0x00c8,
+	0x1a86: 0x00c8, 0x1a87: 0x00c8, 0x1a88: 0x0088, 0x1a89: 0x0088, 0x1a8a: 0x0088, 0x1a8b: 0x0088,
+	0x1a8c: 0x0088, 0x1a8d: 0x0088, 0x1a8e: 0x0088, 0x1a8f: 0x0088, 0x1a90: 0x00c8, 0x1a91: 0x00c8,
+	0x1a92: 0x00c8, 0x1a93: 0x00c8, 0x1a94: 0x00c8, 0x1a95: 0x00c8, 0x1a96: 0x00c8, 0x1a97: 0x00c8,
+	0x1a98: 0x0088, 0x1a99: 0x0088, 0x1a9a: 0x0088, 0x1a9b: 0x0088, 0x1a9c: 0x0088, 0x1a9d: 0x0088,
+	0x1a9e: 0x0088, 0x1a9f: 0x0088, 0x1aa0: 0x00c8, 0x1aa1: 0x00c8, 0x1aa2: 0x00c8, 0x1aa3: 0x00c8,
+	0x1aa4: 0x00c8, 0x1aa5: 0x00c8, 0x1aa6: 0x00c8, 0x1aa7: 0x00c8, 0x1aa8: 0x0088, 0x1aa9: 0x0088,
+	0x1aaa: 0x0088, 0x1aab: 0x0088, 0x1aac: 0x0088, 0x1aad: 0x0088, 0x1aae: 0x0088, 0x1aaf: 0x0088,
+	0x1ab0: 0x00c8, 0x1ab1: 0x00c8, 0x1ab2: 0x00c8, 0x1ab3: 0x00c8, 0x1ab4: 0x00c8,
+	0x1ab6: 0x00c8, 0x1ab7: 0x00c8, 0x1ab8: 0x00c8, 0x1ab9: 0x00c8, 0x1aba: 0x00c8, 0x1abb: 0x0088,
+	0x1abc: 0x0088, 0x1abd: 0x0088, 0x1abe: 0x0088, 0x1abf: 0x0088,
+	// Block 0x6b, offset 0x1ac0
+	0x1ac0: 0x0088, 0x1ac1: 0x0088, 0x1ac2: 0x00c8, 0x1ac3: 0x00c8, 0x1ac4: 0x00c8,
+	0x1ac6: 0x00c8, 0x1ac7: 0x00c8, 0x1ac8: 0x00c8, 0x1ac9: 0x0088, 0x1aca: 0x00c8, 0x1acb: 0x0088,
+	0x1acc: 0x0088, 0x1acd: 0x0088, 0x1ace: 0x0088, 0x1acf: 0x0088, 0x1ad0: 0x00c8, 0x1ad1: 0x00c8,
+	0x1ad2: 0x00c8, 0x1ad3: 0x0088, 0x1ad6: 0x00c8, 0x1ad7: 0x00c8,
+	0x1ad8: 0x00c8, 0x1ad9: 0x00c8, 0x1ada: 0x00c8, 0x1adb: 0x0088, 0x1add: 0x0088,
+	0x1ade: 0x0088, 0x1adf: 0x0088, 0x1ae0: 0x00c8, 0x1ae1: 0x00c8, 0x1ae2: 0x00c8, 0x1ae3: 0x0088,
+	0x1ae4: 0x00c8, 0x1ae5: 0x00c8, 0x1ae6: 0x00c8, 0x1ae7: 0x00c8, 0x1ae8: 0x00c8, 0x1ae9: 0x00c8,
+	0x1aea: 0x00c8, 0x1aeb: 0x0088, 0x1aec: 0x00c8, 0x1aed: 0x0088, 0x1aee: 0x0088, 0x1aef: 0x0088,
+	0x1af2: 0x00c8, 0x1af3: 0x00c8, 0x1af4: 0x00c8,
+	0x1af6: 0x00c8, 0x1af7: 0x00c8, 0x1af8: 0x00c8, 0x1af9: 0x0088, 0x1afa: 0x00c8, 0x1afb: 0x0088,
+	0x1afc: 0x0088, 0x1afd: 0x0088, 0x1afe: 0x0088,
+	// Block 0x6c, offset 0x1b00
+	0x1b00: 0x0080, 0x1b01: 0x0080, 0x1b02: 0x0080, 0x1b03: 0x0080, 0x1b04: 0x0080, 0x1b05: 0x0080,
+	0x1b06: 0x0080, 0x1b07: 0x0080, 0x1b08: 0x0080, 0x1b09: 0x0080, 0x1b0a: 0x0080, 0x1b0b: 0x0040,
+	0x1b0c: 0x004d, 0x1b0d: 0x004e, 0x1b0e: 0x0040, 0x1b0f: 0x0040, 0x1b10: 0x0080, 0x1b11: 0x0080,
+	0x1b12: 0x0080, 0x1b13: 0x0080, 0x1b14: 0x0080, 0x1b15: 0x0080, 0x1b16: 0x0080, 0x1b17: 0x0080,
+	0x1b18: 0x0080, 0x1b19: 0x0080, 0x1b1a: 0x0080, 0x1b1b: 0x0080, 0x1b1c: 0x0080, 0x1b1d: 0x0080,
+	0x1b1e: 0x0080, 0x1b1f: 0x0080, 0x1b20: 0x0080, 0x1b21: 0x0080, 0x1b22: 0x0080, 0x1b23: 0x0080,
+	0x1b24: 0x0080, 0x1b25: 0x0080, 0x1b26: 0x0080, 0x1b27: 0x0080, 0x1b28: 0x0040, 0x1b29: 0x0040,
+	0x1b2a: 0x0040, 0x1b2b: 0x0040, 0x1b2c: 0x0040, 0x1b2d: 0x0040, 0x1b2e: 0x0040, 0x1b2f: 0x0080,
+	0x1b30: 0x0080, 0x1b31: 0x0080, 0x1b32: 0x0080, 0x1b33: 0x0080, 0x1b34: 0x0080, 0x1b35: 0x0080,
+	0x1b36: 0x0080, 0x1b37: 0x0080, 0x1b38: 0x0080, 0x1b39: 0x0080, 0x1b3a: 0x0080, 0x1b3b: 0x0080,
+	0x1b3c: 0x0080, 0x1b3d: 0x0080, 0x1b3e: 0x0080, 0x1b3f: 0x0080,
+	// Block 0x6d, offset 0x1b40
+	0x1b40: 0x0080, 0x1b41: 0x0080, 0x1b42: 0x0080, 0x1b43: 0x0080, 0x1b44: 0x0080, 0x1b45: 0x0080,
+	0x1b46: 0x0080, 0x1b47: 0x0080, 0x1b48: 0x0080, 0x1b49: 0x0080, 0x1b4a: 0x0080, 0x1b4b: 0x0080,
+	0x1b4c: 0x0080, 0x1b4d: 0x0080, 0x1b4e: 0x0080, 0x1b4f: 0x0080, 0x1b50: 0x0080, 0x1b51: 0x0080,
+	0x1b52: 0x0080, 0x1b53: 0x0080, 0x1b54: 0x0080, 0x1b55: 0x0080, 0x1b56: 0x0080, 0x1b57: 0x0080,
+	0x1b58: 0x0080, 0x1b59: 0x0080, 0x1b5a: 0x0080, 0x1b5b: 0x0080, 0x1b5c: 0x0080, 0x1b5d: 0x0080,
+	0x1b5e: 0x0080, 0x1b5f: 0x0080, 0x1b60: 0x0040, 0x1b61: 0x0040, 0x1b62: 0x0040, 0x1b63: 0x0040,
+	0x1b64: 0x0040, 0x1b66: 0x0040, 0x1b67: 0x0040, 0x1b68: 0x0040, 0x1b69: 0x0040,
+	0x1b6a: 0x0040, 0x1b6b: 0x0040, 0x1b6c: 0x0040, 0x1b6d: 0x0040, 0x1b6e: 0x0040, 0x1b6f: 0x0040,
+	0x1b70: 0x0080, 0x1b71: 0x0080, 0x1b74: 0x0080, 0x1b75: 0x0080,
+	0x1b76: 0x0080, 0x1b77: 0x0080, 0x1b78: 0x0080, 0x1b79: 0x0080, 0x1b7a: 0x0080, 0x1b7b: 0x0080,
+	0x1b7c: 0x0080, 0x1b7d: 0x0080, 0x1b7e: 0x0080, 0x1b7f: 0x0080,
+	// Block 0x6e, offset 0x1b80
+	0x1b80: 0x0080, 0x1b81: 0x0080, 0x1b82: 0x0080, 0x1b83: 0x0080, 0x1b84: 0x0080, 0x1b85: 0x0080,
+	0x1b86: 0x0080, 0x1b87: 0x0080, 0x1b88: 0x0080, 0x1b89: 0x0080, 0x1b8a: 0x0080, 0x1b8b: 0x0080,
+	0x1b8c: 0x0080, 0x1b8d: 0x0080, 0x1b8e: 0x0080, 0x1b90: 0x0080, 0x1b91: 0x0080,
+	0x1b92: 0x0080, 0x1b93: 0x0080, 0x1b94: 0x0080, 0x1b95: 0x0080, 0x1b96: 0x0080, 0x1b97: 0x0080,
+	0x1b98: 0x0080, 0x1b99: 0x0080, 0x1b9a: 0x0080, 0x1b9b: 0x0080, 0x1b9c: 0x0080,
+	0x1ba0: 0x0080, 0x1ba1: 0x0080, 0x1ba2: 0x0080, 0x1ba3: 0x0080,
+	0x1ba4: 0x0080, 0x1ba5: 0x0080, 0x1ba6: 0x0080, 0x1ba7: 0x0080, 0x1ba8: 0x0080, 0x1ba9: 0x0080,
+	0x1baa: 0x0080, 0x1bab: 0x0080, 0x1bac: 0x0080, 0x1bad: 0x0080, 0x1bae: 0x0080, 0x1baf: 0x0080,
+	0x1bb0: 0x0080, 0x1bb1: 0x0080, 0x1bb2: 0x0080, 0x1bb3: 0x0080, 0x1bb4: 0x0080, 0x1bb5: 0x0080,
+	0x1bb6: 0x0080, 0x1bb7: 0x0080, 0x1bb8: 0x0080, 0x1bb9: 0x0080, 0x1bba: 0x0080, 0x1bbb: 0x0080,
+	0x1bbc: 0x0080, 0x1bbd: 0x0080, 0x1bbe: 0x0080, 0x1bbf: 0x0080,
+	// Block 0x6f, offset 0x1bc0
+	0x1bc0: 0x0080,
+	0x1bd0: 0x00c3, 0x1bd1: 0x00c3,
+	0x1bd2: 0x00c3, 0x1bd3: 0x00c3, 0x1bd4: 0x00c3, 0x1bd5: 0x00c3, 0x1bd6: 0x00c3, 0x1bd7: 0x00c3,
+	0x1bd8: 0x00c3, 0x1bd9: 0x00c3, 0x1bda: 0x00c3, 0x1bdb: 0x00c3, 0x1bdc: 0x00c3, 0x1bdd: 0x0083,
+	0x1bde: 0x0083, 0x1bdf: 0x0083, 0x1be0: 0x0083, 0x1be1: 0x00c3, 0x1be2: 0x0083, 0x1be3: 0x0083,
+	0x1be4: 0x0083, 0x1be5: 0x00c3, 0x1be6: 0x00c3, 0x1be7: 0x00c3, 0x1be8: 0x00c3, 0x1be9: 0x00c3,
+	0x1bea: 0x00c3, 0x1beb: 0x00c3, 0x1bec: 0x00c3, 0x1bed: 0x00c3, 0x1bee: 0x00c3, 0x1bef: 0x00c3,
+	0x1bf0: 0x00c3,
+	// Block 0x70, offset 0x1c00
+	0x1c00: 0x0080, 0x1c01: 0x0080, 0x1c02: 0x0080, 0x1c03: 0x0080, 0x1c04: 0x0080, 0x1c05: 0x0080,
+	0x1c06: 0x0080, 0x1c07: 0x0080, 0x1c08: 0x0080, 0x1c09: 0x0080, 0x1c0a: 0x0080, 0x1c0b: 0x0080,
+	0x1c0c: 0x0080, 0x1c0d: 0x0080, 0x1c0e: 0x0080, 0x1c0f: 0x0080, 0x1c10: 0x0080, 0x1c11: 0x0080,
+	0x1c12: 0x0080, 0x1c13: 0x0080, 0x1c14: 0x0080, 0x1c15: 0x0080, 0x1c16: 0x0080, 0x1c17: 0x0080,
+	0x1c18: 0x0080, 0x1c19: 0x0080, 0x1c1a: 0x0080, 0x1c1b: 0x0080, 0x1c1c: 0x0080, 0x1c1d: 0x0080,
+	0x1c1e: 0x0080, 0x1c1f: 0x0080, 0x1c20: 0x0080, 0x1c21: 0x0080, 0x1c22: 0x0080, 0x1c23: 0x0080,
+	0x1c24: 0x0080, 0x1c25: 0x0080, 0x1c26: 0x0088, 0x1c27: 0x0080, 0x1c28: 0x0080, 0x1c29: 0x0080,
+	0x1c2a: 0x0080, 0x1c2b: 0x0080, 0x1c2c: 0x0080, 0x1c2d: 0x0080, 0x1c2e: 0x0080, 0x1c2f: 0x0080,
+	0x1c30: 0x0080, 0x1c31: 0x0080, 0x1c32: 0x00c0, 0x1c33: 0x0080, 0x1c34: 0x0080, 0x1c35: 0x0080,
+	0x1c36: 0x0080, 0x1c37: 0x0080, 0x1c38: 0x0080, 0x1c39: 0x0080, 0x1c3a: 0x0080, 0x1c3b: 0x0080,
+	0x1c3c: 0x0080, 0x1c3d: 0x0080, 0x1c3e: 0x0080, 0x1c3f: 0x0080,
+	// Block 0x71, offset 0x1c40
+	0x1c40: 0x0080, 0x1c41: 0x0080, 0x1c42: 0x0080, 0x1c43: 0x0080, 0x1c44: 0x0080, 0x1c45: 0x0080,
+	0x1c46: 0x0080, 0x1c47: 0x0080, 0x1c48: 0x0080, 0x1c49: 0x0080, 0x1c4a: 0x0080, 0x1c4b: 0x0080,
+	0x1c4c: 0x0080, 0x1c4d: 0x0080, 0x1c4e: 0x00c0, 0x1c4f: 0x0080, 0x1c50: 0x0080, 0x1c51: 0x0080,
+	0x1c52: 0x0080, 0x1c53: 0x0080, 0x1c54: 0x0080, 0x1c55: 0x0080, 0x1c56: 0x0080, 0x1c57: 0x0080,
+	0x1c58: 0x0080, 0x1c59: 0x0080, 0x1c5a: 0x0080, 0x1c5b: 0x0080, 0x1c5c: 0x0080, 0x1c5d: 0x0080,
+	0x1c5e: 0x0080, 0x1c5f: 0x0080, 0x1c60: 0x0080, 0x1c61: 0x0080, 0x1c62: 0x0080, 0x1c63: 0x0080,
+	0x1c64: 0x0080, 0x1c65: 0x0080, 0x1c66: 0x0080, 0x1c67: 0x0080, 0x1c68: 0x0080, 0x1c69: 0x0080,
+	0x1c6a: 0x0080, 0x1c6b: 0x0080, 0x1c6c: 0x0080, 0x1c6d: 0x0080, 0x1c6e: 0x0080, 0x1c6f: 0x0080,
+	0x1c70: 0x0080, 0x1c71: 0x0080, 0x1c72: 0x0080, 0x1c73: 0x0080, 0x1c74: 0x0080, 0x1c75: 0x0080,
+	0x1c76: 0x0080, 0x1c77: 0x0080, 0x1c78: 0x0080, 0x1c79: 0x0080, 0x1c7a: 0x0080, 0x1c7b: 0x0080,
+	0x1c7c: 0x0080, 0x1c7d: 0x0080, 0x1c7e: 0x0080, 0x1c7f: 0x0080,
+	// Block 0x72, offset 0x1c80
+	0x1c80: 0x0080, 0x1c81: 0x0080, 0x1c82: 0x0080, 0x1c83: 0x00c0, 0x1c84: 0x00c0, 0x1c85: 0x0080,
+	0x1c86: 0x0080, 0x1c87: 0x0080, 0x1c88: 0x0080, 0x1c89: 0x0080, 0x1c8a: 0x0080, 0x1c8b: 0x0080,
+	0x1c90: 0x0080, 0x1c91: 0x0080,
+	0x1c92: 0x0080, 0x1c93: 0x0080, 0x1c94: 0x0080, 0x1c95: 0x0080, 0x1c96: 0x0080, 0x1c97: 0x0080,
+	0x1c98: 0x0080, 0x1c99: 0x0080, 0x1c9a: 0x0080, 0x1c9b: 0x0080, 0x1c9c: 0x0080, 0x1c9d: 0x0080,
+	0x1c9e: 0x0080, 0x1c9f: 0x0080, 0x1ca0: 0x0080, 0x1ca1: 0x0080, 0x1ca2: 0x0080, 0x1ca3: 0x0080,
+	0x1ca4: 0x0080, 0x1ca5: 0x0080, 0x1ca6: 0x0080, 0x1ca7: 0x0080, 0x1ca8: 0x0080, 0x1ca9: 0x0080,
+	0x1caa: 0x0080, 0x1cab: 0x0080, 0x1cac: 0x0080, 0x1cad: 0x0080, 0x1cae: 0x0080, 0x1caf: 0x0080,
+	0x1cb0: 0x0080, 0x1cb1: 0x0080, 0x1cb2: 0x0080, 0x1cb3: 0x0080, 0x1cb4: 0x0080, 0x1cb5: 0x0080,
+	0x1cb6: 0x0080, 0x1cb7: 0x0080, 0x1cb8: 0x0080, 0x1cb9: 0x0080, 0x1cba: 0x0080, 0x1cbb: 0x0080,
+	0x1cbc: 0x0080, 0x1cbd: 0x0080, 0x1cbe: 0x0080, 0x1cbf: 0x0080,
+	// Block 0x73, offset 0x1cc0
+	0x1cc0: 0x0080, 0x1cc1: 0x0080, 0x1cc2: 0x0080, 0x1cc3: 0x0080, 0x1cc4: 0x0080, 0x1cc5: 0x0080,
+	0x1cc6: 0x0080, 0x1cc7: 0x0080, 0x1cc8: 0x0080, 0x1cc9: 0x0080, 0x1cca: 0x0080, 0x1ccb: 0x0080,
+	0x1ccc: 0x0080, 0x1ccd: 0x0080, 0x1cce: 0x0080, 0x1ccf: 0x0080, 0x1cd0: 0x0080, 0x1cd1: 0x0080,
+	0x1cd2: 0x0080, 0x1cd3: 0x0080, 0x1cd4: 0x0080, 0x1cd5: 0x0080, 0x1cd6: 0x0080, 0x1cd7: 0x0080,
+	0x1cd8: 0x0080, 0x1cd9: 0x0080, 0x1cda: 0x0080, 0x1cdb: 0x0080, 0x1cdc: 0x0080, 0x1cdd: 0x0080,
+	0x1cde: 0x0080, 0x1cdf: 0x0080, 0x1ce0: 0x0080, 0x1ce1: 0x0080, 0x1ce2: 0x0080, 0x1ce3: 0x0080,
+	0x1ce4: 0x0080, 0x1ce5: 0x0080, 0x1ce6: 0x0080, 0x1ce7: 0x0080, 0x1ce8: 0x0080, 0x1ce9: 0x0080,
+	0x1cea: 0x0080, 0x1ceb: 0x0080, 0x1cec: 0x0080, 0x1ced: 0x0080, 0x1cee: 0x0080, 0x1cef: 0x0080,
+	0x1cf0: 0x0080, 0x1cf1: 0x0080, 0x1cf2: 0x0080, 0x1cf3: 0x0080, 0x1cf4: 0x0080, 0x1cf5: 0x0080,
+	0x1cf6: 0x0080, 0x1cf7: 0x0080, 0x1cf8: 0x0080, 0x1cf9: 0x0080, 0x1cfa: 0x0080, 0x1cfb: 0x0080,
+	0x1cfc: 0x0080, 0x1cfd: 0x0080, 0x1cfe: 0x0080, 0x1cff: 0x0080,
+	// Block 0x74, offset 0x1d00
+	0x1d00: 0x0080, 0x1d01: 0x0080, 0x1d02: 0x0080, 0x1d03: 0x0080, 0x1d04: 0x0080, 0x1d05: 0x0080,
+	0x1d06: 0x0080, 0x1d07: 0x0080, 0x1d08: 0x0080, 0x1d09: 0x0080, 0x1d0a: 0x0080, 0x1d0b: 0x0080,
+	0x1d0c: 0x0080, 0x1d0d: 0x0080, 0x1d0e: 0x0080, 0x1d0f: 0x0080, 0x1d10: 0x0080, 0x1d11: 0x0080,
+	0x1d12: 0x0080, 0x1d13: 0x0080, 0x1d14: 0x0080, 0x1d15: 0x0080, 0x1d16: 0x0080, 0x1d17: 0x0080,
+	0x1d18: 0x0080, 0x1d19: 0x0080, 0x1d1a: 0x0080, 0x1d1b: 0x0080, 0x1d1c: 0x0080, 0x1d1d: 0x0080,
+	0x1d1e: 0x0080, 0x1d1f: 0x0080, 0x1d20: 0x0080, 0x1d21: 0x0080, 0x1d22: 0x0080, 0x1d23: 0x0080,
+	0x1d24: 0x0080, 0x1d25: 0x0080, 0x1d26: 0x0080,
+	// Block 0x75, offset 0x1d40
+	0x1d40: 0x0080, 0x1d41: 0x0080, 0x1d42: 0x0080, 0x1d43: 0x0080, 0x1d44: 0x0080, 0x1d45: 0x0080,
+	0x1d46: 0x0080, 0x1d47: 0x0080, 0x1d48: 0x0080, 0x1d49: 0x0080, 0x1d4a: 0x0080,
+	0x1d60: 0x0080, 0x1d61: 0x0080, 0x1d62: 0x0080, 0x1d63: 0x0080,
+	0x1d64: 0x0080, 0x1d65: 0x0080, 0x1d66: 0x0080, 0x1d67: 0x0080, 0x1d68: 0x0080, 0x1d69: 0x0080,
+	0x1d6a: 0x0080, 0x1d6b: 0x0080, 0x1d6c: 0x0080, 0x1d6d: 0x0080, 0x1d6e: 0x0080, 0x1d6f: 0x0080,
+	0x1d70: 0x0080, 0x1d71: 0x0080, 0x1d72: 0x0080, 0x1d73: 0x0080, 0x1d74: 0x0080, 0x1d75: 0x0080,
+	0x1d76: 0x0080, 0x1d77: 0x0080, 0x1d78: 0x0080, 0x1d79: 0x0080, 0x1d7a: 0x0080, 0x1d7b: 0x0080,
+	0x1d7c: 0x0080, 0x1d7d: 0x0080, 0x1d7e: 0x0080, 0x1d7f: 0x0080,
+	// Block 0x76, offset 0x1d80
+	0x1d80: 0x0080, 0x1d81: 0x0080, 0x1d82: 0x0080, 0x1d83: 0x0080, 0x1d84: 0x0080, 0x1d85: 0x0080,
+	0x1d86: 0x0080, 0x1d87: 0x0080, 0x1d88: 0x0080, 0x1d89: 0x0080, 0x1d8a: 0x0080, 0x1d8b: 0x0080,
+	0x1d8c: 0x0080, 0x1d8d: 0x0080, 0x1d8e: 0x0080, 0x1d8f: 0x0080, 0x1d90: 0x0080, 0x1d91: 0x0080,
+	0x1d92: 0x0080, 0x1d93: 0x0080, 0x1d94: 0x0080, 0x1d95: 0x0080, 0x1d96: 0x0080, 0x1d97: 0x0080,
+	0x1d98: 0x0080, 0x1d99: 0x0080, 0x1d9a: 0x0080, 0x1d9b: 0x0080, 0x1d9c: 0x0080, 0x1d9d: 0x0080,
+	0x1d9e: 0x0080, 0x1d9f: 0x0080, 0x1da0: 0x0080, 0x1da1: 0x0080, 0x1da2: 0x0080, 0x1da3: 0x0080,
+	0x1da4: 0x0080, 0x1da5: 0x0080, 0x1da6: 0x0080, 0x1da7: 0x0080, 0x1da8: 0x0080, 0x1da9: 0x0080,
+	0x1daa: 0x0080, 0x1dab: 0x0080, 0x1dac: 0x0080, 0x1dad: 0x0080, 0x1dae: 0x0080, 0x1daf: 0x0080,
+	0x1db0: 0x0080, 0x1db1: 0x0080, 0x1db2: 0x0080, 0x1db3: 0x0080,
+	0x1db6: 0x0080, 0x1db7: 0x0080, 0x1db8: 0x0080, 0x1db9: 0x0080, 0x1dba: 0x0080, 0x1dbb: 0x0080,
+	0x1dbc: 0x0080, 0x1dbd: 0x0080, 0x1dbe: 0x0080, 0x1dbf: 0x0080,
+	// Block 0x77, offset 0x1dc0
+	0x1dc0: 0x0080, 0x1dc1: 0x0080, 0x1dc2: 0x0080, 0x1dc3: 0x0080, 0x1dc4: 0x0080, 0x1dc5: 0x0080,
+	0x1dc6: 0x0080, 0x1dc7: 0x0080, 0x1dc8: 0x0080, 0x1dc9: 0x0080, 0x1dca: 0x0080, 0x1dcb: 0x0080,
+	0x1dcc: 0x0080, 0x1dcd: 0x0080, 0x1dce: 0x0080, 0x1dcf: 0x0080, 0x1dd0: 0x0080, 0x1dd1: 0x0080,
+	0x1dd2: 0x0080, 0x1dd3: 0x0080, 0x1dd4: 0x0080, 0x1dd5: 0x0080, 0x1dd7: 0x0080,
+	0x1dd8: 0x0080, 0x1dd9: 0x0080, 0x1dda: 0x0080, 0x1ddb: 0x0080, 0x1ddc: 0x0080, 0x1ddd: 0x0080,
+	0x1dde: 0x0080, 0x1ddf: 0x0080, 0x1de0: 0x0080, 0x1de1: 0x0080, 0x1de2: 0x0080, 0x1de3: 0x0080,
+	0x1de4: 0x0080, 0x1de5: 0x0080, 0x1de6: 0x0080, 0x1de7: 0x0080, 0x1de8: 0x0080, 0x1de9: 0x0080,
+	0x1dea: 0x0080, 0x1deb: 0x0080, 0x1dec: 0x0080, 0x1ded: 0x0080, 0x1dee: 0x0080, 0x1def: 0x0080,
+	0x1df0: 0x0080, 0x1df1: 0x0080, 0x1df2: 0x0080, 0x1df3: 0x0080, 0x1df4: 0x0080, 0x1df5: 0x0080,
+	0x1df6: 0x0080, 0x1df7: 0x0080, 0x1df8: 0x0080, 0x1df9: 0x0080, 0x1dfa: 0x0080, 0x1dfb: 0x0080,
+	0x1dfc: 0x0080, 0x1dfd: 0x0080, 0x1dfe: 0x0080, 0x1dff: 0x0080,
+	// Block 0x78, offset 0x1e00
+	0x1e00: 0x00c0, 0x1e01: 0x00c0, 0x1e02: 0x00c0, 0x1e03: 0x00c0, 0x1e04: 0x00c0, 0x1e05: 0x00c0,
+	0x1e06: 0x00c0, 0x1e07: 0x00c0, 0x1e08: 0x00c0, 0x1e09: 0x00c0, 0x1e0a: 0x00c0, 0x1e0b: 0x00c0,
+	0x1e0c: 0x00c0, 0x1e0d: 0x00c0, 0x1e0e: 0x00c0, 0x1e0f: 0x00c0, 0x1e10: 0x00c0, 0x1e11: 0x00c0,
+	0x1e12: 0x00c0, 0x1e13: 0x00c0, 0x1e14: 0x00c0, 0x1e15: 0x00c0, 0x1e16: 0x00c0, 0x1e17: 0x00c0,
+	0x1e18: 0x00c0, 0x1e19: 0x00c0, 0x1e1a: 0x00c0, 0x1e1b: 0x00c0, 0x1e1c: 0x00c0, 0x1e1d: 0x00c0,
+	0x1e1e: 0x00c0, 0x1e1f: 0x00c0, 0x1e20: 0x00c0, 0x1e21: 0x00c0, 0x1e22: 0x00c0, 0x1e23: 0x00c0,
+	0x1e24: 0x00c0, 0x1e25: 0x00c0, 0x1e26: 0x00c0, 0x1e27: 0x00c0, 0x1e28: 0x00c0, 0x1e29: 0x00c0,
+	0x1e2a: 0x00c0, 0x1e2b: 0x00c0, 0x1e2c: 0x00c0, 0x1e2d: 0x00c0, 0x1e2e: 0x00c0, 0x1e2f: 0x00c0,
+	0x1e30: 0x00c0, 0x1e31: 0x00c0, 0x1e32: 0x00c0, 0x1e33: 0x00c0, 0x1e34: 0x00c0, 0x1e35: 0x00c0,
+	0x1e36: 0x00c0, 0x1e37: 0x00c0, 0x1e38: 0x00c0, 0x1e39: 0x00c0, 0x1e3a: 0x00c0, 0x1e3b: 0x00c0,
+	0x1e3c: 0x0080, 0x1e3d: 0x0080, 0x1e3e: 0x00c0, 0x1e3f: 0x00c0,
+	// Block 0x79, offset 0x1e40
+	0x1e40: 0x00c0, 0x1e41: 0x00c0, 0x1e42: 0x00c0, 0x1e43: 0x00c0, 0x1e44: 0x00c0, 0x1e45: 0x00c0,
+	0x1e46: 0x00c0, 0x1e47: 0x00c0, 0x1e48: 0x00c0, 0x1e49: 0x00c0, 0x1e4a: 0x00c0, 0x1e4b: 0x00c0,
+	0x1e4c: 0x00c0, 0x1e4d: 0x00c0, 0x1e4e: 0x00c0, 0x1e4f: 0x00c0, 0x1e50: 0x00c0, 0x1e51: 0x00c0,
+	0x1e52: 0x00c0, 0x1e53: 0x00c0, 0x1e54: 0x00c0, 0x1e55: 0x00c0, 0x1e56: 0x00c0, 0x1e57: 0x00c0,
+	0x1e58: 0x00c0, 0x1e59: 0x00c0, 0x1e5a: 0x00c0, 0x1e5b: 0x00c0, 0x1e5c: 0x00c0, 0x1e5d: 0x00c0,
+	0x1e5e: 0x00c0, 0x1e5f: 0x00c0, 0x1e60: 0x00c0, 0x1e61: 0x00c0, 0x1e62: 0x00c0, 0x1e63: 0x00c0,
+	0x1e64: 0x00c0, 0x1e65: 0x0080, 0x1e66: 0x0080, 0x1e67: 0x0080, 0x1e68: 0x0080, 0x1e69: 0x0080,
+	0x1e6a: 0x0080, 0x1e6b: 0x00c0, 0x1e6c: 0x00c0, 0x1e6d: 0x00c0, 0x1e6e: 0x00c0, 0x1e6f: 0x00c3,
+	0x1e70: 0x00c3, 0x1e71: 0x00c3, 0x1e72: 0x00c0, 0x1e73: 0x00c0,
+	0x1e79: 0x0080, 0x1e7a: 0x0080, 0x1e7b: 0x0080,
+	0x1e7c: 0x0080, 0x1e7d: 0x0080, 0x1e7e: 0x0080, 0x1e7f: 0x0080,
+	// Block 0x7a, offset 0x1e80
+	0x1e80: 0x00c0, 0x1e81: 0x00c0, 0x1e82: 0x00c0, 0x1e83: 0x00c0, 0x1e84: 0x00c0, 0x1e85: 0x00c0,
+	0x1e86: 0x00c0, 0x1e87: 0x00c0, 0x1e88: 0x00c0, 0x1e89: 0x00c0, 0x1e8a: 0x00c0, 0x1e8b: 0x00c0,
+	0x1e8c: 0x00c0, 0x1e8d: 0x00c0, 0x1e8e: 0x00c0, 0x1e8f: 0x00c0, 0x1e90: 0x00c0, 0x1e91: 0x00c0,
+	0x1e92: 0x00c0, 0x1e93: 0x00c0, 0x1e94: 0x00c0, 0x1e95: 0x00c0, 0x1e96: 0x00c0, 0x1e97: 0x00c0,
+	0x1e98: 0x00c0, 0x1e99: 0x00c0, 0x1e9a: 0x00c0, 0x1e9b: 0x00c0, 0x1e9c: 0x00c0, 0x1e9d: 0x00c0,
+	0x1e9e: 0x00c0, 0x1e9f: 0x00c0, 0x1ea0: 0x00c0, 0x1ea1: 0x00c0, 0x1ea2: 0x00c0, 0x1ea3: 0x00c0,
+	0x1ea4: 0x00c0, 0x1ea5: 0x00c0, 0x1ea7: 0x00c0,
+	0x1ead: 0x00c0,
+	0x1eb0: 0x00c0, 0x1eb1: 0x00c0, 0x1eb2: 0x00c0, 0x1eb3: 0x00c0, 0x1eb4: 0x00c0, 0x1eb5: 0x00c0,
+	0x1eb6: 0x00c0, 0x1eb7: 0x00c0, 0x1eb8: 0x00c0, 0x1eb9: 0x00c0, 0x1eba: 0x00c0, 0x1ebb: 0x00c0,
+	0x1ebc: 0x00c0, 0x1ebd: 0x00c0, 0x1ebe: 0x00c0, 0x1ebf: 0x00c0,
+	// Block 0x7b, offset 0x1ec0
+	0x1ec0: 0x00c0, 0x1ec1: 0x00c0, 0x1ec2: 0x00c0, 0x1ec3: 0x00c0, 0x1ec4: 0x00c0, 0x1ec5: 0x00c0,
+	0x1ec6: 0x00c0, 0x1ec7: 0x00c0, 0x1ec8: 0x00c0, 0x1ec9: 0x00c0, 0x1eca: 0x00c0, 0x1ecb: 0x00c0,
+	0x1ecc: 0x00c0, 0x1ecd: 0x00c0, 0x1ece: 0x00c0, 0x1ecf: 0x00c0, 0x1ed0: 0x00c0, 0x1ed1: 0x00c0,
+	0x1ed2: 0x00c0, 0x1ed3: 0x00c0, 0x1ed4: 0x00c0, 0x1ed5: 0x00c0, 0x1ed6: 0x00c0, 0x1ed7: 0x00c0,
+	0x1ed8: 0x00c0, 0x1ed9: 0x00c0, 0x1eda: 0x00c0, 0x1edb: 0x00c0, 0x1edc: 0x00c0, 0x1edd: 0x00c0,
+	0x1ede: 0x00c0, 0x1edf: 0x00c0, 0x1ee0: 0x00c0, 0x1ee1: 0x00c0, 0x1ee2: 0x00c0, 0x1ee3: 0x00c0,
+	0x1ee4: 0x00c0, 0x1ee5: 0x00c0, 0x1ee6: 0x00c0, 0x1ee7: 0x00c0,
+	0x1eef: 0x0080,
+	0x1ef0: 0x0080,
+	0x1eff: 0x00c6,
+	// Block 0x7c, offset 0x1f00
+	0x1f00: 0x00c0, 0x1f01: 0x00c0, 0x1f02: 0x00c0, 0x1f03: 0x00c0, 0x1f04: 0x00c0, 0x1f05: 0x00c0,
+	0x1f06: 0x00c0, 0x1f07: 0x00c0, 0x1f08: 0x00c0, 0x1f09: 0x00c0, 0x1f0a: 0x00c0, 0x1f0b: 0x00c0,
+	0x1f0c: 0x00c0, 0x1f0d: 0x00c0, 0x1f0e: 0x00c0, 0x1f0f: 0x00c0, 0x1f10: 0x00c0, 0x1f11: 0x00c0,
+	0x1f12: 0x00c0, 0x1f13: 0x00c0, 0x1f14: 0x00c0, 0x1f15: 0x00c0, 0x1f16: 0x00c0,
+	0x1f20: 0x00c0, 0x1f21: 0x00c0, 0x1f22: 0x00c0, 0x1f23: 0x00c0,
+	0x1f24: 0x00c0, 0x1f25: 0x00c0, 0x1f26: 0x00c0, 0x1f28: 0x00c0, 0x1f29: 0x00c0,
+	0x1f2a: 0x00c0, 0x1f2b: 0x00c0, 0x1f2c: 0x00c0, 0x1f2d: 0x00c0, 0x1f2e: 0x00c0,
+	0x1f30: 0x00c0, 0x1f31: 0x00c0, 0x1f32: 0x00c0, 0x1f33: 0x00c0, 0x1f34: 0x00c0, 0x1f35: 0x00c0,
+	0x1f36: 0x00c0, 0x1f38: 0x00c0, 0x1f39: 0x00c0, 0x1f3a: 0x00c0, 0x1f3b: 0x00c0,
+	0x1f3c: 0x00c0, 0x1f3d: 0x00c0, 0x1f3e: 0x00c0,
+	// Block 0x7d, offset 0x1f40
+	0x1f40: 0x00c0, 0x1f41: 0x00c0, 0x1f42: 0x00c0, 0x1f43: 0x00c0, 0x1f44: 0x00c0, 0x1f45: 0x00c0,
+	0x1f46: 0x00c0, 0x1f48: 0x00c0, 0x1f49: 0x00c0, 0x1f4a: 0x00c0, 0x1f4b: 0x00c0,
+	0x1f4c: 0x00c0, 0x1f4d: 0x00c0, 0x1f4e: 0x00c0, 0x1f50: 0x00c0, 0x1f51: 0x00c0,
+	0x1f52: 0x00c0, 0x1f53: 0x00c0, 0x1f54: 0x00c0, 0x1f55: 0x00c0, 0x1f56: 0x00c0,
+	0x1f58: 0x00c0, 0x1f59: 0x00c0, 0x1f5a: 0x00c0, 0x1f5b: 0x00c0, 0x1f5c: 0x00c0, 0x1f5d: 0x00c0,
+	0x1f5e: 0x00c0, 0x1f60: 0x00c3, 0x1f61: 0x00c3, 0x1f62: 0x00c3, 0x1f63: 0x00c3,
+	0x1f64: 0x00c3, 0x1f65: 0x00c3, 0x1f66: 0x00c3, 0x1f67: 0x00c3, 0x1f68: 0x00c3, 0x1f69: 0x00c3,
+	0x1f6a: 0x00c3, 0x1f6b: 0x00c3, 0x1f6c: 0x00c3, 0x1f6d: 0x00c3, 0x1f6e: 0x00c3, 0x1f6f: 0x00c3,
+	0x1f70: 0x00c3, 0x1f71: 0x00c3, 0x1f72: 0x00c3, 0x1f73: 0x00c3, 0x1f74: 0x00c3, 0x1f75: 0x00c3,
+	0x1f76: 0x00c3, 0x1f77: 0x00c3, 0x1f78: 0x00c3, 0x1f79: 0x00c3, 0x1f7a: 0x00c3, 0x1f7b: 0x00c3,
+	0x1f7c: 0x00c3, 0x1f7d: 0x00c3, 0x1f7e: 0x00c3, 0x1f7f: 0x00c3,
+	// Block 0x7e, offset 0x1f80
+	0x1f80: 0x0080, 0x1f81: 0x0080, 0x1f82: 0x0080, 0x1f83: 0x0080, 0x1f84: 0x0080, 0x1f85: 0x0080,
+	0x1f86: 0x0080, 0x1f87: 0x0080, 0x1f88: 0x0080, 0x1f89: 0x0080, 0x1f8a: 0x0080, 0x1f8b: 0x0080,
+	0x1f8c: 0x0080, 0x1f8d: 0x0080, 0x1f8e: 0x0080, 0x1f8f: 0x0080, 0x1f90: 0x0080, 0x1f91: 0x0080,
+	0x1f92: 0x0080, 0x1f93: 0x0080, 0x1f94: 0x0080, 0x1f95: 0x0080, 0x1f96: 0x0080, 0x1f97: 0x0080,
+	0x1f98: 0x0080, 0x1f99: 0x0080, 0x1f9a: 0x0080, 0x1f9b: 0x0080, 0x1f9c: 0x0080, 0x1f9d: 0x0080,
+	0x1f9e: 0x0080, 0x1f9f: 0x0080, 0x1fa0: 0x0080, 0x1fa1: 0x0080, 0x1fa2: 0x0080, 0x1fa3: 0x0080,
+	0x1fa4: 0x0080, 0x1fa5: 0x0080, 0x1fa6: 0x0080, 0x1fa7: 0x0080, 0x1fa8: 0x0080, 0x1fa9: 0x0080,
+	0x1faa: 0x0080, 0x1fab: 0x0080, 0x1fac: 0x0080, 0x1fad: 0x0080, 0x1fae: 0x0080, 0x1faf: 0x00c0,
+	0x1fb0: 0x0080, 0x1fb1: 0x0080, 0x1fb2: 0x0080, 0x1fb3: 0x0080, 0x1fb4: 0x0080, 0x1fb5: 0x0080,
+	0x1fb6: 0x0080, 0x1fb7: 0x0080, 0x1fb8: 0x0080, 0x1fb9: 0x0080, 0x1fba: 0x0080, 0x1fbb: 0x0080,
+	0x1fbc: 0x0080, 0x1fbd: 0x0080, 0x1fbe: 0x0080, 0x1fbf: 0x0080,
+	// Block 0x7f, offset 0x1fc0
+	0x1fc0: 0x0080, 0x1fc1: 0x0080, 0x1fc2: 0x0080, 0x1fc3: 0x0080, 0x1fc4: 0x0080, 0x1fc5: 0x0080,
+	0x1fc6: 0x0080, 0x1fc7: 0x0080, 0x1fc8: 0x0080, 0x1fc9: 0x0080, 0x1fca: 0x0080, 0x1fcb: 0x0080,
+	0x1fcc: 0x0080, 0x1fcd: 0x0080, 0x1fce: 0x0080, 0x1fcf: 0x0080, 0x1fd0: 0x0080, 0x1fd1: 0x0080,
+	0x1fd2: 0x0080, 0x1fd3: 0x0080, 0x1fd4: 0x0080, 0x1fd5: 0x0080, 0x1fd6: 0x0080, 0x1fd7: 0x0080,
+	0x1fd8: 0x0080, 0x1fd9: 0x0080, 0x1fda: 0x0080, 0x1fdb: 0x0080, 0x1fdc: 0x0080, 0x1fdd: 0x0080,
+	// Block 0x80, offset 0x2000
+	0x2000: 0x008c, 0x2001: 0x008c, 0x2002: 0x008c, 0x2003: 0x008c, 0x2004: 0x008c, 0x2005: 0x008c,
+	0x2006: 0x008c, 0x2007: 0x008c, 0x2008: 0x008c, 0x2009: 0x008c, 0x200a: 0x008c, 0x200b: 0x008c,
+	0x200c: 0x008c, 0x200d: 0x008c, 0x200e: 0x008c, 0x200f: 0x008c, 0x2010: 0x008c, 0x2011: 0x008c,
+	0x2012: 0x008c, 0x2013: 0x008c, 0x2014: 0x008c, 0x2015: 0x008c, 0x2016: 0x008c, 0x2017: 0x008c,
+	0x2018: 0x008c, 0x2019: 0x008c, 0x201b: 0x008c, 0x201c: 0x008c, 0x201d: 0x008c,
+	0x201e: 0x008c, 0x201f: 0x008c, 0x2020: 0x008c, 0x2021: 0x008c, 0x2022: 0x008c, 0x2023: 0x008c,
+	0x2024: 0x008c, 0x2025: 0x008c, 0x2026: 0x008c, 0x2027: 0x008c, 0x2028: 0x008c, 0x2029: 0x008c,
+	0x202a: 0x008c, 0x202b: 0x008c, 0x202c: 0x008c, 0x202d: 0x008c, 0x202e: 0x008c, 0x202f: 0x008c,
+	0x2030: 0x008c, 0x2031: 0x008c, 0x2032: 0x008c, 0x2033: 0x008c, 0x2034: 0x008c, 0x2035: 0x008c,
+	0x2036: 0x008c, 0x2037: 0x008c, 0x2038: 0x008c, 0x2039: 0x008c, 0x203a: 0x008c, 0x203b: 0x008c,
+	0x203c: 0x008c, 0x203d: 0x008c, 0x203e: 0x008c, 0x203f: 0x008c,
+	// Block 0x81, offset 0x2040
+	0x2040: 0x008c, 0x2041: 0x008c, 0x2042: 0x008c, 0x2043: 0x008c, 0x2044: 0x008c, 0x2045: 0x008c,
+	0x2046: 0x008c, 0x2047: 0x008c, 0x2048: 0x008c, 0x2049: 0x008c, 0x204a: 0x008c, 0x204b: 0x008c,
+	0x204c: 0x008c, 0x204d: 0x008c, 0x204e: 0x008c, 0x204f: 0x008c, 0x2050: 0x008c, 0x2051: 0x008c,
+	0x2052: 0x008c, 0x2053: 0x008c, 0x2054: 0x008c, 0x2055: 0x008c, 0x2056: 0x008c, 0x2057: 0x008c,
+	0x2058: 0x008c, 0x2059: 0x008c, 0x205a: 0x008c, 0x205b: 0x008c, 0x205c: 0x008c, 0x205d: 0x008c,
+	0x205e: 0x008c, 0x205f: 0x008c, 0x2060: 0x008c, 0x2061: 0x008c, 0x2062: 0x008c, 0x2063: 0x008c,
+	0x2064: 0x008c, 0x2065: 0x008c, 0x2066: 0x008c, 0x2067: 0x008c, 0x2068: 0x008c, 0x2069: 0x008c,
+	0x206a: 0x008c, 0x206b: 0x008c, 0x206c: 0x008c, 0x206d: 0x008c, 0x206e: 0x008c, 0x206f: 0x008c,
+	0x2070: 0x008c, 0x2071: 0x008c, 0x2072: 0x008c, 0x2073: 0x008c,
+	// Block 0x82, offset 0x2080
+	0x2080: 0x008c, 0x2081: 0x008c, 0x2082: 0x008c, 0x2083: 0x008c, 0x2084: 0x008c, 0x2085: 0x008c,
+	0x2086: 0x008c, 0x2087: 0x008c, 0x2088: 0x008c, 0x2089: 0x008c, 0x208a: 0x008c, 0x208b: 0x008c,
+	0x208c: 0x008c, 0x208d: 0x008c, 0x208e: 0x008c, 0x208f: 0x008c, 0x2090: 0x008c, 0x2091: 0x008c,
+	0x2092: 0x008c, 0x2093: 0x008c, 0x2094: 0x008c, 0x2095: 0x008c, 0x2096: 0x008c, 0x2097: 0x008c,
+	0x2098: 0x008c, 0x2099: 0x008c, 0x209a: 0x008c, 0x209b: 0x008c, 0x209c: 0x008c, 0x209d: 0x008c,
+	0x209e: 0x008c, 0x209f: 0x008c, 0x20a0: 0x008c, 0x20a1: 0x008c, 0x20a2: 0x008c, 0x20a3: 0x008c,
+	0x20a4: 0x008c, 0x20a5: 0x008c, 0x20a6: 0x008c, 0x20a7: 0x008c, 0x20a8: 0x008c, 0x20a9: 0x008c,
+	0x20aa: 0x008c, 0x20ab: 0x008c, 0x20ac: 0x008c, 0x20ad: 0x008c, 0x20ae: 0x008c, 0x20af: 0x008c,
+	0x20b0: 0x008c, 0x20b1: 0x008c, 0x20b2: 0x008c, 0x20b3: 0x008c, 0x20b4: 0x008c, 0x20b5: 0x008c,
+	0x20b6: 0x008c, 0x20b7: 0x008c, 0x20b8: 0x008c, 0x20b9: 0x008c, 0x20ba: 0x008c, 0x20bb: 0x008c,
+	0x20bc: 0x008c, 0x20bd: 0x008c, 0x20be: 0x008c, 0x20bf: 0x008c,
+	// Block 0x83, offset 0x20c0
+	0x20c0: 0x008c, 0x20c1: 0x008c, 0x20c2: 0x008c, 0x20c3: 0x008c, 0x20c4: 0x008c, 0x20c5: 0x008c,
+	0x20c6: 0x008c, 0x20c7: 0x008c, 0x20c8: 0x008c, 0x20c9: 0x008c, 0x20ca: 0x008c, 0x20cb: 0x008c,
+	0x20cc: 0x008c, 0x20cd: 0x008c, 0x20ce: 0x008c, 0x20cf: 0x008c, 0x20d0: 0x008c, 0x20d1: 0x008c,
+	0x20d2: 0x008c, 0x20d3: 0x008c, 0x20d4: 0x008c, 0x20d5: 0x008c,
+	0x20f0: 0x0080, 0x20f1: 0x0080, 0x20f2: 0x0080, 0x20f3: 0x0080, 0x20f4: 0x0080, 0x20f5: 0x0080,
+	0x20f6: 0x0080, 0x20f7: 0x0080, 0x20f8: 0x0080, 0x20f9: 0x0080, 0x20fa: 0x0080, 0x20fb: 0x0080,
+	// Block 0x84, offset 0x2100
+	0x2100: 0x0080, 0x2101: 0x0080, 0x2102: 0x0080, 0x2103: 0x0080, 0x2104: 0x0080, 0x2105: 0x00cc,
+	0x2106: 0x00c0, 0x2107: 0x00cc, 0x2108: 0x0080, 0x2109: 0x0080, 0x210a: 0x0080, 0x210b: 0x0080,
+	0x210c: 0x0080, 0x210d: 0x0080, 0x210e: 0x0080, 0x210f: 0x0080, 0x2110: 0x0080, 0x2111: 0x0080,
+	0x2112: 0x0080, 0x2113: 0x0080, 0x2114: 0x0080, 0x2115: 0x0080, 0x2116: 0x0080, 0x2117: 0x0080,
+	0x2118: 0x0080, 0x2119: 0x0080, 0x211a: 0x0080, 0x211b: 0x0080, 0x211c: 0x0080, 0x211d: 0x0080,
+	0x211e: 0x0080, 0x211f: 0x0080, 0x2120: 0x0080, 0x2121: 0x008c, 0x2122: 0x008c, 0x2123: 0x008c,
+	0x2124: 0x008c, 0x2125: 0x008c, 0x2126: 0x008c, 0x2127: 0x008c, 0x2128: 0x008c, 0x2129: 0x008c,
+	0x212a: 0x00c3, 0x212b: 0x00c3, 0x212c: 0x00c3, 0x212d: 0x00c3, 0x212e: 0x0040, 0x212f: 0x0040,
+	0x2130: 0x0080, 0x2131: 0x0040, 0x2132: 0x0040, 0x2133: 0x0040, 0x2134: 0x0040, 0x2135: 0x0040,
+	0x2136: 0x0080, 0x2137: 0x0080, 0x2138: 0x008c, 0x2139: 0x008c, 0x213a: 0x008c, 0x213b: 0x0040,
+	0x213c: 0x00c0, 0x213d: 0x0080, 0x213e: 0x0080, 0x213f: 0x0080,
+	// Block 0x85, offset 0x2140
+	0x2141: 0x00cc, 0x2142: 0x00cc, 0x2143: 0x00cc, 0x2144: 0x00cc, 0x2145: 0x00cc,
+	0x2146: 0x00cc, 0x2147: 0x00cc, 0x2148: 0x00cc, 0x2149: 0x00cc, 0x214a: 0x00cc, 0x214b: 0x00cc,
+	0x214c: 0x00cc, 0x214d: 0x00cc, 0x214e: 0x00cc, 0x214f: 0x00cc, 0x2150: 0x00cc, 0x2151: 0x00cc,
+	0x2152: 0x00cc, 0x2153: 0x00cc, 0x2154: 0x00cc, 0x2155: 0x00cc, 0x2156: 0x00cc, 0x2157: 0x00cc,
+	0x2158: 0x00cc, 0x2159: 0x00cc, 0x215a: 0x00cc, 0x215b: 0x00cc, 0x215c: 0x00cc, 0x215d: 0x00cc,
+	0x215e: 0x00cc, 0x215f: 0x00cc, 0x2160: 0x00cc, 0x2161: 0x00cc, 0x2162: 0x00cc, 0x2163: 0x00cc,
+	0x2164: 0x00cc, 0x2165: 0x00cc, 0x2166: 0x00cc, 0x2167: 0x00cc, 0x2168: 0x00cc, 0x2169: 0x00cc,
+	0x216a: 0x00cc, 0x216b: 0x00cc, 0x216c: 0x00cc, 0x216d: 0x00cc, 0x216e: 0x00cc, 0x216f: 0x00cc,
+	0x2170: 0x00cc, 0x2171: 0x00cc, 0x2172: 0x00cc, 0x2173: 0x00cc, 0x2174: 0x00cc, 0x2175: 0x00cc,
+	0x2176: 0x00cc, 0x2177: 0x00cc, 0x2178: 0x00cc, 0x2179: 0x00cc, 0x217a: 0x00cc, 0x217b: 0x00cc,
+	0x217c: 0x00cc, 0x217d: 0x00cc, 0x217e: 0x00cc, 0x217f: 0x00cc,
+	// Block 0x86, offset 0x2180
+	0x2180: 0x00cc, 0x2181: 0x00cc, 0x2182: 0x00cc, 0x2183: 0x00cc, 0x2184: 0x00cc, 0x2185: 0x00cc,
+	0x2186: 0x00cc, 0x2187: 0x00cc, 0x2188: 0x00cc, 0x2189: 0x00cc, 0x218a: 0x00cc, 0x218b: 0x00cc,
+	0x218c: 0x00cc, 0x218d: 0x00cc, 0x218e: 0x00cc, 0x218f: 0x00cc, 0x2190: 0x00cc, 0x2191: 0x00cc,
+	0x2192: 0x00cc, 0x2193: 0x00cc, 0x2194: 0x00cc, 0x2195: 0x00cc, 0x2196: 0x00cc,
+	0x2199: 0x00c3, 0x219a: 0x00c3, 0x219b: 0x0080, 0x219c: 0x0080, 0x219d: 0x00cc,
+	0x219e: 0x00cc, 0x219f: 0x008c, 0x21a0: 0x0080, 0x21a1: 0x00cc, 0x21a2: 0x00cc, 0x21a3: 0x00cc,
+	0x21a4: 0x00cc, 0x21a5: 0x00cc, 0x21a6: 0x00cc, 0x21a7: 0x00cc, 0x21a8: 0x00cc, 0x21a9: 0x00cc,
+	0x21aa: 0x00cc, 0x21ab: 0x00cc, 0x21ac: 0x00cc, 0x21ad: 0x00cc, 0x21ae: 0x00cc, 0x21af: 0x00cc,
+	0x21b0: 0x00cc, 0x21b1: 0x00cc, 0x21b2: 0x00cc, 0x21b3: 0x00cc, 0x21b4: 0x00cc, 0x21b5: 0x00cc,
+	0x21b6: 0x00cc, 0x21b7: 0x00cc, 0x21b8: 0x00cc, 0x21b9: 0x00cc, 0x21ba: 0x00cc, 0x21bb: 0x00cc,
+	0x21bc: 0x00cc, 0x21bd: 0x00cc, 0x21be: 0x00cc, 0x21bf: 0x00cc,
+	// Block 0x87, offset 0x21c0
+	0x21c0: 0x00cc, 0x21c1: 0x00cc, 0x21c2: 0x00cc, 0x21c3: 0x00cc, 0x21c4: 0x00cc, 0x21c5: 0x00cc,
+	0x21c6: 0x00cc, 0x21c7: 0x00cc, 0x21c8: 0x00cc, 0x21c9: 0x00cc, 0x21ca: 0x00cc, 0x21cb: 0x00cc,
+	0x21cc: 0x00cc, 0x21cd: 0x00cc, 0x21ce: 0x00cc, 0x21cf: 0x00cc, 0x21d0: 0x00cc, 0x21d1: 0x00cc,
+	0x21d2: 0x00cc, 0x21d3: 0x00cc, 0x21d4: 0x00cc, 0x21d5: 0x00cc, 0x21d6: 0x00cc, 0x21d7: 0x00cc,
+	0x21d8: 0x00cc, 0x21d9: 0x00cc, 0x21da: 0x00cc, 0x21db: 0x00cc, 0x21dc: 0x00cc, 0x21dd: 0x00cc,
+	0x21de: 0x00cc, 0x21df: 0x00cc, 0x21e0: 0x00cc, 0x21e1: 0x00cc, 0x21e2: 0x00cc, 0x21e3: 0x00cc,
+	0x21e4: 0x00cc, 0x21e5: 0x00cc, 0x21e6: 0x00cc, 0x21e7: 0x00cc, 0x21e8: 0x00cc, 0x21e9: 0x00cc,
+	0x21ea: 0x00cc, 0x21eb: 0x00cc, 0x21ec: 0x00cc, 0x21ed: 0x00cc, 0x21ee: 0x00cc, 0x21ef: 0x00cc,
+	0x21f0: 0x00cc, 0x21f1: 0x00cc, 0x21f2: 0x00cc, 0x21f3: 0x00cc, 0x21f4: 0x00cc, 0x21f5: 0x00cc,
+	0x21f6: 0x00cc, 0x21f7: 0x00cc, 0x21f8: 0x00cc, 0x21f9: 0x00cc, 0x21fa: 0x00cc, 0x21fb: 0x00d2,
+	0x21fc: 0x00c0, 0x21fd: 0x00cc, 0x21fe: 0x00cc, 0x21ff: 0x008c,
+	// Block 0x88, offset 0x2200
+	0x2205: 0x00c0,
+	0x2206: 0x00c0, 0x2207: 0x00c0, 0x2208: 0x00c0, 0x2209: 0x00c0, 0x220a: 0x00c0, 0x220b: 0x00c0,
+	0x220c: 0x00c0, 0x220d: 0x00c0, 0x220e: 0x00c0, 0x220f: 0x00c0, 0x2210: 0x00c0, 0x2211: 0x00c0,
+	0x2212: 0x00c0, 0x2213: 0x00c0, 0x2214: 0x00c0, 0x2215: 0x00c0, 0x2216: 0x00c0, 0x2217: 0x00c0,
+	0x2218: 0x00c0, 0x2219: 0x00c0, 0x221a: 0x00c0, 0x221b: 0x00c0, 0x221c: 0x00c0, 0x221d: 0x00c0,
+	0x221e: 0x00c0, 0x221f: 0x00c0, 0x2220: 0x00c0, 0x2221: 0x00c0, 0x2222: 0x00c0, 0x2223: 0x00c0,
+	0x2224: 0x00c0, 0x2225: 0x00c0, 0x2226: 0x00c0, 0x2227: 0x00c0, 0x2228: 0x00c0, 0x2229: 0x00c0,
+	0x222a: 0x00c0, 0x222b: 0x00c0, 0x222c: 0x00c0, 0x222d: 0x00c0, 0x222e: 0x00c0, 0x222f: 0x00c0,
+	0x2231: 0x0080, 0x2232: 0x0080, 0x2233: 0x0080, 0x2234: 0x0080, 0x2235: 0x0080,
+	0x2236: 0x0080, 0x2237: 0x0080, 0x2238: 0x0080, 0x2239: 0x0080, 0x223a: 0x0080, 0x223b: 0x0080,
+	0x223c: 0x0080, 0x223d: 0x0080, 0x223e: 0x0080, 0x223f: 0x0080,
+	// Block 0x89, offset 0x2240
+	0x2240: 0x0080, 0x2241: 0x0080, 0x2242: 0x0080, 0x2243: 0x0080, 0x2244: 0x0080, 0x2245: 0x0080,
+	0x2246: 0x0080, 0x2247: 0x0080, 0x2248: 0x0080, 0x2249: 0x0080, 0x224a: 0x0080, 0x224b: 0x0080,
+	0x224c: 0x0080, 0x224d: 0x0080, 0x224e: 0x0080, 0x224f: 0x0080, 0x2250: 0x0080, 0x2251: 0x0080,
+	0x2252: 0x0080, 0x2253: 0x0080, 0x2254: 0x0080, 0x2255: 0x0080, 0x2256: 0x0080, 0x2257: 0x0080,
+	0x2258: 0x0080, 0x2259: 0x0080, 0x225a: 0x0080, 0x225b: 0x0080, 0x225c: 0x0080, 0x225d: 0x0080,
+	0x225e: 0x0080, 0x225f: 0x0080, 0x2260: 0x0080, 0x2261: 0x0080, 0x2262: 0x0080, 0x2263: 0x0080,
+	0x2264: 0x0040, 0x2265: 0x0080, 0x2266: 0x0080, 0x2267: 0x0080, 0x2268: 0x0080, 0x2269: 0x0080,
+	0x226a: 0x0080, 0x226b: 0x0080, 0x226c: 0x0080, 0x226d: 0x0080, 0x226e: 0x0080, 0x226f: 0x0080,
+	0x2270: 0x0080, 0x2271: 0x0080, 0x2272: 0x0080, 0x2273: 0x0080, 0x2274: 0x0080, 0x2275: 0x0080,
+	0x2276: 0x0080, 0x2277: 0x0080, 0x2278: 0x0080, 0x2279: 0x0080, 0x227a: 0x0080, 0x227b: 0x0080,
+	0x227c: 0x0080, 0x227d: 0x0080, 0x227e: 0x0080, 0x227f: 0x0080,
+	// Block 0x8a, offset 0x2280
+	0x2280: 0x0080, 0x2281: 0x0080, 0x2282: 0x0080, 0x2283: 0x0080, 0x2284: 0x0080, 0x2285: 0x0080,
+	0x2286: 0x0080, 0x2287: 0x0080, 0x2288: 0x0080, 0x2289: 0x0080, 0x228a: 0x0080, 0x228b: 0x0080,
+	0x228c: 0x0080, 0x228d: 0x0080, 0x228e: 0x0080, 0x2290: 0x0080, 0x2291: 0x0080,
+	0x2292: 0x0080, 0x2293: 0x0080, 0x2294: 0x0080, 0x2295: 0x0080, 0x2296: 0x0080, 0x2297: 0x0080,
+	0x2298: 0x0080, 0x2299: 0x0080, 0x229a: 0x0080, 0x229b: 0x0080, 0x229c: 0x0080, 0x229d: 0x0080,
+	0x229e: 0x0080, 0x229f: 0x0080, 0x22a0: 0x00c0, 0x22a1: 0x00c0, 0x22a2: 0x00c0, 0x22a3: 0x00c0,
+	0x22a4: 0x00c0, 0x22a5: 0x00c0, 0x22a6: 0x00c0, 0x22a7: 0x00c0, 0x22a8: 0x00c0, 0x22a9: 0x00c0,
+	0x22aa: 0x00c0, 0x22ab: 0x00c0, 0x22ac: 0x00c0, 0x22ad: 0x00c0, 0x22ae: 0x00c0, 0x22af: 0x00c0,
+	0x22b0: 0x00c0, 0x22b1: 0x00c0, 0x22b2: 0x00c0, 0x22b3: 0x00c0, 0x22b4: 0x00c0, 0x22b5: 0x00c0,
+	0x22b6: 0x00c0, 0x22b7: 0x00c0, 0x22b8: 0x00c0, 0x22b9: 0x00c0, 0x22ba: 0x00c0, 0x22bb: 0x00c0,
+	0x22bc: 0x00c0, 0x22bd: 0x00c0, 0x22be: 0x00c0, 0x22bf: 0x00c0,
+	// Block 0x8b, offset 0x22c0
+	0x22c0: 0x0080, 0x22c1: 0x0080, 0x22c2: 0x0080, 0x22c3: 0x0080, 0x22c4: 0x0080, 0x22c5: 0x0080,
+	0x22c6: 0x0080, 0x22c7: 0x0080, 0x22c8: 0x0080, 0x22c9: 0x0080, 0x22ca: 0x0080, 0x22cb: 0x0080,
+	0x22cc: 0x0080, 0x22cd: 0x0080, 0x22ce: 0x0080, 0x22cf: 0x0080, 0x22d0: 0x0080, 0x22d1: 0x0080,
+	0x22d2: 0x0080, 0x22d3: 0x0080, 0x22d4: 0x0080, 0x22d5: 0x0080, 0x22d6: 0x0080, 0x22d7: 0x0080,
+	0x22d8: 0x0080, 0x22d9: 0x0080, 0x22da: 0x0080, 0x22db: 0x0080, 0x22dc: 0x0080, 0x22dd: 0x0080,
+	0x22de: 0x0080, 0x22df: 0x0080, 0x22e0: 0x0080, 0x22e1: 0x0080, 0x22e2: 0x0080, 0x22e3: 0x0080,
+	0x22f0: 0x00cc, 0x22f1: 0x00cc, 0x22f2: 0x00cc, 0x22f3: 0x00cc, 0x22f4: 0x00cc, 0x22f5: 0x00cc,
+	0x22f6: 0x00cc, 0x22f7: 0x00cc, 0x22f8: 0x00cc, 0x22f9: 0x00cc, 0x22fa: 0x00cc, 0x22fb: 0x00cc,
+	0x22fc: 0x00cc, 0x22fd: 0x00cc, 0x22fe: 0x00cc, 0x22ff: 0x00cc,
+	// Block 0x8c, offset 0x2300
+	0x2300: 0x0080, 0x2301: 0x0080, 0x2302: 0x0080, 0x2303: 0x0080, 0x2304: 0x0080, 0x2305: 0x0080,
+	0x2306: 0x0080, 0x2307: 0x0080, 0x2308: 0x0080, 0x2309: 0x0080, 0x230a: 0x0080, 0x230b: 0x0080,
+	0x230c: 0x0080, 0x230d: 0x0080, 0x230e: 0x0080, 0x230f: 0x0080, 0x2310: 0x0080, 0x2311: 0x0080,
+	0x2312: 0x0080, 0x2313: 0x0080, 0x2314: 0x0080, 0x2315: 0x0080, 0x2316: 0x0080, 0x2317: 0x0080,
+	0x2318: 0x0080, 0x2319: 0x0080, 0x231a: 0x0080, 0x231b: 0x0080, 0x231c: 0x0080, 0x231d: 0x0080,
+	0x231e: 0x0080, 0x2320: 0x0080, 0x2321: 0x0080, 0x2322: 0x0080, 0x2323: 0x0080,
+	0x2324: 0x0080, 0x2325: 0x0080, 0x2326: 0x0080, 0x2327: 0x0080, 0x2328: 0x0080, 0x2329: 0x0080,
+	0x232a: 0x0080, 0x232b: 0x0080, 0x232c: 0x0080, 0x232d: 0x0080, 0x232e: 0x0080, 0x232f: 0x0080,
+	0x2330: 0x0080, 0x2331: 0x0080, 0x2332: 0x0080, 0x2333: 0x0080, 0x2334: 0x0080, 0x2335: 0x0080,
+	0x2336: 0x0080, 0x2337: 0x0080, 0x2338: 0x0080, 0x2339: 0x0080, 0x233a: 0x0080, 0x233b: 0x0080,
+	0x233c: 0x0080, 0x233d: 0x0080, 0x233e: 0x0080, 0x233f: 0x0080,
+	// Block 0x8d, offset 0x2340
+	0x2340: 0x0080, 0x2341: 0x0080, 0x2342: 0x0080, 0x2343: 0x0080, 0x2344: 0x0080, 0x2345: 0x0080,
+	0x2346: 0x0080, 0x2347: 0x0080, 0x2348: 0x0080, 0x2349: 0x0080, 0x234a: 0x0080, 0x234b: 0x0080,
+	0x234c: 0x0080, 0x234d: 0x0080, 0x234e: 0x0080, 0x234f: 0x0080, 0x2350: 0x008c, 0x2351: 0x008c,
+	0x2352: 0x008c, 0x2353: 0x008c, 0x2354: 0x008c, 0x2355: 0x008c, 0x2356: 0x008c, 0x2357: 0x008c,
+	0x2358: 0x008c, 0x2359: 0x008c, 0x235a: 0x008c, 0x235b: 0x008c, 0x235c: 0x008c, 0x235d: 0x008c,
+	0x235e: 0x008c, 0x235f: 0x008c, 0x2360: 0x008c, 0x2361: 0x008c, 0x2362: 0x008c, 0x2363: 0x008c,
+	0x2364: 0x008c, 0x2365: 0x008c, 0x2366: 0x008c, 0x2367: 0x008c, 0x2368: 0x008c, 0x2369: 0x008c,
+	0x236a: 0x008c, 0x236b: 0x008c, 0x236c: 0x008c, 0x236d: 0x008c, 0x236e: 0x008c, 0x236f: 0x008c,
+	0x2370: 0x008c, 0x2371: 0x008c, 0x2372: 0x008c, 0x2373: 0x008c, 0x2374: 0x008c, 0x2375: 0x008c,
+	0x2376: 0x008c, 0x2377: 0x008c, 0x2378: 0x008c, 0x2379: 0x008c, 0x237a: 0x008c, 0x237b: 0x008c,
+	0x237c: 0x008c, 0x237d: 0x008c, 0x237e: 0x008c, 0x237f: 0x0080,
+	// Block 0x8e, offset 0x2380
+	0x2380: 0x008c, 0x2381: 0x008c, 0x2382: 0x008c, 0x2383: 0x008c, 0x2384: 0x008c, 0x2385: 0x008c,
+	0x2386: 0x008c, 0x2387: 0x008c, 0x2388: 0x008c, 0x2389: 0x008c, 0x238a: 0x008c, 0x238b: 0x008c,
+	0x238c: 0x008c, 0x238d: 0x008c, 0x238e: 0x008c, 0x238f: 0x008c, 0x2390: 0x008c, 0x2391: 0x008c,
+	0x2392: 0x008c, 0x2393: 0x008c, 0x2394: 0x008c, 0x2395: 0x008c, 0x2396: 0x008c, 0x2397: 0x008c,
+	0x2398: 0x0080, 0x2399: 0x0080, 0x239a: 0x0080, 0x239b: 0x0080, 0x239c: 0x0080, 0x239d: 0x0080,
+	0x239e: 0x0080, 0x239f: 0x0080, 0x23a0: 0x0080, 0x23a1: 0x0080, 0x23a2: 0x0080, 0x23a3: 0x0080,
+	0x23a4: 0x0080, 0x23a5: 0x0080, 0x23a6: 0x0080, 0x23a7: 0x0080, 0x23a8: 0x0080, 0x23a9: 0x0080,
+	0x23aa: 0x0080, 0x23ab: 0x0080, 0x23ac: 0x0080, 0x23ad: 0x0080, 0x23ae: 0x0080, 0x23af: 0x0080,
+	0x23b0: 0x0080, 0x23b1: 0x0080, 0x23b2: 0x0080, 0x23b3: 0x0080, 0x23b4: 0x0080, 0x23b5: 0x0080,
+	0x23b6: 0x0080, 0x23b7: 0x0080, 0x23b8: 0x0080, 0x23b9: 0x0080, 0x23ba: 0x0080, 0x23bb: 0x0080,
+	0x23bc: 0x0080, 0x23bd: 0x0080, 0x23be: 0x0080, 0x23bf: 0x0080,
+	// Block 0x8f, offset 0x23c0
+	0x23c0: 0x00cc, 0x23c1: 0x00cc, 0x23c2: 0x00cc, 0x23c3: 0x00cc, 0x23c4: 0x00cc, 0x23c5: 0x00cc,
+	0x23c6: 0x00cc, 0x23c7: 0x00cc, 0x23c8: 0x00cc, 0x23c9: 0x00cc, 0x23ca: 0x00cc, 0x23cb: 0x00cc,
+	0x23cc: 0x00cc, 0x23cd: 0x00cc, 0x23ce: 0x00cc, 0x23cf: 0x00cc, 0x23d0: 0x00cc, 0x23d1: 0x00cc,
+	0x23d2: 0x00cc, 0x23d3: 0x00cc, 0x23d4: 0x00cc, 0x23d5: 0x00cc, 0x23d6: 0x00cc, 0x23d7: 0x00cc,
+	0x23d8: 0x00cc, 0x23d9: 0x00cc, 0x23da: 0x00cc, 0x23db: 0x00cc, 0x23dc: 0x00cc, 0x23dd: 0x00cc,
+	0x23de: 0x00cc, 0x23df: 0x00cc, 0x23e0: 0x00cc, 0x23e1: 0x00cc, 0x23e2: 0x00cc, 0x23e3: 0x00cc,
+	0x23e4: 0x00cc, 0x23e5: 0x00cc, 0x23e6: 0x00cc, 0x23e7: 0x00cc, 0x23e8: 0x00cc, 0x23e9: 0x00cc,
+	0x23ea: 0x00cc, 0x23eb: 0x00cc, 0x23ec: 0x00cc, 0x23ed: 0x00cc, 0x23ee: 0x00cc, 0x23ef: 0x00cc,
+	0x23f0: 0x00cc, 0x23f1: 0x00cc, 0x23f2: 0x00cc, 0x23f3: 0x00cc, 0x23f4: 0x00cc, 0x23f5: 0x00cc,
+	0x23f6: 0x00cc, 0x23f7: 0x00cc, 0x23f8: 0x00cc, 0x23f9: 0x00cc, 0x23fa: 0x00cc, 0x23fb: 0x00cc,
+	0x23fc: 0x00cc, 0x23fd: 0x00cc, 0x23fe: 0x00cc, 0x23ff: 0x00cc,
+	// Block 0x90, offset 0x2400
+	0x2400: 0x00c0, 0x2401: 0x00c0, 0x2402: 0x00c0, 0x2403: 0x00c0, 0x2404: 0x00c0, 0x2405: 0x00c0,
+	0x2406: 0x00c0, 0x2407: 0x00c0, 0x2408: 0x00c0, 0x2409: 0x00c0, 0x240a: 0x00c0, 0x240b: 0x00c0,
+	0x240c: 0x00c0, 0x2410: 0x0080, 0x2411: 0x0080,
+	0x2412: 0x0080, 0x2413: 0x0080, 0x2414: 0x0080, 0x2415: 0x0080, 0x2416: 0x0080, 0x2417: 0x0080,
+	0x2418: 0x0080, 0x2419: 0x0080, 0x241a: 0x0080, 0x241b: 0x0080, 0x241c: 0x0080, 0x241d: 0x0080,
+	0x241e: 0x0080, 0x241f: 0x0080, 0x2420: 0x0080, 0x2421: 0x0080, 0x2422: 0x0080, 0x2423: 0x0080,
+	0x2424: 0x0080, 0x2425: 0x0080, 0x2426: 0x0080, 0x2427: 0x0080, 0x2428: 0x0080, 0x2429: 0x0080,
+	0x242a: 0x0080, 0x242b: 0x0080, 0x242c: 0x0080, 0x242d: 0x0080, 0x242e: 0x0080, 0x242f: 0x0080,
+	0x2430: 0x0080, 0x2431: 0x0080, 0x2432: 0x0080, 0x2433: 0x0080, 0x2434: 0x0080, 0x2435: 0x0080,
+	0x2436: 0x0080, 0x2437: 0x0080, 0x2438: 0x0080, 0x2439: 0x0080, 0x243a: 0x0080, 0x243b: 0x0080,
+	0x243c: 0x0080, 0x243d: 0x0080, 0x243e: 0x0080, 0x243f: 0x0080,
+	// Block 0x91, offset 0x2440
+	0x2440: 0x0080, 0x2441: 0x0080, 0x2442: 0x0080, 0x2443: 0x0080, 0x2444: 0x0080, 0x2445: 0x0080,
+	0x2446: 0x0080,
+	0x2450: 0x00c0, 0x2451: 0x00c0,
+	0x2452: 0x00c0, 0x2453: 0x00c0, 0x2454: 0x00c0, 0x2455: 0x00c0, 0x2456: 0x00c0, 0x2457: 0x00c0,
+	0x2458: 0x00c0, 0x2459: 0x00c0, 0x245a: 0x00c0, 0x245b: 0x00c0, 0x245c: 0x00c0, 0x245d: 0x00c0,
+	0x245e: 0x00c0, 0x245f: 0x00c0, 0x2460: 0x00c0, 0x2461: 0x00c0, 0x2462: 0x00c0, 0x2463: 0x00c0,
+	0x2464: 0x00c0, 0x2465: 0x00c0, 0x2466: 0x00c0, 0x2467: 0x00c0, 0x2468: 0x00c0, 0x2469: 0x00c0,
+	0x246a: 0x00c0, 0x246b: 0x00c0, 0x246c: 0x00c0, 0x246d: 0x00c0, 0x246e: 0x00c0, 0x246f: 0x00c0,
+	0x2470: 0x00c0, 0x2471: 0x00c0, 0x2472: 0x00c0, 0x2473: 0x00c0, 0x2474: 0x00c0, 0x2475: 0x00c0,
+	0x2476: 0x00c0, 0x2477: 0x00c0, 0x2478: 0x00c0, 0x2479: 0x00c0, 0x247a: 0x00c0, 0x247b: 0x00c0,
+	0x247c: 0x00c0, 0x247d: 0x00c0, 0x247e: 0x0080, 0x247f: 0x0080,
+	// Block 0x92, offset 0x2480
+	0x2480: 0x00c0, 0x2481: 0x00c0, 0x2482: 0x00c0, 0x2483: 0x00c0, 0x2484: 0x00c0, 0x2485: 0x00c0,
+	0x2486: 0x00c0, 0x2487: 0x00c0, 0x2488: 0x00c0, 0x2489: 0x00c0, 0x248a: 0x00c0, 0x248b: 0x00c0,
+	0x248c: 0x00c0, 0x248d: 0x0080, 0x248e: 0x0080, 0x248f: 0x0080, 0x2490: 0x00c0, 0x2491: 0x00c0,
+	0x2492: 0x00c0, 0x2493: 0x00c0, 0x2494: 0x00c0, 0x2495: 0x00c0, 0x2496: 0x00c0, 0x2497: 0x00c0,
+	0x2498: 0x00c0, 0x2499: 0x00c0, 0x249a: 0x00c0, 0x249b: 0x00c0, 0x249c: 0x00c0, 0x249d: 0x00c0,
+	0x249e: 0x00c0, 0x249f: 0x00c0, 0x24a0: 0x00c0, 0x24a1: 0x00c0, 0x24a2: 0x00c0, 0x24a3: 0x00c0,
+	0x24a4: 0x00c0, 0x24a5: 0x00c0, 0x24a6: 0x00c0, 0x24a7: 0x00c0, 0x24a8: 0x00c0, 0x24a9: 0x00c0,
+	0x24aa: 0x00c0, 0x24ab: 0x00c0,
+	// Block 0x93, offset 0x24c0
+	0x24c0: 0x00c0, 0x24c1: 0x00c0, 0x24c2: 0x00c0, 0x24c3: 0x00c0, 0x24c4: 0x00c0, 0x24c5: 0x00c0,
+	0x24c6: 0x00c0, 0x24c7: 0x00c0, 0x24c8: 0x00c0, 0x24c9: 0x00c0, 0x24ca: 0x00c0, 0x24cb: 0x00c0,
+	0x24cc: 0x00c0, 0x24cd: 0x00c0, 0x24ce: 0x00c0, 0x24cf: 0x00c0, 0x24d0: 0x00c0, 0x24d1: 0x00c0,
+	0x24d2: 0x00c0, 0x24d3: 0x00c0, 0x24d4: 0x00c0, 0x24d5: 0x00c0, 0x24d6: 0x00c0, 0x24d7: 0x00c0,
+	0x24d8: 0x00c0, 0x24d9: 0x00c0, 0x24da: 0x00c0, 0x24db: 0x00c0, 0x24dc: 0x00c0, 0x24dd: 0x00c0,
+	0x24de: 0x00c0, 0x24df: 0x00c0, 0x24e0: 0x00c0, 0x24e1: 0x00c0, 0x24e2: 0x00c0, 0x24e3: 0x00c0,
+	0x24e4: 0x00c0, 0x24e5: 0x00c0, 0x24e6: 0x00c0, 0x24e7: 0x00c0, 0x24e8: 0x00c0, 0x24e9: 0x00c0,
+	0x24ea: 0x00c0, 0x24eb: 0x00c0, 0x24ec: 0x00c0, 0x24ed: 0x00c0, 0x24ee: 0x00c0, 0x24ef: 0x00c3,
+	0x24f0: 0x0083, 0x24f1: 0x0083, 0x24f2: 0x0083, 0x24f3: 0x0080, 0x24f4: 0x00c3, 0x24f5: 0x00c3,
+	0x24f6: 0x00c3, 0x24f7: 0x00c3, 0x24f8: 0x00c3, 0x24f9: 0x00c3, 0x24fa: 0x00c3, 0x24fb: 0x00c3,
+	0x24fc: 0x00c3, 0x24fd: 0x00c3, 0x24fe: 0x0080, 0x24ff: 0x00c0,
+	// Block 0x94, offset 0x2500
+	0x2500: 0x00c0, 0x2501: 0x00c0, 0x2502: 0x00c0, 0x2503: 0x00c0, 0x2504: 0x00c0, 0x2505: 0x00c0,
+	0x2506: 0x00c0, 0x2507: 0x00c0, 0x2508: 0x00c0, 0x2509: 0x00c0, 0x250a: 0x00c0, 0x250b: 0x00c0,
+	0x250c: 0x00c0, 0x250d: 0x00c0, 0x250e: 0x00c0, 0x250f: 0x00c0, 0x2510: 0x00c0, 0x2511: 0x00c0,
+	0x2512: 0x00c0, 0x2513: 0x00c0, 0x2514: 0x00c0, 0x2515: 0x00c0, 0x2516: 0x00c0, 0x2517: 0x00c0,
+	0x2518: 0x00c0, 0x2519: 0x00c0, 0x251a: 0x00c0, 0x251b: 0x00c0, 0x251c: 0x0080, 0x251d: 0x0080,
+	0x251e: 0x00c3, 0x251f: 0x00c3, 0x2520: 0x00c0, 0x2521: 0x00c0, 0x2522: 0x00c0, 0x2523: 0x00c0,
+	0x2524: 0x00c0, 0x2525: 0x00c0, 0x2526: 0x00c0, 0x2527: 0x00c0, 0x2528: 0x00c0, 0x2529: 0x00c0,
+	0x252a: 0x00c0, 0x252b: 0x00c0, 0x252c: 0x00c0, 0x252d: 0x00c0, 0x252e: 0x00c0, 0x252f: 0x00c0,
+	0x2530: 0x00c0, 0x2531: 0x00c0, 0x2532: 0x00c0, 0x2533: 0x00c0, 0x2534: 0x00c0, 0x2535: 0x00c0,
+	0x2536: 0x00c0, 0x2537: 0x00c0, 0x2538: 0x00c0, 0x2539: 0x00c0, 0x253a: 0x00c0, 0x253b: 0x00c0,
+	0x253c: 0x00c0, 0x253d: 0x00c0, 0x253e: 0x00c0, 0x253f: 0x00c0,
+	// Block 0x95, offset 0x2540
+	0x2540: 0x00c0, 0x2541: 0x00c0, 0x2542: 0x00c0, 0x2543: 0x00c0, 0x2544: 0x00c0, 0x2545: 0x00c0,
+	0x2546: 0x00c0, 0x2547: 0x00c0, 0x2548: 0x00c0, 0x2549: 0x00c0, 0x254a: 0x00c0, 0x254b: 0x00c0,
+	0x254c: 0x00c0, 0x254d: 0x00c0, 0x254e: 0x00c0, 0x254f: 0x00c0, 0x2550: 0x00c0, 0x2551: 0x00c0,
+	0x2552: 0x00c0, 0x2553: 0x00c0, 0x2554: 0x00c0, 0x2555: 0x00c0, 0x2556: 0x00c0, 0x2557: 0x00c0,
+	0x2558: 0x00c0, 0x2559: 0x00c0, 0x255a: 0x00c0, 0x255b: 0x00c0, 0x255c: 0x00c0, 0x255d: 0x00c0,
+	0x255e: 0x00c0, 0x255f: 0x00c0, 0x2560: 0x00c0, 0x2561: 0x00c0, 0x2562: 0x00c0, 0x2563: 0x00c0,
+	0x2564: 0x00c0, 0x2565: 0x00c0, 0x2566: 0x0080, 0x2567: 0x0080, 0x2568: 0x0080, 0x2569: 0x0080,
+	0x256a: 0x0080, 0x256b: 0x0080, 0x256c: 0x0080, 0x256d: 0x0080, 0x256e: 0x0080, 0x256f: 0x0080,
+	0x2570: 0x00c3, 0x2571: 0x00c3, 0x2572: 0x0080, 0x2573: 0x0080, 0x2574: 0x0080, 0x2575: 0x0080,
+	0x2576: 0x0080, 0x2577: 0x0080,
+	// Block 0x96, offset 0x2580
+	0x2580: 0x0080, 0x2581: 0x0080, 0x2582: 0x0080, 0x2583: 0x0080, 0x2584: 0x0080, 0x2585: 0x0080,
+	0x2586: 0x0080, 0x2587: 0x0080, 0x2588: 0x0080, 0x2589: 0x0080, 0x258a: 0x0080, 0x258b: 0x0080,
+	0x258c: 0x0080, 0x258d: 0x0080, 0x258e: 0x0080, 0x258f: 0x0080, 0x2590: 0x0080, 0x2591: 0x0080,
+	0x2592: 0x0080, 0x2593: 0x0080, 0x2594: 0x0080, 0x2595: 0x0080, 0x2596: 0x0080, 0x2597: 0x00c0,
+	0x2598: 0x00c0, 0x2599: 0x00c0, 0x259a: 0x00c0, 0x259b: 0x00c0, 0x259c: 0x00c0, 0x259d: 0x00c0,
+	0x259e: 0x00c0, 0x259f: 0x00c0, 0x25a0: 0x0080, 0x25a1: 0x0080, 0x25a2: 0x00c0, 0x25a3: 0x00c0,
+	0x25a4: 0x00c0, 0x25a5: 0x00c0, 0x25a6: 0x00c0, 0x25a7: 0x00c0, 0x25a8: 0x00c0, 0x25a9: 0x00c0,
+	0x25aa: 0x00c0, 0x25ab: 0x00c0, 0x25ac: 0x00c0, 0x25ad: 0x00c0, 0x25ae: 0x00c0, 0x25af: 0x00c0,
+	0x25b0: 0x00c0, 0x25b1: 0x00c0, 0x25b2: 0x00c0, 0x25b3: 0x00c0, 0x25b4: 0x00c0, 0x25b5: 0x00c0,
+	0x25b6: 0x00c0, 0x25b7: 0x00c0, 0x25b8: 0x00c0, 0x25b9: 0x00c0, 0x25ba: 0x00c0, 0x25bb: 0x00c0,
+	0x25bc: 0x00c0, 0x25bd: 0x00c0, 0x25be: 0x00c0, 0x25bf: 0x00c0,
+	// Block 0x97, offset 0x25c0
+	0x25c0: 0x00c0, 0x25c1: 0x00c0, 0x25c2: 0x00c0, 0x25c3: 0x00c0, 0x25c4: 0x00c0, 0x25c5: 0x00c0,
+	0x25c6: 0x00c0, 0x25c7: 0x00c0, 0x25c8: 0x00c0, 0x25c9: 0x00c0, 0x25ca: 0x00c0, 0x25cb: 0x00c0,
+	0x25cc: 0x00c0, 0x25cd: 0x00c0, 0x25ce: 0x00c0, 0x25cf: 0x00c0, 0x25d0: 0x00c0, 0x25d1: 0x00c0,
+	0x25d2: 0x00c0, 0x25d3: 0x00c0, 0x25d4: 0x00c0, 0x25d5: 0x00c0, 0x25d6: 0x00c0, 0x25d7: 0x00c0,
+	0x25d8: 0x00c0, 0x25d9: 0x00c0, 0x25da: 0x00c0, 0x25db: 0x00c0, 0x25dc: 0x00c0, 0x25dd: 0x00c0,
+	0x25de: 0x00c0, 0x25df: 0x00c0, 0x25e0: 0x00c0, 0x25e1: 0x00c0, 0x25e2: 0x00c0, 0x25e3: 0x00c0,
+	0x25e4: 0x00c0, 0x25e5: 0x00c0, 0x25e6: 0x00c0, 0x25e7: 0x00c0, 0x25e8: 0x00c0, 0x25e9: 0x00c0,
+	0x25ea: 0x00c0, 0x25eb: 0x00c0, 0x25ec: 0x00c0, 0x25ed: 0x00c0, 0x25ee: 0x00c0, 0x25ef: 0x00c0,
+	0x25f0: 0x0080, 0x25f1: 0x00c0, 0x25f2: 0x00c0, 0x25f3: 0x00c0, 0x25f4: 0x00c0, 0x25f5: 0x00c0,
+	0x25f6: 0x00c0, 0x25f7: 0x00c0, 0x25f8: 0x00c0, 0x25f9: 0x00c0, 0x25fa: 0x00c0, 0x25fb: 0x00c0,
+	0x25fc: 0x00c0, 0x25fd: 0x00c0, 0x25fe: 0x00c0, 0x25ff: 0x00c0,
+	// Block 0x98, offset 0x2600
+	0x2600: 0x00c0, 0x2601: 0x00c0, 0x2602: 0x00c0, 0x2603: 0x00c0, 0x2604: 0x00c0, 0x2605: 0x00c0,
+	0x2606: 0x00c0, 0x2607: 0x00c0, 0x2608: 0x00c0, 0x2609: 0x0080, 0x260a: 0x0080, 0x260b: 0x00c0,
+	0x260c: 0x00c0, 0x260d: 0x00c0, 0x260e: 0x00c0, 0x260f: 0x00c0, 0x2610: 0x00c0, 0x2611: 0x00c0,
+	0x2612: 0x00c0, 0x2613: 0x00c0, 0x2614: 0x00c0, 0x2615: 0x00c0, 0x2616: 0x00c0, 0x2617: 0x00c0,
+	0x2618: 0x00c0, 0x2619: 0x00c0, 0x261a: 0x00c0, 0x261b: 0x00c0, 0x261c: 0x00c0, 0x261d: 0x00c0,
+	0x261e: 0x00c0, 0x261f: 0x00c0, 0x2620: 0x00c0, 0x2621: 0x00c0, 0x2622: 0x00c0, 0x2623: 0x00c0,
+	0x2624: 0x00c0, 0x2625: 0x00c0, 0x2626: 0x00c0, 0x2627: 0x00c0, 0x2628: 0x00c0, 0x2629: 0x00c0,
+	0x262a: 0x00c0, 0x262b: 0x00c0, 0x262c: 0x00c0, 0x262d: 0x00c0, 0x262e: 0x00c0, 0x262f: 0x00c0,
+	0x2630: 0x00c0, 0x2631: 0x00c0, 0x2632: 0x00c0, 0x2633: 0x00c0, 0x2634: 0x00c0, 0x2635: 0x00c0,
+	0x2636: 0x00c0, 0x2637: 0x00c0, 0x2638: 0x00c0, 0x2639: 0x00c0, 0x263a: 0x00c0, 0x263b: 0x00c0,
+	0x263c: 0x00c0, 0x263d: 0x00c0, 0x263e: 0x00c0, 0x263f: 0x00c0,
+	// Block 0x99, offset 0x2640
+	0x2640: 0x00c0, 0x2641: 0x00c0, 0x2642: 0x00c0, 0x2643: 0x00c0, 0x2644: 0x00c0, 0x2645: 0x00c0,
+	0x2646: 0x00c0, 0x2647: 0x00c0, 0x2648: 0x00c0, 0x2649: 0x00c0, 0x264a: 0x00c0,
+	0x2650: 0x00c0, 0x2651: 0x00c0,
+	0x2653: 0x00c0, 0x2655: 0x00c0, 0x2656: 0x00c0, 0x2657: 0x00c0,
+	0x2658: 0x00c0, 0x2659: 0x00c0,
+	0x2672: 0x0080, 0x2673: 0x0080, 0x2674: 0x0080, 0x2675: 0x00c0,
+	0x2676: 0x00c0, 0x2677: 0x00c0, 0x2678: 0x0080, 0x2679: 0x0080, 0x267a: 0x00c0, 0x267b: 0x00c0,
+	0x267c: 0x00c0, 0x267d: 0x00c0, 0x267e: 0x00c0, 0x267f: 0x00c0,
+	// Block 0x9a, offset 0x2680
+	0x2680: 0x00c0, 0x2681: 0x00c0, 0x2682: 0x00c3, 0x2683: 0x00c0, 0x2684: 0x00c0, 0x2685: 0x00c0,
+	0x2686: 0x00c6, 0x2687: 0x00c0, 0x2688: 0x00c0, 0x2689: 0x00c0, 0x268a: 0x00c0, 0x268b: 0x00c3,
+	0x268c: 0x00c0, 0x268d: 0x00c0, 0x268e: 0x00c0, 0x268f: 0x00c0, 0x2690: 0x00c0, 0x2691: 0x00c0,
+	0x2692: 0x00c0, 0x2693: 0x00c0, 0x2694: 0x00c0, 0x2695: 0x00c0, 0x2696: 0x00c0, 0x2697: 0x00c0,
+	0x2698: 0x00c0, 0x2699: 0x00c0, 0x269a: 0x00c0, 0x269b: 0x00c0, 0x269c: 0x00c0, 0x269d: 0x00c0,
+	0x269e: 0x00c0, 0x269f: 0x00c0, 0x26a0: 0x00c0, 0x26a1: 0x00c0, 0x26a2: 0x00c0, 0x26a3: 0x00c0,
+	0x26a4: 0x00c0, 0x26a5: 0x00c3, 0x26a6: 0x00c3, 0x26a7: 0x00c0, 0x26a8: 0x0080, 0x26a9: 0x0080,
+	0x26aa: 0x0080, 0x26ab: 0x0080, 0x26ac: 0x00c6,
+	0x26b0: 0x0080, 0x26b1: 0x0080, 0x26b2: 0x0080, 0x26b3: 0x0080, 0x26b4: 0x0080, 0x26b5: 0x0080,
+	0x26b6: 0x0080, 0x26b7: 0x0080, 0x26b8: 0x0080, 0x26b9: 0x0080,
+	// Block 0x9b, offset 0x26c0
+	0x26c0: 0x00c2, 0x26c1: 0x00c2, 0x26c2: 0x00c2, 0x26c3: 0x00c2, 0x26c4: 0x00c2, 0x26c5: 0x00c2,
+	0x26c6: 0x00c2, 0x26c7: 0x00c2, 0x26c8: 0x00c2, 0x26c9: 0x00c2, 0x26ca: 0x00c2, 0x26cb: 0x00c2,
+	0x26cc: 0x00c2, 0x26cd: 0x00c2, 0x26ce: 0x00c2, 0x26cf: 0x00c2, 0x26d0: 0x00c2, 0x26d1: 0x00c2,
+	0x26d2: 0x00c2, 0x26d3: 0x00c2, 0x26d4: 0x00c2, 0x26d5: 0x00c2, 0x26d6: 0x00c2, 0x26d7: 0x00c2,
+	0x26d8: 0x00c2, 0x26d9: 0x00c2, 0x26da: 0x00c2, 0x26db: 0x00c2, 0x26dc: 0x00c2, 0x26dd: 0x00c2,
+	0x26de: 0x00c2, 0x26df: 0x00c2, 0x26e0: 0x00c2, 0x26e1: 0x00c2, 0x26e2: 0x00c2, 0x26e3: 0x00c2,
+	0x26e4: 0x00c2, 0x26e5: 0x00c2, 0x26e6: 0x00c2, 0x26e7: 0x00c2, 0x26e8: 0x00c2, 0x26e9: 0x00c2,
+	0x26ea: 0x00c2, 0x26eb: 0x00c2, 0x26ec: 0x00c2, 0x26ed: 0x00c2, 0x26ee: 0x00c2, 0x26ef: 0x00c2,
+	0x26f0: 0x00c2, 0x26f1: 0x00c2, 0x26f2: 0x00c1, 0x26f3: 0x00c0, 0x26f4: 0x0080, 0x26f5: 0x0080,
+	0x26f6: 0x0080, 0x26f7: 0x0080,
+	// Block 0x9c, offset 0x2700
+	0x2700: 0x00c0, 0x2701: 0x00c0, 0x2702: 0x00c0, 0x2703: 0x00c0, 0x2704: 0x00c6, 0x2705: 0x00c3,
+	0x270e: 0x0080, 0x270f: 0x0080, 0x2710: 0x00c0, 0x2711: 0x00c0,
+	0x2712: 0x00c0, 0x2713: 0x00c0, 0x2714: 0x00c0, 0x2715: 0x00c0, 0x2716: 0x00c0, 0x2717: 0x00c0,
+	0x2718: 0x00c0, 0x2719: 0x00c0,
+	0x2720: 0x00c3, 0x2721: 0x00c3, 0x2722: 0x00c3, 0x2723: 0x00c3,
+	0x2724: 0x00c3, 0x2725: 0x00c3, 0x2726: 0x00c3, 0x2727: 0x00c3, 0x2728: 0x00c3, 0x2729: 0x00c3,
+	0x272a: 0x00c3, 0x272b: 0x00c3, 0x272c: 0x00c3, 0x272d: 0x00c3, 0x272e: 0x00c3, 0x272f: 0x00c3,
+	0x2730: 0x00c3, 0x2731: 0x00c3, 0x2732: 0x00c0, 0x2733: 0x00c0, 0x2734: 0x00c0, 0x2735: 0x00c0,
+	0x2736: 0x00c0, 0x2737: 0x00c0, 0x2738: 0x0080, 0x2739: 0x0080, 0x273a: 0x0080, 0x273b: 0x00c0,
+	0x273c: 0x0080, 0x273d: 0x00c0, 0x273e: 0x00c0, 0x273f: 0x00c3,
+	// Block 0x9d, offset 0x2740
+	0x2740: 0x00c0, 0x2741: 0x00c0, 0x2742: 0x00c0, 0x2743: 0x00c0, 0x2744: 0x00c0, 0x2745: 0x00c0,
+	0x2746: 0x00c0, 0x2747: 0x00c0, 0x2748: 0x00c0, 0x2749: 0x00c0, 0x274a: 0x00c0, 0x274b: 0x00c0,
+	0x274c: 0x00c0, 0x274d: 0x00c0, 0x274e: 0x00c0, 0x274f: 0x00c0, 0x2750: 0x00c0, 0x2751: 0x00c0,
+	0x2752: 0x00c0, 0x2753: 0x00c0, 0x2754: 0x00c0, 0x2755: 0x00c0, 0x2756: 0x00c0, 0x2757: 0x00c0,
+	0x2758: 0x00c0, 0x2759: 0x00c0, 0x275a: 0x00c0, 0x275b: 0x00c0, 0x275c: 0x00c0, 0x275d: 0x00c0,
+	0x275e: 0x00c0, 0x275f: 0x00c0, 0x2760: 0x00c0, 0x2761: 0x00c0, 0x2762: 0x00c0, 0x2763: 0x00c0,
+	0x2764: 0x00c0, 0x2765: 0x00c0, 0x2766: 0x00c3, 0x2767: 0x00c3, 0x2768: 0x00c3, 0x2769: 0x00c3,
+	0x276a: 0x00c3, 0x276b: 0x00c3, 0x276c: 0x00c3, 0x276d: 0x00c3, 0x276e: 0x0080, 0x276f: 0x0080,
+	0x2770: 0x00c0, 0x2771: 0x00c0, 0x2772: 0x00c0, 0x2773: 0x00c0, 0x2774: 0x00c0, 0x2775: 0x00c0,
+	0x2776: 0x00c0, 0x2777: 0x00c0, 0x2778: 0x00c0, 0x2779: 0x00c0, 0x277a: 0x00c0, 0x277b: 0x00c0,
+	0x277c: 0x00c0, 0x277d: 0x00c0, 0x277e: 0x00c0, 0x277f: 0x00c0,
+	// Block 0x9e, offset 0x2780
+	0x2780: 0x00c0, 0x2781: 0x00c0, 0x2782: 0x00c0, 0x2783: 0x00c0, 0x2784: 0x00c0, 0x2785: 0x00c0,
+	0x2786: 0x00c0, 0x2787: 0x00c3, 0x2788: 0x00c3, 0x2789: 0x00c3, 0x278a: 0x00c3, 0x278b: 0x00c3,
+	0x278c: 0x00c3, 0x278d: 0x00c3, 0x278e: 0x00c3, 0x278f: 0x00c3, 0x2790: 0x00c3, 0x2791: 0x00c3,
+	0x2792: 0x00c0, 0x2793: 0x00c5,
+	0x279f: 0x0080, 0x27a0: 0x0040, 0x27a1: 0x0040, 0x27a2: 0x0040, 0x27a3: 0x0040,
+	0x27a4: 0x0040, 0x27a5: 0x0040, 0x27a6: 0x0040, 0x27a7: 0x0040, 0x27a8: 0x0040, 0x27a9: 0x0040,
+	0x27aa: 0x0040, 0x27ab: 0x0040, 0x27ac: 0x0040, 0x27ad: 0x0040, 0x27ae: 0x0040, 0x27af: 0x0040,
+	0x27b0: 0x0040, 0x27b1: 0x0040, 0x27b2: 0x0040, 0x27b3: 0x0040, 0x27b4: 0x0040, 0x27b5: 0x0040,
+	0x27b6: 0x0040, 0x27b7: 0x0040, 0x27b8: 0x0040, 0x27b9: 0x0040, 0x27ba: 0x0040, 0x27bb: 0x0040,
+	0x27bc: 0x0040,
+	// Block 0x9f, offset 0x27c0
+	0x27c0: 0x00c3, 0x27c1: 0x00c3, 0x27c2: 0x00c3, 0x27c3: 0x00c0, 0x27c4: 0x00c0, 0x27c5: 0x00c0,
+	0x27c6: 0x00c0, 0x27c7: 0x00c0, 0x27c8: 0x00c0, 0x27c9: 0x00c0, 0x27ca: 0x00c0, 0x27cb: 0x00c0,
+	0x27cc: 0x00c0, 0x27cd: 0x00c0, 0x27ce: 0x00c0, 0x27cf: 0x00c0, 0x27d0: 0x00c0, 0x27d1: 0x00c0,
+	0x27d2: 0x00c0, 0x27d3: 0x00c0, 0x27d4: 0x00c0, 0x27d5: 0x00c0, 0x27d6: 0x00c0, 0x27d7: 0x00c0,
+	0x27d8: 0x00c0, 0x27d9: 0x00c0, 0x27da: 0x00c0, 0x27db: 0x00c0, 0x27dc: 0x00c0, 0x27dd: 0x00c0,
+	0x27de: 0x00c0, 0x27df: 0x00c0, 0x27e0: 0x00c0, 0x27e1: 0x00c0, 0x27e2: 0x00c0, 0x27e3: 0x00c0,
+	0x27e4: 0x00c0, 0x27e5: 0x00c0, 0x27e6: 0x00c0, 0x27e7: 0x00c0, 0x27e8: 0x00c0, 0x27e9: 0x00c0,
+	0x27ea: 0x00c0, 0x27eb: 0x00c0, 0x27ec: 0x00c0, 0x27ed: 0x00c0, 0x27ee: 0x00c0, 0x27ef: 0x00c0,
+	0x27f0: 0x00c0, 0x27f1: 0x00c0, 0x27f2: 0x00c0, 0x27f3: 0x00c3, 0x27f4: 0x00c0, 0x27f5: 0x00c0,
+	0x27f6: 0x00c3, 0x27f7: 0x00c3, 0x27f8: 0x00c3, 0x27f9: 0x00c3, 0x27fa: 0x00c0, 0x27fb: 0x00c0,
+	0x27fc: 0x00c3, 0x27fd: 0x00c3, 0x27fe: 0x00c0, 0x27ff: 0x00c0,
+	// Block 0xa0, offset 0x2800
+	0x2800: 0x00c5, 0x2801: 0x0080, 0x2802: 0x0080, 0x2803: 0x0080, 0x2804: 0x0080, 0x2805: 0x0080,
+	0x2806: 0x0080, 0x2807: 0x0080, 0x2808: 0x0080, 0x2809: 0x0080, 0x280a: 0x0080, 0x280b: 0x0080,
+	0x280c: 0x0080, 0x280d: 0x0080, 0x280f: 0x00c0, 0x2810: 0x00c0, 0x2811: 0x00c0,
+	0x2812: 0x00c0, 0x2813: 0x00c0, 0x2814: 0x00c0, 0x2815: 0x00c0, 0x2816: 0x00c0, 0x2817: 0x00c0,
+	0x2818: 0x00c0, 0x2819: 0x00c0,
+	0x281e: 0x0080, 0x281f: 0x0080, 0x2820: 0x00c0, 0x2821: 0x00c0, 0x2822: 0x00c0, 0x2823: 0x00c0,
+	0x2824: 0x00c0, 0x2825: 0x00c3, 0x2826: 0x00c0, 0x2827: 0x00c0, 0x2828: 0x00c0, 0x2829: 0x00c0,
+	0x282a: 0x00c0, 0x282b: 0x00c0, 0x282c: 0x00c0, 0x282d: 0x00c0, 0x282e: 0x00c0, 0x282f: 0x00c0,
+	0x2830: 0x00c0, 0x2831: 0x00c0, 0x2832: 0x00c0, 0x2833: 0x00c0, 0x2834: 0x00c0, 0x2835: 0x00c0,
+	0x2836: 0x00c0, 0x2837: 0x00c0, 0x2838: 0x00c0, 0x2839: 0x00c0, 0x283a: 0x00c0, 0x283b: 0x00c0,
+	0x283c: 0x00c0, 0x283d: 0x00c0, 0x283e: 0x00c0,
+	// Block 0xa1, offset 0x2840
+	0x2840: 0x00c0, 0x2841: 0x00c0, 0x2842: 0x00c0, 0x2843: 0x00c0, 0x2844: 0x00c0, 0x2845: 0x00c0,
+	0x2846: 0x00c0, 0x2847: 0x00c0, 0x2848: 0x00c0, 0x2849: 0x00c0, 0x284a: 0x00c0, 0x284b: 0x00c0,
+	0x284c: 0x00c0, 0x284d: 0x00c0, 0x284e: 0x00c0, 0x284f: 0x00c0, 0x2850: 0x00c0, 0x2851: 0x00c0,
+	0x2852: 0x00c0, 0x2853: 0x00c0, 0x2854: 0x00c0, 0x2855: 0x00c0, 0x2856: 0x00c0, 0x2857: 0x00c0,
+	0x2858: 0x00c0, 0x2859: 0x00c0, 0x285a: 0x00c0, 0x285b: 0x00c0, 0x285c: 0x00c0, 0x285d: 0x00c0,
+	0x285e: 0x00c0, 0x285f: 0x00c0, 0x2860: 0x00c0, 0x2861: 0x00c0, 0x2862: 0x00c0, 0x2863: 0x00c0,
+	0x2864: 0x00c0, 0x2865: 0x00c0, 0x2866: 0x00c0, 0x2867: 0x00c0, 0x2868: 0x00c0, 0x2869: 0x00c3,
+	0x286a: 0x00c3, 0x286b: 0x00c3, 0x286c: 0x00c3, 0x286d: 0x00c3, 0x286e: 0x00c3, 0x286f: 0x00c0,
+	0x2870: 0x00c0, 0x2871: 0x00c3, 0x2872: 0x00c3, 0x2873: 0x00c0, 0x2874: 0x00c0, 0x2875: 0x00c3,
+	0x2876: 0x00c3,
+	// Block 0xa2, offset 0x2880
+	0x2880: 0x00c0, 0x2881: 0x00c0, 0x2882: 0x00c0, 0x2883: 0x00c3, 0x2884: 0x00c0, 0x2885: 0x00c0,
+	0x2886: 0x00c0, 0x2887: 0x00c0, 0x2888: 0x00c0, 0x2889: 0x00c0, 0x288a: 0x00c0, 0x288b: 0x00c0,
+	0x288c: 0x00c3, 0x288d: 0x00c0, 0x2890: 0x00c0, 0x2891: 0x00c0,
+	0x2892: 0x00c0, 0x2893: 0x00c0, 0x2894: 0x00c0, 0x2895: 0x00c0, 0x2896: 0x00c0, 0x2897: 0x00c0,
+	0x2898: 0x00c0, 0x2899: 0x00c0, 0x289c: 0x0080, 0x289d: 0x0080,
+	0x289e: 0x0080, 0x289f: 0x0080, 0x28a0: 0x00c0, 0x28a1: 0x00c0, 0x28a2: 0x00c0, 0x28a3: 0x00c0,
+	0x28a4: 0x00c0, 0x28a5: 0x00c0, 0x28a6: 0x00c0, 0x28a7: 0x00c0, 0x28a8: 0x00c0, 0x28a9: 0x00c0,
+	0x28aa: 0x00c0, 0x28ab: 0x00c0, 0x28ac: 0x00c0, 0x28ad: 0x00c0, 0x28ae: 0x00c0, 0x28af: 0x00c0,
+	0x28b0: 0x00c0, 0x28b1: 0x00c0, 0x28b2: 0x00c0, 0x28b3: 0x00c0, 0x28b4: 0x00c0, 0x28b5: 0x00c0,
+	0x28b6: 0x00c0, 0x28b7: 0x0080, 0x28b8: 0x0080, 0x28b9: 0x0080, 0x28ba: 0x00c0, 0x28bb: 0x00c0,
+	0x28bc: 0x00c3, 0x28bd: 0x00c0, 0x28be: 0x00c0, 0x28bf: 0x00c0,
+	// Block 0xa3, offset 0x28c0
+	0x28c0: 0x00c0, 0x28c1: 0x00c0, 0x28c2: 0x00c0, 0x28c3: 0x00c0, 0x28c4: 0x00c0, 0x28c5: 0x00c0,
+	0x28c6: 0x00c0, 0x28c7: 0x00c0, 0x28c8: 0x00c0, 0x28c9: 0x00c0, 0x28ca: 0x00c0, 0x28cb: 0x00c0,
+	0x28cc: 0x00c0, 0x28cd: 0x00c0, 0x28ce: 0x00c0, 0x28cf: 0x00c0, 0x28d0: 0x00c0, 0x28d1: 0x00c0,
+	0x28d2: 0x00c0, 0x28d3: 0x00c0, 0x28d4: 0x00c0, 0x28d5: 0x00c0, 0x28d6: 0x00c0, 0x28d7: 0x00c0,
+	0x28d8: 0x00c0, 0x28d9: 0x00c0, 0x28da: 0x00c0, 0x28db: 0x00c0, 0x28dc: 0x00c0, 0x28dd: 0x00c0,
+	0x28de: 0x00c0, 0x28df: 0x00c0, 0x28e0: 0x00c0, 0x28e1: 0x00c0, 0x28e2: 0x00c0, 0x28e3: 0x00c0,
+	0x28e4: 0x00c0, 0x28e5: 0x00c0, 0x28e6: 0x00c0, 0x28e7: 0x00c0, 0x28e8: 0x00c0, 0x28e9: 0x00c0,
+	0x28ea: 0x00c0, 0x28eb: 0x00c0, 0x28ec: 0x00c0, 0x28ed: 0x00c0, 0x28ee: 0x00c0, 0x28ef: 0x00c0,
+	0x28f0: 0x00c3, 0x28f1: 0x00c0, 0x28f2: 0x00c3, 0x28f3: 0x00c3, 0x28f4: 0x00c3, 0x28f5: 0x00c0,
+	0x28f6: 0x00c0, 0x28f7: 0x00c3, 0x28f8: 0x00c3, 0x28f9: 0x00c0, 0x28fa: 0x00c0, 0x28fb: 0x00c0,
+	0x28fc: 0x00c0, 0x28fd: 0x00c0, 0x28fe: 0x00c3, 0x28ff: 0x00c3,
+	// Block 0xa4, offset 0x2900
+	0x2900: 0x00c0, 0x2901: 0x00c3, 0x2902: 0x00c0,
+	0x291b: 0x00c0, 0x291c: 0x00c0, 0x291d: 0x00c0,
+	0x291e: 0x0080, 0x291f: 0x0080, 0x2920: 0x00c0, 0x2921: 0x00c0, 0x2922: 0x00c0, 0x2923: 0x00c0,
+	0x2924: 0x00c0, 0x2925: 0x00c0, 0x2926: 0x00c0, 0x2927: 0x00c0, 0x2928: 0x00c0, 0x2929: 0x00c0,
+	0x292a: 0x00c0, 0x292b: 0x00c0, 0x292c: 0x00c3, 0x292d: 0x00c3, 0x292e: 0x00c0, 0x292f: 0x00c0,
+	0x2930: 0x0080, 0x2931: 0x0080, 0x2932: 0x00c0, 0x2933: 0x00c0, 0x2934: 0x00c0, 0x2935: 0x00c0,
+	0x2936: 0x00c6,
+	// Block 0xa5, offset 0x2940
+	0x2941: 0x00c0, 0x2942: 0x00c0, 0x2943: 0x00c0, 0x2944: 0x00c0, 0x2945: 0x00c0,
+	0x2946: 0x00c0, 0x2949: 0x00c0, 0x294a: 0x00c0, 0x294b: 0x00c0,
+	0x294c: 0x00c0, 0x294d: 0x00c0, 0x294e: 0x00c0, 0x2951: 0x00c0,
+	0x2952: 0x00c0, 0x2953: 0x00c0, 0x2954: 0x00c0, 0x2955: 0x00c0, 0x2956: 0x00c0,
+	0x2960: 0x00c0, 0x2961: 0x00c0, 0x2962: 0x00c0, 0x2963: 0x00c0,
+	0x2964: 0x00c0, 0x2965: 0x00c0, 0x2966: 0x00c0, 0x2968: 0x00c0, 0x2969: 0x00c0,
+	0x296a: 0x00c0, 0x296b: 0x00c0, 0x296c: 0x00c0, 0x296d: 0x00c0, 0x296e: 0x00c0,
+	0x2970: 0x00c0, 0x2971: 0x00c0, 0x2972: 0x00c0, 0x2973: 0x00c0, 0x2974: 0x00c0, 0x2975: 0x00c0,
+	0x2976: 0x00c0, 0x2977: 0x00c0, 0x2978: 0x00c0, 0x2979: 0x00c0, 0x297a: 0x00c0, 0x297b: 0x00c0,
+	0x297c: 0x00c0, 0x297d: 0x00c0, 0x297e: 0x00c0, 0x297f: 0x00c0,
+	// Block 0xa6, offset 0x2980
+	0x2980: 0x00c0, 0x2981: 0x00c0, 0x2982: 0x00c0, 0x2983: 0x00c0, 0x2984: 0x00c0, 0x2985: 0x00c0,
+	0x2986: 0x00c0, 0x2987: 0x00c0, 0x2988: 0x00c0, 0x2989: 0x00c0, 0x298a: 0x00c0, 0x298b: 0x00c0,
+	0x298c: 0x00c0, 0x298d: 0x00c0, 0x298e: 0x00c0, 0x298f: 0x00c0, 0x2990: 0x00c0, 0x2991: 0x00c0,
+	0x2992: 0x00c0, 0x2993: 0x00c0, 0x2994: 0x00c0, 0x2995: 0x00c0, 0x2996: 0x00c0, 0x2997: 0x00c0,
+	0x2998: 0x00c0, 0x2999: 0x00c0, 0x299a: 0x00c0, 0x299b: 0x0080, 0x299c: 0x0080, 0x299d: 0x0080,
+	0x299e: 0x0080, 0x299f: 0x0080, 0x29a0: 0x00c0, 0x29a1: 0x00c0, 0x29a2: 0x00c0, 0x29a3: 0x00c0,
+	0x29a4: 0x00c0, 0x29a5: 0x00c8, 0x29a6: 0x00c0, 0x29a7: 0x00c0, 0x29a8: 0x00c0, 0x29a9: 0x0080,
+	0x29aa: 0x0080, 0x29ab: 0x0080,
+	0x29b0: 0x00c0, 0x29b1: 0x00c0, 0x29b2: 0x00c0, 0x29b3: 0x00c0, 0x29b4: 0x00c0, 0x29b5: 0x00c0,
+	0x29b6: 0x00c0, 0x29b7: 0x00c0, 0x29b8: 0x00c0, 0x29b9: 0x00c0, 0x29ba: 0x00c0, 0x29bb: 0x00c0,
+	0x29bc: 0x00c0, 0x29bd: 0x00c0, 0x29be: 0x00c0, 0x29bf: 0x00c0,
+	// Block 0xa7, offset 0x29c0
+	0x29c0: 0x00c0, 0x29c1: 0x00c0, 0x29c2: 0x00c0, 0x29c3: 0x00c0, 0x29c4: 0x00c0, 0x29c5: 0x00c0,
+	0x29c6: 0x00c0, 0x29c7: 0x00c0, 0x29c8: 0x00c0, 0x29c9: 0x00c0, 0x29ca: 0x00c0, 0x29cb: 0x00c0,
+	0x29cc: 0x00c0, 0x29cd: 0x00c0, 0x29ce: 0x00c0, 0x29cf: 0x00c0, 0x29d0: 0x00c0, 0x29d1: 0x00c0,
+	0x29d2: 0x00c0, 0x29d3: 0x00c0, 0x29d4: 0x00c0, 0x29d5: 0x00c0, 0x29d6: 0x00c0, 0x29d7: 0x00c0,
+	0x29d8: 0x00c0, 0x29d9: 0x00c0, 0x29da: 0x00c0, 0x29db: 0x00c0, 0x29dc: 0x00c0, 0x29dd: 0x00c0,
+	0x29de: 0x00c0, 0x29df: 0x00c0, 0x29e0: 0x00c0, 0x29e1: 0x00c0, 0x29e2: 0x00c0, 0x29e3: 0x00c0,
+	0x29e4: 0x00c0, 0x29e5: 0x00c3, 0x29e6: 0x00c0, 0x29e7: 0x00c0, 0x29e8: 0x00c3, 0x29e9: 0x00c0,
+	0x29ea: 0x00c0, 0x29eb: 0x0080, 0x29ec: 0x00c0, 0x29ed: 0x00c6,
+	0x29f0: 0x00c0, 0x29f1: 0x00c0, 0x29f2: 0x00c0, 0x29f3: 0x00c0, 0x29f4: 0x00c0, 0x29f5: 0x00c0,
+	0x29f6: 0x00c0, 0x29f7: 0x00c0, 0x29f8: 0x00c0, 0x29f9: 0x00c0,
+	// Block 0xa8, offset 0x2a00
+	0x2a00: 0x00c0, 0x2a01: 0x00c0, 0x2a02: 0x00c0, 0x2a03: 0x00c0, 0x2a04: 0x00c0, 0x2a05: 0x00c0,
+	0x2a06: 0x00c0, 0x2a07: 0x00c0, 0x2a08: 0x00c0, 0x2a09: 0x00c0, 0x2a0a: 0x00c0, 0x2a0b: 0x00c0,
+	0x2a0c: 0x00c0, 0x2a0d: 0x00c0, 0x2a0e: 0x00c0, 0x2a0f: 0x00c0, 0x2a10: 0x00c0, 0x2a11: 0x00c0,
+	0x2a12: 0x00c0, 0x2a13: 0x00c0, 0x2a14: 0x00c0, 0x2a15: 0x00c0, 0x2a16: 0x00c0, 0x2a17: 0x00c0,
+	0x2a18: 0x00c0, 0x2a19: 0x00c0, 0x2a1a: 0x00c0, 0x2a1b: 0x00c0, 0x2a1c: 0x00c0, 0x2a1d: 0x00c0,
+	0x2a1e: 0x00c0, 0x2a1f: 0x00c0, 0x2a20: 0x00c0, 0x2a21: 0x00c0, 0x2a22: 0x00c0, 0x2a23: 0x00c0,
+	0x2a30: 0x0040, 0x2a31: 0x0040, 0x2a32: 0x0040, 0x2a33: 0x0040, 0x2a34: 0x0040, 0x2a35: 0x0040,
+	0x2a36: 0x0040, 0x2a37: 0x0040, 0x2a38: 0x0040, 0x2a39: 0x0040, 0x2a3a: 0x0040, 0x2a3b: 0x0040,
+	0x2a3c: 0x0040, 0x2a3d: 0x0040, 0x2a3e: 0x0040, 0x2a3f: 0x0040,
+	// Block 0xa9, offset 0x2a40
+	0x2a40: 0x0040, 0x2a41: 0x0040, 0x2a42: 0x0040, 0x2a43: 0x0040, 0x2a44: 0x0040, 0x2a45: 0x0040,
+	0x2a46: 0x0040, 0x2a4b: 0x0040,
+	0x2a4c: 0x0040, 0x2a4d: 0x0040, 0x2a4e: 0x0040, 0x2a4f: 0x0040, 0x2a50: 0x0040, 0x2a51: 0x0040,
+	0x2a52: 0x0040, 0x2a53: 0x0040, 0x2a54: 0x0040, 0x2a55: 0x0040, 0x2a56: 0x0040, 0x2a57: 0x0040,
+	0x2a58: 0x0040, 0x2a59: 0x0040, 0x2a5a: 0x0040, 0x2a5b: 0x0040, 0x2a5c: 0x0040, 0x2a5d: 0x0040,
+	0x2a5e: 0x0040, 0x2a5f: 0x0040, 0x2a60: 0x0040, 0x2a61: 0x0040, 0x2a62: 0x0040, 0x2a63: 0x0040,
+	0x2a64: 0x0040, 0x2a65: 0x0040, 0x2a66: 0x0040, 0x2a67: 0x0040, 0x2a68: 0x0040, 0x2a69: 0x0040,
+	0x2a6a: 0x0040, 0x2a6b: 0x0040, 0x2a6c: 0x0040, 0x2a6d: 0x0040, 0x2a6e: 0x0040, 0x2a6f: 0x0040,
+	0x2a70: 0x0040, 0x2a71: 0x0040, 0x2a72: 0x0040, 0x2a73: 0x0040, 0x2a74: 0x0040, 0x2a75: 0x0040,
+	0x2a76: 0x0040, 0x2a77: 0x0040, 0x2a78: 0x0040, 0x2a79: 0x0040, 0x2a7a: 0x0040, 0x2a7b: 0x0040,
+	// Block 0xaa, offset 0x2a80
+	0x2a80: 0x008c, 0x2a81: 0x008c, 0x2a82: 0x008c, 0x2a83: 0x008c, 0x2a84: 0x008c, 0x2a85: 0x008c,
+	0x2a86: 0x008c, 0x2a87: 0x008c, 0x2a88: 0x008c, 0x2a89: 0x008c, 0x2a8a: 0x008c, 0x2a8b: 0x008c,
+	0x2a8c: 0x008c, 0x2a8d: 0x008c, 0x2a8e: 0x00cc, 0x2a8f: 0x00cc, 0x2a90: 0x008c, 0x2a91: 0x00cc,
+	0x2a92: 0x008c, 0x2a93: 0x00cc, 0x2a94: 0x00cc, 0x2a95: 0x008c, 0x2a96: 0x008c, 0x2a97: 0x008c,
+	0x2a98: 0x008c, 0x2a99: 0x008c, 0x2a9a: 0x008c, 0x2a9b: 0x008c, 0x2a9c: 0x008c, 0x2a9d: 0x008c,
+	0x2a9e: 0x008c, 0x2a9f: 0x00cc, 0x2aa0: 0x008c, 0x2aa1: 0x00cc, 0x2aa2: 0x008c, 0x2aa3: 0x00cc,
+	0x2aa4: 0x00cc, 0x2aa5: 0x008c, 0x2aa6: 0x008c, 0x2aa7: 0x00cc, 0x2aa8: 0x00cc, 0x2aa9: 0x00cc,
+	0x2aaa: 0x008c, 0x2aab: 0x008c, 0x2aac: 0x008c, 0x2aad: 0x008c, 0x2aae: 0x008c, 0x2aaf: 0x008c,
+	0x2ab0: 0x008c, 0x2ab1: 0x008c, 0x2ab2: 0x008c, 0x2ab3: 0x008c, 0x2ab4: 0x008c, 0x2ab5: 0x008c,
+	0x2ab6: 0x008c, 0x2ab7: 0x008c, 0x2ab8: 0x008c, 0x2ab9: 0x008c, 0x2aba: 0x008c, 0x2abb: 0x008c,
+	0x2abc: 0x008c, 0x2abd: 0x008c, 0x2abe: 0x008c, 0x2abf: 0x008c,
+	// Block 0xab, offset 0x2ac0
+	0x2ac0: 0x008c, 0x2ac1: 0x008c, 0x2ac2: 0x008c, 0x2ac3: 0x008c, 0x2ac4: 0x008c, 0x2ac5: 0x008c,
+	0x2ac6: 0x008c, 0x2ac7: 0x008c, 0x2ac8: 0x008c, 0x2ac9: 0x008c, 0x2aca: 0x008c, 0x2acb: 0x008c,
+	0x2acc: 0x008c, 0x2acd: 0x008c, 0x2ace: 0x008c, 0x2acf: 0x008c, 0x2ad0: 0x008c, 0x2ad1: 0x008c,
+	0x2ad2: 0x008c, 0x2ad3: 0x008c, 0x2ad4: 0x008c, 0x2ad5: 0x008c, 0x2ad6: 0x008c, 0x2ad7: 0x008c,
+	0x2ad8: 0x008c, 0x2ad9: 0x008c, 0x2ada: 0x008c, 0x2adb: 0x008c, 0x2adc: 0x008c, 0x2add: 0x008c,
+	0x2ade: 0x008c, 0x2adf: 0x008c, 0x2ae0: 0x008c, 0x2ae1: 0x008c, 0x2ae2: 0x008c, 0x2ae3: 0x008c,
+	0x2ae4: 0x008c, 0x2ae5: 0x008c, 0x2ae6: 0x008c, 0x2ae7: 0x008c, 0x2ae8: 0x008c, 0x2ae9: 0x008c,
+	0x2aea: 0x008c, 0x2aeb: 0x008c, 0x2aec: 0x008c, 0x2aed: 0x008c,
+	0x2af0: 0x008c, 0x2af1: 0x008c, 0x2af2: 0x008c, 0x2af3: 0x008c, 0x2af4: 0x008c, 0x2af5: 0x008c,
+	0x2af6: 0x008c, 0x2af7: 0x008c, 0x2af8: 0x008c, 0x2af9: 0x008c, 0x2afa: 0x008c, 0x2afb: 0x008c,
+	0x2afc: 0x008c, 0x2afd: 0x008c, 0x2afe: 0x008c, 0x2aff: 0x008c,
+	// Block 0xac, offset 0x2b00
+	0x2b00: 0x008c, 0x2b01: 0x008c, 0x2b02: 0x008c, 0x2b03: 0x008c, 0x2b04: 0x008c, 0x2b05: 0x008c,
+	0x2b06: 0x008c, 0x2b07: 0x008c, 0x2b08: 0x008c, 0x2b09: 0x008c, 0x2b0a: 0x008c, 0x2b0b: 0x008c,
+	0x2b0c: 0x008c, 0x2b0d: 0x008c, 0x2b0e: 0x008c, 0x2b0f: 0x008c, 0x2b10: 0x008c, 0x2b11: 0x008c,
+	0x2b12: 0x008c, 0x2b13: 0x008c, 0x2b14: 0x008c, 0x2b15: 0x008c, 0x2b16: 0x008c, 0x2b17: 0x008c,
+	0x2b18: 0x008c, 0x2b19: 0x008c,
+	// Block 0xad, offset 0x2b40
+	0x2b40: 0x0080, 0x2b41: 0x0080, 0x2b42: 0x0080, 0x2b43: 0x0080, 0x2b44: 0x0080, 0x2b45: 0x0080,
+	0x2b46: 0x0080,
+	0x2b53: 0x0080, 0x2b54: 0x0080, 0x2b55: 0x0080, 0x2b56: 0x0080, 0x2b57: 0x0080,
+	0x2b5d: 0x008a,
+	0x2b5e: 0x00cb, 0x2b5f: 0x008a, 0x2b60: 0x008a, 0x2b61: 0x008a, 0x2b62: 0x008a, 0x2b63: 0x008a,
+	0x2b64: 0x008a, 0x2b65: 0x008a, 0x2b66: 0x008a, 0x2b67: 0x008a, 0x2b68: 0x008a, 0x2b69: 0x008a,
+	0x2b6a: 0x008a, 0x2b6b: 0x008a, 0x2b6c: 0x008a, 0x2b6d: 0x008a, 0x2b6e: 0x008a, 0x2b6f: 0x008a,
+	0x2b70: 0x008a, 0x2b71: 0x008a, 0x2b72: 0x008a, 0x2b73: 0x008a, 0x2b74: 0x008a, 0x2b75: 0x008a,
+	0x2b76: 0x008a, 0x2b78: 0x008a, 0x2b79: 0x008a, 0x2b7a: 0x008a, 0x2b7b: 0x008a,
+	0x2b7c: 0x008a, 0x2b7e: 0x008a,
+	// Block 0xae, offset 0x2b80
+	0x2b80: 0x008a, 0x2b81: 0x008a, 0x2b83: 0x008a, 0x2b84: 0x008a,
+	0x2b86: 0x008a, 0x2b87: 0x008a, 0x2b88: 0x008a, 0x2b89: 0x008a, 0x2b8a: 0x008a, 0x2b8b: 0x008a,
+	0x2b8c: 0x008a, 0x2b8d: 0x008a, 0x2b8e: 0x008a, 0x2b8f: 0x008a, 0x2b90: 0x0080, 0x2b91: 0x0080,
+	0x2b92: 0x0080, 0x2b93: 0x0080, 0x2b94: 0x0080, 0x2b95: 0x0080, 0x2b96: 0x0080, 0x2b97: 0x0080,
+	0x2b98: 0x0080, 0x2b99: 0x0080, 0x2b9a: 0x0080, 0x2b9b: 0x0080, 0x2b9c: 0x0080, 0x2b9d: 0x0080,
+	0x2b9e: 0x0080, 0x2b9f: 0x0080, 0x2ba0: 0x0080, 0x2ba1: 0x0080, 0x2ba2: 0x0080, 0x2ba3: 0x0080,
+	0x2ba4: 0x0080, 0x2ba5: 0x0080, 0x2ba6: 0x0080, 0x2ba7: 0x0080, 0x2ba8: 0x0080, 0x2ba9: 0x0080,
+	0x2baa: 0x0080, 0x2bab: 0x0080, 0x2bac: 0x0080, 0x2bad: 0x0080, 0x2bae: 0x0080, 0x2baf: 0x0080,
+	0x2bb0: 0x0080, 0x2bb1: 0x0080, 0x2bb2: 0x0080, 0x2bb3: 0x0080, 0x2bb4: 0x0080, 0x2bb5: 0x0080,
+	0x2bb6: 0x0080, 0x2bb7: 0x0080, 0x2bb8: 0x0080, 0x2bb9: 0x0080, 0x2bba: 0x0080, 0x2bbb: 0x0080,
+	0x2bbc: 0x0080, 0x2bbd: 0x0080, 0x2bbe: 0x0080, 0x2bbf: 0x0080,
+	// Block 0xaf, offset 0x2bc0
+	0x2bc0: 0x0080, 0x2bc1: 0x0080, 0x2bc2: 0x0080,
+	0x2bd3: 0x0080, 0x2bd4: 0x0080, 0x2bd5: 0x0080, 0x2bd6: 0x0080, 0x2bd7: 0x0080,
+	0x2bd8: 0x0080, 0x2bd9: 0x0080, 0x2bda: 0x0080, 0x2bdb: 0x0080, 0x2bdc: 0x0080, 0x2bdd: 0x0080,
+	0x2bde: 0x0080, 0x2bdf: 0x0080, 0x2be0: 0x0080, 0x2be1: 0x0080, 0x2be2: 0x0080, 0x2be3: 0x0080,
+	0x2be4: 0x0080, 0x2be5: 0x0080, 0x2be6: 0x0080, 0x2be7: 0x0080, 0x2be8: 0x0080, 0x2be9: 0x0080,
+	0x2bea: 0x0080, 0x2beb: 0x0080, 0x2bec: 0x0080, 0x2bed: 0x0080, 0x2bee: 0x0080, 0x2bef: 0x0080,
+	0x2bf0: 0x0080, 0x2bf1: 0x0080, 0x2bf2: 0x0080, 0x2bf3: 0x0080, 0x2bf4: 0x0080, 0x2bf5: 0x0080,
+	0x2bf6: 0x0080, 0x2bf7: 0x0080, 0x2bf8: 0x0080, 0x2bf9: 0x0080, 0x2bfa: 0x0080, 0x2bfb: 0x0080,
+	0x2bfc: 0x0080, 0x2bfd: 0x0080, 0x2bfe: 0x0080, 0x2bff: 0x0080,
+	// Block 0xb0, offset 0x2c00
+	0x2c00: 0x0080, 0x2c01: 0x0080, 0x2c02: 0x0080, 0x2c03: 0x0080, 0x2c04: 0x0080, 0x2c05: 0x0080,
+	0x2c06: 0x0080, 0x2c07: 0x0080, 0x2c08: 0x0080, 0x2c09: 0x0080, 0x2c0a: 0x0080, 0x2c0b: 0x0080,
+	0x2c0c: 0x0080, 0x2c0d: 0x0080, 0x2c0e: 0x0080, 0x2c0f: 0x0080,
+	0x2c12: 0x0080, 0x2c13: 0x0080, 0x2c14: 0x0080, 0x2c15: 0x0080, 0x2c16: 0x0080, 0x2c17: 0x0080,
+	0x2c18: 0x0080, 0x2c19: 0x0080, 0x2c1a: 0x0080, 0x2c1b: 0x0080, 0x2c1c: 0x0080, 0x2c1d: 0x0080,
+	0x2c1e: 0x0080, 0x2c1f: 0x0080, 0x2c20: 0x0080, 0x2c21: 0x0080, 0x2c22: 0x0080, 0x2c23: 0x0080,
+	0x2c24: 0x0080, 0x2c25: 0x0080, 0x2c26: 0x0080, 0x2c27: 0x0080, 0x2c28: 0x0080, 0x2c29: 0x0080,
+	0x2c2a: 0x0080, 0x2c2b: 0x0080, 0x2c2c: 0x0080, 0x2c2d: 0x0080, 0x2c2e: 0x0080, 0x2c2f: 0x0080,
+	0x2c30: 0x0080, 0x2c31: 0x0080, 0x2c32: 0x0080, 0x2c33: 0x0080, 0x2c34: 0x0080, 0x2c35: 0x0080,
+	0x2c36: 0x0080, 0x2c37: 0x0080, 0x2c38: 0x0080, 0x2c39: 0x0080, 0x2c3a: 0x0080, 0x2c3b: 0x0080,
+	0x2c3c: 0x0080, 0x2c3d: 0x0080, 0x2c3e: 0x0080, 0x2c3f: 0x0080,
+	// Block 0xb1, offset 0x2c40
+	0x2c40: 0x0080, 0x2c41: 0x0080, 0x2c42: 0x0080, 0x2c43: 0x0080, 0x2c44: 0x0080, 0x2c45: 0x0080,
+	0x2c46: 0x0080, 0x2c47: 0x0080,
+	0x2c4f: 0x0080,
+	0x2c70: 0x0080, 0x2c71: 0x0080, 0x2c72: 0x0080, 0x2c73: 0x0080, 0x2c74: 0x0080, 0x2c75: 0x0080,
+	0x2c76: 0x0080, 0x2c77: 0x0080, 0x2c78: 0x0080, 0x2c79: 0x0080, 0x2c7a: 0x0080, 0x2c7b: 0x0080,
+	0x2c7c: 0x0080, 0x2c7d: 0x0080, 0x2c7e: 0x0080, 0x2c7f: 0x0080,
+	// Block 0xb2, offset 0x2c80
+	0x2c80: 0x0040, 0x2c81: 0x0040, 0x2c82: 0x0040, 0x2c83: 0x0040, 0x2c84: 0x0040, 0x2c85: 0x0040,
+	0x2c86: 0x0040, 0x2c87: 0x0040, 0x2c88: 0x0040, 0x2c89: 0x0040, 0x2c8a: 0x0040, 0x2c8b: 0x0040,
+	0x2c8c: 0x0040, 0x2c8d: 0x0040, 0x2c8e: 0x0040, 0x2c8f: 0x0040, 0x2c90: 0x0080, 0x2c91: 0x0080,
+	0x2c92: 0x0080, 0x2c93: 0x0080, 0x2c94: 0x0080, 0x2c95: 0x0080, 0x2c96: 0x0080, 0x2c97: 0x0080,
+	0x2c98: 0x0080, 0x2c99: 0x0080,
+	0x2ca0: 0x00c3, 0x2ca1: 0x00c3, 0x2ca2: 0x00c3, 0x2ca3: 0x00c3,
+	0x2ca4: 0x00c3, 0x2ca5: 0x00c3, 0x2ca6: 0x00c3, 0x2ca7: 0x00c3, 0x2ca8: 0x00c3, 0x2ca9: 0x00c3,
+	0x2caa: 0x00c3, 0x2cab: 0x00c3, 0x2cac: 0x00c3, 0x2cad: 0x00c3, 0x2cae: 0x00c3, 0x2caf: 0x00c3,
+	0x2cb0: 0x0080, 0x2cb1: 0x0080, 0x2cb2: 0x0080, 0x2cb3: 0x0080, 0x2cb4: 0x0080, 0x2cb5: 0x0080,
+	0x2cb6: 0x0080, 0x2cb7: 0x0080, 0x2cb8: 0x0080, 0x2cb9: 0x0080, 0x2cba: 0x0080, 0x2cbb: 0x0080,
+	0x2cbc: 0x0080, 0x2cbd: 0x0080, 0x2cbe: 0x0080, 0x2cbf: 0x0080,
+	// Block 0xb3, offset 0x2cc0
+	0x2cc0: 0x0080, 0x2cc1: 0x0080, 0x2cc2: 0x0080, 0x2cc3: 0x0080, 0x2cc4: 0x0080, 0x2cc5: 0x0080,
+	0x2cc6: 0x0080, 0x2cc7: 0x0080, 0x2cc8: 0x0080, 0x2cc9: 0x0080, 0x2cca: 0x0080, 0x2ccb: 0x0080,
+	0x2ccc: 0x0080, 0x2ccd: 0x0080, 0x2cce: 0x0080, 0x2ccf: 0x0080, 0x2cd0: 0x0080, 0x2cd1: 0x0080,
+	0x2cd2: 0x0080, 0x2cd4: 0x0080, 0x2cd5: 0x0080, 0x2cd6: 0x0080, 0x2cd7: 0x0080,
+	0x2cd8: 0x0080, 0x2cd9: 0x0080, 0x2cda: 0x0080, 0x2cdb: 0x0080, 0x2cdc: 0x0080, 0x2cdd: 0x0080,
+	0x2cde: 0x0080, 0x2cdf: 0x0080, 0x2ce0: 0x0080, 0x2ce1: 0x0080, 0x2ce2: 0x0080, 0x2ce3: 0x0080,
+	0x2ce4: 0x0080, 0x2ce5: 0x0080, 0x2ce6: 0x0080, 0x2ce8: 0x0080, 0x2ce9: 0x0080,
+	0x2cea: 0x0080, 0x2ceb: 0x0080,
+	0x2cf0: 0x0080, 0x2cf1: 0x0080, 0x2cf2: 0x0080, 0x2cf3: 0x00c0, 0x2cf4: 0x0080,
+	0x2cf6: 0x0080, 0x2cf7: 0x0080, 0x2cf8: 0x0080, 0x2cf9: 0x0080, 0x2cfa: 0x0080, 0x2cfb: 0x0080,
+	0x2cfc: 0x0080, 0x2cfd: 0x0080, 0x2cfe: 0x0080, 0x2cff: 0x0080,
+	// Block 0xb4, offset 0x2d00
+	0x2d00: 0x0080, 0x2d01: 0x0080, 0x2d02: 0x0080, 0x2d03: 0x0080, 0x2d04: 0x0080, 0x2d05: 0x0080,
+	0x2d06: 0x0080, 0x2d07: 0x0080, 0x2d08: 0x0080, 0x2d09: 0x0080, 0x2d0a: 0x0080, 0x2d0b: 0x0080,
+	0x2d0c: 0x0080, 0x2d0d: 0x0080, 0x2d0e: 0x0080, 0x2d0f: 0x0080, 0x2d10: 0x0080, 0x2d11: 0x0080,
+	0x2d12: 0x0080, 0x2d13: 0x0080, 0x2d14: 0x0080, 0x2d15: 0x0080, 0x2d16: 0x0080, 0x2d17: 0x0080,
+	0x2d18: 0x0080, 0x2d19: 0x0080, 0x2d1a: 0x0080, 0x2d1b: 0x0080, 0x2d1c: 0x0080, 0x2d1d: 0x0080,
+	0x2d1e: 0x0080, 0x2d1f: 0x0080, 0x2d20: 0x0080, 0x2d21: 0x0080, 0x2d22: 0x0080, 0x2d23: 0x0080,
+	0x2d24: 0x0080, 0x2d25: 0x0080, 0x2d26: 0x0080, 0x2d27: 0x0080, 0x2d28: 0x0080, 0x2d29: 0x0080,
+	0x2d2a: 0x0080, 0x2d2b: 0x0080, 0x2d2c: 0x0080, 0x2d2d: 0x0080, 0x2d2e: 0x0080, 0x2d2f: 0x0080,
+	0x2d30: 0x0080, 0x2d31: 0x0080, 0x2d32: 0x0080, 0x2d33: 0x0080, 0x2d34: 0x0080, 0x2d35: 0x0080,
+	0x2d36: 0x0080, 0x2d37: 0x0080, 0x2d38: 0x0080, 0x2d39: 0x0080, 0x2d3a: 0x0080, 0x2d3b: 0x0080,
+	0x2d3c: 0x0080, 0x2d3f: 0x0040,
+	// Block 0xb5, offset 0x2d40
+	0x2d41: 0x0080, 0x2d42: 0x0080, 0x2d43: 0x0080, 0x2d44: 0x0080, 0x2d45: 0x0080,
+	0x2d46: 0x0080, 0x2d47: 0x0080, 0x2d48: 0x0080, 0x2d49: 0x0080, 0x2d4a: 0x0080, 0x2d4b: 0x0080,
+	0x2d4c: 0x0080, 0x2d4d: 0x0080, 0x2d4e: 0x0080, 0x2d4f: 0x0080, 0x2d50: 0x0080, 0x2d51: 0x0080,
+	0x2d52: 0x0080, 0x2d53: 0x0080, 0x2d54: 0x0080, 0x2d55: 0x0080, 0x2d56: 0x0080, 0x2d57: 0x0080,
+	0x2d58: 0x0080, 0x2d59: 0x0080, 0x2d5a: 0x0080, 0x2d5b: 0x0080, 0x2d5c: 0x0080, 0x2d5d: 0x0080,
+	0x2d5e: 0x0080, 0x2d5f: 0x0080, 0x2d60: 0x0080, 0x2d61: 0x0080, 0x2d62: 0x0080, 0x2d63: 0x0080,
+	0x2d64: 0x0080, 0x2d65: 0x0080, 0x2d66: 0x0080, 0x2d67: 0x0080, 0x2d68: 0x0080, 0x2d69: 0x0080,
+	0x2d6a: 0x0080, 0x2d6b: 0x0080, 0x2d6c: 0x0080, 0x2d6d: 0x0080, 0x2d6e: 0x0080, 0x2d6f: 0x0080,
+	0x2d70: 0x0080, 0x2d71: 0x0080, 0x2d72: 0x0080, 0x2d73: 0x0080, 0x2d74: 0x0080, 0x2d75: 0x0080,
+	0x2d76: 0x0080, 0x2d77: 0x0080, 0x2d78: 0x0080, 0x2d79: 0x0080, 0x2d7a: 0x0080, 0x2d7b: 0x0080,
+	0x2d7c: 0x0080, 0x2d7d: 0x0080, 0x2d7e: 0x0080, 0x2d7f: 0x0080,
+	// Block 0xb6, offset 0x2d80
+	0x2d80: 0x0080, 0x2d81: 0x0080, 0x2d82: 0x0080, 0x2d83: 0x0080, 0x2d84: 0x0080, 0x2d85: 0x0080,
+	0x2d86: 0x0080, 0x2d87: 0x0080, 0x2d88: 0x0080, 0x2d89: 0x0080, 0x2d8a: 0x0080, 0x2d8b: 0x0080,
+	0x2d8c: 0x0080, 0x2d8d: 0x0080, 0x2d8e: 0x0080, 0x2d8f: 0x0080, 0x2d90: 0x0080, 0x2d91: 0x0080,
+	0x2d92: 0x0080, 0x2d93: 0x0080, 0x2d94: 0x0080, 0x2d95: 0x0080, 0x2d96: 0x0080, 0x2d97: 0x0080,
+	0x2d98: 0x0080, 0x2d99: 0x0080, 0x2d9a: 0x0080, 0x2d9b: 0x0080, 0x2d9c: 0x0080, 0x2d9d: 0x0080,
+	0x2d9e: 0x0080, 0x2d9f: 0x0080, 0x2da0: 0x0080, 0x2da1: 0x0080, 0x2da2: 0x0080, 0x2da3: 0x0080,
+	0x2da4: 0x0080, 0x2da5: 0x0080, 0x2da6: 0x008c, 0x2da7: 0x008c, 0x2da8: 0x008c, 0x2da9: 0x008c,
+	0x2daa: 0x008c, 0x2dab: 0x008c, 0x2dac: 0x008c, 0x2dad: 0x008c, 0x2dae: 0x008c, 0x2daf: 0x008c,
+	0x2db0: 0x0080, 0x2db1: 0x008c, 0x2db2: 0x008c, 0x2db3: 0x008c, 0x2db4: 0x008c, 0x2db5: 0x008c,
+	0x2db6: 0x008c, 0x2db7: 0x008c, 0x2db8: 0x008c, 0x2db9: 0x008c, 0x2dba: 0x008c, 0x2dbb: 0x008c,
+	0x2dbc: 0x008c, 0x2dbd: 0x008c, 0x2dbe: 0x008c, 0x2dbf: 0x008c,
+	// Block 0xb7, offset 0x2dc0
+	0x2dc0: 0x008c, 0x2dc1: 0x008c, 0x2dc2: 0x008c, 0x2dc3: 0x008c, 0x2dc4: 0x008c, 0x2dc5: 0x008c,
+	0x2dc6: 0x008c, 0x2dc7: 0x008c, 0x2dc8: 0x008c, 0x2dc9: 0x008c, 0x2dca: 0x008c, 0x2dcb: 0x008c,
+	0x2dcc: 0x008c, 0x2dcd: 0x008c, 0x2dce: 0x008c, 0x2dcf: 0x008c, 0x2dd0: 0x008c, 0x2dd1: 0x008c,
+	0x2dd2: 0x008c, 0x2dd3: 0x008c, 0x2dd4: 0x008c, 0x2dd5: 0x008c, 0x2dd6: 0x008c, 0x2dd7: 0x008c,
+	0x2dd8: 0x008c, 0x2dd9: 0x008c, 0x2dda: 0x008c, 0x2ddb: 0x008c, 0x2ddc: 0x008c, 0x2ddd: 0x008c,
+	0x2dde: 0x0080, 0x2ddf: 0x0080, 0x2de0: 0x0040, 0x2de1: 0x0080, 0x2de2: 0x0080, 0x2de3: 0x0080,
+	0x2de4: 0x0080, 0x2de5: 0x0080, 0x2de6: 0x0080, 0x2de7: 0x0080, 0x2de8: 0x0080, 0x2de9: 0x0080,
+	0x2dea: 0x0080, 0x2deb: 0x0080, 0x2dec: 0x0080, 0x2ded: 0x0080, 0x2dee: 0x0080, 0x2def: 0x0080,
+	0x2df0: 0x0080, 0x2df1: 0x0080, 0x2df2: 0x0080, 0x2df3: 0x0080, 0x2df4: 0x0080, 0x2df5: 0x0080,
+	0x2df6: 0x0080, 0x2df7: 0x0080, 0x2df8: 0x0080, 0x2df9: 0x0080, 0x2dfa: 0x0080, 0x2dfb: 0x0080,
+	0x2dfc: 0x0080, 0x2dfd: 0x0080, 0x2dfe: 0x0080,
+	// Block 0xb8, offset 0x2e00
+	0x2e02: 0x0080, 0x2e03: 0x0080, 0x2e04: 0x0080, 0x2e05: 0x0080,
+	0x2e06: 0x0080, 0x2e07: 0x0080, 0x2e0a: 0x0080, 0x2e0b: 0x0080,
+	0x2e0c: 0x0080, 0x2e0d: 0x0080, 0x2e0e: 0x0080, 0x2e0f: 0x0080,
+	0x2e12: 0x0080, 0x2e13: 0x0080, 0x2e14: 0x0080, 0x2e15: 0x0080, 0x2e16: 0x0080, 0x2e17: 0x0080,
+	0x2e1a: 0x0080, 0x2e1b: 0x0080, 0x2e1c: 0x0080,
+	0x2e20: 0x0080, 0x2e21: 0x0080, 0x2e22: 0x0080, 0x2e23: 0x0080,
+	0x2e24: 0x0080, 0x2e25: 0x0080, 0x2e26: 0x0080, 0x2e28: 0x0080, 0x2e29: 0x0080,
+	0x2e2a: 0x0080, 0x2e2b: 0x0080, 0x2e2c: 0x0080, 0x2e2d: 0x0080, 0x2e2e: 0x0080,
+	0x2e39: 0x0040, 0x2e3a: 0x0040, 0x2e3b: 0x0040,
+	0x2e3c: 0x0080, 0x2e3d: 0x0080,
+	// Block 0xb9, offset 0x2e40
+	0x2e40: 0x00c0, 0x2e41: 0x00c0, 0x2e42: 0x00c0, 0x2e43: 0x00c0, 0x2e44: 0x00c0, 0x2e45: 0x00c0,
+	0x2e46: 0x00c0, 0x2e47: 0x00c0, 0x2e48: 0x00c0, 0x2e49: 0x00c0, 0x2e4a: 0x00c0, 0x2e4b: 0x00c0,
+	0x2e4d: 0x00c0, 0x2e4e: 0x00c0, 0x2e4f: 0x00c0, 0x2e50: 0x00c0, 0x2e51: 0x00c0,
+	0x2e52: 0x00c0, 0x2e53: 0x00c0, 0x2e54: 0x00c0, 0x2e55: 0x00c0, 0x2e56: 0x00c0, 0x2e57: 0x00c0,
+	0x2e58: 0x00c0, 0x2e59: 0x00c0, 0x2e5a: 0x00c0, 0x2e5b: 0x00c0, 0x2e5c: 0x00c0, 0x2e5d: 0x00c0,
+	0x2e5e: 0x00c0, 0x2e5f: 0x00c0, 0x2e60: 0x00c0, 0x2e61: 0x00c0, 0x2e62: 0x00c0, 0x2e63: 0x00c0,
+	0x2e64: 0x00c0, 0x2e65: 0x00c0, 0x2e66: 0x00c0, 0x2e68: 0x00c0, 0x2e69: 0x00c0,
+	0x2e6a: 0x00c0, 0x2e6b: 0x00c0, 0x2e6c: 0x00c0, 0x2e6d: 0x00c0, 0x2e6e: 0x00c0, 0x2e6f: 0x00c0,
+	0x2e70: 0x00c0, 0x2e71: 0x00c0, 0x2e72: 0x00c0, 0x2e73: 0x00c0, 0x2e74: 0x00c0, 0x2e75: 0x00c0,
+	0x2e76: 0x00c0, 0x2e77: 0x00c0, 0x2e78: 0x00c0, 0x2e79: 0x00c0, 0x2e7a: 0x00c0,
+	0x2e7c: 0x00c0, 0x2e7d: 0x00c0, 0x2e7f: 0x00c0,
+	// Block 0xba, offset 0x2e80
+	0x2e80: 0x00c0, 0x2e81: 0x00c0, 0x2e82: 0x00c0, 0x2e83: 0x00c0, 0x2e84: 0x00c0, 0x2e85: 0x00c0,
+	0x2e86: 0x00c0, 0x2e87: 0x00c0, 0x2e88: 0x00c0, 0x2e89: 0x00c0, 0x2e8a: 0x00c0, 0x2e8b: 0x00c0,
+	0x2e8c: 0x00c0, 0x2e8d: 0x00c0, 0x2e90: 0x00c0, 0x2e91: 0x00c0,
+	0x2e92: 0x00c0, 0x2e93: 0x00c0, 0x2e94: 0x00c0, 0x2e95: 0x00c0, 0x2e96: 0x00c0, 0x2e97: 0x00c0,
+	0x2e98: 0x00c0, 0x2e99: 0x00c0, 0x2e9a: 0x00c0, 0x2e9b: 0x00c0, 0x2e9c: 0x00c0, 0x2e9d: 0x00c0,
+	// Block 0xbb, offset 0x2ec0
+	0x2ec0: 0x00c0, 0x2ec1: 0x00c0, 0x2ec2: 0x00c0, 0x2ec3: 0x00c0, 0x2ec4: 0x00c0, 0x2ec5: 0x00c0,
+	0x2ec6: 0x00c0, 0x2ec7: 0x00c0, 0x2ec8: 0x00c0, 0x2ec9: 0x00c0, 0x2eca: 0x00c0, 0x2ecb: 0x00c0,
+	0x2ecc: 0x00c0, 0x2ecd: 0x00c0, 0x2ece: 0x00c0, 0x2ecf: 0x00c0, 0x2ed0: 0x00c0, 0x2ed1: 0x00c0,
+	0x2ed2: 0x00c0, 0x2ed3: 0x00c0, 0x2ed4: 0x00c0, 0x2ed5: 0x00c0, 0x2ed6: 0x00c0, 0x2ed7: 0x00c0,
+	0x2ed8: 0x00c0, 0x2ed9: 0x00c0, 0x2eda: 0x00c0, 0x2edb: 0x00c0, 0x2edc: 0x00c0, 0x2edd: 0x00c0,
+	0x2ede: 0x00c0, 0x2edf: 0x00c0, 0x2ee0: 0x00c0, 0x2ee1: 0x00c0, 0x2ee2: 0x00c0, 0x2ee3: 0x00c0,
+	0x2ee4: 0x00c0, 0x2ee5: 0x00c0, 0x2ee6: 0x00c0, 0x2ee7: 0x00c0, 0x2ee8: 0x00c0, 0x2ee9: 0x00c0,
+	0x2eea: 0x00c0, 0x2eeb: 0x00c0, 0x2eec: 0x00c0, 0x2eed: 0x00c0, 0x2eee: 0x00c0, 0x2eef: 0x00c0,
+	0x2ef0: 0x00c0, 0x2ef1: 0x00c0, 0x2ef2: 0x00c0, 0x2ef3: 0x00c0, 0x2ef4: 0x00c0, 0x2ef5: 0x00c0,
+	0x2ef6: 0x00c0, 0x2ef7: 0x00c0, 0x2ef8: 0x00c0, 0x2ef9: 0x00c0, 0x2efa: 0x00c0,
+	// Block 0xbc, offset 0x2f00
+	0x2f00: 0x0080, 0x2f01: 0x0080, 0x2f02: 0x0080,
+	0x2f07: 0x0080, 0x2f08: 0x0080, 0x2f09: 0x0080, 0x2f0a: 0x0080, 0x2f0b: 0x0080,
+	0x2f0c: 0x0080, 0x2f0d: 0x0080, 0x2f0e: 0x0080, 0x2f0f: 0x0080, 0x2f10: 0x0080, 0x2f11: 0x0080,
+	0x2f12: 0x0080, 0x2f13: 0x0080, 0x2f14: 0x0080, 0x2f15: 0x0080, 0x2f16: 0x0080, 0x2f17: 0x0080,
+	0x2f18: 0x0080, 0x2f19: 0x0080, 0x2f1a: 0x0080, 0x2f1b: 0x0080, 0x2f1c: 0x0080, 0x2f1d: 0x0080,
+	0x2f1e: 0x0080, 0x2f1f: 0x0080, 0x2f20: 0x0080, 0x2f21: 0x0080, 0x2f22: 0x0080, 0x2f23: 0x0080,
+	0x2f24: 0x0080, 0x2f25: 0x0080, 0x2f26: 0x0080, 0x2f27: 0x0080, 0x2f28: 0x0080, 0x2f29: 0x0080,
+	0x2f2a: 0x0080, 0x2f2b: 0x0080, 0x2f2c: 0x0080, 0x2f2d: 0x0080, 0x2f2e: 0x0080, 0x2f2f: 0x0080,
+	0x2f30: 0x0080, 0x2f31: 0x0080, 0x2f32: 0x0080, 0x2f33: 0x0080,
+	0x2f37: 0x0080, 0x2f38: 0x0080, 0x2f39: 0x0080, 0x2f3a: 0x0080, 0x2f3b: 0x0080,
+	0x2f3c: 0x0080, 0x2f3d: 0x0080, 0x2f3e: 0x0080, 0x2f3f: 0x0080,
+	// Block 0xbd, offset 0x2f40
+	0x2f40: 0x0088, 0x2f41: 0x0088, 0x2f42: 0x0088, 0x2f43: 0x0088, 0x2f44: 0x0088, 0x2f45: 0x0088,
+	0x2f46: 0x0088, 0x2f47: 0x0088, 0x2f48: 0x0088, 0x2f49: 0x0088, 0x2f4a: 0x0088, 0x2f4b: 0x0088,
+	0x2f4c: 0x0088, 0x2f4d: 0x0088, 0x2f4e: 0x0088, 0x2f4f: 0x0088, 0x2f50: 0x0088, 0x2f51: 0x0088,
+	0x2f52: 0x0088, 0x2f53: 0x0088, 0x2f54: 0x0088, 0x2f55: 0x0088, 0x2f56: 0x0088, 0x2f57: 0x0088,
+	0x2f58: 0x0088, 0x2f59: 0x0088, 0x2f5a: 0x0088, 0x2f5b: 0x0088, 0x2f5c: 0x0088, 0x2f5d: 0x0088,
+	0x2f5e: 0x0088, 0x2f5f: 0x0088, 0x2f60: 0x0088, 0x2f61: 0x0088, 0x2f62: 0x0088, 0x2f63: 0x0088,
+	0x2f64: 0x0088, 0x2f65: 0x0088, 0x2f66: 0x0088, 0x2f67: 0x0088, 0x2f68: 0x0088, 0x2f69: 0x0088,
+	0x2f6a: 0x0088, 0x2f6b: 0x0088, 0x2f6c: 0x0088, 0x2f6d: 0x0088, 0x2f6e: 0x0088, 0x2f6f: 0x0088,
+	0x2f70: 0x0088, 0x2f71: 0x0088, 0x2f72: 0x0088, 0x2f73: 0x0088, 0x2f74: 0x0088, 0x2f75: 0x0088,
+	0x2f76: 0x0088, 0x2f77: 0x0088, 0x2f78: 0x0088, 0x2f79: 0x0088, 0x2f7a: 0x0088, 0x2f7b: 0x0088,
+	0x2f7c: 0x0088, 0x2f7d: 0x0088, 0x2f7e: 0x0088, 0x2f7f: 0x0088,
+	// Block 0xbe, offset 0x2f80
+	0x2f80: 0x0088, 0x2f81: 0x0088, 0x2f82: 0x0088, 0x2f83: 0x0088, 0x2f84: 0x0088, 0x2f85: 0x0088,
+	0x2f86: 0x0088, 0x2f87: 0x0088, 0x2f88: 0x0088, 0x2f89: 0x0088, 0x2f8a: 0x0088, 0x2f8b: 0x0088,
+	0x2f8c: 0x0088, 0x2f8d: 0x0088, 0x2f8e: 0x0088, 0x2f90: 0x0080, 0x2f91: 0x0080,
+	0x2f92: 0x0080, 0x2f93: 0x0080, 0x2f94: 0x0080, 0x2f95: 0x0080, 0x2f96: 0x0080, 0x2f97: 0x0080,
+	0x2f98: 0x0080, 0x2f99: 0x0080, 0x2f9a: 0x0080, 0x2f9b: 0x0080, 0x2f9c: 0x0080,
+	0x2fa0: 0x0088,
+	// Block 0xbf, offset 0x2fc0
+	0x2fd0: 0x0080, 0x2fd1: 0x0080,
+	0x2fd2: 0x0080, 0x2fd3: 0x0080, 0x2fd4: 0x0080, 0x2fd5: 0x0080, 0x2fd6: 0x0080, 0x2fd7: 0x0080,
+	0x2fd8: 0x0080, 0x2fd9: 0x0080, 0x2fda: 0x0080, 0x2fdb: 0x0080, 0x2fdc: 0x0080, 0x2fdd: 0x0080,
+	0x2fde: 0x0080, 0x2fdf: 0x0080, 0x2fe0: 0x0080, 0x2fe1: 0x0080, 0x2fe2: 0x0080, 0x2fe3: 0x0080,
+	0x2fe4: 0x0080, 0x2fe5: 0x0080, 0x2fe6: 0x0080, 0x2fe7: 0x0080, 0x2fe8: 0x0080, 0x2fe9: 0x0080,
+	0x2fea: 0x0080, 0x2feb: 0x0080, 0x2fec: 0x0080, 0x2fed: 0x0080, 0x2fee: 0x0080, 0x2fef: 0x0080,
+	0x2ff0: 0x0080, 0x2ff1: 0x0080, 0x2ff2: 0x0080, 0x2ff3: 0x0080, 0x2ff4: 0x0080, 0x2ff5: 0x0080,
+	0x2ff6: 0x0080, 0x2ff7: 0x0080, 0x2ff8: 0x0080, 0x2ff9: 0x0080, 0x2ffa: 0x0080, 0x2ffb: 0x0080,
+	0x2ffc: 0x0080, 0x2ffd: 0x00c3,
+	// Block 0xc0, offset 0x3000
+	0x3000: 0x00c0, 0x3001: 0x00c0, 0x3002: 0x00c0, 0x3003: 0x00c0, 0x3004: 0x00c0, 0x3005: 0x00c0,
+	0x3006: 0x00c0, 0x3007: 0x00c0, 0x3008: 0x00c0, 0x3009: 0x00c0, 0x300a: 0x00c0, 0x300b: 0x00c0,
+	0x300c: 0x00c0, 0x300d: 0x00c0, 0x300e: 0x00c0, 0x300f: 0x00c0, 0x3010: 0x00c0, 0x3011: 0x00c0,
+	0x3012: 0x00c0, 0x3013: 0x00c0, 0x3014: 0x00c0, 0x3015: 0x00c0, 0x3016: 0x00c0, 0x3017: 0x00c0,
+	0x3018: 0x00c0, 0x3019: 0x00c0, 0x301a: 0x00c0, 0x301b: 0x00c0, 0x301c: 0x00c0,
+	0x3020: 0x00c0, 0x3021: 0x00c0, 0x3022: 0x00c0, 0x3023: 0x00c0,
+	0x3024: 0x00c0, 0x3025: 0x00c0, 0x3026: 0x00c0, 0x3027: 0x00c0, 0x3028: 0x00c0, 0x3029: 0x00c0,
+	0x302a: 0x00c0, 0x302b: 0x00c0, 0x302c: 0x00c0, 0x302d: 0x00c0, 0x302e: 0x00c0, 0x302f: 0x00c0,
+	0x3030: 0x00c0, 0x3031: 0x00c0, 0x3032: 0x00c0, 0x3033: 0x00c0, 0x3034: 0x00c0, 0x3035: 0x00c0,
+	0x3036: 0x00c0, 0x3037: 0x00c0, 0x3038: 0x00c0, 0x3039: 0x00c0, 0x303a: 0x00c0, 0x303b: 0x00c0,
+	0x303c: 0x00c0, 0x303d: 0x00c0, 0x303e: 0x00c0, 0x303f: 0x00c0,
+	// Block 0xc1, offset 0x3040
+	0x3040: 0x00c0, 0x3041: 0x00c0, 0x3042: 0x00c0, 0x3043: 0x00c0, 0x3044: 0x00c0, 0x3045: 0x00c0,
+	0x3046: 0x00c0, 0x3047: 0x00c0, 0x3048: 0x00c0, 0x3049: 0x00c0, 0x304a: 0x00c0, 0x304b: 0x00c0,
+	0x304c: 0x00c0, 0x304d: 0x00c0, 0x304e: 0x00c0, 0x304f: 0x00c0, 0x3050: 0x00c0,
+	0x3060: 0x00c3, 0x3061: 0x0080, 0x3062: 0x0080, 0x3063: 0x0080,
+	0x3064: 0x0080, 0x3065: 0x0080, 0x3066: 0x0080, 0x3067: 0x0080, 0x3068: 0x0080, 0x3069: 0x0080,
+	0x306a: 0x0080, 0x306b: 0x0080, 0x306c: 0x0080, 0x306d: 0x0080, 0x306e: 0x0080, 0x306f: 0x0080,
+	0x3070: 0x0080, 0x3071: 0x0080, 0x3072: 0x0080, 0x3073: 0x0080, 0x3074: 0x0080, 0x3075: 0x0080,
+	0x3076: 0x0080, 0x3077: 0x0080, 0x3078: 0x0080, 0x3079: 0x0080, 0x307a: 0x0080, 0x307b: 0x0080,
+	// Block 0xc2, offset 0x3080
+	0x3080: 0x00c0, 0x3081: 0x00c0, 0x3082: 0x00c0, 0x3083: 0x00c0, 0x3084: 0x00c0, 0x3085: 0x00c0,
+	0x3086: 0x00c0, 0x3087: 0x00c0, 0x3088: 0x00c0, 0x3089: 0x00c0, 0x308a: 0x00c0, 0x308b: 0x00c0,
+	0x308c: 0x00c0, 0x308d: 0x00c0, 0x308e: 0x00c0, 0x308f: 0x00c0, 0x3090: 0x00c0, 0x3091: 0x00c0,
+	0x3092: 0x00c0, 0x3093: 0x00c0, 0x3094: 0x00c0, 0x3095: 0x00c0, 0x3096: 0x00c0, 0x3097: 0x00c0,
+	0x3098: 0x00c0, 0x3099: 0x00c0, 0x309a: 0x00c0, 0x309b: 0x00c0, 0x309c: 0x00c0, 0x309d: 0x00c0,
+	0x309e: 0x00c0, 0x309f: 0x00c0, 0x30a0: 0x0080, 0x30a1: 0x0080, 0x30a2: 0x0080, 0x30a3: 0x0080,
+	0x30ad: 0x00c0, 0x30ae: 0x00c0, 0x30af: 0x00c0,
+	0x30b0: 0x00c0, 0x30b1: 0x00c0, 0x30b2: 0x00c0, 0x30b3: 0x00c0, 0x30b4: 0x00c0, 0x30b5: 0x00c0,
+	0x30b6: 0x00c0, 0x30b7: 0x00c0, 0x30b8: 0x00c0, 0x30b9: 0x00c0, 0x30ba: 0x00c0, 0x30bb: 0x00c0,
+	0x30bc: 0x00c0, 0x30bd: 0x00c0, 0x30be: 0x00c0, 0x30bf: 0x00c0,
+	// Block 0xc3, offset 0x30c0
+	0x30c0: 0x00c0, 0x30c1: 0x0080, 0x30c2: 0x00c0, 0x30c3: 0x00c0, 0x30c4: 0x00c0, 0x30c5: 0x00c0,
+	0x30c6: 0x00c0, 0x30c7: 0x00c0, 0x30c8: 0x00c0, 0x30c9: 0x00c0, 0x30ca: 0x0080,
+	0x30d0: 0x00c0, 0x30d1: 0x00c0,
+	0x30d2: 0x00c0, 0x30d3: 0x00c0, 0x30d4: 0x00c0, 0x30d5: 0x00c0, 0x30d6: 0x00c0, 0x30d7: 0x00c0,
+	0x30d8: 0x00c0, 0x30d9: 0x00c0, 0x30da: 0x00c0, 0x30db: 0x00c0, 0x30dc: 0x00c0, 0x30dd: 0x00c0,
+	0x30de: 0x00c0, 0x30df: 0x00c0, 0x30e0: 0x00c0, 0x30e1: 0x00c0, 0x30e2: 0x00c0, 0x30e3: 0x00c0,
+	0x30e4: 0x00c0, 0x30e5: 0x00c0, 0x30e6: 0x00c0, 0x30e7: 0x00c0, 0x30e8: 0x00c0, 0x30e9: 0x00c0,
+	0x30ea: 0x00c0, 0x30eb: 0x00c0, 0x30ec: 0x00c0, 0x30ed: 0x00c0, 0x30ee: 0x00c0, 0x30ef: 0x00c0,
+	0x30f0: 0x00c0, 0x30f1: 0x00c0, 0x30f2: 0x00c0, 0x30f3: 0x00c0, 0x30f4: 0x00c0, 0x30f5: 0x00c0,
+	0x30f6: 0x00c3, 0x30f7: 0x00c3, 0x30f8: 0x00c3, 0x30f9: 0x00c3, 0x30fa: 0x00c3,
+	// Block 0xc4, offset 0x3100
+	0x3100: 0x00c0, 0x3101: 0x00c0, 0x3102: 0x00c0, 0x3103: 0x00c0, 0x3104: 0x00c0, 0x3105: 0x00c0,
+	0x3106: 0x00c0, 0x3107: 0x00c0, 0x3108: 0x00c0, 0x3109: 0x00c0, 0x310a: 0x00c0, 0x310b: 0x00c0,
+	0x310c: 0x00c0, 0x310d: 0x00c0, 0x310e: 0x00c0, 0x310f: 0x00c0, 0x3110: 0x00c0, 0x3111: 0x00c0,
+	0x3112: 0x00c0, 0x3113: 0x00c0, 0x3114: 0x00c0, 0x3115: 0x00c0, 0x3116: 0x00c0, 0x3117: 0x00c0,
+	0x3118: 0x00c0, 0x3119: 0x00c0, 0x311a: 0x00c0, 0x311b: 0x00c0, 0x311c: 0x00c0, 0x311d: 0x00c0,
+	0x311f: 0x0080, 0x3120: 0x00c0, 0x3121: 0x00c0, 0x3122: 0x00c0, 0x3123: 0x00c0,
+	0x3124: 0x00c0, 0x3125: 0x00c0, 0x3126: 0x00c0, 0x3127: 0x00c0, 0x3128: 0x00c0, 0x3129: 0x00c0,
+	0x312a: 0x00c0, 0x312b: 0x00c0, 0x312c: 0x00c0, 0x312d: 0x00c0, 0x312e: 0x00c0, 0x312f: 0x00c0,
+	0x3130: 0x00c0, 0x3131: 0x00c0, 0x3132: 0x00c0, 0x3133: 0x00c0, 0x3134: 0x00c0, 0x3135: 0x00c0,
+	0x3136: 0x00c0, 0x3137: 0x00c0, 0x3138: 0x00c0, 0x3139: 0x00c0, 0x313a: 0x00c0, 0x313b: 0x00c0,
+	0x313c: 0x00c0, 0x313d: 0x00c0, 0x313e: 0x00c0, 0x313f: 0x00c0,
+	// Block 0xc5, offset 0x3140
+	0x3140: 0x00c0, 0x3141: 0x00c0, 0x3142: 0x00c0, 0x3143: 0x00c0,
+	0x3148: 0x00c0, 0x3149: 0x00c0, 0x314a: 0x00c0, 0x314b: 0x00c0,
+	0x314c: 0x00c0, 0x314d: 0x00c0, 0x314e: 0x00c0, 0x314f: 0x00c0, 0x3150: 0x0080, 0x3151: 0x0080,
+	0x3152: 0x0080, 0x3153: 0x0080, 0x3154: 0x0080, 0x3155: 0x0080,
+	// Block 0xc6, offset 0x3180
+	0x3180: 0x00c0, 0x3181: 0x00c0, 0x3182: 0x00c0, 0x3183: 0x00c0, 0x3184: 0x00c0, 0x3185: 0x00c0,
+	0x3186: 0x00c0, 0x3187: 0x00c0, 0x3188: 0x00c0, 0x3189: 0x00c0, 0x318a: 0x00c0, 0x318b: 0x00c0,
+	0x318c: 0x00c0, 0x318d: 0x00c0, 0x318e: 0x00c0, 0x318f: 0x00c0, 0x3190: 0x00c0, 0x3191: 0x00c0,
+	0x3192: 0x00c0, 0x3193: 0x00c0, 0x3194: 0x00c0, 0x3195: 0x00c0, 0x3196: 0x00c0, 0x3197: 0x00c0,
+	0x3198: 0x00c0, 0x3199: 0x00c0, 0x319a: 0x00c0, 0x319b: 0x00c0, 0x319c: 0x00c0, 0x319d: 0x00c0,
+	0x31a0: 0x00c0, 0x31a1: 0x00c0, 0x31a2: 0x00c0, 0x31a3: 0x00c0,
+	0x31a4: 0x00c0, 0x31a5: 0x00c0, 0x31a6: 0x00c0, 0x31a7: 0x00c0, 0x31a8: 0x00c0, 0x31a9: 0x00c0,
+	0x31b0: 0x00c0, 0x31b1: 0x00c0, 0x31b2: 0x00c0, 0x31b3: 0x00c0, 0x31b4: 0x00c0, 0x31b5: 0x00c0,
+	0x31b6: 0x00c0, 0x31b7: 0x00c0, 0x31b8: 0x00c0, 0x31b9: 0x00c0, 0x31ba: 0x00c0, 0x31bb: 0x00c0,
+	0x31bc: 0x00c0, 0x31bd: 0x00c0, 0x31be: 0x00c0, 0x31bf: 0x00c0,
+	// Block 0xc7, offset 0x31c0
+	0x31c0: 0x00c0, 0x31c1: 0x00c0, 0x31c2: 0x00c0, 0x31c3: 0x00c0, 0x31c4: 0x00c0, 0x31c5: 0x00c0,
+	0x31c6: 0x00c0, 0x31c7: 0x00c0, 0x31c8: 0x00c0, 0x31c9: 0x00c0, 0x31ca: 0x00c0, 0x31cb: 0x00c0,
+	0x31cc: 0x00c0, 0x31cd: 0x00c0, 0x31ce: 0x00c0, 0x31cf: 0x00c0, 0x31d0: 0x00c0, 0x31d1: 0x00c0,
+	0x31d2: 0x00c0, 0x31d3: 0x00c0,
+	0x31d8: 0x00c0, 0x31d9: 0x00c0, 0x31da: 0x00c0, 0x31db: 0x00c0, 0x31dc: 0x00c0, 0x31dd: 0x00c0,
+	0x31de: 0x00c0, 0x31df: 0x00c0, 0x31e0: 0x00c0, 0x31e1: 0x00c0, 0x31e2: 0x00c0, 0x31e3: 0x00c0,
+	0x31e4: 0x00c0, 0x31e5: 0x00c0, 0x31e6: 0x00c0, 0x31e7: 0x00c0, 0x31e8: 0x00c0, 0x31e9: 0x00c0,
+	0x31ea: 0x00c0, 0x31eb: 0x00c0, 0x31ec: 0x00c0, 0x31ed: 0x00c0, 0x31ee: 0x00c0, 0x31ef: 0x00c0,
+	0x31f0: 0x00c0, 0x31f1: 0x00c0, 0x31f2: 0x00c0, 0x31f3: 0x00c0, 0x31f4: 0x00c0, 0x31f5: 0x00c0,
+	0x31f6: 0x00c0, 0x31f7: 0x00c0, 0x31f8: 0x00c0, 0x31f9: 0x00c0, 0x31fa: 0x00c0, 0x31fb: 0x00c0,
+	// Block 0xc8, offset 0x3200
+	0x3200: 0x00c0, 0x3201: 0x00c0, 0x3202: 0x00c0, 0x3203: 0x00c0, 0x3204: 0x00c0, 0x3205: 0x00c0,
+	0x3206: 0x00c0, 0x3207: 0x00c0, 0x3208: 0x00c0, 0x3209: 0x00c0, 0x320a: 0x00c0, 0x320b: 0x00c0,
+	0x320c: 0x00c0, 0x320d: 0x00c0, 0x320e: 0x00c0, 0x320f: 0x00c0, 0x3210: 0x00c0, 0x3211: 0x00c0,
+	0x3212: 0x00c0, 0x3213: 0x00c0, 0x3214: 0x00c0, 0x3215: 0x00c0, 0x3216: 0x00c0, 0x3217: 0x00c0,
+	0x3218: 0x00c0, 0x3219: 0x00c0, 0x321a: 0x00c0, 0x321b: 0x00c0, 0x321c: 0x00c0, 0x321d: 0x00c0,
+	0x321e: 0x00c0, 0x321f: 0x00c0, 0x3220: 0x00c0, 0x3221: 0x00c0, 0x3222: 0x00c0, 0x3223: 0x00c0,
+	0x3224: 0x00c0, 0x3225: 0x00c0, 0x3226: 0x00c0, 0x3227: 0x00c0,
+	0x3230: 0x00c0, 0x3231: 0x00c0, 0x3232: 0x00c0, 0x3233: 0x00c0, 0x3234: 0x00c0, 0x3235: 0x00c0,
+	0x3236: 0x00c0, 0x3237: 0x00c0, 0x3238: 0x00c0, 0x3239: 0x00c0, 0x323a: 0x00c0, 0x323b: 0x00c0,
+	0x323c: 0x00c0, 0x323d: 0x00c0, 0x323e: 0x00c0, 0x323f: 0x00c0,
+	// Block 0xc9, offset 0x3240
+	0x3240: 0x00c0, 0x3241: 0x00c0, 0x3242: 0x00c0, 0x3243: 0x00c0, 0x3244: 0x00c0, 0x3245: 0x00c0,
+	0x3246: 0x00c0, 0x3247: 0x00c0, 0x3248: 0x00c0, 0x3249: 0x00c0, 0x324a: 0x00c0, 0x324b: 0x00c0,
+	0x324c: 0x00c0, 0x324d: 0x00c0, 0x324e: 0x00c0, 0x324f: 0x00c0, 0x3250: 0x00c0, 0x3251: 0x00c0,
+	0x3252: 0x00c0, 0x3253: 0x00c0, 0x3254: 0x00c0, 0x3255: 0x00c0, 0x3256: 0x00c0, 0x3257: 0x00c0,
+	0x3258: 0x00c0, 0x3259: 0x00c0, 0x325a: 0x00c0, 0x325b: 0x00c0, 0x325c: 0x00c0, 0x325d: 0x00c0,
+	0x325e: 0x00c0, 0x325f: 0x00c0, 0x3260: 0x00c0, 0x3261: 0x00c0, 0x3262: 0x00c0, 0x3263: 0x00c0,
+	0x326f: 0x0080,
+	0x3270: 0x00c0, 0x3271: 0x00c0, 0x3272: 0x00c0, 0x3273: 0x00c0, 0x3274: 0x00c0, 0x3275: 0x00c0,
+	0x3276: 0x00c0, 0x3277: 0x00c0, 0x3278: 0x00c0, 0x3279: 0x00c0, 0x327a: 0x00c0,
+	0x327c: 0x00c0, 0x327d: 0x00c0, 0x327e: 0x00c0, 0x327f: 0x00c0,
+	// Block 0xca, offset 0x3280
+	0x3280: 0x00c0, 0x3281: 0x00c0, 0x3282: 0x00c0, 0x3283: 0x00c0, 0x3284: 0x00c0, 0x3285: 0x00c0,
+	0x3286: 0x00c0, 0x3287: 0x00c0, 0x3288: 0x00c0, 0x3289: 0x00c0, 0x328a: 0x00c0,
+	0x328c: 0x00c0, 0x328d: 0x00c0, 0x328e: 0x00c0, 0x328f: 0x00c0, 0x3290: 0x00c0, 0x3291: 0x00c0,
+	0x3292: 0x00c0, 0x3294: 0x00c0, 0x3295: 0x00c0, 0x3297: 0x00c0,
+	0x3298: 0x00c0, 0x3299: 0x00c0, 0x329a: 0x00c0, 0x329b: 0x00c0, 0x329c: 0x00c0, 0x329d: 0x00c0,
+	0x329e: 0x00c0, 0x329f: 0x00c0, 0x32a0: 0x00c0, 0x32a1: 0x00c0, 0x32a3: 0x00c0,
+	0x32a4: 0x00c0, 0x32a5: 0x00c0, 0x32a6: 0x00c0, 0x32a7: 0x00c0, 0x32a8: 0x00c0, 0x32a9: 0x00c0,
+	0x32aa: 0x00c0, 0x32ab: 0x00c0, 0x32ac: 0x00c0, 0x32ad: 0x00c0, 0x32ae: 0x00c0, 0x32af: 0x00c0,
+	0x32b0: 0x00c0, 0x32b1: 0x00c0, 0x32b3: 0x00c0, 0x32b4: 0x00c0, 0x32b5: 0x00c0,
+	0x32b6: 0x00c0, 0x32b7: 0x00c0, 0x32b8: 0x00c0, 0x32b9: 0x00c0, 0x32bb: 0x00c0,
+	0x32bc: 0x00c0,
+	// Block 0xcb, offset 0x32c0
+	0x32c0: 0x00c0, 0x32c1: 0x00c0, 0x32c2: 0x00c0, 0x32c3: 0x00c0, 0x32c4: 0x00c0, 0x32c5: 0x00c0,
+	0x32c6: 0x00c0, 0x32c7: 0x00c0, 0x32c8: 0x00c0, 0x32c9: 0x00c0, 0x32ca: 0x00c0, 0x32cb: 0x00c0,
+	0x32cc: 0x00c0, 0x32cd: 0x00c0, 0x32ce: 0x00c0, 0x32cf: 0x00c0, 0x32d0: 0x00c0, 0x32d1: 0x00c0,
+	0x32d2: 0x00c0, 0x32d3: 0x00c0, 0x32d4: 0x00c0, 0x32d5: 0x00c0, 0x32d6: 0x00c0, 0x32d7: 0x00c0,
+	0x32d8: 0x00c0, 0x32d9: 0x00c0, 0x32da: 0x00c0, 0x32db: 0x00c0, 0x32dc: 0x00c0, 0x32dd: 0x00c0,
+	0x32de: 0x00c0, 0x32df: 0x00c0, 0x32e0: 0x00c0, 0x32e1: 0x00c0, 0x32e2: 0x00c0, 0x32e3: 0x00c0,
+	0x32e4: 0x00c0, 0x32e5: 0x00c0, 0x32e6: 0x00c0, 0x32e7: 0x00c0, 0x32e8: 0x00c0, 0x32e9: 0x00c0,
+	0x32ea: 0x00c0, 0x32eb: 0x00c0, 0x32ec: 0x00c0, 0x32ed: 0x00c0, 0x32ee: 0x00c0, 0x32ef: 0x00c0,
+	0x32f0: 0x00c0, 0x32f1: 0x00c0, 0x32f2: 0x00c0, 0x32f3: 0x00c0, 0x32f4: 0x00c0, 0x32f5: 0x00c0,
+	0x32f6: 0x00c0,
+	// Block 0xcc, offset 0x3300
+	0x3300: 0x00c0, 0x3301: 0x00c0, 0x3302: 0x00c0, 0x3303: 0x00c0, 0x3304: 0x00c0, 0x3305: 0x00c0,
+	0x3306: 0x00c0, 0x3307: 0x00c0, 0x3308: 0x00c0, 0x3309: 0x00c0, 0x330a: 0x00c0, 0x330b: 0x00c0,
+	0x330c: 0x00c0, 0x330d: 0x00c0, 0x330e: 0x00c0, 0x330f: 0x00c0, 0x3310: 0x00c0, 0x3311: 0x00c0,
+	0x3312: 0x00c0, 0x3313: 0x00c0, 0x3314: 0x00c0, 0x3315: 0x00c0,
+	0x3320: 0x00c0, 0x3321: 0x00c0, 0x3322: 0x00c0, 0x3323: 0x00c0,
+	0x3324: 0x00c0, 0x3325: 0x00c0, 0x3326: 0x00c0, 0x3327: 0x00c0,
+	// Block 0xcd, offset 0x3340
+	0x3340: 0x00c0, 0x3341: 0x0080, 0x3342: 0x0080, 0x3343: 0x0080, 0x3344: 0x0080, 0x3345: 0x0080,
+	0x3347: 0x0080, 0x3348: 0x0080, 0x3349: 0x0080, 0x334a: 0x0080, 0x334b: 0x0080,
+	0x334c: 0x0080, 0x334d: 0x0080, 0x334e: 0x0080, 0x334f: 0x0080, 0x3350: 0x0080, 0x3351: 0x0080,
+	0x3352: 0x0080, 0x3353: 0x0080, 0x3354: 0x0080, 0x3355: 0x0080, 0x3356: 0x0080, 0x3357: 0x0080,
+	0x3358: 0x0080, 0x3359: 0x0080, 0x335a: 0x0080, 0x335b: 0x0080, 0x335c: 0x0080, 0x335d: 0x0080,
+	0x335e: 0x0080, 0x335f: 0x0080, 0x3360: 0x0080, 0x3361: 0x0080, 0x3362: 0x0080, 0x3363: 0x0080,
+	0x3364: 0x0080, 0x3365: 0x0080, 0x3366: 0x0080, 0x3367: 0x0080, 0x3368: 0x0080, 0x3369: 0x0080,
+	0x336a: 0x0080, 0x336b: 0x0080, 0x336c: 0x0080, 0x336d: 0x0080, 0x336e: 0x0080, 0x336f: 0x0080,
+	0x3370: 0x0080, 0x3372: 0x0080, 0x3373: 0x0080, 0x3374: 0x0080, 0x3375: 0x0080,
+	0x3376: 0x0080, 0x3377: 0x0080, 0x3378: 0x0080, 0x3379: 0x0080, 0x337a: 0x0080,
+	// Block 0xce, offset 0x3380
+	0x3380: 0x00c0, 0x3381: 0x00c0, 0x3382: 0x00c0, 0x3383: 0x00c0, 0x3384: 0x00c0, 0x3385: 0x00c0,
+	0x3388: 0x00c0, 0x338a: 0x00c0, 0x338b: 0x00c0,
+	0x338c: 0x00c0, 0x338d: 0x00c0, 0x338e: 0x00c0, 0x338f: 0x00c0, 0x3390: 0x00c0, 0x3391: 0x00c0,
+	0x3392: 0x00c0, 0x3393: 0x00c0, 0x3394: 0x00c0, 0x3395: 0x00c0, 0x3396: 0x00c0, 0x3397: 0x00c0,
+	0x3398: 0x00c0, 0x3399: 0x00c0, 0x339a: 0x00c0, 0x339b: 0x00c0, 0x339c: 0x00c0, 0x339d: 0x00c0,
+	0x339e: 0x00c0, 0x339f: 0x00c0, 0x33a0: 0x00c0, 0x33a1: 0x00c0, 0x33a2: 0x00c0, 0x33a3: 0x00c0,
+	0x33a4: 0x00c0, 0x33a5: 0x00c0, 0x33a6: 0x00c0, 0x33a7: 0x00c0, 0x33a8: 0x00c0, 0x33a9: 0x00c0,
+	0x33aa: 0x00c0, 0x33ab: 0x00c0, 0x33ac: 0x00c0, 0x33ad: 0x00c0, 0x33ae: 0x00c0, 0x33af: 0x00c0,
+	0x33b0: 0x00c0, 0x33b1: 0x00c0, 0x33b2: 0x00c0, 0x33b3: 0x00c0, 0x33b4: 0x00c0, 0x33b5: 0x00c0,
+	0x33b7: 0x00c0, 0x33b8: 0x00c0,
+	0x33bc: 0x00c0, 0x33bf: 0x00c0,
+	// Block 0xcf, offset 0x33c0
+	0x33c0: 0x00c0, 0x33c1: 0x00c0, 0x33c2: 0x00c0, 0x33c3: 0x00c0, 0x33c4: 0x00c0, 0x33c5: 0x00c0,
+	0x33c6: 0x00c0, 0x33c7: 0x00c0, 0x33c8: 0x00c0, 0x33c9: 0x00c0, 0x33ca: 0x00c0, 0x33cb: 0x00c0,
+	0x33cc: 0x00c0, 0x33cd: 0x00c0, 0x33ce: 0x00c0, 0x33cf: 0x00c0, 0x33d0: 0x00c0, 0x33d1: 0x00c0,
+	0x33d2: 0x00c0, 0x33d3: 0x00c0, 0x33d4: 0x00c0, 0x33d5: 0x00c0, 0x33d7: 0x0080,
+	0x33d8: 0x0080, 0x33d9: 0x0080, 0x33da: 0x0080, 0x33db: 0x0080, 0x33dc: 0x0080, 0x33dd: 0x0080,
+	0x33de: 0x0080, 0x33df: 0x0080, 0x33e0: 0x00c0, 0x33e1: 0x00c0, 0x33e2: 0x00c0, 0x33e3: 0x00c0,
+	0x33e4: 0x00c0, 0x33e5: 0x00c0, 0x33e6: 0x00c0, 0x33e7: 0x00c0, 0x33e8: 0x00c0, 0x33e9: 0x00c0,
+	0x33ea: 0x00c0, 0x33eb: 0x00c0, 0x33ec: 0x00c0, 0x33ed: 0x00c0, 0x33ee: 0x00c0, 0x33ef: 0x00c0,
+	0x33f0: 0x00c0, 0x33f1: 0x00c0, 0x33f2: 0x00c0, 0x33f3: 0x00c0, 0x33f4: 0x00c0, 0x33f5: 0x00c0,
+	0x33f6: 0x00c0, 0x33f7: 0x0080, 0x33f8: 0x0080, 0x33f9: 0x0080, 0x33fa: 0x0080, 0x33fb: 0x0080,
+	0x33fc: 0x0080, 0x33fd: 0x0080, 0x33fe: 0x0080, 0x33ff: 0x0080,
+	// Block 0xd0, offset 0x3400
+	0x3400: 0x00c0, 0x3401: 0x00c0, 0x3402: 0x00c0, 0x3403: 0x00c0, 0x3404: 0x00c0, 0x3405: 0x00c0,
+	0x3406: 0x00c0, 0x3407: 0x00c0, 0x3408: 0x00c0, 0x3409: 0x00c0, 0x340a: 0x00c0, 0x340b: 0x00c0,
+	0x340c: 0x00c0, 0x340d: 0x00c0, 0x340e: 0x00c0, 0x340f: 0x00c0, 0x3410: 0x00c0, 0x3411: 0x00c0,
+	0x3412: 0x00c0, 0x3413: 0x00c0, 0x3414: 0x00c0, 0x3415: 0x00c0, 0x3416: 0x00c0, 0x3417: 0x00c0,
+	0x3418: 0x00c0, 0x3419: 0x00c0, 0x341a: 0x00c0, 0x341b: 0x00c0, 0x341c: 0x00c0, 0x341d: 0x00c0,
+	0x341e: 0x00c0,
+	0x3427: 0x0080, 0x3428: 0x0080, 0x3429: 0x0080,
+	0x342a: 0x0080, 0x342b: 0x0080, 0x342c: 0x0080, 0x342d: 0x0080, 0x342e: 0x0080, 0x342f: 0x0080,
+	// Block 0xd1, offset 0x3440
+	0x3460: 0x00c0, 0x3461: 0x00c0, 0x3462: 0x00c0, 0x3463: 0x00c0,
+	0x3464: 0x00c0, 0x3465: 0x00c0, 0x3466: 0x00c0, 0x3467: 0x00c0, 0x3468: 0x00c0, 0x3469: 0x00c0,
+	0x346a: 0x00c0, 0x346b: 0x00c0, 0x346c: 0x00c0, 0x346d: 0x00c0, 0x346e: 0x00c0, 0x346f: 0x00c0,
+	0x3470: 0x00c0, 0x3471: 0x00c0, 0x3472: 0x00c0, 0x3474: 0x00c0, 0x3475: 0x00c0,
+	0x347b: 0x0080,
+	0x347c: 0x0080, 0x347d: 0x0080, 0x347e: 0x0080, 0x347f: 0x0080,
+	// Block 0xd2, offset 0x3480
+	0x3480: 0x00c0, 0x3481: 0x00c0, 0x3482: 0x00c0, 0x3483: 0x00c0, 0x3484: 0x00c0, 0x3485: 0x00c0,
+	0x3486: 0x00c0, 0x3487: 0x00c0, 0x3488: 0x00c0, 0x3489: 0x00c0, 0x348a: 0x00c0, 0x348b: 0x00c0,
+	0x348c: 0x00c0, 0x348d: 0x00c0, 0x348e: 0x00c0, 0x348f: 0x00c0, 0x3490: 0x00c0, 0x3491: 0x00c0,
+	0x3492: 0x00c0, 0x3493: 0x00c0, 0x3494: 0x00c0, 0x3495: 0x00c0, 0x3496: 0x0080, 0x3497: 0x0080,
+	0x3498: 0x0080, 0x3499: 0x0080, 0x349a: 0x0080, 0x349b: 0x0080,
+	0x349f: 0x0080, 0x34a0: 0x00c0, 0x34a1: 0x00c0, 0x34a2: 0x00c0, 0x34a3: 0x00c0,
+	0x34a4: 0x00c0, 0x34a5: 0x00c0, 0x34a6: 0x00c0, 0x34a7: 0x00c0, 0x34a8: 0x00c0, 0x34a9: 0x00c0,
+	0x34aa: 0x00c0, 0x34ab: 0x00c0, 0x34ac: 0x00c0, 0x34ad: 0x00c0, 0x34ae: 0x00c0, 0x34af: 0x00c0,
+	0x34b0: 0x00c0, 0x34b1: 0x00c0, 0x34b2: 0x00c0, 0x34b3: 0x00c0, 0x34b4: 0x00c0, 0x34b5: 0x00c0,
+	0x34b6: 0x00c0, 0x34b7: 0x00c0, 0x34b8: 0x00c0, 0x34b9: 0x00c0,
+	0x34bf: 0x0080,
+	// Block 0xd3, offset 0x34c0
+	0x34c0: 0x00c0, 0x34c1: 0x00c0, 0x34c2: 0x00c0, 0x34c3: 0x00c0, 0x34c4: 0x00c0, 0x34c5: 0x00c0,
+	0x34c6: 0x00c0, 0x34c7: 0x00c0, 0x34c8: 0x00c0, 0x34c9: 0x00c0, 0x34ca: 0x00c0, 0x34cb: 0x00c0,
+	0x34cc: 0x00c0, 0x34cd: 0x00c0, 0x34ce: 0x00c0, 0x34cf: 0x00c0, 0x34d0: 0x00c0, 0x34d1: 0x00c0,
+	0x34d2: 0x00c0, 0x34d3: 0x00c0, 0x34d4: 0x00c0, 0x34d5: 0x00c0, 0x34d6: 0x00c0, 0x34d7: 0x00c0,
+	0x34d8: 0x00c0, 0x34d9: 0x00c0, 0x34da: 0x00c0, 0x34db: 0x00c0, 0x34dc: 0x00c0, 0x34dd: 0x00c0,
+	0x34de: 0x00c0, 0x34df: 0x00c0, 0x34e0: 0x00c0, 0x34e1: 0x00c0, 0x34e2: 0x00c0, 0x34e3: 0x00c0,
+	0x34e4: 0x00c0, 0x34e5: 0x00c0, 0x34e6: 0x00c0, 0x34e7: 0x00c0, 0x34e8: 0x00c0, 0x34e9: 0x00c0,
+	0x34ea: 0x00c0, 0x34eb: 0x00c0, 0x34ec: 0x00c0, 0x34ed: 0x00c0, 0x34ee: 0x00c0, 0x34ef: 0x00c0,
+	0x34f0: 0x00c0, 0x34f1: 0x00c0, 0x34f2: 0x00c0, 0x34f3: 0x00c0, 0x34f4: 0x00c0, 0x34f5: 0x00c0,
+	0x34f6: 0x00c0, 0x34f7: 0x00c0,
+	0x34fc: 0x0080, 0x34fd: 0x0080, 0x34fe: 0x00c0, 0x34ff: 0x00c0,
+	// Block 0xd4, offset 0x3500
+	0x3500: 0x00c0, 0x3501: 0x00c3, 0x3502: 0x00c3, 0x3503: 0x00c3, 0x3505: 0x00c3,
+	0x3506: 0x00c3,
+	0x350c: 0x00c3, 0x350d: 0x00c3, 0x350e: 0x00c3, 0x350f: 0x00c3, 0x3510: 0x00c0, 0x3511: 0x00c0,
+	0x3512: 0x00c0, 0x3513: 0x00c0, 0x3515: 0x00c0, 0x3516: 0x00c0, 0x3517: 0x00c0,
+	0x3519: 0x00c0, 0x351a: 0x00c0, 0x351b: 0x00c0, 0x351c: 0x00c0, 0x351d: 0x00c0,
+	0x351e: 0x00c0, 0x351f: 0x00c0, 0x3520: 0x00c0, 0x3521: 0x00c0, 0x3522: 0x00c0, 0x3523: 0x00c0,
+	0x3524: 0x00c0, 0x3525: 0x00c0, 0x3526: 0x00c0, 0x3527: 0x00c0, 0x3528: 0x00c0, 0x3529: 0x00c0,
+	0x352a: 0x00c0, 0x352b: 0x00c0, 0x352c: 0x00c0, 0x352d: 0x00c0, 0x352e: 0x00c0, 0x352f: 0x00c0,
+	0x3530: 0x00c0, 0x3531: 0x00c0, 0x3532: 0x00c0, 0x3533: 0x00c0, 0x3534: 0x00c0, 0x3535: 0x00c0,
+	0x3538: 0x00c3, 0x3539: 0x00c3, 0x353a: 0x00c3,
+	0x353f: 0x00c6,
+	// Block 0xd5, offset 0x3540
+	0x3540: 0x0080, 0x3541: 0x0080, 0x3542: 0x0080, 0x3543: 0x0080, 0x3544: 0x0080, 0x3545: 0x0080,
+	0x3546: 0x0080, 0x3547: 0x0080, 0x3548: 0x0080,
+	0x3550: 0x0080, 0x3551: 0x0080,
+	0x3552: 0x0080, 0x3553: 0x0080, 0x3554: 0x0080, 0x3555: 0x0080, 0x3556: 0x0080, 0x3557: 0x0080,
+	0x3558: 0x0080,
+	0x3560: 0x00c0, 0x3561: 0x00c0, 0x3562: 0x00c0, 0x3563: 0x00c0,
+	0x3564: 0x00c0, 0x3565: 0x00c0, 0x3566: 0x00c0, 0x3567: 0x00c0, 0x3568: 0x00c0, 0x3569: 0x00c0,
+	0x356a: 0x00c0, 0x356b: 0x00c0, 0x356c: 0x00c0, 0x356d: 0x00c0, 0x356e: 0x00c0, 0x356f: 0x00c0,
+	0x3570: 0x00c0, 0x3571: 0x00c0, 0x3572: 0x00c0, 0x3573: 0x00c0, 0x3574: 0x00c0, 0x3575: 0x00c0,
+	0x3576: 0x00c0, 0x3577: 0x00c0, 0x3578: 0x00c0, 0x3579: 0x00c0, 0x357a: 0x00c0, 0x357b: 0x00c0,
+	0x357c: 0x00c0, 0x357d: 0x0080, 0x357e: 0x0080, 0x357f: 0x0080,
+	// Block 0xd6, offset 0x3580
+	0x3580: 0x00c0, 0x3581: 0x00c0, 0x3582: 0x00c0, 0x3583: 0x00c0, 0x3584: 0x00c0, 0x3585: 0x00c0,
+	0x3586: 0x00c0, 0x3587: 0x00c0, 0x3588: 0x00c0, 0x3589: 0x00c0, 0x358a: 0x00c0, 0x358b: 0x00c0,
+	0x358c: 0x00c0, 0x358d: 0x00c0, 0x358e: 0x00c0, 0x358f: 0x00c0, 0x3590: 0x00c0, 0x3591: 0x00c0,
+	0x3592: 0x00c0, 0x3593: 0x00c0, 0x3594: 0x00c0, 0x3595: 0x00c0, 0x3596: 0x00c0, 0x3597: 0x00c0,
+	0x3598: 0x00c0, 0x3599: 0x00c0, 0x359a: 0x00c0, 0x359b: 0x00c0, 0x359c: 0x00c0, 0x359d: 0x0080,
+	0x359e: 0x0080, 0x359f: 0x0080,
+	// Block 0xd7, offset 0x35c0
+	0x35c0: 0x00c2, 0x35c1: 0x00c2, 0x35c2: 0x00c2, 0x35c3: 0x00c2, 0x35c4: 0x00c2, 0x35c5: 0x00c4,
+	0x35c6: 0x00c0, 0x35c7: 0x00c4, 0x35c8: 0x0080, 0x35c9: 0x00c4, 0x35ca: 0x00c4, 0x35cb: 0x00c0,
+	0x35cc: 0x00c0, 0x35cd: 0x00c1, 0x35ce: 0x00c4, 0x35cf: 0x00c4, 0x35d0: 0x00c4, 0x35d1: 0x00c4,
+	0x35d2: 0x00c4, 0x35d3: 0x00c2, 0x35d4: 0x00c2, 0x35d5: 0x00c2, 0x35d6: 0x00c2, 0x35d7: 0x00c1,
+	0x35d8: 0x00c2, 0x35d9: 0x00c2, 0x35da: 0x00c2, 0x35db: 0x00c2, 0x35dc: 0x00c2, 0x35dd: 0x00c4,
+	0x35de: 0x00c2, 0x35df: 0x00c2, 0x35e0: 0x00c2, 0x35e1: 0x00c4, 0x35e2: 0x00c0, 0x35e3: 0x00c0,
+	0x35e4: 0x00c4, 0x35e5: 0x00c3, 0x35e6: 0x00c3,
+	0x35eb: 0x0082, 0x35ec: 0x0082, 0x35ed: 0x0082, 0x35ee: 0x0082, 0x35ef: 0x0084,
+	0x35f0: 0x0080, 0x35f1: 0x0080, 0x35f2: 0x0080, 0x35f3: 0x0080, 0x35f4: 0x0080, 0x35f5: 0x0080,
+	0x35f6: 0x0080,
+	// Block 0xd8, offset 0x3600
+	0x3600: 0x00c0, 0x3601: 0x00c0, 0x3602: 0x00c0, 0x3603: 0x00c0, 0x3604: 0x00c0, 0x3605: 0x00c0,
+	0x3606: 0x00c0, 0x3607: 0x00c0, 0x3608: 0x00c0, 0x3609: 0x00c0, 0x360a: 0x00c0, 0x360b: 0x00c0,
+	0x360c: 0x00c0, 0x360d: 0x00c0, 0x360e: 0x00c0, 0x360f: 0x00c0, 0x3610: 0x00c0, 0x3611: 0x00c0,
+	0x3612: 0x00c0, 0x3613: 0x00c0, 0x3614: 0x00c0, 0x3615: 0x00c0, 0x3616: 0x00c0, 0x3617: 0x00c0,
+	0x3618: 0x00c0, 0x3619: 0x00c0, 0x361a: 0x00c0, 0x361b: 0x00c0, 0x361c: 0x00c0, 0x361d: 0x00c0,
+	0x361e: 0x00c0, 0x361f: 0x00c0, 0x3620: 0x00c0, 0x3621: 0x00c0, 0x3622: 0x00c0, 0x3623: 0x00c0,
+	0x3624: 0x00c0, 0x3625: 0x00c0, 0x3626: 0x00c0, 0x3627: 0x00c0, 0x3628: 0x00c0, 0x3629: 0x00c0,
+	0x362a: 0x00c0, 0x362b: 0x00c0, 0x362c: 0x00c0, 0x362d: 0x00c0, 0x362e: 0x00c0, 0x362f: 0x00c0,
+	0x3630: 0x00c0, 0x3631: 0x00c0, 0x3632: 0x00c0, 0x3633: 0x00c0, 0x3634: 0x00c0, 0x3635: 0x00c0,
+	0x3639: 0x0080, 0x363a: 0x0080, 0x363b: 0x0080,
+	0x363c: 0x0080, 0x363d: 0x0080, 0x363e: 0x0080, 0x363f: 0x0080,
+	// Block 0xd9, offset 0x3640
+	0x3640: 0x00c0, 0x3641: 0x00c0, 0x3642: 0x00c0, 0x3643: 0x00c0, 0x3644: 0x00c0, 0x3645: 0x00c0,
+	0x3646: 0x00c0, 0x3647: 0x00c0, 0x3648: 0x00c0, 0x3649: 0x00c0, 0x364a: 0x00c0, 0x364b: 0x00c0,
+	0x364c: 0x00c0, 0x364d: 0x00c0, 0x364e: 0x00c0, 0x364f: 0x00c0, 0x3650: 0x00c0, 0x3651: 0x00c0,
+	0x3652: 0x00c0, 0x3653: 0x00c0, 0x3654: 0x00c0, 0x3655: 0x00c0,
+	0x3658: 0x0080, 0x3659: 0x0080, 0x365a: 0x0080, 0x365b: 0x0080, 0x365c: 0x0080, 0x365d: 0x0080,
+	0x365e: 0x0080, 0x365f: 0x0080, 0x3660: 0x00c0, 0x3661: 0x00c0, 0x3662: 0x00c0, 0x3663: 0x00c0,
+	0x3664: 0x00c0, 0x3665: 0x00c0, 0x3666: 0x00c0, 0x3667: 0x00c0, 0x3668: 0x00c0, 0x3669: 0x00c0,
+	0x366a: 0x00c0, 0x366b: 0x00c0, 0x366c: 0x00c0, 0x366d: 0x00c0, 0x366e: 0x00c0, 0x366f: 0x00c0,
+	0x3670: 0x00c0, 0x3671: 0x00c0, 0x3672: 0x00c0,
+	0x3678: 0x0080, 0x3679: 0x0080, 0x367a: 0x0080, 0x367b: 0x0080,
+	0x367c: 0x0080, 0x367d: 0x0080, 0x367e: 0x0080, 0x367f: 0x0080,
+	// Block 0xda, offset 0x3680
+	0x3680: 0x00c2, 0x3681: 0x00c4, 0x3682: 0x00c2, 0x3683: 0x00c4, 0x3684: 0x00c4, 0x3685: 0x00c4,
+	0x3686: 0x00c2, 0x3687: 0x00c2, 0x3688: 0x00c2, 0x3689: 0x00c4, 0x368a: 0x00c2, 0x368b: 0x00c2,
+	0x368c: 0x00c4, 0x368d: 0x00c2, 0x368e: 0x00c4, 0x368f: 0x00c4, 0x3690: 0x00c2, 0x3691: 0x00c4,
+	0x3699: 0x0080, 0x369a: 0x0080, 0x369b: 0x0080, 0x369c: 0x0080,
+	0x36a9: 0x0084,
+	0x36aa: 0x0084, 0x36ab: 0x0084, 0x36ac: 0x0084, 0x36ad: 0x0082, 0x36ae: 0x0082, 0x36af: 0x0080,
+	// Block 0xdb, offset 0x36c0
+	0x36c0: 0x00c0, 0x36c1: 0x00c0, 0x36c2: 0x00c0, 0x36c3: 0x00c0, 0x36c4: 0x00c0, 0x36c5: 0x00c0,
+	0x36c6: 0x00c0, 0x36c7: 0x00c0, 0x36c8: 0x00c0,
+	// Block 0xdc, offset 0x3700
+	0x3700: 0x00c0, 0x3701: 0x00c0, 0x3702: 0x00c0, 0x3703: 0x00c0, 0x3704: 0x00c0, 0x3705: 0x00c0,
+	0x3706: 0x00c0, 0x3707: 0x00c0, 0x3708: 0x00c0, 0x3709: 0x00c0, 0x370a: 0x00c0, 0x370b: 0x00c0,
+	0x370c: 0x00c0, 0x370d: 0x00c0, 0x370e: 0x00c0, 0x370f: 0x00c0, 0x3710: 0x00c0, 0x3711: 0x00c0,
+	0x3712: 0x00c0, 0x3713: 0x00c0, 0x3714: 0x00c0, 0x3715: 0x00c0, 0x3716: 0x00c0, 0x3717: 0x00c0,
+	0x3718: 0x00c0, 0x3719: 0x00c0, 0x371a: 0x00c0, 0x371b: 0x00c0, 0x371c: 0x00c0, 0x371d: 0x00c0,
+	0x371e: 0x00c0, 0x371f: 0x00c0, 0x3720: 0x00c0, 0x3721: 0x00c0, 0x3722: 0x00c0, 0x3723: 0x00c0,
+	0x3724: 0x00c0, 0x3725: 0x00c0, 0x3726: 0x00c0, 0x3727: 0x00c0, 0x3728: 0x00c0, 0x3729: 0x00c0,
+	0x372a: 0x00c0, 0x372b: 0x00c0, 0x372c: 0x00c0, 0x372d: 0x00c0, 0x372e: 0x00c0, 0x372f: 0x00c0,
+	0x3730: 0x00c0, 0x3731: 0x00c0, 0x3732: 0x00c0,
+	// Block 0xdd, offset 0x3740
+	0x3740: 0x00c0, 0x3741: 0x00c0, 0x3742: 0x00c0, 0x3743: 0x00c0, 0x3744: 0x00c0, 0x3745: 0x00c0,
+	0x3746: 0x00c0, 0x3747: 0x00c0, 0x3748: 0x00c0, 0x3749: 0x00c0, 0x374a: 0x00c0, 0x374b: 0x00c0,
+	0x374c: 0x00c0, 0x374d: 0x00c0, 0x374e: 0x00c0, 0x374f: 0x00c0, 0x3750: 0x00c0, 0x3751: 0x00c0,
+	0x3752: 0x00c0, 0x3753: 0x00c0, 0x3754: 0x00c0, 0x3755: 0x00c0, 0x3756: 0x00c0, 0x3757: 0x00c0,
+	0x3758: 0x00c0, 0x3759: 0x00c0, 0x375a: 0x00c0, 0x375b: 0x00c0, 0x375c: 0x00c0, 0x375d: 0x00c0,
+	0x375e: 0x00c0, 0x375f: 0x00c0, 0x3760: 0x00c0, 0x3761: 0x00c0, 0x3762: 0x00c0, 0x3763: 0x00c0,
+	0x3764: 0x00c0, 0x3765: 0x00c0, 0x3766: 0x00c0, 0x3767: 0x00c0, 0x3768: 0x00c0, 0x3769: 0x00c0,
+	0x376a: 0x00c0, 0x376b: 0x00c0, 0x376c: 0x00c0, 0x376d: 0x00c0, 0x376e: 0x00c0, 0x376f: 0x00c0,
+	0x3770: 0x00c0, 0x3771: 0x00c0, 0x3772: 0x00c0,
+	0x377a: 0x0080, 0x377b: 0x0080,
+	0x377c: 0x0080, 0x377d: 0x0080, 0x377e: 0x0080, 0x377f: 0x0080,
+	// Block 0xde, offset 0x3780
+	0x3780: 0x00c1, 0x3781: 0x00c2, 0x3782: 0x00c2, 0x3783: 0x00c2, 0x3784: 0x00c2, 0x3785: 0x00c2,
+	0x3786: 0x00c2, 0x3787: 0x00c2, 0x3788: 0x00c2, 0x3789: 0x00c2, 0x378a: 0x00c2, 0x378b: 0x00c2,
+	0x378c: 0x00c2, 0x378d: 0x00c2, 0x378e: 0x00c2, 0x378f: 0x00c2, 0x3790: 0x00c2, 0x3791: 0x00c2,
+	0x3792: 0x00c2, 0x3793: 0x00c2, 0x3794: 0x00c2, 0x3795: 0x00c2, 0x3796: 0x00c2, 0x3797: 0x00c2,
+	0x3798: 0x00c2, 0x3799: 0x00c2, 0x379a: 0x00c2, 0x379b: 0x00c2, 0x379c: 0x00c2, 0x379d: 0x00c2,
+	0x379e: 0x00c2, 0x379f: 0x00c2, 0x37a0: 0x00c2, 0x37a1: 0x00c2, 0x37a2: 0x00c4, 0x37a3: 0x00c2,
+	0x37a4: 0x00c3, 0x37a5: 0x00c3, 0x37a6: 0x00c3, 0x37a7: 0x00c3,
+	0x37b0: 0x00c0, 0x37b1: 0x00c0, 0x37b2: 0x00c0, 0x37b3: 0x00c0, 0x37b4: 0x00c0, 0x37b5: 0x00c0,
+	0x37b6: 0x00c0, 0x37b7: 0x00c0, 0x37b8: 0x00c0, 0x37b9: 0x00c0,
+	// Block 0xdf, offset 0x37c0
+	0x37e0: 0x0080, 0x37e1: 0x0080, 0x37e2: 0x0080, 0x37e3: 0x0080,
+	0x37e4: 0x0080, 0x37e5: 0x0080, 0x37e6: 0x0080, 0x37e7: 0x0080, 0x37e8: 0x0080, 0x37e9: 0x0080,
+	0x37ea: 0x0080, 0x37eb: 0x0080, 0x37ec: 0x0080, 0x37ed: 0x0080, 0x37ee: 0x0080, 0x37ef: 0x0080,
+	0x37f0: 0x0080, 0x37f1: 0x0080, 0x37f2: 0x0080, 0x37f3: 0x0080, 0x37f4: 0x0080, 0x37f5: 0x0080,
+	0x37f6: 0x0080, 0x37f7: 0x0080, 0x37f8: 0x0080, 0x37f9: 0x0080, 0x37fa: 0x0080, 0x37fb: 0x0080,
+	0x37fc: 0x0080, 0x37fd: 0x0080, 0x37fe: 0x0080,
+	// Block 0xe0, offset 0x3800
+	0x3800: 0x00c0, 0x3801: 0x00c0, 0x3802: 0x00c0, 0x3803: 0x00c0, 0x3804: 0x00c0, 0x3805: 0x00c0,
+	0x3806: 0x00c0, 0x3807: 0x00c0, 0x3808: 0x00c0, 0x3809: 0x00c0, 0x380a: 0x00c0, 0x380b: 0x00c0,
+	0x380c: 0x00c0, 0x380d: 0x00c0, 0x380e: 0x00c0, 0x380f: 0x00c0, 0x3810: 0x00c0, 0x3811: 0x00c0,
+	0x3812: 0x00c0, 0x3813: 0x00c0, 0x3814: 0x00c0, 0x3815: 0x00c0, 0x3816: 0x00c0, 0x3817: 0x00c0,
+	0x3818: 0x00c0, 0x3819: 0x00c0, 0x381a: 0x00c0, 0x381b: 0x00c0, 0x381c: 0x00c0, 0x381d: 0x00c0,
+	0x381e: 0x00c0, 0x381f: 0x00c0, 0x3820: 0x00c0, 0x3821: 0x00c0, 0x3822: 0x00c0, 0x3823: 0x00c0,
+	0x3824: 0x00c0, 0x3825: 0x00c0, 0x3826: 0x00c0, 0x3827: 0x00c0, 0x3828: 0x00c0, 0x3829: 0x00c0,
+	0x382b: 0x00c3, 0x382c: 0x00c3, 0x382d: 0x0080,
+	0x3830: 0x00c0, 0x3831: 0x00c0,
+	// Block 0xe1, offset 0x3840
+	0x387d: 0x00c3, 0x387e: 0x00c3, 0x387f: 0x00c3,
+	// Block 0xe2, offset 0x3880
+	0x3880: 0x00c0, 0x3881: 0x00c0, 0x3882: 0x00c0, 0x3883: 0x00c0, 0x3884: 0x00c0, 0x3885: 0x00c0,
+	0x3886: 0x00c0, 0x3887: 0x00c0, 0x3888: 0x00c0, 0x3889: 0x00c0, 0x388a: 0x00c0, 0x388b: 0x00c0,
+	0x388c: 0x00c0, 0x388d: 0x00c0, 0x388e: 0x00c0, 0x388f: 0x00c0, 0x3890: 0x00c0, 0x3891: 0x00c0,
+	0x3892: 0x00c0, 0x3893: 0x00c0, 0x3894: 0x00c0, 0x3895: 0x00c0, 0x3896: 0x00c0, 0x3897: 0x00c0,
+	0x3898: 0x00c0, 0x3899: 0x00c0, 0x389a: 0x00c0, 0x389b: 0x00c0, 0x389c: 0x00c0, 0x389d: 0x0080,
+	0x389e: 0x0080, 0x389f: 0x0080, 0x38a0: 0x0080, 0x38a1: 0x0080, 0x38a2: 0x0080, 0x38a3: 0x0080,
+	0x38a4: 0x0080, 0x38a5: 0x0080, 0x38a6: 0x0080, 0x38a7: 0x00c0,
+	0x38b0: 0x00c2, 0x38b1: 0x00c2, 0x38b2: 0x00c2, 0x38b3: 0x00c4, 0x38b4: 0x00c2, 0x38b5: 0x00c2,
+	0x38b6: 0x00c2, 0x38b7: 0x00c2, 0x38b8: 0x00c2, 0x38b9: 0x00c2, 0x38ba: 0x00c2, 0x38bb: 0x00c2,
+	0x38bc: 0x00c2, 0x38bd: 0x00c2, 0x38be: 0x00c2, 0x38bf: 0x00c2,
+	// Block 0xe3, offset 0x38c0
+	0x38c0: 0x00c2, 0x38c1: 0x00c2, 0x38c2: 0x00c2, 0x38c3: 0x00c2, 0x38c4: 0x00c2, 0x38c5: 0x00c0,
+	0x38c6: 0x00c3, 0x38c7: 0x00c3, 0x38c8: 0x00c3, 0x38c9: 0x00c3, 0x38ca: 0x00c3, 0x38cb: 0x00c3,
+	0x38cc: 0x00c3, 0x38cd: 0x00c3, 0x38ce: 0x00c3, 0x38cf: 0x00c3, 0x38d0: 0x00c3, 0x38d1: 0x0082,
+	0x38d2: 0x0082, 0x38d3: 0x0082, 0x38d4: 0x0084, 0x38d5: 0x0080, 0x38d6: 0x0080, 0x38d7: 0x0080,
+	0x38d8: 0x0080, 0x38d9: 0x0080,
+	0x38f0: 0x00c2, 0x38f1: 0x00c2, 0x38f2: 0x00c2, 0x38f3: 0x00c2, 0x38f4: 0x00c4, 0x38f5: 0x00c4,
+	0x38f6: 0x00c2, 0x38f7: 0x00c2, 0x38f8: 0x00c2, 0x38f9: 0x00c2, 0x38fa: 0x00c2, 0x38fb: 0x00c2,
+	0x38fc: 0x00c2, 0x38fd: 0x00c2, 0x38fe: 0x00c2, 0x38ff: 0x00c2,
+	// Block 0xe4, offset 0x3900
+	0x3900: 0x00c2, 0x3901: 0x00c2, 0x3902: 0x00c3, 0x3903: 0x00c3, 0x3904: 0x00c3, 0x3905: 0x00c3,
+	0x3906: 0x0080, 0x3907: 0x0080, 0x3908: 0x0080, 0x3909: 0x0080,
+	0x3930: 0x00c2, 0x3931: 0x00c0, 0x3932: 0x00c2, 0x3933: 0x00c2, 0x3934: 0x00c4, 0x3935: 0x00c4,
+	0x3936: 0x00c4, 0x3937: 0x00c0, 0x3938: 0x00c2, 0x3939: 0x00c4, 0x393a: 0x00c4, 0x393b: 0x00c2,
+	0x393c: 0x00c2, 0x393d: 0x00c4, 0x393e: 0x00c2, 0x393f: 0x00c2,
+	// Block 0xe5, offset 0x3940
+	0x3940: 0x00c0, 0x3941: 0x00c2, 0x3942: 0x00c4, 0x3943: 0x00c4, 0x3944: 0x00c2, 0x3945: 0x0080,
+	0x3946: 0x0080, 0x3947: 0x0080, 0x3948: 0x0080, 0x3949: 0x0084, 0x394a: 0x0082, 0x394b: 0x0081,
+	0x3960: 0x00c0, 0x3961: 0x00c0, 0x3962: 0x00c0, 0x3963: 0x00c0,
+	0x3964: 0x00c0, 0x3965: 0x00c0, 0x3966: 0x00c0, 0x3967: 0x00c0, 0x3968: 0x00c0, 0x3969: 0x00c0,
+	0x396a: 0x00c0, 0x396b: 0x00c0, 0x396c: 0x00c0, 0x396d: 0x00c0, 0x396e: 0x00c0, 0x396f: 0x00c0,
+	0x3970: 0x00c0, 0x3971: 0x00c0, 0x3972: 0x00c0, 0x3973: 0x00c0, 0x3974: 0x00c0, 0x3975: 0x00c0,
+	0x3976: 0x00c0,
+	// Block 0xe6, offset 0x3980
+	0x3980: 0x00c0, 0x3981: 0x00c3, 0x3982: 0x00c0, 0x3983: 0x00c0, 0x3984: 0x00c0, 0x3985: 0x00c0,
+	0x3986: 0x00c0, 0x3987: 0x00c0, 0x3988: 0x00c0, 0x3989: 0x00c0, 0x398a: 0x00c0, 0x398b: 0x00c0,
+	0x398c: 0x00c0, 0x398d: 0x00c0, 0x398e: 0x00c0, 0x398f: 0x00c0, 0x3990: 0x00c0, 0x3991: 0x00c0,
+	0x3992: 0x00c0, 0x3993: 0x00c0, 0x3994: 0x00c0, 0x3995: 0x00c0, 0x3996: 0x00c0, 0x3997: 0x00c0,
+	0x3998: 0x00c0, 0x3999: 0x00c0, 0x399a: 0x00c0, 0x399b: 0x00c0, 0x399c: 0x00c0, 0x399d: 0x00c0,
+	0x399e: 0x00c0, 0x399f: 0x00c0, 0x39a0: 0x00c0, 0x39a1: 0x00c0, 0x39a2: 0x00c0, 0x39a3: 0x00c0,
+	0x39a4: 0x00c0, 0x39a5: 0x00c0, 0x39a6: 0x00c0, 0x39a7: 0x00c0, 0x39a8: 0x00c0, 0x39a9: 0x00c0,
+	0x39aa: 0x00c0, 0x39ab: 0x00c0, 0x39ac: 0x00c0, 0x39ad: 0x00c0, 0x39ae: 0x00c0, 0x39af: 0x00c0,
+	0x39b0: 0x00c0, 0x39b1: 0x00c0, 0x39b2: 0x00c0, 0x39b3: 0x00c0, 0x39b4: 0x00c0, 0x39b5: 0x00c0,
+	0x39b6: 0x00c0, 0x39b7: 0x00c0, 0x39b8: 0x00c3, 0x39b9: 0x00c3, 0x39ba: 0x00c3, 0x39bb: 0x00c3,
+	0x39bc: 0x00c3, 0x39bd: 0x00c3, 0x39be: 0x00c3, 0x39bf: 0x00c3,
+	// Block 0xe7, offset 0x39c0
+	0x39c0: 0x00c3, 0x39c1: 0x00c3, 0x39c2: 0x00c3, 0x39c3: 0x00c3, 0x39c4: 0x00c3, 0x39c5: 0x00c3,
+	0x39c6: 0x00c6, 0x39c7: 0x0080, 0x39c8: 0x0080, 0x39c9: 0x0080, 0x39ca: 0x0080, 0x39cb: 0x0080,
+	0x39cc: 0x0080, 0x39cd: 0x0080,
+	0x39d2: 0x0080, 0x39d3: 0x0080, 0x39d4: 0x0080, 0x39d5: 0x0080, 0x39d6: 0x0080, 0x39d7: 0x0080,
+	0x39d8: 0x0080, 0x39d9: 0x0080, 0x39da: 0x0080, 0x39db: 0x0080, 0x39dc: 0x0080, 0x39dd: 0x0080,
+	0x39de: 0x0080, 0x39df: 0x0080, 0x39e0: 0x0080, 0x39e1: 0x0080, 0x39e2: 0x0080, 0x39e3: 0x0080,
+	0x39e4: 0x0080, 0x39e5: 0x0080, 0x39e6: 0x00c0, 0x39e7: 0x00c0, 0x39e8: 0x00c0, 0x39e9: 0x00c0,
+	0x39ea: 0x00c0, 0x39eb: 0x00c0, 0x39ec: 0x00c0, 0x39ed: 0x00c0, 0x39ee: 0x00c0, 0x39ef: 0x00c0,
+	0x39f0: 0x00c6, 0x39f1: 0x00c0, 0x39f2: 0x00c0, 0x39f3: 0x00c3, 0x39f4: 0x00c3, 0x39f5: 0x00c0,
+	0x39ff: 0x00c6,
+	// Block 0xe8, offset 0x3a00
+	0x3a00: 0x00c3, 0x3a01: 0x00c3, 0x3a02: 0x00c0, 0x3a03: 0x00c0, 0x3a04: 0x00c0, 0x3a05: 0x00c0,
+	0x3a06: 0x00c0, 0x3a07: 0x00c0, 0x3a08: 0x00c0, 0x3a09: 0x00c0, 0x3a0a: 0x00c0, 0x3a0b: 0x00c0,
+	0x3a0c: 0x00c0, 0x3a0d: 0x00c0, 0x3a0e: 0x00c0, 0x3a0f: 0x00c0, 0x3a10: 0x00c0, 0x3a11: 0x00c0,
+	0x3a12: 0x00c0, 0x3a13: 0x00c0, 0x3a14: 0x00c0, 0x3a15: 0x00c0, 0x3a16: 0x00c0, 0x3a17: 0x00c0,
+	0x3a18: 0x00c0, 0x3a19: 0x00c0, 0x3a1a: 0x00c0, 0x3a1b: 0x00c0, 0x3a1c: 0x00c0, 0x3a1d: 0x00c0,
+	0x3a1e: 0x00c0, 0x3a1f: 0x00c0, 0x3a20: 0x00c0, 0x3a21: 0x00c0, 0x3a22: 0x00c0, 0x3a23: 0x00c0,
+	0x3a24: 0x00c0, 0x3a25: 0x00c0, 0x3a26: 0x00c0, 0x3a27: 0x00c0, 0x3a28: 0x00c0, 0x3a29: 0x00c0,
+	0x3a2a: 0x00c0, 0x3a2b: 0x00c0, 0x3a2c: 0x00c0, 0x3a2d: 0x00c0, 0x3a2e: 0x00c0, 0x3a2f: 0x00c0,
+	0x3a30: 0x00c0, 0x3a31: 0x00c0, 0x3a32: 0x00c0, 0x3a33: 0x00c3, 0x3a34: 0x00c3, 0x3a35: 0x00c3,
+	0x3a36: 0x00c3, 0x3a37: 0x00c0, 0x3a38: 0x00c0, 0x3a39: 0x00c6, 0x3a3a: 0x00c3, 0x3a3b: 0x0080,
+	0x3a3c: 0x0080, 0x3a3d: 0x0040, 0x3a3e: 0x0080, 0x3a3f: 0x0080,
+	// Block 0xe9, offset 0x3a40
+	0x3a40: 0x0080, 0x3a41: 0x0080, 0x3a42: 0x00c3,
+	0x3a4d: 0x0040, 0x3a50: 0x00c0, 0x3a51: 0x00c0,
+	0x3a52: 0x00c0, 0x3a53: 0x00c0, 0x3a54: 0x00c0, 0x3a55: 0x00c0, 0x3a56: 0x00c0, 0x3a57: 0x00c0,
+	0x3a58: 0x00c0, 0x3a59: 0x00c0, 0x3a5a: 0x00c0, 0x3a5b: 0x00c0, 0x3a5c: 0x00c0, 0x3a5d: 0x00c0,
+	0x3a5e: 0x00c0, 0x3a5f: 0x00c0, 0x3a60: 0x00c0, 0x3a61: 0x00c0, 0x3a62: 0x00c0, 0x3a63: 0x00c0,
+	0x3a64: 0x00c0, 0x3a65: 0x00c0, 0x3a66: 0x00c0, 0x3a67: 0x00c0, 0x3a68: 0x00c0,
+	0x3a70: 0x00c0, 0x3a71: 0x00c0, 0x3a72: 0x00c0, 0x3a73: 0x00c0, 0x3a74: 0x00c0, 0x3a75: 0x00c0,
+	0x3a76: 0x00c0, 0x3a77: 0x00c0, 0x3a78: 0x00c0, 0x3a79: 0x00c0,
+	// Block 0xea, offset 0x3a80
+	0x3a80: 0x00c3, 0x3a81: 0x00c3, 0x3a82: 0x00c3, 0x3a83: 0x00c0, 0x3a84: 0x00c0, 0x3a85: 0x00c0,
+	0x3a86: 0x00c0, 0x3a87: 0x00c0, 0x3a88: 0x00c0, 0x3a89: 0x00c0, 0x3a8a: 0x00c0, 0x3a8b: 0x00c0,
+	0x3a8c: 0x00c0, 0x3a8d: 0x00c0, 0x3a8e: 0x00c0, 0x3a8f: 0x00c0, 0x3a90: 0x00c0, 0x3a91: 0x00c0,
+	0x3a92: 0x00c0, 0x3a93: 0x00c0, 0x3a94: 0x00c0, 0x3a95: 0x00c0, 0x3a96: 0x00c0, 0x3a97: 0x00c0,
+	0x3a98: 0x00c0, 0x3a99: 0x00c0, 0x3a9a: 0x00c0, 0x3a9b: 0x00c0, 0x3a9c: 0x00c0, 0x3a9d: 0x00c0,
+	0x3a9e: 0x00c0, 0x3a9f: 0x00c0, 0x3aa0: 0x00c0, 0x3aa1: 0x00c0, 0x3aa2: 0x00c0, 0x3aa3: 0x00c0,
+	0x3aa4: 0x00c0, 0x3aa5: 0x00c0, 0x3aa6: 0x00c0, 0x3aa7: 0x00c3, 0x3aa8: 0x00c3, 0x3aa9: 0x00c3,
+	0x3aaa: 0x00c3, 0x3aab: 0x00c3, 0x3aac: 0x00c0, 0x3aad: 0x00c3, 0x3aae: 0x00c3, 0x3aaf: 0x00c3,
+	0x3ab0: 0x00c3, 0x3ab1: 0x00c3, 0x3ab2: 0x00c3, 0x3ab3: 0x00c6, 0x3ab4: 0x00c6,
+	0x3ab6: 0x00c0, 0x3ab7: 0x00c0, 0x3ab8: 0x00c0, 0x3ab9: 0x00c0, 0x3aba: 0x00c0, 0x3abb: 0x00c0,
+	0x3abc: 0x00c0, 0x3abd: 0x00c0, 0x3abe: 0x00c0, 0x3abf: 0x00c0,
+	// Block 0xeb, offset 0x3ac0
+	0x3ac0: 0x0080, 0x3ac1: 0x0080, 0x3ac2: 0x0080, 0x3ac3: 0x0080, 0x3ac4: 0x00c0, 0x3ac5: 0x00c0,
+	0x3ac6: 0x00c0, 0x3ac7: 0x00c0,
+	0x3ad0: 0x00c0, 0x3ad1: 0x00c0,
+	0x3ad2: 0x00c0, 0x3ad3: 0x00c0, 0x3ad4: 0x00c0, 0x3ad5: 0x00c0, 0x3ad6: 0x00c0, 0x3ad7: 0x00c0,
+	0x3ad8: 0x00c0, 0x3ad9: 0x00c0, 0x3ada: 0x00c0, 0x3adb: 0x00c0, 0x3adc: 0x00c0, 0x3add: 0x00c0,
+	0x3ade: 0x00c0, 0x3adf: 0x00c0, 0x3ae0: 0x00c0, 0x3ae1: 0x00c0, 0x3ae2: 0x00c0, 0x3ae3: 0x00c0,
+	0x3ae4: 0x00c0, 0x3ae5: 0x00c0, 0x3ae6: 0x00c0, 0x3ae7: 0x00c0, 0x3ae8: 0x00c0, 0x3ae9: 0x00c0,
+	0x3aea: 0x00c0, 0x3aeb: 0x00c0, 0x3aec: 0x00c0, 0x3aed: 0x00c0, 0x3aee: 0x00c0, 0x3aef: 0x00c0,
+	0x3af0: 0x00c0, 0x3af1: 0x00c0, 0x3af2: 0x00c0, 0x3af3: 0x00c3, 0x3af4: 0x0080, 0x3af5: 0x0080,
+	0x3af6: 0x00c0,
+	// Block 0xec, offset 0x3b00
+	0x3b00: 0x00c3, 0x3b01: 0x00c3, 0x3b02: 0x00c0, 0x3b03: 0x00c0, 0x3b04: 0x00c0, 0x3b05: 0x00c0,
+	0x3b06: 0x00c0, 0x3b07: 0x00c0, 0x3b08: 0x00c0, 0x3b09: 0x00c0, 0x3b0a: 0x00c0, 0x3b0b: 0x00c0,
+	0x3b0c: 0x00c0, 0x3b0d: 0x00c0, 0x3b0e: 0x00c0, 0x3b0f: 0x00c0, 0x3b10: 0x00c0, 0x3b11: 0x00c0,
+	0x3b12: 0x00c0, 0x3b13: 0x00c0, 0x3b14: 0x00c0, 0x3b15: 0x00c0, 0x3b16: 0x00c0, 0x3b17: 0x00c0,
+	0x3b18: 0x00c0, 0x3b19: 0x00c0, 0x3b1a: 0x00c0, 0x3b1b: 0x00c0, 0x3b1c: 0x00c0, 0x3b1d: 0x00c0,
+	0x3b1e: 0x00c0, 0x3b1f: 0x00c0, 0x3b20: 0x00c0, 0x3b21: 0x00c0, 0x3b22: 0x00c0, 0x3b23: 0x00c0,
+	0x3b24: 0x00c0, 0x3b25: 0x00c0, 0x3b26: 0x00c0, 0x3b27: 0x00c0, 0x3b28: 0x00c0, 0x3b29: 0x00c0,
+	0x3b2a: 0x00c0, 0x3b2b: 0x00c0, 0x3b2c: 0x00c0, 0x3b2d: 0x00c0, 0x3b2e: 0x00c0, 0x3b2f: 0x00c0,
+	0x3b30: 0x00c0, 0x3b31: 0x00c0, 0x3b32: 0x00c0, 0x3b33: 0x00c0, 0x3b34: 0x00c0, 0x3b35: 0x00c0,
+	0x3b36: 0x00c3, 0x3b37: 0x00c3, 0x3b38: 0x00c3, 0x3b39: 0x00c3, 0x3b3a: 0x00c3, 0x3b3b: 0x00c3,
+	0x3b3c: 0x00c3, 0x3b3d: 0x00c3, 0x3b3e: 0x00c3, 0x3b3f: 0x00c0,
+	// Block 0xed, offset 0x3b40
+	0x3b40: 0x00c5, 0x3b41: 0x00c0, 0x3b42: 0x00c0, 0x3b43: 0x00c0, 0x3b44: 0x00c0, 0x3b45: 0x0080,
+	0x3b46: 0x0080, 0x3b47: 0x0080, 0x3b48: 0x0080, 0x3b49: 0x00c3, 0x3b4a: 0x00c3, 0x3b4b: 0x00c3,
+	0x3b4c: 0x00c3, 0x3b4d: 0x0080, 0x3b4e: 0x00c0, 0x3b4f: 0x00c3, 0x3b50: 0x00c0, 0x3b51: 0x00c0,
+	0x3b52: 0x00c0, 0x3b53: 0x00c0, 0x3b54: 0x00c0, 0x3b55: 0x00c0, 0x3b56: 0x00c0, 0x3b57: 0x00c0,
+	0x3b58: 0x00c0, 0x3b59: 0x00c0, 0x3b5a: 0x00c0, 0x3b5b: 0x0080, 0x3b5c: 0x00c0, 0x3b5d: 0x0080,
+	0x3b5e: 0x0080, 0x3b5f: 0x0080, 0x3b61: 0x0080, 0x3b62: 0x0080, 0x3b63: 0x0080,
+	0x3b64: 0x0080, 0x3b65: 0x0080, 0x3b66: 0x0080, 0x3b67: 0x0080, 0x3b68: 0x0080, 0x3b69: 0x0080,
+	0x3b6a: 0x0080, 0x3b6b: 0x0080, 0x3b6c: 0x0080, 0x3b6d: 0x0080, 0x3b6e: 0x0080, 0x3b6f: 0x0080,
+	0x3b70: 0x0080, 0x3b71: 0x0080, 0x3b72: 0x0080, 0x3b73: 0x0080, 0x3b74: 0x0080,
+	// Block 0xee, offset 0x3b80
+	0x3b80: 0x00c0, 0x3b81: 0x00c0, 0x3b82: 0x00c0, 0x3b83: 0x00c0, 0x3b84: 0x00c0, 0x3b85: 0x00c0,
+	0x3b86: 0x00c0, 0x3b87: 0x00c0, 0x3b88: 0x00c0, 0x3b89: 0x00c0, 0x3b8a: 0x00c0, 0x3b8b: 0x00c0,
+	0x3b8c: 0x00c0, 0x3b8d: 0x00c0, 0x3b8e: 0x00c0, 0x3b8f: 0x00c0, 0x3b90: 0x00c0, 0x3b91: 0x00c0,
+	0x3b93: 0x00c0, 0x3b94: 0x00c0, 0x3b95: 0x00c0, 0x3b96: 0x00c0, 0x3b97: 0x00c0,
+	0x3b98: 0x00c0, 0x3b99: 0x00c0, 0x3b9a: 0x00c0, 0x3b9b: 0x00c0, 0x3b9c: 0x00c0, 0x3b9d: 0x00c0,
+	0x3b9e: 0x00c0, 0x3b9f: 0x00c0, 0x3ba0: 0x00c0, 0x3ba1: 0x00c0, 0x3ba2: 0x00c0, 0x3ba3: 0x00c0,
+	0x3ba4: 0x00c0, 0x3ba5: 0x00c0, 0x3ba6: 0x00c0, 0x3ba7: 0x00c0, 0x3ba8: 0x00c0, 0x3ba9: 0x00c0,
+	0x3baa: 0x00c0, 0x3bab: 0x00c0, 0x3bac: 0x00c0, 0x3bad: 0x00c0, 0x3bae: 0x00c0, 0x3baf: 0x00c3,
+	0x3bb0: 0x00c3, 0x3bb1: 0x00c3, 0x3bb2: 0x00c0, 0x3bb3: 0x00c0, 0x3bb4: 0x00c3, 0x3bb5: 0x00c5,
+	0x3bb6: 0x00c3, 0x3bb7: 0x00c3, 0x3bb8: 0x0080, 0x3bb9: 0x0080, 0x3bba: 0x0080, 0x3bbb: 0x0080,
+	0x3bbc: 0x0080, 0x3bbd: 0x0080, 0x3bbe: 0x00c3, 0x3bbf: 0x00c0,
+	// Block 0xef, offset 0x3bc0
+	0x3bc0: 0x00c0, 0x3bc1: 0x00c3,
+	// Block 0xf0, offset 0x3c00
+	0x3c00: 0x00c0, 0x3c01: 0x00c0, 0x3c02: 0x00c0, 0x3c03: 0x00c0, 0x3c04: 0x00c0, 0x3c05: 0x00c0,
+	0x3c06: 0x00c0, 0x3c08: 0x00c0, 0x3c0a: 0x00c0, 0x3c0b: 0x00c0,
+	0x3c0c: 0x00c0, 0x3c0d: 0x00c0, 0x3c0f: 0x00c0, 0x3c10: 0x00c0, 0x3c11: 0x00c0,
+	0x3c12: 0x00c0, 0x3c13: 0x00c0, 0x3c14: 0x00c0, 0x3c15: 0x00c0, 0x3c16: 0x00c0, 0x3c17: 0x00c0,
+	0x3c18: 0x00c0, 0x3c19: 0x00c0, 0x3c1a: 0x00c0, 0x3c1b: 0x00c0, 0x3c1c: 0x00c0, 0x3c1d: 0x00c0,
+	0x3c1f: 0x00c0, 0x3c20: 0x00c0, 0x3c21: 0x00c0, 0x3c22: 0x00c0, 0x3c23: 0x00c0,
+	0x3c24: 0x00c0, 0x3c25: 0x00c0, 0x3c26: 0x00c0, 0x3c27: 0x00c0, 0x3c28: 0x00c0, 0x3c29: 0x0080,
+	0x3c30: 0x00c0, 0x3c31: 0x00c0, 0x3c32: 0x00c0, 0x3c33: 0x00c0, 0x3c34: 0x00c0, 0x3c35: 0x00c0,
+	0x3c36: 0x00c0, 0x3c37: 0x00c0, 0x3c38: 0x00c0, 0x3c39: 0x00c0, 0x3c3a: 0x00c0, 0x3c3b: 0x00c0,
+	0x3c3c: 0x00c0, 0x3c3d: 0x00c0, 0x3c3e: 0x00c0, 0x3c3f: 0x00c0,
+	// Block 0xf1, offset 0x3c40
+	0x3c40: 0x00c0, 0x3c41: 0x00c0, 0x3c42: 0x00c0, 0x3c43: 0x00c0, 0x3c44: 0x00c0, 0x3c45: 0x00c0,
+	0x3c46: 0x00c0, 0x3c47: 0x00c0, 0x3c48: 0x00c0, 0x3c49: 0x00c0, 0x3c4a: 0x00c0, 0x3c4b: 0x00c0,
+	0x3c4c: 0x00c0, 0x3c4d: 0x00c0, 0x3c4e: 0x00c0, 0x3c4f: 0x00c0, 0x3c50: 0x00c0, 0x3c51: 0x00c0,
+	0x3c52: 0x00c0, 0x3c53: 0x00c0, 0x3c54: 0x00c0, 0x3c55: 0x00c0, 0x3c56: 0x00c0, 0x3c57: 0x00c0,
+	0x3c58: 0x00c0, 0x3c59: 0x00c0, 0x3c5a: 0x00c0, 0x3c5b: 0x00c0, 0x3c5c: 0x00c0, 0x3c5d: 0x00c0,
+	0x3c5e: 0x00c0, 0x3c5f: 0x00c3, 0x3c60: 0x00c0, 0x3c61: 0x00c0, 0x3c62: 0x00c0, 0x3c63: 0x00c3,
+	0x3c64: 0x00c3, 0x3c65: 0x00c3, 0x3c66: 0x00c3, 0x3c67: 0x00c3, 0x3c68: 0x00c3, 0x3c69: 0x00c3,
+	0x3c6a: 0x00c6,
+	0x3c70: 0x00c0, 0x3c71: 0x00c0, 0x3c72: 0x00c0, 0x3c73: 0x00c0, 0x3c74: 0x00c0, 0x3c75: 0x00c0,
+	0x3c76: 0x00c0, 0x3c77: 0x00c0, 0x3c78: 0x00c0, 0x3c79: 0x00c0,
+	// Block 0xf2, offset 0x3c80
+	0x3c80: 0x00c3, 0x3c81: 0x00c3, 0x3c82: 0x00c0, 0x3c83: 0x00c0, 0x3c85: 0x00c0,
+	0x3c86: 0x00c0, 0x3c87: 0x00c0, 0x3c88: 0x00c0, 0x3c89: 0x00c0, 0x3c8a: 0x00c0, 0x3c8b: 0x00c0,
+	0x3c8c: 0x00c0, 0x3c8f: 0x00c0, 0x3c90: 0x00c0,
+	0x3c93: 0x00c0, 0x3c94: 0x00c0, 0x3c95: 0x00c0, 0x3c96: 0x00c0, 0x3c97: 0x00c0,
+	0x3c98: 0x00c0, 0x3c99: 0x00c0, 0x3c9a: 0x00c0, 0x3c9b: 0x00c0, 0x3c9c: 0x00c0, 0x3c9d: 0x00c0,
+	0x3c9e: 0x00c0, 0x3c9f: 0x00c0, 0x3ca0: 0x00c0, 0x3ca1: 0x00c0, 0x3ca2: 0x00c0, 0x3ca3: 0x00c0,
+	0x3ca4: 0x00c0, 0x3ca5: 0x00c0, 0x3ca6: 0x00c0, 0x3ca7: 0x00c0, 0x3ca8: 0x00c0,
+	0x3caa: 0x00c0, 0x3cab: 0x00c0, 0x3cac: 0x00c0, 0x3cad: 0x00c0, 0x3cae: 0x00c0, 0x3caf: 0x00c0,
+	0x3cb0: 0x00c0, 0x3cb2: 0x00c0, 0x3cb3: 0x00c0, 0x3cb5: 0x00c0,
+	0x3cb6: 0x00c0, 0x3cb7: 0x00c0, 0x3cb8: 0x00c0, 0x3cb9: 0x00c0, 0x3cbb: 0x00c3,
+	0x3cbc: 0x00c3, 0x3cbd: 0x00c0, 0x3cbe: 0x00c0, 0x3cbf: 0x00c0,
+	// Block 0xf3, offset 0x3cc0
+	0x3cc0: 0x00c3, 0x3cc1: 0x00c0, 0x3cc2: 0x00c0, 0x3cc3: 0x00c0, 0x3cc4: 0x00c0,
+	0x3cc7: 0x00c0, 0x3cc8: 0x00c0, 0x3ccb: 0x00c0,
+	0x3ccc: 0x00c0, 0x3ccd: 0x00c5, 0x3cd0: 0x00c0,
+	0x3cd7: 0x00c0,
+	0x3cdd: 0x00c0,
+	0x3cde: 0x00c0, 0x3cdf: 0x00c0, 0x3ce0: 0x00c0, 0x3ce1: 0x00c0, 0x3ce2: 0x00c0, 0x3ce3: 0x00c0,
+	0x3ce6: 0x00c3, 0x3ce7: 0x00c3, 0x3ce8: 0x00c3, 0x3ce9: 0x00c3,
+	0x3cea: 0x00c3, 0x3ceb: 0x00c3, 0x3cec: 0x00c3,
+	0x3cf0: 0x00c3, 0x3cf1: 0x00c3, 0x3cf2: 0x00c3, 0x3cf3: 0x00c3, 0x3cf4: 0x00c3,
+	// Block 0xf4, offset 0x3d00
+	0x3d00: 0x00c0, 0x3d01: 0x00c0, 0x3d02: 0x00c0, 0x3d03: 0x00c0, 0x3d04: 0x00c0, 0x3d05: 0x00c0,
+	0x3d06: 0x00c0, 0x3d07: 0x00c0, 0x3d08: 0x00c0, 0x3d09: 0x00c0, 0x3d0a: 0x00c0, 0x3d0b: 0x00c0,
+	0x3d0c: 0x00c0, 0x3d0d: 0x00c0, 0x3d0e: 0x00c0, 0x3d0f: 0x00c0, 0x3d10: 0x00c0, 0x3d11: 0x00c0,
+	0x3d12: 0x00c0, 0x3d13: 0x00c0, 0x3d14: 0x00c0, 0x3d15: 0x00c0, 0x3d16: 0x00c0, 0x3d17: 0x00c0,
+	0x3d18: 0x00c0, 0x3d19: 0x00c0, 0x3d1a: 0x00c0, 0x3d1b: 0x00c0, 0x3d1c: 0x00c0, 0x3d1d: 0x00c0,
+	0x3d1e: 0x00c0, 0x3d1f: 0x00c0, 0x3d20: 0x00c0, 0x3d21: 0x00c0, 0x3d22: 0x00c0, 0x3d23: 0x00c0,
+	0x3d24: 0x00c0, 0x3d25: 0x00c0, 0x3d26: 0x00c0, 0x3d27: 0x00c0, 0x3d28: 0x00c0, 0x3d29: 0x00c0,
+	0x3d2a: 0x00c0, 0x3d2b: 0x00c0, 0x3d2c: 0x00c0, 0x3d2d: 0x00c0, 0x3d2e: 0x00c0, 0x3d2f: 0x00c0,
+	0x3d30: 0x00c0, 0x3d31: 0x00c0, 0x3d32: 0x00c0, 0x3d33: 0x00c0, 0x3d34: 0x00c0, 0x3d35: 0x00c0,
+	0x3d36: 0x00c0, 0x3d37: 0x00c0, 0x3d38: 0x00c3, 0x3d39: 0x00c3, 0x3d3a: 0x00c3, 0x3d3b: 0x00c3,
+	0x3d3c: 0x00c3, 0x3d3d: 0x00c3, 0x3d3e: 0x00c3, 0x3d3f: 0x00c3,
+	// Block 0xf5, offset 0x3d40
+	0x3d40: 0x00c0, 0x3d41: 0x00c0, 0x3d42: 0x00c6, 0x3d43: 0x00c3, 0x3d44: 0x00c3, 0x3d45: 0x00c0,
+	0x3d46: 0x00c3, 0x3d47: 0x00c0, 0x3d48: 0x00c0, 0x3d49: 0x00c0, 0x3d4a: 0x00c0, 0x3d4b: 0x0080,
+	0x3d4c: 0x0080, 0x3d4d: 0x0080, 0x3d4e: 0x0080, 0x3d4f: 0x0080, 0x3d50: 0x00c0, 0x3d51: 0x00c0,
+	0x3d52: 0x00c0, 0x3d53: 0x00c0, 0x3d54: 0x00c0, 0x3d55: 0x00c0, 0x3d56: 0x00c0, 0x3d57: 0x00c0,
+	0x3d58: 0x00c0, 0x3d59: 0x00c0, 0x3d5a: 0x0080, 0x3d5b: 0x0080, 0x3d5d: 0x0080,
+	0x3d5e: 0x00c3, 0x3d5f: 0x00c0, 0x3d60: 0x00c0, 0x3d61: 0x00c0,
+	// Block 0xf6, offset 0x3d80
+	0x3d80: 0x00c0, 0x3d81: 0x00c0, 0x3d82: 0x00c0, 0x3d83: 0x00c0, 0x3d84: 0x00c0, 0x3d85: 0x00c0,
+	0x3d86: 0x00c0, 0x3d87: 0x00c0, 0x3d88: 0x00c0, 0x3d89: 0x00c0, 0x3d8a: 0x00c0, 0x3d8b: 0x00c0,
+	0x3d8c: 0x00c0, 0x3d8d: 0x00c0, 0x3d8e: 0x00c0, 0x3d8f: 0x00c0, 0x3d90: 0x00c0, 0x3d91: 0x00c0,
+	0x3d92: 0x00c0, 0x3d93: 0x00c0, 0x3d94: 0x00c0, 0x3d95: 0x00c0, 0x3d96: 0x00c0, 0x3d97: 0x00c0,
+	0x3d98: 0x00c0, 0x3d99: 0x00c0, 0x3d9a: 0x00c0, 0x3d9b: 0x00c0, 0x3d9c: 0x00c0, 0x3d9d: 0x00c0,
+	0x3d9e: 0x00c0, 0x3d9f: 0x00c0, 0x3da0: 0x00c0, 0x3da1: 0x00c0, 0x3da2: 0x00c0, 0x3da3: 0x00c0,
+	0x3da4: 0x00c0, 0x3da5: 0x00c0, 0x3da6: 0x00c0, 0x3da7: 0x00c0, 0x3da8: 0x00c0, 0x3da9: 0x00c0,
+	0x3daa: 0x00c0, 0x3dab: 0x00c0, 0x3dac: 0x00c0, 0x3dad: 0x00c0, 0x3dae: 0x00c0, 0x3daf: 0x00c0,
+	0x3db0: 0x00c0, 0x3db1: 0x00c0, 0x3db2: 0x00c0, 0x3db3: 0x00c3, 0x3db4: 0x00c3, 0x3db5: 0x00c3,
+	0x3db6: 0x00c3, 0x3db7: 0x00c3, 0x3db8: 0x00c3, 0x3db9: 0x00c0, 0x3dba: 0x00c3, 0x3dbb: 0x00c0,
+	0x3dbc: 0x00c0, 0x3dbd: 0x00c0, 0x3dbe: 0x00c0, 0x3dbf: 0x00c3,
+	// Block 0xf7, offset 0x3dc0
+	0x3dc0: 0x00c3, 0x3dc1: 0x00c0, 0x3dc2: 0x00c6, 0x3dc3: 0x00c3, 0x3dc4: 0x00c0, 0x3dc5: 0x00c0,
+	0x3dc6: 0x0080, 0x3dc7: 0x00c0,
+	0x3dd0: 0x00c0, 0x3dd1: 0x00c0,
+	0x3dd2: 0x00c0, 0x3dd3: 0x00c0, 0x3dd4: 0x00c0, 0x3dd5: 0x00c0, 0x3dd6: 0x00c0, 0x3dd7: 0x00c0,
+	0x3dd8: 0x00c0, 0x3dd9: 0x00c0,
+	// Block 0xf8, offset 0x3e00
+	0x3e00: 0x00c0, 0x3e01: 0x00c0, 0x3e02: 0x00c0, 0x3e03: 0x00c0, 0x3e04: 0x00c0, 0x3e05: 0x00c0,
+	0x3e06: 0x00c0, 0x3e07: 0x00c0, 0x3e08: 0x00c0, 0x3e09: 0x00c0, 0x3e0a: 0x00c0, 0x3e0b: 0x00c0,
+	0x3e0c: 0x00c0, 0x3e0d: 0x00c0, 0x3e0e: 0x00c0, 0x3e0f: 0x00c0, 0x3e10: 0x00c0, 0x3e11: 0x00c0,
+	0x3e12: 0x00c0, 0x3e13: 0x00c0, 0x3e14: 0x00c0, 0x3e15: 0x00c0, 0x3e16: 0x00c0, 0x3e17: 0x00c0,
+	0x3e18: 0x00c0, 0x3e19: 0x00c0, 0x3e1a: 0x00c0, 0x3e1b: 0x00c0, 0x3e1c: 0x00c0, 0x3e1d: 0x00c0,
+	0x3e1e: 0x00c0, 0x3e1f: 0x00c0, 0x3e20: 0x00c0, 0x3e21: 0x00c0, 0x3e22: 0x00c0, 0x3e23: 0x00c0,
+	0x3e24: 0x00c0, 0x3e25: 0x00c0, 0x3e26: 0x00c0, 0x3e27: 0x00c0, 0x3e28: 0x00c0, 0x3e29: 0x00c0,
+	0x3e2a: 0x00c0, 0x3e2b: 0x00c0, 0x3e2c: 0x00c0, 0x3e2d: 0x00c0, 0x3e2e: 0x00c0, 0x3e2f: 0x00c0,
+	0x3e30: 0x00c0, 0x3e31: 0x00c0, 0x3e32: 0x00c3, 0x3e33: 0x00c3, 0x3e34: 0x00c3, 0x3e35: 0x00c3,
+	0x3e38: 0x00c0, 0x3e39: 0x00c0, 0x3e3a: 0x00c0, 0x3e3b: 0x00c0,
+	0x3e3c: 0x00c3, 0x3e3d: 0x00c3, 0x3e3e: 0x00c0, 0x3e3f: 0x00c6,
+	// Block 0xf9, offset 0x3e40
+	0x3e40: 0x00c3, 0x3e41: 0x0080, 0x3e42: 0x0080, 0x3e43: 0x0080, 0x3e44: 0x0080, 0x3e45: 0x0080,
+	0x3e46: 0x0080, 0x3e47: 0x0080, 0x3e48: 0x0080, 0x3e49: 0x0080, 0x3e4a: 0x0080, 0x3e4b: 0x0080,
+	0x3e4c: 0x0080, 0x3e4d: 0x0080, 0x3e4e: 0x0080, 0x3e4f: 0x0080, 0x3e50: 0x0080, 0x3e51: 0x0080,
+	0x3e52: 0x0080, 0x3e53: 0x0080, 0x3e54: 0x0080, 0x3e55: 0x0080, 0x3e56: 0x0080, 0x3e57: 0x0080,
+	0x3e58: 0x00c0, 0x3e59: 0x00c0, 0x3e5a: 0x00c0, 0x3e5b: 0x00c0, 0x3e5c: 0x00c3, 0x3e5d: 0x00c3,
+	// Block 0xfa, offset 0x3e80
+	0x3e80: 0x00c0, 0x3e81: 0x00c0, 0x3e82: 0x00c0, 0x3e83: 0x00c0, 0x3e84: 0x00c0, 0x3e85: 0x00c0,
+	0x3e86: 0x00c0, 0x3e87: 0x00c0, 0x3e88: 0x00c0, 0x3e89: 0x00c0, 0x3e8a: 0x00c0, 0x3e8b: 0x00c0,
+	0x3e8c: 0x00c0, 0x3e8d: 0x00c0, 0x3e8e: 0x00c0, 0x3e8f: 0x00c0, 0x3e90: 0x00c0, 0x3e91: 0x00c0,
+	0x3e92: 0x00c0, 0x3e93: 0x00c0, 0x3e94: 0x00c0, 0x3e95: 0x00c0, 0x3e96: 0x00c0, 0x3e97: 0x00c0,
+	0x3e98: 0x00c0, 0x3e99: 0x00c0, 0x3e9a: 0x00c0, 0x3e9b: 0x00c0, 0x3e9c: 0x00c0, 0x3e9d: 0x00c0,
+	0x3e9e: 0x00c0, 0x3e9f: 0x00c0, 0x3ea0: 0x00c0, 0x3ea1: 0x00c0, 0x3ea2: 0x00c0, 0x3ea3: 0x00c0,
+	0x3ea4: 0x00c0, 0x3ea5: 0x00c0, 0x3ea6: 0x00c0, 0x3ea7: 0x00c0, 0x3ea8: 0x00c0, 0x3ea9: 0x00c0,
+	0x3eaa: 0x00c0, 0x3eab: 0x00c0, 0x3eac: 0x00c0, 0x3ead: 0x00c0, 0x3eae: 0x00c0, 0x3eaf: 0x00c0,
+	0x3eb0: 0x00c0, 0x3eb1: 0x00c0, 0x3eb2: 0x00c0, 0x3eb3: 0x00c3, 0x3eb4: 0x00c3, 0x3eb5: 0x00c3,
+	0x3eb6: 0x00c3, 0x3eb7: 0x00c3, 0x3eb8: 0x00c3, 0x3eb9: 0x00c3, 0x3eba: 0x00c3, 0x3ebb: 0x00c0,
+	0x3ebc: 0x00c0, 0x3ebd: 0x00c3, 0x3ebe: 0x00c0, 0x3ebf: 0x00c6,
+	// Block 0xfb, offset 0x3ec0
+	0x3ec0: 0x00c3, 0x3ec1: 0x0080, 0x3ec2: 0x0080, 0x3ec3: 0x0080, 0x3ec4: 0x00c0,
+	0x3ed0: 0x00c0, 0x3ed1: 0x00c0,
+	0x3ed2: 0x00c0, 0x3ed3: 0x00c0, 0x3ed4: 0x00c0, 0x3ed5: 0x00c0, 0x3ed6: 0x00c0, 0x3ed7: 0x00c0,
+	0x3ed8: 0x00c0, 0x3ed9: 0x00c0,
+	0x3ee0: 0x0080, 0x3ee1: 0x0080, 0x3ee2: 0x0080, 0x3ee3: 0x0080,
+	0x3ee4: 0x0080, 0x3ee5: 0x0080, 0x3ee6: 0x0080, 0x3ee7: 0x0080, 0x3ee8: 0x0080, 0x3ee9: 0x0080,
+	0x3eea: 0x0080, 0x3eeb: 0x0080, 0x3eec: 0x0080,
+	// Block 0xfc, offset 0x3f00
+	0x3f00: 0x00c0, 0x3f01: 0x00c0, 0x3f02: 0x00c0, 0x3f03: 0x00c0, 0x3f04: 0x00c0, 0x3f05: 0x00c0,
+	0x3f06: 0x00c0, 0x3f07: 0x00c0, 0x3f08: 0x00c0, 0x3f09: 0x00c0, 0x3f0a: 0x00c0, 0x3f0b: 0x00c0,
+	0x3f0c: 0x00c0, 0x3f0d: 0x00c0, 0x3f0e: 0x00c0, 0x3f0f: 0x00c0, 0x3f10: 0x00c0, 0x3f11: 0x00c0,
+	0x3f12: 0x00c0, 0x3f13: 0x00c0, 0x3f14: 0x00c0, 0x3f15: 0x00c0, 0x3f16: 0x00c0, 0x3f17: 0x00c0,
+	0x3f18: 0x00c0, 0x3f19: 0x00c0, 0x3f1a: 0x00c0, 0x3f1b: 0x00c0, 0x3f1c: 0x00c0, 0x3f1d: 0x00c0,
+	0x3f1e: 0x00c0, 0x3f1f: 0x00c0, 0x3f20: 0x00c0, 0x3f21: 0x00c0, 0x3f22: 0x00c0, 0x3f23: 0x00c0,
+	0x3f24: 0x00c0, 0x3f25: 0x00c0, 0x3f26: 0x00c0, 0x3f27: 0x00c0, 0x3f28: 0x00c0, 0x3f29: 0x00c0,
+	0x3f2a: 0x00c0, 0x3f2b: 0x00c3, 0x3f2c: 0x00c0, 0x3f2d: 0x00c3, 0x3f2e: 0x00c0, 0x3f2f: 0x00c0,
+	0x3f30: 0x00c3, 0x3f31: 0x00c3, 0x3f32: 0x00c3, 0x3f33: 0x00c3, 0x3f34: 0x00c3, 0x3f35: 0x00c3,
+	0x3f36: 0x00c5, 0x3f37: 0x00c3, 0x3f38: 0x00c0, 0x3f39: 0x0080,
+	// Block 0xfd, offset 0x3f40
+	0x3f40: 0x00c0, 0x3f41: 0x00c0, 0x3f42: 0x00c0, 0x3f43: 0x00c0, 0x3f44: 0x00c0, 0x3f45: 0x00c0,
+	0x3f46: 0x00c0, 0x3f47: 0x00c0, 0x3f48: 0x00c0, 0x3f49: 0x00c0,
+	// Block 0xfe, offset 0x3f80
+	0x3f80: 0x00c0, 0x3f81: 0x00c0, 0x3f82: 0x00c0, 0x3f83: 0x00c0, 0x3f84: 0x00c0, 0x3f85: 0x00c0,
+	0x3f86: 0x00c0, 0x3f87: 0x00c0, 0x3f88: 0x00c0, 0x3f89: 0x00c0, 0x3f8a: 0x00c0, 0x3f8b: 0x00c0,
+	0x3f8c: 0x00c0, 0x3f8d: 0x00c0, 0x3f8e: 0x00c0, 0x3f8f: 0x00c0, 0x3f90: 0x00c0, 0x3f91: 0x00c0,
+	0x3f92: 0x00c0, 0x3f93: 0x00c0, 0x3f94: 0x00c0, 0x3f95: 0x00c0, 0x3f96: 0x00c0, 0x3f97: 0x00c0,
+	0x3f98: 0x00c0, 0x3f99: 0x00c0, 0x3f9a: 0x00c0, 0x3f9d: 0x00c3,
+	0x3f9e: 0x00c3, 0x3f9f: 0x00c3, 0x3fa0: 0x00c0, 0x3fa1: 0x00c0, 0x3fa2: 0x00c3, 0x3fa3: 0x00c3,
+	0x3fa4: 0x00c3, 0x3fa5: 0x00c3, 0x3fa6: 0x00c0, 0x3fa7: 0x00c3, 0x3fa8: 0x00c3, 0x3fa9: 0x00c3,
+	0x3faa: 0x00c3, 0x3fab: 0x00c6,
+	0x3fb0: 0x00c0, 0x3fb1: 0x00c0, 0x3fb2: 0x00c0, 0x3fb3: 0x00c0, 0x3fb4: 0x00c0, 0x3fb5: 0x00c0,
+	0x3fb6: 0x00c0, 0x3fb7: 0x00c0, 0x3fb8: 0x00c0, 0x3fb9: 0x00c0, 0x3fba: 0x0080, 0x3fbb: 0x0080,
+	0x3fbc: 0x0080, 0x3fbd: 0x0080, 0x3fbe: 0x0080, 0x3fbf: 0x0080,
+	// Block 0xff, offset 0x3fc0
+	0x3fc0: 0x00c0, 0x3fc1: 0x00c0, 0x3fc2: 0x00c0, 0x3fc3: 0x00c0, 0x3fc4: 0x00c0, 0x3fc5: 0x00c0,
+	0x3fc6: 0x00c0,
+	// Block 0x100, offset 0x4000
+	0x4000: 0x00c0, 0x4001: 0x00c0, 0x4002: 0x00c0, 0x4003: 0x00c0, 0x4004: 0x00c0, 0x4005: 0x00c0,
+	0x4006: 0x00c0, 0x4007: 0x00c0, 0x4008: 0x00c0, 0x4009: 0x00c0, 0x400a: 0x00c0, 0x400b: 0x00c0,
+	0x400c: 0x00c0, 0x400d: 0x00c0, 0x400e: 0x00c0, 0x400f: 0x00c0, 0x4010: 0x00c0, 0x4011: 0x00c0,
+	0x4012: 0x00c0, 0x4013: 0x00c0, 0x4014: 0x00c0, 0x4015: 0x00c0, 0x4016: 0x00c0, 0x4017: 0x00c0,
+	0x4018: 0x00c0, 0x4019: 0x00c0, 0x401a: 0x00c0, 0x401b: 0x00c0, 0x401c: 0x00c0, 0x401d: 0x00c0,
+	0x401e: 0x00c0, 0x401f: 0x00c0, 0x4020: 0x00c0, 0x4021: 0x00c0, 0x4022: 0x00c0, 0x4023: 0x00c0,
+	0x4024: 0x00c0, 0x4025: 0x00c0, 0x4026: 0x00c0, 0x4027: 0x00c0, 0x4028: 0x00c0, 0x4029: 0x00c0,
+	0x402a: 0x00c0, 0x402b: 0x00c0, 0x402c: 0x00c0, 0x402d: 0x00c0, 0x402e: 0x00c0, 0x402f: 0x00c3,
+	0x4030: 0x00c3, 0x4031: 0x00c3, 0x4032: 0x00c3, 0x4033: 0x00c3, 0x4034: 0x00c3, 0x4035: 0x00c3,
+	0x4036: 0x00c3, 0x4037: 0x00c3, 0x4038: 0x00c0, 0x4039: 0x00c6, 0x403a: 0x00c3, 0x403b: 0x0080,
+	// Block 0x101, offset 0x4040
+	0x4060: 0x00c0, 0x4061: 0x00c0, 0x4062: 0x00c0, 0x4063: 0x00c0,
+	0x4064: 0x00c0, 0x4065: 0x00c0, 0x4066: 0x00c0, 0x4067: 0x00c0, 0x4068: 0x00c0, 0x4069: 0x00c0,
+	0x406a: 0x00c0, 0x406b: 0x00c0, 0x406c: 0x00c0, 0x406d: 0x00c0, 0x406e: 0x00c0, 0x406f: 0x00c0,
+	0x4070: 0x00c0, 0x4071: 0x00c0, 0x4072: 0x00c0, 0x4073: 0x00c0, 0x4074: 0x00c0, 0x4075: 0x00c0,
+	0x4076: 0x00c0, 0x4077: 0x00c0, 0x4078: 0x00c0, 0x4079: 0x00c0, 0x407a: 0x00c0, 0x407b: 0x00c0,
+	0x407c: 0x00c0, 0x407d: 0x00c0, 0x407e: 0x00c0, 0x407f: 0x00c0,
+	// Block 0x102, offset 0x4080
+	0x4080: 0x00c0, 0x4081: 0x00c0, 0x4082: 0x00c0, 0x4083: 0x00c0, 0x4084: 0x00c0, 0x4085: 0x00c0,
+	0x4086: 0x00c0, 0x4087: 0x00c0, 0x4088: 0x00c0, 0x4089: 0x00c0, 0x408a: 0x00c0, 0x408b: 0x00c0,
+	0x408c: 0x00c0, 0x408d: 0x00c0, 0x408e: 0x00c0, 0x408f: 0x00c0, 0x4090: 0x00c0, 0x4091: 0x00c0,
+	0x4092: 0x00c0, 0x4093: 0x00c0, 0x4094: 0x00c0, 0x4095: 0x00c0, 0x4096: 0x00c0, 0x4097: 0x00c0,
+	0x4098: 0x00c0, 0x4099: 0x00c0, 0x409a: 0x00c0, 0x409b: 0x00c0, 0x409c: 0x00c0, 0x409d: 0x00c0,
+	0x409e: 0x00c0, 0x409f: 0x00c0, 0x40a0: 0x00c0, 0x40a1: 0x00c0, 0x40a2: 0x00c0, 0x40a3: 0x00c0,
+	0x40a4: 0x00c0, 0x40a5: 0x00c0, 0x40a6: 0x00c0, 0x40a7: 0x00c0, 0x40a8: 0x00c0, 0x40a9: 0x00c0,
+	0x40aa: 0x0080, 0x40ab: 0x0080, 0x40ac: 0x0080, 0x40ad: 0x0080, 0x40ae: 0x0080, 0x40af: 0x0080,
+	0x40b0: 0x0080, 0x40b1: 0x0080, 0x40b2: 0x0080,
+	0x40bf: 0x00c0,
+	// Block 0x103, offset 0x40c0
+	0x40c0: 0x00c0, 0x40c1: 0x00c0, 0x40c2: 0x00c0, 0x40c3: 0x00c0, 0x40c4: 0x00c0, 0x40c5: 0x00c0,
+	0x40c6: 0x00c0, 0x40c9: 0x00c0,
+	0x40cc: 0x00c0, 0x40cd: 0x00c0, 0x40ce: 0x00c0, 0x40cf: 0x00c0, 0x40d0: 0x00c0, 0x40d1: 0x00c0,
+	0x40d2: 0x00c0, 0x40d3: 0x00c0, 0x40d5: 0x00c0, 0x40d6: 0x00c0,
+	0x40d8: 0x00c0, 0x40d9: 0x00c0, 0x40da: 0x00c0, 0x40db: 0x00c0, 0x40dc: 0x00c0, 0x40dd: 0x00c0,
+	0x40de: 0x00c0, 0x40df: 0x00c0, 0x40e0: 0x00c0, 0x40e1: 0x00c0, 0x40e2: 0x00c0, 0x40e3: 0x00c0,
+	0x40e4: 0x00c0, 0x40e5: 0x00c0, 0x40e6: 0x00c0, 0x40e7: 0x00c0, 0x40e8: 0x00c0, 0x40e9: 0x00c0,
+	0x40ea: 0x00c0, 0x40eb: 0x00c0, 0x40ec: 0x00c0, 0x40ed: 0x00c0, 0x40ee: 0x00c0, 0x40ef: 0x00c0,
+	0x40f0: 0x00c0, 0x40f1: 0x00c0, 0x40f2: 0x00c0, 0x40f3: 0x00c0, 0x40f4: 0x00c0, 0x40f5: 0x00c0,
+	0x40f7: 0x00c0, 0x40f8: 0x00c0, 0x40fb: 0x00c3,
+	0x40fc: 0x00c3, 0x40fd: 0x00c5, 0x40fe: 0x00c6, 0x40ff: 0x00c0,
+	// Block 0x104, offset 0x4100
+	0x4100: 0x00c0, 0x4101: 0x00c0, 0x4102: 0x00c0, 0x4103: 0x00c3, 0x4104: 0x0080, 0x4105: 0x0080,
+	0x4106: 0x0080,
+	0x4110: 0x00c0, 0x4111: 0x00c0,
+	0x4112: 0x00c0, 0x4113: 0x00c0, 0x4114: 0x00c0, 0x4115: 0x00c0, 0x4116: 0x00c0, 0x4117: 0x00c0,
+	0x4118: 0x00c0, 0x4119: 0x00c0,
+	// Block 0x105, offset 0x4140
+	0x4160: 0x00c0, 0x4161: 0x00c0, 0x4162: 0x00c0, 0x4163: 0x00c0,
+	0x4164: 0x00c0, 0x4165: 0x00c0, 0x4166: 0x00c0, 0x4167: 0x00c0,
+	0x416a: 0x00c0, 0x416b: 0x00c0, 0x416c: 0x00c0, 0x416d: 0x00c0, 0x416e: 0x00c0, 0x416f: 0x00c0,
+	0x4170: 0x00c0, 0x4171: 0x00c0, 0x4172: 0x00c0, 0x4173: 0x00c0, 0x4174: 0x00c0, 0x4175: 0x00c0,
+	0x4176: 0x00c0, 0x4177: 0x00c0, 0x4178: 0x00c0, 0x4179: 0x00c0, 0x417a: 0x00c0, 0x417b: 0x00c0,
+	0x417c: 0x00c0, 0x417d: 0x00c0, 0x417e: 0x00c0, 0x417f: 0x00c0,
+	// Block 0x106, offset 0x4180
+	0x4180: 0x00c0, 0x4181: 0x00c0, 0x4182: 0x00c0, 0x4183: 0x00c0, 0x4184: 0x00c0, 0x4185: 0x00c0,
+	0x4186: 0x00c0, 0x4187: 0x00c0, 0x4188: 0x00c0, 0x4189: 0x00c0, 0x418a: 0x00c0, 0x418b: 0x00c0,
+	0x418c: 0x00c0, 0x418d: 0x00c0, 0x418e: 0x00c0, 0x418f: 0x00c0, 0x4190: 0x00c0, 0x4191: 0x00c0,
+	0x4192: 0x00c0, 0x4193: 0x00c0, 0x4194: 0x00c3, 0x4195: 0x00c3, 0x4196: 0x00c3, 0x4197: 0x00c3,
+	0x419a: 0x00c3, 0x419b: 0x00c3, 0x419c: 0x00c0, 0x419d: 0x00c0,
+	0x419e: 0x00c0, 0x419f: 0x00c0, 0x41a0: 0x00c6, 0x41a1: 0x00c0, 0x41a2: 0x0080, 0x41a3: 0x00c0,
+	0x41a4: 0x00c0,
+	// Block 0x107, offset 0x41c0
+	0x41c0: 0x00c0, 0x41c1: 0x00c3, 0x41c2: 0x00c3, 0x41c3: 0x00c3, 0x41c4: 0x00c3, 0x41c5: 0x00c3,
+	0x41c6: 0x00c3, 0x41c7: 0x00c3, 0x41c8: 0x00c3, 0x41c9: 0x00c3, 0x41ca: 0x00c3, 0x41cb: 0x00c0,
+	0x41cc: 0x00c0, 0x41cd: 0x00c0, 0x41ce: 0x00c0, 0x41cf: 0x00c0, 0x41d0: 0x00c0, 0x41d1: 0x00c0,
+	0x41d2: 0x00c0, 0x41d3: 0x00c0, 0x41d4: 0x00c0, 0x41d5: 0x00c0, 0x41d6: 0x00c0, 0x41d7: 0x00c0,
+	0x41d8: 0x00c0, 0x41d9: 0x00c0, 0x41da: 0x00c0, 0x41db: 0x00c0, 0x41dc: 0x00c0, 0x41dd: 0x00c0,
+	0x41de: 0x00c0, 0x41df: 0x00c0, 0x41e0: 0x00c0, 0x41e1: 0x00c0, 0x41e2: 0x00c0, 0x41e3: 0x00c0,
+	0x41e4: 0x00c0, 0x41e5: 0x00c0, 0x41e6: 0x00c0, 0x41e7: 0x00c0, 0x41e8: 0x00c0, 0x41e9: 0x00c0,
+	0x41ea: 0x00c0, 0x41eb: 0x00c0, 0x41ec: 0x00c0, 0x41ed: 0x00c0, 0x41ee: 0x00c0, 0x41ef: 0x00c0,
+	0x41f0: 0x00c0, 0x41f1: 0x00c0, 0x41f2: 0x00c0, 0x41f3: 0x00c3, 0x41f4: 0x00c6, 0x41f5: 0x00c3,
+	0x41f6: 0x00c3, 0x41f7: 0x00c3, 0x41f8: 0x00c3, 0x41f9: 0x00c0, 0x41fa: 0x00c0, 0x41fb: 0x00c3,
+	0x41fc: 0x00c3, 0x41fd: 0x00c3, 0x41fe: 0x00c3, 0x41ff: 0x0080,
+	// Block 0x108, offset 0x4200
+	0x4200: 0x0080, 0x4201: 0x0080, 0x4202: 0x0080, 0x4203: 0x0080, 0x4204: 0x0080, 0x4205: 0x0080,
+	0x4206: 0x0080, 0x4207: 0x00c6,
+	0x4210: 0x00c0, 0x4211: 0x00c3,
+	0x4212: 0x00c3, 0x4213: 0x00c3, 0x4214: 0x00c3, 0x4215: 0x00c3, 0x4216: 0x00c3, 0x4217: 0x00c0,
+	0x4218: 0x00c0, 0x4219: 0x00c3, 0x421a: 0x00c3, 0x421b: 0x00c3, 0x421c: 0x00c0, 0x421d: 0x00c0,
+	0x421e: 0x00c0, 0x421f: 0x00c0, 0x4220: 0x00c0, 0x4221: 0x00c0, 0x4222: 0x00c0, 0x4223: 0x00c0,
+	0x4224: 0x00c0, 0x4225: 0x00c0, 0x4226: 0x00c0, 0x4227: 0x00c0, 0x4228: 0x00c0, 0x4229: 0x00c0,
+	0x422a: 0x00c0, 0x422b: 0x00c0, 0x422c: 0x00c0, 0x422d: 0x00c0, 0x422e: 0x00c0, 0x422f: 0x00c0,
+	0x4230: 0x00c0, 0x4231: 0x00c0, 0x4232: 0x00c0, 0x4233: 0x00c0, 0x4234: 0x00c0, 0x4235: 0x00c0,
+	0x4236: 0x00c0, 0x4237: 0x00c0, 0x4238: 0x00c0, 0x4239: 0x00c0, 0x423a: 0x00c0, 0x423b: 0x00c0,
+	0x423c: 0x00c0, 0x423d: 0x00c0, 0x423e: 0x00c0, 0x423f: 0x00c0,
+	// Block 0x109, offset 0x4240
+	0x4240: 0x00c0, 0x4241: 0x00c0, 0x4242: 0x00c0, 0x4243: 0x00c0, 0x4244: 0x00c0, 0x4245: 0x00c0,
+	0x4246: 0x00c0, 0x4247: 0x00c0, 0x4248: 0x00c0, 0x4249: 0x00c0, 0x424a: 0x00c3, 0x424b: 0x00c3,
+	0x424c: 0x00c3, 0x424d: 0x00c3, 0x424e: 0x00c3, 0x424f: 0x00c3, 0x4250: 0x00c3, 0x4251: 0x00c3,
+	0x4252: 0x00c3, 0x4253: 0x00c3, 0x4254: 0x00c3, 0x4255: 0x00c3, 0x4256: 0x00c3, 0x4257: 0x00c0,
+	0x4258: 0x00c3, 0x4259: 0x00c6, 0x425a: 0x0080, 0x425b: 0x0080, 0x425c: 0x0080, 0x425d: 0x00c0,
+	0x425e: 0x0080, 0x425f: 0x0080, 0x4260: 0x0080, 0x4261: 0x0080, 0x4262: 0x0080,
+	0x4270: 0x00c0, 0x4271: 0x00c0, 0x4272: 0x00c0, 0x4273: 0x00c0, 0x4274: 0x00c0, 0x4275: 0x00c0,
+	0x4276: 0x00c0, 0x4277: 0x00c0, 0x4278: 0x00c0, 0x4279: 0x00c0, 0x427a: 0x00c0, 0x427b: 0x00c0,
+	0x427c: 0x00c0, 0x427d: 0x00c0, 0x427e: 0x00c0, 0x427f: 0x00c0,
+	// Block 0x10a, offset 0x4280
+	0x4280: 0x00c0, 0x4281: 0x00c0, 0x4282: 0x00c0, 0x4283: 0x00c0, 0x4284: 0x00c0, 0x4285: 0x00c0,
+	0x4286: 0x00c0, 0x4287: 0x00c0, 0x4288: 0x00c0, 0x4289: 0x00c0, 0x428a: 0x00c0, 0x428b: 0x00c0,
+	0x428c: 0x00c0, 0x428d: 0x00c0, 0x428e: 0x00c0, 0x428f: 0x00c0, 0x4290: 0x00c0, 0x4291: 0x00c0,
+	0x4292: 0x00c0, 0x4293: 0x00c0, 0x4294: 0x00c0, 0x4295: 0x00c0, 0x4296: 0x00c0, 0x4297: 0x00c0,
+	0x4298: 0x00c0, 0x4299: 0x00c0, 0x429a: 0x00c0, 0x429b: 0x00c0, 0x429c: 0x00c0, 0x429d: 0x00c0,
+	0x429e: 0x00c0, 0x429f: 0x00c0, 0x42a0: 0x00c0, 0x42a1: 0x00c0, 0x42a2: 0x00c0, 0x42a3: 0x00c0,
+	0x42a4: 0x00c0, 0x42a5: 0x00c0, 0x42a6: 0x00c0, 0x42a7: 0x00c0, 0x42a8: 0x00c0, 0x42a9: 0x00c0,
+	0x42aa: 0x00c0, 0x42ab: 0x00c0, 0x42ac: 0x00c0, 0x42ad: 0x00c0, 0x42ae: 0x00c0, 0x42af: 0x00c0,
+	0x42b0: 0x00c0, 0x42b1: 0x00c0, 0x42b2: 0x00c0, 0x42b3: 0x00c0, 0x42b4: 0x00c0, 0x42b5: 0x00c0,
+	0x42b6: 0x00c0, 0x42b7: 0x00c0, 0x42b8: 0x00c0,
+	// Block 0x10b, offset 0x42c0
+	0x42c0: 0x0080, 0x42c1: 0x0080, 0x42c2: 0x0080, 0x42c3: 0x0080, 0x42c4: 0x0080, 0x42c5: 0x0080,
+	0x42c6: 0x0080, 0x42c7: 0x0080, 0x42c8: 0x0080, 0x42c9: 0x0080,
+	// Block 0x10c, offset 0x4300
+	0x4300: 0x00c0, 0x4301: 0x00c0, 0x4302: 0x00c0, 0x4303: 0x00c0, 0x4304: 0x00c0, 0x4305: 0x00c0,
+	0x4306: 0x00c0, 0x4307: 0x00c0, 0x4308: 0x00c0, 0x430a: 0x00c0, 0x430b: 0x00c0,
+	0x430c: 0x00c0, 0x430d: 0x00c0, 0x430e: 0x00c0, 0x430f: 0x00c0, 0x4310: 0x00c0, 0x4311: 0x00c0,
+	0x4312: 0x00c0, 0x4313: 0x00c0, 0x4314: 0x00c0, 0x4315: 0x00c0, 0x4316: 0x00c0, 0x4317: 0x00c0,
+	0x4318: 0x00c0, 0x4319: 0x00c0, 0x431a: 0x00c0, 0x431b: 0x00c0, 0x431c: 0x00c0, 0x431d: 0x00c0,
+	0x431e: 0x00c0, 0x431f: 0x00c0, 0x4320: 0x00c0, 0x4321: 0x00c0, 0x4322: 0x00c0, 0x4323: 0x00c0,
+	0x4324: 0x00c0, 0x4325: 0x00c0, 0x4326: 0x00c0, 0x4327: 0x00c0, 0x4328: 0x00c0, 0x4329: 0x00c0,
+	0x432a: 0x00c0, 0x432b: 0x00c0, 0x432c: 0x00c0, 0x432d: 0x00c0, 0x432e: 0x00c0, 0x432f: 0x00c0,
+	0x4330: 0x00c3, 0x4331: 0x00c3, 0x4332: 0x00c3, 0x4333: 0x00c3, 0x4334: 0x00c3, 0x4335: 0x00c3,
+	0x4336: 0x00c3, 0x4338: 0x00c3, 0x4339: 0x00c3, 0x433a: 0x00c3, 0x433b: 0x00c3,
+	0x433c: 0x00c3, 0x433d: 0x00c3, 0x433e: 0x00c0, 0x433f: 0x00c6,
+	// Block 0x10d, offset 0x4340
+	0x4340: 0x00c0, 0x4341: 0x0080, 0x4342: 0x0080, 0x4343: 0x0080, 0x4344: 0x0080, 0x4345: 0x0080,
+	0x4350: 0x00c0, 0x4351: 0x00c0,
+	0x4352: 0x00c0, 0x4353: 0x00c0, 0x4354: 0x00c0, 0x4355: 0x00c0, 0x4356: 0x00c0, 0x4357: 0x00c0,
+	0x4358: 0x00c0, 0x4359: 0x00c0, 0x435a: 0x0080, 0x435b: 0x0080, 0x435c: 0x0080, 0x435d: 0x0080,
+	0x435e: 0x0080, 0x435f: 0x0080, 0x4360: 0x0080, 0x4361: 0x0080, 0x4362: 0x0080, 0x4363: 0x0080,
+	0x4364: 0x0080, 0x4365: 0x0080, 0x4366: 0x0080, 0x4367: 0x0080, 0x4368: 0x0080, 0x4369: 0x0080,
+	0x436a: 0x0080, 0x436b: 0x0080, 0x436c: 0x0080,
+	0x4370: 0x0080, 0x4371: 0x0080, 0x4372: 0x00c0, 0x4373: 0x00c0, 0x4374: 0x00c0, 0x4375: 0x00c0,
+	0x4376: 0x00c0, 0x4377: 0x00c0, 0x4378: 0x00c0, 0x4379: 0x00c0, 0x437a: 0x00c0, 0x437b: 0x00c0,
+	0x437c: 0x00c0, 0x437d: 0x00c0, 0x437e: 0x00c0, 0x437f: 0x00c0,
+	// Block 0x10e, offset 0x4380
+	0x4380: 0x00c0, 0x4381: 0x00c0, 0x4382: 0x00c0, 0x4383: 0x00c0, 0x4384: 0x00c0, 0x4385: 0x00c0,
+	0x4386: 0x00c0, 0x4387: 0x00c0, 0x4388: 0x00c0, 0x4389: 0x00c0, 0x438a: 0x00c0, 0x438b: 0x00c0,
+	0x438c: 0x00c0, 0x438d: 0x00c0, 0x438e: 0x00c0, 0x438f: 0x00c0,
+	0x4392: 0x00c3, 0x4393: 0x00c3, 0x4394: 0x00c3, 0x4395: 0x00c3, 0x4396: 0x00c3, 0x4397: 0x00c3,
+	0x4398: 0x00c3, 0x4399: 0x00c3, 0x439a: 0x00c3, 0x439b: 0x00c3, 0x439c: 0x00c3, 0x439d: 0x00c3,
+	0x439e: 0x00c3, 0x439f: 0x00c3, 0x43a0: 0x00c3, 0x43a1: 0x00c3, 0x43a2: 0x00c3, 0x43a3: 0x00c3,
+	0x43a4: 0x00c3, 0x43a5: 0x00c3, 0x43a6: 0x00c3, 0x43a7: 0x00c3, 0x43a9: 0x00c0,
+	0x43aa: 0x00c3, 0x43ab: 0x00c3, 0x43ac: 0x00c3, 0x43ad: 0x00c3, 0x43ae: 0x00c3, 0x43af: 0x00c3,
+	0x43b0: 0x00c3, 0x43b1: 0x00c0, 0x43b2: 0x00c3, 0x43b3: 0x00c3, 0x43b4: 0x00c0, 0x43b5: 0x00c3,
+	0x43b6: 0x00c3,
+	// Block 0x10f, offset 0x43c0
+	0x43c0: 0x00c0, 0x43c1: 0x00c0, 0x43c2: 0x00c0, 0x43c3: 0x00c0, 0x43c4: 0x00c0, 0x43c5: 0x00c0,
+	0x43c6: 0x00c0, 0x43c8: 0x00c0, 0x43c9: 0x00c0, 0x43cb: 0x00c0,
+	0x43cc: 0x00c0, 0x43cd: 0x00c0, 0x43ce: 0x00c0, 0x43cf: 0x00c0, 0x43d0: 0x00c0, 0x43d1: 0x00c0,
+	0x43d2: 0x00c0, 0x43d3: 0x00c0, 0x43d4: 0x00c0, 0x43d5: 0x00c0, 0x43d6: 0x00c0, 0x43d7: 0x00c0,
+	0x43d8: 0x00c0, 0x43d9: 0x00c0, 0x43da: 0x00c0, 0x43db: 0x00c0, 0x43dc: 0x00c0, 0x43dd: 0x00c0,
+	0x43de: 0x00c0, 0x43df: 0x00c0, 0x43e0: 0x00c0, 0x43e1: 0x00c0, 0x43e2: 0x00c0, 0x43e3: 0x00c0,
+	0x43e4: 0x00c0, 0x43e5: 0x00c0, 0x43e6: 0x00c0, 0x43e7: 0x00c0, 0x43e8: 0x00c0, 0x43e9: 0x00c0,
+	0x43ea: 0x00c0, 0x43eb: 0x00c0, 0x43ec: 0x00c0, 0x43ed: 0x00c0, 0x43ee: 0x00c0, 0x43ef: 0x00c0,
+	0x43f0: 0x00c0, 0x43f1: 0x00c3, 0x43f2: 0x00c3, 0x43f3: 0x00c3, 0x43f4: 0x00c3, 0x43f5: 0x00c3,
+	0x43f6: 0x00c3, 0x43fa: 0x00c3,
+	0x43fc: 0x00c3, 0x43fd: 0x00c3, 0x43ff: 0x00c3,
+	// Block 0x110, offset 0x4400
+	0x4400: 0x00c3, 0x4401: 0x00c3, 0x4402: 0x00c3, 0x4403: 0x00c3, 0x4404: 0x00c6, 0x4405: 0x00c6,
+	0x4406: 0x00c0, 0x4407: 0x00c3,
+	0x4410: 0x00c0, 0x4411: 0x00c0,
+	0x4412: 0x00c0, 0x4413: 0x00c0, 0x4414: 0x00c0, 0x4415: 0x00c0, 0x4416: 0x00c0, 0x4417: 0x00c0,
+	0x4418: 0x00c0, 0x4419: 0x00c0,
+	0x4420: 0x00c0, 0x4421: 0x00c0, 0x4422: 0x00c0, 0x4423: 0x00c0,
+	0x4424: 0x00c0, 0x4425: 0x00c0, 0x4427: 0x00c0, 0x4428: 0x00c0,
+	0x442a: 0x00c0, 0x442b: 0x00c0, 0x442c: 0x00c0, 0x442d: 0x00c0, 0x442e: 0x00c0, 0x442f: 0x00c0,
+	0x4430: 0x00c0, 0x4431: 0x00c0, 0x4432: 0x00c0, 0x4433: 0x00c0, 0x4434: 0x00c0, 0x4435: 0x00c0,
+	0x4436: 0x00c0, 0x4437: 0x00c0, 0x4438: 0x00c0, 0x4439: 0x00c0, 0x443a: 0x00c0, 0x443b: 0x00c0,
+	0x443c: 0x00c0, 0x443d: 0x00c0, 0x443e: 0x00c0, 0x443f: 0x00c0,
+	// Block 0x111, offset 0x4440
+	0x4440: 0x00c0, 0x4441: 0x00c0, 0x4442: 0x00c0, 0x4443: 0x00c0, 0x4444: 0x00c0, 0x4445: 0x00c0,
+	0x4446: 0x00c0, 0x4447: 0x00c0, 0x4448: 0x00c0, 0x4449: 0x00c0, 0x444a: 0x00c0, 0x444b: 0x00c0,
+	0x444c: 0x00c0, 0x444d: 0x00c0, 0x444e: 0x00c0, 0x4450: 0x00c3, 0x4451: 0x00c3,
+	0x4453: 0x00c0, 0x4454: 0x00c0, 0x4455: 0x00c3, 0x4456: 0x00c0, 0x4457: 0x00c6,
+	0x4458: 0x00c0,
+	0x4460: 0x00c0, 0x4461: 0x00c0, 0x4462: 0x00c0, 0x4463: 0x00c0,
+	0x4464: 0x00c0, 0x4465: 0x00c0, 0x4466: 0x00c0, 0x4467: 0x00c0, 0x4468: 0x00c0, 0x4469: 0x00c0,
+	// Block 0x112, offset 0x4480
+	0x44a0: 0x00c0, 0x44a1: 0x00c0, 0x44a2: 0x00c0, 0x44a3: 0x00c0,
+	0x44a4: 0x00c0, 0x44a5: 0x00c0, 0x44a6: 0x00c0, 0x44a7: 0x00c0, 0x44a8: 0x00c0, 0x44a9: 0x00c0,
+	0x44aa: 0x00c0, 0x44ab: 0x00c0, 0x44ac: 0x00c0, 0x44ad: 0x00c0, 0x44ae: 0x00c0, 0x44af: 0x00c0,
+	0x44b0: 0x00c0, 0x44b1: 0x00c0, 0x44b2: 0x00c0, 0x44b3: 0x00c3, 0x44b4: 0x00c3, 0x44b5: 0x00c0,
+	0x44b6: 0x00c0, 0x44b7: 0x0080, 0x44b8: 0x0080,
+	// Block 0x113, offset 0x44c0
+	0x44c0: 0x00c3, 0x44c1: 0x00c3, 0x44c2: 0x00c0, 0x44c3: 0x00c0, 0x44c4: 0x00c0, 0x44c5: 0x00c0,
+	0x44c6: 0x00c0, 0x44c7: 0x00c0, 0x44c8: 0x00c0, 0x44c9: 0x00c0, 0x44ca: 0x00c0, 0x44cb: 0x00c0,
+	0x44cc: 0x00c0, 0x44cd: 0x00c0, 0x44ce: 0x00c0, 0x44cf: 0x00c0, 0x44d0: 0x00c0,
+	0x44d2: 0x00c0, 0x44d3: 0x00c0, 0x44d4: 0x00c0, 0x44d5: 0x00c0, 0x44d6: 0x00c0, 0x44d7: 0x00c0,
+	0x44d8: 0x00c0, 0x44d9: 0x00c0, 0x44da: 0x00c0, 0x44db: 0x00c0, 0x44dc: 0x00c0, 0x44dd: 0x00c0,
+	0x44de: 0x00c0, 0x44df: 0x00c0, 0x44e0: 0x00c0, 0x44e1: 0x00c0, 0x44e2: 0x00c0, 0x44e3: 0x00c0,
+	0x44e4: 0x00c0, 0x44e5: 0x00c0, 0x44e6: 0x00c0, 0x44e7: 0x00c0, 0x44e8: 0x00c0, 0x44e9: 0x00c0,
+	0x44ea: 0x00c0, 0x44eb: 0x00c0, 0x44ec: 0x00c0, 0x44ed: 0x00c0, 0x44ee: 0x00c0, 0x44ef: 0x00c0,
+	0x44f0: 0x00c0, 0x44f1: 0x00c0, 0x44f2: 0x00c0, 0x44f3: 0x00c0, 0x44f4: 0x00c0, 0x44f5: 0x00c0,
+	0x44f6: 0x00c3, 0x44f7: 0x00c3, 0x44f8: 0x00c3, 0x44f9: 0x00c3, 0x44fa: 0x00c3,
+	0x44fe: 0x00c0, 0x44ff: 0x00c0,
+	// Block 0x114, offset 0x4500
+	0x4500: 0x00c3, 0x4501: 0x00c5, 0x4502: 0x00c6, 0x4503: 0x0080, 0x4504: 0x0080, 0x4505: 0x0080,
+	0x4506: 0x0080, 0x4507: 0x0080, 0x4508: 0x0080, 0x4509: 0x0080, 0x450a: 0x0080, 0x450b: 0x0080,
+	0x450c: 0x0080, 0x450d: 0x0080, 0x450e: 0x0080, 0x450f: 0x0080, 0x4510: 0x00c0, 0x4511: 0x00c0,
+	0x4512: 0x00c0, 0x4513: 0x00c0, 0x4514: 0x00c0, 0x4515: 0x00c0, 0x4516: 0x00c0, 0x4517: 0x00c0,
+	0x4518: 0x00c0, 0x4519: 0x00c0,
+	// Block 0x115, offset 0x4540
+	0x4570: 0x00c0,
+	// Block 0x116, offset 0x4580
+	0x4580: 0x0080, 0x4581: 0x0080, 0x4582: 0x0080, 0x4583: 0x0080, 0x4584: 0x0080, 0x4585: 0x0080,
+	0x4586: 0x0080, 0x4587: 0x0080, 0x4588: 0x0080, 0x4589: 0x0080, 0x458a: 0x0080, 0x458b: 0x0080,
+	0x458c: 0x0080, 0x458d: 0x0080, 0x458e: 0x0080, 0x458f: 0x0080, 0x4590: 0x0080, 0x4591: 0x0080,
+	0x4592: 0x0080, 0x4593: 0x0080, 0x4594: 0x0080, 0x4595: 0x0080, 0x4596: 0x0080, 0x4597: 0x0080,
+	0x4598: 0x0080, 0x4599: 0x0080, 0x459a: 0x0080, 0x459b: 0x0080, 0x459c: 0x0080, 0x459d: 0x0080,
+	0x459e: 0x0080, 0x459f: 0x0080, 0x45a0: 0x0080, 0x45a1: 0x0080, 0x45a2: 0x0080, 0x45a3: 0x0080,
+	0x45a4: 0x0080, 0x45a5: 0x0080, 0x45a6: 0x0080, 0x45a7: 0x0080, 0x45a8: 0x0080, 0x45a9: 0x0080,
+	0x45aa: 0x0080, 0x45ab: 0x0080, 0x45ac: 0x0080, 0x45ad: 0x0080, 0x45ae: 0x0080, 0x45af: 0x0080,
+	0x45b0: 0x0080, 0x45b1: 0x0080,
+	0x45bf: 0x0080,
+	// Block 0x117, offset 0x45c0
+	0x45c0: 0x00c0, 0x45c1: 0x00c0, 0x45c2: 0x00c0, 0x45c3: 0x00c0, 0x45c4: 0x00c0, 0x45c5: 0x00c0,
+	0x45c6: 0x00c0, 0x45c7: 0x00c0, 0x45c8: 0x00c0, 0x45c9: 0x00c0, 0x45ca: 0x00c0, 0x45cb: 0x00c0,
+	0x45cc: 0x00c0, 0x45cd: 0x00c0, 0x45ce: 0x00c0, 0x45cf: 0x00c0, 0x45d0: 0x00c0, 0x45d1: 0x00c0,
+	0x45d2: 0x00c0, 0x45d3: 0x00c0, 0x45d4: 0x00c0, 0x45d5: 0x00c0, 0x45d6: 0x00c0, 0x45d7: 0x00c0,
+	0x45d8: 0x00c0, 0x45d9: 0x00c0,
+	// Block 0x118, offset 0x4600
+	0x4600: 0x0080, 0x4601: 0x0080, 0x4602: 0x0080, 0x4603: 0x0080, 0x4604: 0x0080, 0x4605: 0x0080,
+	0x4606: 0x0080, 0x4607: 0x0080, 0x4608: 0x0080, 0x4609: 0x0080, 0x460a: 0x0080, 0x460b: 0x0080,
+	0x460c: 0x0080, 0x460d: 0x0080, 0x460e: 0x0080, 0x460f: 0x0080, 0x4610: 0x0080, 0x4611: 0x0080,
+	0x4612: 0x0080, 0x4613: 0x0080, 0x4614: 0x0080, 0x4615: 0x0080, 0x4616: 0x0080, 0x4617: 0x0080,
+	0x4618: 0x0080, 0x4619: 0x0080, 0x461a: 0x0080, 0x461b: 0x0080, 0x461c: 0x0080, 0x461d: 0x0080,
+	0x461e: 0x0080, 0x461f: 0x0080, 0x4620: 0x0080, 0x4621: 0x0080, 0x4622: 0x0080, 0x4623: 0x0080,
+	0x4624: 0x0080, 0x4625: 0x0080, 0x4626: 0x0080, 0x4627: 0x0080, 0x4628: 0x0080, 0x4629: 0x0080,
+	0x462a: 0x0080, 0x462b: 0x0080, 0x462c: 0x0080, 0x462d: 0x0080, 0x462e: 0x0080,
+	0x4630: 0x0080, 0x4631: 0x0080, 0x4632: 0x0080, 0x4633: 0x0080, 0x4634: 0x0080,
+	// Block 0x119, offset 0x4640
+	0x4640: 0x00c0, 0x4641: 0x00c0, 0x4642: 0x00c0, 0x4643: 0x00c0,
+	// Block 0x11a, offset 0x4680
+	0x4690: 0x00c0, 0x4691: 0x00c0,
+	0x4692: 0x00c0, 0x4693: 0x00c0, 0x4694: 0x00c0, 0x4695: 0x00c0, 0x4696: 0x00c0, 0x4697: 0x00c0,
+	0x4698: 0x00c0, 0x4699: 0x00c0, 0x469a: 0x00c0, 0x469b: 0x00c0, 0x469c: 0x00c0, 0x469d: 0x00c0,
+	0x469e: 0x00c0, 0x469f: 0x00c0, 0x46a0: 0x00c0, 0x46a1: 0x00c0, 0x46a2: 0x00c0, 0x46a3: 0x00c0,
+	0x46a4: 0x00c0, 0x46a5: 0x00c0, 0x46a6: 0x00c0, 0x46a7: 0x00c0, 0x46a8: 0x00c0, 0x46a9: 0x00c0,
+	0x46aa: 0x00c0, 0x46ab: 0x00c0, 0x46ac: 0x00c0, 0x46ad: 0x00c0, 0x46ae: 0x00c0, 0x46af: 0x00c0,
+	0x46b0: 0x00c0, 0x46b1: 0x00c0, 0x46b2: 0x00c0, 0x46b3: 0x00c0, 0x46b4: 0x00c0, 0x46b5: 0x00c0,
+	0x46b6: 0x00c0, 0x46b7: 0x00c0, 0x46b8: 0x00c0, 0x46b9: 0x00c0, 0x46ba: 0x00c0, 0x46bb: 0x00c0,
+	0x46bc: 0x00c0, 0x46bd: 0x00c0, 0x46be: 0x00c0, 0x46bf: 0x00c0,
+	// Block 0x11b, offset 0x46c0
+	0x46c0: 0x00c0, 0x46c1: 0x00c0, 0x46c2: 0x00c0, 0x46c3: 0x00c0, 0x46c4: 0x00c0, 0x46c5: 0x00c0,
+	0x46c6: 0x00c0, 0x46c7: 0x00c0, 0x46c8: 0x00c0, 0x46c9: 0x00c0, 0x46ca: 0x00c0, 0x46cb: 0x00c0,
+	0x46cc: 0x00c0, 0x46cd: 0x00c0, 0x46ce: 0x00c0, 0x46cf: 0x00c0, 0x46d0: 0x00c0, 0x46d1: 0x00c0,
+	0x46d2: 0x00c0, 0x46d3: 0x00c0, 0x46d4: 0x00c0, 0x46d5: 0x00c0, 0x46d6: 0x00c0, 0x46d7: 0x00c0,
+	0x46d8: 0x00c0, 0x46d9: 0x00c0, 0x46da: 0x00c0, 0x46db: 0x00c0, 0x46dc: 0x00c0, 0x46dd: 0x00c0,
+	0x46de: 0x00c0, 0x46df: 0x00c0, 0x46e0: 0x00c0, 0x46e1: 0x00c0, 0x46e2: 0x00c0, 0x46e3: 0x00c0,
+	0x46e4: 0x00c0, 0x46e5: 0x00c0, 0x46e6: 0x00c0, 0x46e7: 0x00c0, 0x46e8: 0x00c0, 0x46e9: 0x00c0,
+	0x46ea: 0x00c0, 0x46eb: 0x00c0, 0x46ec: 0x00c0, 0x46ed: 0x00c0, 0x46ee: 0x00c0, 0x46ef: 0x00c0,
+	0x46f0: 0x00c0, 0x46f1: 0x0080, 0x46f2: 0x0080,
+	// Block 0x11c, offset 0x4700
+	0x4700: 0x00c0, 0x4701: 0x00c0, 0x4702: 0x00c0, 0x4703: 0x00c0, 0x4704: 0x00c0, 0x4705: 0x00c0,
+	0x4706: 0x00c0, 0x4707: 0x00c0, 0x4708: 0x00c0, 0x4709: 0x00c0, 0x470a: 0x00c0, 0x470b: 0x00c0,
+	0x470c: 0x00c0, 0x470d: 0x00c0, 0x470e: 0x00c0, 0x470f: 0x00c0, 0x4710: 0x00c0, 0x4711: 0x00c0,
+	0x4712: 0x00c0, 0x4713: 0x00c0, 0x4714: 0x00c0, 0x4715: 0x00c0, 0x4716: 0x00c0, 0x4717: 0x00c0,
+	0x4718: 0x00c0, 0x4719: 0x00c0, 0x471a: 0x00c0, 0x471b: 0x00c0, 0x471c: 0x00c0, 0x471d: 0x00c0,
+	0x471e: 0x00c0, 0x471f: 0x00c0, 0x4720: 0x00c0, 0x4721: 0x00c0, 0x4722: 0x00c0, 0x4723: 0x00c0,
+	0x4724: 0x00c0, 0x4725: 0x00c0, 0x4726: 0x00c0, 0x4727: 0x00c0, 0x4728: 0x00c0, 0x4729: 0x00c0,
+	0x472a: 0x00c0, 0x472b: 0x00c0, 0x472c: 0x00c0, 0x472d: 0x00c0, 0x472e: 0x00c0, 0x472f: 0x00c0,
+	0x4730: 0x0040, 0x4731: 0x0040, 0x4732: 0x0040, 0x4733: 0x0040, 0x4734: 0x0040, 0x4735: 0x0040,
+	0x4736: 0x0040, 0x4737: 0x0040, 0x4738: 0x0040, 0x4739: 0x0040, 0x473a: 0x0040, 0x473b: 0x0040,
+	0x473c: 0x0040, 0x473d: 0x0040, 0x473e: 0x0040, 0x473f: 0x0040,
+	// Block 0x11d, offset 0x4740
+	0x4740: 0x00c3, 0x4741: 0x00c0, 0x4742: 0x00c0, 0x4743: 0x00c0, 0x4744: 0x00c0, 0x4745: 0x00c0,
+	0x4746: 0x00c0, 0x4747: 0x00c3, 0x4748: 0x00c3, 0x4749: 0x00c3, 0x474a: 0x00c3, 0x474b: 0x00c3,
+	0x474c: 0x00c3, 0x474d: 0x00c3, 0x474e: 0x00c3, 0x474f: 0x00c3, 0x4750: 0x00c3, 0x4751: 0x00c3,
+	0x4752: 0x00c3, 0x4753: 0x00c3, 0x4754: 0x00c3, 0x4755: 0x00c3,
+	// Block 0x11e, offset 0x4780
+	0x4780: 0x00c0, 0x4781: 0x00c0, 0x4782: 0x00c0, 0x4783: 0x00c0, 0x4784: 0x00c0, 0x4785: 0x00c0,
+	0x4786: 0x00c0, 0x4787: 0x00c0, 0x4788: 0x00c0, 0x4789: 0x00c0, 0x478a: 0x00c0, 0x478b: 0x00c0,
+	0x478c: 0x00c0, 0x478d: 0x00c0, 0x478e: 0x00c0, 0x478f: 0x00c0, 0x4790: 0x00c0, 0x4791: 0x00c0,
+	0x4792: 0x00c0, 0x4793: 0x00c0, 0x4794: 0x00c0, 0x4795: 0x00c0, 0x4796: 0x00c0, 0x4797: 0x00c0,
+	0x4798: 0x00c0, 0x4799: 0x00c0, 0x479a: 0x00c0, 0x479b: 0x00c0, 0x479c: 0x00c0, 0x479d: 0x00c0,
+	0x479e: 0x00c0, 0x47a0: 0x00c0, 0x47a1: 0x00c0, 0x47a2: 0x00c0, 0x47a3: 0x00c0,
+	0x47a4: 0x00c0, 0x47a5: 0x00c0, 0x47a6: 0x00c0, 0x47a7: 0x00c0, 0x47a8: 0x00c0, 0x47a9: 0x00c0,
+	0x47ae: 0x0080, 0x47af: 0x0080,
+	0x47b0: 0x00c0, 0x47b1: 0x00c0, 0x47b2: 0x00c0, 0x47b3: 0x00c0, 0x47b4: 0x00c0, 0x47b5: 0x00c0,
+	0x47b6: 0x00c0, 0x47b7: 0x00c0, 0x47b8: 0x00c0, 0x47b9: 0x00c0, 0x47ba: 0x00c0, 0x47bb: 0x00c0,
+	0x47bc: 0x00c0, 0x47bd: 0x00c0, 0x47be: 0x00c0, 0x47bf: 0x00c0,
+	// Block 0x11f, offset 0x47c0
+	0x47c0: 0x00c0, 0x47c1: 0x00c0, 0x47c2: 0x00c0, 0x47c3: 0x00c0, 0x47c4: 0x00c0, 0x47c5: 0x00c0,
+	0x47c6: 0x00c0, 0x47c7: 0x00c0, 0x47c8: 0x00c0, 0x47c9: 0x00c0, 0x47ca: 0x00c0, 0x47cb: 0x00c0,
+	0x47cc: 0x00c0, 0x47cd: 0x00c0, 0x47ce: 0x00c0, 0x47cf: 0x00c0, 0x47d0: 0x00c0, 0x47d1: 0x00c0,
+	0x47d2: 0x00c0, 0x47d3: 0x00c0, 0x47d4: 0x00c0, 0x47d5: 0x00c0, 0x47d6: 0x00c0, 0x47d7: 0x00c0,
+	0x47d8: 0x00c0, 0x47d9: 0x00c0, 0x47da: 0x00c0, 0x47db: 0x00c0, 0x47dc: 0x00c0, 0x47dd: 0x00c0,
+	0x47de: 0x00c0, 0x47df: 0x00c0, 0x47e0: 0x00c0, 0x47e1: 0x00c0, 0x47e2: 0x00c0, 0x47e3: 0x00c0,
+	0x47e4: 0x00c0, 0x47e5: 0x00c0, 0x47e6: 0x00c0, 0x47e7: 0x00c0, 0x47e8: 0x00c0, 0x47e9: 0x00c0,
+	0x47ea: 0x00c0, 0x47eb: 0x00c0, 0x47ec: 0x00c0, 0x47ed: 0x00c0, 0x47ee: 0x00c0, 0x47ef: 0x00c0,
+	0x47f0: 0x00c0, 0x47f1: 0x00c0, 0x47f2: 0x00c0, 0x47f3: 0x00c0, 0x47f4: 0x00c0, 0x47f5: 0x00c0,
+	0x47f6: 0x00c0, 0x47f7: 0x00c0, 0x47f8: 0x00c0, 0x47f9: 0x00c0, 0x47fa: 0x00c0, 0x47fb: 0x00c0,
+	0x47fc: 0x00c0, 0x47fd: 0x00c0, 0x47fe: 0x00c0,
+	// Block 0x120, offset 0x4800
+	0x4800: 0x00c0, 0x4801: 0x00c0, 0x4802: 0x00c0, 0x4803: 0x00c0, 0x4804: 0x00c0, 0x4805: 0x00c0,
+	0x4806: 0x00c0, 0x4807: 0x00c0, 0x4808: 0x00c0, 0x4809: 0x00c0,
+	0x4810: 0x00c0, 0x4811: 0x00c0,
+	0x4812: 0x00c0, 0x4813: 0x00c0, 0x4814: 0x00c0, 0x4815: 0x00c0, 0x4816: 0x00c0, 0x4817: 0x00c0,
+	0x4818: 0x00c0, 0x4819: 0x00c0, 0x481a: 0x00c0, 0x481b: 0x00c0, 0x481c: 0x00c0, 0x481d: 0x00c0,
+	0x481e: 0x00c0, 0x481f: 0x00c0, 0x4820: 0x00c0, 0x4821: 0x00c0, 0x4822: 0x00c0, 0x4823: 0x00c0,
+	0x4824: 0x00c0, 0x4825: 0x00c0, 0x4826: 0x00c0, 0x4827: 0x00c0, 0x4828: 0x00c0, 0x4829: 0x00c0,
+	0x482a: 0x00c0, 0x482b: 0x00c0, 0x482c: 0x00c0, 0x482d: 0x00c0,
+	0x4830: 0x00c3, 0x4831: 0x00c3, 0x4832: 0x00c3, 0x4833: 0x00c3, 0x4834: 0x00c3, 0x4835: 0x0080,
+	// Block 0x121, offset 0x4840
+	0x4840: 0x00c0, 0x4841: 0x00c0, 0x4842: 0x00c0, 0x4843: 0x00c0, 0x4844: 0x00c0, 0x4845: 0x00c0,
+	0x4846: 0x00c0, 0x4847: 0x00c0, 0x4848: 0x00c0, 0x4849: 0x00c0, 0x484a: 0x00c0, 0x484b: 0x00c0,
+	0x484c: 0x00c0, 0x484d: 0x00c0, 0x484e: 0x00c0, 0x484f: 0x00c0, 0x4850: 0x00c0, 0x4851: 0x00c0,
+	0x4852: 0x00c0, 0x4853: 0x00c0, 0x4854: 0x00c0, 0x4855: 0x00c0, 0x4856: 0x00c0, 0x4857: 0x00c0,
+	0x4858: 0x00c0, 0x4859: 0x00c0, 0x485a: 0x00c0, 0x485b: 0x00c0, 0x485c: 0x00c0, 0x485d: 0x00c0,
+	0x485e: 0x00c0, 0x485f: 0x00c0, 0x4860: 0x00c0, 0x4861: 0x00c0, 0x4862: 0x00c0, 0x4863: 0x00c0,
+	0x4864: 0x00c0, 0x4865: 0x00c0, 0x4866: 0x00c0, 0x4867: 0x00c0, 0x4868: 0x00c0, 0x4869: 0x00c0,
+	0x486a: 0x00c0, 0x486b: 0x00c0, 0x486c: 0x00c0, 0x486d: 0x00c0, 0x486e: 0x00c0, 0x486f: 0x00c0,
+	0x4870: 0x00c3, 0x4871: 0x00c3, 0x4872: 0x00c3, 0x4873: 0x00c3, 0x4874: 0x00c3, 0x4875: 0x00c3,
+	0x4876: 0x00c3, 0x4877: 0x0080, 0x4878: 0x0080, 0x4879: 0x0080, 0x487a: 0x0080, 0x487b: 0x0080,
+	0x487c: 0x0080, 0x487d: 0x0080, 0x487e: 0x0080, 0x487f: 0x0080,
+	// Block 0x122, offset 0x4880
+	0x4880: 0x00c0, 0x4881: 0x00c0, 0x4882: 0x00c0, 0x4883: 0x00c0, 0x4884: 0x0080, 0x4885: 0x0080,
+	0x4890: 0x00c0, 0x4891: 0x00c0,
+	0x4892: 0x00c0, 0x4893: 0x00c0, 0x4894: 0x00c0, 0x4895: 0x00c0, 0x4896: 0x00c0, 0x4897: 0x00c0,
+	0x4898: 0x00c0, 0x4899: 0x00c0, 0x489b: 0x0080, 0x489c: 0x0080, 0x489d: 0x0080,
+	0x489e: 0x0080, 0x489f: 0x0080, 0x48a0: 0x0080, 0x48a1: 0x0080, 0x48a3: 0x00c0,
+	0x48a4: 0x00c0, 0x48a5: 0x00c0, 0x48a6: 0x00c0, 0x48a7: 0x00c0, 0x48a8: 0x00c0, 0x48a9: 0x00c0,
+	0x48aa: 0x00c0, 0x48ab: 0x00c0, 0x48ac: 0x00c0, 0x48ad: 0x00c0, 0x48ae: 0x00c0, 0x48af: 0x00c0,
+	0x48b0: 0x00c0, 0x48b1: 0x00c0, 0x48b2: 0x00c0, 0x48b3: 0x00c0, 0x48b4: 0x00c0, 0x48b5: 0x00c0,
+	0x48b6: 0x00c0, 0x48b7: 0x00c0,
+	0x48bd: 0x00c0, 0x48be: 0x00c0, 0x48bf: 0x00c0,
+	// Block 0x123, offset 0x48c0
+	0x48c0: 0x00c0, 0x48c1: 0x00c0, 0x48c2: 0x00c0, 0x48c3: 0x00c0, 0x48c4: 0x00c0, 0x48c5: 0x00c0,
+	0x48c6: 0x00c0, 0x48c7: 0x00c0, 0x48c8: 0x00c0, 0x48c9: 0x00c0, 0x48ca: 0x00c0, 0x48cb: 0x00c0,
+	0x48cc: 0x00c0, 0x48cd: 0x00c0, 0x48ce: 0x00c0, 0x48cf: 0x00c0,
+	// Block 0x124, offset 0x4900
+	0x4900: 0x0080, 0x4901: 0x0080, 0x4902: 0x0080, 0x4903: 0x0080, 0x4904: 0x0080, 0x4905: 0x0080,
+	0x4906: 0x0080, 0x4907: 0x0080, 0x4908: 0x0080, 0x4909: 0x0080, 0x490a: 0x0080, 0x490b: 0x0080,
+	0x490c: 0x0080, 0x490d: 0x0080, 0x490e: 0x0080, 0x490f: 0x0080, 0x4910: 0x0080, 0x4911: 0x0080,
+	0x4912: 0x0080, 0x4913: 0x0080, 0x4914: 0x0080, 0x4915: 0x0080, 0x4916: 0x0080, 0x4917: 0x0080,
+	0x4918: 0x0080, 0x4919: 0x0080, 0x491a: 0x0080,
+	// Block 0x125, offset 0x4940
+	0x4940: 0x00c0, 0x4941: 0x00c0, 0x4942: 0x00c0, 0x4943: 0x00c0, 0x4944: 0x00c0, 0x4945: 0x00c0,
+	0x4946: 0x00c0, 0x4947: 0x00c0, 0x4948: 0x00c0, 0x4949: 0x00c0, 0x494a: 0x00c0,
+	0x494f: 0x00c3, 0x4950: 0x00c0, 0x4951: 0x00c0,
+	0x4952: 0x00c0, 0x4953: 0x00c0, 0x4954: 0x00c0, 0x4955: 0x00c0, 0x4956: 0x00c0, 0x4957: 0x00c0,
+	0x4958: 0x00c0, 0x4959: 0x00c0, 0x495a: 0x00c0, 0x495b: 0x00c0, 0x495c: 0x00c0, 0x495d: 0x00c0,
+	0x495e: 0x00c0, 0x495f: 0x00c0, 0x4960: 0x00c0, 0x4961: 0x00c0, 0x4962: 0x00c0, 0x4963: 0x00c0,
+	0x4964: 0x00c0, 0x4965: 0x00c0, 0x4966: 0x00c0, 0x4967: 0x00c0, 0x4968: 0x00c0, 0x4969: 0x00c0,
+	0x496a: 0x00c0, 0x496b: 0x00c0, 0x496c: 0x00c0, 0x496d: 0x00c0, 0x496e: 0x00c0, 0x496f: 0x00c0,
+	0x4970: 0x00c0, 0x4971: 0x00c0, 0x4972: 0x00c0, 0x4973: 0x00c0, 0x4974: 0x00c0, 0x4975: 0x00c0,
+	0x4976: 0x00c0, 0x4977: 0x00c0, 0x4978: 0x00c0, 0x4979: 0x00c0, 0x497a: 0x00c0, 0x497b: 0x00c0,
+	0x497c: 0x00c0, 0x497d: 0x00c0, 0x497e: 0x00c0, 0x497f: 0x00c0,
+	// Block 0x126, offset 0x4980
+	0x4980: 0x00c0, 0x4981: 0x00c0, 0x4982: 0x00c0, 0x4983: 0x00c0, 0x4984: 0x00c0, 0x4985: 0x00c0,
+	0x4986: 0x00c0, 0x4987: 0x00c0,
+	0x498f: 0x00c3, 0x4990: 0x00c3, 0x4991: 0x00c3,
+	0x4992: 0x00c3, 0x4993: 0x00c0, 0x4994: 0x00c0, 0x4995: 0x00c0, 0x4996: 0x00c0, 0x4997: 0x00c0,
+	0x4998: 0x00c0, 0x4999: 0x00c0, 0x499a: 0x00c0, 0x499b: 0x00c0, 0x499c: 0x00c0, 0x499d: 0x00c0,
+	0x499e: 0x00c0, 0x499f: 0x00c0,
+	// Block 0x127, offset 0x49c0
+	0x49e0: 0x00c0, 0x49e1: 0x00c0, 0x49e2: 0x008c, 0x49e3: 0x00cc,
+	0x49e4: 0x00c3,
+	0x49f0: 0x00cc, 0x49f1: 0x00cc,
+	// Block 0x128, offset 0x4a00
+	0x4a00: 0x00c0, 0x4a01: 0x00c0, 0x4a02: 0x00c0, 0x4a03: 0x00c0, 0x4a04: 0x00c0, 0x4a05: 0x00c0,
+	0x4a06: 0x00c0, 0x4a07: 0x00c0, 0x4a08: 0x00c0, 0x4a09: 0x00c0, 0x4a0a: 0x00c0, 0x4a0b: 0x00c0,
+	0x4a0c: 0x00c0, 0x4a0d: 0x00c0, 0x4a0e: 0x00c0, 0x4a0f: 0x00c0, 0x4a10: 0x00c0, 0x4a11: 0x00c0,
+	0x4a12: 0x00c0, 0x4a13: 0x00c0, 0x4a14: 0x00c0, 0x4a15: 0x00c0, 0x4a16: 0x00c0, 0x4a17: 0x00c0,
+	0x4a18: 0x00c0, 0x4a19: 0x00c0, 0x4a1a: 0x00c0, 0x4a1b: 0x00c0, 0x4a1c: 0x00c0, 0x4a1d: 0x00c0,
+	0x4a1e: 0x00c0, 0x4a1f: 0x00c0, 0x4a20: 0x00c0, 0x4a21: 0x00c0, 0x4a22: 0x00c0, 0x4a23: 0x00c0,
+	0x4a24: 0x00c0, 0x4a25: 0x00c0, 0x4a26: 0x00c0, 0x4a27: 0x00c0, 0x4a28: 0x00c0, 0x4a29: 0x00c0,
+	0x4a2a: 0x00c0, 0x4a2b: 0x00c0, 0x4a2c: 0x00c0, 0x4a2d: 0x00c0, 0x4a2e: 0x00c0, 0x4a2f: 0x00c0,
+	0x4a30: 0x00c0, 0x4a31: 0x00c0, 0x4a32: 0x00c0, 0x4a33: 0x00c0, 0x4a34: 0x00c0, 0x4a35: 0x00c0,
+	0x4a36: 0x00c0, 0x4a37: 0x00c0,
+	// Block 0x129, offset 0x4a40
+	0x4a40: 0x00c0, 0x4a41: 0x00c0, 0x4a42: 0x00c0, 0x4a43: 0x00c0, 0x4a44: 0x00c0, 0x4a45: 0x00c0,
+	0x4a46: 0x00c0, 0x4a47: 0x00c0, 0x4a48: 0x00c0, 0x4a49: 0x00c0, 0x4a4a: 0x00c0, 0x4a4b: 0x00c0,
+	0x4a4c: 0x00c0, 0x4a4d: 0x00c0, 0x4a4e: 0x00c0, 0x4a4f: 0x00c0, 0x4a50: 0x00c0, 0x4a51: 0x00c0,
+	0x4a52: 0x00c0, 0x4a53: 0x00c0, 0x4a54: 0x00c0, 0x4a55: 0x00c0,
+	// Block 0x12a, offset 0x4a80
+	0x4ab0: 0x00cc, 0x4ab1: 0x00cc, 0x4ab2: 0x00cc, 0x4ab3: 0x00cc, 0x4ab5: 0x00cc,
+	0x4ab6: 0x00cc, 0x4ab7: 0x00cc, 0x4ab8: 0x00cc, 0x4ab9: 0x00cc, 0x4aba: 0x00cc, 0x4abb: 0x00cc,
+	0x4abd: 0x00cc, 0x4abe: 0x00cc,
+	// Block 0x12b, offset 0x4ac0
+	0x4ac0: 0x00cc, 0x4ac1: 0x00cc, 0x4ac2: 0x00cc, 0x4ac3: 0x00cc, 0x4ac4: 0x00cc, 0x4ac5: 0x00cc,
+	0x4ac6: 0x00cc, 0x4ac7: 0x00cc, 0x4ac8: 0x00cc, 0x4ac9: 0x00cc, 0x4aca: 0x00cc, 0x4acb: 0x00cc,
+	0x4acc: 0x00cc, 0x4acd: 0x00cc, 0x4ace: 0x00cc, 0x4acf: 0x00cc, 0x4ad0: 0x00cc, 0x4ad1: 0x00cc,
+	0x4ad2: 0x00cc, 0x4ad3: 0x00cc, 0x4ad4: 0x00cc, 0x4ad5: 0x00cc, 0x4ad6: 0x00cc, 0x4ad7: 0x00cc,
+	0x4ad8: 0x00cc, 0x4ad9: 0x00cc, 0x4ada: 0x00cc, 0x4adb: 0x00cc, 0x4adc: 0x00cc, 0x4add: 0x00cc,
+	0x4ade: 0x00cc, 0x4adf: 0x00cc, 0x4ae0: 0x00cc, 0x4ae1: 0x00cc, 0x4ae2: 0x00cc,
+	0x4af2: 0x00cc,
+	// Block 0x12c, offset 0x4b00
+	0x4b10: 0x00cc, 0x4b11: 0x00cc,
+	0x4b12: 0x00cc, 0x4b15: 0x00cc,
+	0x4b24: 0x00cc, 0x4b25: 0x00cc, 0x4b26: 0x00cc, 0x4b27: 0x00cc,
+	0x4b30: 0x00c0, 0x4b31: 0x00c0, 0x4b32: 0x00c0, 0x4b33: 0x00c0, 0x4b34: 0x00c0, 0x4b35: 0x00c0,
+	0x4b36: 0x00c0, 0x4b37: 0x00c0, 0x4b38: 0x00c0, 0x4b39: 0x00c0, 0x4b3a: 0x00c0, 0x4b3b: 0x00c0,
+	0x4b3c: 0x00c0, 0x4b3d: 0x00c0, 0x4b3e: 0x00c0, 0x4b3f: 0x00c0,
+	// Block 0x12d, offset 0x4b40
+	0x4b40: 0x00c0, 0x4b41: 0x00c0, 0x4b42: 0x00c0, 0x4b43: 0x00c0, 0x4b44: 0x00c0, 0x4b45: 0x00c0,
+	0x4b46: 0x00c0, 0x4b47: 0x00c0, 0x4b48: 0x00c0, 0x4b49: 0x00c0, 0x4b4a: 0x00c0, 0x4b4b: 0x00c0,
+	0x4b4c: 0x00c0, 0x4b4d: 0x00c0, 0x4b4e: 0x00c0, 0x4b4f: 0x00c0, 0x4b50: 0x00c0, 0x4b51: 0x00c0,
+	0x4b52: 0x00c0, 0x4b53: 0x00c0, 0x4b54: 0x00c0, 0x4b55: 0x00c0, 0x4b56: 0x00c0, 0x4b57: 0x00c0,
+	0x4b58: 0x00c0, 0x4b59: 0x00c0, 0x4b5a: 0x00c0, 0x4b5b: 0x00c0, 0x4b5c: 0x00c0, 0x4b5d: 0x00c0,
+	0x4b5e: 0x00c0, 0x4b5f: 0x00c0, 0x4b60: 0x00c0, 0x4b61: 0x00c0, 0x4b62: 0x00c0, 0x4b63: 0x00c0,
+	0x4b64: 0x00c0, 0x4b65: 0x00c0, 0x4b66: 0x00c0, 0x4b67: 0x00c0, 0x4b68: 0x00c0, 0x4b69: 0x00c0,
+	0x4b6a: 0x00c0, 0x4b6b: 0x00c0, 0x4b6c: 0x00c0, 0x4b6d: 0x00c0, 0x4b6e: 0x00c0, 0x4b6f: 0x00c0,
+	0x4b70: 0x00c0, 0x4b71: 0x00c0, 0x4b72: 0x00c0, 0x4b73: 0x00c0, 0x4b74: 0x00c0, 0x4b75: 0x00c0,
+	0x4b76: 0x00c0, 0x4b77: 0x00c0, 0x4b78: 0x00c0, 0x4b79: 0x00c0, 0x4b7a: 0x00c0, 0x4b7b: 0x00c0,
+	// Block 0x12e, offset 0x4b80
+	0x4b80: 0x00c0, 0x4b81: 0x00c0, 0x4b82: 0x00c0, 0x4b83: 0x00c0, 0x4b84: 0x00c0, 0x4b85: 0x00c0,
+	0x4b86: 0x00c0, 0x4b87: 0x00c0, 0x4b88: 0x00c0, 0x4b89: 0x00c0, 0x4b8a: 0x00c0, 0x4b8b: 0x00c0,
+	0x4b8c: 0x00c0, 0x4b8d: 0x00c0, 0x4b8e: 0x00c0, 0x4b8f: 0x00c0, 0x4b90: 0x00c0, 0x4b91: 0x00c0,
+	0x4b92: 0x00c0, 0x4b93: 0x00c0, 0x4b94: 0x00c0, 0x4b95: 0x00c0, 0x4b96: 0x00c0, 0x4b97: 0x00c0,
+	0x4b98: 0x00c0, 0x4b99: 0x00c0, 0x4b9a: 0x00c0, 0x4b9b: 0x00c0, 0x4b9c: 0x00c0, 0x4b9d: 0x00c0,
+	0x4b9e: 0x00c0, 0x4b9f: 0x00c0, 0x4ba0: 0x00c0, 0x4ba1: 0x00c0, 0x4ba2: 0x00c0, 0x4ba3: 0x00c0,
+	0x4ba4: 0x00c0, 0x4ba5: 0x00c0, 0x4ba6: 0x00c0, 0x4ba7: 0x00c0, 0x4ba8: 0x00c0, 0x4ba9: 0x00c0,
+	0x4baa: 0x00c0,
+	0x4bb0: 0x00c0, 0x4bb1: 0x00c0, 0x4bb2: 0x00c0, 0x4bb3: 0x00c0, 0x4bb4: 0x00c0, 0x4bb5: 0x00c0,
+	0x4bb6: 0x00c0, 0x4bb7: 0x00c0, 0x4bb8: 0x00c0, 0x4bb9: 0x00c0, 0x4bba: 0x00c0, 0x4bbb: 0x00c0,
+	0x4bbc: 0x00c0,
+	// Block 0x12f, offset 0x4bc0
+	0x4bc0: 0x00c0, 0x4bc1: 0x00c0, 0x4bc2: 0x00c0, 0x4bc3: 0x00c0, 0x4bc4: 0x00c0, 0x4bc5: 0x00c0,
+	0x4bc6: 0x00c0, 0x4bc7: 0x00c0, 0x4bc8: 0x00c0,
+	0x4bd0: 0x00c0, 0x4bd1: 0x00c0,
+	0x4bd2: 0x00c0, 0x4bd3: 0x00c0, 0x4bd4: 0x00c0, 0x4bd5: 0x00c0, 0x4bd6: 0x00c0, 0x4bd7: 0x00c0,
+	0x4bd8: 0x00c0, 0x4bd9: 0x00c0, 0x4bdc: 0x0080, 0x4bdd: 0x00c3,
+	0x4bde: 0x00c3, 0x4bdf: 0x0080, 0x4be0: 0x0040, 0x4be1: 0x0040, 0x4be2: 0x0040, 0x4be3: 0x0040,
+	// Block 0x130, offset 0x4c00
+	0x4c00: 0x00c3, 0x4c01: 0x00c3, 0x4c02: 0x00c3, 0x4c03: 0x00c3, 0x4c04: 0x00c3, 0x4c05: 0x00c3,
+	0x4c06: 0x00c3, 0x4c07: 0x00c3, 0x4c08: 0x00c3, 0x4c09: 0x00c3, 0x4c0a: 0x00c3, 0x4c0b: 0x00c3,
+	0x4c0c: 0x00c3, 0x4c0d: 0x00c3, 0x4c0e: 0x00c3, 0x4c0f: 0x00c3, 0x4c10: 0x00c3, 0x4c11: 0x00c3,
+	0x4c12: 0x00c3, 0x4c13: 0x00c3, 0x4c14: 0x00c3, 0x4c15: 0x00c3, 0x4c16: 0x00c3, 0x4c17: 0x00c3,
+	0x4c18: 0x00c3, 0x4c19: 0x00c3, 0x4c1a: 0x00c3, 0x4c1b: 0x00c3, 0x4c1c: 0x00c3, 0x4c1d: 0x00c3,
+	0x4c1e: 0x00c3, 0x4c1f: 0x00c3, 0x4c20: 0x00c3, 0x4c21: 0x00c3, 0x4c22: 0x00c3, 0x4c23: 0x00c3,
+	0x4c24: 0x00c3, 0x4c25: 0x00c3, 0x4c26: 0x00c3, 0x4c27: 0x00c3, 0x4c28: 0x00c3, 0x4c29: 0x00c3,
+	0x4c2a: 0x00c3, 0x4c2b: 0x00c3, 0x4c2c: 0x00c3, 0x4c2d: 0x00c3,
+	0x4c30: 0x00c3, 0x4c31: 0x00c3, 0x4c32: 0x00c3, 0x4c33: 0x00c3, 0x4c34: 0x00c3, 0x4c35: 0x00c3,
+	0x4c36: 0x00c3, 0x4c37: 0x00c3, 0x4c38: 0x00c3, 0x4c39: 0x00c3, 0x4c3a: 0x00c3, 0x4c3b: 0x00c3,
+	0x4c3c: 0x00c3, 0x4c3d: 0x00c3, 0x4c3e: 0x00c3, 0x4c3f: 0x00c3,
+	// Block 0x131, offset 0x4c40
+	0x4c40: 0x00c3, 0x4c41: 0x00c3, 0x4c42: 0x00c3, 0x4c43: 0x00c3, 0x4c44: 0x00c3, 0x4c45: 0x00c3,
+	0x4c46: 0x00c3,
+	0x4c50: 0x0080, 0x4c51: 0x0080,
+	0x4c52: 0x0080, 0x4c53: 0x0080, 0x4c54: 0x0080, 0x4c55: 0x0080, 0x4c56: 0x0080, 0x4c57: 0x0080,
+	0x4c58: 0x0080, 0x4c59: 0x0080, 0x4c5a: 0x0080, 0x4c5b: 0x0080, 0x4c5c: 0x0080, 0x4c5d: 0x0080,
+	0x4c5e: 0x0080, 0x4c5f: 0x0080, 0x4c60: 0x0080, 0x4c61: 0x0080, 0x4c62: 0x0080, 0x4c63: 0x0080,
+	0x4c64: 0x0080, 0x4c65: 0x0080, 0x4c66: 0x0080, 0x4c67: 0x0080, 0x4c68: 0x0080, 0x4c69: 0x0080,
+	0x4c6a: 0x0080, 0x4c6b: 0x0080, 0x4c6c: 0x0080, 0x4c6d: 0x0080, 0x4c6e: 0x0080, 0x4c6f: 0x0080,
+	0x4c70: 0x0080, 0x4c71: 0x0080, 0x4c72: 0x0080, 0x4c73: 0x0080, 0x4c74: 0x0080, 0x4c75: 0x0080,
+	0x4c76: 0x0080, 0x4c77: 0x0080, 0x4c78: 0x0080, 0x4c79: 0x0080, 0x4c7a: 0x0080, 0x4c7b: 0x0080,
+	0x4c7c: 0x0080, 0x4c7d: 0x0080, 0x4c7e: 0x0080, 0x4c7f: 0x0080,
+	// Block 0x132, offset 0x4c80
+	0x4c80: 0x0080, 0x4c81: 0x0080, 0x4c82: 0x0080, 0x4c83: 0x0080,
+	// Block 0x133, offset 0x4cc0
+	0x4cc0: 0x0080, 0x4cc1: 0x0080, 0x4cc2: 0x0080, 0x4cc3: 0x0080, 0x4cc4: 0x0080, 0x4cc5: 0x0080,
+	0x4cc6: 0x0080, 0x4cc7: 0x0080, 0x4cc8: 0x0080, 0x4cc9: 0x0080, 0x4cca: 0x0080, 0x4ccb: 0x0080,
+	0x4ccc: 0x0080, 0x4ccd: 0x0080, 0x4cce: 0x0080, 0x4ccf: 0x0080, 0x4cd0: 0x0080, 0x4cd1: 0x0080,
+	0x4cd2: 0x0080, 0x4cd3: 0x0080, 0x4cd4: 0x0080, 0x4cd5: 0x0080, 0x4cd6: 0x0080, 0x4cd7: 0x0080,
+	0x4cd8: 0x0080, 0x4cd9: 0x0080, 0x4cda: 0x0080, 0x4cdb: 0x0080, 0x4cdc: 0x0080, 0x4cdd: 0x0080,
+	0x4cde: 0x0080, 0x4cdf: 0x0080, 0x4ce0: 0x0080, 0x4ce1: 0x0080, 0x4ce2: 0x0080, 0x4ce3: 0x0080,
+	0x4ce4: 0x0080, 0x4ce5: 0x0080, 0x4ce6: 0x0080, 0x4ce7: 0x0080, 0x4ce8: 0x0080, 0x4ce9: 0x0080,
+	0x4cea: 0x0080, 0x4ceb: 0x0080, 0x4cec: 0x0080, 0x4ced: 0x0080, 0x4cee: 0x0080, 0x4cef: 0x0080,
+	0x4cf0: 0x0080, 0x4cf1: 0x0080, 0x4cf2: 0x0080, 0x4cf3: 0x0080, 0x4cf4: 0x0080, 0x4cf5: 0x0080,
+	// Block 0x134, offset 0x4d00
+	0x4d00: 0x0080, 0x4d01: 0x0080, 0x4d02: 0x0080, 0x4d03: 0x0080, 0x4d04: 0x0080, 0x4d05: 0x0080,
+	0x4d06: 0x0080, 0x4d07: 0x0080, 0x4d08: 0x0080, 0x4d09: 0x0080, 0x4d0a: 0x0080, 0x4d0b: 0x0080,
+	0x4d0c: 0x0080, 0x4d0d: 0x0080, 0x4d0e: 0x0080, 0x4d0f: 0x0080, 0x4d10: 0x0080, 0x4d11: 0x0080,
+	0x4d12: 0x0080, 0x4d13: 0x0080, 0x4d14: 0x0080, 0x4d15: 0x0080, 0x4d16: 0x0080, 0x4d17: 0x0080,
+	0x4d18: 0x0080, 0x4d19: 0x0080, 0x4d1a: 0x0080, 0x4d1b: 0x0080, 0x4d1c: 0x0080, 0x4d1d: 0x0080,
+	0x4d1e: 0x0080, 0x4d1f: 0x0080, 0x4d20: 0x0080, 0x4d21: 0x0080, 0x4d22: 0x0080, 0x4d23: 0x0080,
+	0x4d24: 0x0080, 0x4d25: 0x0080, 0x4d26: 0x0080, 0x4d29: 0x0080,
+	0x4d2a: 0x0080, 0x4d2b: 0x0080, 0x4d2c: 0x0080, 0x4d2d: 0x0080, 0x4d2e: 0x0080, 0x4d2f: 0x0080,
+	0x4d30: 0x0080, 0x4d31: 0x0080, 0x4d32: 0x0080, 0x4d33: 0x0080, 0x4d34: 0x0080, 0x4d35: 0x0080,
+	0x4d36: 0x0080, 0x4d37: 0x0080, 0x4d38: 0x0080, 0x4d39: 0x0080, 0x4d3a: 0x0080, 0x4d3b: 0x0080,
+	0x4d3c: 0x0080, 0x4d3d: 0x0080, 0x4d3e: 0x0080, 0x4d3f: 0x0080,
+	// Block 0x135, offset 0x4d40
+	0x4d40: 0x0080, 0x4d41: 0x0080, 0x4d42: 0x0080, 0x4d43: 0x0080, 0x4d44: 0x0080, 0x4d45: 0x0080,
+	0x4d46: 0x0080, 0x4d47: 0x0080, 0x4d48: 0x0080, 0x4d49: 0x0080, 0x4d4a: 0x0080, 0x4d4b: 0x0080,
+	0x4d4c: 0x0080, 0x4d4d: 0x0080, 0x4d4e: 0x0080, 0x4d4f: 0x0080, 0x4d50: 0x0080, 0x4d51: 0x0080,
+	0x4d52: 0x0080, 0x4d53: 0x0080, 0x4d54: 0x0080, 0x4d55: 0x0080, 0x4d56: 0x0080, 0x4d57: 0x0080,
+	0x4d58: 0x0080, 0x4d59: 0x0080, 0x4d5a: 0x0080, 0x4d5b: 0x0080, 0x4d5c: 0x0080, 0x4d5d: 0x0080,
+	0x4d5e: 0x0080, 0x4d5f: 0x0080, 0x4d60: 0x0080, 0x4d61: 0x0080, 0x4d62: 0x0080, 0x4d63: 0x0080,
+	0x4d64: 0x0080, 0x4d65: 0x00c0, 0x4d66: 0x00c0, 0x4d67: 0x00c3, 0x4d68: 0x00c3, 0x4d69: 0x00c3,
+	0x4d6a: 0x0080, 0x4d6b: 0x0080, 0x4d6c: 0x0080, 0x4d6d: 0x00c0, 0x4d6e: 0x00c0, 0x4d6f: 0x00c0,
+	0x4d70: 0x00c0, 0x4d71: 0x00c0, 0x4d72: 0x00c0, 0x4d73: 0x0040, 0x4d74: 0x0040, 0x4d75: 0x0040,
+	0x4d76: 0x0040, 0x4d77: 0x0040, 0x4d78: 0x0040, 0x4d79: 0x0040, 0x4d7a: 0x0040, 0x4d7b: 0x00c3,
+	0x4d7c: 0x00c3, 0x4d7d: 0x00c3, 0x4d7e: 0x00c3, 0x4d7f: 0x00c3,
+	// Block 0x136, offset 0x4d80
+	0x4d80: 0x00c3, 0x4d81: 0x00c3, 0x4d82: 0x00c3, 0x4d83: 0x0080, 0x4d84: 0x0080, 0x4d85: 0x00c3,
+	0x4d86: 0x00c3, 0x4d87: 0x00c3, 0x4d88: 0x00c3, 0x4d89: 0x00c3, 0x4d8a: 0x00c3, 0x4d8b: 0x00c3,
+	0x4d8c: 0x0080, 0x4d8d: 0x0080, 0x4d8e: 0x0080, 0x4d8f: 0x0080, 0x4d90: 0x0080, 0x4d91: 0x0080,
+	0x4d92: 0x0080, 0x4d93: 0x0080, 0x4d94: 0x0080, 0x4d95: 0x0080, 0x4d96: 0x0080, 0x4d97: 0x0080,
+	0x4d98: 0x0080, 0x4d99: 0x0080, 0x4d9a: 0x0080, 0x4d9b: 0x0080, 0x4d9c: 0x0080, 0x4d9d: 0x0080,
+	0x4d9e: 0x0080, 0x4d9f: 0x0080, 0x4da0: 0x0080, 0x4da1: 0x0080, 0x4da2: 0x0080, 0x4da3: 0x0080,
+	0x4da4: 0x0080, 0x4da5: 0x0080, 0x4da6: 0x0080, 0x4da7: 0x0080, 0x4da8: 0x0080, 0x4da9: 0x0080,
+	0x4daa: 0x00c3, 0x4dab: 0x00c3, 0x4dac: 0x00c3, 0x4dad: 0x00c3, 0x4dae: 0x0080, 0x4daf: 0x0080,
+	0x4db0: 0x0080, 0x4db1: 0x0080, 0x4db2: 0x0080, 0x4db3: 0x0080, 0x4db4: 0x0080, 0x4db5: 0x0080,
+	0x4db6: 0x0080, 0x4db7: 0x0080, 0x4db8: 0x0080, 0x4db9: 0x0080, 0x4dba: 0x0080, 0x4dbb: 0x0080,
+	0x4dbc: 0x0080, 0x4dbd: 0x0080, 0x4dbe: 0x0080, 0x4dbf: 0x0080,
+	// Block 0x137, offset 0x4dc0
+	0x4dc0: 0x0080, 0x4dc1: 0x0080, 0x4dc2: 0x0080, 0x4dc3: 0x0080, 0x4dc4: 0x0080, 0x4dc5: 0x0080,
+	0x4dc6: 0x0080, 0x4dc7: 0x0080, 0x4dc8: 0x0080, 0x4dc9: 0x0080, 0x4dca: 0x0080, 0x4dcb: 0x0080,
+	0x4dcc: 0x0080, 0x4dcd: 0x0080, 0x4dce: 0x0080, 0x4dcf: 0x0080, 0x4dd0: 0x0080, 0x4dd1: 0x0080,
+	0x4dd2: 0x0080, 0x4dd3: 0x0080, 0x4dd4: 0x0080, 0x4dd5: 0x0080, 0x4dd6: 0x0080, 0x4dd7: 0x0080,
+	0x4dd8: 0x0080, 0x4dd9: 0x0080, 0x4dda: 0x0080, 0x4ddb: 0x0080, 0x4ddc: 0x0080, 0x4ddd: 0x0080,
+	0x4dde: 0x0080, 0x4ddf: 0x0080, 0x4de0: 0x0080, 0x4de1: 0x0080, 0x4de2: 0x0080, 0x4de3: 0x0080,
+	0x4de4: 0x0080, 0x4de5: 0x0080, 0x4de6: 0x0080, 0x4de7: 0x0080, 0x4de8: 0x0080, 0x4de9: 0x0080,
+	0x4dea: 0x0080,
+	// Block 0x138, offset 0x4e00
+	0x4e00: 0x0088, 0x4e01: 0x0088, 0x4e02: 0x00c9, 0x4e03: 0x00c9, 0x4e04: 0x00c9, 0x4e05: 0x0088,
+	// Block 0x139, offset 0x4e40
+	0x4e40: 0x0080, 0x4e41: 0x0080, 0x4e42: 0x0080, 0x4e43: 0x0080, 0x4e44: 0x0080, 0x4e45: 0x0080,
+	0x4e46: 0x0080, 0x4e47: 0x0080, 0x4e48: 0x0080, 0x4e49: 0x0080, 0x4e4a: 0x0080, 0x4e4b: 0x0080,
+	0x4e4c: 0x0080, 0x4e4d: 0x0080, 0x4e4e: 0x0080, 0x4e4f: 0x0080, 0x4e50: 0x0080, 0x4e51: 0x0080,
+	0x4e52: 0x0080, 0x4e53: 0x0080,
+	0x4e60: 0x0080, 0x4e61: 0x0080, 0x4e62: 0x0080, 0x4e63: 0x0080,
+	0x4e64: 0x0080, 0x4e65: 0x0080, 0x4e66: 0x0080, 0x4e67: 0x0080, 0x4e68: 0x0080, 0x4e69: 0x0080,
+	0x4e6a: 0x0080, 0x4e6b: 0x0080, 0x4e6c: 0x0080, 0x4e6d: 0x0080, 0x4e6e: 0x0080, 0x4e6f: 0x0080,
+	0x4e70: 0x0080, 0x4e71: 0x0080, 0x4e72: 0x0080, 0x4e73: 0x0080,
+	// Block 0x13a, offset 0x4e80
+	0x4e80: 0x0080, 0x4e81: 0x0080, 0x4e82: 0x0080, 0x4e83: 0x0080, 0x4e84: 0x0080, 0x4e85: 0x0080,
+	0x4e86: 0x0080, 0x4e87: 0x0080, 0x4e88: 0x0080, 0x4e89: 0x0080, 0x4e8a: 0x0080, 0x4e8b: 0x0080,
+	0x4e8c: 0x0080, 0x4e8d: 0x0080, 0x4e8e: 0x0080, 0x4e8f: 0x0080, 0x4e90: 0x0080, 0x4e91: 0x0080,
+	0x4e92: 0x0080, 0x4e93: 0x0080, 0x4e94: 0x0080, 0x4e95: 0x0080, 0x4e96: 0x0080,
+	0x4ea0: 0x0080, 0x4ea1: 0x0080, 0x4ea2: 0x0080, 0x4ea3: 0x0080,
+	0x4ea4: 0x0080, 0x4ea5: 0x0080, 0x4ea6: 0x0080, 0x4ea7: 0x0080, 0x4ea8: 0x0080, 0x4ea9: 0x0080,
+	0x4eaa: 0x0080, 0x4eab: 0x0080, 0x4eac: 0x0080, 0x4ead: 0x0080, 0x4eae: 0x0080, 0x4eaf: 0x0080,
+	0x4eb0: 0x0080, 0x4eb1: 0x0080, 0x4eb2: 0x0080, 0x4eb3: 0x0080, 0x4eb4: 0x0080, 0x4eb5: 0x0080,
+	0x4eb6: 0x0080, 0x4eb7: 0x0080, 0x4eb8: 0x0080,
+	// Block 0x13b, offset 0x4ec0
+	0x4ec0: 0x0080, 0x4ec1: 0x0080, 0x4ec2: 0x0080, 0x4ec3: 0x0080, 0x4ec4: 0x0080, 0x4ec5: 0x0080,
+	0x4ec6: 0x0080, 0x4ec7: 0x0080, 0x4ec8: 0x0080, 0x4ec9: 0x0080, 0x4eca: 0x0080, 0x4ecb: 0x0080,
+	0x4ecc: 0x0080, 0x4ecd: 0x0080, 0x4ece: 0x0080, 0x4ecf: 0x0080, 0x4ed0: 0x0080, 0x4ed1: 0x0080,
+	0x4ed2: 0x0080, 0x4ed3: 0x0080, 0x4ed4: 0x0080, 0x4ed6: 0x0080, 0x4ed7: 0x0080,
+	0x4ed8: 0x0080, 0x4ed9: 0x0080, 0x4eda: 0x0080, 0x4edb: 0x0080, 0x4edc: 0x0080, 0x4edd: 0x0080,
+	0x4ede: 0x0080, 0x4edf: 0x0080, 0x4ee0: 0x0080, 0x4ee1: 0x0080, 0x4ee2: 0x0080, 0x4ee3: 0x0080,
+	0x4ee4: 0x0080, 0x4ee5: 0x0080, 0x4ee6: 0x0080, 0x4ee7: 0x0080, 0x4ee8: 0x0080, 0x4ee9: 0x0080,
+	0x4eea: 0x0080, 0x4eeb: 0x0080, 0x4eec: 0x0080, 0x4eed: 0x0080, 0x4eee: 0x0080, 0x4eef: 0x0080,
+	0x4ef0: 0x0080, 0x4ef1: 0x0080, 0x4ef2: 0x0080, 0x4ef3: 0x0080, 0x4ef4: 0x0080, 0x4ef5: 0x0080,
+	0x4ef6: 0x0080, 0x4ef7: 0x0080, 0x4ef8: 0x0080, 0x4ef9: 0x0080, 0x4efa: 0x0080, 0x4efb: 0x0080,
+	0x4efc: 0x0080, 0x4efd: 0x0080, 0x4efe: 0x0080, 0x4eff: 0x0080,
+	// Block 0x13c, offset 0x4f00
+	0x4f00: 0x0080, 0x4f01: 0x0080, 0x4f02: 0x0080, 0x4f03: 0x0080, 0x4f04: 0x0080, 0x4f05: 0x0080,
+	0x4f06: 0x0080, 0x4f07: 0x0080, 0x4f08: 0x0080, 0x4f09: 0x0080, 0x4f0a: 0x0080, 0x4f0b: 0x0080,
+	0x4f0c: 0x0080, 0x4f0d: 0x0080, 0x4f0e: 0x0080, 0x4f0f: 0x0080, 0x4f10: 0x0080, 0x4f11: 0x0080,
+	0x4f12: 0x0080, 0x4f13: 0x0080, 0x4f14: 0x0080, 0x4f15: 0x0080, 0x4f16: 0x0080, 0x4f17: 0x0080,
+	0x4f18: 0x0080, 0x4f19: 0x0080, 0x4f1a: 0x0080, 0x4f1b: 0x0080, 0x4f1c: 0x0080,
+	0x4f1e: 0x0080, 0x4f1f: 0x0080, 0x4f22: 0x0080,
+	0x4f25: 0x0080, 0x4f26: 0x0080, 0x4f29: 0x0080,
+	0x4f2a: 0x0080, 0x4f2b: 0x0080, 0x4f2c: 0x0080, 0x4f2e: 0x0080, 0x4f2f: 0x0080,
+	0x4f30: 0x0080, 0x4f31: 0x0080, 0x4f32: 0x0080, 0x4f33: 0x0080, 0x4f34: 0x0080, 0x4f35: 0x0080,
+	0x4f36: 0x0080, 0x4f37: 0x0080, 0x4f38: 0x0080, 0x4f39: 0x0080, 0x4f3b: 0x0080,
+	0x4f3d: 0x0080, 0x4f3e: 0x0080, 0x4f3f: 0x0080,
+	// Block 0x13d, offset 0x4f40
+	0x4f40: 0x0080, 0x4f41: 0x0080, 0x4f42: 0x0080, 0x4f43: 0x0080, 0x4f45: 0x0080,
+	0x4f46: 0x0080, 0x4f47: 0x0080, 0x4f48: 0x0080, 0x4f49: 0x0080, 0x4f4a: 0x0080, 0x4f4b: 0x0080,
+	0x4f4c: 0x0080, 0x4f4d: 0x0080, 0x4f4e: 0x0080, 0x4f4f: 0x0080, 0x4f50: 0x0080, 0x4f51: 0x0080,
+	0x4f52: 0x0080, 0x4f53: 0x0080, 0x4f54: 0x0080, 0x4f55: 0x0080, 0x4f56: 0x0080, 0x4f57: 0x0080,
+	0x4f58: 0x0080, 0x4f59: 0x0080, 0x4f5a: 0x0080, 0x4f5b: 0x0080, 0x4f5c: 0x0080, 0x4f5d: 0x0080,
+	0x4f5e: 0x0080, 0x4f5f: 0x0080, 0x4f60: 0x0080, 0x4f61: 0x0080, 0x4f62: 0x0080, 0x4f63: 0x0080,
+	0x4f64: 0x0080, 0x4f65: 0x0080, 0x4f66: 0x0080, 0x4f67: 0x0080, 0x4f68: 0x0080, 0x4f69: 0x0080,
+	0x4f6a: 0x0080, 0x4f6b: 0x0080, 0x4f6c: 0x0080, 0x4f6d: 0x0080, 0x4f6e: 0x0080, 0x4f6f: 0x0080,
+	0x4f70: 0x0080, 0x4f71: 0x0080, 0x4f72: 0x0080, 0x4f73: 0x0080, 0x4f74: 0x0080, 0x4f75: 0x0080,
+	0x4f76: 0x0080, 0x4f77: 0x0080, 0x4f78: 0x0080, 0x4f79: 0x0080, 0x4f7a: 0x0080, 0x4f7b: 0x0080,
+	0x4f7c: 0x0080, 0x4f7d: 0x0080, 0x4f7e: 0x0080, 0x4f7f: 0x0080,
+	// Block 0x13e, offset 0x4f80
+	0x4f80: 0x0080, 0x4f81: 0x0080, 0x4f82: 0x0080, 0x4f83: 0x0080, 0x4f84: 0x0080, 0x4f85: 0x0080,
+	0x4f87: 0x0080, 0x4f88: 0x0080, 0x4f89: 0x0080, 0x4f8a: 0x0080,
+	0x4f8d: 0x0080, 0x4f8e: 0x0080, 0x4f8f: 0x0080, 0x4f90: 0x0080, 0x4f91: 0x0080,
+	0x4f92: 0x0080, 0x4f93: 0x0080, 0x4f94: 0x0080, 0x4f96: 0x0080, 0x4f97: 0x0080,
+	0x4f98: 0x0080, 0x4f99: 0x0080, 0x4f9a: 0x0080, 0x4f9b: 0x0080, 0x4f9c: 0x0080,
+	0x4f9e: 0x0080, 0x4f9f: 0x0080, 0x4fa0: 0x0080, 0x4fa1: 0x0080, 0x4fa2: 0x0080, 0x4fa3: 0x0080,
+	0x4fa4: 0x0080, 0x4fa5: 0x0080, 0x4fa6: 0x0080, 0x4fa7: 0x0080, 0x4fa8: 0x0080, 0x4fa9: 0x0080,
+	0x4faa: 0x0080, 0x4fab: 0x0080, 0x4fac: 0x0080, 0x4fad: 0x0080, 0x4fae: 0x0080, 0x4faf: 0x0080,
+	0x4fb0: 0x0080, 0x4fb1: 0x0080, 0x4fb2: 0x0080, 0x4fb3: 0x0080, 0x4fb4: 0x0080, 0x4fb5: 0x0080,
+	0x4fb6: 0x0080, 0x4fb7: 0x0080, 0x4fb8: 0x0080, 0x4fb9: 0x0080, 0x4fbb: 0x0080,
+	0x4fbc: 0x0080, 0x4fbd: 0x0080, 0x4fbe: 0x0080,
+	// Block 0x13f, offset 0x4fc0
+	0x4fc0: 0x0080, 0x4fc1: 0x0080, 0x4fc2: 0x0080, 0x4fc3: 0x0080, 0x4fc4: 0x0080,
+	0x4fc6: 0x0080, 0x4fca: 0x0080, 0x4fcb: 0x0080,
+	0x4fcc: 0x0080, 0x4fcd: 0x0080, 0x4fce: 0x0080, 0x4fcf: 0x0080, 0x4fd0: 0x0080,
+	0x4fd2: 0x0080, 0x4fd3: 0x0080, 0x4fd4: 0x0080, 0x4fd5: 0x0080, 0x4fd6: 0x0080, 0x4fd7: 0x0080,
+	0x4fd8: 0x0080, 0x4fd9: 0x0080, 0x4fda: 0x0080, 0x4fdb: 0x0080, 0x4fdc: 0x0080, 0x4fdd: 0x0080,
+	0x4fde: 0x0080, 0x4fdf: 0x0080, 0x4fe0: 0x0080, 0x4fe1: 0x0080, 0x4fe2: 0x0080, 0x4fe3: 0x0080,
+	0x4fe4: 0x0080, 0x4fe5: 0x0080, 0x4fe6: 0x0080, 0x4fe7: 0x0080, 0x4fe8: 0x0080, 0x4fe9: 0x0080,
+	0x4fea: 0x0080, 0x4feb: 0x0080, 0x4fec: 0x0080, 0x4fed: 0x0080, 0x4fee: 0x0080, 0x4fef: 0x0080,
+	0x4ff0: 0x0080, 0x4ff1: 0x0080, 0x4ff2: 0x0080, 0x4ff3: 0x0080, 0x4ff4: 0x0080, 0x4ff5: 0x0080,
+	0x4ff6: 0x0080, 0x4ff7: 0x0080, 0x4ff8: 0x0080, 0x4ff9: 0x0080, 0x4ffa: 0x0080, 0x4ffb: 0x0080,
+	0x4ffc: 0x0080, 0x4ffd: 0x0080, 0x4ffe: 0x0080, 0x4fff: 0x0080,
+	// Block 0x140, offset 0x5000
+	0x5000: 0x0080, 0x5001: 0x0080, 0x5002: 0x0080, 0x5003: 0x0080, 0x5004: 0x0080, 0x5005: 0x0080,
+	0x5006: 0x0080, 0x5007: 0x0080, 0x5008: 0x0080, 0x5009: 0x0080, 0x500a: 0x0080, 0x500b: 0x0080,
+	0x500c: 0x0080, 0x500d: 0x0080, 0x500e: 0x0080, 0x500f: 0x0080, 0x5010: 0x0080, 0x5011: 0x0080,
+	0x5012: 0x0080, 0x5013: 0x0080, 0x5014: 0x0080, 0x5015: 0x0080, 0x5016: 0x0080, 0x5017: 0x0080,
+	0x5018: 0x0080, 0x5019: 0x0080, 0x501a: 0x0080, 0x501b: 0x0080, 0x501c: 0x0080, 0x501d: 0x0080,
+	0x501e: 0x0080, 0x501f: 0x0080, 0x5020: 0x0080, 0x5021: 0x0080, 0x5022: 0x0080, 0x5023: 0x0080,
+	0x5024: 0x0080, 0x5025: 0x0080, 0x5028: 0x0080, 0x5029: 0x0080,
+	0x502a: 0x0080, 0x502b: 0x0080, 0x502c: 0x0080, 0x502d: 0x0080, 0x502e: 0x0080, 0x502f: 0x0080,
+	0x5030: 0x0080, 0x5031: 0x0080, 0x5032: 0x0080, 0x5033: 0x0080, 0x5034: 0x0080, 0x5035: 0x0080,
+	0x5036: 0x0080, 0x5037: 0x0080, 0x5038: 0x0080, 0x5039: 0x0080, 0x503a: 0x0080, 0x503b: 0x0080,
+	0x503c: 0x0080, 0x503d: 0x0080, 0x503e: 0x0080, 0x503f: 0x0080,
+	// Block 0x141, offset 0x5040
+	0x5040: 0x0080, 0x5041: 0x0080, 0x5042: 0x0080, 0x5043: 0x0080, 0x5044: 0x0080, 0x5045: 0x0080,
+	0x5046: 0x0080, 0x5047: 0x0080, 0x5048: 0x0080, 0x5049: 0x0080, 0x504a: 0x0080, 0x504b: 0x0080,
+	0x504e: 0x0080, 0x504f: 0x0080, 0x5050: 0x0080, 0x5051: 0x0080,
+	0x5052: 0x0080, 0x5053: 0x0080, 0x5054: 0x0080, 0x5055: 0x0080, 0x5056: 0x0080, 0x5057: 0x0080,
+	0x5058: 0x0080, 0x5059: 0x0080, 0x505a: 0x0080, 0x505b: 0x0080, 0x505c: 0x0080, 0x505d: 0x0080,
+	0x505e: 0x0080, 0x505f: 0x0080, 0x5060: 0x0080, 0x5061: 0x0080, 0x5062: 0x0080, 0x5063: 0x0080,
+	0x5064: 0x0080, 0x5065: 0x0080, 0x5066: 0x0080, 0x5067: 0x0080, 0x5068: 0x0080, 0x5069: 0x0080,
+	0x506a: 0x0080, 0x506b: 0x0080, 0x506c: 0x0080, 0x506d: 0x0080, 0x506e: 0x0080, 0x506f: 0x0080,
+	0x5070: 0x0080, 0x5071: 0x0080, 0x5072: 0x0080, 0x5073: 0x0080, 0x5074: 0x0080, 0x5075: 0x0080,
+	0x5076: 0x0080, 0x5077: 0x0080, 0x5078: 0x0080, 0x5079: 0x0080, 0x507a: 0x0080, 0x507b: 0x0080,
+	0x507c: 0x0080, 0x507d: 0x0080, 0x507e: 0x0080, 0x507f: 0x0080,
+	// Block 0x142, offset 0x5080
+	0x5080: 0x00c3, 0x5081: 0x00c3, 0x5082: 0x00c3, 0x5083: 0x00c3, 0x5084: 0x00c3, 0x5085: 0x00c3,
+	0x5086: 0x00c3, 0x5087: 0x00c3, 0x5088: 0x00c3, 0x5089: 0x00c3, 0x508a: 0x00c3, 0x508b: 0x00c3,
+	0x508c: 0x00c3, 0x508d: 0x00c3, 0x508e: 0x00c3, 0x508f: 0x00c3, 0x5090: 0x00c3, 0x5091: 0x00c3,
+	0x5092: 0x00c3, 0x5093: 0x00c3, 0x5094: 0x00c3, 0x5095: 0x00c3, 0x5096: 0x00c3, 0x5097: 0x00c3,
+	0x5098: 0x00c3, 0x5099: 0x00c3, 0x509a: 0x00c3, 0x509b: 0x00c3, 0x509c: 0x00c3, 0x509d: 0x00c3,
+	0x509e: 0x00c3, 0x509f: 0x00c3, 0x50a0: 0x00c3, 0x50a1: 0x00c3, 0x50a2: 0x00c3, 0x50a3: 0x00c3,
+	0x50a4: 0x00c3, 0x50a5: 0x00c3, 0x50a6: 0x00c3, 0x50a7: 0x00c3, 0x50a8: 0x00c3, 0x50a9: 0x00c3,
+	0x50aa: 0x00c3, 0x50ab: 0x00c3, 0x50ac: 0x00c3, 0x50ad: 0x00c3, 0x50ae: 0x00c3, 0x50af: 0x00c3,
+	0x50b0: 0x00c3, 0x50b1: 0x00c3, 0x50b2: 0x00c3, 0x50b3: 0x00c3, 0x50b4: 0x00c3, 0x50b5: 0x00c3,
+	0x50b6: 0x00c3, 0x50b7: 0x0080, 0x50b8: 0x0080, 0x50b9: 0x0080, 0x50ba: 0x0080, 0x50bb: 0x00c3,
+	0x50bc: 0x00c3, 0x50bd: 0x00c3, 0x50be: 0x00c3, 0x50bf: 0x00c3,
+	// Block 0x143, offset 0x50c0
+	0x50c0: 0x00c3, 0x50c1: 0x00c3, 0x50c2: 0x00c3, 0x50c3: 0x00c3, 0x50c4: 0x00c3, 0x50c5: 0x00c3,
+	0x50c6: 0x00c3, 0x50c7: 0x00c3, 0x50c8: 0x00c3, 0x50c9: 0x00c3, 0x50ca: 0x00c3, 0x50cb: 0x00c3,
+	0x50cc: 0x00c3, 0x50cd: 0x00c3, 0x50ce: 0x00c3, 0x50cf: 0x00c3, 0x50d0: 0x00c3, 0x50d1: 0x00c3,
+	0x50d2: 0x00c3, 0x50d3: 0x00c3, 0x50d4: 0x00c3, 0x50d5: 0x00c3, 0x50d6: 0x00c3, 0x50d7: 0x00c3,
+	0x50d8: 0x00c3, 0x50d9: 0x00c3, 0x50da: 0x00c3, 0x50db: 0x00c3, 0x50dc: 0x00c3, 0x50dd: 0x00c3,
+	0x50de: 0x00c3, 0x50df: 0x00c3, 0x50e0: 0x00c3, 0x50e1: 0x00c3, 0x50e2: 0x00c3, 0x50e3: 0x00c3,
+	0x50e4: 0x00c3, 0x50e5: 0x00c3, 0x50e6: 0x00c3, 0x50e7: 0x00c3, 0x50e8: 0x00c3, 0x50e9: 0x00c3,
+	0x50ea: 0x00c3, 0x50eb: 0x00c3, 0x50ec: 0x00c3, 0x50ed: 0x0080, 0x50ee: 0x0080, 0x50ef: 0x0080,
+	0x50f0: 0x0080, 0x50f1: 0x0080, 0x50f2: 0x0080, 0x50f3: 0x0080, 0x50f4: 0x0080, 0x50f5: 0x00c3,
+	0x50f6: 0x0080, 0x50f7: 0x0080, 0x50f8: 0x0080, 0x50f9: 0x0080, 0x50fa: 0x0080, 0x50fb: 0x0080,
+	0x50fc: 0x0080, 0x50fd: 0x0080, 0x50fe: 0x0080, 0x50ff: 0x0080,
+	// Block 0x144, offset 0x5100
+	0x5100: 0x0080, 0x5101: 0x0080, 0x5102: 0x0080, 0x5103: 0x0080, 0x5104: 0x00c3, 0x5105: 0x0080,
+	0x5106: 0x0080, 0x5107: 0x0080, 0x5108: 0x0080, 0x5109: 0x0080, 0x510a: 0x0080, 0x510b: 0x0080,
+	0x511b: 0x00c3, 0x511c: 0x00c3, 0x511d: 0x00c3,
+	0x511e: 0x00c3, 0x511f: 0x00c3, 0x5121: 0x00c3, 0x5122: 0x00c3, 0x5123: 0x00c3,
+	0x5124: 0x00c3, 0x5125: 0x00c3, 0x5126: 0x00c3, 0x5127: 0x00c3, 0x5128: 0x00c3, 0x5129: 0x00c3,
+	0x512a: 0x00c3, 0x512b: 0x00c3, 0x512c: 0x00c3, 0x512d: 0x00c3, 0x512e: 0x00c3, 0x512f: 0x00c3,
+	// Block 0x145, offset 0x5140
+	0x5140: 0x00c0, 0x5141: 0x00c0, 0x5142: 0x00c0, 0x5143: 0x00c0, 0x5144: 0x00c0, 0x5145: 0x00c0,
+	0x5146: 0x00c0, 0x5147: 0x00c0, 0x5148: 0x00c0, 0x5149: 0x00c0, 0x514a: 0x00c0, 0x514b: 0x00c0,
+	0x514c: 0x00c0, 0x514d: 0x00c0, 0x514e: 0x00c0, 0x514f: 0x00c0, 0x5150: 0x00c0, 0x5151: 0x00c0,
+	0x5152: 0x00c0, 0x5153: 0x00c0, 0x5154: 0x00c0, 0x5155: 0x00c0, 0x5156: 0x00c0, 0x5157: 0x00c0,
+	0x5158: 0x00c0, 0x5159: 0x00c0, 0x515a: 0x00c0, 0x515b: 0x00c0, 0x515c: 0x00c0, 0x515d: 0x00c0,
+	0x515e: 0x00c0,
+	0x5165: 0x00c0, 0x5166: 0x00c0, 0x5167: 0x00c0, 0x5168: 0x00c0, 0x5169: 0x00c0,
+	0x516a: 0x00c0,
+	// Block 0x146, offset 0x5180
+	0x5180: 0x00c3, 0x5181: 0x00c3, 0x5182: 0x00c3, 0x5183: 0x00c3, 0x5184: 0x00c3, 0x5185: 0x00c3,
+	0x5186: 0x00c3, 0x5188: 0x00c3, 0x5189: 0x00c3, 0x518a: 0x00c3, 0x518b: 0x00c3,
+	0x518c: 0x00c3, 0x518d: 0x00c3, 0x518e: 0x00c3, 0x518f: 0x00c3, 0x5190: 0x00c3, 0x5191: 0x00c3,
+	0x5192: 0x00c3, 0x5193: 0x00c3, 0x5194: 0x00c3, 0x5195: 0x00c3, 0x5196: 0x00c3, 0x5197: 0x00c3,
+	0x5198: 0x00c3, 0x519b: 0x00c3, 0x519c: 0x00c3, 0x519d: 0x00c3,
+	0x519e: 0x00c3, 0x519f: 0x00c3, 0x51a0: 0x00c3, 0x51a1: 0x00c3, 0x51a3: 0x00c3,
+	0x51a4: 0x00c3, 0x51a6: 0x00c3, 0x51a7: 0x00c3, 0x51a8: 0x00c3, 0x51a9: 0x00c3,
+	0x51aa: 0x00c3,
+	0x51b0: 0x0080, 0x51b1: 0x0080, 0x51b2: 0x0080, 0x51b3: 0x0080, 0x51b4: 0x0080, 0x51b5: 0x0080,
+	0x51b6: 0x0080, 0x51b7: 0x0080, 0x51b8: 0x0080, 0x51b9: 0x0080, 0x51ba: 0x0080, 0x51bb: 0x0080,
+	0x51bc: 0x0080, 0x51bd: 0x0080, 0x51be: 0x0080, 0x51bf: 0x0080,
+	// Block 0x147, offset 0x51c0
+	0x51c0: 0x0080, 0x51c1: 0x0080, 0x51c2: 0x0080, 0x51c3: 0x0080, 0x51c4: 0x0080, 0x51c5: 0x0080,
+	0x51c6: 0x0080, 0x51c7: 0x0080, 0x51c8: 0x0080, 0x51c9: 0x0080, 0x51ca: 0x0080, 0x51cb: 0x0080,
+	0x51cc: 0x0080, 0x51cd: 0x0080, 0x51ce: 0x0080, 0x51cf: 0x0080, 0x51d0: 0x0080, 0x51d1: 0x0080,
+	0x51d2: 0x0080, 0x51d3: 0x0080, 0x51d4: 0x0080, 0x51d5: 0x0080, 0x51d6: 0x0080, 0x51d7: 0x0080,
+	0x51d8: 0x0080, 0x51d9: 0x0080, 0x51da: 0x0080, 0x51db: 0x0080, 0x51dc: 0x0080, 0x51dd: 0x0080,
+	0x51de: 0x0080, 0x51df: 0x0080, 0x51e0: 0x0080, 0x51e1: 0x0080, 0x51e2: 0x0080, 0x51e3: 0x0080,
+	0x51e4: 0x0080, 0x51e5: 0x0080, 0x51e6: 0x0080, 0x51e7: 0x0080, 0x51e8: 0x0080, 0x51e9: 0x0080,
+	0x51ea: 0x0080, 0x51eb: 0x0080, 0x51ec: 0x0080, 0x51ed: 0x0080,
+	// Block 0x148, offset 0x5200
+	0x520f: 0x00c3,
+	// Block 0x149, offset 0x5240
+	0x5240: 0x00c0, 0x5241: 0x00c0, 0x5242: 0x00c0, 0x5243: 0x00c0, 0x5244: 0x00c0, 0x5245: 0x00c0,
+	0x5246: 0x00c0, 0x5247: 0x00c0, 0x5248: 0x00c0, 0x5249: 0x00c0, 0x524a: 0x00c0, 0x524b: 0x00c0,
+	0x524c: 0x00c0, 0x524d: 0x00c0, 0x524e: 0x00c0, 0x524f: 0x00c0, 0x5250: 0x00c0, 0x5251: 0x00c0,
+	0x5252: 0x00c0, 0x5253: 0x00c0, 0x5254: 0x00c0, 0x5255: 0x00c0, 0x5256: 0x00c0, 0x5257: 0x00c0,
+	0x5258: 0x00c0, 0x5259: 0x00c0, 0x525a: 0x00c0, 0x525b: 0x00c0, 0x525c: 0x00c0, 0x525d: 0x00c0,
+	0x525e: 0x00c0, 0x525f: 0x00c0, 0x5260: 0x00c0, 0x5261: 0x00c0, 0x5262: 0x00c0, 0x5263: 0x00c0,
+	0x5264: 0x00c0, 0x5265: 0x00c0, 0x5266: 0x00c0, 0x5267: 0x00c0, 0x5268: 0x00c0, 0x5269: 0x00c0,
+	0x526a: 0x00c0, 0x526b: 0x00c0, 0x526c: 0x00c0,
+	0x5270: 0x00c3, 0x5271: 0x00c3, 0x5272: 0x00c3, 0x5273: 0x00c3, 0x5274: 0x00c3, 0x5275: 0x00c3,
+	0x5276: 0x00c3, 0x5277: 0x00c0, 0x5278: 0x00c0, 0x5279: 0x00c0, 0x527a: 0x00c0, 0x527b: 0x00c0,
+	0x527c: 0x00c0, 0x527d: 0x00c0,
+	// Block 0x14a, offset 0x5280
+	0x5280: 0x00c0, 0x5281: 0x00c0, 0x5282: 0x00c0, 0x5283: 0x00c0, 0x5284: 0x00c0, 0x5285: 0x00c0,
+	0x5286: 0x00c0, 0x5287: 0x00c0, 0x5288: 0x00c0, 0x5289: 0x00c0,
+	0x528e: 0x00c0, 0x528f: 0x0080,
+	// Block 0x14b, offset 0x52c0
+	0x52d0: 0x00c0, 0x52d1: 0x00c0,
+	0x52d2: 0x00c0, 0x52d3: 0x00c0, 0x52d4: 0x00c0, 0x52d5: 0x00c0, 0x52d6: 0x00c0, 0x52d7: 0x00c0,
+	0x52d8: 0x00c0, 0x52d9: 0x00c0, 0x52da: 0x00c0, 0x52db: 0x00c0, 0x52dc: 0x00c0, 0x52dd: 0x00c0,
+	0x52de: 0x00c0, 0x52df: 0x00c0, 0x52e0: 0x00c0, 0x52e1: 0x00c0, 0x52e2: 0x00c0, 0x52e3: 0x00c0,
+	0x52e4: 0x00c0, 0x52e5: 0x00c0, 0x52e6: 0x00c0, 0x52e7: 0x00c0, 0x52e8: 0x00c0, 0x52e9: 0x00c0,
+	0x52ea: 0x00c0, 0x52eb: 0x00c0, 0x52ec: 0x00c0, 0x52ed: 0x00c0, 0x52ee: 0x00c3,
+	// Block 0x14c, offset 0x5300
+	0x5300: 0x00c0, 0x5301: 0x00c0, 0x5302: 0x00c0, 0x5303: 0x00c0, 0x5304: 0x00c0, 0x5305: 0x00c0,
+	0x5306: 0x00c0, 0x5307: 0x00c0, 0x5308: 0x00c0, 0x5309: 0x00c0, 0x530a: 0x00c0, 0x530b: 0x00c0,
+	0x530c: 0x00c0, 0x530d: 0x00c0, 0x530e: 0x00c0, 0x530f: 0x00c0, 0x5310: 0x00c0, 0x5311: 0x00c0,
+	0x5312: 0x00c0, 0x5313: 0x00c0, 0x5314: 0x00c0, 0x5315: 0x00c0, 0x5316: 0x00c0, 0x5317: 0x00c0,
+	0x5318: 0x00c0, 0x5319: 0x00c0, 0x531a: 0x00c0, 0x531b: 0x00c0, 0x531c: 0x00c0, 0x531d: 0x00c0,
+	0x531e: 0x00c0, 0x531f: 0x00c0, 0x5320: 0x00c0, 0x5321: 0x00c0, 0x5322: 0x00c0, 0x5323: 0x00c0,
+	0x5324: 0x00c0, 0x5325: 0x00c0, 0x5326: 0x00c0, 0x5327: 0x00c0, 0x5328: 0x00c0, 0x5329: 0x00c0,
+	0x532a: 0x00c0, 0x532b: 0x00c0, 0x532c: 0x00c3, 0x532d: 0x00c3, 0x532e: 0x00c3, 0x532f: 0x00c3,
+	0x5330: 0x00c0, 0x5331: 0x00c0, 0x5332: 0x00c0, 0x5333: 0x00c0, 0x5334: 0x00c0, 0x5335: 0x00c0,
+	0x5336: 0x00c0, 0x5337: 0x00c0, 0x5338: 0x00c0, 0x5339: 0x00c0,
+	0x533f: 0x0080,
+	// Block 0x14d, offset 0x5340
+	0x5350: 0x00c0, 0x5351: 0x00c0,
+	0x5352: 0x00c0, 0x5353: 0x00c0, 0x5354: 0x00c0, 0x5355: 0x00c0, 0x5356: 0x00c0, 0x5357: 0x00c0,
+	0x5358: 0x00c0, 0x5359: 0x00c0, 0x535a: 0x00c0, 0x535b: 0x00c0, 0x535c: 0x00c0, 0x535d: 0x00c0,
+	0x535e: 0x00c0, 0x535f: 0x00c0, 0x5360: 0x00c0, 0x5361: 0x00c0, 0x5362: 0x00c0, 0x5363: 0x00c0,
+	0x5364: 0x00c0, 0x5365: 0x00c0, 0x5366: 0x00c0, 0x5367: 0x00c0, 0x5368: 0x00c0, 0x5369: 0x00c0,
+	0x536a: 0x00c0, 0x536b: 0x00c0, 0x536c: 0x00c3, 0x536d: 0x00c3, 0x536e: 0x00c3, 0x536f: 0x00c3,
+	0x5370: 0x00c0, 0x5371: 0x00c0, 0x5372: 0x00c0, 0x5373: 0x00c0, 0x5374: 0x00c0, 0x5375: 0x00c0,
+	0x5376: 0x00c0, 0x5377: 0x00c0, 0x5378: 0x00c0, 0x5379: 0x00c0,
+	// Block 0x14e, offset 0x5380
+	0x53a0: 0x00c0, 0x53a1: 0x00c0, 0x53a2: 0x00c0, 0x53a3: 0x00c0,
+	0x53a4: 0x00c0, 0x53a5: 0x00c0, 0x53a6: 0x00c0, 0x53a8: 0x00c0, 0x53a9: 0x00c0,
+	0x53aa: 0x00c0, 0x53ab: 0x00c0, 0x53ad: 0x00c0, 0x53ae: 0x00c0,
+	0x53b0: 0x00c0, 0x53b1: 0x00c0, 0x53b2: 0x00c0, 0x53b3: 0x00c0, 0x53b4: 0x00c0, 0x53b5: 0x00c0,
+	0x53b6: 0x00c0, 0x53b7: 0x00c0, 0x53b8: 0x00c0, 0x53b9: 0x00c0, 0x53ba: 0x00c0, 0x53bb: 0x00c0,
+	0x53bc: 0x00c0, 0x53bd: 0x00c0, 0x53be: 0x00c0,
+	// Block 0x14f, offset 0x53c0
+	0x53c0: 0x00c0, 0x53c1: 0x00c0, 0x53c2: 0x00c0, 0x53c3: 0x00c0, 0x53c4: 0x00c0,
+	0x53c7: 0x0080, 0x53c8: 0x0080, 0x53c9: 0x0080, 0x53ca: 0x0080, 0x53cb: 0x0080,
+	0x53cc: 0x0080, 0x53cd: 0x0080, 0x53ce: 0x0080, 0x53cf: 0x0080, 0x53d0: 0x00c3, 0x53d1: 0x00c3,
+	0x53d2: 0x00c3, 0x53d3: 0x00c3, 0x53d4: 0x00c3, 0x53d5: 0x00c3, 0x53d6: 0x00c3,
+	// Block 0x150, offset 0x5400
+	0x5400: 0x00c2, 0x5401: 0x00c2, 0x5402: 0x00c2, 0x5403: 0x00c2, 0x5404: 0x00c2, 0x5405: 0x00c2,
+	0x5406: 0x00c2, 0x5407: 0x00c2, 0x5408: 0x00c2, 0x5409: 0x00c2, 0x540a: 0x00c2, 0x540b: 0x00c2,
+	0x540c: 0x00c2, 0x540d: 0x00c2, 0x540e: 0x00c2, 0x540f: 0x00c2, 0x5410: 0x00c2, 0x5411: 0x00c2,
+	0x5412: 0x00c2, 0x5413: 0x00c2, 0x5414: 0x00c2, 0x5415: 0x00c2, 0x5416: 0x00c2, 0x5417: 0x00c2,
+	0x5418: 0x00c2, 0x5419: 0x00c2, 0x541a: 0x00c2, 0x541b: 0x00c2, 0x541c: 0x00c2, 0x541d: 0x00c2,
+	0x541e: 0x00c2, 0x541f: 0x00c2, 0x5420: 0x00c2, 0x5421: 0x00c2, 0x5422: 0x00c2, 0x5423: 0x00c2,
+	0x5424: 0x00c2, 0x5425: 0x00c2, 0x5426: 0x00c2, 0x5427: 0x00c2, 0x5428: 0x00c2, 0x5429: 0x00c2,
+	0x542a: 0x00c2, 0x542b: 0x00c2, 0x542c: 0x00c2, 0x542d: 0x00c2, 0x542e: 0x00c2, 0x542f: 0x00c2,
+	0x5430: 0x00c2, 0x5431: 0x00c2, 0x5432: 0x00c2, 0x5433: 0x00c2, 0x5434: 0x00c2, 0x5435: 0x00c2,
+	0x5436: 0x00c2, 0x5437: 0x00c2, 0x5438: 0x00c2, 0x5439: 0x00c2, 0x543a: 0x00c2, 0x543b: 0x00c2,
+	0x543c: 0x00c2, 0x543d: 0x00c2, 0x543e: 0x00c2, 0x543f: 0x00c2,
+	// Block 0x151, offset 0x5440
+	0x5440: 0x00c2, 0x5441: 0x00c2, 0x5442: 0x00c2, 0x5443: 0x00c2, 0x5444: 0x00c3, 0x5445: 0x00c3,
+	0x5446: 0x00c3, 0x5447: 0x00c3, 0x5448: 0x00c3, 0x5449: 0x00c3, 0x544a: 0x00c3, 0x544b: 0x00c3,
+	0x5450: 0x00c0, 0x5451: 0x00c0,
+	0x5452: 0x00c0, 0x5453: 0x00c0, 0x5454: 0x00c0, 0x5455: 0x00c0, 0x5456: 0x00c0, 0x5457: 0x00c0,
+	0x5458: 0x00c0, 0x5459: 0x00c0,
+	0x545e: 0x0080, 0x545f: 0x0080,
+	// Block 0x152, offset 0x5480
+	0x54b1: 0x0080, 0x54b2: 0x0080, 0x54b3: 0x0080, 0x54b4: 0x0080, 0x54b5: 0x0080,
+	0x54b6: 0x0080, 0x54b7: 0x0080, 0x54b8: 0x0080, 0x54b9: 0x0080, 0x54ba: 0x0080, 0x54bb: 0x0080,
+	0x54bc: 0x0080, 0x54bd: 0x0080, 0x54be: 0x0080, 0x54bf: 0x0080,
+	// Block 0x153, offset 0x54c0
+	0x54c0: 0x0080, 0x54c1: 0x0080, 0x54c2: 0x0080, 0x54c3: 0x0080, 0x54c4: 0x0080, 0x54c5: 0x0080,
+	0x54c6: 0x0080, 0x54c7: 0x0080, 0x54c8: 0x0080, 0x54c9: 0x0080, 0x54ca: 0x0080, 0x54cb: 0x0080,
+	0x54cc: 0x0080, 0x54cd: 0x0080, 0x54ce: 0x0080, 0x54cf: 0x0080, 0x54d0: 0x0080, 0x54d1: 0x0080,
+	0x54d2: 0x0080, 0x54d3: 0x0080, 0x54d4: 0x0080, 0x54d5: 0x0080, 0x54d6: 0x0080, 0x54d7: 0x0080,
+	0x54d8: 0x0080, 0x54d9: 0x0080, 0x54da: 0x0080, 0x54db: 0x0080, 0x54dc: 0x0080, 0x54dd: 0x0080,
+	0x54de: 0x0080, 0x54df: 0x0080, 0x54e0: 0x0080, 0x54e1: 0x0080, 0x54e2: 0x0080, 0x54e3: 0x0080,
+	0x54e4: 0x0080, 0x54e5: 0x0080, 0x54e6: 0x0080, 0x54e7: 0x0080, 0x54e8: 0x0080, 0x54e9: 0x0080,
+	0x54ea: 0x0080, 0x54eb: 0x0080, 0x54ec: 0x0080, 0x54ed: 0x0080, 0x54ee: 0x0080, 0x54ef: 0x0080,
+	0x54f0: 0x0080, 0x54f1: 0x0080, 0x54f2: 0x0080, 0x54f3: 0x0080, 0x54f4: 0x0080,
+	// Block 0x154, offset 0x5500
+	0x5501: 0x0080, 0x5502: 0x0080, 0x5503: 0x0080, 0x5504: 0x0080, 0x5505: 0x0080,
+	0x5506: 0x0080, 0x5507: 0x0080, 0x5508: 0x0080, 0x5509: 0x0080, 0x550a: 0x0080, 0x550b: 0x0080,
+	0x550c: 0x0080, 0x550d: 0x0080, 0x550e: 0x0080, 0x550f: 0x0080, 0x5510: 0x0080, 0x5511: 0x0080,
+	0x5512: 0x0080, 0x5513: 0x0080, 0x5514: 0x0080, 0x5515: 0x0080, 0x5516: 0x0080, 0x5517: 0x0080,
+	0x5518: 0x0080, 0x5519: 0x0080, 0x551a: 0x0080, 0x551b: 0x0080, 0x551c: 0x0080, 0x551d: 0x0080,
+	0x551e: 0x0080, 0x551f: 0x0080, 0x5520: 0x0080, 0x5521: 0x0080, 0x5522: 0x0080, 0x5523: 0x0080,
+	0x5524: 0x0080, 0x5525: 0x0080, 0x5526: 0x0080, 0x5527: 0x0080, 0x5528: 0x0080, 0x5529: 0x0080,
+	0x552a: 0x0080, 0x552b: 0x0080, 0x552c: 0x0080, 0x552d: 0x0080, 0x552e: 0x0080, 0x552f: 0x0080,
+	0x5530: 0x0080, 0x5531: 0x0080, 0x5532: 0x0080, 0x5533: 0x0080, 0x5534: 0x0080, 0x5535: 0x0080,
+	0x5536: 0x0080, 0x5537: 0x0080, 0x5538: 0x0080, 0x5539: 0x0080, 0x553a: 0x0080, 0x553b: 0x0080,
+	0x553c: 0x0080, 0x553d: 0x0080,
+	// Block 0x155, offset 0x5540
+	0x5540: 0x0080, 0x5541: 0x0080, 0x5542: 0x0080, 0x5543: 0x0080, 0x5545: 0x0080,
+	0x5546: 0x0080, 0x5547: 0x0080, 0x5548: 0x0080, 0x5549: 0x0080, 0x554a: 0x0080, 0x554b: 0x0080,
+	0x554c: 0x0080, 0x554d: 0x0080, 0x554e: 0x0080, 0x554f: 0x0080, 0x5550: 0x0080, 0x5551: 0x0080,
+	0x5552: 0x0080, 0x5553: 0x0080, 0x5554: 0x0080, 0x5555: 0x0080, 0x5556: 0x0080, 0x5557: 0x0080,
+	0x5558: 0x0080, 0x5559: 0x0080, 0x555a: 0x0080, 0x555b: 0x0080, 0x555c: 0x0080, 0x555d: 0x0080,
+	0x555e: 0x0080, 0x555f: 0x0080, 0x5561: 0x0080, 0x5562: 0x0080,
+	0x5564: 0x0080, 0x5567: 0x0080, 0x5569: 0x0080,
+	0x556a: 0x0080, 0x556b: 0x0080, 0x556c: 0x0080, 0x556d: 0x0080, 0x556e: 0x0080, 0x556f: 0x0080,
+	0x5570: 0x0080, 0x5571: 0x0080, 0x5572: 0x0080, 0x5574: 0x0080, 0x5575: 0x0080,
+	0x5576: 0x0080, 0x5577: 0x0080, 0x5579: 0x0080, 0x557b: 0x0080,
+	// Block 0x156, offset 0x5580
+	0x5582: 0x0080,
+	0x5587: 0x0080, 0x5589: 0x0080, 0x558b: 0x0080,
+	0x558d: 0x0080, 0x558e: 0x0080, 0x558f: 0x0080, 0x5591: 0x0080,
+	0x5592: 0x0080, 0x5594: 0x0080, 0x5597: 0x0080,
+	0x5599: 0x0080, 0x559b: 0x0080, 0x559d: 0x0080,
+	0x559f: 0x0080, 0x55a1: 0x0080, 0x55a2: 0x0080,
+	0x55a4: 0x0080, 0x55a7: 0x0080, 0x55a8: 0x0080, 0x55a9: 0x0080,
+	0x55aa: 0x0080, 0x55ac: 0x0080, 0x55ad: 0x0080, 0x55ae: 0x0080, 0x55af: 0x0080,
+	0x55b0: 0x0080, 0x55b1: 0x0080, 0x55b2: 0x0080, 0x55b4: 0x0080, 0x55b5: 0x0080,
+	0x55b6: 0x0080, 0x55b7: 0x0080, 0x55b9: 0x0080, 0x55ba: 0x0080, 0x55bb: 0x0080,
+	0x55bc: 0x0080, 0x55be: 0x0080,
+	// Block 0x157, offset 0x55c0
+	0x55c0: 0x0080, 0x55c1: 0x0080, 0x55c2: 0x0080, 0x55c3: 0x0080, 0x55c4: 0x0080, 0x55c5: 0x0080,
+	0x55c6: 0x0080, 0x55c7: 0x0080, 0x55c8: 0x0080, 0x55c9: 0x0080, 0x55cb: 0x0080,
+	0x55cc: 0x0080, 0x55cd: 0x0080, 0x55ce: 0x0080, 0x55cf: 0x0080, 0x55d0: 0x0080, 0x55d1: 0x0080,
+	0x55d2: 0x0080, 0x55d3: 0x0080, 0x55d4: 0x0080, 0x55d5: 0x0080, 0x55d6: 0x0080, 0x55d7: 0x0080,
+	0x55d8: 0x0080, 0x55d9: 0x0080, 0x55da: 0x0080, 0x55db: 0x0080,
+	0x55e1: 0x0080, 0x55e2: 0x0080, 0x55e3: 0x0080,
+	0x55e5: 0x0080, 0x55e6: 0x0080, 0x55e7: 0x0080, 0x55e8: 0x0080, 0x55e9: 0x0080,
+	0x55eb: 0x0080, 0x55ec: 0x0080, 0x55ed: 0x0080, 0x55ee: 0x0080, 0x55ef: 0x0080,
+	0x55f0: 0x0080, 0x55f1: 0x0080, 0x55f2: 0x0080, 0x55f3: 0x0080, 0x55f4: 0x0080, 0x55f5: 0x0080,
+	0x55f6: 0x0080, 0x55f7: 0x0080, 0x55f8: 0x0080, 0x55f9: 0x0080, 0x55fa: 0x0080, 0x55fb: 0x0080,
+	// Block 0x158, offset 0x5600
+	0x5630: 0x0080, 0x5631: 0x0080,
+	// Block 0x159, offset 0x5640
+	0x5640: 0x0080, 0x5641: 0x0080, 0x5642: 0x0080, 0x5643: 0x0080, 0x5644: 0x0080, 0x5645: 0x0080,
+	0x5646: 0x0080, 0x5647: 0x0080, 0x5648: 0x0080, 0x5649: 0x0080, 0x564a: 0x0080, 0x564b: 0x0080,
+	0x564c: 0x0080, 0x564d: 0x0080, 0x564e: 0x0080, 0x564f: 0x0080, 0x5650: 0x0080, 0x5651: 0x0080,
+	0x5652: 0x0080, 0x5653: 0x0080, 0x5654: 0x0080, 0x5655: 0x0080, 0x5656: 0x0080, 0x5657: 0x0080,
+	0x5658: 0x0080, 0x5659: 0x0080, 0x565a: 0x0080, 0x565b: 0x0080, 0x565c: 0x0080, 0x565d: 0x0080,
+	0x565e: 0x0080, 0x565f: 0x0080, 0x5660: 0x0080, 0x5661: 0x0080, 0x5662: 0x0080, 0x5663: 0x0080,
+	0x5664: 0x0080, 0x5665: 0x0080, 0x5666: 0x0080, 0x5667: 0x0080, 0x5668: 0x0080, 0x5669: 0x0080,
+	0x566a: 0x0080, 0x566b: 0x0080,
+	0x5670: 0x0080, 0x5671: 0x0080, 0x5672: 0x0080, 0x5673: 0x0080, 0x5674: 0x0080, 0x5675: 0x0080,
+	0x5676: 0x0080, 0x5677: 0x0080, 0x5678: 0x0080, 0x5679: 0x0080, 0x567a: 0x0080, 0x567b: 0x0080,
+	0x567c: 0x0080, 0x567d: 0x0080, 0x567e: 0x0080, 0x567f: 0x0080,
+	// Block 0x15a, offset 0x5680
+	0x5680: 0x0080, 0x5681: 0x0080, 0x5682: 0x0080, 0x5683: 0x0080, 0x5684: 0x0080, 0x5685: 0x0080,
+	0x5686: 0x0080, 0x5687: 0x0080, 0x5688: 0x0080, 0x5689: 0x0080, 0x568a: 0x0080, 0x568b: 0x0080,
+	0x568c: 0x0080, 0x568d: 0x0080, 0x568e: 0x0080, 0x568f: 0x0080, 0x5690: 0x0080, 0x5691: 0x0080,
+	0x5692: 0x0080, 0x5693: 0x0080,
+	0x56a0: 0x0080, 0x56a1: 0x0080, 0x56a2: 0x0080, 0x56a3: 0x0080,
+	0x56a4: 0x0080, 0x56a5: 0x0080, 0x56a6: 0x0080, 0x56a7: 0x0080, 0x56a8: 0x0080, 0x56a9: 0x0080,
+	0x56aa: 0x0080, 0x56ab: 0x0080, 0x56ac: 0x0080, 0x56ad: 0x0080, 0x56ae: 0x0080,
+	0x56b1: 0x0080, 0x56b2: 0x0080, 0x56b3: 0x0080, 0x56b4: 0x0080, 0x56b5: 0x0080,
+	0x56b6: 0x0080, 0x56b7: 0x0080, 0x56b8: 0x0080, 0x56b9: 0x0080, 0x56ba: 0x0080, 0x56bb: 0x0080,
+	0x56bc: 0x0080, 0x56bd: 0x0080, 0x56be: 0x0080, 0x56bf: 0x0080,
+	// Block 0x15b, offset 0x56c0
+	0x56c1: 0x0080, 0x56c2: 0x0080, 0x56c3: 0x0080, 0x56c4: 0x0080, 0x56c5: 0x0080,
+	0x56c6: 0x0080, 0x56c7: 0x0080, 0x56c8: 0x0080, 0x56c9: 0x0080, 0x56ca: 0x0080, 0x56cb: 0x0080,
+	0x56cc: 0x0080, 0x56cd: 0x0080, 0x56ce: 0x0080, 0x56cf: 0x0080, 0x56d1: 0x0080,
+	0x56d2: 0x0080, 0x56d3: 0x0080, 0x56d4: 0x0080, 0x56d5: 0x0080, 0x56d6: 0x0080, 0x56d7: 0x0080,
+	0x56d8: 0x0080, 0x56d9: 0x0080, 0x56da: 0x0080, 0x56db: 0x0080, 0x56dc: 0x0080, 0x56dd: 0x0080,
+	0x56de: 0x0080, 0x56df: 0x0080, 0x56e0: 0x0080, 0x56e1: 0x0080, 0x56e2: 0x0080, 0x56e3: 0x0080,
+	0x56e4: 0x0080, 0x56e5: 0x0080, 0x56e6: 0x0080, 0x56e7: 0x0080, 0x56e8: 0x0080, 0x56e9: 0x0080,
+	0x56ea: 0x0080, 0x56eb: 0x0080, 0x56ec: 0x0080, 0x56ed: 0x0080, 0x56ee: 0x0080, 0x56ef: 0x0080,
+	0x56f0: 0x0080, 0x56f1: 0x0080, 0x56f2: 0x0080, 0x56f3: 0x0080, 0x56f4: 0x0080, 0x56f5: 0x0080,
+	// Block 0x15c, offset 0x5700
+	0x5726: 0x0080, 0x5727: 0x0080, 0x5728: 0x0080, 0x5729: 0x0080,
+	0x572a: 0x0080, 0x572b: 0x0080, 0x572c: 0x0080, 0x572d: 0x0080, 0x572e: 0x0080, 0x572f: 0x0080,
+	0x5730: 0x0080, 0x5731: 0x0080, 0x5732: 0x0080, 0x5733: 0x0080, 0x5734: 0x0080, 0x5735: 0x0080,
+	0x5736: 0x0080, 0x5737: 0x0080, 0x5738: 0x0080, 0x5739: 0x0080, 0x573a: 0x0080, 0x573b: 0x0080,
+	0x573c: 0x0080, 0x573d: 0x0080, 0x573e: 0x0080, 0x573f: 0x0080,
+	// Block 0x15d, offset 0x5740
+	0x5740: 0x008c, 0x5741: 0x0080, 0x5742: 0x0080,
+	0x5750: 0x0080, 0x5751: 0x0080,
+	0x5752: 0x0080, 0x5753: 0x0080, 0x5754: 0x0080, 0x5755: 0x0080, 0x5756: 0x0080, 0x5757: 0x0080,
+	0x5758: 0x0080, 0x5759: 0x0080, 0x575a: 0x0080, 0x575b: 0x0080, 0x575c: 0x0080, 0x575d: 0x0080,
+	0x575e: 0x0080, 0x575f: 0x0080, 0x5760: 0x0080, 0x5761: 0x0080, 0x5762: 0x0080, 0x5763: 0x0080,
+	0x5764: 0x0080, 0x5765: 0x0080, 0x5766: 0x0080, 0x5767: 0x0080, 0x5768: 0x0080, 0x5769: 0x0080,
+	0x576a: 0x0080, 0x576b: 0x0080, 0x576c: 0x0080, 0x576d: 0x0080, 0x576e: 0x0080, 0x576f: 0x0080,
+	0x5770: 0x0080, 0x5771: 0x0080, 0x5772: 0x0080, 0x5773: 0x0080, 0x5774: 0x0080, 0x5775: 0x0080,
+	0x5776: 0x0080, 0x5777: 0x0080, 0x5778: 0x0080, 0x5779: 0x0080, 0x577a: 0x0080, 0x577b: 0x0080,
+	// Block 0x15e, offset 0x5780
+	0x5780: 0x0080, 0x5781: 0x0080, 0x5782: 0x0080, 0x5783: 0x0080, 0x5784: 0x0080, 0x5785: 0x0080,
+	0x5786: 0x0080, 0x5787: 0x0080, 0x5788: 0x0080,
+	0x5790: 0x0080, 0x5791: 0x0080,
+	0x57a0: 0x0080, 0x57a1: 0x0080, 0x57a2: 0x0080, 0x57a3: 0x0080,
+	0x57a4: 0x0080, 0x57a5: 0x0080,
+	// Block 0x15f, offset 0x57c0
+	0x57c0: 0x0080, 0x57c1: 0x0080, 0x57c2: 0x0080, 0x57c3: 0x0080, 0x57c4: 0x0080, 0x57c5: 0x0080,
+	0x57c6: 0x0080, 0x57c7: 0x0080, 0x57c8: 0x0080, 0x57c9: 0x0080, 0x57ca: 0x0080, 0x57cb: 0x0080,
+	0x57cc: 0x0080, 0x57cd: 0x0080, 0x57ce: 0x0080, 0x57cf: 0x0080, 0x57d0: 0x0080, 0x57d1: 0x0080,
+	0x57d2: 0x0080, 0x57d3: 0x0080, 0x57d4: 0x0080, 0x57d5: 0x0080, 0x57d6: 0x0080, 0x57d7: 0x0080,
+	0x57dc: 0x0080, 0x57dd: 0x0080,
+	0x57de: 0x0080, 0x57df: 0x0080, 0x57e0: 0x0080, 0x57e1: 0x0080, 0x57e2: 0x0080, 0x57e3: 0x0080,
+	0x57e4: 0x0080, 0x57e5: 0x0080, 0x57e6: 0x0080, 0x57e7: 0x0080, 0x57e8: 0x0080, 0x57e9: 0x0080,
+	0x57ea: 0x0080, 0x57eb: 0x0080, 0x57ec: 0x0080,
+	0x57f0: 0x0080, 0x57f1: 0x0080, 0x57f2: 0x0080, 0x57f3: 0x0080, 0x57f4: 0x0080, 0x57f5: 0x0080,
+	0x57f6: 0x0080, 0x57f7: 0x0080, 0x57f8: 0x0080, 0x57f9: 0x0080, 0x57fa: 0x0080, 0x57fb: 0x0080,
+	0x57fc: 0x0080,
+	// Block 0x160, offset 0x5800
+	0x5800: 0x0080, 0x5801: 0x0080, 0x5802: 0x0080, 0x5803: 0x0080, 0x5804: 0x0080, 0x5805: 0x0080,
+	0x5806: 0x0080, 0x5807: 0x0080, 0x5808: 0x0080, 0x5809: 0x0080, 0x580a: 0x0080, 0x580b: 0x0080,
+	0x580c: 0x0080, 0x580d: 0x0080, 0x580e: 0x0080, 0x580f: 0x0080, 0x5810: 0x0080, 0x5811: 0x0080,
+	0x5812: 0x0080, 0x5813: 0x0080, 0x5814: 0x0080, 0x5815: 0x0080, 0x5816: 0x0080, 0x5817: 0x0080,
+	0x5818: 0x0080, 0x5819: 0x0080, 0x581a: 0x0080, 0x581b: 0x0080, 0x581c: 0x0080, 0x581d: 0x0080,
+	0x581e: 0x0080, 0x581f: 0x0080, 0x5820: 0x0080, 0x5821: 0x0080, 0x5822: 0x0080, 0x5823: 0x0080,
+	0x5824: 0x0080, 0x5825: 0x0080, 0x5826: 0x0080, 0x5827: 0x0080, 0x5828: 0x0080, 0x5829: 0x0080,
+	0x582a: 0x0080, 0x582b: 0x0080, 0x582c: 0x0080, 0x582d: 0x0080, 0x582e: 0x0080, 0x582f: 0x0080,
+	0x5830: 0x0080, 0x5831: 0x0080, 0x5832: 0x0080, 0x5833: 0x0080, 0x5834: 0x0080, 0x5835: 0x0080,
+	0x5836: 0x0080, 0x583b: 0x0080,
+	0x583c: 0x0080, 0x583d: 0x0080, 0x583e: 0x0080, 0x583f: 0x0080,
+	// Block 0x161, offset 0x5840
+	0x5840: 0x0080, 0x5841: 0x0080, 0x5842: 0x0080, 0x5843: 0x0080, 0x5844: 0x0080, 0x5845: 0x0080,
+	0x5846: 0x0080, 0x5847: 0x0080, 0x5848: 0x0080, 0x5849: 0x0080, 0x584a: 0x0080, 0x584b: 0x0080,
+	0x584c: 0x0080, 0x584d: 0x0080, 0x584e: 0x0080, 0x584f: 0x0080, 0x5850: 0x0080, 0x5851: 0x0080,
+	0x5852: 0x0080, 0x5853: 0x0080, 0x5854: 0x0080, 0x5855: 0x0080, 0x5856: 0x0080, 0x5857: 0x0080,
+	0x5858: 0x0080, 0x5859: 0x0080,
+	0x5860: 0x0080, 0x5861: 0x0080, 0x5862: 0x0080, 0x5863: 0x0080,
+	0x5864: 0x0080, 0x5865: 0x0080, 0x5866: 0x0080, 0x5867: 0x0080, 0x5868: 0x0080, 0x5869: 0x0080,
+	0x586a: 0x0080, 0x586b: 0x0080,
+	0x5870: 0x0080,
+	// Block 0x162, offset 0x5880
+	0x5880: 0x0080, 0x5881: 0x0080, 0x5882: 0x0080, 0x5883: 0x0080, 0x5884: 0x0080, 0x5885: 0x0080,
+	0x5886: 0x0080, 0x5887: 0x0080, 0x5888: 0x0080, 0x5889: 0x0080, 0x588a: 0x0080, 0x588b: 0x0080,
+	0x5890: 0x0080, 0x5891: 0x0080,
+	0x5892: 0x0080, 0x5893: 0x0080, 0x5894: 0x0080, 0x5895: 0x0080, 0x5896: 0x0080, 0x5897: 0x0080,
+	0x5898: 0x0080, 0x5899: 0x0080, 0x589a: 0x0080, 0x589b: 0x0080, 0x589c: 0x0080, 0x589d: 0x0080,
+	0x589e: 0x0080, 0x589f: 0x0080, 0x58a0: 0x0080, 0x58a1: 0x0080, 0x58a2: 0x0080, 0x58a3: 0x0080,
+	0x58a4: 0x0080, 0x58a5: 0x0080, 0x58a6: 0x0080, 0x58a7: 0x0080, 0x58a8: 0x0080, 0x58a9: 0x0080,
+	0x58aa: 0x0080, 0x58ab: 0x0080, 0x58ac: 0x0080, 0x58ad: 0x0080, 0x58ae: 0x0080, 0x58af: 0x0080,
+	0x58b0: 0x0080, 0x58b1: 0x0080, 0x58b2: 0x0080, 0x58b3: 0x0080, 0x58b4: 0x0080, 0x58b5: 0x0080,
+	0x58b6: 0x0080, 0x58b7: 0x0080, 0x58b8: 0x0080, 0x58b9: 0x0080, 0x58ba: 0x0080, 0x58bb: 0x0080,
+	0x58bc: 0x0080, 0x58bd: 0x0080, 0x58be: 0x0080, 0x58bf: 0x0080,
+	// Block 0x163, offset 0x58c0
+	0x58c0: 0x0080, 0x58c1: 0x0080, 0x58c2: 0x0080, 0x58c3: 0x0080, 0x58c4: 0x0080, 0x58c5: 0x0080,
+	0x58c6: 0x0080, 0x58c7: 0x0080,
+	0x58d0: 0x0080, 0x58d1: 0x0080,
+	0x58d2: 0x0080, 0x58d3: 0x0080, 0x58d4: 0x0080, 0x58d5: 0x0080, 0x58d6: 0x0080, 0x58d7: 0x0080,
+	0x58d8: 0x0080, 0x58d9: 0x0080,
+	0x58e0: 0x0080, 0x58e1: 0x0080, 0x58e2: 0x0080, 0x58e3: 0x0080,
+	0x58e4: 0x0080, 0x58e5: 0x0080, 0x58e6: 0x0080, 0x58e7: 0x0080, 0x58e8: 0x0080, 0x58e9: 0x0080,
+	0x58ea: 0x0080, 0x58eb: 0x0080, 0x58ec: 0x0080, 0x58ed: 0x0080, 0x58ee: 0x0080, 0x58ef: 0x0080,
+	0x58f0: 0x0080, 0x58f1: 0x0080, 0x58f2: 0x0080, 0x58f3: 0x0080, 0x58f4: 0x0080, 0x58f5: 0x0080,
+	0x58f6: 0x0080, 0x58f7: 0x0080, 0x58f8: 0x0080, 0x58f9: 0x0080, 0x58fa: 0x0080, 0x58fb: 0x0080,
+	0x58fc: 0x0080, 0x58fd: 0x0080, 0x58fe: 0x0080, 0x58ff: 0x0080,
+	// Block 0x164, offset 0x5900
+	0x5900: 0x0080, 0x5901: 0x0080, 0x5902: 0x0080, 0x5903: 0x0080, 0x5904: 0x0080, 0x5905: 0x0080,
+	0x5906: 0x0080, 0x5907: 0x0080,
+	0x5910: 0x0080, 0x5911: 0x0080,
+	0x5912: 0x0080, 0x5913: 0x0080, 0x5914: 0x0080, 0x5915: 0x0080, 0x5916: 0x0080, 0x5917: 0x0080,
+	0x5918: 0x0080, 0x5919: 0x0080, 0x591a: 0x0080, 0x591b: 0x0080, 0x591c: 0x0080, 0x591d: 0x0080,
+	0x591e: 0x0080, 0x591f: 0x0080, 0x5920: 0x0080, 0x5921: 0x0080, 0x5922: 0x0080, 0x5923: 0x0080,
+	0x5924: 0x0080, 0x5925: 0x0080, 0x5926: 0x0080, 0x5927: 0x0080, 0x5928: 0x0080, 0x5929: 0x0080,
+	0x592a: 0x0080, 0x592b: 0x0080, 0x592c: 0x0080, 0x592d: 0x0080,
+	0x5930: 0x0080, 0x5931: 0x0080,
+	// Block 0x165, offset 0x5940
+	0x5940: 0x0080, 0x5941: 0x0080, 0x5942: 0x0080, 0x5943: 0x0080, 0x5944: 0x0080, 0x5945: 0x0080,
+	0x5946: 0x0080, 0x5947: 0x0080, 0x5948: 0x0080, 0x5949: 0x0080, 0x594a: 0x0080, 0x594b: 0x0080,
+	0x594c: 0x0080, 0x594d: 0x0080, 0x594e: 0x0080, 0x594f: 0x0080, 0x5950: 0x0080, 0x5951: 0x0080,
+	0x5952: 0x0080, 0x5953: 0x0080,
+	0x5960: 0x0080, 0x5961: 0x0080, 0x5962: 0x0080, 0x5963: 0x0080,
+	0x5964: 0x0080, 0x5965: 0x0080, 0x5966: 0x0080, 0x5967: 0x0080, 0x5968: 0x0080, 0x5969: 0x0080,
+	0x596a: 0x0080, 0x596b: 0x0080, 0x596c: 0x0080, 0x596d: 0x0080,
+	0x5970: 0x0080, 0x5971: 0x0080, 0x5972: 0x0080, 0x5973: 0x0080, 0x5974: 0x0080, 0x5975: 0x0080,
+	0x5976: 0x0080, 0x5977: 0x0080, 0x5978: 0x0080, 0x5979: 0x0080, 0x597a: 0x0080, 0x597b: 0x0080,
+	0x597c: 0x0080,
+	// Block 0x166, offset 0x5980
+	0x5980: 0x0080, 0x5981: 0x0080, 0x5982: 0x0080, 0x5983: 0x0080, 0x5984: 0x0080, 0x5985: 0x0080,
+	0x5986: 0x0080, 0x5987: 0x0080, 0x5988: 0x0080,
+	0x5990: 0x0080, 0x5991: 0x0080,
+	0x5992: 0x0080, 0x5993: 0x0080, 0x5994: 0x0080, 0x5995: 0x0080, 0x5996: 0x0080, 0x5997: 0x0080,
+	0x5998: 0x0080, 0x5999: 0x0080, 0x599a: 0x0080, 0x599b: 0x0080, 0x599c: 0x0080, 0x599d: 0x0080,
+	0x599e: 0x0080, 0x599f: 0x0080, 0x59a0: 0x0080, 0x59a1: 0x0080, 0x59a2: 0x0080, 0x59a3: 0x0080,
+	0x59a4: 0x0080, 0x59a5: 0x0080, 0x59a6: 0x0080, 0x59a7: 0x0080, 0x59a8: 0x0080, 0x59a9: 0x0080,
+	0x59aa: 0x0080, 0x59ab: 0x0080, 0x59ac: 0x0080, 0x59ad: 0x0080, 0x59ae: 0x0080, 0x59af: 0x0080,
+	0x59b0: 0x0080, 0x59b1: 0x0080, 0x59b2: 0x0080, 0x59b3: 0x0080, 0x59b4: 0x0080, 0x59b5: 0x0080,
+	0x59b6: 0x0080, 0x59b7: 0x0080, 0x59b8: 0x0080, 0x59b9: 0x0080, 0x59ba: 0x0080, 0x59bb: 0x0080,
+	0x59bc: 0x0080, 0x59bd: 0x0080, 0x59bf: 0x0080,
+	// Block 0x167, offset 0x59c0
+	0x59c0: 0x0080, 0x59c1: 0x0080, 0x59c2: 0x0080, 0x59c3: 0x0080, 0x59c4: 0x0080, 0x59c5: 0x0080,
+	0x59ce: 0x0080, 0x59cf: 0x0080, 0x59d0: 0x0080, 0x59d1: 0x0080,
+	0x59d2: 0x0080, 0x59d3: 0x0080, 0x59d4: 0x0080, 0x59d5: 0x0080, 0x59d6: 0x0080, 0x59d7: 0x0080,
+	0x59d8: 0x0080, 0x59d9: 0x0080, 0x59da: 0x0080, 0x59db: 0x0080,
+	0x59e0: 0x0080, 0x59e1: 0x0080, 0x59e2: 0x0080, 0x59e3: 0x0080,
+	0x59e4: 0x0080, 0x59e5: 0x0080, 0x59e6: 0x0080, 0x59e7: 0x0080, 0x59e8: 0x0080,
+	0x59f0: 0x0080, 0x59f1: 0x0080, 0x59f2: 0x0080, 0x59f3: 0x0080, 0x59f4: 0x0080, 0x59f5: 0x0080,
+	0x59f6: 0x0080, 0x59f7: 0x0080, 0x59f8: 0x0080,
+	// Block 0x168, offset 0x5a00
+	0x5a00: 0x0080, 0x5a01: 0x0080, 0x5a02: 0x0080, 0x5a03: 0x0080, 0x5a04: 0x0080, 0x5a05: 0x0080,
+	0x5a06: 0x0080, 0x5a07: 0x0080, 0x5a08: 0x0080, 0x5a09: 0x0080, 0x5a0a: 0x0080, 0x5a0b: 0x0080,
+	0x5a0c: 0x0080, 0x5a0d: 0x0080, 0x5a0e: 0x0080, 0x5a0f: 0x0080, 0x5a10: 0x0080, 0x5a11: 0x0080,
+	0x5a12: 0x0080, 0x5a14: 0x0080, 0x5a15: 0x0080, 0x5a16: 0x0080, 0x5a17: 0x0080,
+	0x5a18: 0x0080, 0x5a19: 0x0080, 0x5a1a: 0x0080, 0x5a1b: 0x0080, 0x5a1c: 0x0080, 0x5a1d: 0x0080,
+	0x5a1e: 0x0080, 0x5a1f: 0x0080, 0x5a20: 0x0080, 0x5a21: 0x0080, 0x5a22: 0x0080, 0x5a23: 0x0080,
+	0x5a24: 0x0080, 0x5a25: 0x0080, 0x5a26: 0x0080, 0x5a27: 0x0080, 0x5a28: 0x0080, 0x5a29: 0x0080,
+	0x5a2a: 0x0080, 0x5a2b: 0x0080, 0x5a2c: 0x0080, 0x5a2d: 0x0080, 0x5a2e: 0x0080, 0x5a2f: 0x0080,
+	0x5a30: 0x0080, 0x5a31: 0x0080, 0x5a32: 0x0080, 0x5a33: 0x0080, 0x5a34: 0x0080, 0x5a35: 0x0080,
+	0x5a36: 0x0080, 0x5a37: 0x0080, 0x5a38: 0x0080, 0x5a39: 0x0080, 0x5a3a: 0x0080, 0x5a3b: 0x0080,
+	0x5a3c: 0x0080, 0x5a3d: 0x0080, 0x5a3e: 0x0080, 0x5a3f: 0x0080,
+	// Block 0x169, offset 0x5a40
+	0x5a40: 0x0080, 0x5a41: 0x0080, 0x5a42: 0x0080, 0x5a43: 0x0080, 0x5a44: 0x0080, 0x5a45: 0x0080,
+	0x5a46: 0x0080, 0x5a47: 0x0080, 0x5a48: 0x0080, 0x5a49: 0x0080, 0x5a4a: 0x0080,
+	0x5a70: 0x0080, 0x5a71: 0x0080, 0x5a72: 0x0080, 0x5a73: 0x0080, 0x5a74: 0x0080, 0x5a75: 0x0080,
+	0x5a76: 0x0080, 0x5a77: 0x0080, 0x5a78: 0x0080, 0x5a79: 0x0080,
+	// Block 0x16a, offset 0x5a80
+	0x5a80: 0x00cc, 0x5a81: 0x00cc, 0x5a82: 0x00cc, 0x5a83: 0x00cc, 0x5a84: 0x00cc, 0x5a85: 0x00cc,
+	0x5a86: 0x00cc, 0x5a87: 0x00cc, 0x5a88: 0x00cc, 0x5a89: 0x00cc, 0x5a8a: 0x00cc, 0x5a8b: 0x00cc,
+	0x5a8c: 0x00cc, 0x5a8d: 0x00cc, 0x5a8e: 0x00cc, 0x5a8f: 0x00cc, 0x5a90: 0x00cc, 0x5a91: 0x00cc,
+	0x5a92: 0x00cc, 0x5a93: 0x00cc, 0x5a94: 0x00cc, 0x5a95: 0x00cc, 0x5a96: 0x00cc, 0x5a97: 0x00cc,
+	0x5a98: 0x00cc, 0x5a99: 0x00cc, 0x5a9a: 0x00cc, 0x5a9b: 0x00cc, 0x5a9c: 0x00cc, 0x5a9d: 0x00cc,
+	0x5a9e: 0x00cc, 0x5a9f: 0x00cc,
+	// Block 0x16b, offset 0x5ac0
+	0x5ac0: 0x00cc, 0x5ac1: 0x00cc, 0x5ac2: 0x00cc, 0x5ac3: 0x00cc, 0x5ac4: 0x00cc, 0x5ac5: 0x00cc,
+	0x5ac6: 0x00cc, 0x5ac7: 0x00cc, 0x5ac8: 0x00cc, 0x5ac9: 0x00cc, 0x5aca: 0x00cc, 0x5acb: 0x00cc,
+	0x5acc: 0x00cc, 0x5acd: 0x00cc, 0x5ace: 0x00cc, 0x5acf: 0x00cc, 0x5ad0: 0x00cc, 0x5ad1: 0x00cc,
+	0x5ad2: 0x00cc, 0x5ad3: 0x00cc, 0x5ad4: 0x00cc, 0x5ad5: 0x00cc, 0x5ad6: 0x00cc, 0x5ad7: 0x00cc,
+	0x5ad8: 0x00cc, 0x5ad9: 0x00cc, 0x5ada: 0x00cc, 0x5adb: 0x00cc, 0x5adc: 0x00cc, 0x5add: 0x00cc,
+	0x5ade: 0x00cc, 0x5adf: 0x00cc, 0x5ae0: 0x00cc, 0x5ae1: 0x00cc, 0x5ae2: 0x00cc, 0x5ae3: 0x00cc,
+	0x5ae4: 0x00cc, 0x5ae5: 0x00cc, 0x5ae6: 0x00cc, 0x5ae7: 0x00cc, 0x5ae8: 0x00cc, 0x5ae9: 0x00cc,
+	0x5aea: 0x00cc, 0x5aeb: 0x00cc, 0x5aec: 0x00cc, 0x5aed: 0x00cc, 0x5aee: 0x00cc, 0x5aef: 0x00cc,
+	0x5af0: 0x00cc, 0x5af1: 0x00cc, 0x5af2: 0x00cc, 0x5af3: 0x00cc, 0x5af4: 0x00cc, 0x5af5: 0x00cc,
+	0x5af6: 0x00cc, 0x5af7: 0x00cc, 0x5af8: 0x00cc, 0x5af9: 0x00cc,
+	// Block 0x16c, offset 0x5b00
+	0x5b00: 0x00cc, 0x5b01: 0x00cc, 0x5b02: 0x00cc, 0x5b03: 0x00cc, 0x5b04: 0x00cc, 0x5b05: 0x00cc,
+	0x5b06: 0x00cc, 0x5b07: 0x00cc, 0x5b08: 0x00cc, 0x5b09: 0x00cc, 0x5b0a: 0x00cc, 0x5b0b: 0x00cc,
+	0x5b0c: 0x00cc, 0x5b0d: 0x00cc, 0x5b0e: 0x00cc, 0x5b0f: 0x00cc, 0x5b10: 0x00cc, 0x5b11: 0x00cc,
+	0x5b12: 0x00cc, 0x5b13: 0x00cc, 0x5b14: 0x00cc, 0x5b15: 0x00cc, 0x5b16: 0x00cc, 0x5b17: 0x00cc,
+	0x5b18: 0x00cc, 0x5b19: 0x00cc, 0x5b1a: 0x00cc, 0x5b1b: 0x00cc, 0x5b1c: 0x00cc, 0x5b1d: 0x00cc,
+	0x5b20: 0x00cc, 0x5b21: 0x00cc, 0x5b22: 0x00cc, 0x5b23: 0x00cc,
+	0x5b24: 0x00cc, 0x5b25: 0x00cc, 0x5b26: 0x00cc, 0x5b27: 0x00cc, 0x5b28: 0x00cc, 0x5b29: 0x00cc,
+	0x5b2a: 0x00cc, 0x5b2b: 0x00cc, 0x5b2c: 0x00cc, 0x5b2d: 0x00cc, 0x5b2e: 0x00cc, 0x5b2f: 0x00cc,
+	0x5b30: 0x00cc, 0x5b31: 0x00cc, 0x5b32: 0x00cc, 0x5b33: 0x00cc, 0x5b34: 0x00cc, 0x5b35: 0x00cc,
+	0x5b36: 0x00cc, 0x5b37: 0x00cc, 0x5b38: 0x00cc, 0x5b39: 0x00cc, 0x5b3a: 0x00cc, 0x5b3b: 0x00cc,
+	0x5b3c: 0x00cc, 0x5b3d: 0x00cc, 0x5b3e: 0x00cc, 0x5b3f: 0x00cc,
+	// Block 0x16d, offset 0x5b40
+	0x5b40: 0x00cc, 0x5b41: 0x00cc, 0x5b42: 0x00cc, 0x5b43: 0x00cc, 0x5b44: 0x00cc, 0x5b45: 0x00cc,
+	0x5b46: 0x00cc, 0x5b47: 0x00cc, 0x5b48: 0x00cc, 0x5b49: 0x00cc, 0x5b4a: 0x00cc, 0x5b4b: 0x00cc,
+	0x5b4c: 0x00cc, 0x5b4d: 0x00cc, 0x5b4e: 0x00cc, 0x5b4f: 0x00cc, 0x5b50: 0x00cc, 0x5b51: 0x00cc,
+	0x5b52: 0x00cc, 0x5b53: 0x00cc, 0x5b54: 0x00cc, 0x5b55: 0x00cc, 0x5b56: 0x00cc, 0x5b57: 0x00cc,
+	0x5b58: 0x00cc, 0x5b59: 0x00cc, 0x5b5a: 0x00cc, 0x5b5b: 0x00cc, 0x5b5c: 0x00cc, 0x5b5d: 0x00cc,
+	0x5b5e: 0x00cc, 0x5b5f: 0x00cc, 0x5b60: 0x00cc, 0x5b61: 0x00cc,
+	0x5b70: 0x00cc, 0x5b71: 0x00cc, 0x5b72: 0x00cc, 0x5b73: 0x00cc, 0x5b74: 0x00cc, 0x5b75: 0x00cc,
+	0x5b76: 0x00cc, 0x5b77: 0x00cc, 0x5b78: 0x00cc, 0x5b79: 0x00cc, 0x5b7a: 0x00cc, 0x5b7b: 0x00cc,
+	0x5b7c: 0x00cc, 0x5b7d: 0x00cc, 0x5b7e: 0x00cc, 0x5b7f: 0x00cc,
+	// Block 0x16e, offset 0x5b80
+	0x5b80: 0x00cc, 0x5b81: 0x00cc, 0x5b82: 0x00cc, 0x5b83: 0x00cc, 0x5b84: 0x00cc, 0x5b85: 0x00cc,
+	0x5b86: 0x00cc, 0x5b87: 0x00cc, 0x5b88: 0x00cc, 0x5b89: 0x00cc, 0x5b8a: 0x00cc, 0x5b8b: 0x00cc,
+	0x5b8c: 0x00cc, 0x5b8d: 0x00cc, 0x5b8e: 0x00cc, 0x5b8f: 0x00cc, 0x5b90: 0x00cc, 0x5b91: 0x00cc,
+	0x5b92: 0x00cc, 0x5b93: 0x00cc, 0x5b94: 0x00cc, 0x5b95: 0x00cc, 0x5b96: 0x00cc, 0x5b97: 0x00cc,
+	0x5b98: 0x00cc, 0x5b99: 0x00cc, 0x5b9a: 0x00cc, 0x5b9b: 0x00cc, 0x5b9c: 0x00cc, 0x5b9d: 0x00cc,
+	0x5b9e: 0x00cc, 0x5b9f: 0x00cc, 0x5ba0: 0x00cc,
+	// Block 0x16f, offset 0x5bc0
+	0x5bc0: 0x008c, 0x5bc1: 0x008c, 0x5bc2: 0x008c, 0x5bc3: 0x008c, 0x5bc4: 0x008c, 0x5bc5: 0x008c,
+	0x5bc6: 0x008c, 0x5bc7: 0x008c, 0x5bc8: 0x008c, 0x5bc9: 0x008c, 0x5bca: 0x008c, 0x5bcb: 0x008c,
+	0x5bcc: 0x008c, 0x5bcd: 0x008c, 0x5bce: 0x008c, 0x5bcf: 0x008c, 0x5bd0: 0x008c, 0x5bd1: 0x008c,
+	0x5bd2: 0x008c, 0x5bd3: 0x008c, 0x5bd4: 0x008c, 0x5bd5: 0x008c, 0x5bd6: 0x008c, 0x5bd7: 0x008c,
+	0x5bd8: 0x008c, 0x5bd9: 0x008c, 0x5bda: 0x008c, 0x5bdb: 0x008c, 0x5bdc: 0x008c, 0x5bdd: 0x008c,
+	// Block 0x170, offset 0x5c00
+	0x5c00: 0x00cc, 0x5c01: 0x00cc, 0x5c02: 0x00cc, 0x5c03: 0x00cc, 0x5c04: 0x00cc, 0x5c05: 0x00cc,
+	0x5c06: 0x00cc, 0x5c07: 0x00cc, 0x5c08: 0x00cc, 0x5c09: 0x00cc, 0x5c0a: 0x00cc,
+	0x5c10: 0x00cc, 0x5c11: 0x00cc,
+	0x5c12: 0x00cc, 0x5c13: 0x00cc, 0x5c14: 0x00cc, 0x5c15: 0x00cc, 0x5c16: 0x00cc, 0x5c17: 0x00cc,
+	0x5c18: 0x00cc, 0x5c19: 0x00cc, 0x5c1a: 0x00cc, 0x5c1b: 0x00cc, 0x5c1c: 0x00cc, 0x5c1d: 0x00cc,
+	0x5c1e: 0x00cc, 0x5c1f: 0x00cc, 0x5c20: 0x00cc, 0x5c21: 0x00cc, 0x5c22: 0x00cc, 0x5c23: 0x00cc,
+	0x5c24: 0x00cc, 0x5c25: 0x00cc, 0x5c26: 0x00cc, 0x5c27: 0x00cc, 0x5c28: 0x00cc, 0x5c29: 0x00cc,
+	0x5c2a: 0x00cc, 0x5c2b: 0x00cc, 0x5c2c: 0x00cc, 0x5c2d: 0x00cc, 0x5c2e: 0x00cc, 0x5c2f: 0x00cc,
+	0x5c30: 0x00cc, 0x5c31: 0x00cc, 0x5c32: 0x00cc, 0x5c33: 0x00cc, 0x5c34: 0x00cc, 0x5c35: 0x00cc,
+	0x5c36: 0x00cc, 0x5c37: 0x00cc, 0x5c38: 0x00cc, 0x5c39: 0x00cc, 0x5c3a: 0x00cc, 0x5c3b: 0x00cc,
+	0x5c3c: 0x00cc, 0x5c3d: 0x00cc, 0x5c3e: 0x00cc, 0x5c3f: 0x00cc,
+	// Block 0x171, offset 0x5c40
+	0x5c40: 0x00cc, 0x5c41: 0x00cc, 0x5c42: 0x00cc, 0x5c43: 0x00cc, 0x5c44: 0x00cc, 0x5c45: 0x00cc,
+	0x5c46: 0x00cc, 0x5c47: 0x00cc, 0x5c48: 0x00cc, 0x5c49: 0x00cc, 0x5c4a: 0x00cc, 0x5c4b: 0x00cc,
+	0x5c4c: 0x00cc, 0x5c4d: 0x00cc, 0x5c4e: 0x00cc, 0x5c4f: 0x00cc, 0x5c50: 0x00cc, 0x5c51: 0x00cc,
+	0x5c52: 0x00cc, 0x5c53: 0x00cc, 0x5c54: 0x00cc, 0x5c55: 0x00cc, 0x5c56: 0x00cc, 0x5c57: 0x00cc,
+	0x5c58: 0x00cc, 0x5c59: 0x00cc, 0x5c5a: 0x00cc, 0x5c5b: 0x00cc, 0x5c5c: 0x00cc, 0x5c5d: 0x00cc,
+	0x5c5e: 0x00cc, 0x5c5f: 0x00cc, 0x5c60: 0x00cc, 0x5c61: 0x00cc, 0x5c62: 0x00cc, 0x5c63: 0x00cc,
+	0x5c64: 0x00cc, 0x5c65: 0x00cc, 0x5c66: 0x00cc, 0x5c67: 0x00cc, 0x5c68: 0x00cc, 0x5c69: 0x00cc,
+	0x5c6a: 0x00cc, 0x5c6b: 0x00cc, 0x5c6c: 0x00cc, 0x5c6d: 0x00cc, 0x5c6e: 0x00cc, 0x5c6f: 0x00cc,
+	// Block 0x172, offset 0x5c80
+	0x5c81: 0x0040,
+	0x5ca0: 0x0040, 0x5ca1: 0x0040, 0x5ca2: 0x0040, 0x5ca3: 0x0040,
+	0x5ca4: 0x0040, 0x5ca5: 0x0040, 0x5ca6: 0x0040, 0x5ca7: 0x0040, 0x5ca8: 0x0040, 0x5ca9: 0x0040,
+	0x5caa: 0x0040, 0x5cab: 0x0040, 0x5cac: 0x0040, 0x5cad: 0x0040, 0x5cae: 0x0040, 0x5caf: 0x0040,
+	0x5cb0: 0x0040, 0x5cb1: 0x0040, 0x5cb2: 0x0040, 0x5cb3: 0x0040, 0x5cb4: 0x0040, 0x5cb5: 0x0040,
+	0x5cb6: 0x0040, 0x5cb7: 0x0040, 0x5cb8: 0x0040, 0x5cb9: 0x0040, 0x5cba: 0x0040, 0x5cbb: 0x0040,
+	0x5cbc: 0x0040, 0x5cbd: 0x0040, 0x5cbe: 0x0040, 0x5cbf: 0x0040,
+	// Block 0x173, offset 0x5cc0
+	0x5cc0: 0x0040, 0x5cc1: 0x0040, 0x5cc2: 0x0040, 0x5cc3: 0x0040, 0x5cc4: 0x0040, 0x5cc5: 0x0040,
+	0x5cc6: 0x0040, 0x5cc7: 0x0040, 0x5cc8: 0x0040, 0x5cc9: 0x0040, 0x5cca: 0x0040, 0x5ccb: 0x0040,
+	0x5ccc: 0x0040, 0x5ccd: 0x0040, 0x5cce: 0x0040, 0x5ccf: 0x0040, 0x5cd0: 0x0040, 0x5cd1: 0x0040,
+	0x5cd2: 0x0040, 0x5cd3: 0x0040, 0x5cd4: 0x0040, 0x5cd5: 0x0040, 0x5cd6: 0x0040, 0x5cd7: 0x0040,
+	0x5cd8: 0x0040, 0x5cd9: 0x0040, 0x5cda: 0x0040, 0x5cdb: 0x0040, 0x5cdc: 0x0040, 0x5cdd: 0x0040,
+	0x5cde: 0x0040, 0x5cdf: 0x0040, 0x5ce0: 0x0040, 0x5ce1: 0x0040, 0x5ce2: 0x0040, 0x5ce3: 0x0040,
+	0x5ce4: 0x0040, 0x5ce5: 0x0040, 0x5ce6: 0x0040, 0x5ce7: 0x0040, 0x5ce8: 0x0040, 0x5ce9: 0x0040,
+	0x5cea: 0x0040, 0x5ceb: 0x0040, 0x5cec: 0x0040, 0x5ced: 0x0040, 0x5cee: 0x0040, 0x5cef: 0x0040,
+	// Block 0x174, offset 0x5d00
+	0x5d00: 0x0040, 0x5d01: 0x0040, 0x5d02: 0x0040, 0x5d03: 0x0040, 0x5d04: 0x0040, 0x5d05: 0x0040,
+	0x5d06: 0x0040, 0x5d07: 0x0040, 0x5d08: 0x0040, 0x5d09: 0x0040, 0x5d0a: 0x0040, 0x5d0b: 0x0040,
+	0x5d0c: 0x0040, 0x5d0d: 0x0040, 0x5d0e: 0x0040, 0x5d0f: 0x0040, 0x5d10: 0x0040, 0x5d11: 0x0040,
+	0x5d12: 0x0040, 0x5d13: 0x0040, 0x5d14: 0x0040, 0x5d15: 0x0040, 0x5d16: 0x0040, 0x5d17: 0x0040,
+	0x5d18: 0x0040, 0x5d19: 0x0040, 0x5d1a: 0x0040, 0x5d1b: 0x0040, 0x5d1c: 0x0040, 0x5d1d: 0x0040,
+	0x5d1e: 0x0040, 0x5d1f: 0x0040, 0x5d20: 0x0040, 0x5d21: 0x0040, 0x5d22: 0x0040, 0x5d23: 0x0040,
+	0x5d24: 0x0040, 0x5d25: 0x0040, 0x5d26: 0x0040, 0x5d27: 0x0040, 0x5d28: 0x0040, 0x5d29: 0x0040,
+	0x5d2a: 0x0040, 0x5d2b: 0x0040, 0x5d2c: 0x0040, 0x5d2d: 0x0040, 0x5d2e: 0x0040, 0x5d2f: 0x0040,
+	0x5d30: 0x0040, 0x5d31: 0x0040, 0x5d32: 0x0040, 0x5d33: 0x0040, 0x5d34: 0x0040, 0x5d35: 0x0040,
+	0x5d36: 0x0040, 0x5d37: 0x0040, 0x5d38: 0x0040, 0x5d39: 0x0040, 0x5d3a: 0x0040, 0x5d3b: 0x0040,
+	0x5d3c: 0x0040, 0x5d3d: 0x0040,
+}
+
+// derivedPropertiesIndex: 40 blocks, 2560 entries, 5120 bytes
+// Block 0 is the zero block.
+var derivedPropertiesIndex = [2560]uint16{
+	// Block 0x0, offset 0x0
+	// Block 0x1, offset 0x40
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc6: 0x05, 0xc7: 0x06,
+	0xc8: 0x05, 0xc9: 0x05, 0xca: 0x07, 0xcb: 0x08, 0xcc: 0x09, 0xcd: 0x0a, 0xce: 0x0b, 0xcf: 0x0c,
+	0xd0: 0x05, 0xd1: 0x05, 0xd2: 0x0d, 0xd3: 0x05, 0xd4: 0x0e, 0xd5: 0x0f, 0xd6: 0x10, 0xd7: 0x11,
+	0xd8: 0x12, 0xd9: 0x13, 0xda: 0x14, 0xdb: 0x15, 0xdc: 0x16, 0xdd: 0x17, 0xde: 0x18, 0xdf: 0x19,
+	0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07,
+	0xe8: 0x07, 0xe9: 0x07, 0xea: 0x08, 0xeb: 0x09, 0xec: 0x09, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c,
+	0xf0: 0x21, 0xf3: 0x24, 0xf4: 0x25,
+	// Block 0x4, offset 0x100
+	0x120: 0x1a, 0x121: 0x1b, 0x122: 0x1c, 0x123: 0x1d, 0x124: 0x1e, 0x125: 0x1f, 0x126: 0x20, 0x127: 0x21,
+	0x128: 0x22, 0x129: 0x23, 0x12a: 0x24, 0x12b: 0x25, 0x12c: 0x26, 0x12d: 0x27, 0x12e: 0x28, 0x12f: 0x29,
+	0x130: 0x2a, 0x131: 0x2b, 0x132: 0x2c, 0x133: 0x2d, 0x134: 0x2e, 0x135: 0x2f, 0x136: 0x30, 0x137: 0x31,
+	0x138: 0x32, 0x139: 0x33, 0x13a: 0x34, 0x13b: 0x35, 0x13c: 0x36, 0x13d: 0x37, 0x13e: 0x38, 0x13f: 0x39,
+	// Block 0x5, offset 0x140
+	0x140: 0x3a, 0x141: 0x3b, 0x142: 0x3c, 0x143: 0x3d, 0x144: 0x3e, 0x145: 0x3e, 0x146: 0x3e, 0x147: 0x3e,
+	0x148: 0x05, 0x149: 0x3f, 0x14a: 0x40, 0x14b: 0x41, 0x14c: 0x42, 0x14d: 0x43, 0x14e: 0x44, 0x14f: 0x45,
+	0x150: 0x46, 0x151: 0x05, 0x152: 0x05, 0x153: 0x05, 0x154: 0x05, 0x155: 0x05, 0x156: 0x05, 0x157: 0x05,
+	0x158: 0x05, 0x159: 0x47, 0x15a: 0x48, 0x15b: 0x49, 0x15c: 0x4a, 0x15d: 0x4b, 0x15e: 0x4c, 0x15f: 0x4d,
+	0x160: 0x4e, 0x161: 0x4f, 0x162: 0x50, 0x163: 0x51, 0x164: 0x52, 0x165: 0x53, 0x166: 0x54, 0x167: 0x55,
+	0x168: 0x56, 0x169: 0x57, 0x16a: 0x58, 0x16b: 0x59, 0x16c: 0x5a, 0x16d: 0x5b, 0x16e: 0x5c, 0x16f: 0x5d,
+	0x170: 0x5e, 0x171: 0x5f, 0x172: 0x60, 0x173: 0x61, 0x174: 0x62, 0x175: 0x63, 0x176: 0x64, 0x177: 0x09,
+	0x178: 0x05, 0x179: 0x05, 0x17a: 0x65, 0x17b: 0x05, 0x17c: 0x66, 0x17d: 0x67, 0x17e: 0x68, 0x17f: 0x69,
+	// Block 0x6, offset 0x180
+	0x180: 0x6a, 0x181: 0x6b, 0x182: 0x6c, 0x183: 0x6d, 0x184: 0x6e, 0x185: 0x6f, 0x186: 0x70, 0x187: 0x71,
+	0x188: 0x71, 0x189: 0x71, 0x18a: 0x71, 0x18b: 0x71, 0x18c: 0x71, 0x18d: 0x71, 0x18e: 0x71, 0x18f: 0x71,
+	0x190: 0x72, 0x191: 0x73, 0x192: 0x71, 0x193: 0x71, 0x194: 0x71, 0x195: 0x71, 0x196: 0x71, 0x197: 0x71,
+	0x198: 0x71, 0x199: 0x71, 0x19a: 0x71, 0x19b: 0x71, 0x19c: 0x71, 0x19d: 0x71, 0x19e: 0x71, 0x19f: 0x71,
+	0x1a0: 0x71, 0x1a1: 0x71, 0x1a2: 0x71, 0x1a3: 0x71, 0x1a4: 0x71, 0x1a5: 0x71, 0x1a6: 0x71, 0x1a7: 0x71,
+	0x1a8: 0x71, 0x1a9: 0x71, 0x1aa: 0x71, 0x1ab: 0x71, 0x1ac: 0x71, 0x1ad: 0x74, 0x1ae: 0x75, 0x1af: 0x71,
+	0x1b0: 0x05, 0x1b1: 0x76, 0x1b2: 0x05, 0x1b3: 0x77, 0x1b4: 0x78, 0x1b5: 0x79, 0x1b6: 0x7a, 0x1b7: 0x7b,
+	0x1b8: 0x7c, 0x1b9: 0x7d, 0x1ba: 0x7e, 0x1bb: 0x7f, 0x1bc: 0x80, 0x1bd: 0x80, 0x1be: 0x80, 0x1bf: 0x81,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x82, 0x1c1: 0x83, 0x1c2: 0x84, 0x1c3: 0x85, 0x1c4: 0x86, 0x1c5: 0x87, 0x1c6: 0x88, 0x1c7: 0x89,
+	0x1c8: 0x8a, 0x1c9: 0x71, 0x1ca: 0x71, 0x1cb: 0x8b, 0x1cc: 0x80, 0x1cd: 0x8c, 0x1ce: 0x71, 0x1cf: 0x71,
+	0x1d0: 0x8d, 0x1d1: 0x8d, 0x1d2: 0x8d, 0x1d3: 0x8d, 0x1d4: 0x8d, 0x1d5: 0x8d, 0x1d6: 0x8d, 0x1d7: 0x8d,
+	0x1d8: 0x8d, 0x1d9: 0x8d, 0x1da: 0x8d, 0x1db: 0x8d, 0x1dc: 0x8d, 0x1dd: 0x8d, 0x1de: 0x8d, 0x1df: 0x8d,
+	0x1e0: 0x8d, 0x1e1: 0x8d, 0x1e2: 0x8d, 0x1e3: 0x8d, 0x1e4: 0x8d, 0x1e5: 0x8d, 0x1e6: 0x8d, 0x1e7: 0x8d,
+	0x1e8: 0x8d, 0x1e9: 0x8d, 0x1ea: 0x8d, 0x1eb: 0x8d, 0x1ec: 0x8d, 0x1ed: 0x8d, 0x1ee: 0x8d, 0x1ef: 0x8d,
+	0x1f0: 0x8d, 0x1f1: 0x8d, 0x1f2: 0x8d, 0x1f3: 0x8d, 0x1f4: 0x8d, 0x1f5: 0x8d, 0x1f6: 0x8d, 0x1f7: 0x8d,
+	0x1f8: 0x8d, 0x1f9: 0x8d, 0x1fa: 0x8d, 0x1fb: 0x8d, 0x1fc: 0x8d, 0x1fd: 0x8d, 0x1fe: 0x8d, 0x1ff: 0x8d,
+	// Block 0x8, offset 0x200
+	0x200: 0x8d, 0x201: 0x8d, 0x202: 0x8d, 0x203: 0x8d, 0x204: 0x8d, 0x205: 0x8d, 0x206: 0x8d, 0x207: 0x8d,
+	0x208: 0x8d, 0x209: 0x8d, 0x20a: 0x8d, 0x20b: 0x8d, 0x20c: 0x8d, 0x20d: 0x8d, 0x20e: 0x8d, 0x20f: 0x8d,
+	0x210: 0x8d, 0x211: 0x8d, 0x212: 0x8d, 0x213: 0x8d, 0x214: 0x8d, 0x215: 0x8d, 0x216: 0x8d, 0x217: 0x8d,
+	0x218: 0x8d, 0x219: 0x8d, 0x21a: 0x8d, 0x21b: 0x8d, 0x21c: 0x8d, 0x21d: 0x8d, 0x21e: 0x8d, 0x21f: 0x8d,
+	0x220: 0x8d, 0x221: 0x8d, 0x222: 0x8d, 0x223: 0x8d, 0x224: 0x8d, 0x225: 0x8d, 0x226: 0x8d, 0x227: 0x8d,
+	0x228: 0x8d, 0x229: 0x8d, 0x22a: 0x8d, 0x22b: 0x8d, 0x22c: 0x8d, 0x22d: 0x8d, 0x22e: 0x8d, 0x22f: 0x8d,
+	0x230: 0x8d, 0x231: 0x8d, 0x232: 0x8d, 0x233: 0x8d, 0x234: 0x8d, 0x235: 0x8d, 0x236: 0x8d, 0x237: 0x71,
+	0x238: 0x8d, 0x239: 0x8d, 0x23a: 0x8d, 0x23b: 0x8d, 0x23c: 0x8d, 0x23d: 0x8d, 0x23e: 0x8d, 0x23f: 0x8d,
+	// Block 0x9, offset 0x240
+	0x240: 0x8d, 0x241: 0x8d, 0x242: 0x8d, 0x243: 0x8d, 0x244: 0x8d, 0x245: 0x8d, 0x246: 0x8d, 0x247: 0x8d,
+	0x248: 0x8d, 0x249: 0x8d, 0x24a: 0x8d, 0x24b: 0x8d, 0x24c: 0x8d, 0x24d: 0x8d, 0x24e: 0x8d, 0x24f: 0x8d,
+	0x250: 0x8d, 0x251: 0x8d, 0x252: 0x8d, 0x253: 0x8d, 0x254: 0x8d, 0x255: 0x8d, 0x256: 0x8d, 0x257: 0x8d,
+	0x258: 0x8d, 0x259: 0x8d, 0x25a: 0x8d, 0x25b: 0x8d, 0x25c: 0x8d, 0x25d: 0x8d, 0x25e: 0x8d, 0x25f: 0x8d,
+	0x260: 0x8d, 0x261: 0x8d, 0x262: 0x8d, 0x263: 0x8d, 0x264: 0x8d, 0x265: 0x8d, 0x266: 0x8d, 0x267: 0x8d,
+	0x268: 0x8d, 0x269: 0x8d, 0x26a: 0x8d, 0x26b: 0x8d, 0x26c: 0x8d, 0x26d: 0x8d, 0x26e: 0x8d, 0x26f: 0x8d,
+	0x270: 0x8d, 0x271: 0x8d, 0x272: 0x8d, 0x273: 0x8d, 0x274: 0x8d, 0x275: 0x8d, 0x276: 0x8d, 0x277: 0x8d,
+	0x278: 0x8d, 0x279: 0x8d, 0x27a: 0x8d, 0x27b: 0x8d, 0x27c: 0x8d, 0x27d: 0x8d, 0x27e: 0x8d, 0x27f: 0x8d,
+	// Block 0xa, offset 0x280
+	0x280: 0x05, 0x281: 0x05, 0x282: 0x05, 0x283: 0x05, 0x284: 0x05, 0x285: 0x05, 0x286: 0x05, 0x287: 0x05,
+	0x288: 0x05, 0x289: 0x05, 0x28a: 0x05, 0x28b: 0x05, 0x28c: 0x05, 0x28d: 0x05, 0x28e: 0x05, 0x28f: 0x05,
+	0x290: 0x05, 0x291: 0x05, 0x292: 0x8e, 0x293: 0x8f, 0x294: 0x05, 0x295: 0x05, 0x296: 0x05, 0x297: 0x05,
+	0x298: 0x90, 0x299: 0x91, 0x29a: 0x92, 0x29b: 0x93, 0x29c: 0x94, 0x29d: 0x95, 0x29e: 0x96, 0x29f: 0x97,
+	0x2a0: 0x98, 0x2a1: 0x99, 0x2a2: 0x05, 0x2a3: 0x9a, 0x2a4: 0x9b, 0x2a5: 0x9c, 0x2a6: 0x9d, 0x2a7: 0x9e,
+	0x2a8: 0x9f, 0x2a9: 0xa0, 0x2aa: 0xa1, 0x2ab: 0xa2, 0x2ac: 0xa3, 0x2ad: 0xa4, 0x2ae: 0x05, 0x2af: 0xa5,
+	0x2b0: 0x05, 0x2b1: 0x05, 0x2b2: 0x05, 0x2b3: 0x05, 0x2b4: 0x05, 0x2b5: 0x05, 0x2b6: 0x05, 0x2b7: 0x05,
+	0x2b8: 0x05, 0x2b9: 0x05, 0x2ba: 0x05, 0x2bb: 0x05, 0x2bc: 0x05, 0x2bd: 0x05, 0x2be: 0x05, 0x2bf: 0x05,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x05, 0x2c1: 0x05, 0x2c2: 0x05, 0x2c3: 0x05, 0x2c4: 0x05, 0x2c5: 0x05, 0x2c6: 0x05, 0x2c7: 0x05,
+	0x2c8: 0x05, 0x2c9: 0x05, 0x2ca: 0x05, 0x2cb: 0x05, 0x2cc: 0x05, 0x2cd: 0x05, 0x2ce: 0x05, 0x2cf: 0x05,
+	0x2d0: 0x05, 0x2d1: 0x05, 0x2d2: 0x05, 0x2d3: 0x05, 0x2d4: 0x05, 0x2d5: 0x05, 0x2d6: 0x05, 0x2d7: 0x05,
+	0x2d8: 0x05, 0x2d9: 0x05, 0x2da: 0x05, 0x2db: 0x05, 0x2dc: 0x05, 0x2dd: 0x05, 0x2de: 0x05, 0x2df: 0x05,
+	0x2e0: 0x05, 0x2e1: 0x05, 0x2e2: 0x05, 0x2e3: 0x05, 0x2e4: 0x05, 0x2e5: 0x05, 0x2e6: 0x05, 0x2e7: 0x05,
+	0x2e8: 0x05, 0x2e9: 0x05, 0x2ea: 0x05, 0x2eb: 0x05, 0x2ec: 0x05, 0x2ed: 0x05, 0x2ee: 0x05, 0x2ef: 0x05,
+	0x2f0: 0x05, 0x2f1: 0x05, 0x2f2: 0x05, 0x2f3: 0x05, 0x2f4: 0x05, 0x2f5: 0x05, 0x2f6: 0x05, 0x2f7: 0x05,
+	0x2f8: 0x05, 0x2f9: 0x05, 0x2fa: 0x05, 0x2fb: 0x05, 0x2fc: 0x05, 0x2fd: 0x05, 0x2fe: 0x05, 0x2ff: 0x05,
+	// Block 0xc, offset 0x300
+	0x300: 0x05, 0x301: 0x05, 0x302: 0x05, 0x303: 0x05, 0x304: 0x05, 0x305: 0x05, 0x306: 0x05, 0x307: 0x05,
+	0x308: 0x05, 0x309: 0x05, 0x30a: 0x05, 0x30b: 0x05, 0x30c: 0x05, 0x30d: 0x05, 0x30e: 0x05, 0x30f: 0x05,
+	0x310: 0x05, 0x311: 0x05, 0x312: 0x05, 0x313: 0x05, 0x314: 0x05, 0x315: 0x05, 0x316: 0x05, 0x317: 0x05,
+	0x318: 0x05, 0x319: 0x05, 0x31a: 0x05, 0x31b: 0x05, 0x31c: 0x05, 0x31d: 0x05, 0x31e: 0xa6, 0x31f: 0xa7,
+	// Block 0xd, offset 0x340
+	0x340: 0x3e, 0x341: 0x3e, 0x342: 0x3e, 0x343: 0x3e, 0x344: 0x3e, 0x345: 0x3e, 0x346: 0x3e, 0x347: 0x3e,
+	0x348: 0x3e, 0x349: 0x3e, 0x34a: 0x3e, 0x34b: 0x3e, 0x34c: 0x3e, 0x34d: 0x3e, 0x34e: 0x3e, 0x34f: 0x3e,
+	0x350: 0x3e, 0x351: 0x3e, 0x352: 0x3e, 0x353: 0x3e, 0x354: 0x3e, 0x355: 0x3e, 0x356: 0x3e, 0x357: 0x3e,
+	0x358: 0x3e, 0x359: 0x3e, 0x35a: 0x3e, 0x35b: 0x3e, 0x35c: 0x3e, 0x35d: 0x3e, 0x35e: 0x3e, 0x35f: 0x3e,
+	0x360: 0x3e, 0x361: 0x3e, 0x362: 0x3e, 0x363: 0x3e, 0x364: 0x3e, 0x365: 0x3e, 0x366: 0x3e, 0x367: 0x3e,
+	0x368: 0x3e, 0x369: 0x3e, 0x36a: 0x3e, 0x36b: 0x3e, 0x36c: 0x3e, 0x36d: 0x3e, 0x36e: 0x3e, 0x36f: 0x3e,
+	0x370: 0x3e, 0x371: 0x3e, 0x372: 0x3e, 0x373: 0x3e, 0x374: 0x3e, 0x375: 0x3e, 0x376: 0x3e, 0x377: 0x3e,
+	0x378: 0x3e, 0x379: 0x3e, 0x37a: 0x3e, 0x37b: 0x3e, 0x37c: 0x3e, 0x37d: 0x3e, 0x37e: 0x3e, 0x37f: 0x3e,
+	// Block 0xe, offset 0x380
+	0x380: 0x3e, 0x381: 0x3e, 0x382: 0x3e, 0x383: 0x3e, 0x384: 0x3e, 0x385: 0x3e, 0x386: 0x3e, 0x387: 0x3e,
+	0x388: 0x3e, 0x389: 0x3e, 0x38a: 0x3e, 0x38b: 0x3e, 0x38c: 0x3e, 0x38d: 0x3e, 0x38e: 0x3e, 0x38f: 0x3e,
+	0x390: 0x3e, 0x391: 0x3e, 0x392: 0x3e, 0x393: 0x3e, 0x394: 0x3e, 0x395: 0x3e, 0x396: 0x3e, 0x397: 0x3e,
+	0x398: 0x3e, 0x399: 0x3e, 0x39a: 0x3e, 0x39b: 0x3e, 0x39c: 0x3e, 0x39d: 0x3e, 0x39e: 0x3e, 0x39f: 0x3e,
+	0x3a0: 0x3e, 0x3a1: 0x3e, 0x3a2: 0x3e, 0x3a3: 0x3e, 0x3a4: 0x80, 0x3a5: 0x80, 0x3a6: 0x80, 0x3a7: 0x80,
+	0x3a8: 0xa8, 0x3a9: 0xa9, 0x3aa: 0x80, 0x3ab: 0xaa, 0x3ac: 0xab, 0x3ad: 0xac, 0x3ae: 0x71, 0x3af: 0xad,
+	0x3b0: 0x71, 0x3b1: 0x71, 0x3b2: 0x71, 0x3b3: 0x71, 0x3b4: 0x71, 0x3b5: 0x71, 0x3b6: 0xae, 0x3b7: 0xaf,
+	0x3b8: 0xb0, 0x3b9: 0xb1, 0x3ba: 0x71, 0x3bb: 0xb2, 0x3bc: 0xb3, 0x3bd: 0xb4, 0x3be: 0xb5, 0x3bf: 0xb6,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0xb7, 0x3c1: 0xb8, 0x3c2: 0x05, 0x3c3: 0xb9, 0x3c4: 0xba, 0x3c5: 0xbb, 0x3c6: 0xbc, 0x3c7: 0xbd,
+	0x3ca: 0xbe, 0x3cb: 0xbf, 0x3cc: 0xc0, 0x3cd: 0xc1, 0x3ce: 0xc2, 0x3cf: 0xc3,
+	0x3d0: 0x05, 0x3d1: 0x05, 0x3d2: 0xc4, 0x3d3: 0xc5, 0x3d4: 0xc6, 0x3d5: 0xc7, 0x3d6: 0xc8,
+	0x3d8: 0x05, 0x3d9: 0x05, 0x3da: 0x05, 0x3db: 0x05, 0x3dc: 0xc9, 0x3dd: 0xca, 0x3de: 0xcb,
+	0x3e0: 0xcc, 0x3e1: 0xcd, 0x3e2: 0xce, 0x3e3: 0xcf, 0x3e4: 0xd0, 0x3e6: 0xd1, 0x3e7: 0xae,
+	0x3e8: 0xd2, 0x3e9: 0xd3, 0x3ea: 0xd4, 0x3eb: 0xd5, 0x3ec: 0xd6, 0x3ed: 0xd7, 0x3ee: 0xd8,
+	0x3f0: 0x05, 0x3f1: 0xd9, 0x3f2: 0xda, 0x3f3: 0xdb, 0x3f4: 0xdc,
+	0x3f9: 0xdd, 0x3fa: 0xde, 0x3fb: 0xdf, 0x3fc: 0xe0, 0x3fd: 0xe1, 0x3fe: 0xe2, 0x3ff: 0xe3,
+	// Block 0x10, offset 0x400
+	0x400: 0xe4, 0x401: 0xe5, 0x402: 0xe6, 0x403: 0xe7, 0x404: 0xe8, 0x405: 0xe9, 0x406: 0xea, 0x407: 0xeb,
+	0x408: 0xec, 0x409: 0xed, 0x40a: 0xee, 0x40b: 0xef, 0x40c: 0xf0, 0x40d: 0xf1,
+	0x410: 0xf2, 0x411: 0xf3, 0x412: 0xf4, 0x413: 0xf5, 0x416: 0xf6, 0x417: 0xf7,
+	0x418: 0xf8, 0x419: 0xf9, 0x41a: 0xfa, 0x41b: 0xfb, 0x41c: 0xfc, 0x41d: 0xfd,
+	0x420: 0xfe, 0x422: 0xff, 0x423: 0x100, 0x424: 0x101, 0x425: 0x102, 0x426: 0x103, 0x427: 0x104,
+	0x428: 0x105, 0x429: 0x106, 0x42a: 0x107, 0x42b: 0x108, 0x42c: 0x109,
+	0x430: 0x10a, 0x431: 0x10b, 0x432: 0x10c, 0x434: 0x10d, 0x435: 0x10e, 0x436: 0x10f,
+	0x43b: 0x110, 0x43c: 0x111, 0x43d: 0x112, 0x43e: 0x113, 0x43f: 0x114,
+	// Block 0x11, offset 0x440
+	0x440: 0x05, 0x441: 0x05, 0x442: 0x05, 0x443: 0x05, 0x444: 0x05, 0x445: 0x05, 0x446: 0x05, 0x447: 0x05,
+	0x448: 0x05, 0x449: 0x05, 0x44a: 0x05, 0x44b: 0x05, 0x44c: 0x05, 0x44d: 0x05, 0x44e: 0x115,
+	0x450: 0x71, 0x451: 0x116, 0x452: 0x05, 0x453: 0x05, 0x454: 0x05, 0x455: 0x117,
+	0x47e: 0x118, 0x47f: 0x119,
+	// Block 0x12, offset 0x480
+	0x480: 0x05, 0x481: 0x05, 0x482: 0x05, 0x483: 0x05, 0x484: 0x05, 0x485: 0x05, 0x486: 0x05, 0x487: 0x05,
+	0x488: 0x05, 0x489: 0x05, 0x48a: 0x05, 0x48b: 0x05, 0x48c: 0x05, 0x48d: 0x05, 0x48e: 0x05, 0x48f: 0x05,
+	0x490: 0x11a, 0x491: 0x11b,
+	// Block 0x13, offset 0x4c0
+	0x4d0: 0x05, 0x4d1: 0x05, 0x4d2: 0x05, 0x4d3: 0x05, 0x4d4: 0x05, 0x4d5: 0x05, 0x4d6: 0x05, 0x4d7: 0x05,
+	0x4d8: 0x05, 0x4d9: 0xfd,
+	// Block 0x14, offset 0x500
+	0x520: 0x05, 0x521: 0x05, 0x522: 0x05, 0x523: 0x05, 0x524: 0x05, 0x525: 0x05, 0x526: 0x05, 0x527: 0x05,
+	0x528: 0x108, 0x529: 0x11c, 0x52a: 0x11d, 0x52b: 0x11e, 0x52c: 0x11f, 0x52d: 0x120, 0x52e: 0x121,
+	0x539: 0x05, 0x53a: 0x122, 0x53c: 0x05, 0x53d: 0x123, 0x53e: 0x124, 0x53f: 0x125,
+	// Block 0x15, offset 0x540
+	0x540: 0x05, 0x541: 0x05, 0x542: 0x05, 0x543: 0x05, 0x544: 0x05, 0x545: 0x05, 0x546: 0x05, 0x547: 0x05,
+	0x548: 0x05, 0x549: 0x05, 0x54a: 0x05, 0x54b: 0x05, 0x54c: 0x05, 0x54d: 0x05, 0x54e: 0x05, 0x54f: 0x05,
+	0x550: 0x05, 0x551: 0x05, 0x552: 0x05, 0x553: 0x05, 0x554: 0x05, 0x555: 0x05, 0x556: 0x05, 0x557: 0x05,
+	0x558: 0x05, 0x559: 0x05, 0x55a: 0x05, 0x55b: 0x05, 0x55c: 0x05, 0x55d: 0x05, 0x55e: 0x05, 0x55f: 0x126,
+	0x560: 0x05, 0x561: 0x05, 0x562: 0x05, 0x563: 0x05, 0x564: 0x05, 0x565: 0x05, 0x566: 0x05, 0x567: 0x05,
+	0x568: 0x05, 0x569: 0x05, 0x56a: 0x05, 0x56b: 0x05, 0x56c: 0x05, 0x56d: 0x05, 0x56e: 0x05, 0x56f: 0x05,
+	0x570: 0x05, 0x571: 0x05, 0x572: 0x05, 0x573: 0x127, 0x574: 0xd9,
+	// Block 0x16, offset 0x580
+	0x5bf: 0x128,
+	// Block 0x17, offset 0x5c0
+	0x5c0: 0x8d, 0x5c1: 0x8d, 0x5c2: 0x8d, 0x5c3: 0x8d, 0x5c4: 0x129, 0x5c5: 0x12a, 0x5c6: 0x05, 0x5c7: 0x05,
+	0x5c8: 0x05, 0x5c9: 0x05, 0x5ca: 0x05, 0x5cb: 0x12b,
+	0x5f0: 0x05, 0x5f1: 0x12c, 0x5f2: 0x12d,
+	// Block 0x18, offset 0x600
+	0x63c: 0x12e, 0x63d: 0x12f, 0x63e: 0x71, 0x63f: 0x130,
+	// Block 0x19, offset 0x640
+	0x640: 0x71, 0x641: 0x71, 0x642: 0x71, 0x643: 0x131, 0x644: 0x132, 0x645: 0x133, 0x646: 0x134, 0x647: 0x135,
+	0x648: 0xbb, 0x649: 0x136, 0x64b: 0x137, 0x64c: 0x71, 0x64d: 0x138,
+	0x650: 0x71, 0x651: 0x139, 0x652: 0x13a, 0x653: 0x13b, 0x654: 0x13c, 0x655: 0x13d, 0x656: 0x71, 0x657: 0x71,
+	0x658: 0x71, 0x659: 0x71, 0x65a: 0x13e, 0x65b: 0x71, 0x65c: 0x71, 0x65d: 0x71, 0x65e: 0x71, 0x65f: 0x13f,
+	0x660: 0x71, 0x661: 0x71, 0x662: 0x71, 0x663: 0x71, 0x664: 0x71, 0x665: 0x71, 0x666: 0x71, 0x667: 0x71,
+	0x668: 0x140, 0x669: 0x141, 0x66a: 0x142,
+	0x67c: 0x143,
+	// Block 0x1a, offset 0x680
+	0x680: 0x144, 0x681: 0x145, 0x682: 0x146, 0x684: 0x147, 0x685: 0x148,
+	0x68a: 0x149, 0x68b: 0x14a,
+	0x693: 0x14b,
+	0x69f: 0x14c,
+	0x6a0: 0x05, 0x6a1: 0x05, 0x6a2: 0x05, 0x6a3: 0x14d, 0x6a4: 0x14e, 0x6a5: 0x14f,
+	0x6b1: 0x150, 0x6b2: 0x151, 0x6b4: 0x152,
+	0x6b8: 0x153, 0x6b9: 0x154, 0x6ba: 0x155, 0x6bb: 0x156,
+	// Block 0x1b, offset 0x6c0
+	0x6c0: 0x157, 0x6c1: 0x71, 0x6c2: 0x158, 0x6c3: 0x159, 0x6c4: 0x71, 0x6c5: 0x71, 0x6c6: 0x145, 0x6c7: 0x15a,
+	0x6c8: 0x15b, 0x6c9: 0x15c, 0x6cc: 0x71, 0x6cd: 0x71, 0x6ce: 0x71, 0x6cf: 0x71,
+	0x6d0: 0x71, 0x6d1: 0x71, 0x6d2: 0x71, 0x6d3: 0x71, 0x6d4: 0x71, 0x6d5: 0x71, 0x6d6: 0x71, 0x6d7: 0x71,
+	0x6d8: 0x71, 0x6d9: 0x71, 0x6da: 0x71, 0x6db: 0x15d, 0x6dc: 0x71, 0x6dd: 0x15e, 0x6de: 0x71, 0x6df: 0x15f,
+	0x6e0: 0x160, 0x6e1: 0x161, 0x6e2: 0x162, 0x6e4: 0x71, 0x6e5: 0x71, 0x6e6: 0x71, 0x6e7: 0x71,
+	0x6e8: 0x71, 0x6e9: 0x163, 0x6ea: 0x164, 0x6eb: 0x165, 0x6ec: 0x71, 0x6ed: 0x71, 0x6ee: 0x166, 0x6ef: 0x167,
+	// Block 0x1c, offset 0x700
+	0x700: 0x8d, 0x701: 0x8d, 0x702: 0x8d, 0x703: 0x8d, 0x704: 0x8d, 0x705: 0x8d, 0x706: 0x8d, 0x707: 0x8d,
+	0x708: 0x8d, 0x709: 0x8d, 0x70a: 0x8d, 0x70b: 0x8d, 0x70c: 0x8d, 0x70d: 0x8d, 0x70e: 0x8d, 0x70f: 0x8d,
+	0x710: 0x8d, 0x711: 0x8d, 0x712: 0x8d, 0x713: 0x8d, 0x714: 0x8d, 0x715: 0x8d, 0x716: 0x8d, 0x717: 0x8d,
+	0x718: 0x8d, 0x719: 0x8d, 0x71a: 0x8d, 0x71b: 0x168, 0x71c: 0x8d, 0x71d: 0x8d, 0x71e: 0x8d, 0x71f: 0x8d,
+	0x720: 0x8d, 0x721: 0x8d, 0x722: 0x8d, 0x723: 0x8d, 0x724: 0x8d, 0x725: 0x8d, 0x726: 0x8d, 0x727: 0x8d,
+	0x728: 0x8d, 0x729: 0x8d, 0x72a: 0x8d, 0x72b: 0x8d, 0x72c: 0x8d, 0x72d: 0x8d, 0x72e: 0x8d, 0x72f: 0x8d,
+	0x730: 0x8d, 0x731: 0x8d, 0x732: 0x8d, 0x733: 0x8d, 0x734: 0x8d, 0x735: 0x8d, 0x736: 0x8d, 0x737: 0x8d,
+	0x738: 0x8d, 0x739: 0x8d, 0x73a: 0x8d, 0x73b: 0x8d, 0x73c: 0x8d, 0x73d: 0x8d, 0x73e: 0x8d, 0x73f: 0x8d,
+	// Block 0x1d, offset 0x740
+	0x740: 0x8d, 0x741: 0x8d, 0x742: 0x8d, 0x743: 0x8d, 0x744: 0x8d, 0x745: 0x8d, 0x746: 0x8d, 0x747: 0x8d,
+	0x748: 0x8d, 0x749: 0x8d, 0x74a: 0x8d, 0x74b: 0x8d, 0x74c: 0x8d, 0x74d: 0x8d, 0x74e: 0x8d, 0x74f: 0x8d,
+	0x750: 0x8d, 0x751: 0x8d, 0x752: 0x8d, 0x753: 0x8d, 0x754: 0x8d, 0x755: 0x8d, 0x756: 0x8d, 0x757: 0x8d,
+	0x758: 0x8d, 0x759: 0x8d, 0x75a: 0x8d, 0x75b: 0x8d, 0x75c: 0x169, 0x75d: 0x8d, 0x75e: 0x8d, 0x75f: 0x8d,
+	0x760: 0x16a, 0x761: 0x8d, 0x762: 0x8d, 0x763: 0x8d, 0x764: 0x8d, 0x765: 0x8d, 0x766: 0x8d, 0x767: 0x8d,
+	0x768: 0x8d, 0x769: 0x8d, 0x76a: 0x8d, 0x76b: 0x8d, 0x76c: 0x8d, 0x76d: 0x8d, 0x76e: 0x8d, 0x76f: 0x8d,
+	0x770: 0x8d, 0x771: 0x8d, 0x772: 0x8d, 0x773: 0x8d, 0x774: 0x8d, 0x775: 0x8d, 0x776: 0x8d, 0x777: 0x8d,
+	0x778: 0x8d, 0x779: 0x8d, 0x77a: 0x8d, 0x77b: 0x8d, 0x77c: 0x8d, 0x77d: 0x8d, 0x77e: 0x8d, 0x77f: 0x8d,
+	// Block 0x1e, offset 0x780
+	0x780: 0x8d, 0x781: 0x8d, 0x782: 0x8d, 0x783: 0x8d, 0x784: 0x8d, 0x785: 0x8d, 0x786: 0x8d, 0x787: 0x8d,
+	0x788: 0x8d, 0x789: 0x8d, 0x78a: 0x8d, 0x78b: 0x8d, 0x78c: 0x8d, 0x78d: 0x8d, 0x78e: 0x8d, 0x78f: 0x8d,
+	0x790: 0x8d, 0x791: 0x8d, 0x792: 0x8d, 0x793: 0x8d, 0x794: 0x8d, 0x795: 0x8d, 0x796: 0x8d, 0x797: 0x8d,
+	0x798: 0x8d, 0x799: 0x8d, 0x79a: 0x8d, 0x79b: 0x8d, 0x79c: 0x8d, 0x79d: 0x8d, 0x79e: 0x8d, 0x79f: 0x8d,
+	0x7a0: 0x8d, 0x7a1: 0x8d, 0x7a2: 0x8d, 0x7a3: 0x8d, 0x7a4: 0x8d, 0x7a5: 0x8d, 0x7a6: 0x8d, 0x7a7: 0x8d,
+	0x7a8: 0x8d, 0x7a9: 0x8d, 0x7aa: 0x8d, 0x7ab: 0x8d, 0x7ac: 0x8d, 0x7ad: 0x8d, 0x7ae: 0x8d, 0x7af: 0x8d,
+	0x7b0: 0x8d, 0x7b1: 0x8d, 0x7b2: 0x8d, 0x7b3: 0x8d, 0x7b4: 0x8d, 0x7b5: 0x8d, 0x7b6: 0x8d, 0x7b7: 0x8d,
+	0x7b8: 0x8d, 0x7b9: 0x8d, 0x7ba: 0x16b, 0x7bb: 0x8d, 0x7bc: 0x8d, 0x7bd: 0x8d, 0x7be: 0x8d, 0x7bf: 0x8d,
+	// Block 0x1f, offset 0x7c0
+	0x7c0: 0x8d, 0x7c1: 0x8d, 0x7c2: 0x8d, 0x7c3: 0x8d, 0x7c4: 0x8d, 0x7c5: 0x8d, 0x7c6: 0x8d, 0x7c7: 0x8d,
+	0x7c8: 0x8d, 0x7c9: 0x8d, 0x7ca: 0x8d, 0x7cb: 0x8d, 0x7cc: 0x8d, 0x7cd: 0x8d, 0x7ce: 0x8d, 0x7cf: 0x8d,
+	0x7d0: 0x8d, 0x7d1: 0x8d, 0x7d2: 0x8d, 0x7d3: 0x8d, 0x7d4: 0x8d, 0x7d5: 0x8d, 0x7d6: 0x8d, 0x7d7: 0x8d,
+	0x7d8: 0x8d, 0x7d9: 0x8d, 0x7da: 0x8d, 0x7db: 0x8d, 0x7dc: 0x8d, 0x7dd: 0x8d, 0x7de: 0x8d, 0x7df: 0x8d,
+	0x7e0: 0x8d, 0x7e1: 0x8d, 0x7e2: 0x8d, 0x7e3: 0x8d, 0x7e4: 0x8d, 0x7e5: 0x8d, 0x7e6: 0x8d, 0x7e7: 0x8d,
+	0x7e8: 0x8d, 0x7e9: 0x8d, 0x7ea: 0x8d, 0x7eb: 0x8d, 0x7ec: 0x8d, 0x7ed: 0x8d, 0x7ee: 0x8d, 0x7ef: 0x16c,
+	// Block 0x20, offset 0x800
+	0x820: 0x80, 0x821: 0x80, 0x822: 0x80, 0x823: 0x80, 0x824: 0x80, 0x825: 0x80, 0x826: 0x80, 0x827: 0x80,
+	0x828: 0x16d,
+	// Block 0x21, offset 0x840
+	0x840: 0x8d, 0x841: 0x8d, 0x842: 0x8d, 0x843: 0x8d, 0x844: 0x8d, 0x845: 0x8d, 0x846: 0x8d, 0x847: 0x8d,
+	0x848: 0x8d, 0x849: 0x8d, 0x84a: 0x8d, 0x84b: 0x8d, 0x84c: 0x8d, 0x84d: 0x16e, 0x84e: 0x8d, 0x84f: 0x8d,
+	0x850: 0x8d, 0x851: 0x8d, 0x852: 0x8d, 0x853: 0x8d, 0x854: 0x8d, 0x855: 0x8d, 0x856: 0x8d, 0x857: 0x8d,
+	0x858: 0x8d, 0x859: 0x8d, 0x85a: 0x8d, 0x85b: 0x8d, 0x85c: 0x8d, 0x85d: 0x8d, 0x85e: 0x8d, 0x85f: 0x8d,
+	0x860: 0x8d, 0x861: 0x8d, 0x862: 0x8d, 0x863: 0x8d, 0x864: 0x8d, 0x865: 0x8d, 0x866: 0x8d, 0x867: 0x8d,
+	0x868: 0x8d, 0x869: 0x8d, 0x86a: 0x8d, 0x86b: 0x8d, 0x86c: 0x8d, 0x86d: 0x8d, 0x86e: 0x8d, 0x86f: 0x8d,
+	0x870: 0x8d, 0x871: 0x8d, 0x872: 0x8d, 0x873: 0x8d, 0x874: 0x8d, 0x875: 0x8d, 0x876: 0x8d, 0x877: 0x8d,
+	0x878: 0x8d, 0x879: 0x8d, 0x87a: 0x8d, 0x87b: 0x8d, 0x87c: 0x8d, 0x87d: 0x8d, 0x87e: 0x8d, 0x87f: 0x8d,
+	// Block 0x22, offset 0x880
+	0x880: 0x8d, 0x881: 0x8d, 0x882: 0x8d, 0x883: 0x8d, 0x884: 0x8d, 0x885: 0x8d, 0x886: 0x8d, 0x887: 0x8d,
+	0x888: 0x8d, 0x889: 0x8d, 0x88a: 0x8d, 0x88b: 0x8d, 0x88c: 0x8d, 0x88d: 0x8d, 0x88e: 0x16f,
+	// Block 0x23, offset 0x8c0
+	0x8d0: 0x0d, 0x8d1: 0x0e, 0x8d2: 0x0f, 0x8d3: 0x10, 0x8d4: 0x11, 0x8d6: 0x12, 0x8d7: 0x09,
+	0x8d8: 0x13, 0x8da: 0x14, 0x8db: 0x15, 0x8dc: 0x16, 0x8dd: 0x17, 0x8de: 0x18, 0x8df: 0x19,
+	0x8e0: 0x07, 0x8e1: 0x07, 0x8e2: 0x07, 0x8e3: 0x07, 0x8e4: 0x07, 0x8e5: 0x07, 0x8e6: 0x07, 0x8e7: 0x07,
+	0x8e8: 0x07, 0x8e9: 0x07, 0x8ea: 0x1a, 0x8eb: 0x1b, 0x8ec: 0x1c, 0x8ed: 0x07, 0x8ee: 0x1d, 0x8ef: 0x1e,
+	0x8f0: 0x07, 0x8f1: 0x1f, 0x8f2: 0x20,
+	// Block 0x24, offset 0x900
+	0x900: 0x170, 0x901: 0x3e, 0x904: 0x3e, 0x905: 0x3e, 0x906: 0x3e, 0x907: 0x171,
+	// Block 0x25, offset 0x940
+	0x940: 0x3e, 0x941: 0x3e, 0x942: 0x3e, 0x943: 0x3e, 0x944: 0x3e, 0x945: 0x3e, 0x946: 0x3e, 0x947: 0x3e,
+	0x948: 0x3e, 0x949: 0x3e, 0x94a: 0x3e, 0x94b: 0x3e, 0x94c: 0x3e, 0x94d: 0x3e, 0x94e: 0x3e, 0x94f: 0x3e,
+	0x950: 0x3e, 0x951: 0x3e, 0x952: 0x3e, 0x953: 0x3e, 0x954: 0x3e, 0x955: 0x3e, 0x956: 0x3e, 0x957: 0x3e,
+	0x958: 0x3e, 0x959: 0x3e, 0x95a: 0x3e, 0x95b: 0x3e, 0x95c: 0x3e, 0x95d: 0x3e, 0x95e: 0x3e, 0x95f: 0x3e,
+	0x960: 0x3e, 0x961: 0x3e, 0x962: 0x3e, 0x963: 0x3e, 0x964: 0x3e, 0x965: 0x3e, 0x966: 0x3e, 0x967: 0x3e,
+	0x968: 0x3e, 0x969: 0x3e, 0x96a: 0x3e, 0x96b: 0x3e, 0x96c: 0x3e, 0x96d: 0x3e, 0x96e: 0x3e, 0x96f: 0x3e,
+	0x970: 0x3e, 0x971: 0x3e, 0x972: 0x3e, 0x973: 0x3e, 0x974: 0x3e, 0x975: 0x3e, 0x976: 0x3e, 0x977: 0x3e,
+	0x978: 0x3e, 0x979: 0x3e, 0x97a: 0x3e, 0x97b: 0x3e, 0x97c: 0x3e, 0x97d: 0x3e, 0x97e: 0x3e, 0x97f: 0x172,
+	// Block 0x26, offset 0x980
+	0x9a0: 0x22,
+	0x9b0: 0x0b, 0x9b1: 0x0b, 0x9b2: 0x0b, 0x9b3: 0x0b, 0x9b4: 0x0b, 0x9b5: 0x0b, 0x9b6: 0x0b, 0x9b7: 0x0b,
+	0x9b8: 0x0b, 0x9b9: 0x0b, 0x9ba: 0x0b, 0x9bb: 0x0b, 0x9bc: 0x0b, 0x9bd: 0x0b, 0x9be: 0x0b, 0x9bf: 0x23,
+	// Block 0x27, offset 0x9c0
+	0x9c0: 0x0b, 0x9c1: 0x0b, 0x9c2: 0x0b, 0x9c3: 0x0b, 0x9c4: 0x0b, 0x9c5: 0x0b, 0x9c6: 0x0b, 0x9c7: 0x0b,
+	0x9c8: 0x0b, 0x9c9: 0x0b, 0x9ca: 0x0b, 0x9cb: 0x0b, 0x9cc: 0x0b, 0x9cd: 0x0b, 0x9ce: 0x0b, 0x9cf: 0x23,
+}
+
+// Total table size 28992 bytes (28KiB); checksum: 811C9DC5
diff --git a/vendor/golang.org/x/text/secure/precis/tables17.0.0.go b/vendor/golang.org/x/text/secure/precis/tables17.0.0.go
new file mode 100644
index 000000000..b2563147a
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/tables17.0.0.go
@@ -0,0 +1,4486 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+//go:build go1.27
+
+package precis
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "17.0.0"
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *derivedPropertiesTrie) lookup(s []byte) (v uint8, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return derivedPropertiesValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = derivedPropertiesIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = derivedPropertiesIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = derivedPropertiesIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *derivedPropertiesTrie) lookupUnsafe(s []byte) uint8 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return derivedPropertiesValues[c0]
+	}
+	i := derivedPropertiesIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *derivedPropertiesTrie) lookupString(s string) (v uint8, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return derivedPropertiesValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = derivedPropertiesIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := derivedPropertiesIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = derivedPropertiesIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = derivedPropertiesIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *derivedPropertiesTrie) lookupStringUnsafe(s string) uint8 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return derivedPropertiesValues[c0]
+	}
+	i := derivedPropertiesIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = derivedPropertiesIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// derivedPropertiesTrie. Total size: 29888 bytes (29.19 KiB). Checksum: 95c6e1fb42cd4aca.
+type derivedPropertiesTrie struct{}
+
+func newDerivedPropertiesTrie(i int) *derivedPropertiesTrie {
+	return &derivedPropertiesTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *derivedPropertiesTrie) lookupValue(n uint32, b byte) uint8 {
+	switch {
+	default:
+		return uint8(derivedPropertiesValues[n<<6+uint32(b)])
+	}
+}
+
+// derivedPropertiesValues: 387 blocks, 24768 entries, 24768 bytes
+// The third block is the zero block.
+var derivedPropertiesValues = [24768]uint8{
+	// Block 0x0, offset 0x0
+	0x00: 0x0040, 0x01: 0x0040, 0x02: 0x0040, 0x03: 0x0040, 0x04: 0x0040, 0x05: 0x0040,
+	0x06: 0x0040, 0x07: 0x0040, 0x08: 0x0040, 0x09: 0x0040, 0x0a: 0x0040, 0x0b: 0x0040,
+	0x0c: 0x0040, 0x0d: 0x0040, 0x0e: 0x0040, 0x0f: 0x0040, 0x10: 0x0040, 0x11: 0x0040,
+	0x12: 0x0040, 0x13: 0x0040, 0x14: 0x0040, 0x15: 0x0040, 0x16: 0x0040, 0x17: 0x0040,
+	0x18: 0x0040, 0x19: 0x0040, 0x1a: 0x0040, 0x1b: 0x0040, 0x1c: 0x0040, 0x1d: 0x0040,
+	0x1e: 0x0040, 0x1f: 0x0040, 0x20: 0x0080, 0x21: 0x00c0, 0x22: 0x00c0, 0x23: 0x00c0,
+	0x24: 0x00c0, 0x25: 0x00c0, 0x26: 0x00c0, 0x27: 0x00c0, 0x28: 0x00c0, 0x29: 0x00c0,
+	0x2a: 0x00c0, 0x2b: 0x00c0, 0x2c: 0x00c0, 0x2d: 0x00c0, 0x2e: 0x00c0, 0x2f: 0x00c0,
+	0x30: 0x00c0, 0x31: 0x00c0, 0x32: 0x00c0, 0x33: 0x00c0, 0x34: 0x00c0, 0x35: 0x00c0,
+	0x36: 0x00c0, 0x37: 0x00c0, 0x38: 0x00c0, 0x39: 0x00c0, 0x3a: 0x00c0, 0x3b: 0x00c0,
+	0x3c: 0x00c0, 0x3d: 0x00c0, 0x3e: 0x00c0, 0x3f: 0x00c0,
+	// Block 0x1, offset 0x40
+	0x40: 0x00c0, 0x41: 0x00c0, 0x42: 0x00c0, 0x43: 0x00c0, 0x44: 0x00c0, 0x45: 0x00c0,
+	0x46: 0x00c0, 0x47: 0x00c0, 0x48: 0x00c0, 0x49: 0x00c0, 0x4a: 0x00c0, 0x4b: 0x00c0,
+	0x4c: 0x00c0, 0x4d: 0x00c0, 0x4e: 0x00c0, 0x4f: 0x00c0, 0x50: 0x00c0, 0x51: 0x00c0,
+	0x52: 0x00c0, 0x53: 0x00c0, 0x54: 0x00c0, 0x55: 0x00c0, 0x56: 0x00c0, 0x57: 0x00c0,
+	0x58: 0x00c0, 0x59: 0x00c0, 0x5a: 0x00c0, 0x5b: 0x00c0, 0x5c: 0x00c0, 0x5d: 0x00c0,
+	0x5e: 0x00c0, 0x5f: 0x00c0, 0x60: 0x00c0, 0x61: 0x00c0, 0x62: 0x00c0, 0x63: 0x00c0,
+	0x64: 0x00c0, 0x65: 0x00c0, 0x66: 0x00c0, 0x67: 0x00c0, 0x68: 0x00c0, 0x69: 0x00c0,
+	0x6a: 0x00c0, 0x6b: 0x00c0, 0x6c: 0x00c7, 0x6d: 0x00c0, 0x6e: 0x00c0, 0x6f: 0x00c0,
+	0x70: 0x00c0, 0x71: 0x00c0, 0x72: 0x00c0, 0x73: 0x00c0, 0x74: 0x00c0, 0x75: 0x00c0,
+	0x76: 0x00c0, 0x77: 0x00c0, 0x78: 0x00c0, 0x79: 0x00c0, 0x7a: 0x00c0, 0x7b: 0x00c0,
+	0x7c: 0x00c0, 0x7d: 0x00c0, 0x7e: 0x00c0, 0x7f: 0x0040,
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc0: 0x0040, 0xc1: 0x0040, 0xc2: 0x0040, 0xc3: 0x0040, 0xc4: 0x0040, 0xc5: 0x0040,
+	0xc6: 0x0040, 0xc7: 0x0040, 0xc8: 0x0040, 0xc9: 0x0040, 0xca: 0x0040, 0xcb: 0x0040,
+	0xcc: 0x0040, 0xcd: 0x0040, 0xce: 0x0040, 0xcf: 0x0040, 0xd0: 0x0040, 0xd1: 0x0040,
+	0xd2: 0x0040, 0xd3: 0x0040, 0xd4: 0x0040, 0xd5: 0x0040, 0xd6: 0x0040, 0xd7: 0x0040,
+	0xd8: 0x0040, 0xd9: 0x0040, 0xda: 0x0040, 0xdb: 0x0040, 0xdc: 0x0040, 0xdd: 0x0040,
+	0xde: 0x0040, 0xdf: 0x0040, 0xe0: 0x0080, 0xe1: 0x0080, 0xe2: 0x0080, 0xe3: 0x0080,
+	0xe4: 0x0080, 0xe5: 0x0080, 0xe6: 0x0080, 0xe7: 0x0080, 0xe8: 0x0080, 0xe9: 0x0080,
+	0xea: 0x0080, 0xeb: 0x0080, 0xec: 0x0080, 0xed: 0x0040, 0xee: 0x0080, 0xef: 0x0080,
+	0xf0: 0x0080, 0xf1: 0x0080, 0xf2: 0x0080, 0xf3: 0x0080, 0xf4: 0x0080, 0xf5: 0x0080,
+	0xf6: 0x0080, 0xf7: 0x004f, 0xf8: 0x0080, 0xf9: 0x0080, 0xfa: 0x0080, 0xfb: 0x0080,
+	0xfc: 0x0080, 0xfd: 0x0080, 0xfe: 0x0080, 0xff: 0x0080,
+	// Block 0x4, offset 0x100
+	0x100: 0x00c0, 0x101: 0x00c0, 0x102: 0x00c0, 0x103: 0x00c0, 0x104: 0x00c0, 0x105: 0x00c0,
+	0x106: 0x00c0, 0x107: 0x00c0, 0x108: 0x00c0, 0x109: 0x00c0, 0x10a: 0x00c0, 0x10b: 0x00c0,
+	0x10c: 0x00c0, 0x10d: 0x00c0, 0x10e: 0x00c0, 0x10f: 0x00c0, 0x110: 0x00c0, 0x111: 0x00c0,
+	0x112: 0x00c0, 0x113: 0x00c0, 0x114: 0x00c0, 0x115: 0x00c0, 0x116: 0x00c0, 0x117: 0x0080,
+	0x118: 0x00c0, 0x119: 0x00c0, 0x11a: 0x00c0, 0x11b: 0x00c0, 0x11c: 0x00c0, 0x11d: 0x00c0,
+	0x11e: 0x00c0, 0x11f: 0x00c0, 0x120: 0x00c0, 0x121: 0x00c0, 0x122: 0x00c0, 0x123: 0x00c0,
+	0x124: 0x00c0, 0x125: 0x00c0, 0x126: 0x00c0, 0x127: 0x00c0, 0x128: 0x00c0, 0x129: 0x00c0,
+	0x12a: 0x00c0, 0x12b: 0x00c0, 0x12c: 0x00c0, 0x12d: 0x00c0, 0x12e: 0x00c0, 0x12f: 0x00c0,
+	0x130: 0x00c0, 0x131: 0x00c0, 0x132: 0x00c0, 0x133: 0x00c0, 0x134: 0x00c0, 0x135: 0x00c0,
+	0x136: 0x00c0, 0x137: 0x0080, 0x138: 0x00c0, 0x139: 0x00c0, 0x13a: 0x00c0, 0x13b: 0x00c0,
+	0x13c: 0x00c0, 0x13d: 0x00c0, 0x13e: 0x00c0, 0x13f: 0x00c0,
+	// Block 0x5, offset 0x140
+	0x140: 0x00c0, 0x141: 0x00c0, 0x142: 0x00c0, 0x143: 0x00c0, 0x144: 0x00c0, 0x145: 0x00c0,
+	0x146: 0x00c0, 0x147: 0x00c0, 0x148: 0x00c0, 0x149: 0x00c0, 0x14a: 0x00c0, 0x14b: 0x00c0,
+	0x14c: 0x00c0, 0x14d: 0x00c0, 0x14e: 0x00c0, 0x14f: 0x00c0, 0x150: 0x00c0, 0x151: 0x00c0,
+	0x152: 0x00c0, 0x153: 0x00c0, 0x154: 0x00c0, 0x155: 0x00c0, 0x156: 0x00c0, 0x157: 0x00c0,
+	0x158: 0x00c0, 0x159: 0x00c0, 0x15a: 0x00c0, 0x15b: 0x00c0, 0x15c: 0x00c0, 0x15d: 0x00c0,
+	0x15e: 0x00c0, 0x15f: 0x00c0, 0x160: 0x00c0, 0x161: 0x00c0, 0x162: 0x00c0, 0x163: 0x00c0,
+	0x164: 0x00c0, 0x165: 0x00c0, 0x166: 0x00c0, 0x167: 0x00c0, 0x168: 0x00c0, 0x169: 0x00c0,
+	0x16a: 0x00c0, 0x16b: 0x00c0, 0x16c: 0x00c0, 0x16d: 0x00c0, 0x16e: 0x00c0, 0x16f: 0x00c0,
+	0x170: 0x00c0, 0x171: 0x00c0, 0x172: 0x0080, 0x173: 0x0080, 0x174: 0x00c0, 0x175: 0x00c0,
+	0x176: 0x00c0, 0x177: 0x00c0, 0x178: 0x00c0, 0x179: 0x00c0, 0x17a: 0x00c0, 0x17b: 0x00c0,
+	0x17c: 0x00c0, 0x17d: 0x00c0, 0x17e: 0x00c0, 0x17f: 0x0080,
+	// Block 0x6, offset 0x180
+	0x180: 0x0080, 0x181: 0x00c0, 0x182: 0x00c0, 0x183: 0x00c0, 0x184: 0x00c0, 0x185: 0x00c0,
+	0x186: 0x00c0, 0x187: 0x00c0, 0x188: 0x00c0, 0x189: 0x0080, 0x18a: 0x00c0, 0x18b: 0x00c0,
+	0x18c: 0x00c0, 0x18d: 0x00c0, 0x18e: 0x00c0, 0x18f: 0x00c0, 0x190: 0x00c0, 0x191: 0x00c0,
+	0x192: 0x00c0, 0x193: 0x00c0, 0x194: 0x00c0, 0x195: 0x00c0, 0x196: 0x00c0, 0x197: 0x00c0,
+	0x198: 0x00c0, 0x199: 0x00c0, 0x19a: 0x00c0, 0x19b: 0x00c0, 0x19c: 0x00c0, 0x19d: 0x00c0,
+	0x19e: 0x00c0, 0x19f: 0x00c0, 0x1a0: 0x00c0, 0x1a1: 0x00c0, 0x1a2: 0x00c0, 0x1a3: 0x00c0,
+	0x1a4: 0x00c0, 0x1a5: 0x00c0, 0x1a6: 0x00c0, 0x1a7: 0x00c0, 0x1a8: 0x00c0, 0x1a9: 0x00c0,
+	0x1aa: 0x00c0, 0x1ab: 0x00c0, 0x1ac: 0x00c0, 0x1ad: 0x00c0, 0x1ae: 0x00c0, 0x1af: 0x00c0,
+	0x1b0: 0x00c0, 0x1b1: 0x00c0, 0x1b2: 0x00c0, 0x1b3: 0x00c0, 0x1b4: 0x00c0, 0x1b5: 0x00c0,
+	0x1b6: 0x00c0, 0x1b7: 0x00c0, 0x1b8: 0x00c0, 0x1b9: 0x00c0, 0x1ba: 0x00c0, 0x1bb: 0x00c0,
+	0x1bc: 0x00c0, 0x1bd: 0x00c0, 0x1be: 0x00c0, 0x1bf: 0x0080,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x00c0, 0x1c1: 0x00c0, 0x1c2: 0x00c0, 0x1c3: 0x00c0, 0x1c4: 0x00c0, 0x1c5: 0x00c0,
+	0x1c6: 0x00c0, 0x1c7: 0x00c0, 0x1c8: 0x00c0, 0x1c9: 0x00c0, 0x1ca: 0x00c0, 0x1cb: 0x00c0,
+	0x1cc: 0x00c0, 0x1cd: 0x00c0, 0x1ce: 0x00c0, 0x1cf: 0x00c0, 0x1d0: 0x00c0, 0x1d1: 0x00c0,
+	0x1d2: 0x00c0, 0x1d3: 0x00c0, 0x1d4: 0x00c0, 0x1d5: 0x00c0, 0x1d6: 0x00c0, 0x1d7: 0x00c0,
+	0x1d8: 0x00c0, 0x1d9: 0x00c0, 0x1da: 0x00c0, 0x1db: 0x00c0, 0x1dc: 0x00c0, 0x1dd: 0x00c0,
+	0x1de: 0x00c0, 0x1df: 0x00c0, 0x1e0: 0x00c0, 0x1e1: 0x00c0, 0x1e2: 0x00c0, 0x1e3: 0x00c0,
+	0x1e4: 0x00c0, 0x1e5: 0x00c0, 0x1e6: 0x00c0, 0x1e7: 0x00c0, 0x1e8: 0x00c0, 0x1e9: 0x00c0,
+	0x1ea: 0x00c0, 0x1eb: 0x00c0, 0x1ec: 0x00c0, 0x1ed: 0x00c0, 0x1ee: 0x00c0, 0x1ef: 0x00c0,
+	0x1f0: 0x00c0, 0x1f1: 0x00c0, 0x1f2: 0x00c0, 0x1f3: 0x00c0, 0x1f4: 0x00c0, 0x1f5: 0x00c0,
+	0x1f6: 0x00c0, 0x1f7: 0x00c0, 0x1f8: 0x00c0, 0x1f9: 0x00c0, 0x1fa: 0x00c0, 0x1fb: 0x00c0,
+	0x1fc: 0x00c0, 0x1fd: 0x00c0, 0x1fe: 0x00c0, 0x1ff: 0x00c0,
+	// Block 0x8, offset 0x200
+	0x200: 0x00c0, 0x201: 0x00c0, 0x202: 0x00c0, 0x203: 0x00c0, 0x204: 0x0080, 0x205: 0x0080,
+	0x206: 0x0080, 0x207: 0x0080, 0x208: 0x0080, 0x209: 0x0080, 0x20a: 0x0080, 0x20b: 0x0080,
+	0x20c: 0x0080, 0x20d: 0x00c0, 0x20e: 0x00c0, 0x20f: 0x00c0, 0x210: 0x00c0, 0x211: 0x00c0,
+	0x212: 0x00c0, 0x213: 0x00c0, 0x214: 0x00c0, 0x215: 0x00c0, 0x216: 0x00c0, 0x217: 0x00c0,
+	0x218: 0x00c0, 0x219: 0x00c0, 0x21a: 0x00c0, 0x21b: 0x00c0, 0x21c: 0x00c0, 0x21d: 0x00c0,
+	0x21e: 0x00c0, 0x21f: 0x00c0, 0x220: 0x00c0, 0x221: 0x00c0, 0x222: 0x00c0, 0x223: 0x00c0,
+	0x224: 0x00c0, 0x225: 0x00c0, 0x226: 0x00c0, 0x227: 0x00c0, 0x228: 0x00c0, 0x229: 0x00c0,
+	0x22a: 0x00c0, 0x22b: 0x00c0, 0x22c: 0x00c0, 0x22d: 0x00c0, 0x22e: 0x00c0, 0x22f: 0x00c0,
+	0x230: 0x00c0, 0x231: 0x0080, 0x232: 0x0080, 0x233: 0x0080, 0x234: 0x00c0, 0x235: 0x00c0,
+	0x236: 0x00c0, 0x237: 0x00c0, 0x238: 0x00c0, 0x239: 0x00c0, 0x23a: 0x00c0, 0x23b: 0x00c0,
+	0x23c: 0x00c0, 0x23d: 0x00c0, 0x23e: 0x00c0, 0x23f: 0x00c0,
+	// Block 0x9, offset 0x240
+	0x240: 0x00c0, 0x241: 0x00c0, 0x242: 0x00c0, 0x243: 0x00c0, 0x244: 0x00c0, 0x245: 0x00c0,
+	0x246: 0x00c0, 0x247: 0x00c0, 0x248: 0x00c0, 0x249: 0x00c0, 0x24a: 0x00c0, 0x24b: 0x00c0,
+	0x24c: 0x00c0, 0x24d: 0x00c0, 0x24e: 0x00c0, 0x24f: 0x00c0, 0x250: 0x00c0, 0x251: 0x00c0,
+	0x252: 0x00c0, 0x253: 0x00c0, 0x254: 0x00c0, 0x255: 0x00c0, 0x256: 0x00c0, 0x257: 0x00c0,
+	0x258: 0x00c0, 0x259: 0x00c0, 0x25a: 0x00c0, 0x25b: 0x00c0, 0x25c: 0x00c0, 0x25d: 0x00c0,
+	0x25e: 0x00c0, 0x25f: 0x00c0, 0x260: 0x00c0, 0x261: 0x00c0, 0x262: 0x00c0, 0x263: 0x00c0,
+	0x264: 0x00c0, 0x265: 0x00c0, 0x266: 0x00c0, 0x267: 0x00c0, 0x268: 0x00c0, 0x269: 0x00c0,
+	0x26a: 0x00c0, 0x26b: 0x00c0, 0x26c: 0x00c0, 0x26d: 0x00c0, 0x26e: 0x00c0, 0x26f: 0x00c0,
+	0x270: 0x0080, 0x271: 0x0080, 0x272: 0x0080, 0x273: 0x0080, 0x274: 0x0080, 0x275: 0x0080,
+	0x276: 0x0080, 0x277: 0x0080, 0x278: 0x0080, 0x279: 0x00c0, 0x27a: 0x00c0, 0x27b: 0x00c0,
+	0x27c: 0x00c0, 0x27d: 0x00c0, 0x27e: 0x00c0, 0x27f: 0x00c0,
+	// Block 0xa, offset 0x280
+	0x280: 0x00c0, 0x281: 0x00c0, 0x282: 0x0080, 0x283: 0x0080, 0x284: 0x0080, 0x285: 0x0080,
+	0x286: 0x00c0, 0x287: 0x00c0, 0x288: 0x00c0, 0x289: 0x00c0, 0x28a: 0x00c0, 0x28b: 0x00c0,
+	0x28c: 0x00c0, 0x28d: 0x00c0, 0x28e: 0x00c0, 0x28f: 0x00c0, 0x290: 0x00c0, 0x291: 0x00c0,
+	0x292: 0x0080, 0x293: 0x0080, 0x294: 0x0080, 0x295: 0x0080, 0x296: 0x0080, 0x297: 0x0080,
+	0x298: 0x0080, 0x299: 0x0080, 0x29a: 0x0080, 0x29b: 0x0080, 0x29c: 0x0080, 0x29d: 0x0080,
+	0x29e: 0x0080, 0x29f: 0x0080, 0x2a0: 0x0080, 0x2a1: 0x0080, 0x2a2: 0x0080, 0x2a3: 0x0080,
+	0x2a4: 0x0080, 0x2a5: 0x0080, 0x2a6: 0x0080, 0x2a7: 0x0080, 0x2a8: 0x0080, 0x2a9: 0x0080,
+	0x2aa: 0x0080, 0x2ab: 0x0080, 0x2ac: 0x00c0, 0x2ad: 0x0080, 0x2ae: 0x00c0, 0x2af: 0x0080,
+	0x2b0: 0x0080, 0x2b1: 0x0080, 0x2b2: 0x0080, 0x2b3: 0x0080, 0x2b4: 0x0080, 0x2b5: 0x0080,
+	0x2b6: 0x0080, 0x2b7: 0x0080, 0x2b8: 0x0080, 0x2b9: 0x0080, 0x2ba: 0x0080, 0x2bb: 0x0080,
+	0x2bc: 0x0080, 0x2bd: 0x0080, 0x2be: 0x0080, 0x2bf: 0x0080,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x00c3, 0x2c1: 0x00c3, 0x2c2: 0x00c3, 0x2c3: 0x00c3, 0x2c4: 0x00c3, 0x2c5: 0x00c3,
+	0x2c6: 0x00c3, 0x2c7: 0x00c3, 0x2c8: 0x00c3, 0x2c9: 0x00c3, 0x2ca: 0x00c3, 0x2cb: 0x00c3,
+	0x2cc: 0x00c3, 0x2cd: 0x00c3, 0x2ce: 0x00c3, 0x2cf: 0x00c3, 0x2d0: 0x00c3, 0x2d1: 0x00c3,
+	0x2d2: 0x00c3, 0x2d3: 0x00c3, 0x2d4: 0x00c3, 0x2d5: 0x00c3, 0x2d6: 0x00c3, 0x2d7: 0x00c3,
+	0x2d8: 0x00c3, 0x2d9: 0x00c3, 0x2da: 0x00c3, 0x2db: 0x00c3, 0x2dc: 0x00c3, 0x2dd: 0x00c3,
+	0x2de: 0x00c3, 0x2df: 0x00c3, 0x2e0: 0x00c3, 0x2e1: 0x00c3, 0x2e2: 0x00c3, 0x2e3: 0x00c3,
+	0x2e4: 0x00c3, 0x2e5: 0x00c3, 0x2e6: 0x00c3, 0x2e7: 0x00c3, 0x2e8: 0x00c3, 0x2e9: 0x00c3,
+	0x2ea: 0x00c3, 0x2eb: 0x00c3, 0x2ec: 0x00c3, 0x2ed: 0x00c3, 0x2ee: 0x00c3, 0x2ef: 0x00c3,
+	0x2f0: 0x00c3, 0x2f1: 0x00c3, 0x2f2: 0x00c3, 0x2f3: 0x00c3, 0x2f4: 0x00c3, 0x2f5: 0x00c3,
+	0x2f6: 0x00c3, 0x2f7: 0x00c3, 0x2f8: 0x00c3, 0x2f9: 0x00c3, 0x2fa: 0x00c3, 0x2fb: 0x00c3,
+	0x2fc: 0x00c3, 0x2fd: 0x00c3, 0x2fe: 0x00c3, 0x2ff: 0x00c3,
+	// Block 0xc, offset 0x300
+	0x300: 0x0083, 0x301: 0x0083, 0x302: 0x00c3, 0x303: 0x0083, 0x304: 0x0083, 0x305: 0x00c3,
+	0x306: 0x00c3, 0x307: 0x00c3, 0x308: 0x00c3, 0x309: 0x00c3, 0x30a: 0x00c3, 0x30b: 0x00c3,
+	0x30c: 0x00c3, 0x30d: 0x00c3, 0x30e: 0x00c3, 0x30f: 0x0040, 0x310: 0x00c3, 0x311: 0x00c3,
+	0x312: 0x00c3, 0x313: 0x00c3, 0x314: 0x00c3, 0x315: 0x00c3, 0x316: 0x00c3, 0x317: 0x00c3,
+	0x318: 0x00c3, 0x319: 0x00c3, 0x31a: 0x00c3, 0x31b: 0x00c3, 0x31c: 0x00c3, 0x31d: 0x00c3,
+	0x31e: 0x00c3, 0x31f: 0x00c3, 0x320: 0x00c3, 0x321: 0x00c3, 0x322: 0x00c3, 0x323: 0x00c3,
+	0x324: 0x00c3, 0x325: 0x00c3, 0x326: 0x00c3, 0x327: 0x00c3, 0x328: 0x00c3, 0x329: 0x00c3,
+	0x32a: 0x00c3, 0x32b: 0x00c3, 0x32c: 0x00c3, 0x32d: 0x00c3, 0x32e: 0x00c3, 0x32f: 0x00c3,
+	0x330: 0x00c8, 0x331: 0x00c8, 0x332: 0x00c8, 0x333: 0x00c8, 0x334: 0x0080, 0x335: 0x0050,
+	0x336: 0x00c8, 0x337: 0x00c8, 0x33a: 0x0088, 0x33b: 0x00c8,
+	0x33c: 0x00c8, 0x33d: 0x00c8, 0x33e: 0x0080, 0x33f: 0x00c8,
+	// Block 0xd, offset 0x340
+	0x344: 0x0088, 0x345: 0x0080,
+	0x346: 0x00c8, 0x347: 0x0080, 0x348: 0x00c8, 0x349: 0x00c8, 0x34a: 0x00c8,
+	0x34c: 0x00c8, 0x34e: 0x00c8, 0x34f: 0x00c8, 0x350: 0x00c8, 0x351: 0x00c8,
+	0x352: 0x00c8, 0x353: 0x00c8, 0x354: 0x00c8, 0x355: 0x00c8, 0x356: 0x00c8, 0x357: 0x00c8,
+	0x358: 0x00c8, 0x359: 0x00c8, 0x35a: 0x00c8, 0x35b: 0x00c8, 0x35c: 0x00c8, 0x35d: 0x00c8,
+	0x35e: 0x00c8, 0x35f: 0x00c8, 0x360: 0x00c8, 0x361: 0x00c8, 0x363: 0x00c8,
+	0x364: 0x00c8, 0x365: 0x00c8, 0x366: 0x00c8, 0x367: 0x00c8, 0x368: 0x00c8, 0x369: 0x00c8,
+	0x36a: 0x00c8, 0x36b: 0x00c8, 0x36c: 0x00c8, 0x36d: 0x00c8, 0x36e: 0x00c8, 0x36f: 0x00c8,
+	0x370: 0x00c8, 0x371: 0x00c8, 0x372: 0x00c8, 0x373: 0x00c8, 0x374: 0x00c8, 0x375: 0x00c8,
+	0x376: 0x00c8, 0x377: 0x00c8, 0x378: 0x00c8, 0x379: 0x00c8, 0x37a: 0x00c8, 0x37b: 0x00c8,
+	0x37c: 0x00c8, 0x37d: 0x00c8, 0x37e: 0x00c8, 0x37f: 0x00c8,
+	// Block 0xe, offset 0x380
+	0x380: 0x00c8, 0x381: 0x00c8, 0x382: 0x00c8, 0x383: 0x00c8, 0x384: 0x00c8, 0x385: 0x00c8,
+	0x386: 0x00c8, 0x387: 0x00c8, 0x388: 0x00c8, 0x389: 0x00c8, 0x38a: 0x00c8, 0x38b: 0x00c8,
+	0x38c: 0x00c8, 0x38d: 0x00c8, 0x38e: 0x00c8, 0x38f: 0x00c8, 0x390: 0x0088, 0x391: 0x0088,
+	0x392: 0x0088, 0x393: 0x0088, 0x394: 0x0088, 0x395: 0x0088, 0x396: 0x0088, 0x397: 0x00c8,
+	0x398: 0x00c8, 0x399: 0x00c8, 0x39a: 0x00c8, 0x39b: 0x00c8, 0x39c: 0x00c8, 0x39d: 0x00c8,
+	0x39e: 0x00c8, 0x39f: 0x00c8, 0x3a0: 0x00c8, 0x3a1: 0x00c8, 0x3a2: 0x00c0, 0x3a3: 0x00c0,
+	0x3a4: 0x00c0, 0x3a5: 0x00c0, 0x3a6: 0x00c0, 0x3a7: 0x00c0, 0x3a8: 0x00c0, 0x3a9: 0x00c0,
+	0x3aa: 0x00c0, 0x3ab: 0x00c0, 0x3ac: 0x00c0, 0x3ad: 0x00c0, 0x3ae: 0x00c0, 0x3af: 0x00c0,
+	0x3b0: 0x0088, 0x3b1: 0x0088, 0x3b2: 0x0088, 0x3b3: 0x00c8, 0x3b4: 0x0088, 0x3b5: 0x0088,
+	0x3b6: 0x0088, 0x3b7: 0x00c8, 0x3b8: 0x00c8, 0x3b9: 0x0088, 0x3ba: 0x00c8, 0x3bb: 0x00c8,
+	0x3bc: 0x00c8, 0x3bd: 0x00c8, 0x3be: 0x00c8, 0x3bf: 0x00c8,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x00c0, 0x3c1: 0x00c0, 0x3c2: 0x0080, 0x3c3: 0x00c3, 0x3c4: 0x00c3, 0x3c5: 0x00c3,
+	0x3c6: 0x00c3, 0x3c7: 0x00c3, 0x3c8: 0x0083, 0x3c9: 0x0083, 0x3ca: 0x00c0, 0x3cb: 0x00c0,
+	0x3cc: 0x00c0, 0x3cd: 0x00c0, 0x3ce: 0x00c0, 0x3cf: 0x00c0, 0x3d0: 0x00c0, 0x3d1: 0x00c0,
+	0x3d2: 0x00c0, 0x3d3: 0x00c0, 0x3d4: 0x00c0, 0x3d5: 0x00c0, 0x3d6: 0x00c0, 0x3d7: 0x00c0,
+	0x3d8: 0x00c0, 0x3d9: 0x00c0, 0x3da: 0x00c0, 0x3db: 0x00c0, 0x3dc: 0x00c0, 0x3dd: 0x00c0,
+	0x3de: 0x00c0, 0x3df: 0x00c0, 0x3e0: 0x00c0, 0x3e1: 0x00c0, 0x3e2: 0x00c0, 0x3e3: 0x00c0,
+	0x3e4: 0x00c0, 0x3e5: 0x00c0, 0x3e6: 0x00c0, 0x3e7: 0x00c0, 0x3e8: 0x00c0, 0x3e9: 0x00c0,
+	0x3ea: 0x00c0, 0x3eb: 0x00c0, 0x3ec: 0x00c0, 0x3ed: 0x00c0, 0x3ee: 0x00c0, 0x3ef: 0x00c0,
+	0x3f0: 0x00c0, 0x3f1: 0x00c0, 0x3f2: 0x00c0, 0x3f3: 0x00c0, 0x3f4: 0x00c0, 0x3f5: 0x00c0,
+	0x3f6: 0x00c0, 0x3f7: 0x00c0, 0x3f8: 0x00c0, 0x3f9: 0x00c0, 0x3fa: 0x00c0, 0x3fb: 0x00c0,
+	0x3fc: 0x00c0, 0x3fd: 0x00c0, 0x3fe: 0x00c0, 0x3ff: 0x00c0,
+	// Block 0x10, offset 0x400
+	0x400: 0x00c0, 0x401: 0x00c0, 0x402: 0x00c0, 0x403: 0x00c0, 0x404: 0x00c0, 0x405: 0x00c0,
+	0x406: 0x00c0, 0x407: 0x00c0, 0x408: 0x00c0, 0x409: 0x00c0, 0x40a: 0x00c0, 0x40b: 0x00c0,
+	0x40c: 0x00c0, 0x40d: 0x00c0, 0x40e: 0x00c0, 0x40f: 0x00c0, 0x410: 0x00c0, 0x411: 0x00c0,
+	0x412: 0x00c0, 0x413: 0x00c0, 0x414: 0x00c0, 0x415: 0x00c0, 0x416: 0x00c0, 0x417: 0x00c0,
+	0x418: 0x00c0, 0x419: 0x00c0, 0x41a: 0x00c0, 0x41b: 0x00c0, 0x41c: 0x00c0, 0x41d: 0x00c0,
+	0x41e: 0x00c0, 0x41f: 0x00c0, 0x420: 0x00c0, 0x421: 0x00c0, 0x422: 0x00c0, 0x423: 0x00c0,
+	0x424: 0x00c0, 0x425: 0x00c0, 0x426: 0x00c0, 0x427: 0x00c0, 0x428: 0x00c0, 0x429: 0x00c0,
+	0x42a: 0x00c0, 0x42b: 0x00c0, 0x42c: 0x00c0, 0x42d: 0x00c0, 0x42e: 0x00c0, 0x42f: 0x00c0,
+	0x431: 0x00c0, 0x432: 0x00c0, 0x433: 0x00c0, 0x434: 0x00c0, 0x435: 0x00c0,
+	0x436: 0x00c0, 0x437: 0x00c0, 0x438: 0x00c0, 0x439: 0x00c0, 0x43a: 0x00c0, 0x43b: 0x00c0,
+	0x43c: 0x00c0, 0x43d: 0x00c0, 0x43e: 0x00c0, 0x43f: 0x00c0,
+	// Block 0x11, offset 0x440
+	0x440: 0x00c0, 0x441: 0x00c0, 0x442: 0x00c0, 0x443: 0x00c0, 0x444: 0x00c0, 0x445: 0x00c0,
+	0x446: 0x00c0, 0x447: 0x00c0, 0x448: 0x00c0, 0x449: 0x00c0, 0x44a: 0x00c0, 0x44b: 0x00c0,
+	0x44c: 0x00c0, 0x44d: 0x00c0, 0x44e: 0x00c0, 0x44f: 0x00c0, 0x450: 0x00c0, 0x451: 0x00c0,
+	0x452: 0x00c0, 0x453: 0x00c0, 0x454: 0x00c0, 0x455: 0x00c0, 0x456: 0x00c0,
+	0x459: 0x00c0, 0x45a: 0x0080, 0x45b: 0x0080, 0x45c: 0x0080, 0x45d: 0x0080,
+	0x45e: 0x0080, 0x45f: 0x0080, 0x460: 0x00c0, 0x461: 0x00c0, 0x462: 0x00c0, 0x463: 0x00c0,
+	0x464: 0x00c0, 0x465: 0x00c0, 0x466: 0x00c0, 0x467: 0x00c0, 0x468: 0x00c0, 0x469: 0x00c0,
+	0x46a: 0x00c0, 0x46b: 0x00c0, 0x46c: 0x00c0, 0x46d: 0x00c0, 0x46e: 0x00c0, 0x46f: 0x00c0,
+	0x470: 0x00c0, 0x471: 0x00c0, 0x472: 0x00c0, 0x473: 0x00c0, 0x474: 0x00c0, 0x475: 0x00c0,
+	0x476: 0x00c0, 0x477: 0x00c0, 0x478: 0x00c0, 0x479: 0x00c0, 0x47a: 0x00c0, 0x47b: 0x00c0,
+	0x47c: 0x00c0, 0x47d: 0x00c0, 0x47e: 0x00c0, 0x47f: 0x00c0,
+	// Block 0x12, offset 0x480
+	0x480: 0x00c0, 0x481: 0x00c0, 0x482: 0x00c0, 0x483: 0x00c0, 0x484: 0x00c0, 0x485: 0x00c0,
+	0x486: 0x00c0, 0x487: 0x0080, 0x488: 0x00c0, 0x489: 0x0080, 0x48a: 0x0080,
+	0x48d: 0x0080, 0x48e: 0x0080, 0x48f: 0x0080, 0x491: 0x00cb,
+	0x492: 0x00cb, 0x493: 0x00cb, 0x494: 0x00cb, 0x495: 0x00cb, 0x496: 0x00cb, 0x497: 0x00cb,
+	0x498: 0x00cb, 0x499: 0x00cb, 0x49a: 0x00cb, 0x49b: 0x00cb, 0x49c: 0x00cb, 0x49d: 0x00cb,
+	0x49e: 0x00cb, 0x49f: 0x00cb, 0x4a0: 0x00cb, 0x4a1: 0x00cb, 0x4a2: 0x00cb, 0x4a3: 0x00cb,
+	0x4a4: 0x00cb, 0x4a5: 0x00cb, 0x4a6: 0x00cb, 0x4a7: 0x00cb, 0x4a8: 0x00cb, 0x4a9: 0x00cb,
+	0x4aa: 0x00cb, 0x4ab: 0x00cb, 0x4ac: 0x00cb, 0x4ad: 0x00cb, 0x4ae: 0x00cb, 0x4af: 0x00cb,
+	0x4b0: 0x00cb, 0x4b1: 0x00cb, 0x4b2: 0x00cb, 0x4b3: 0x00cb, 0x4b4: 0x00cb, 0x4b5: 0x00cb,
+	0x4b6: 0x00cb, 0x4b7: 0x00cb, 0x4b8: 0x00cb, 0x4b9: 0x00cb, 0x4ba: 0x00cb, 0x4bb: 0x00cb,
+	0x4bc: 0x00cb, 0x4bd: 0x00cb, 0x4be: 0x008a, 0x4bf: 0x00cb,
+	// Block 0x13, offset 0x4c0
+	0x4c0: 0x008a, 0x4c1: 0x00cb, 0x4c2: 0x00cb, 0x4c3: 0x008a, 0x4c4: 0x00cb, 0x4c5: 0x00cb,
+	0x4c6: 0x008a, 0x4c7: 0x00cb,
+	0x4d0: 0x00ca, 0x4d1: 0x00ca,
+	0x4d2: 0x00ca, 0x4d3: 0x00ca, 0x4d4: 0x00ca, 0x4d5: 0x00ca, 0x4d6: 0x00ca, 0x4d7: 0x00ca,
+	0x4d8: 0x00ca, 0x4d9: 0x00ca, 0x4da: 0x00ca, 0x4db: 0x00ca, 0x4dc: 0x00ca, 0x4dd: 0x00ca,
+	0x4de: 0x00ca, 0x4df: 0x00ca, 0x4e0: 0x00ca, 0x4e1: 0x00ca, 0x4e2: 0x00ca, 0x4e3: 0x00ca,
+	0x4e4: 0x00ca, 0x4e5: 0x00ca, 0x4e6: 0x00ca, 0x4e7: 0x00ca, 0x4e8: 0x00ca, 0x4e9: 0x00ca,
+	0x4ea: 0x00ca, 0x4ef: 0x00ca,
+	0x4f0: 0x00ca, 0x4f1: 0x00ca, 0x4f2: 0x00ca, 0x4f3: 0x0051, 0x4f4: 0x0051,
+	// Block 0x14, offset 0x500
+	0x500: 0x0040, 0x501: 0x0040, 0x502: 0x0040, 0x503: 0x0040, 0x504: 0x0040, 0x505: 0x0040,
+	0x506: 0x0080, 0x507: 0x0080, 0x508: 0x0080, 0x509: 0x0080, 0x50a: 0x0080, 0x50b: 0x0080,
+	0x50c: 0x0080, 0x50d: 0x0080, 0x50e: 0x0080, 0x50f: 0x0080, 0x510: 0x00c3, 0x511: 0x00c3,
+	0x512: 0x00c3, 0x513: 0x00c3, 0x514: 0x00c3, 0x515: 0x00c3, 0x516: 0x00c3, 0x517: 0x00c3,
+	0x518: 0x00c3, 0x519: 0x00c3, 0x51a: 0x00c3, 0x51b: 0x0080, 0x51c: 0x0040, 0x51d: 0x0080,
+	0x51e: 0x0080, 0x51f: 0x0080, 0x520: 0x00c2, 0x521: 0x00c0, 0x522: 0x00c4, 0x523: 0x00c4,
+	0x524: 0x00c4, 0x525: 0x00c4, 0x526: 0x00c2, 0x527: 0x00c4, 0x528: 0x00c2, 0x529: 0x00c4,
+	0x52a: 0x00c2, 0x52b: 0x00c2, 0x52c: 0x00c2, 0x52d: 0x00c2, 0x52e: 0x00c2, 0x52f: 0x00c4,
+	0x530: 0x00c4, 0x531: 0x00c4, 0x532: 0x00c4, 0x533: 0x00c2, 0x534: 0x00c2, 0x535: 0x00c2,
+	0x536: 0x00c2, 0x537: 0x00c2, 0x538: 0x00c2, 0x539: 0x00c2, 0x53a: 0x00c2, 0x53b: 0x00c2,
+	0x53c: 0x00c2, 0x53d: 0x00c2, 0x53e: 0x00c2, 0x53f: 0x00c2,
+	// Block 0x15, offset 0x540
+	0x540: 0x0040, 0x541: 0x00c2, 0x542: 0x00c2, 0x543: 0x00c2, 0x544: 0x00c2, 0x545: 0x00c2,
+	0x546: 0x00c2, 0x547: 0x00c2, 0x548: 0x00c4, 0x549: 0x00c2, 0x54a: 0x00c2, 0x54b: 0x00c3,
+	0x54c: 0x00c3, 0x54d: 0x00c3, 0x54e: 0x00c3, 0x54f: 0x00c3, 0x550: 0x00c3, 0x551: 0x00c3,
+	0x552: 0x00c3, 0x553: 0x00c3, 0x554: 0x00c3, 0x555: 0x00c3, 0x556: 0x00c3, 0x557: 0x00c3,
+	0x558: 0x00c3, 0x559: 0x00c3, 0x55a: 0x00c3, 0x55b: 0x00c3, 0x55c: 0x00c3, 0x55d: 0x00c3,
+	0x55e: 0x00c3, 0x55f: 0x00c3, 0x560: 0x0053, 0x561: 0x0053, 0x562: 0x0053, 0x563: 0x0053,
+	0x564: 0x0053, 0x565: 0x0053, 0x566: 0x0053, 0x567: 0x0053, 0x568: 0x0053, 0x569: 0x0053,
+	0x56a: 0x0080, 0x56b: 0x0080, 0x56c: 0x0080, 0x56d: 0x0080, 0x56e: 0x00c2, 0x56f: 0x00c2,
+	0x570: 0x00c3, 0x571: 0x00c4, 0x572: 0x00c4, 0x573: 0x00c4, 0x574: 0x00c0, 0x575: 0x0084,
+	0x576: 0x0084, 0x577: 0x0084, 0x578: 0x0082, 0x579: 0x00c2, 0x57a: 0x00c2, 0x57b: 0x00c2,
+	0x57c: 0x00c2, 0x57d: 0x00c2, 0x57e: 0x00c2, 0x57f: 0x00c2,
+	// Block 0x16, offset 0x580
+	0x580: 0x00c2, 0x581: 0x00c2, 0x582: 0x00c2, 0x583: 0x00c2, 0x584: 0x00c2, 0x585: 0x00c2,
+	0x586: 0x00c2, 0x587: 0x00c2, 0x588: 0x00c4, 0x589: 0x00c4, 0x58a: 0x00c4, 0x58b: 0x00c4,
+	0x58c: 0x00c4, 0x58d: 0x00c4, 0x58e: 0x00c4, 0x58f: 0x00c4, 0x590: 0x00c4, 0x591: 0x00c4,
+	0x592: 0x00c4, 0x593: 0x00c4, 0x594: 0x00c4, 0x595: 0x00c4, 0x596: 0x00c4, 0x597: 0x00c4,
+	0x598: 0x00c4, 0x599: 0x00c4, 0x59a: 0x00c2, 0x59b: 0x00c2, 0x59c: 0x00c2, 0x59d: 0x00c2,
+	0x59e: 0x00c2, 0x59f: 0x00c2, 0x5a0: 0x00c2, 0x5a1: 0x00c2, 0x5a2: 0x00c2, 0x5a3: 0x00c2,
+	0x5a4: 0x00c2, 0x5a5: 0x00c2, 0x5a6: 0x00c2, 0x5a7: 0x00c2, 0x5a8: 0x00c2, 0x5a9: 0x00c2,
+	0x5aa: 0x00c2, 0x5ab: 0x00c2, 0x5ac: 0x00c2, 0x5ad: 0x00c2, 0x5ae: 0x00c2, 0x5af: 0x00c2,
+	0x5b0: 0x00c2, 0x5b1: 0x00c2, 0x5b2: 0x00c2, 0x5b3: 0x00c2, 0x5b4: 0x00c2, 0x5b5: 0x00c2,
+	0x5b6: 0x00c2, 0x5b7: 0x00c2, 0x5b8: 0x00c2, 0x5b9: 0x00c2, 0x5ba: 0x00c2, 0x5bb: 0x00c2,
+	0x5bc: 0x00c2, 0x5bd: 0x00c2, 0x5be: 0x00c2, 0x5bf: 0x00c2,
+	// Block 0x17, offset 0x5c0
+	0x5c0: 0x00c4, 0x5c1: 0x00c2, 0x5c2: 0x00c2, 0x5c3: 0x00c4, 0x5c4: 0x00c4, 0x5c5: 0x00c4,
+	0x5c6: 0x00c4, 0x5c7: 0x00c4, 0x5c8: 0x00c4, 0x5c9: 0x00c4, 0x5ca: 0x00c4, 0x5cb: 0x00c4,
+	0x5cc: 0x00c2, 0x5cd: 0x00c4, 0x5ce: 0x00c2, 0x5cf: 0x00c4, 0x5d0: 0x00c2, 0x5d1: 0x00c2,
+	0x5d2: 0x00c4, 0x5d3: 0x00c4, 0x5d4: 0x0080, 0x5d5: 0x00c4, 0x5d6: 0x00c3, 0x5d7: 0x00c3,
+	0x5d8: 0x00c3, 0x5d9: 0x00c3, 0x5da: 0x00c3, 0x5db: 0x00c3, 0x5dc: 0x00c3, 0x5dd: 0x0040,
+	0x5de: 0x0080, 0x5df: 0x00c3, 0x5e0: 0x00c3, 0x5e1: 0x00c3, 0x5e2: 0x00c3, 0x5e3: 0x00c3,
+	0x5e4: 0x00c3, 0x5e5: 0x00c0, 0x5e6: 0x00c0, 0x5e7: 0x00c3, 0x5e8: 0x00c3, 0x5e9: 0x0080,
+	0x5ea: 0x00c3, 0x5eb: 0x00c3, 0x5ec: 0x00c3, 0x5ed: 0x00c3, 0x5ee: 0x00c4, 0x5ef: 0x00c4,
+	0x5f0: 0x0054, 0x5f1: 0x0054, 0x5f2: 0x0054, 0x5f3: 0x0054, 0x5f4: 0x0054, 0x5f5: 0x0054,
+	0x5f6: 0x0054, 0x5f7: 0x0054, 0x5f8: 0x0054, 0x5f9: 0x0054, 0x5fa: 0x00c2, 0x5fb: 0x00c2,
+	0x5fc: 0x00c2, 0x5fd: 0x00c0, 0x5fe: 0x00c0, 0x5ff: 0x00c2,
+	// Block 0x18, offset 0x600
+	0x600: 0x0080, 0x601: 0x0080, 0x602: 0x0080, 0x603: 0x0080, 0x604: 0x0080, 0x605: 0x0080,
+	0x606: 0x0080, 0x607: 0x0080, 0x608: 0x0080, 0x609: 0x0080, 0x60a: 0x0080, 0x60b: 0x0080,
+	0x60c: 0x0080, 0x60d: 0x0080, 0x60f: 0x0040, 0x610: 0x00c4, 0x611: 0x00c3,
+	0x612: 0x00c2, 0x613: 0x00c2, 0x614: 0x00c2, 0x615: 0x00c4, 0x616: 0x00c4, 0x617: 0x00c4,
+	0x618: 0x00c4, 0x619: 0x00c4, 0x61a: 0x00c2, 0x61b: 0x00c2, 0x61c: 0x00c2, 0x61d: 0x00c2,
+	0x61e: 0x00c4, 0x61f: 0x00c2, 0x620: 0x00c2, 0x621: 0x00c2, 0x622: 0x00c2, 0x623: 0x00c2,
+	0x624: 0x00c2, 0x625: 0x00c2, 0x626: 0x00c2, 0x627: 0x00c2, 0x628: 0x00c4, 0x629: 0x00c2,
+	0x62a: 0x00c4, 0x62b: 0x00c2, 0x62c: 0x00c4, 0x62d: 0x00c2, 0x62e: 0x00c2, 0x62f: 0x00c4,
+	0x630: 0x00c3, 0x631: 0x00c3, 0x632: 0x00c3, 0x633: 0x00c3, 0x634: 0x00c3, 0x635: 0x00c3,
+	0x636: 0x00c3, 0x637: 0x00c3, 0x638: 0x00c3, 0x639: 0x00c3, 0x63a: 0x00c3, 0x63b: 0x00c3,
+	0x63c: 0x00c3, 0x63d: 0x00c3, 0x63e: 0x00c3, 0x63f: 0x00c3,
+	// Block 0x19, offset 0x640
+	0x640: 0x00c3, 0x641: 0x00c3, 0x642: 0x00c3, 0x643: 0x00c3, 0x644: 0x00c3, 0x645: 0x00c3,
+	0x646: 0x00c3, 0x647: 0x00c3, 0x648: 0x00c3, 0x649: 0x00c3, 0x64a: 0x00c3,
+	0x64d: 0x00c4, 0x64e: 0x00c2, 0x64f: 0x00c2, 0x650: 0x00c2, 0x651: 0x00c2,
+	0x652: 0x00c2, 0x653: 0x00c2, 0x654: 0x00c2, 0x655: 0x00c2, 0x656: 0x00c2, 0x657: 0x00c2,
+	0x658: 0x00c2, 0x659: 0x00c4, 0x65a: 0x00c4, 0x65b: 0x00c4, 0x65c: 0x00c2, 0x65d: 0x00c2,
+	0x65e: 0x00c2, 0x65f: 0x00c2, 0x660: 0x00c2, 0x661: 0x00c2, 0x662: 0x00c2, 0x663: 0x00c2,
+	0x664: 0x00c2, 0x665: 0x00c2, 0x666: 0x00c2, 0x667: 0x00c2, 0x668: 0x00c2, 0x669: 0x00c2,
+	0x66a: 0x00c2, 0x66b: 0x00c4, 0x66c: 0x00c4, 0x66d: 0x00c2, 0x66e: 0x00c2, 0x66f: 0x00c2,
+	0x670: 0x00c2, 0x671: 0x00c4, 0x672: 0x00c2, 0x673: 0x00c4, 0x674: 0x00c4, 0x675: 0x00c2,
+	0x676: 0x00c2, 0x677: 0x00c2, 0x678: 0x00c4, 0x679: 0x00c4, 0x67a: 0x00c2, 0x67b: 0x00c2,
+	0x67c: 0x00c2, 0x67d: 0x00c2, 0x67e: 0x00c2, 0x67f: 0x00c2,
+	// Block 0x1a, offset 0x680
+	0x680: 0x00c0, 0x681: 0x00c0, 0x682: 0x00c0, 0x683: 0x00c0, 0x684: 0x00c0, 0x685: 0x00c0,
+	0x686: 0x00c0, 0x687: 0x00c0, 0x688: 0x00c0, 0x689: 0x00c0, 0x68a: 0x00c0, 0x68b: 0x00c0,
+	0x68c: 0x00c0, 0x68d: 0x00c0, 0x68e: 0x00c0, 0x68f: 0x00c0, 0x690: 0x00c0, 0x691: 0x00c0,
+	0x692: 0x00c0, 0x693: 0x00c0, 0x694: 0x00c0, 0x695: 0x00c0, 0x696: 0x00c0, 0x697: 0x00c0,
+	0x698: 0x00c0, 0x699: 0x00c0, 0x69a: 0x00c0, 0x69b: 0x00c0, 0x69c: 0x00c0, 0x69d: 0x00c0,
+	0x69e: 0x00c0, 0x69f: 0x00c0, 0x6a0: 0x00c0, 0x6a1: 0x00c0, 0x6a2: 0x00c0, 0x6a3: 0x00c0,
+	0x6a4: 0x00c0, 0x6a5: 0x00c0, 0x6a6: 0x00c3, 0x6a7: 0x00c3, 0x6a8: 0x00c3, 0x6a9: 0x00c3,
+	0x6aa: 0x00c3, 0x6ab: 0x00c3, 0x6ac: 0x00c3, 0x6ad: 0x00c3, 0x6ae: 0x00c3, 0x6af: 0x00c3,
+	0x6b0: 0x00c3, 0x6b1: 0x00c0,
+	// Block 0x1b, offset 0x6c0
+	0x6c0: 0x00c0, 0x6c1: 0x00c0, 0x6c2: 0x00c0, 0x6c3: 0x00c0, 0x6c4: 0x00c0, 0x6c5: 0x00c0,
+	0x6c6: 0x00c0, 0x6c7: 0x00c0, 0x6c8: 0x00c0, 0x6c9: 0x00c0, 0x6ca: 0x00c2, 0x6cb: 0x00c2,
+	0x6cc: 0x00c2, 0x6cd: 0x00c2, 0x6ce: 0x00c2, 0x6cf: 0x00c2, 0x6d0: 0x00c2, 0x6d1: 0x00c2,
+	0x6d2: 0x00c2, 0x6d3: 0x00c2, 0x6d4: 0x00c2, 0x6d5: 0x00c2, 0x6d6: 0x00c2, 0x6d7: 0x00c2,
+	0x6d8: 0x00c2, 0x6d9: 0x00c2, 0x6da: 0x00c2, 0x6db: 0x00c2, 0x6dc: 0x00c2, 0x6dd: 0x00c2,
+	0x6de: 0x00c2, 0x6df: 0x00c2, 0x6e0: 0x00c2, 0x6e1: 0x00c2, 0x6e2: 0x00c2, 0x6e3: 0x00c2,
+	0x6e4: 0x00c2, 0x6e5: 0x00c2, 0x6e6: 0x00c2, 0x6e7: 0x00c2, 0x6e8: 0x00c2, 0x6e9: 0x00c2,
+	0x6ea: 0x00c2, 0x6eb: 0x00c3, 0x6ec: 0x00c3, 0x6ed: 0x00c3, 0x6ee: 0x00c3, 0x6ef: 0x00c3,
+	0x6f0: 0x00c3, 0x6f1: 0x00c3, 0x6f2: 0x00c3, 0x6f3: 0x00c3, 0x6f4: 0x00c0, 0x6f5: 0x00c0,
+	0x6f6: 0x0080, 0x6f7: 0x0080, 0x6f8: 0x0080, 0x6f9: 0x0080, 0x6fa: 0x0040,
+	0x6fd: 0x00c3, 0x6fe: 0x0080, 0x6ff: 0x0080,
+	// Block 0x1c, offset 0x700
+	0x700: 0x00c0, 0x701: 0x00c0, 0x702: 0x00c0, 0x703: 0x00c0, 0x704: 0x00c0, 0x705: 0x00c0,
+	0x706: 0x00c0, 0x707: 0x00c0, 0x708: 0x00c0, 0x709: 0x00c0, 0x70a: 0x00c0, 0x70b: 0x00c0,
+	0x70c: 0x00c0, 0x70d: 0x00c0, 0x70e: 0x00c0, 0x70f: 0x00c0, 0x710: 0x00c0, 0x711: 0x00c0,
+	0x712: 0x00c0, 0x713: 0x00c0, 0x714: 0x00c0, 0x715: 0x00c0, 0x716: 0x00c3, 0x717: 0x00c3,
+	0x718: 0x00c3, 0x719: 0x00c3, 0x71a: 0x00c0, 0x71b: 0x00c3, 0x71c: 0x00c3, 0x71d: 0x00c3,
+	0x71e: 0x00c3, 0x71f: 0x00c3, 0x720: 0x00c3, 0x721: 0x00c3, 0x722: 0x00c3, 0x723: 0x00c3,
+	0x724: 0x00c0, 0x725: 0x00c3, 0x726: 0x00c3, 0x727: 0x00c3, 0x728: 0x00c0, 0x729: 0x00c3,
+	0x72a: 0x00c3, 0x72b: 0x00c3, 0x72c: 0x00c3, 0x72d: 0x00c3,
+	0x730: 0x0080, 0x731: 0x0080, 0x732: 0x0080, 0x733: 0x0080, 0x734: 0x0080, 0x735: 0x0080,
+	0x736: 0x0080, 0x737: 0x0080, 0x738: 0x0080, 0x739: 0x0080, 0x73a: 0x0080, 0x73b: 0x0080,
+	0x73c: 0x0080, 0x73d: 0x0080, 0x73e: 0x0080,
+	// Block 0x1d, offset 0x740
+	0x740: 0x00c4, 0x741: 0x00c2, 0x742: 0x00c2, 0x743: 0x00c2, 0x744: 0x00c2, 0x745: 0x00c2,
+	0x746: 0x00c4, 0x747: 0x00c4, 0x748: 0x00c2, 0x749: 0x00c4, 0x74a: 0x00c2, 0x74b: 0x00c2,
+	0x74c: 0x00c2, 0x74d: 0x00c2, 0x74e: 0x00c2, 0x74f: 0x00c2, 0x750: 0x00c2, 0x751: 0x00c2,
+	0x752: 0x00c2, 0x753: 0x00c2, 0x754: 0x00c4, 0x755: 0x00c2, 0x756: 0x00c4, 0x757: 0x00c4,
+	0x758: 0x00c4, 0x759: 0x00c3, 0x75a: 0x00c3, 0x75b: 0x00c3,
+	0x75e: 0x0080, 0x760: 0x00c2, 0x761: 0x00c0, 0x762: 0x00c2, 0x763: 0x00c2,
+	0x764: 0x00c2, 0x765: 0x00c2, 0x766: 0x00c0, 0x767: 0x00c4, 0x768: 0x00c2, 0x769: 0x00c4,
+	0x76a: 0x00c4,
+	0x770: 0x00c4, 0x771: 0x00c4, 0x772: 0x00c4, 0x773: 0x00c4, 0x774: 0x00c4, 0x775: 0x00c4,
+	0x776: 0x00c4, 0x777: 0x00c4, 0x778: 0x00c4, 0x779: 0x00c4, 0x77a: 0x00c4, 0x77b: 0x00c4,
+	0x77c: 0x00c4, 0x77d: 0x00c4, 0x77e: 0x00c4, 0x77f: 0x00c4,
+	// Block 0x1e, offset 0x780
+	0x780: 0x00c4, 0x781: 0x00c4, 0x782: 0x00c4, 0x783: 0x00c0, 0x784: 0x00c0, 0x785: 0x00c0,
+	0x786: 0x00c2, 0x787: 0x00c0, 0x788: 0x0080, 0x789: 0x00c2, 0x78a: 0x00c2, 0x78b: 0x00c2,
+	0x78c: 0x00c2, 0x78d: 0x00c2, 0x78e: 0x00c4, 0x78f: 0x00c2, 0x790: 0x0040, 0x791: 0x0040,
+	0x797: 0x00c3,
+	0x798: 0x00c3, 0x799: 0x00c3, 0x79a: 0x00c3, 0x79b: 0x00c3, 0x79c: 0x00c3, 0x79d: 0x00c3,
+	0x79e: 0x00c3, 0x79f: 0x00c3, 0x7a0: 0x00c2, 0x7a1: 0x00c2, 0x7a2: 0x00c2, 0x7a3: 0x00c2,
+	0x7a4: 0x00c2, 0x7a5: 0x00c2, 0x7a6: 0x00c2, 0x7a7: 0x00c2, 0x7a8: 0x00c2, 0x7a9: 0x00c2,
+	0x7aa: 0x00c4, 0x7ab: 0x00c4, 0x7ac: 0x00c4, 0x7ad: 0x00c0, 0x7ae: 0x00c4, 0x7af: 0x00c2,
+	0x7b0: 0x00c2, 0x7b1: 0x00c4, 0x7b2: 0x00c4, 0x7b3: 0x00c2, 0x7b4: 0x00c2, 0x7b5: 0x00c2,
+	0x7b6: 0x00c2, 0x7b7: 0x00c2, 0x7b8: 0x00c2, 0x7b9: 0x00c4, 0x7ba: 0x00c2, 0x7bb: 0x00c2,
+	0x7bc: 0x00c2, 0x7bd: 0x00c2, 0x7be: 0x00c2, 0x7bf: 0x00c2,
+	// Block 0x1f, offset 0x7c0
+	0x7c0: 0x00c2, 0x7c1: 0x00c2, 0x7c2: 0x00c2, 0x7c3: 0x00c2, 0x7c4: 0x00c2, 0x7c5: 0x00c2,
+	0x7c6: 0x00c2, 0x7c7: 0x00c2, 0x7c8: 0x00c2, 0x7c9: 0x00c0, 0x7ca: 0x00c3, 0x7cb: 0x00c3,
+	0x7cc: 0x00c3, 0x7cd: 0x00c3, 0x7ce: 0x00c3, 0x7cf: 0x00c3, 0x7d0: 0x00c3, 0x7d1: 0x00c3,
+	0x7d2: 0x00c3, 0x7d3: 0x00c3, 0x7d4: 0x00c3, 0x7d5: 0x00c3, 0x7d6: 0x00c3, 0x7d7: 0x00c3,
+	0x7d8: 0x00c3, 0x7d9: 0x00c3, 0x7da: 0x00c3, 0x7db: 0x00c3, 0x7dc: 0x00c3, 0x7dd: 0x00c3,
+	0x7de: 0x00c3, 0x7df: 0x00c3, 0x7e0: 0x00c3, 0x7e1: 0x00c3, 0x7e2: 0x0040, 0x7e3: 0x00c3,
+	0x7e4: 0x00c3, 0x7e5: 0x00c3, 0x7e6: 0x00c3, 0x7e7: 0x00c3, 0x7e8: 0x00c3, 0x7e9: 0x00c3,
+	0x7ea: 0x00c3, 0x7eb: 0x00c3, 0x7ec: 0x00c3, 0x7ed: 0x00c3, 0x7ee: 0x00c3, 0x7ef: 0x00c3,
+	0x7f0: 0x00c3, 0x7f1: 0x00c3, 0x7f2: 0x00c3, 0x7f3: 0x00c3, 0x7f4: 0x00c3, 0x7f5: 0x00c3,
+	0x7f6: 0x00c3, 0x7f7: 0x00c3, 0x7f8: 0x00c3, 0x7f9: 0x00c3, 0x7fa: 0x00c3, 0x7fb: 0x00c3,
+	0x7fc: 0x00c3, 0x7fd: 0x00c3, 0x7fe: 0x00c3, 0x7ff: 0x00c3,
+	// Block 0x20, offset 0x800
+	0x800: 0x00c3, 0x801: 0x00c3, 0x802: 0x00c3, 0x803: 0x00c0, 0x804: 0x00c0, 0x805: 0x00c0,
+	0x806: 0x00c0, 0x807: 0x00c0, 0x808: 0x00c0, 0x809: 0x00c0, 0x80a: 0x00c0, 0x80b: 0x00c0,
+	0x80c: 0x00c0, 0x80d: 0x00c0, 0x80e: 0x00c0, 0x80f: 0x00c0, 0x810: 0x00c0, 0x811: 0x00c0,
+	0x812: 0x00c0, 0x813: 0x00c0, 0x814: 0x00c0, 0x815: 0x00c0, 0x816: 0x00c0, 0x817: 0x00c0,
+	0x818: 0x00c0, 0x819: 0x00c0, 0x81a: 0x00c0, 0x81b: 0x00c0, 0x81c: 0x00c0, 0x81d: 0x00c0,
+	0x81e: 0x00c0, 0x81f: 0x00c0, 0x820: 0x00c0, 0x821: 0x00c0, 0x822: 0x00c0, 0x823: 0x00c0,
+	0x824: 0x00c0, 0x825: 0x00c0, 0x826: 0x00c0, 0x827: 0x00c0, 0x828: 0x00c0, 0x829: 0x00c0,
+	0x82a: 0x00c0, 0x82b: 0x00c0, 0x82c: 0x00c0, 0x82d: 0x00c0, 0x82e: 0x00c0, 0x82f: 0x00c0,
+	0x830: 0x00c0, 0x831: 0x00c0, 0x832: 0x00c0, 0x833: 0x00c0, 0x834: 0x00c0, 0x835: 0x00c0,
+	0x836: 0x00c0, 0x837: 0x00c0, 0x838: 0x00c0, 0x839: 0x00c0, 0x83a: 0x00c3, 0x83b: 0x00c0,
+	0x83c: 0x00c3, 0x83d: 0x00c0, 0x83e: 0x00c0, 0x83f: 0x00c0,
+	// Block 0x21, offset 0x840
+	0x840: 0x00c0, 0x841: 0x00c3, 0x842: 0x00c3, 0x843: 0x00c3, 0x844: 0x00c3, 0x845: 0x00c3,
+	0x846: 0x00c3, 0x847: 0x00c3, 0x848: 0x00c3, 0x849: 0x00c0, 0x84a: 0x00c0, 0x84b: 0x00c0,
+	0x84c: 0x00c0, 0x84d: 0x00c6, 0x84e: 0x00c0, 0x84f: 0x00c0, 0x850: 0x00c0, 0x851: 0x00c3,
+	0x852: 0x00c3, 0x853: 0x00c3, 0x854: 0x00c3, 0x855: 0x00c3, 0x856: 0x00c3, 0x857: 0x00c3,
+	0x858: 0x0080, 0x859: 0x0080, 0x85a: 0x0080, 0x85b: 0x0080, 0x85c: 0x0080, 0x85d: 0x0080,
+	0x85e: 0x0080, 0x85f: 0x0080, 0x860: 0x00c0, 0x861: 0x00c0, 0x862: 0x00c3, 0x863: 0x00c3,
+	0x864: 0x0080, 0x865: 0x0080, 0x866: 0x00c0, 0x867: 0x00c0, 0x868: 0x00c0, 0x869: 0x00c0,
+	0x86a: 0x00c0, 0x86b: 0x00c0, 0x86c: 0x00c0, 0x86d: 0x00c0, 0x86e: 0x00c0, 0x86f: 0x00c0,
+	0x870: 0x0080, 0x871: 0x00c0, 0x872: 0x00c0, 0x873: 0x00c0, 0x874: 0x00c0, 0x875: 0x00c0,
+	0x876: 0x00c0, 0x877: 0x00c0, 0x878: 0x00c0, 0x879: 0x00c0, 0x87a: 0x00c0, 0x87b: 0x00c0,
+	0x87c: 0x00c0, 0x87d: 0x00c0, 0x87e: 0x00c0, 0x87f: 0x00c0,
+	// Block 0x22, offset 0x880
+	0x880: 0x00c0, 0x881: 0x00c3, 0x882: 0x00c0, 0x883: 0x00c0, 0x885: 0x00c0,
+	0x886: 0x00c0, 0x887: 0x00c0, 0x888: 0x00c0, 0x889: 0x00c0, 0x88a: 0x00c0, 0x88b: 0x00c0,
+	0x88c: 0x00c0, 0x88f: 0x00c0, 0x890: 0x00c0,
+	0x893: 0x00c0, 0x894: 0x00c0, 0x895: 0x00c0, 0x896: 0x00c0, 0x897: 0x00c0,
+	0x898: 0x00c0, 0x899: 0x00c0, 0x89a: 0x00c0, 0x89b: 0x00c0, 0x89c: 0x00c0, 0x89d: 0x00c0,
+	0x89e: 0x00c0, 0x89f: 0x00c0, 0x8a0: 0x00c0, 0x8a1: 0x00c0, 0x8a2: 0x00c0, 0x8a3: 0x00c0,
+	0x8a4: 0x00c0, 0x8a5: 0x00c0, 0x8a6: 0x00c0, 0x8a7: 0x00c0, 0x8a8: 0x00c0,
+	0x8aa: 0x00c0, 0x8ab: 0x00c0, 0x8ac: 0x00c0, 0x8ad: 0x00c0, 0x8ae: 0x00c0, 0x8af: 0x00c0,
+	0x8b0: 0x00c0, 0x8b2: 0x00c0,
+	0x8b6: 0x00c0, 0x8b7: 0x00c0, 0x8b8: 0x00c0, 0x8b9: 0x00c0,
+	0x8bc: 0x00c3, 0x8bd: 0x00c0, 0x8be: 0x00c0, 0x8bf: 0x00c0,
+	// Block 0x23, offset 0x8c0
+	0x8c0: 0x00c0, 0x8c1: 0x00c3, 0x8c2: 0x00c3, 0x8c3: 0x00c3, 0x8c4: 0x00c3,
+	0x8c7: 0x00c0, 0x8c8: 0x00c0, 0x8cb: 0x00c0,
+	0x8cc: 0x00c0, 0x8cd: 0x00c6, 0x8ce: 0x00c0,
+	0x8d7: 0x00c0,
+	0x8dc: 0x0080, 0x8dd: 0x0080,
+	0x8df: 0x0080, 0x8e0: 0x00c0, 0x8e1: 0x00c0, 0x8e2: 0x00c3, 0x8e3: 0x00c3,
+	0x8e6: 0x00c0, 0x8e7: 0x00c0, 0x8e8: 0x00c0, 0x8e9: 0x00c0,
+	0x8ea: 0x00c0, 0x8eb: 0x00c0, 0x8ec: 0x00c0, 0x8ed: 0x00c0, 0x8ee: 0x00c0, 0x8ef: 0x00c0,
+	0x8f0: 0x00c0, 0x8f1: 0x00c0, 0x8f2: 0x0080, 0x8f3: 0x0080, 0x8f4: 0x0080, 0x8f5: 0x0080,
+	0x8f6: 0x0080, 0x8f7: 0x0080, 0x8f8: 0x0080, 0x8f9: 0x0080, 0x8fa: 0x0080, 0x8fb: 0x0080,
+	0x8fc: 0x00c0, 0x8fd: 0x0080, 0x8fe: 0x00c3,
+	// Block 0x24, offset 0x900
+	0x901: 0x00c3, 0x902: 0x00c3, 0x903: 0x00c0, 0x905: 0x00c0,
+	0x906: 0x00c0, 0x907: 0x00c0, 0x908: 0x00c0, 0x909: 0x00c0, 0x90a: 0x00c0,
+	0x90f: 0x00c0, 0x910: 0x00c0,
+	0x913: 0x00c0, 0x914: 0x00c0, 0x915: 0x00c0, 0x916: 0x00c0, 0x917: 0x00c0,
+	0x918: 0x00c0, 0x919: 0x00c0, 0x91a: 0x00c0, 0x91b: 0x00c0, 0x91c: 0x00c0, 0x91d: 0x00c0,
+	0x91e: 0x00c0, 0x91f: 0x00c0, 0x920: 0x00c0, 0x921: 0x00c0, 0x922: 0x00c0, 0x923: 0x00c0,
+	0x924: 0x00c0, 0x925: 0x00c0, 0x926: 0x00c0, 0x927: 0x00c0, 0x928: 0x00c0,
+	0x92a: 0x00c0, 0x92b: 0x00c0, 0x92c: 0x00c0, 0x92d: 0x00c0, 0x92e: 0x00c0, 0x92f: 0x00c0,
+	0x930: 0x00c0, 0x932: 0x00c0, 0x933: 0x0080, 0x935: 0x00c0,
+	0x936: 0x0080, 0x938: 0x00c0, 0x939: 0x00c0,
+	0x93c: 0x00c3, 0x93e: 0x00c0, 0x93f: 0x00c0,
+	// Block 0x25, offset 0x940
+	0x940: 0x00c0, 0x941: 0x00c3, 0x942: 0x00c3,
+	0x947: 0x00c3, 0x948: 0x00c3, 0x94b: 0x00c3,
+	0x94c: 0x00c3, 0x94d: 0x00c6, 0x951: 0x00c3,
+	0x959: 0x0080, 0x95a: 0x0080, 0x95b: 0x0080, 0x95c: 0x00c0,
+	0x95e: 0x0080,
+	0x966: 0x00c0, 0x967: 0x00c0, 0x968: 0x00c0, 0x969: 0x00c0,
+	0x96a: 0x00c0, 0x96b: 0x00c0, 0x96c: 0x00c0, 0x96d: 0x00c0, 0x96e: 0x00c0, 0x96f: 0x00c0,
+	0x970: 0x00c3, 0x971: 0x00c3, 0x972: 0x00c0, 0x973: 0x00c0, 0x974: 0x00c0, 0x975: 0x00c3,
+	0x976: 0x0080,
+	// Block 0x26, offset 0x980
+	0x981: 0x00c3, 0x982: 0x00c3, 0x983: 0x00c0, 0x985: 0x00c0,
+	0x986: 0x00c0, 0x987: 0x00c0, 0x988: 0x00c0, 0x989: 0x00c0, 0x98a: 0x00c0, 0x98b: 0x00c0,
+	0x98c: 0x00c0, 0x98d: 0x00c0, 0x98f: 0x00c0, 0x990: 0x00c0, 0x991: 0x00c0,
+	0x993: 0x00c0, 0x994: 0x00c0, 0x995: 0x00c0, 0x996: 0x00c0, 0x997: 0x00c0,
+	0x998: 0x00c0, 0x999: 0x00c0, 0x99a: 0x00c0, 0x99b: 0x00c0, 0x99c: 0x00c0, 0x99d: 0x00c0,
+	0x99e: 0x00c0, 0x99f: 0x00c0, 0x9a0: 0x00c0, 0x9a1: 0x00c0, 0x9a2: 0x00c0, 0x9a3: 0x00c0,
+	0x9a4: 0x00c0, 0x9a5: 0x00c0, 0x9a6: 0x00c0, 0x9a7: 0x00c0, 0x9a8: 0x00c0,
+	0x9aa: 0x00c0, 0x9ab: 0x00c0, 0x9ac: 0x00c0, 0x9ad: 0x00c0, 0x9ae: 0x00c0, 0x9af: 0x00c0,
+	0x9b0: 0x00c0, 0x9b2: 0x00c0, 0x9b3: 0x00c0, 0x9b5: 0x00c0,
+	0x9b6: 0x00c0, 0x9b7: 0x00c0, 0x9b8: 0x00c0, 0x9b9: 0x00c0,
+	0x9bc: 0x00c3, 0x9bd: 0x00c0, 0x9be: 0x00c0, 0x9bf: 0x00c0,
+	// Block 0x27, offset 0x9c0
+	0x9c0: 0x00c0, 0x9c1: 0x00c3, 0x9c2: 0x00c3, 0x9c3: 0x00c3, 0x9c4: 0x00c3, 0x9c5: 0x00c3,
+	0x9c7: 0x00c3, 0x9c8: 0x00c3, 0x9c9: 0x00c0, 0x9cb: 0x00c0,
+	0x9cc: 0x00c0, 0x9cd: 0x00c6, 0x9d0: 0x00c0,
+	0x9e0: 0x00c0, 0x9e1: 0x00c0, 0x9e2: 0x00c3, 0x9e3: 0x00c3,
+	0x9e6: 0x00c0, 0x9e7: 0x00c0, 0x9e8: 0x00c0, 0x9e9: 0x00c0,
+	0x9ea: 0x00c0, 0x9eb: 0x00c0, 0x9ec: 0x00c0, 0x9ed: 0x00c0, 0x9ee: 0x00c0, 0x9ef: 0x00c0,
+	0x9f0: 0x0080, 0x9f1: 0x0080,
+	0x9f9: 0x00c0, 0x9fa: 0x00c3, 0x9fb: 0x00c3,
+	0x9fc: 0x00c3, 0x9fd: 0x00c3, 0x9fe: 0x00c3, 0x9ff: 0x00c3,
+	// Block 0x28, offset 0xa00
+	0xa01: 0x00c3, 0xa02: 0x00c0, 0xa03: 0x00c0, 0xa05: 0x00c0,
+	0xa06: 0x00c0, 0xa07: 0x00c0, 0xa08: 0x00c0, 0xa09: 0x00c0, 0xa0a: 0x00c0, 0xa0b: 0x00c0,
+	0xa0c: 0x00c0, 0xa0f: 0x00c0, 0xa10: 0x00c0,
+	0xa13: 0x00c0, 0xa14: 0x00c0, 0xa15: 0x00c0, 0xa16: 0x00c0, 0xa17: 0x00c0,
+	0xa18: 0x00c0, 0xa19: 0x00c0, 0xa1a: 0x00c0, 0xa1b: 0x00c0, 0xa1c: 0x00c0, 0xa1d: 0x00c0,
+	0xa1e: 0x00c0, 0xa1f: 0x00c0, 0xa20: 0x00c0, 0xa21: 0x00c0, 0xa22: 0x00c0, 0xa23: 0x00c0,
+	0xa24: 0x00c0, 0xa25: 0x00c0, 0xa26: 0x00c0, 0xa27: 0x00c0, 0xa28: 0x00c0,
+	0xa2a: 0x00c0, 0xa2b: 0x00c0, 0xa2c: 0x00c0, 0xa2d: 0x00c0, 0xa2e: 0x00c0, 0xa2f: 0x00c0,
+	0xa30: 0x00c0, 0xa32: 0x00c0, 0xa33: 0x00c0, 0xa35: 0x00c0,
+	0xa36: 0x00c0, 0xa37: 0x00c0, 0xa38: 0x00c0, 0xa39: 0x00c0,
+	0xa3c: 0x00c3, 0xa3d: 0x00c0, 0xa3e: 0x00c0, 0xa3f: 0x00c3,
+	// Block 0x29, offset 0xa40
+	0xa40: 0x00c0, 0xa41: 0x00c3, 0xa42: 0x00c3, 0xa43: 0x00c3, 0xa44: 0x00c3,
+	0xa47: 0x00c0, 0xa48: 0x00c0, 0xa4b: 0x00c0,
+	0xa4c: 0x00c0, 0xa4d: 0x00c6,
+	0xa55: 0x00c3, 0xa56: 0x00c3, 0xa57: 0x00c0,
+	0xa5c: 0x0080, 0xa5d: 0x0080,
+	0xa5f: 0x00c0, 0xa60: 0x00c0, 0xa61: 0x00c0, 0xa62: 0x00c3, 0xa63: 0x00c3,
+	0xa66: 0x00c0, 0xa67: 0x00c0, 0xa68: 0x00c0, 0xa69: 0x00c0,
+	0xa6a: 0x00c0, 0xa6b: 0x00c0, 0xa6c: 0x00c0, 0xa6d: 0x00c0, 0xa6e: 0x00c0, 0xa6f: 0x00c0,
+	0xa70: 0x0080, 0xa71: 0x00c0, 0xa72: 0x0080, 0xa73: 0x0080, 0xa74: 0x0080, 0xa75: 0x0080,
+	0xa76: 0x0080, 0xa77: 0x0080,
+	// Block 0x2a, offset 0xa80
+	0xa82: 0x00c3, 0xa83: 0x00c0, 0xa85: 0x00c0,
+	0xa86: 0x00c0, 0xa87: 0x00c0, 0xa88: 0x00c0, 0xa89: 0x00c0, 0xa8a: 0x00c0,
+	0xa8e: 0x00c0, 0xa8f: 0x00c0, 0xa90: 0x00c0,
+	0xa92: 0x00c0, 0xa93: 0x00c0, 0xa94: 0x00c0, 0xa95: 0x00c0,
+	0xa99: 0x00c0, 0xa9a: 0x00c0, 0xa9c: 0x00c0,
+	0xa9e: 0x00c0, 0xa9f: 0x00c0, 0xaa3: 0x00c0,
+	0xaa4: 0x00c0, 0xaa8: 0x00c0, 0xaa9: 0x00c0,
+	0xaaa: 0x00c0, 0xaae: 0x00c0, 0xaaf: 0x00c0,
+	0xab0: 0x00c0, 0xab1: 0x00c0, 0xab2: 0x00c0, 0xab3: 0x00c0, 0xab4: 0x00c0, 0xab5: 0x00c0,
+	0xab6: 0x00c0, 0xab7: 0x00c0, 0xab8: 0x00c0, 0xab9: 0x00c0,
+	0xabe: 0x00c0, 0xabf: 0x00c0,
+	// Block 0x2b, offset 0xac0
+	0xac0: 0x00c3, 0xac1: 0x00c0, 0xac2: 0x00c0,
+	0xac6: 0x00c0, 0xac7: 0x00c0, 0xac8: 0x00c0, 0xaca: 0x00c0, 0xacb: 0x00c0,
+	0xacc: 0x00c0, 0xacd: 0x00c6, 0xad0: 0x00c0,
+	0xad7: 0x00c0,
+	0xae6: 0x00c0, 0xae7: 0x00c0, 0xae8: 0x00c0, 0xae9: 0x00c0,
+	0xaea: 0x00c0, 0xaeb: 0x00c0, 0xaec: 0x00c0, 0xaed: 0x00c0, 0xaee: 0x00c0, 0xaef: 0x00c0,
+	0xaf0: 0x0080, 0xaf1: 0x0080, 0xaf2: 0x0080, 0xaf3: 0x0080, 0xaf4: 0x0080, 0xaf5: 0x0080,
+	0xaf6: 0x0080, 0xaf7: 0x0080, 0xaf8: 0x0080, 0xaf9: 0x0080, 0xafa: 0x0080,
+	// Block 0x2c, offset 0xb00
+	0xb00: 0x00c3, 0xb01: 0x00c0, 0xb02: 0x00c0, 0xb03: 0x00c0, 0xb04: 0x00c3, 0xb05: 0x00c0,
+	0xb06: 0x00c0, 0xb07: 0x00c0, 0xb08: 0x00c0, 0xb09: 0x00c0, 0xb0a: 0x00c0, 0xb0b: 0x00c0,
+	0xb0c: 0x00c0, 0xb0e: 0x00c0, 0xb0f: 0x00c0, 0xb10: 0x00c0,
+	0xb12: 0x00c0, 0xb13: 0x00c0, 0xb14: 0x00c0, 0xb15: 0x00c0, 0xb16: 0x00c0, 0xb17: 0x00c0,
+	0xb18: 0x00c0, 0xb19: 0x00c0, 0xb1a: 0x00c0, 0xb1b: 0x00c0, 0xb1c: 0x00c0, 0xb1d: 0x00c0,
+	0xb1e: 0x00c0, 0xb1f: 0x00c0, 0xb20: 0x00c0, 0xb21: 0x00c0, 0xb22: 0x00c0, 0xb23: 0x00c0,
+	0xb24: 0x00c0, 0xb25: 0x00c0, 0xb26: 0x00c0, 0xb27: 0x00c0, 0xb28: 0x00c0,
+	0xb2a: 0x00c0, 0xb2b: 0x00c0, 0xb2c: 0x00c0, 0xb2d: 0x00c0, 0xb2e: 0x00c0, 0xb2f: 0x00c0,
+	0xb30: 0x00c0, 0xb31: 0x00c0, 0xb32: 0x00c0, 0xb33: 0x00c0, 0xb34: 0x00c0, 0xb35: 0x00c0,
+	0xb36: 0x00c0, 0xb37: 0x00c0, 0xb38: 0x00c0, 0xb39: 0x00c0,
+	0xb3c: 0x00c3, 0xb3d: 0x00c0, 0xb3e: 0x00c3, 0xb3f: 0x00c3,
+	// Block 0x2d, offset 0xb40
+	0xb40: 0x00c3, 0xb41: 0x00c0, 0xb42: 0x00c0, 0xb43: 0x00c0, 0xb44: 0x00c0,
+	0xb46: 0x00c3, 0xb47: 0x00c3, 0xb48: 0x00c3, 0xb4a: 0x00c3, 0xb4b: 0x00c3,
+	0xb4c: 0x00c3, 0xb4d: 0x00c6,
+	0xb55: 0x00c3, 0xb56: 0x00c3,
+	0xb58: 0x00c0, 0xb59: 0x00c0, 0xb5a: 0x00c0, 0xb5c: 0x00c0, 0xb5d: 0x00c0,
+	0xb60: 0x00c0, 0xb61: 0x00c0, 0xb62: 0x00c3, 0xb63: 0x00c3,
+	0xb66: 0x00c0, 0xb67: 0x00c0, 0xb68: 0x00c0, 0xb69: 0x00c0,
+	0xb6a: 0x00c0, 0xb6b: 0x00c0, 0xb6c: 0x00c0, 0xb6d: 0x00c0, 0xb6e: 0x00c0, 0xb6f: 0x00c0,
+	0xb77: 0x0080, 0xb78: 0x0080, 0xb79: 0x0080, 0xb7a: 0x0080, 0xb7b: 0x0080,
+	0xb7c: 0x0080, 0xb7d: 0x0080, 0xb7e: 0x0080, 0xb7f: 0x0080,
+	// Block 0x2e, offset 0xb80
+	0xb80: 0x00c0, 0xb81: 0x00c3, 0xb82: 0x00c0, 0xb83: 0x00c0, 0xb84: 0x0080, 0xb85: 0x00c0,
+	0xb86: 0x00c0, 0xb87: 0x00c0, 0xb88: 0x00c0, 0xb89: 0x00c0, 0xb8a: 0x00c0, 0xb8b: 0x00c0,
+	0xb8c: 0x00c0, 0xb8e: 0x00c0, 0xb8f: 0x00c0, 0xb90: 0x00c0,
+	0xb92: 0x00c0, 0xb93: 0x00c0, 0xb94: 0x00c0, 0xb95: 0x00c0, 0xb96: 0x00c0, 0xb97: 0x00c0,
+	0xb98: 0x00c0, 0xb99: 0x00c0, 0xb9a: 0x00c0, 0xb9b: 0x00c0, 0xb9c: 0x00c0, 0xb9d: 0x00c0,
+	0xb9e: 0x00c0, 0xb9f: 0x00c0, 0xba0: 0x00c0, 0xba1: 0x00c0, 0xba2: 0x00c0, 0xba3: 0x00c0,
+	0xba4: 0x00c0, 0xba5: 0x00c0, 0xba6: 0x00c0, 0xba7: 0x00c0, 0xba8: 0x00c0,
+	0xbaa: 0x00c0, 0xbab: 0x00c0, 0xbac: 0x00c0, 0xbad: 0x00c0, 0xbae: 0x00c0, 0xbaf: 0x00c0,
+	0xbb0: 0x00c0, 0xbb1: 0x00c0, 0xbb2: 0x00c0, 0xbb3: 0x00c0, 0xbb5: 0x00c0,
+	0xbb6: 0x00c0, 0xbb7: 0x00c0, 0xbb8: 0x00c0, 0xbb9: 0x00c0,
+	0xbbc: 0x00c3, 0xbbd: 0x00c0, 0xbbe: 0x00c0, 0xbbf: 0x00c3,
+	// Block 0x2f, offset 0xbc0
+	0xbc0: 0x00c0, 0xbc1: 0x00c0, 0xbc2: 0x00c0, 0xbc3: 0x00c0, 0xbc4: 0x00c0,
+	0xbc6: 0x00c3, 0xbc7: 0x00c0, 0xbc8: 0x00c0, 0xbca: 0x00c0, 0xbcb: 0x00c0,
+	0xbcc: 0x00c3, 0xbcd: 0x00c6,
+	0xbd5: 0x00c0, 0xbd6: 0x00c0,
+	0xbdc: 0x00c0, 0xbdd: 0x00c0,
+	0xbde: 0x00c0, 0xbe0: 0x00c0, 0xbe1: 0x00c0, 0xbe2: 0x00c3, 0xbe3: 0x00c3,
+	0xbe6: 0x00c0, 0xbe7: 0x00c0, 0xbe8: 0x00c0, 0xbe9: 0x00c0,
+	0xbea: 0x00c0, 0xbeb: 0x00c0, 0xbec: 0x00c0, 0xbed: 0x00c0, 0xbee: 0x00c0, 0xbef: 0x00c0,
+	0xbf1: 0x00c0, 0xbf2: 0x00c0, 0xbf3: 0x00c0,
+	// Block 0x30, offset 0xc00
+	0xc00: 0x00c3, 0xc01: 0x00c3, 0xc02: 0x00c0, 0xc03: 0x00c0, 0xc04: 0x00c0, 0xc05: 0x00c0,
+	0xc06: 0x00c0, 0xc07: 0x00c0, 0xc08: 0x00c0, 0xc09: 0x00c0, 0xc0a: 0x00c0, 0xc0b: 0x00c0,
+	0xc0c: 0x00c0, 0xc0e: 0x00c0, 0xc0f: 0x00c0, 0xc10: 0x00c0,
+	0xc12: 0x00c0, 0xc13: 0x00c0, 0xc14: 0x00c0, 0xc15: 0x00c0, 0xc16: 0x00c0, 0xc17: 0x00c0,
+	0xc18: 0x00c0, 0xc19: 0x00c0, 0xc1a: 0x00c0, 0xc1b: 0x00c0, 0xc1c: 0x00c0, 0xc1d: 0x00c0,
+	0xc1e: 0x00c0, 0xc1f: 0x00c0, 0xc20: 0x00c0, 0xc21: 0x00c0, 0xc22: 0x00c0, 0xc23: 0x00c0,
+	0xc24: 0x00c0, 0xc25: 0x00c0, 0xc26: 0x00c0, 0xc27: 0x00c0, 0xc28: 0x00c0, 0xc29: 0x00c0,
+	0xc2a: 0x00c0, 0xc2b: 0x00c0, 0xc2c: 0x00c0, 0xc2d: 0x00c0, 0xc2e: 0x00c0, 0xc2f: 0x00c0,
+	0xc30: 0x00c0, 0xc31: 0x00c0, 0xc32: 0x00c0, 0xc33: 0x00c0, 0xc34: 0x00c0, 0xc35: 0x00c0,
+	0xc36: 0x00c0, 0xc37: 0x00c0, 0xc38: 0x00c0, 0xc39: 0x00c0, 0xc3a: 0x00c0, 0xc3b: 0x00c6,
+	0xc3c: 0x00c6, 0xc3d: 0x00c0, 0xc3e: 0x00c0, 0xc3f: 0x00c0,
+	// Block 0x31, offset 0xc40
+	0xc40: 0x00c0, 0xc41: 0x00c3, 0xc42: 0x00c3, 0xc43: 0x00c3, 0xc44: 0x00c3,
+	0xc46: 0x00c0, 0xc47: 0x00c0, 0xc48: 0x00c0, 0xc4a: 0x00c0, 0xc4b: 0x00c0,
+	0xc4c: 0x00c0, 0xc4d: 0x00c6, 0xc4e: 0x00c0, 0xc4f: 0x0080,
+	0xc54: 0x00c0, 0xc55: 0x00c0, 0xc56: 0x00c0, 0xc57: 0x00c0,
+	0xc58: 0x0080, 0xc59: 0x0080, 0xc5a: 0x0080, 0xc5b: 0x0080, 0xc5c: 0x0080, 0xc5d: 0x0080,
+	0xc5e: 0x0080, 0xc5f: 0x00c0, 0xc60: 0x00c0, 0xc61: 0x00c0, 0xc62: 0x00c3, 0xc63: 0x00c3,
+	0xc66: 0x00c0, 0xc67: 0x00c0, 0xc68: 0x00c0, 0xc69: 0x00c0,
+	0xc6a: 0x00c0, 0xc6b: 0x00c0, 0xc6c: 0x00c0, 0xc6d: 0x00c0, 0xc6e: 0x00c0, 0xc6f: 0x00c0,
+	0xc70: 0x0080, 0xc71: 0x0080, 0xc72: 0x0080, 0xc73: 0x0080, 0xc74: 0x0080, 0xc75: 0x0080,
+	0xc76: 0x0080, 0xc77: 0x0080, 0xc78: 0x0080, 0xc79: 0x0080, 0xc7a: 0x00c0, 0xc7b: 0x00c0,
+	0xc7c: 0x00c0, 0xc7d: 0x00c0, 0xc7e: 0x00c0, 0xc7f: 0x00c0,
+	// Block 0x32, offset 0xc80
+	0xc81: 0x00c3, 0xc82: 0x00c0, 0xc83: 0x00c0, 0xc85: 0x00c0,
+	0xc86: 0x00c0, 0xc87: 0x00c0, 0xc88: 0x00c0, 0xc89: 0x00c0, 0xc8a: 0x00c0, 0xc8b: 0x00c0,
+	0xc8c: 0x00c0, 0xc8d: 0x00c0, 0xc8e: 0x00c0, 0xc8f: 0x00c0, 0xc90: 0x00c0, 0xc91: 0x00c0,
+	0xc92: 0x00c0, 0xc93: 0x00c0, 0xc94: 0x00c0, 0xc95: 0x00c0, 0xc96: 0x00c0,
+	0xc9a: 0x00c0, 0xc9b: 0x00c0, 0xc9c: 0x00c0, 0xc9d: 0x00c0,
+	0xc9e: 0x00c0, 0xc9f: 0x00c0, 0xca0: 0x00c0, 0xca1: 0x00c0, 0xca2: 0x00c0, 0xca3: 0x00c0,
+	0xca4: 0x00c0, 0xca5: 0x00c0, 0xca6: 0x00c0, 0xca7: 0x00c0, 0xca8: 0x00c0, 0xca9: 0x00c0,
+	0xcaa: 0x00c0, 0xcab: 0x00c0, 0xcac: 0x00c0, 0xcad: 0x00c0, 0xcae: 0x00c0, 0xcaf: 0x00c0,
+	0xcb0: 0x00c0, 0xcb1: 0x00c0, 0xcb3: 0x00c0, 0xcb4: 0x00c0, 0xcb5: 0x00c0,
+	0xcb6: 0x00c0, 0xcb7: 0x00c0, 0xcb8: 0x00c0, 0xcb9: 0x00c0, 0xcba: 0x00c0, 0xcbb: 0x00c0,
+	0xcbd: 0x00c0,
+	// Block 0x33, offset 0xcc0
+	0xcc0: 0x00c0, 0xcc1: 0x00c0, 0xcc2: 0x00c0, 0xcc3: 0x00c0, 0xcc4: 0x00c0, 0xcc5: 0x00c0,
+	0xcc6: 0x00c0, 0xcca: 0x00c6,
+	0xccf: 0x00c0, 0xcd0: 0x00c0, 0xcd1: 0x00c0,
+	0xcd2: 0x00c3, 0xcd3: 0x00c3, 0xcd4: 0x00c3, 0xcd6: 0x00c3,
+	0xcd8: 0x00c0, 0xcd9: 0x00c0, 0xcda: 0x00c0, 0xcdb: 0x00c0, 0xcdc: 0x00c0, 0xcdd: 0x00c0,
+	0xcde: 0x00c0, 0xcdf: 0x00c0,
+	0xce6: 0x00c0, 0xce7: 0x00c0, 0xce8: 0x00c0, 0xce9: 0x00c0,
+	0xcea: 0x00c0, 0xceb: 0x00c0, 0xcec: 0x00c0, 0xced: 0x00c0, 0xcee: 0x00c0, 0xcef: 0x00c0,
+	0xcf2: 0x00c0, 0xcf3: 0x00c0, 0xcf4: 0x0080,
+	// Block 0x34, offset 0xd00
+	0xd01: 0x00c0, 0xd02: 0x00c0, 0xd03: 0x00c0, 0xd04: 0x00c0, 0xd05: 0x00c0,
+	0xd06: 0x00c0, 0xd07: 0x00c0, 0xd08: 0x00c0, 0xd09: 0x00c0, 0xd0a: 0x00c0, 0xd0b: 0x00c0,
+	0xd0c: 0x00c0, 0xd0d: 0x00c0, 0xd0e: 0x00c0, 0xd0f: 0x00c0, 0xd10: 0x00c0, 0xd11: 0x00c0,
+	0xd12: 0x00c0, 0xd13: 0x00c0, 0xd14: 0x00c0, 0xd15: 0x00c0, 0xd16: 0x00c0, 0xd17: 0x00c0,
+	0xd18: 0x00c0, 0xd19: 0x00c0, 0xd1a: 0x00c0, 0xd1b: 0x00c0, 0xd1c: 0x00c0, 0xd1d: 0x00c0,
+	0xd1e: 0x00c0, 0xd1f: 0x00c0, 0xd20: 0x00c0, 0xd21: 0x00c0, 0xd22: 0x00c0, 0xd23: 0x00c0,
+	0xd24: 0x00c0, 0xd25: 0x00c0, 0xd26: 0x00c0, 0xd27: 0x00c0, 0xd28: 0x00c0, 0xd29: 0x00c0,
+	0xd2a: 0x00c0, 0xd2b: 0x00c0, 0xd2c: 0x00c0, 0xd2d: 0x00c0, 0xd2e: 0x00c0, 0xd2f: 0x00c0,
+	0xd30: 0x00c0, 0xd31: 0x00c3, 0xd32: 0x00c0, 0xd33: 0x0080, 0xd34: 0x00c3, 0xd35: 0x00c3,
+	0xd36: 0x00c3, 0xd37: 0x00c3, 0xd38: 0x00c3, 0xd39: 0x00c3, 0xd3a: 0x00c6,
+	0xd3f: 0x0080,
+	// Block 0x35, offset 0xd40
+	0xd40: 0x00c0, 0xd41: 0x00c0, 0xd42: 0x00c0, 0xd43: 0x00c0, 0xd44: 0x00c0, 0xd45: 0x00c0,
+	0xd46: 0x00c0, 0xd47: 0x00c3, 0xd48: 0x00c3, 0xd49: 0x00c3, 0xd4a: 0x00c3, 0xd4b: 0x00c3,
+	0xd4c: 0x00c3, 0xd4d: 0x00c3, 0xd4e: 0x00c3, 0xd4f: 0x0080, 0xd50: 0x00c0, 0xd51: 0x00c0,
+	0xd52: 0x00c0, 0xd53: 0x00c0, 0xd54: 0x00c0, 0xd55: 0x00c0, 0xd56: 0x00c0, 0xd57: 0x00c0,
+	0xd58: 0x00c0, 0xd59: 0x00c0, 0xd5a: 0x0080, 0xd5b: 0x0080,
+	// Block 0x36, offset 0xd80
+	0xd81: 0x00c0, 0xd82: 0x00c0, 0xd84: 0x00c0,
+	0xd86: 0x00c0, 0xd87: 0x00c0, 0xd88: 0x00c0, 0xd89: 0x00c0, 0xd8a: 0x00c0,
+	0xd8c: 0x00c0, 0xd8d: 0x00c0, 0xd8e: 0x00c0, 0xd8f: 0x00c0, 0xd90: 0x00c0, 0xd91: 0x00c0,
+	0xd92: 0x00c0, 0xd93: 0x00c0, 0xd94: 0x00c0, 0xd95: 0x00c0, 0xd96: 0x00c0, 0xd97: 0x00c0,
+	0xd98: 0x00c0, 0xd99: 0x00c0, 0xd9a: 0x00c0, 0xd9b: 0x00c0, 0xd9c: 0x00c0, 0xd9d: 0x00c0,
+	0xd9e: 0x00c0, 0xd9f: 0x00c0, 0xda0: 0x00c0, 0xda1: 0x00c0, 0xda2: 0x00c0, 0xda3: 0x00c0,
+	0xda5: 0x00c0, 0xda7: 0x00c0, 0xda8: 0x00c0, 0xda9: 0x00c0,
+	0xdaa: 0x00c0, 0xdab: 0x00c0, 0xdac: 0x00c0, 0xdad: 0x00c0, 0xdae: 0x00c0, 0xdaf: 0x00c0,
+	0xdb0: 0x00c0, 0xdb1: 0x00c3, 0xdb2: 0x00c0, 0xdb3: 0x0080, 0xdb4: 0x00c3, 0xdb5: 0x00c3,
+	0xdb6: 0x00c3, 0xdb7: 0x00c3, 0xdb8: 0x00c3, 0xdb9: 0x00c3, 0xdba: 0x00c6, 0xdbb: 0x00c3,
+	0xdbc: 0x00c3, 0xdbd: 0x00c0,
+	// Block 0x37, offset 0xdc0
+	0xdc0: 0x00c0, 0xdc1: 0x00c0, 0xdc2: 0x00c0, 0xdc3: 0x00c0, 0xdc4: 0x00c0,
+	0xdc6: 0x00c0, 0xdc8: 0x00c3, 0xdc9: 0x00c3, 0xdca: 0x00c3, 0xdcb: 0x00c3,
+	0xdcc: 0x00c3, 0xdcd: 0x00c3, 0xdce: 0x00c3, 0xdd0: 0x00c0, 0xdd1: 0x00c0,
+	0xdd2: 0x00c0, 0xdd3: 0x00c0, 0xdd4: 0x00c0, 0xdd5: 0x00c0, 0xdd6: 0x00c0, 0xdd7: 0x00c0,
+	0xdd8: 0x00c0, 0xdd9: 0x00c0, 0xddc: 0x0080, 0xddd: 0x0080,
+	0xdde: 0x00c0, 0xddf: 0x00c0,
+	// Block 0x38, offset 0xe00
+	0xe00: 0x00c0, 0xe01: 0x0080, 0xe02: 0x0080, 0xe03: 0x0080, 0xe04: 0x0080, 0xe05: 0x0080,
+	0xe06: 0x0080, 0xe07: 0x0080, 0xe08: 0x0080, 0xe09: 0x0080, 0xe0a: 0x0080, 0xe0b: 0x00c0,
+	0xe0c: 0x0080, 0xe0d: 0x0080, 0xe0e: 0x0080, 0xe0f: 0x0080, 0xe10: 0x0080, 0xe11: 0x0080,
+	0xe12: 0x0080, 0xe13: 0x0080, 0xe14: 0x0080, 0xe15: 0x0080, 0xe16: 0x0080, 0xe17: 0x0080,
+	0xe18: 0x00c3, 0xe19: 0x00c3, 0xe1a: 0x0080, 0xe1b: 0x0080, 0xe1c: 0x0080, 0xe1d: 0x0080,
+	0xe1e: 0x0080, 0xe1f: 0x0080, 0xe20: 0x00c0, 0xe21: 0x00c0, 0xe22: 0x00c0, 0xe23: 0x00c0,
+	0xe24: 0x00c0, 0xe25: 0x00c0, 0xe26: 0x00c0, 0xe27: 0x00c0, 0xe28: 0x00c0, 0xe29: 0x00c0,
+	0xe2a: 0x0080, 0xe2b: 0x0080, 0xe2c: 0x0080, 0xe2d: 0x0080, 0xe2e: 0x0080, 0xe2f: 0x0080,
+	0xe30: 0x0080, 0xe31: 0x0080, 0xe32: 0x0080, 0xe33: 0x0080, 0xe34: 0x0080, 0xe35: 0x00c3,
+	0xe36: 0x0080, 0xe37: 0x00c3, 0xe38: 0x0080, 0xe39: 0x00c3, 0xe3a: 0x0080, 0xe3b: 0x0080,
+	0xe3c: 0x0080, 0xe3d: 0x0080, 0xe3e: 0x00c0, 0xe3f: 0x00c0,
+	// Block 0x39, offset 0xe40
+	0xe40: 0x00c0, 0xe41: 0x00c0, 0xe42: 0x00c0, 0xe43: 0x0080, 0xe44: 0x00c0, 0xe45: 0x00c0,
+	0xe46: 0x00c0, 0xe47: 0x00c0, 0xe49: 0x00c0, 0xe4a: 0x00c0, 0xe4b: 0x00c0,
+	0xe4c: 0x00c0, 0xe4d: 0x0080, 0xe4e: 0x00c0, 0xe4f: 0x00c0, 0xe50: 0x00c0, 0xe51: 0x00c0,
+	0xe52: 0x0080, 0xe53: 0x00c0, 0xe54: 0x00c0, 0xe55: 0x00c0, 0xe56: 0x00c0, 0xe57: 0x0080,
+	0xe58: 0x00c0, 0xe59: 0x00c0, 0xe5a: 0x00c0, 0xe5b: 0x00c0, 0xe5c: 0x0080, 0xe5d: 0x00c0,
+	0xe5e: 0x00c0, 0xe5f: 0x00c0, 0xe60: 0x00c0, 0xe61: 0x00c0, 0xe62: 0x00c0, 0xe63: 0x00c0,
+	0xe64: 0x00c0, 0xe65: 0x00c0, 0xe66: 0x00c0, 0xe67: 0x00c0, 0xe68: 0x00c0, 0xe69: 0x0080,
+	0xe6a: 0x00c0, 0xe6b: 0x00c0, 0xe6c: 0x00c0,
+	0xe71: 0x00c3, 0xe72: 0x00c3, 0xe73: 0x0083, 0xe74: 0x00c3, 0xe75: 0x0083,
+	0xe76: 0x0083, 0xe77: 0x0083, 0xe78: 0x0083, 0xe79: 0x0083, 0xe7a: 0x00c3, 0xe7b: 0x00c3,
+	0xe7c: 0x00c3, 0xe7d: 0x00c3, 0xe7e: 0x00c3, 0xe7f: 0x00c0,
+	// Block 0x3a, offset 0xe80
+	0xe80: 0x00c3, 0xe81: 0x0083, 0xe82: 0x00c3, 0xe83: 0x00c3, 0xe84: 0x00c6, 0xe85: 0x0080,
+	0xe86: 0x00c3, 0xe87: 0x00c3, 0xe88: 0x00c0, 0xe89: 0x00c0, 0xe8a: 0x00c0, 0xe8b: 0x00c0,
+	0xe8c: 0x00c0, 0xe8d: 0x00c3, 0xe8e: 0x00c3, 0xe8f: 0x00c3, 0xe90: 0x00c3, 0xe91: 0x00c3,
+	0xe92: 0x00c3, 0xe93: 0x0083, 0xe94: 0x00c3, 0xe95: 0x00c3, 0xe96: 0x00c3, 0xe97: 0x00c3,
+	0xe99: 0x00c3, 0xe9a: 0x00c3, 0xe9b: 0x00c3, 0xe9c: 0x00c3, 0xe9d: 0x0083,
+	0xe9e: 0x00c3, 0xe9f: 0x00c3, 0xea0: 0x00c3, 0xea1: 0x00c3, 0xea2: 0x0083, 0xea3: 0x00c3,
+	0xea4: 0x00c3, 0xea5: 0x00c3, 0xea6: 0x00c3, 0xea7: 0x0083, 0xea8: 0x00c3, 0xea9: 0x00c3,
+	0xeaa: 0x00c3, 0xeab: 0x00c3, 0xeac: 0x0083, 0xead: 0x00c3, 0xeae: 0x00c3, 0xeaf: 0x00c3,
+	0xeb0: 0x00c3, 0xeb1: 0x00c3, 0xeb2: 0x00c3, 0xeb3: 0x00c3, 0xeb4: 0x00c3, 0xeb5: 0x00c3,
+	0xeb6: 0x00c3, 0xeb7: 0x00c3, 0xeb8: 0x00c3, 0xeb9: 0x0083, 0xeba: 0x00c3, 0xebb: 0x00c3,
+	0xebc: 0x00c3, 0xebe: 0x0080, 0xebf: 0x0080,
+	// Block 0x3b, offset 0xec0
+	0xec0: 0x0080, 0xec1: 0x0080, 0xec2: 0x0080, 0xec3: 0x0080, 0xec4: 0x0080, 0xec5: 0x0080,
+	0xec6: 0x00c3, 0xec7: 0x0080, 0xec8: 0x0080, 0xec9: 0x0080, 0xeca: 0x0080, 0xecb: 0x0080,
+	0xecc: 0x0080, 0xece: 0x0080, 0xecf: 0x0080, 0xed0: 0x0080, 0xed1: 0x0080,
+	0xed2: 0x0080, 0xed3: 0x0080, 0xed4: 0x0080, 0xed5: 0x0080, 0xed6: 0x0080, 0xed7: 0x0080,
+	0xed8: 0x0080, 0xed9: 0x0080, 0xeda: 0x0080,
+	// Block 0x3c, offset 0xf00
+	0xf00: 0x00c0, 0xf01: 0x00c0, 0xf02: 0x00c0, 0xf03: 0x00c0, 0xf04: 0x00c0, 0xf05: 0x00c0,
+	0xf06: 0x00c0, 0xf07: 0x00c0, 0xf08: 0x00c0, 0xf09: 0x00c0, 0xf0a: 0x00c0, 0xf0b: 0x00c0,
+	0xf0c: 0x00c0, 0xf0d: 0x00c0, 0xf0e: 0x00c0, 0xf0f: 0x00c0, 0xf10: 0x00c0, 0xf11: 0x00c0,
+	0xf12: 0x00c0, 0xf13: 0x00c0, 0xf14: 0x00c0, 0xf15: 0x00c0, 0xf16: 0x00c0, 0xf17: 0x00c0,
+	0xf18: 0x00c0, 0xf19: 0x00c0, 0xf1a: 0x00c0, 0xf1b: 0x00c0, 0xf1c: 0x00c0, 0xf1d: 0x00c0,
+	0xf1e: 0x00c0, 0xf1f: 0x00c0, 0xf20: 0x00c0, 0xf21: 0x00c0, 0xf22: 0x00c0, 0xf23: 0x00c0,
+	0xf24: 0x00c0, 0xf25: 0x00c0, 0xf26: 0x00c0, 0xf27: 0x00c0, 0xf28: 0x00c0, 0xf29: 0x00c0,
+	0xf2a: 0x00c0, 0xf2b: 0x00c0, 0xf2c: 0x00c0, 0xf2d: 0x00c3, 0xf2e: 0x00c3, 0xf2f: 0x00c3,
+	0xf30: 0x00c3, 0xf31: 0x00c0, 0xf32: 0x00c3, 0xf33: 0x00c3, 0xf34: 0x00c3, 0xf35: 0x00c3,
+	0xf36: 0x00c3, 0xf37: 0x00c3, 0xf38: 0x00c0, 0xf39: 0x00c6, 0xf3a: 0x00c6, 0xf3b: 0x00c0,
+	0xf3c: 0x00c0, 0xf3d: 0x00c3, 0xf3e: 0x00c3, 0xf3f: 0x00c0,
+	// Block 0x3d, offset 0xf40
+	0xf40: 0x00c0, 0xf41: 0x00c0, 0xf42: 0x00c0, 0xf43: 0x00c0, 0xf44: 0x00c0, 0xf45: 0x00c0,
+	0xf46: 0x00c0, 0xf47: 0x00c0, 0xf48: 0x00c0, 0xf49: 0x00c0, 0xf4a: 0x0080, 0xf4b: 0x0080,
+	0xf4c: 0x0080, 0xf4d: 0x0080, 0xf4e: 0x0080, 0xf4f: 0x0080, 0xf50: 0x00c0, 0xf51: 0x00c0,
+	0xf52: 0x00c0, 0xf53: 0x00c0, 0xf54: 0x00c0, 0xf55: 0x00c0, 0xf56: 0x00c0, 0xf57: 0x00c0,
+	0xf58: 0x00c3, 0xf59: 0x00c3, 0xf5a: 0x00c0, 0xf5b: 0x00c0, 0xf5c: 0x00c0, 0xf5d: 0x00c0,
+	0xf5e: 0x00c3, 0xf5f: 0x00c3, 0xf60: 0x00c3, 0xf61: 0x00c0, 0xf62: 0x00c0, 0xf63: 0x00c0,
+	0xf64: 0x00c0, 0xf65: 0x00c0, 0xf66: 0x00c0, 0xf67: 0x00c0, 0xf68: 0x00c0, 0xf69: 0x00c0,
+	0xf6a: 0x00c0, 0xf6b: 0x00c0, 0xf6c: 0x00c0, 0xf6d: 0x00c0, 0xf6e: 0x00c0, 0xf6f: 0x00c0,
+	0xf70: 0x00c0, 0xf71: 0x00c3, 0xf72: 0x00c3, 0xf73: 0x00c3, 0xf74: 0x00c3, 0xf75: 0x00c0,
+	0xf76: 0x00c0, 0xf77: 0x00c0, 0xf78: 0x00c0, 0xf79: 0x00c0, 0xf7a: 0x00c0, 0xf7b: 0x00c0,
+	0xf7c: 0x00c0, 0xf7d: 0x00c0, 0xf7e: 0x00c0, 0xf7f: 0x00c0,
+	// Block 0x3e, offset 0xf80
+	0xf80: 0x00c0, 0xf81: 0x00c0, 0xf82: 0x00c3, 0xf83: 0x00c0, 0xf84: 0x00c0, 0xf85: 0x00c3,
+	0xf86: 0x00c3, 0xf87: 0x00c0, 0xf88: 0x00c0, 0xf89: 0x00c0, 0xf8a: 0x00c0, 0xf8b: 0x00c0,
+	0xf8c: 0x00c0, 0xf8d: 0x00c3, 0xf8e: 0x00c0, 0xf8f: 0x00c0, 0xf90: 0x00c0, 0xf91: 0x00c0,
+	0xf92: 0x00c0, 0xf93: 0x00c0, 0xf94: 0x00c0, 0xf95: 0x00c0, 0xf96: 0x00c0, 0xf97: 0x00c0,
+	0xf98: 0x00c0, 0xf99: 0x00c0, 0xf9a: 0x00c0, 0xf9b: 0x00c0, 0xf9c: 0x00c0, 0xf9d: 0x00c3,
+	0xf9e: 0x0080, 0xf9f: 0x0080, 0xfa0: 0x00c0, 0xfa1: 0x00c0, 0xfa2: 0x00c0, 0xfa3: 0x00c0,
+	0xfa4: 0x00c0, 0xfa5: 0x00c0, 0xfa6: 0x00c0, 0xfa7: 0x00c0, 0xfa8: 0x00c0, 0xfa9: 0x00c0,
+	0xfaa: 0x00c0, 0xfab: 0x00c0, 0xfac: 0x00c0, 0xfad: 0x00c0, 0xfae: 0x00c0, 0xfaf: 0x00c0,
+	0xfb0: 0x00c0, 0xfb1: 0x00c0, 0xfb2: 0x00c0, 0xfb3: 0x00c0, 0xfb4: 0x00c0, 0xfb5: 0x00c0,
+	0xfb6: 0x00c0, 0xfb7: 0x00c0, 0xfb8: 0x00c0, 0xfb9: 0x00c0, 0xfba: 0x00c0, 0xfbb: 0x00c0,
+	0xfbc: 0x00c0, 0xfbd: 0x00c0, 0xfbe: 0x00c0, 0xfbf: 0x00c0,
+	// Block 0x3f, offset 0xfc0
+	0xfc0: 0x00c0, 0xfc1: 0x00c0, 0xfc2: 0x00c0, 0xfc3: 0x00c0, 0xfc4: 0x00c0, 0xfc5: 0x00c0,
+	0xfc7: 0x00c0,
+	0xfcd: 0x00c0, 0xfd0: 0x00c0, 0xfd1: 0x00c0,
+	0xfd2: 0x00c0, 0xfd3: 0x00c0, 0xfd4: 0x00c0, 0xfd5: 0x00c0, 0xfd6: 0x00c0, 0xfd7: 0x00c0,
+	0xfd8: 0x00c0, 0xfd9: 0x00c0, 0xfda: 0x00c0, 0xfdb: 0x00c0, 0xfdc: 0x00c0, 0xfdd: 0x00c0,
+	0xfde: 0x00c0, 0xfdf: 0x00c0, 0xfe0: 0x00c0, 0xfe1: 0x00c0, 0xfe2: 0x00c0, 0xfe3: 0x00c0,
+	0xfe4: 0x00c0, 0xfe5: 0x00c0, 0xfe6: 0x00c0, 0xfe7: 0x00c0, 0xfe8: 0x00c0, 0xfe9: 0x00c0,
+	0xfea: 0x00c0, 0xfeb: 0x00c0, 0xfec: 0x00c0, 0xfed: 0x00c0, 0xfee: 0x00c0, 0xfef: 0x00c0,
+	0xff0: 0x00c0, 0xff1: 0x00c0, 0xff2: 0x00c0, 0xff3: 0x00c0, 0xff4: 0x00c0, 0xff5: 0x00c0,
+	0xff6: 0x00c0, 0xff7: 0x00c0, 0xff8: 0x00c0, 0xff9: 0x00c0, 0xffa: 0x00c0, 0xffb: 0x0080,
+	0xffc: 0x0080, 0xffd: 0x00c0, 0xffe: 0x00c0, 0xfff: 0x00c0,
+	// Block 0x40, offset 0x1000
+	0x1000: 0x0040, 0x1001: 0x0040, 0x1002: 0x0040, 0x1003: 0x0040, 0x1004: 0x0040, 0x1005: 0x0040,
+	0x1006: 0x0040, 0x1007: 0x0040, 0x1008: 0x0040, 0x1009: 0x0040, 0x100a: 0x0040, 0x100b: 0x0040,
+	0x100c: 0x0040, 0x100d: 0x0040, 0x100e: 0x0040, 0x100f: 0x0040, 0x1010: 0x0040, 0x1011: 0x0040,
+	0x1012: 0x0040, 0x1013: 0x0040, 0x1014: 0x0040, 0x1015: 0x0040, 0x1016: 0x0040, 0x1017: 0x0040,
+	0x1018: 0x0040, 0x1019: 0x0040, 0x101a: 0x0040, 0x101b: 0x0040, 0x101c: 0x0040, 0x101d: 0x0040,
+	0x101e: 0x0040, 0x101f: 0x0040, 0x1020: 0x0040, 0x1021: 0x0040, 0x1022: 0x0040, 0x1023: 0x0040,
+	0x1024: 0x0040, 0x1025: 0x0040, 0x1026: 0x0040, 0x1027: 0x0040, 0x1028: 0x0040, 0x1029: 0x0040,
+	0x102a: 0x0040, 0x102b: 0x0040, 0x102c: 0x0040, 0x102d: 0x0040, 0x102e: 0x0040, 0x102f: 0x0040,
+	0x1030: 0x0040, 0x1031: 0x0040, 0x1032: 0x0040, 0x1033: 0x0040, 0x1034: 0x0040, 0x1035: 0x0040,
+	0x1036: 0x0040, 0x1037: 0x0040, 0x1038: 0x0040, 0x1039: 0x0040, 0x103a: 0x0040, 0x103b: 0x0040,
+	0x103c: 0x0040, 0x103d: 0x0040, 0x103e: 0x0040, 0x103f: 0x0040,
+	// Block 0x41, offset 0x1040
+	0x1040: 0x00c0, 0x1041: 0x00c0, 0x1042: 0x00c0, 0x1043: 0x00c0, 0x1044: 0x00c0, 0x1045: 0x00c0,
+	0x1046: 0x00c0, 0x1047: 0x00c0, 0x1048: 0x00c0, 0x104a: 0x00c0, 0x104b: 0x00c0,
+	0x104c: 0x00c0, 0x104d: 0x00c0, 0x1050: 0x00c0, 0x1051: 0x00c0,
+	0x1052: 0x00c0, 0x1053: 0x00c0, 0x1054: 0x00c0, 0x1055: 0x00c0, 0x1056: 0x00c0,
+	0x1058: 0x00c0, 0x105a: 0x00c0, 0x105b: 0x00c0, 0x105c: 0x00c0, 0x105d: 0x00c0,
+	0x1060: 0x00c0, 0x1061: 0x00c0, 0x1062: 0x00c0, 0x1063: 0x00c0,
+	0x1064: 0x00c0, 0x1065: 0x00c0, 0x1066: 0x00c0, 0x1067: 0x00c0, 0x1068: 0x00c0, 0x1069: 0x00c0,
+	0x106a: 0x00c0, 0x106b: 0x00c0, 0x106c: 0x00c0, 0x106d: 0x00c0, 0x106e: 0x00c0, 0x106f: 0x00c0,
+	0x1070: 0x00c0, 0x1071: 0x00c0, 0x1072: 0x00c0, 0x1073: 0x00c0, 0x1074: 0x00c0, 0x1075: 0x00c0,
+	0x1076: 0x00c0, 0x1077: 0x00c0, 0x1078: 0x00c0, 0x1079: 0x00c0, 0x107a: 0x00c0, 0x107b: 0x00c0,
+	0x107c: 0x00c0, 0x107d: 0x00c0, 0x107e: 0x00c0, 0x107f: 0x00c0,
+	// Block 0x42, offset 0x1080
+	0x1080: 0x00c0, 0x1081: 0x00c0, 0x1082: 0x00c0, 0x1083: 0x00c0, 0x1084: 0x00c0, 0x1085: 0x00c0,
+	0x1086: 0x00c0, 0x1087: 0x00c0, 0x1088: 0x00c0, 0x108a: 0x00c0, 0x108b: 0x00c0,
+	0x108c: 0x00c0, 0x108d: 0x00c0, 0x1090: 0x00c0, 0x1091: 0x00c0,
+	0x1092: 0x00c0, 0x1093: 0x00c0, 0x1094: 0x00c0, 0x1095: 0x00c0, 0x1096: 0x00c0, 0x1097: 0x00c0,
+	0x1098: 0x00c0, 0x1099: 0x00c0, 0x109a: 0x00c0, 0x109b: 0x00c0, 0x109c: 0x00c0, 0x109d: 0x00c0,
+	0x109e: 0x00c0, 0x109f: 0x00c0, 0x10a0: 0x00c0, 0x10a1: 0x00c0, 0x10a2: 0x00c0, 0x10a3: 0x00c0,
+	0x10a4: 0x00c0, 0x10a5: 0x00c0, 0x10a6: 0x00c0, 0x10a7: 0x00c0, 0x10a8: 0x00c0, 0x10a9: 0x00c0,
+	0x10aa: 0x00c0, 0x10ab: 0x00c0, 0x10ac: 0x00c0, 0x10ad: 0x00c0, 0x10ae: 0x00c0, 0x10af: 0x00c0,
+	0x10b0: 0x00c0, 0x10b2: 0x00c0, 0x10b3: 0x00c0, 0x10b4: 0x00c0, 0x10b5: 0x00c0,
+	0x10b8: 0x00c0, 0x10b9: 0x00c0, 0x10ba: 0x00c0, 0x10bb: 0x00c0,
+	0x10bc: 0x00c0, 0x10bd: 0x00c0, 0x10be: 0x00c0,
+	// Block 0x43, offset 0x10c0
+	0x10c0: 0x00c0, 0x10c2: 0x00c0, 0x10c3: 0x00c0, 0x10c4: 0x00c0, 0x10c5: 0x00c0,
+	0x10c8: 0x00c0, 0x10c9: 0x00c0, 0x10ca: 0x00c0, 0x10cb: 0x00c0,
+	0x10cc: 0x00c0, 0x10cd: 0x00c0, 0x10ce: 0x00c0, 0x10cf: 0x00c0, 0x10d0: 0x00c0, 0x10d1: 0x00c0,
+	0x10d2: 0x00c0, 0x10d3: 0x00c0, 0x10d4: 0x00c0, 0x10d5: 0x00c0, 0x10d6: 0x00c0,
+	0x10d8: 0x00c0, 0x10d9: 0x00c0, 0x10da: 0x00c0, 0x10db: 0x00c0, 0x10dc: 0x00c0, 0x10dd: 0x00c0,
+	0x10de: 0x00c0, 0x10df: 0x00c0, 0x10e0: 0x00c0, 0x10e1: 0x00c0, 0x10e2: 0x00c0, 0x10e3: 0x00c0,
+	0x10e4: 0x00c0, 0x10e5: 0x00c0, 0x10e6: 0x00c0, 0x10e7: 0x00c0, 0x10e8: 0x00c0, 0x10e9: 0x00c0,
+	0x10ea: 0x00c0, 0x10eb: 0x00c0, 0x10ec: 0x00c0, 0x10ed: 0x00c0, 0x10ee: 0x00c0, 0x10ef: 0x00c0,
+	0x10f0: 0x00c0, 0x10f1: 0x00c0, 0x10f2: 0x00c0, 0x10f3: 0x00c0, 0x10f4: 0x00c0, 0x10f5: 0x00c0,
+	0x10f6: 0x00c0, 0x10f7: 0x00c0, 0x10f8: 0x00c0, 0x10f9: 0x00c0, 0x10fa: 0x00c0, 0x10fb: 0x00c0,
+	0x10fc: 0x00c0, 0x10fd: 0x00c0, 0x10fe: 0x00c0, 0x10ff: 0x00c0,
+	// Block 0x44, offset 0x1100
+	0x1100: 0x00c0, 0x1101: 0x00c0, 0x1102: 0x00c0, 0x1103: 0x00c0, 0x1104: 0x00c0, 0x1105: 0x00c0,
+	0x1106: 0x00c0, 0x1107: 0x00c0, 0x1108: 0x00c0, 0x1109: 0x00c0, 0x110a: 0x00c0, 0x110b: 0x00c0,
+	0x110c: 0x00c0, 0x110d: 0x00c0, 0x110e: 0x00c0, 0x110f: 0x00c0, 0x1110: 0x00c0,
+	0x1112: 0x00c0, 0x1113: 0x00c0, 0x1114: 0x00c0, 0x1115: 0x00c0,
+	0x1118: 0x00c0, 0x1119: 0x00c0, 0x111a: 0x00c0, 0x111b: 0x00c0, 0x111c: 0x00c0, 0x111d: 0x00c0,
+	0x111e: 0x00c0, 0x111f: 0x00c0, 0x1120: 0x00c0, 0x1121: 0x00c0, 0x1122: 0x00c0, 0x1123: 0x00c0,
+	0x1124: 0x00c0, 0x1125: 0x00c0, 0x1126: 0x00c0, 0x1127: 0x00c0, 0x1128: 0x00c0, 0x1129: 0x00c0,
+	0x112a: 0x00c0, 0x112b: 0x00c0, 0x112c: 0x00c0, 0x112d: 0x00c0, 0x112e: 0x00c0, 0x112f: 0x00c0,
+	0x1130: 0x00c0, 0x1131: 0x00c0, 0x1132: 0x00c0, 0x1133: 0x00c0, 0x1134: 0x00c0, 0x1135: 0x00c0,
+	0x1136: 0x00c0, 0x1137: 0x00c0, 0x1138: 0x00c0, 0x1139: 0x00c0, 0x113a: 0x00c0, 0x113b: 0x00c0,
+	0x113c: 0x00c0, 0x113d: 0x00c0, 0x113e: 0x00c0, 0x113f: 0x00c0,
+	// Block 0x45, offset 0x1140
+	0x1140: 0x00c0, 0x1141: 0x00c0, 0x1142: 0x00c0, 0x1143: 0x00c0, 0x1144: 0x00c0, 0x1145: 0x00c0,
+	0x1146: 0x00c0, 0x1147: 0x00c0, 0x1148: 0x00c0, 0x1149: 0x00c0, 0x114a: 0x00c0, 0x114b: 0x00c0,
+	0x114c: 0x00c0, 0x114d: 0x00c0, 0x114e: 0x00c0, 0x114f: 0x00c0, 0x1150: 0x00c0, 0x1151: 0x00c0,
+	0x1152: 0x00c0, 0x1153: 0x00c0, 0x1154: 0x00c0, 0x1155: 0x00c0, 0x1156: 0x00c0, 0x1157: 0x00c0,
+	0x1158: 0x00c0, 0x1159: 0x00c0, 0x115a: 0x00c0, 0x115d: 0x00c3,
+	0x115e: 0x00c3, 0x115f: 0x00c3, 0x1160: 0x0080, 0x1161: 0x0080, 0x1162: 0x0080, 0x1163: 0x0080,
+	0x1164: 0x0080, 0x1165: 0x0080, 0x1166: 0x0080, 0x1167: 0x0080, 0x1168: 0x0080, 0x1169: 0x0080,
+	0x116a: 0x0080, 0x116b: 0x0080, 0x116c: 0x0080, 0x116d: 0x0080, 0x116e: 0x0080, 0x116f: 0x0080,
+	0x1170: 0x0080, 0x1171: 0x0080, 0x1172: 0x0080, 0x1173: 0x0080, 0x1174: 0x0080, 0x1175: 0x0080,
+	0x1176: 0x0080, 0x1177: 0x0080, 0x1178: 0x0080, 0x1179: 0x0080, 0x117a: 0x0080, 0x117b: 0x0080,
+	0x117c: 0x0080,
+	// Block 0x46, offset 0x1180
+	0x1180: 0x00c0, 0x1181: 0x00c0, 0x1182: 0x00c0, 0x1183: 0x00c0, 0x1184: 0x00c0, 0x1185: 0x00c0,
+	0x1186: 0x00c0, 0x1187: 0x00c0, 0x1188: 0x00c0, 0x1189: 0x00c0, 0x118a: 0x00c0, 0x118b: 0x00c0,
+	0x118c: 0x00c0, 0x118d: 0x00c0, 0x118e: 0x00c0, 0x118f: 0x00c0, 0x1190: 0x0080, 0x1191: 0x0080,
+	0x1192: 0x0080, 0x1193: 0x0080, 0x1194: 0x0080, 0x1195: 0x0080, 0x1196: 0x0080, 0x1197: 0x0080,
+	0x1198: 0x0080, 0x1199: 0x0080,
+	0x11a0: 0x00c0, 0x11a1: 0x00c0, 0x11a2: 0x00c0, 0x11a3: 0x00c0,
+	0x11a4: 0x00c0, 0x11a5: 0x00c0, 0x11a6: 0x00c0, 0x11a7: 0x00c0, 0x11a8: 0x00c0, 0x11a9: 0x00c0,
+	0x11aa: 0x00c0, 0x11ab: 0x00c0, 0x11ac: 0x00c0, 0x11ad: 0x00c0, 0x11ae: 0x00c0, 0x11af: 0x00c0,
+	0x11b0: 0x00c0, 0x11b1: 0x00c0, 0x11b2: 0x00c0, 0x11b3: 0x00c0, 0x11b4: 0x00c0, 0x11b5: 0x00c0,
+	0x11b6: 0x00c0, 0x11b7: 0x00c0, 0x11b8: 0x00c0, 0x11b9: 0x00c0, 0x11ba: 0x00c0, 0x11bb: 0x00c0,
+	0x11bc: 0x00c0, 0x11bd: 0x00c0, 0x11be: 0x00c0, 0x11bf: 0x00c0,
+	// Block 0x47, offset 0x11c0
+	0x11c0: 0x00c0, 0x11c1: 0x00c0, 0x11c2: 0x00c0, 0x11c3: 0x00c0, 0x11c4: 0x00c0, 0x11c5: 0x00c0,
+	0x11c6: 0x00c0, 0x11c7: 0x00c0, 0x11c8: 0x00c0, 0x11c9: 0x00c0, 0x11ca: 0x00c0, 0x11cb: 0x00c0,
+	0x11cc: 0x00c0, 0x11cd: 0x00c0, 0x11ce: 0x00c0, 0x11cf: 0x00c0, 0x11d0: 0x00c0, 0x11d1: 0x00c0,
+	0x11d2: 0x00c0, 0x11d3: 0x00c0, 0x11d4: 0x00c0, 0x11d5: 0x00c0, 0x11d6: 0x00c0, 0x11d7: 0x00c0,
+	0x11d8: 0x00c0, 0x11d9: 0x00c0, 0x11da: 0x00c0, 0x11db: 0x00c0, 0x11dc: 0x00c0, 0x11dd: 0x00c0,
+	0x11de: 0x00c0, 0x11df: 0x00c0, 0x11e0: 0x00c0, 0x11e1: 0x00c0, 0x11e2: 0x00c0, 0x11e3: 0x00c0,
+	0x11e4: 0x00c0, 0x11e5: 0x00c0, 0x11e6: 0x00c0, 0x11e7: 0x00c0, 0x11e8: 0x00c0, 0x11e9: 0x00c0,
+	0x11ea: 0x00c0, 0x11eb: 0x00c0, 0x11ec: 0x00c0, 0x11ed: 0x00c0, 0x11ee: 0x00c0, 0x11ef: 0x00c0,
+	0x11f0: 0x00c0, 0x11f1: 0x00c0, 0x11f2: 0x00c0, 0x11f3: 0x00c0, 0x11f4: 0x00c0, 0x11f5: 0x00c0,
+	0x11f8: 0x00c0, 0x11f9: 0x00c0, 0x11fa: 0x00c0, 0x11fb: 0x00c0,
+	0x11fc: 0x00c0, 0x11fd: 0x00c0,
+	// Block 0x48, offset 0x1200
+	0x1200: 0x0080, 0x1201: 0x00c0, 0x1202: 0x00c0, 0x1203: 0x00c0, 0x1204: 0x00c0, 0x1205: 0x00c0,
+	0x1206: 0x00c0, 0x1207: 0x00c0, 0x1208: 0x00c0, 0x1209: 0x00c0, 0x120a: 0x00c0, 0x120b: 0x00c0,
+	0x120c: 0x00c0, 0x120d: 0x00c0, 0x120e: 0x00c0, 0x120f: 0x00c0, 0x1210: 0x00c0, 0x1211: 0x00c0,
+	0x1212: 0x00c0, 0x1213: 0x00c0, 0x1214: 0x00c0, 0x1215: 0x00c0, 0x1216: 0x00c0, 0x1217: 0x00c0,
+	0x1218: 0x00c0, 0x1219: 0x00c0, 0x121a: 0x00c0, 0x121b: 0x00c0, 0x121c: 0x00c0, 0x121d: 0x00c0,
+	0x121e: 0x00c0, 0x121f: 0x00c0, 0x1220: 0x00c0, 0x1221: 0x00c0, 0x1222: 0x00c0, 0x1223: 0x00c0,
+	0x1224: 0x00c0, 0x1225: 0x00c0, 0x1226: 0x00c0, 0x1227: 0x00c0, 0x1228: 0x00c0, 0x1229: 0x00c0,
+	0x122a: 0x00c0, 0x122b: 0x00c0, 0x122c: 0x00c0, 0x122d: 0x00c0, 0x122e: 0x00c0, 0x122f: 0x00c0,
+	0x1230: 0x00c0, 0x1231: 0x00c0, 0x1232: 0x00c0, 0x1233: 0x00c0, 0x1234: 0x00c0, 0x1235: 0x00c0,
+	0x1236: 0x00c0, 0x1237: 0x00c0, 0x1238: 0x00c0, 0x1239: 0x00c0, 0x123a: 0x00c0, 0x123b: 0x00c0,
+	0x123c: 0x00c0, 0x123d: 0x00c0, 0x123e: 0x00c0, 0x123f: 0x00c0,
+	// Block 0x49, offset 0x1240
+	0x1240: 0x00c0, 0x1241: 0x00c0, 0x1242: 0x00c0, 0x1243: 0x00c0, 0x1244: 0x00c0, 0x1245: 0x00c0,
+	0x1246: 0x00c0, 0x1247: 0x00c0, 0x1248: 0x00c0, 0x1249: 0x00c0, 0x124a: 0x00c0, 0x124b: 0x00c0,
+	0x124c: 0x00c0, 0x124d: 0x00c0, 0x124e: 0x00c0, 0x124f: 0x00c0, 0x1250: 0x00c0, 0x1251: 0x00c0,
+	0x1252: 0x00c0, 0x1253: 0x00c0, 0x1254: 0x00c0, 0x1255: 0x00c0, 0x1256: 0x00c0, 0x1257: 0x00c0,
+	0x1258: 0x00c0, 0x1259: 0x00c0, 0x125a: 0x00c0, 0x125b: 0x00c0, 0x125c: 0x00c0, 0x125d: 0x00c0,
+	0x125e: 0x00c0, 0x125f: 0x00c0, 0x1260: 0x00c0, 0x1261: 0x00c0, 0x1262: 0x00c0, 0x1263: 0x00c0,
+	0x1264: 0x00c0, 0x1265: 0x00c0, 0x1266: 0x00c0, 0x1267: 0x00c0, 0x1268: 0x00c0, 0x1269: 0x00c0,
+	0x126a: 0x00c0, 0x126b: 0x00c0, 0x126c: 0x00c0, 0x126d: 0x0080, 0x126e: 0x0080, 0x126f: 0x00c0,
+	0x1270: 0x00c0, 0x1271: 0x00c0, 0x1272: 0x00c0, 0x1273: 0x00c0, 0x1274: 0x00c0, 0x1275: 0x00c0,
+	0x1276: 0x00c0, 0x1277: 0x00c0, 0x1278: 0x00c0, 0x1279: 0x00c0, 0x127a: 0x00c0, 0x127b: 0x00c0,
+	0x127c: 0x00c0, 0x127d: 0x00c0, 0x127e: 0x00c0, 0x127f: 0x00c0,
+	// Block 0x4a, offset 0x1280
+	0x1280: 0x0080, 0x1281: 0x00c0, 0x1282: 0x00c0, 0x1283: 0x00c0, 0x1284: 0x00c0, 0x1285: 0x00c0,
+	0x1286: 0x00c0, 0x1287: 0x00c0, 0x1288: 0x00c0, 0x1289: 0x00c0, 0x128a: 0x00c0, 0x128b: 0x00c0,
+	0x128c: 0x00c0, 0x128d: 0x00c0, 0x128e: 0x00c0, 0x128f: 0x00c0, 0x1290: 0x00c0, 0x1291: 0x00c0,
+	0x1292: 0x00c0, 0x1293: 0x00c0, 0x1294: 0x00c0, 0x1295: 0x00c0, 0x1296: 0x00c0, 0x1297: 0x00c0,
+	0x1298: 0x00c0, 0x1299: 0x00c0, 0x129a: 0x00c0, 0x129b: 0x0080, 0x129c: 0x0080,
+	0x12a0: 0x00c0, 0x12a1: 0x00c0, 0x12a2: 0x00c0, 0x12a3: 0x00c0,
+	0x12a4: 0x00c0, 0x12a5: 0x00c0, 0x12a6: 0x00c0, 0x12a7: 0x00c0, 0x12a8: 0x00c0, 0x12a9: 0x00c0,
+	0x12aa: 0x00c0, 0x12ab: 0x00c0, 0x12ac: 0x00c0, 0x12ad: 0x00c0, 0x12ae: 0x00c0, 0x12af: 0x00c0,
+	0x12b0: 0x00c0, 0x12b1: 0x00c0, 0x12b2: 0x00c0, 0x12b3: 0x00c0, 0x12b4: 0x00c0, 0x12b5: 0x00c0,
+	0x12b6: 0x00c0, 0x12b7: 0x00c0, 0x12b8: 0x00c0, 0x12b9: 0x00c0, 0x12ba: 0x00c0, 0x12bb: 0x00c0,
+	0x12bc: 0x00c0, 0x12bd: 0x00c0, 0x12be: 0x00c0, 0x12bf: 0x00c0,
+	// Block 0x4b, offset 0x12c0
+	0x12c0: 0x00c0, 0x12c1: 0x00c0, 0x12c2: 0x00c0, 0x12c3: 0x00c0, 0x12c4: 0x00c0, 0x12c5: 0x00c0,
+	0x12c6: 0x00c0, 0x12c7: 0x00c0, 0x12c8: 0x00c0, 0x12c9: 0x00c0, 0x12ca: 0x00c0, 0x12cb: 0x00c0,
+	0x12cc: 0x00c0, 0x12cd: 0x00c0, 0x12ce: 0x00c0, 0x12cf: 0x00c0, 0x12d0: 0x00c0, 0x12d1: 0x00c0,
+	0x12d2: 0x00c0, 0x12d3: 0x00c0, 0x12d4: 0x00c0, 0x12d5: 0x00c0, 0x12d6: 0x00c0, 0x12d7: 0x00c0,
+	0x12d8: 0x00c0, 0x12d9: 0x00c0, 0x12da: 0x00c0, 0x12db: 0x00c0, 0x12dc: 0x00c0, 0x12dd: 0x00c0,
+	0x12de: 0x00c0, 0x12df: 0x00c0, 0x12e0: 0x00c0, 0x12e1: 0x00c0, 0x12e2: 0x00c0, 0x12e3: 0x00c0,
+	0x12e4: 0x00c0, 0x12e5: 0x00c0, 0x12e6: 0x00c0, 0x12e7: 0x00c0, 0x12e8: 0x00c0, 0x12e9: 0x00c0,
+	0x12ea: 0x00c0, 0x12eb: 0x0080, 0x12ec: 0x0080, 0x12ed: 0x0080, 0x12ee: 0x0080, 0x12ef: 0x0080,
+	0x12f0: 0x0080, 0x12f1: 0x00c0, 0x12f2: 0x00c0, 0x12f3: 0x00c0, 0x12f4: 0x00c0, 0x12f5: 0x00c0,
+	0x12f6: 0x00c0, 0x12f7: 0x00c0, 0x12f8: 0x00c0,
+	// Block 0x4c, offset 0x1300
+	0x1300: 0x00c0, 0x1301: 0x00c0, 0x1302: 0x00c0, 0x1303: 0x00c0, 0x1304: 0x00c0, 0x1305: 0x00c0,
+	0x1306: 0x00c0, 0x1307: 0x00c0, 0x1308: 0x00c0, 0x1309: 0x00c0, 0x130a: 0x00c0, 0x130b: 0x00c0,
+	0x130c: 0x00c0, 0x130d: 0x00c0, 0x130e: 0x00c0, 0x130f: 0x00c0, 0x1310: 0x00c0, 0x1311: 0x00c0,
+	0x1312: 0x00c3, 0x1313: 0x00c3, 0x1314: 0x00c6, 0x1315: 0x00c5,
+	0x131f: 0x00c0, 0x1320: 0x00c0, 0x1321: 0x00c0, 0x1322: 0x00c0, 0x1323: 0x00c0,
+	0x1324: 0x00c0, 0x1325: 0x00c0, 0x1326: 0x00c0, 0x1327: 0x00c0, 0x1328: 0x00c0, 0x1329: 0x00c0,
+	0x132a: 0x00c0, 0x132b: 0x00c0, 0x132c: 0x00c0, 0x132d: 0x00c0, 0x132e: 0x00c0, 0x132f: 0x00c0,
+	0x1330: 0x00c0, 0x1331: 0x00c0, 0x1332: 0x00c3, 0x1333: 0x00c3, 0x1334: 0x00c5, 0x1335: 0x0080,
+	0x1336: 0x0080,
+	// Block 0x4d, offset 0x1340
+	0x1340: 0x00c0, 0x1341: 0x00c0, 0x1342: 0x00c0, 0x1343: 0x00c0, 0x1344: 0x00c0, 0x1345: 0x00c0,
+	0x1346: 0x00c0, 0x1347: 0x00c0, 0x1348: 0x00c0, 0x1349: 0x00c0, 0x134a: 0x00c0, 0x134b: 0x00c0,
+	0x134c: 0x00c0, 0x134d: 0x00c0, 0x134e: 0x00c0, 0x134f: 0x00c0, 0x1350: 0x00c0, 0x1351: 0x00c0,
+	0x1352: 0x00c3, 0x1353: 0x00c3,
+	0x1360: 0x00c0, 0x1361: 0x00c0, 0x1362: 0x00c0, 0x1363: 0x00c0,
+	0x1364: 0x00c0, 0x1365: 0x00c0, 0x1366: 0x00c0, 0x1367: 0x00c0, 0x1368: 0x00c0, 0x1369: 0x00c0,
+	0x136a: 0x00c0, 0x136b: 0x00c0, 0x136c: 0x00c0, 0x136e: 0x00c0, 0x136f: 0x00c0,
+	0x1370: 0x00c0, 0x1372: 0x00c3, 0x1373: 0x00c3,
+	// Block 0x4e, offset 0x1380
+	0x1380: 0x00c0, 0x1381: 0x00c0, 0x1382: 0x00c0, 0x1383: 0x00c0, 0x1384: 0x00c0, 0x1385: 0x00c0,
+	0x1386: 0x00c0, 0x1387: 0x00c0, 0x1388: 0x00c0, 0x1389: 0x00c0, 0x138a: 0x00c0, 0x138b: 0x00c0,
+	0x138c: 0x00c0, 0x138d: 0x00c0, 0x138e: 0x00c0, 0x138f: 0x00c0, 0x1390: 0x00c0, 0x1391: 0x00c0,
+	0x1392: 0x00c0, 0x1393: 0x00c0, 0x1394: 0x00c0, 0x1395: 0x00c0, 0x1396: 0x00c0, 0x1397: 0x00c0,
+	0x1398: 0x00c0, 0x1399: 0x00c0, 0x139a: 0x00c0, 0x139b: 0x00c0, 0x139c: 0x00c0, 0x139d: 0x00c0,
+	0x139e: 0x00c0, 0x139f: 0x00c0, 0x13a0: 0x00c0, 0x13a1: 0x00c0, 0x13a2: 0x00c0, 0x13a3: 0x00c0,
+	0x13a4: 0x00c0, 0x13a5: 0x00c0, 0x13a6: 0x00c0, 0x13a7: 0x00c0, 0x13a8: 0x00c0, 0x13a9: 0x00c0,
+	0x13aa: 0x00c0, 0x13ab: 0x00c0, 0x13ac: 0x00c0, 0x13ad: 0x00c0, 0x13ae: 0x00c0, 0x13af: 0x00c0,
+	0x13b0: 0x00c0, 0x13b1: 0x00c0, 0x13b2: 0x00c0, 0x13b3: 0x00c0, 0x13b4: 0x0040, 0x13b5: 0x0040,
+	0x13b6: 0x00c0, 0x13b7: 0x00c3, 0x13b8: 0x00c3, 0x13b9: 0x00c3, 0x13ba: 0x00c3, 0x13bb: 0x00c3,
+	0x13bc: 0x00c3, 0x13bd: 0x00c3, 0x13be: 0x00c0, 0x13bf: 0x00c0,
+	// Block 0x4f, offset 0x13c0
+	0x13c0: 0x00c0, 0x13c1: 0x00c0, 0x13c2: 0x00c0, 0x13c3: 0x00c0, 0x13c4: 0x00c0, 0x13c5: 0x00c0,
+	0x13c6: 0x00c3, 0x13c7: 0x00c0, 0x13c8: 0x00c0, 0x13c9: 0x00c3, 0x13ca: 0x00c3, 0x13cb: 0x00c3,
+	0x13cc: 0x00c3, 0x13cd: 0x00c3, 0x13ce: 0x00c3, 0x13cf: 0x00c3, 0x13d0: 0x00c3, 0x13d1: 0x00c3,
+	0x13d2: 0x00c6, 0x13d3: 0x00c3, 0x13d4: 0x0080, 0x13d5: 0x0080, 0x13d6: 0x0080, 0x13d7: 0x00c0,
+	0x13d8: 0x0080, 0x13d9: 0x0080, 0x13da: 0x0080, 0x13db: 0x0080, 0x13dc: 0x00c0, 0x13dd: 0x00c3,
+	0x13e0: 0x00c0, 0x13e1: 0x00c0, 0x13e2: 0x00c0, 0x13e3: 0x00c0,
+	0x13e4: 0x00c0, 0x13e5: 0x00c0, 0x13e6: 0x00c0, 0x13e7: 0x00c0, 0x13e8: 0x00c0, 0x13e9: 0x00c0,
+	0x13f0: 0x0080, 0x13f1: 0x0080, 0x13f2: 0x0080, 0x13f3: 0x0080, 0x13f4: 0x0080, 0x13f5: 0x0080,
+	0x13f6: 0x0080, 0x13f7: 0x0080, 0x13f8: 0x0080, 0x13f9: 0x0080,
+	// Block 0x50, offset 0x1400
+	0x1400: 0x0080, 0x1401: 0x0080, 0x1402: 0x0080, 0x1403: 0x0080, 0x1404: 0x0080, 0x1405: 0x0080,
+	0x1406: 0x0080, 0x1407: 0x0082, 0x1408: 0x0080, 0x1409: 0x0080, 0x140a: 0x0080, 0x140b: 0x0040,
+	0x140c: 0x0040, 0x140d: 0x0040, 0x140e: 0x0040, 0x140f: 0x0040, 0x1410: 0x00c0, 0x1411: 0x00c0,
+	0x1412: 0x00c0, 0x1413: 0x00c0, 0x1414: 0x00c0, 0x1415: 0x00c0, 0x1416: 0x00c0, 0x1417: 0x00c0,
+	0x1418: 0x00c0, 0x1419: 0x00c0,
+	0x1420: 0x00c2, 0x1421: 0x00c2, 0x1422: 0x00c2, 0x1423: 0x00c2,
+	0x1424: 0x00c2, 0x1425: 0x00c2, 0x1426: 0x00c2, 0x1427: 0x00c2, 0x1428: 0x00c2, 0x1429: 0x00c2,
+	0x142a: 0x00c2, 0x142b: 0x00c2, 0x142c: 0x00c2, 0x142d: 0x00c2, 0x142e: 0x00c2, 0x142f: 0x00c2,
+	0x1430: 0x00c2, 0x1431: 0x00c2, 0x1432: 0x00c2, 0x1433: 0x00c2, 0x1434: 0x00c2, 0x1435: 0x00c2,
+	0x1436: 0x00c2, 0x1437: 0x00c2, 0x1438: 0x00c2, 0x1439: 0x00c2, 0x143a: 0x00c2, 0x143b: 0x00c2,
+	0x143c: 0x00c2, 0x143d: 0x00c2, 0x143e: 0x00c2, 0x143f: 0x00c2,
+	// Block 0x51, offset 0x1440
+	0x1440: 0x00c2, 0x1441: 0x00c2, 0x1442: 0x00c2, 0x1443: 0x00c2, 0x1444: 0x00c2, 0x1445: 0x00c2,
+	0x1446: 0x00c2, 0x1447: 0x00c2, 0x1448: 0x00c2, 0x1449: 0x00c2, 0x144a: 0x00c2, 0x144b: 0x00c2,
+	0x144c: 0x00c2, 0x144d: 0x00c2, 0x144e: 0x00c2, 0x144f: 0x00c2, 0x1450: 0x00c2, 0x1451: 0x00c2,
+	0x1452: 0x00c2, 0x1453: 0x00c2, 0x1454: 0x00c2, 0x1455: 0x00c2, 0x1456: 0x00c2, 0x1457: 0x00c2,
+	0x1458: 0x00c2, 0x1459: 0x00c2, 0x145a: 0x00c2, 0x145b: 0x00c2, 0x145c: 0x00c2, 0x145d: 0x00c2,
+	0x145e: 0x00c2, 0x145f: 0x00c2, 0x1460: 0x00c2, 0x1461: 0x00c2, 0x1462: 0x00c2, 0x1463: 0x00c2,
+	0x1464: 0x00c2, 0x1465: 0x00c2, 0x1466: 0x00c2, 0x1467: 0x00c2, 0x1468: 0x00c2, 0x1469: 0x00c2,
+	0x146a: 0x00c2, 0x146b: 0x00c2, 0x146c: 0x00c2, 0x146d: 0x00c2, 0x146e: 0x00c2, 0x146f: 0x00c2,
+	0x1470: 0x00c2, 0x1471: 0x00c2, 0x1472: 0x00c2, 0x1473: 0x00c2, 0x1474: 0x00c2, 0x1475: 0x00c2,
+	0x1476: 0x00c2, 0x1477: 0x00c2, 0x1478: 0x00c2,
+	// Block 0x52, offset 0x1480
+	0x1480: 0x00c0, 0x1481: 0x00c0, 0x1482: 0x00c0, 0x1483: 0x00c0, 0x1484: 0x00c0, 0x1485: 0x00c3,
+	0x1486: 0x00c3, 0x1487: 0x00c2, 0x1488: 0x00c2, 0x1489: 0x00c2, 0x148a: 0x00c2, 0x148b: 0x00c2,
+	0x148c: 0x00c2, 0x148d: 0x00c2, 0x148e: 0x00c2, 0x148f: 0x00c2, 0x1490: 0x00c2, 0x1491: 0x00c2,
+	0x1492: 0x00c2, 0x1493: 0x00c2, 0x1494: 0x00c2, 0x1495: 0x00c2, 0x1496: 0x00c2, 0x1497: 0x00c2,
+	0x1498: 0x00c2, 0x1499: 0x00c2, 0x149a: 0x00c2, 0x149b: 0x00c2, 0x149c: 0x00c2, 0x149d: 0x00c2,
+	0x149e: 0x00c2, 0x149f: 0x00c2, 0x14a0: 0x00c2, 0x14a1: 0x00c2, 0x14a2: 0x00c2, 0x14a3: 0x00c2,
+	0x14a4: 0x00c2, 0x14a5: 0x00c2, 0x14a6: 0x00c2, 0x14a7: 0x00c2, 0x14a8: 0x00c2, 0x14a9: 0x00c3,
+	0x14aa: 0x00c2,
+	0x14b0: 0x00c0, 0x14b1: 0x00c0, 0x14b2: 0x00c0, 0x14b3: 0x00c0, 0x14b4: 0x00c0, 0x14b5: 0x00c0,
+	0x14b6: 0x00c0, 0x14b7: 0x00c0, 0x14b8: 0x00c0, 0x14b9: 0x00c0, 0x14ba: 0x00c0, 0x14bb: 0x00c0,
+	0x14bc: 0x00c0, 0x14bd: 0x00c0, 0x14be: 0x00c0, 0x14bf: 0x00c0,
+	// Block 0x53, offset 0x14c0
+	0x14c0: 0x00c0, 0x14c1: 0x00c0, 0x14c2: 0x00c0, 0x14c3: 0x00c0, 0x14c4: 0x00c0, 0x14c5: 0x00c0,
+	0x14c6: 0x00c0, 0x14c7: 0x00c0, 0x14c8: 0x00c0, 0x14c9: 0x00c0, 0x14ca: 0x00c0, 0x14cb: 0x00c0,
+	0x14cc: 0x00c0, 0x14cd: 0x00c0, 0x14ce: 0x00c0, 0x14cf: 0x00c0, 0x14d0: 0x00c0, 0x14d1: 0x00c0,
+	0x14d2: 0x00c0, 0x14d3: 0x00c0, 0x14d4: 0x00c0, 0x14d5: 0x00c0, 0x14d6: 0x00c0, 0x14d7: 0x00c0,
+	0x14d8: 0x00c0, 0x14d9: 0x00c0, 0x14da: 0x00c0, 0x14db: 0x00c0, 0x14dc: 0x00c0, 0x14dd: 0x00c0,
+	0x14de: 0x00c0, 0x14df: 0x00c0, 0x14e0: 0x00c0, 0x14e1: 0x00c0, 0x14e2: 0x00c0, 0x14e3: 0x00c0,
+	0x14e4: 0x00c0, 0x14e5: 0x00c0, 0x14e6: 0x00c0, 0x14e7: 0x00c0, 0x14e8: 0x00c0, 0x14e9: 0x00c0,
+	0x14ea: 0x00c0, 0x14eb: 0x00c0, 0x14ec: 0x00c0, 0x14ed: 0x00c0, 0x14ee: 0x00c0, 0x14ef: 0x00c0,
+	0x14f0: 0x00c0, 0x14f1: 0x00c0, 0x14f2: 0x00c0, 0x14f3: 0x00c0, 0x14f4: 0x00c0, 0x14f5: 0x00c0,
+	// Block 0x54, offset 0x1500
+	0x1500: 0x00c0, 0x1501: 0x00c0, 0x1502: 0x00c0, 0x1503: 0x00c0, 0x1504: 0x00c0, 0x1505: 0x00c0,
+	0x1506: 0x00c0, 0x1507: 0x00c0, 0x1508: 0x00c0, 0x1509: 0x00c0, 0x150a: 0x00c0, 0x150b: 0x00c0,
+	0x150c: 0x00c0, 0x150d: 0x00c0, 0x150e: 0x00c0, 0x150f: 0x00c0, 0x1510: 0x00c0, 0x1511: 0x00c0,
+	0x1512: 0x00c0, 0x1513: 0x00c0, 0x1514: 0x00c0, 0x1515: 0x00c0, 0x1516: 0x00c0, 0x1517: 0x00c0,
+	0x1518: 0x00c0, 0x1519: 0x00c0, 0x151a: 0x00c0, 0x151b: 0x00c0, 0x151c: 0x00c0, 0x151d: 0x00c0,
+	0x151e: 0x00c0, 0x1520: 0x00c3, 0x1521: 0x00c3, 0x1522: 0x00c3, 0x1523: 0x00c0,
+	0x1524: 0x00c0, 0x1525: 0x00c0, 0x1526: 0x00c0, 0x1527: 0x00c3, 0x1528: 0x00c3, 0x1529: 0x00c0,
+	0x152a: 0x00c0, 0x152b: 0x00c0,
+	0x1530: 0x00c0, 0x1531: 0x00c0, 0x1532: 0x00c3, 0x1533: 0x00c0, 0x1534: 0x00c0, 0x1535: 0x00c0,
+	0x1536: 0x00c0, 0x1537: 0x00c0, 0x1538: 0x00c0, 0x1539: 0x00c3, 0x153a: 0x00c3, 0x153b: 0x00c3,
+	// Block 0x55, offset 0x1540
+	0x1540: 0x0080, 0x1544: 0x0080, 0x1545: 0x0080,
+	0x1546: 0x00c0, 0x1547: 0x00c0, 0x1548: 0x00c0, 0x1549: 0x00c0, 0x154a: 0x00c0, 0x154b: 0x00c0,
+	0x154c: 0x00c0, 0x154d: 0x00c0, 0x154e: 0x00c0, 0x154f: 0x00c0, 0x1550: 0x00c0, 0x1551: 0x00c0,
+	0x1552: 0x00c0, 0x1553: 0x00c0, 0x1554: 0x00c0, 0x1555: 0x00c0, 0x1556: 0x00c0, 0x1557: 0x00c0,
+	0x1558: 0x00c0, 0x1559: 0x00c0, 0x155a: 0x00c0, 0x155b: 0x00c0, 0x155c: 0x00c0, 0x155d: 0x00c0,
+	0x155e: 0x00c0, 0x155f: 0x00c0, 0x1560: 0x00c0, 0x1561: 0x00c0, 0x1562: 0x00c0, 0x1563: 0x00c0,
+	0x1564: 0x00c0, 0x1565: 0x00c0, 0x1566: 0x00c0, 0x1567: 0x00c0, 0x1568: 0x00c0, 0x1569: 0x00c0,
+	0x156a: 0x00c0, 0x156b: 0x00c0, 0x156c: 0x00c0, 0x156d: 0x00c0,
+	0x1570: 0x00c0, 0x1571: 0x00c0, 0x1572: 0x00c0, 0x1573: 0x00c0, 0x1574: 0x00c0,
+	// Block 0x56, offset 0x1580
+	0x1580: 0x00c0, 0x1581: 0x00c0, 0x1582: 0x00c0, 0x1583: 0x00c0, 0x1584: 0x00c0, 0x1585: 0x00c0,
+	0x1586: 0x00c0, 0x1587: 0x00c0, 0x1588: 0x00c0, 0x1589: 0x00c0, 0x158a: 0x00c0, 0x158b: 0x00c0,
+	0x158c: 0x00c0, 0x158d: 0x00c0, 0x158e: 0x00c0, 0x158f: 0x00c0, 0x1590: 0x00c0, 0x1591: 0x00c0,
+	0x1592: 0x00c0, 0x1593: 0x00c0, 0x1594: 0x00c0, 0x1595: 0x00c0, 0x1596: 0x00c0, 0x1597: 0x00c0,
+	0x1598: 0x00c0, 0x1599: 0x00c0, 0x159a: 0x00c0, 0x159b: 0x00c0, 0x159c: 0x00c0, 0x159d: 0x00c0,
+	0x159e: 0x00c0, 0x159f: 0x00c0, 0x15a0: 0x00c0, 0x15a1: 0x00c0, 0x15a2: 0x00c0, 0x15a3: 0x00c0,
+	0x15a4: 0x00c0, 0x15a5: 0x00c0, 0x15a6: 0x00c0, 0x15a7: 0x00c0, 0x15a8: 0x00c0, 0x15a9: 0x00c0,
+	0x15aa: 0x00c0, 0x15ab: 0x00c0,
+	0x15b0: 0x00c0, 0x15b1: 0x00c0, 0x15b2: 0x00c0, 0x15b3: 0x00c0, 0x15b4: 0x00c0, 0x15b5: 0x00c0,
+	0x15b6: 0x00c0, 0x15b7: 0x00c0, 0x15b8: 0x00c0, 0x15b9: 0x00c0, 0x15ba: 0x00c0, 0x15bb: 0x00c0,
+	0x15bc: 0x00c0, 0x15bd: 0x00c0, 0x15be: 0x00c0, 0x15bf: 0x00c0,
+	// Block 0x57, offset 0x15c0
+	0x15c0: 0x00c0, 0x15c1: 0x00c0, 0x15c2: 0x00c0, 0x15c3: 0x00c0, 0x15c4: 0x00c0, 0x15c5: 0x00c0,
+	0x15c6: 0x00c0, 0x15c7: 0x00c0, 0x15c8: 0x00c0, 0x15c9: 0x00c0,
+	0x15d0: 0x00c0, 0x15d1: 0x00c0,
+	0x15d2: 0x00c0, 0x15d3: 0x00c0, 0x15d4: 0x00c0, 0x15d5: 0x00c0, 0x15d6: 0x00c0, 0x15d7: 0x00c0,
+	0x15d8: 0x00c0, 0x15d9: 0x00c0, 0x15da: 0x0080,
+	0x15de: 0x0080, 0x15df: 0x0080, 0x15e0: 0x0080, 0x15e1: 0x0080, 0x15e2: 0x0080, 0x15e3: 0x0080,
+	0x15e4: 0x0080, 0x15e5: 0x0080, 0x15e6: 0x0080, 0x15e7: 0x0080, 0x15e8: 0x0080, 0x15e9: 0x0080,
+	0x15ea: 0x0080, 0x15eb: 0x0080, 0x15ec: 0x0080, 0x15ed: 0x0080, 0x15ee: 0x0080, 0x15ef: 0x0080,
+	0x15f0: 0x0080, 0x15f1: 0x0080, 0x15f2: 0x0080, 0x15f3: 0x0080, 0x15f4: 0x0080, 0x15f5: 0x0080,
+	0x15f6: 0x0080, 0x15f7: 0x0080, 0x15f8: 0x0080, 0x15f9: 0x0080, 0x15fa: 0x0080, 0x15fb: 0x0080,
+	0x15fc: 0x0080, 0x15fd: 0x0080, 0x15fe: 0x0080, 0x15ff: 0x0080,
+	// Block 0x58, offset 0x1600
+	0x1600: 0x00c0, 0x1601: 0x00c0, 0x1602: 0x00c0, 0x1603: 0x00c0, 0x1604: 0x00c0, 0x1605: 0x00c0,
+	0x1606: 0x00c0, 0x1607: 0x00c0, 0x1608: 0x00c0, 0x1609: 0x00c0, 0x160a: 0x00c0, 0x160b: 0x00c0,
+	0x160c: 0x00c0, 0x160d: 0x00c0, 0x160e: 0x00c0, 0x160f: 0x00c0, 0x1610: 0x00c0, 0x1611: 0x00c0,
+	0x1612: 0x00c0, 0x1613: 0x00c0, 0x1614: 0x00c0, 0x1615: 0x00c0, 0x1616: 0x00c0, 0x1617: 0x00c3,
+	0x1618: 0x00c3, 0x1619: 0x00c0, 0x161a: 0x00c0, 0x161b: 0x00c3,
+	0x161e: 0x0080, 0x161f: 0x0080, 0x1620: 0x00c0, 0x1621: 0x00c0, 0x1622: 0x00c0, 0x1623: 0x00c0,
+	0x1624: 0x00c0, 0x1625: 0x00c0, 0x1626: 0x00c0, 0x1627: 0x00c0, 0x1628: 0x00c0, 0x1629: 0x00c0,
+	0x162a: 0x00c0, 0x162b: 0x00c0, 0x162c: 0x00c0, 0x162d: 0x00c0, 0x162e: 0x00c0, 0x162f: 0x00c0,
+	0x1630: 0x00c0, 0x1631: 0x00c0, 0x1632: 0x00c0, 0x1633: 0x00c0, 0x1634: 0x00c0, 0x1635: 0x00c0,
+	0x1636: 0x00c0, 0x1637: 0x00c0, 0x1638: 0x00c0, 0x1639: 0x00c0, 0x163a: 0x00c0, 0x163b: 0x00c0,
+	0x163c: 0x00c0, 0x163d: 0x00c0, 0x163e: 0x00c0, 0x163f: 0x00c0,
+	// Block 0x59, offset 0x1640
+	0x1640: 0x00c0, 0x1641: 0x00c0, 0x1642: 0x00c0, 0x1643: 0x00c0, 0x1644: 0x00c0, 0x1645: 0x00c0,
+	0x1646: 0x00c0, 0x1647: 0x00c0, 0x1648: 0x00c0, 0x1649: 0x00c0, 0x164a: 0x00c0, 0x164b: 0x00c0,
+	0x164c: 0x00c0, 0x164d: 0x00c0, 0x164e: 0x00c0, 0x164f: 0x00c0, 0x1650: 0x00c0, 0x1651: 0x00c0,
+	0x1652: 0x00c0, 0x1653: 0x00c0, 0x1654: 0x00c0, 0x1655: 0x00c0, 0x1656: 0x00c3, 0x1657: 0x00c0,
+	0x1658: 0x00c3, 0x1659: 0x00c3, 0x165a: 0x00c3, 0x165b: 0x00c3, 0x165c: 0x00c3, 0x165d: 0x00c3,
+	0x165e: 0x00c3, 0x1660: 0x00c6, 0x1661: 0x00c0, 0x1662: 0x00c3, 0x1663: 0x00c0,
+	0x1664: 0x00c0, 0x1665: 0x00c3, 0x1666: 0x00c3, 0x1667: 0x00c3, 0x1668: 0x00c3, 0x1669: 0x00c3,
+	0x166a: 0x00c3, 0x166b: 0x00c3, 0x166c: 0x00c3, 0x166d: 0x00c0, 0x166e: 0x00c0, 0x166f: 0x00c0,
+	0x1670: 0x00c0, 0x1671: 0x00c0, 0x1672: 0x00c0, 0x1673: 0x00c3, 0x1674: 0x00c3, 0x1675: 0x00c3,
+	0x1676: 0x00c3, 0x1677: 0x00c3, 0x1678: 0x00c3, 0x1679: 0x00c3, 0x167a: 0x00c3, 0x167b: 0x00c3,
+	0x167c: 0x00c3, 0x167f: 0x00c3,
+	// Block 0x5a, offset 0x1680
+	0x1680: 0x00c0, 0x1681: 0x00c0, 0x1682: 0x00c0, 0x1683: 0x00c0, 0x1684: 0x00c0, 0x1685: 0x00c0,
+	0x1686: 0x00c0, 0x1687: 0x00c0, 0x1688: 0x00c0, 0x1689: 0x00c0,
+	0x1690: 0x00c0, 0x1691: 0x00c0,
+	0x1692: 0x00c0, 0x1693: 0x00c0, 0x1694: 0x00c0, 0x1695: 0x00c0, 0x1696: 0x00c0, 0x1697: 0x00c0,
+	0x1698: 0x00c0, 0x1699: 0x00c0,
+	0x16a0: 0x0080, 0x16a1: 0x0080, 0x16a2: 0x0080, 0x16a3: 0x0080,
+	0x16a4: 0x0080, 0x16a5: 0x0080, 0x16a6: 0x0080, 0x16a7: 0x00c0, 0x16a8: 0x0080, 0x16a9: 0x0080,
+	0x16aa: 0x0080, 0x16ab: 0x0080, 0x16ac: 0x0080, 0x16ad: 0x0080,
+	0x16b0: 0x00c3, 0x16b1: 0x00c3, 0x16b2: 0x00c3, 0x16b3: 0x00c3, 0x16b4: 0x00c3, 0x16b5: 0x00c3,
+	0x16b6: 0x00c3, 0x16b7: 0x00c3, 0x16b8: 0x00c3, 0x16b9: 0x00c3, 0x16ba: 0x00c3, 0x16bb: 0x00c3,
+	0x16bc: 0x00c3, 0x16bd: 0x00c3, 0x16be: 0x0083, 0x16bf: 0x00c3,
+	// Block 0x5b, offset 0x16c0
+	0x16c0: 0x00c3, 0x16c1: 0x00c3, 0x16c2: 0x00c3, 0x16c3: 0x00c3, 0x16c4: 0x00c3, 0x16c5: 0x00c3,
+	0x16c6: 0x00c3, 0x16c7: 0x00c3, 0x16c8: 0x00c3, 0x16c9: 0x00c3, 0x16ca: 0x00c3, 0x16cb: 0x00c3,
+	0x16cc: 0x00c3, 0x16cd: 0x00c3, 0x16ce: 0x00c3, 0x16cf: 0x00c3, 0x16d0: 0x00c3, 0x16d1: 0x00c3,
+	0x16d2: 0x00c3, 0x16d3: 0x00c3, 0x16d4: 0x00c3, 0x16d5: 0x00c3, 0x16d6: 0x00c3, 0x16d7: 0x00c3,
+	0x16d8: 0x00c3, 0x16d9: 0x00c3, 0x16da: 0x00c3, 0x16db: 0x00c3, 0x16dc: 0x00c3, 0x16dd: 0x00c3,
+	0x16e0: 0x00c3, 0x16e1: 0x00c3, 0x16e2: 0x00c3, 0x16e3: 0x00c3,
+	0x16e4: 0x00c3, 0x16e5: 0x00c3, 0x16e6: 0x00c3, 0x16e7: 0x00c3, 0x16e8: 0x00c3, 0x16e9: 0x00c3,
+	0x16ea: 0x00c3, 0x16eb: 0x00c3,
+	// Block 0x5c, offset 0x1700
+	0x1700: 0x00c3, 0x1701: 0x00c3, 0x1702: 0x00c3, 0x1703: 0x00c3, 0x1704: 0x00c0, 0x1705: 0x00c0,
+	0x1706: 0x00c0, 0x1707: 0x00c0, 0x1708: 0x00c0, 0x1709: 0x00c0, 0x170a: 0x00c0, 0x170b: 0x00c0,
+	0x170c: 0x00c0, 0x170d: 0x00c0, 0x170e: 0x00c0, 0x170f: 0x00c0, 0x1710: 0x00c0, 0x1711: 0x00c0,
+	0x1712: 0x00c0, 0x1713: 0x00c0, 0x1714: 0x00c0, 0x1715: 0x00c0, 0x1716: 0x00c0, 0x1717: 0x00c0,
+	0x1718: 0x00c0, 0x1719: 0x00c0, 0x171a: 0x00c0, 0x171b: 0x00c0, 0x171c: 0x00c0, 0x171d: 0x00c0,
+	0x171e: 0x00c0, 0x171f: 0x00c0, 0x1720: 0x00c0, 0x1721: 0x00c0, 0x1722: 0x00c0, 0x1723: 0x00c0,
+	0x1724: 0x00c0, 0x1725: 0x00c0, 0x1726: 0x00c0, 0x1727: 0x00c0, 0x1728: 0x00c0, 0x1729: 0x00c0,
+	0x172a: 0x00c0, 0x172b: 0x00c0, 0x172c: 0x00c0, 0x172d: 0x00c0, 0x172e: 0x00c0, 0x172f: 0x00c0,
+	0x1730: 0x00c0, 0x1731: 0x00c0, 0x1732: 0x00c0, 0x1733: 0x00c0, 0x1734: 0x00c3, 0x1735: 0x00c0,
+	0x1736: 0x00c3, 0x1737: 0x00c3, 0x1738: 0x00c3, 0x1739: 0x00c3, 0x173a: 0x00c3, 0x173b: 0x00c0,
+	0x173c: 0x00c3, 0x173d: 0x00c0, 0x173e: 0x00c0, 0x173f: 0x00c0,
+	// Block 0x5d, offset 0x1740
+	0x1740: 0x00c0, 0x1741: 0x00c0, 0x1742: 0x00c3, 0x1743: 0x00c0, 0x1744: 0x00c5, 0x1745: 0x00c0,
+	0x1746: 0x00c0, 0x1747: 0x00c0, 0x1748: 0x00c0, 0x1749: 0x00c0, 0x174a: 0x00c0, 0x174b: 0x00c0,
+	0x174c: 0x00c0, 0x174e: 0x0080, 0x174f: 0x0080, 0x1750: 0x00c0, 0x1751: 0x00c0,
+	0x1752: 0x00c0, 0x1753: 0x00c0, 0x1754: 0x00c0, 0x1755: 0x00c0, 0x1756: 0x00c0, 0x1757: 0x00c0,
+	0x1758: 0x00c0, 0x1759: 0x00c0, 0x175a: 0x0080, 0x175b: 0x0080, 0x175c: 0x0080, 0x175d: 0x0080,
+	0x175e: 0x0080, 0x175f: 0x0080, 0x1760: 0x0080, 0x1761: 0x0080, 0x1762: 0x0080, 0x1763: 0x0080,
+	0x1764: 0x0080, 0x1765: 0x0080, 0x1766: 0x0080, 0x1767: 0x0080, 0x1768: 0x0080, 0x1769: 0x0080,
+	0x176a: 0x0080, 0x176b: 0x00c3, 0x176c: 0x00c3, 0x176d: 0x00c3, 0x176e: 0x00c3, 0x176f: 0x00c3,
+	0x1770: 0x00c3, 0x1771: 0x00c3, 0x1772: 0x00c3, 0x1773: 0x00c3, 0x1774: 0x0080, 0x1775: 0x0080,
+	0x1776: 0x0080, 0x1777: 0x0080, 0x1778: 0x0080, 0x1779: 0x0080, 0x177a: 0x0080, 0x177b: 0x0080,
+	0x177c: 0x0080, 0x177d: 0x0080, 0x177e: 0x0080, 0x177f: 0x0080,
+	// Block 0x5e, offset 0x1780
+	0x1780: 0x00c3, 0x1781: 0x00c3, 0x1782: 0x00c0, 0x1783: 0x00c0, 0x1784: 0x00c0, 0x1785: 0x00c0,
+	0x1786: 0x00c0, 0x1787: 0x00c0, 0x1788: 0x00c0, 0x1789: 0x00c0, 0x178a: 0x00c0, 0x178b: 0x00c0,
+	0x178c: 0x00c0, 0x178d: 0x00c0, 0x178e: 0x00c0, 0x178f: 0x00c0, 0x1790: 0x00c0, 0x1791: 0x00c0,
+	0x1792: 0x00c0, 0x1793: 0x00c0, 0x1794: 0x00c0, 0x1795: 0x00c0, 0x1796: 0x00c0, 0x1797: 0x00c0,
+	0x1798: 0x00c0, 0x1799: 0x00c0, 0x179a: 0x00c0, 0x179b: 0x00c0, 0x179c: 0x00c0, 0x179d: 0x00c0,
+	0x179e: 0x00c0, 0x179f: 0x00c0, 0x17a0: 0x00c0, 0x17a1: 0x00c0, 0x17a2: 0x00c3, 0x17a3: 0x00c3,
+	0x17a4: 0x00c3, 0x17a5: 0x00c3, 0x17a6: 0x00c0, 0x17a7: 0x00c0, 0x17a8: 0x00c3, 0x17a9: 0x00c3,
+	0x17aa: 0x00c5, 0x17ab: 0x00c6, 0x17ac: 0x00c3, 0x17ad: 0x00c3, 0x17ae: 0x00c0, 0x17af: 0x00c0,
+	0x17b0: 0x00c0, 0x17b1: 0x00c0, 0x17b2: 0x00c0, 0x17b3: 0x00c0, 0x17b4: 0x00c0, 0x17b5: 0x00c0,
+	0x17b6: 0x00c0, 0x17b7: 0x00c0, 0x17b8: 0x00c0, 0x17b9: 0x00c0, 0x17ba: 0x00c0, 0x17bb: 0x00c0,
+	0x17bc: 0x00c0, 0x17bd: 0x00c0, 0x17be: 0x00c0, 0x17bf: 0x00c0,
+	// Block 0x5f, offset 0x17c0
+	0x17c0: 0x00c0, 0x17c1: 0x00c0, 0x17c2: 0x00c0, 0x17c3: 0x00c0, 0x17c4: 0x00c0, 0x17c5: 0x00c0,
+	0x17c6: 0x00c0, 0x17c7: 0x00c0, 0x17c8: 0x00c0, 0x17c9: 0x00c0, 0x17ca: 0x00c0, 0x17cb: 0x00c0,
+	0x17cc: 0x00c0, 0x17cd: 0x00c0, 0x17ce: 0x00c0, 0x17cf: 0x00c0, 0x17d0: 0x00c0, 0x17d1: 0x00c0,
+	0x17d2: 0x00c0, 0x17d3: 0x00c0, 0x17d4: 0x00c0, 0x17d5: 0x00c0, 0x17d6: 0x00c0, 0x17d7: 0x00c0,
+	0x17d8: 0x00c0, 0x17d9: 0x00c0, 0x17da: 0x00c0, 0x17db: 0x00c0, 0x17dc: 0x00c0, 0x17dd: 0x00c0,
+	0x17de: 0x00c0, 0x17df: 0x00c0, 0x17e0: 0x00c0, 0x17e1: 0x00c0, 0x17e2: 0x00c0, 0x17e3: 0x00c0,
+	0x17e4: 0x00c0, 0x17e5: 0x00c0, 0x17e6: 0x00c3, 0x17e7: 0x00c0, 0x17e8: 0x00c3, 0x17e9: 0x00c3,
+	0x17ea: 0x00c0, 0x17eb: 0x00c0, 0x17ec: 0x00c0, 0x17ed: 0x00c3, 0x17ee: 0x00c0, 0x17ef: 0x00c3,
+	0x17f0: 0x00c3, 0x17f1: 0x00c3, 0x17f2: 0x00c5, 0x17f3: 0x00c5,
+	0x17fc: 0x0080, 0x17fd: 0x0080, 0x17fe: 0x0080, 0x17ff: 0x0080,
+	// Block 0x60, offset 0x1800
+	0x1800: 0x00c0, 0x1801: 0x00c0, 0x1802: 0x00c0, 0x1803: 0x00c0, 0x1804: 0x00c0, 0x1805: 0x00c0,
+	0x1806: 0x00c0, 0x1807: 0x00c0, 0x1808: 0x00c0, 0x1809: 0x00c0, 0x180a: 0x00c0, 0x180b: 0x00c0,
+	0x180c: 0x00c0, 0x180d: 0x00c0, 0x180e: 0x00c0, 0x180f: 0x00c0, 0x1810: 0x00c0, 0x1811: 0x00c0,
+	0x1812: 0x00c0, 0x1813: 0x00c0, 0x1814: 0x00c0, 0x1815: 0x00c0, 0x1816: 0x00c0, 0x1817: 0x00c0,
+	0x1818: 0x00c0, 0x1819: 0x00c0, 0x181a: 0x00c0, 0x181b: 0x00c0, 0x181c: 0x00c0, 0x181d: 0x00c0,
+	0x181e: 0x00c0, 0x181f: 0x00c0, 0x1820: 0x00c0, 0x1821: 0x00c0, 0x1822: 0x00c0, 0x1823: 0x00c0,
+	0x1824: 0x00c0, 0x1825: 0x00c0, 0x1826: 0x00c0, 0x1827: 0x00c0, 0x1828: 0x00c0, 0x1829: 0x00c0,
+	0x182a: 0x00c0, 0x182b: 0x00c0, 0x182c: 0x00c3, 0x182d: 0x00c3, 0x182e: 0x00c3, 0x182f: 0x00c3,
+	0x1830: 0x00c3, 0x1831: 0x00c3, 0x1832: 0x00c3, 0x1833: 0x00c3, 0x1834: 0x00c0, 0x1835: 0x00c0,
+	0x1836: 0x00c3, 0x1837: 0x00c3, 0x183b: 0x0080,
+	0x183c: 0x0080, 0x183d: 0x0080, 0x183e: 0x0080, 0x183f: 0x0080,
+	// Block 0x61, offset 0x1840
+	0x1840: 0x00c0, 0x1841: 0x00c0, 0x1842: 0x00c0, 0x1843: 0x00c0, 0x1844: 0x00c0, 0x1845: 0x00c0,
+	0x1846: 0x00c0, 0x1847: 0x00c0, 0x1848: 0x00c0, 0x1849: 0x00c0,
+	0x184d: 0x00c0, 0x184e: 0x00c0, 0x184f: 0x00c0, 0x1850: 0x00c0, 0x1851: 0x00c0,
+	0x1852: 0x00c0, 0x1853: 0x00c0, 0x1854: 0x00c0, 0x1855: 0x00c0, 0x1856: 0x00c0, 0x1857: 0x00c0,
+	0x1858: 0x00c0, 0x1859: 0x00c0, 0x185a: 0x00c0, 0x185b: 0x00c0, 0x185c: 0x00c0, 0x185d: 0x00c0,
+	0x185e: 0x00c0, 0x185f: 0x00c0, 0x1860: 0x00c0, 0x1861: 0x00c0, 0x1862: 0x00c0, 0x1863: 0x00c0,
+	0x1864: 0x00c0, 0x1865: 0x00c0, 0x1866: 0x00c0, 0x1867: 0x00c0, 0x1868: 0x00c0, 0x1869: 0x00c0,
+	0x186a: 0x00c0, 0x186b: 0x00c0, 0x186c: 0x00c0, 0x186d: 0x00c0, 0x186e: 0x00c0, 0x186f: 0x00c0,
+	0x1870: 0x00c0, 0x1871: 0x00c0, 0x1872: 0x00c0, 0x1873: 0x00c0, 0x1874: 0x00c0, 0x1875: 0x00c0,
+	0x1876: 0x00c0, 0x1877: 0x00c0, 0x1878: 0x00c0, 0x1879: 0x00c0, 0x187a: 0x00c0, 0x187b: 0x00c0,
+	0x187c: 0x00c0, 0x187d: 0x00c0, 0x187e: 0x0080, 0x187f: 0x0080,
+	// Block 0x62, offset 0x1880
+	0x1880: 0x00c0, 0x1881: 0x00c0, 0x1882: 0x00c0, 0x1883: 0x00c0, 0x1884: 0x00c0, 0x1885: 0x00c0,
+	0x1886: 0x00c0, 0x1887: 0x00c0, 0x1888: 0x00c0, 0x1889: 0x00c0, 0x188a: 0x00c0,
+	0x1890: 0x00c0, 0x1891: 0x00c0,
+	0x1892: 0x00c0, 0x1893: 0x00c0, 0x1894: 0x00c0, 0x1895: 0x00c0, 0x1896: 0x00c0, 0x1897: 0x00c0,
+	0x1898: 0x00c0, 0x1899: 0x00c0, 0x189a: 0x00c0, 0x189b: 0x00c0, 0x189c: 0x00c0, 0x189d: 0x00c0,
+	0x189e: 0x00c0, 0x189f: 0x00c0, 0x18a0: 0x00c0, 0x18a1: 0x00c0, 0x18a2: 0x00c0, 0x18a3: 0x00c0,
+	0x18a4: 0x00c0, 0x18a5: 0x00c0, 0x18a6: 0x00c0, 0x18a7: 0x00c0, 0x18a8: 0x00c0, 0x18a9: 0x00c0,
+	0x18aa: 0x00c0, 0x18ab: 0x00c0, 0x18ac: 0x00c0, 0x18ad: 0x00c0, 0x18ae: 0x00c0, 0x18af: 0x00c0,
+	0x18b0: 0x00c0, 0x18b1: 0x00c0, 0x18b2: 0x00c0, 0x18b3: 0x00c0, 0x18b4: 0x00c0, 0x18b5: 0x00c0,
+	0x18b6: 0x00c0, 0x18b7: 0x00c0, 0x18b8: 0x00c0, 0x18b9: 0x00c0, 0x18ba: 0x00c0,
+	0x18bd: 0x00c0, 0x18be: 0x00c0, 0x18bf: 0x00c0,
+	// Block 0x63, offset 0x18c0
+	0x18c0: 0x0080, 0x18c1: 0x0080, 0x18c2: 0x0080, 0x18c3: 0x0080, 0x18c4: 0x0080, 0x18c5: 0x0080,
+	0x18c6: 0x0080, 0x18c7: 0x0080,
+	0x18d0: 0x00c3, 0x18d1: 0x00c3,
+	0x18d2: 0x00c3, 0x18d3: 0x0080, 0x18d4: 0x00c3, 0x18d5: 0x00c3, 0x18d6: 0x00c3, 0x18d7: 0x00c3,
+	0x18d8: 0x00c3, 0x18d9: 0x00c3, 0x18da: 0x00c3, 0x18db: 0x00c3, 0x18dc: 0x00c3, 0x18dd: 0x00c3,
+	0x18de: 0x00c3, 0x18df: 0x00c3, 0x18e0: 0x00c3, 0x18e1: 0x00c0, 0x18e2: 0x00c3, 0x18e3: 0x00c3,
+	0x18e4: 0x00c3, 0x18e5: 0x00c3, 0x18e6: 0x00c3, 0x18e7: 0x00c3, 0x18e8: 0x00c3, 0x18e9: 0x00c0,
+	0x18ea: 0x00c0, 0x18eb: 0x00c0, 0x18ec: 0x00c0, 0x18ed: 0x00c3, 0x18ee: 0x00c0, 0x18ef: 0x00c0,
+	0x18f0: 0x00c0, 0x18f1: 0x00c0, 0x18f2: 0x00c0, 0x18f3: 0x00c0, 0x18f4: 0x00c3, 0x18f5: 0x00c0,
+	0x18f6: 0x00c0, 0x18f7: 0x00c0, 0x18f8: 0x00c3, 0x18f9: 0x00c3, 0x18fa: 0x00c0,
+	// Block 0x64, offset 0x1900
+	0x1900: 0x00c0, 0x1901: 0x00c0, 0x1902: 0x00c0, 0x1903: 0x00c0, 0x1904: 0x00c0, 0x1905: 0x00c0,
+	0x1906: 0x00c0, 0x1907: 0x00c0, 0x1908: 0x00c0, 0x1909: 0x00c0, 0x190a: 0x00c0, 0x190b: 0x00c0,
+	0x190c: 0x00c0, 0x190d: 0x00c0, 0x190e: 0x00c0, 0x190f: 0x00c0, 0x1910: 0x00c0, 0x1911: 0x00c0,
+	0x1912: 0x00c0, 0x1913: 0x00c0, 0x1914: 0x00c0, 0x1915: 0x00c0, 0x1916: 0x00c0, 0x1917: 0x00c0,
+	0x1918: 0x00c0, 0x1919: 0x00c0, 0x191a: 0x00c0, 0x191b: 0x00c0, 0x191c: 0x00c0, 0x191d: 0x00c0,
+	0x191e: 0x00c0, 0x191f: 0x00c0, 0x1920: 0x00c0, 0x1921: 0x00c0, 0x1922: 0x00c0, 0x1923: 0x00c0,
+	0x1924: 0x00c0, 0x1925: 0x00c0, 0x1926: 0x00c8, 0x1927: 0x00c8, 0x1928: 0x00c8, 0x1929: 0x00c8,
+	0x192a: 0x00c8, 0x192b: 0x00c0, 0x192c: 0x0080, 0x192d: 0x0080, 0x192e: 0x0080, 0x192f: 0x00c0,
+	0x1930: 0x0080, 0x1931: 0x0080, 0x1932: 0x0080, 0x1933: 0x0080, 0x1934: 0x0080, 0x1935: 0x0080,
+	0x1936: 0x0080, 0x1937: 0x0080, 0x1938: 0x0080, 0x1939: 0x0080, 0x193a: 0x0080, 0x193b: 0x00c0,
+	0x193c: 0x0080, 0x193d: 0x0080, 0x193e: 0x0080, 0x193f: 0x0080,
+	// Block 0x65, offset 0x1940
+	0x1940: 0x0080, 0x1941: 0x0080, 0x1942: 0x0080, 0x1943: 0x0080, 0x1944: 0x0080, 0x1945: 0x0080,
+	0x1946: 0x0080, 0x1947: 0x0080, 0x1948: 0x0080, 0x1949: 0x0080, 0x194a: 0x0080, 0x194b: 0x0080,
+	0x194c: 0x0080, 0x194d: 0x0080, 0x194e: 0x00c0, 0x194f: 0x0080, 0x1950: 0x0080, 0x1951: 0x0080,
+	0x1952: 0x0080, 0x1953: 0x0080, 0x1954: 0x0080, 0x1955: 0x0080, 0x1956: 0x0080, 0x1957: 0x0080,
+	0x1958: 0x0080, 0x1959: 0x0080, 0x195a: 0x0080, 0x195b: 0x0080, 0x195c: 0x0080, 0x195d: 0x0088,
+	0x195e: 0x0088, 0x195f: 0x0088, 0x1960: 0x0088, 0x1961: 0x0088, 0x1962: 0x0080, 0x1963: 0x0080,
+	0x1964: 0x0080, 0x1965: 0x0080, 0x1966: 0x0088, 0x1967: 0x0088, 0x1968: 0x0088, 0x1969: 0x0088,
+	0x196a: 0x0088, 0x196b: 0x00c0, 0x196c: 0x00c0, 0x196d: 0x00c0, 0x196e: 0x00c0, 0x196f: 0x00c0,
+	0x1970: 0x00c0, 0x1971: 0x00c0, 0x1972: 0x00c0, 0x1973: 0x00c0, 0x1974: 0x00c0, 0x1975: 0x00c0,
+	0x1976: 0x00c0, 0x1977: 0x00c0, 0x1978: 0x0080, 0x1979: 0x00c0, 0x197a: 0x00c0, 0x197b: 0x00c0,
+	0x197c: 0x00c0, 0x197d: 0x00c0, 0x197e: 0x00c0, 0x197f: 0x00c0,
+	// Block 0x66, offset 0x1980
+	0x1980: 0x00c0, 0x1981: 0x00c0, 0x1982: 0x00c0, 0x1983: 0x00c0, 0x1984: 0x00c0, 0x1985: 0x00c0,
+	0x1986: 0x00c0, 0x1987: 0x00c0, 0x1988: 0x00c0, 0x1989: 0x00c0, 0x198a: 0x00c0, 0x198b: 0x00c0,
+	0x198c: 0x00c0, 0x198d: 0x00c0, 0x198e: 0x00c0, 0x198f: 0x00c0, 0x1990: 0x00c0, 0x1991: 0x00c0,
+	0x1992: 0x00c0, 0x1993: 0x00c0, 0x1994: 0x00c0, 0x1995: 0x00c0, 0x1996: 0x00c0, 0x1997: 0x00c0,
+	0x1998: 0x00c0, 0x1999: 0x00c0, 0x199a: 0x00c0, 0x199b: 0x0080, 0x199c: 0x0080, 0x199d: 0x0080,
+	0x199e: 0x0080, 0x199f: 0x0080, 0x19a0: 0x0080, 0x19a1: 0x0080, 0x19a2: 0x0080, 0x19a3: 0x0080,
+	0x19a4: 0x0080, 0x19a5: 0x0080, 0x19a6: 0x0080, 0x19a7: 0x0080, 0x19a8: 0x0080, 0x19a9: 0x0080,
+	0x19aa: 0x0080, 0x19ab: 0x0080, 0x19ac: 0x0080, 0x19ad: 0x0080, 0x19ae: 0x0080, 0x19af: 0x0080,
+	0x19b0: 0x0080, 0x19b1: 0x0080, 0x19b2: 0x0080, 0x19b3: 0x0080, 0x19b4: 0x0080, 0x19b5: 0x0080,
+	0x19b6: 0x0080, 0x19b7: 0x0080, 0x19b8: 0x0080, 0x19b9: 0x0080, 0x19ba: 0x0080, 0x19bb: 0x0080,
+	0x19bc: 0x0080, 0x19bd: 0x0080, 0x19be: 0x0080, 0x19bf: 0x0088,
+	// Block 0x67, offset 0x19c0
+	0x19c0: 0x00c0, 0x19c1: 0x00c0, 0x19c2: 0x00c0, 0x19c3: 0x00c0, 0x19c4: 0x00c0, 0x19c5: 0x00c0,
+	0x19c6: 0x00c0, 0x19c7: 0x00c0, 0x19c8: 0x00c0, 0x19c9: 0x00c0, 0x19ca: 0x00c0, 0x19cb: 0x00c0,
+	0x19cc: 0x00c0, 0x19cd: 0x00c0, 0x19ce: 0x00c0, 0x19cf: 0x00c0, 0x19d0: 0x00c0, 0x19d1: 0x00c0,
+	0x19d2: 0x00c0, 0x19d3: 0x00c0, 0x19d4: 0x00c0, 0x19d5: 0x00c0, 0x19d6: 0x00c0, 0x19d7: 0x00c0,
+	0x19d8: 0x00c0, 0x19d9: 0x00c0, 0x19da: 0x0080, 0x19db: 0x0080, 0x19dc: 0x00c0, 0x19dd: 0x00c0,
+	0x19de: 0x00c0, 0x19df: 0x00c0, 0x19e0: 0x00c0, 0x19e1: 0x00c0, 0x19e2: 0x00c0, 0x19e3: 0x00c0,
+	0x19e4: 0x00c0, 0x19e5: 0x00c0, 0x19e6: 0x00c0, 0x19e7: 0x00c0, 0x19e8: 0x00c0, 0x19e9: 0x00c0,
+	0x19ea: 0x00c0, 0x19eb: 0x00c0, 0x19ec: 0x00c0, 0x19ed: 0x00c0, 0x19ee: 0x00c0, 0x19ef: 0x00c0,
+	0x19f0: 0x00c0, 0x19f1: 0x00c0, 0x19f2: 0x00c0, 0x19f3: 0x00c0, 0x19f4: 0x00c0, 0x19f5: 0x00c0,
+	0x19f6: 0x00c0, 0x19f7: 0x00c0, 0x19f8: 0x00c0, 0x19f9: 0x00c0, 0x19fa: 0x00c0, 0x19fb: 0x00c0,
+	0x19fc: 0x00c0, 0x19fd: 0x00c0, 0x19fe: 0x00c0, 0x19ff: 0x00c0,
+	// Block 0x68, offset 0x1a00
+	0x1a00: 0x00c8, 0x1a01: 0x00c8, 0x1a02: 0x00c8, 0x1a03: 0x00c8, 0x1a04: 0x00c8, 0x1a05: 0x00c8,
+	0x1a06: 0x00c8, 0x1a07: 0x00c8, 0x1a08: 0x00c8, 0x1a09: 0x00c8, 0x1a0a: 0x00c8, 0x1a0b: 0x00c8,
+	0x1a0c: 0x00c8, 0x1a0d: 0x00c8, 0x1a0e: 0x00c8, 0x1a0f: 0x00c8, 0x1a10: 0x00c8, 0x1a11: 0x00c8,
+	0x1a12: 0x00c8, 0x1a13: 0x00c8, 0x1a14: 0x00c8, 0x1a15: 0x00c8,
+	0x1a18: 0x00c8, 0x1a19: 0x00c8, 0x1a1a: 0x00c8, 0x1a1b: 0x00c8, 0x1a1c: 0x00c8, 0x1a1d: 0x00c8,
+	0x1a20: 0x00c8, 0x1a21: 0x00c8, 0x1a22: 0x00c8, 0x1a23: 0x00c8,
+	0x1a24: 0x00c8, 0x1a25: 0x00c8, 0x1a26: 0x00c8, 0x1a27: 0x00c8, 0x1a28: 0x00c8, 0x1a29: 0x00c8,
+	0x1a2a: 0x00c8, 0x1a2b: 0x00c8, 0x1a2c: 0x00c8, 0x1a2d: 0x00c8, 0x1a2e: 0x00c8, 0x1a2f: 0x00c8,
+	0x1a30: 0x00c8, 0x1a31: 0x00c8, 0x1a32: 0x00c8, 0x1a33: 0x00c8, 0x1a34: 0x00c8, 0x1a35: 0x00c8,
+	0x1a36: 0x00c8, 0x1a37: 0x00c8, 0x1a38: 0x00c8, 0x1a39: 0x00c8, 0x1a3a: 0x00c8, 0x1a3b: 0x00c8,
+	0x1a3c: 0x00c8, 0x1a3d: 0x00c8, 0x1a3e: 0x00c8, 0x1a3f: 0x00c8,
+	// Block 0x69, offset 0x1a40
+	0x1a40: 0x00c8, 0x1a41: 0x00c8, 0x1a42: 0x00c8, 0x1a43: 0x00c8, 0x1a44: 0x00c8, 0x1a45: 0x00c8,
+	0x1a48: 0x00c8, 0x1a49: 0x00c8, 0x1a4a: 0x00c8, 0x1a4b: 0x00c8,
+	0x1a4c: 0x00c8, 0x1a4d: 0x00c8, 0x1a50: 0x00c8, 0x1a51: 0x00c8,
+	0x1a52: 0x00c8, 0x1a53: 0x00c8, 0x1a54: 0x00c8, 0x1a55: 0x00c8, 0x1a56: 0x00c8, 0x1a57: 0x00c8,
+	0x1a59: 0x00c8, 0x1a5b: 0x00c8, 0x1a5d: 0x00c8,
+	0x1a5f: 0x00c8, 0x1a60: 0x00c8, 0x1a61: 0x00c8, 0x1a62: 0x00c8, 0x1a63: 0x00c8,
+	0x1a64: 0x00c8, 0x1a65: 0x00c8, 0x1a66: 0x00c8, 0x1a67: 0x00c8, 0x1a68: 0x00c8, 0x1a69: 0x00c8,
+	0x1a6a: 0x00c8, 0x1a6b: 0x00c8, 0x1a6c: 0x00c8, 0x1a6d: 0x00c8, 0x1a6e: 0x00c8, 0x1a6f: 0x00c8,
+	0x1a70: 0x00c8, 0x1a71: 0x0088, 0x1a72: 0x00c8, 0x1a73: 0x0088, 0x1a74: 0x00c8, 0x1a75: 0x0088,
+	0x1a76: 0x00c8, 0x1a77: 0x0088, 0x1a78: 0x00c8, 0x1a79: 0x0088, 0x1a7a: 0x00c8, 0x1a7b: 0x0088,
+	0x1a7c: 0x00c8, 0x1a7d: 0x0088,
+	// Block 0x6a, offset 0x1a80
+	0x1a80: 0x00c8, 0x1a81: 0x00c8, 0x1a82: 0x00c8, 0x1a83: 0x00c8, 0x1a84: 0x00c8, 0x1a85: 0x00c8,
+	0x1a86: 0x00c8, 0x1a87: 0x00c8, 0x1a88: 0x0088, 0x1a89: 0x0088, 0x1a8a: 0x0088, 0x1a8b: 0x0088,
+	0x1a8c: 0x0088, 0x1a8d: 0x0088, 0x1a8e: 0x0088, 0x1a8f: 0x0088, 0x1a90: 0x00c8, 0x1a91: 0x00c8,
+	0x1a92: 0x00c8, 0x1a93: 0x00c8, 0x1a94: 0x00c8, 0x1a95: 0x00c8, 0x1a96: 0x00c8, 0x1a97: 0x00c8,
+	0x1a98: 0x0088, 0x1a99: 0x0088, 0x1a9a: 0x0088, 0x1a9b: 0x0088, 0x1a9c: 0x0088, 0x1a9d: 0x0088,
+	0x1a9e: 0x0088, 0x1a9f: 0x0088, 0x1aa0: 0x00c8, 0x1aa1: 0x00c8, 0x1aa2: 0x00c8, 0x1aa3: 0x00c8,
+	0x1aa4: 0x00c8, 0x1aa5: 0x00c8, 0x1aa6: 0x00c8, 0x1aa7: 0x00c8, 0x1aa8: 0x0088, 0x1aa9: 0x0088,
+	0x1aaa: 0x0088, 0x1aab: 0x0088, 0x1aac: 0x0088, 0x1aad: 0x0088, 0x1aae: 0x0088, 0x1aaf: 0x0088,
+	0x1ab0: 0x00c8, 0x1ab1: 0x00c8, 0x1ab2: 0x00c8, 0x1ab3: 0x00c8, 0x1ab4: 0x00c8,
+	0x1ab6: 0x00c8, 0x1ab7: 0x00c8, 0x1ab8: 0x00c8, 0x1ab9: 0x00c8, 0x1aba: 0x00c8, 0x1abb: 0x0088,
+	0x1abc: 0x0088, 0x1abd: 0x0088, 0x1abe: 0x0088, 0x1abf: 0x0088,
+	// Block 0x6b, offset 0x1ac0
+	0x1ac0: 0x0088, 0x1ac1: 0x0088, 0x1ac2: 0x00c8, 0x1ac3: 0x00c8, 0x1ac4: 0x00c8,
+	0x1ac6: 0x00c8, 0x1ac7: 0x00c8, 0x1ac8: 0x00c8, 0x1ac9: 0x0088, 0x1aca: 0x00c8, 0x1acb: 0x0088,
+	0x1acc: 0x0088, 0x1acd: 0x0088, 0x1ace: 0x0088, 0x1acf: 0x0088, 0x1ad0: 0x00c8, 0x1ad1: 0x00c8,
+	0x1ad2: 0x00c8, 0x1ad3: 0x0088, 0x1ad6: 0x00c8, 0x1ad7: 0x00c8,
+	0x1ad8: 0x00c8, 0x1ad9: 0x00c8, 0x1ada: 0x00c8, 0x1adb: 0x0088, 0x1add: 0x0088,
+	0x1ade: 0x0088, 0x1adf: 0x0088, 0x1ae0: 0x00c8, 0x1ae1: 0x00c8, 0x1ae2: 0x00c8, 0x1ae3: 0x0088,
+	0x1ae4: 0x00c8, 0x1ae5: 0x00c8, 0x1ae6: 0x00c8, 0x1ae7: 0x00c8, 0x1ae8: 0x00c8, 0x1ae9: 0x00c8,
+	0x1aea: 0x00c8, 0x1aeb: 0x0088, 0x1aec: 0x00c8, 0x1aed: 0x0088, 0x1aee: 0x0088, 0x1aef: 0x0088,
+	0x1af2: 0x00c8, 0x1af3: 0x00c8, 0x1af4: 0x00c8,
+	0x1af6: 0x00c8, 0x1af7: 0x00c8, 0x1af8: 0x00c8, 0x1af9: 0x0088, 0x1afa: 0x00c8, 0x1afb: 0x0088,
+	0x1afc: 0x0088, 0x1afd: 0x0088, 0x1afe: 0x0088,
+	// Block 0x6c, offset 0x1b00
+	0x1b00: 0x0080, 0x1b01: 0x0080, 0x1b02: 0x0080, 0x1b03: 0x0080, 0x1b04: 0x0080, 0x1b05: 0x0080,
+	0x1b06: 0x0080, 0x1b07: 0x0080, 0x1b08: 0x0080, 0x1b09: 0x0080, 0x1b0a: 0x0080, 0x1b0b: 0x0040,
+	0x1b0c: 0x004d, 0x1b0d: 0x004e, 0x1b0e: 0x0040, 0x1b0f: 0x0040, 0x1b10: 0x0080, 0x1b11: 0x0080,
+	0x1b12: 0x0080, 0x1b13: 0x0080, 0x1b14: 0x0080, 0x1b15: 0x0080, 0x1b16: 0x0080, 0x1b17: 0x0080,
+	0x1b18: 0x0080, 0x1b19: 0x0080, 0x1b1a: 0x0080, 0x1b1b: 0x0080, 0x1b1c: 0x0080, 0x1b1d: 0x0080,
+	0x1b1e: 0x0080, 0x1b1f: 0x0080, 0x1b20: 0x0080, 0x1b21: 0x0080, 0x1b22: 0x0080, 0x1b23: 0x0080,
+	0x1b24: 0x0080, 0x1b25: 0x0080, 0x1b26: 0x0080, 0x1b27: 0x0080, 0x1b28: 0x0040, 0x1b29: 0x0040,
+	0x1b2a: 0x0040, 0x1b2b: 0x0040, 0x1b2c: 0x0040, 0x1b2d: 0x0040, 0x1b2e: 0x0040, 0x1b2f: 0x0080,
+	0x1b30: 0x0080, 0x1b31: 0x0080, 0x1b32: 0x0080, 0x1b33: 0x0080, 0x1b34: 0x0080, 0x1b35: 0x0080,
+	0x1b36: 0x0080, 0x1b37: 0x0080, 0x1b38: 0x0080, 0x1b39: 0x0080, 0x1b3a: 0x0080, 0x1b3b: 0x0080,
+	0x1b3c: 0x0080, 0x1b3d: 0x0080, 0x1b3e: 0x0080, 0x1b3f: 0x0080,
+	// Block 0x6d, offset 0x1b40
+	0x1b40: 0x0080, 0x1b41: 0x0080, 0x1b42: 0x0080, 0x1b43: 0x0080, 0x1b44: 0x0080, 0x1b45: 0x0080,
+	0x1b46: 0x0080, 0x1b47: 0x0080, 0x1b48: 0x0080, 0x1b49: 0x0080, 0x1b4a: 0x0080, 0x1b4b: 0x0080,
+	0x1b4c: 0x0080, 0x1b4d: 0x0080, 0x1b4e: 0x0080, 0x1b4f: 0x0080, 0x1b50: 0x0080, 0x1b51: 0x0080,
+	0x1b52: 0x0080, 0x1b53: 0x0080, 0x1b54: 0x0080, 0x1b55: 0x0080, 0x1b56: 0x0080, 0x1b57: 0x0080,
+	0x1b58: 0x0080, 0x1b59: 0x0080, 0x1b5a: 0x0080, 0x1b5b: 0x0080, 0x1b5c: 0x0080, 0x1b5d: 0x0080,
+	0x1b5e: 0x0080, 0x1b5f: 0x0080, 0x1b60: 0x0040, 0x1b61: 0x0040, 0x1b62: 0x0040, 0x1b63: 0x0040,
+	0x1b64: 0x0040, 0x1b66: 0x0040, 0x1b67: 0x0040, 0x1b68: 0x0040, 0x1b69: 0x0040,
+	0x1b6a: 0x0040, 0x1b6b: 0x0040, 0x1b6c: 0x0040, 0x1b6d: 0x0040, 0x1b6e: 0x0040, 0x1b6f: 0x0040,
+	0x1b70: 0x0080, 0x1b71: 0x0080, 0x1b74: 0x0080, 0x1b75: 0x0080,
+	0x1b76: 0x0080, 0x1b77: 0x0080, 0x1b78: 0x0080, 0x1b79: 0x0080, 0x1b7a: 0x0080, 0x1b7b: 0x0080,
+	0x1b7c: 0x0080, 0x1b7d: 0x0080, 0x1b7e: 0x0080, 0x1b7f: 0x0080,
+	// Block 0x6e, offset 0x1b80
+	0x1b80: 0x0080, 0x1b81: 0x0080, 0x1b82: 0x0080, 0x1b83: 0x0080, 0x1b84: 0x0080, 0x1b85: 0x0080,
+	0x1b86: 0x0080, 0x1b87: 0x0080, 0x1b88: 0x0080, 0x1b89: 0x0080, 0x1b8a: 0x0080, 0x1b8b: 0x0080,
+	0x1b8c: 0x0080, 0x1b8d: 0x0080, 0x1b8e: 0x0080, 0x1b90: 0x0080, 0x1b91: 0x0080,
+	0x1b92: 0x0080, 0x1b93: 0x0080, 0x1b94: 0x0080, 0x1b95: 0x0080, 0x1b96: 0x0080, 0x1b97: 0x0080,
+	0x1b98: 0x0080, 0x1b99: 0x0080, 0x1b9a: 0x0080, 0x1b9b: 0x0080, 0x1b9c: 0x0080,
+	0x1ba0: 0x0080, 0x1ba1: 0x0080, 0x1ba2: 0x0080, 0x1ba3: 0x0080,
+	0x1ba4: 0x0080, 0x1ba5: 0x0080, 0x1ba6: 0x0080, 0x1ba7: 0x0080, 0x1ba8: 0x0080, 0x1ba9: 0x0080,
+	0x1baa: 0x0080, 0x1bab: 0x0080, 0x1bac: 0x0080, 0x1bad: 0x0080, 0x1bae: 0x0080, 0x1baf: 0x0080,
+	0x1bb0: 0x0080, 0x1bb1: 0x0080, 0x1bb2: 0x0080, 0x1bb3: 0x0080, 0x1bb4: 0x0080, 0x1bb5: 0x0080,
+	0x1bb6: 0x0080, 0x1bb7: 0x0080, 0x1bb8: 0x0080, 0x1bb9: 0x0080, 0x1bba: 0x0080, 0x1bbb: 0x0080,
+	0x1bbc: 0x0080, 0x1bbd: 0x0080, 0x1bbe: 0x0080, 0x1bbf: 0x0080,
+	// Block 0x6f, offset 0x1bc0
+	0x1bc0: 0x0080, 0x1bc1: 0x0080,
+	0x1bd0: 0x00c3, 0x1bd1: 0x00c3,
+	0x1bd2: 0x00c3, 0x1bd3: 0x00c3, 0x1bd4: 0x00c3, 0x1bd5: 0x00c3, 0x1bd6: 0x00c3, 0x1bd7: 0x00c3,
+	0x1bd8: 0x00c3, 0x1bd9: 0x00c3, 0x1bda: 0x00c3, 0x1bdb: 0x00c3, 0x1bdc: 0x00c3, 0x1bdd: 0x0083,
+	0x1bde: 0x0083, 0x1bdf: 0x0083, 0x1be0: 0x0083, 0x1be1: 0x00c3, 0x1be2: 0x0083, 0x1be3: 0x0083,
+	0x1be4: 0x0083, 0x1be5: 0x00c3, 0x1be6: 0x00c3, 0x1be7: 0x00c3, 0x1be8: 0x00c3, 0x1be9: 0x00c3,
+	0x1bea: 0x00c3, 0x1beb: 0x00c3, 0x1bec: 0x00c3, 0x1bed: 0x00c3, 0x1bee: 0x00c3, 0x1bef: 0x00c3,
+	0x1bf0: 0x00c3,
+	// Block 0x70, offset 0x1c00
+	0x1c00: 0x0080, 0x1c01: 0x0080, 0x1c02: 0x0080, 0x1c03: 0x0080, 0x1c04: 0x0080, 0x1c05: 0x0080,
+	0x1c06: 0x0080, 0x1c07: 0x0080, 0x1c08: 0x0080, 0x1c09: 0x0080, 0x1c0a: 0x0080, 0x1c0b: 0x0080,
+	0x1c0c: 0x0080, 0x1c0d: 0x0080, 0x1c0e: 0x0080, 0x1c0f: 0x0080, 0x1c10: 0x0080, 0x1c11: 0x0080,
+	0x1c12: 0x0080, 0x1c13: 0x0080, 0x1c14: 0x0080, 0x1c15: 0x0080, 0x1c16: 0x0080, 0x1c17: 0x0080,
+	0x1c18: 0x0080, 0x1c19: 0x0080, 0x1c1a: 0x0080, 0x1c1b: 0x0080, 0x1c1c: 0x0080, 0x1c1d: 0x0080,
+	0x1c1e: 0x0080, 0x1c1f: 0x0080, 0x1c20: 0x0080, 0x1c21: 0x0080, 0x1c22: 0x0080, 0x1c23: 0x0080,
+	0x1c24: 0x0080, 0x1c25: 0x0080, 0x1c26: 0x0088, 0x1c27: 0x0080, 0x1c28: 0x0080, 0x1c29: 0x0080,
+	0x1c2a: 0x0080, 0x1c2b: 0x0080, 0x1c2c: 0x0080, 0x1c2d: 0x0080, 0x1c2e: 0x0080, 0x1c2f: 0x0080,
+	0x1c30: 0x0080, 0x1c31: 0x0080, 0x1c32: 0x00c0, 0x1c33: 0x0080, 0x1c34: 0x0080, 0x1c35: 0x0080,
+	0x1c36: 0x0080, 0x1c37: 0x0080, 0x1c38: 0x0080, 0x1c39: 0x0080, 0x1c3a: 0x0080, 0x1c3b: 0x0080,
+	0x1c3c: 0x0080, 0x1c3d: 0x0080, 0x1c3e: 0x0080, 0x1c3f: 0x0080,
+	// Block 0x71, offset 0x1c40
+	0x1c40: 0x0080, 0x1c41: 0x0080, 0x1c42: 0x0080, 0x1c43: 0x0080, 0x1c44: 0x0080, 0x1c45: 0x0080,
+	0x1c46: 0x0080, 0x1c47: 0x0080, 0x1c48: 0x0080, 0x1c49: 0x0080, 0x1c4a: 0x0080, 0x1c4b: 0x0080,
+	0x1c4c: 0x0080, 0x1c4d: 0x0080, 0x1c4e: 0x00c0, 0x1c4f: 0x0080, 0x1c50: 0x0080, 0x1c51: 0x0080,
+	0x1c52: 0x0080, 0x1c53: 0x0080, 0x1c54: 0x0080, 0x1c55: 0x0080, 0x1c56: 0x0080, 0x1c57: 0x0080,
+	0x1c58: 0x0080, 0x1c59: 0x0080, 0x1c5a: 0x0080, 0x1c5b: 0x0080, 0x1c5c: 0x0080, 0x1c5d: 0x0080,
+	0x1c5e: 0x0080, 0x1c5f: 0x0080, 0x1c60: 0x0080, 0x1c61: 0x0080, 0x1c62: 0x0080, 0x1c63: 0x0080,
+	0x1c64: 0x0080, 0x1c65: 0x0080, 0x1c66: 0x0080, 0x1c67: 0x0080, 0x1c68: 0x0080, 0x1c69: 0x0080,
+	0x1c6a: 0x0080, 0x1c6b: 0x0080, 0x1c6c: 0x0080, 0x1c6d: 0x0080, 0x1c6e: 0x0080, 0x1c6f: 0x0080,
+	0x1c70: 0x0080, 0x1c71: 0x0080, 0x1c72: 0x0080, 0x1c73: 0x0080, 0x1c74: 0x0080, 0x1c75: 0x0080,
+	0x1c76: 0x0080, 0x1c77: 0x0080, 0x1c78: 0x0080, 0x1c79: 0x0080, 0x1c7a: 0x0080, 0x1c7b: 0x0080,
+	0x1c7c: 0x0080, 0x1c7d: 0x0080, 0x1c7e: 0x0080, 0x1c7f: 0x0080,
+	// Block 0x72, offset 0x1c80
+	0x1c80: 0x0080, 0x1c81: 0x0080, 0x1c82: 0x0080, 0x1c83: 0x00c0, 0x1c84: 0x00c0, 0x1c85: 0x0080,
+	0x1c86: 0x0080, 0x1c87: 0x0080, 0x1c88: 0x0080, 0x1c89: 0x0080, 0x1c8a: 0x0080, 0x1c8b: 0x0080,
+	0x1c90: 0x0080, 0x1c91: 0x0080,
+	0x1c92: 0x0080, 0x1c93: 0x0080, 0x1c94: 0x0080, 0x1c95: 0x0080, 0x1c96: 0x0080, 0x1c97: 0x0080,
+	0x1c98: 0x0080, 0x1c99: 0x0080, 0x1c9a: 0x0080, 0x1c9b: 0x0080, 0x1c9c: 0x0080, 0x1c9d: 0x0080,
+	0x1c9e: 0x0080, 0x1c9f: 0x0080, 0x1ca0: 0x0080, 0x1ca1: 0x0080, 0x1ca2: 0x0080, 0x1ca3: 0x0080,
+	0x1ca4: 0x0080, 0x1ca5: 0x0080, 0x1ca6: 0x0080, 0x1ca7: 0x0080, 0x1ca8: 0x0080, 0x1ca9: 0x0080,
+	0x1caa: 0x0080, 0x1cab: 0x0080, 0x1cac: 0x0080, 0x1cad: 0x0080, 0x1cae: 0x0080, 0x1caf: 0x0080,
+	0x1cb0: 0x0080, 0x1cb1: 0x0080, 0x1cb2: 0x0080, 0x1cb3: 0x0080, 0x1cb4: 0x0080, 0x1cb5: 0x0080,
+	0x1cb6: 0x0080, 0x1cb7: 0x0080, 0x1cb8: 0x0080, 0x1cb9: 0x0080, 0x1cba: 0x0080, 0x1cbb: 0x0080,
+	0x1cbc: 0x0080, 0x1cbd: 0x0080, 0x1cbe: 0x0080, 0x1cbf: 0x0080,
+	// Block 0x73, offset 0x1cc0
+	0x1cc0: 0x0080, 0x1cc1: 0x0080, 0x1cc2: 0x0080, 0x1cc3: 0x0080, 0x1cc4: 0x0080, 0x1cc5: 0x0080,
+	0x1cc6: 0x0080, 0x1cc7: 0x0080, 0x1cc8: 0x0080, 0x1cc9: 0x0080, 0x1cca: 0x0080, 0x1ccb: 0x0080,
+	0x1ccc: 0x0080, 0x1ccd: 0x0080, 0x1cce: 0x0080, 0x1ccf: 0x0080, 0x1cd0: 0x0080, 0x1cd1: 0x0080,
+	0x1cd2: 0x0080, 0x1cd3: 0x0080, 0x1cd4: 0x0080, 0x1cd5: 0x0080, 0x1cd6: 0x0080, 0x1cd7: 0x0080,
+	0x1cd8: 0x0080, 0x1cd9: 0x0080, 0x1cda: 0x0080, 0x1cdb: 0x0080, 0x1cdc: 0x0080, 0x1cdd: 0x0080,
+	0x1cde: 0x0080, 0x1cdf: 0x0080, 0x1ce0: 0x0080, 0x1ce1: 0x0080, 0x1ce2: 0x0080, 0x1ce3: 0x0080,
+	0x1ce4: 0x0080, 0x1ce5: 0x0080, 0x1ce6: 0x0080, 0x1ce7: 0x0080, 0x1ce8: 0x0080, 0x1ce9: 0x0080,
+	0x1cea: 0x0080, 0x1ceb: 0x0080, 0x1cec: 0x0080, 0x1ced: 0x0080, 0x1cee: 0x0080, 0x1cef: 0x0080,
+	0x1cf0: 0x0080, 0x1cf1: 0x0080, 0x1cf2: 0x0080, 0x1cf3: 0x0080, 0x1cf4: 0x0080, 0x1cf5: 0x0080,
+	0x1cf6: 0x0080, 0x1cf7: 0x0080, 0x1cf8: 0x0080, 0x1cf9: 0x0080, 0x1cfa: 0x0080, 0x1cfb: 0x0080,
+	0x1cfc: 0x0080, 0x1cfd: 0x0080, 0x1cfe: 0x0080, 0x1cff: 0x0080,
+	// Block 0x74, offset 0x1d00
+	0x1d00: 0x0080, 0x1d01: 0x0080, 0x1d02: 0x0080, 0x1d03: 0x0080, 0x1d04: 0x0080, 0x1d05: 0x0080,
+	0x1d06: 0x0080, 0x1d07: 0x0080, 0x1d08: 0x0080, 0x1d09: 0x0080, 0x1d0a: 0x0080, 0x1d0b: 0x0080,
+	0x1d0c: 0x0080, 0x1d0d: 0x0080, 0x1d0e: 0x0080, 0x1d0f: 0x0080, 0x1d10: 0x0080, 0x1d11: 0x0080,
+	0x1d12: 0x0080, 0x1d13: 0x0080, 0x1d14: 0x0080, 0x1d15: 0x0080, 0x1d16: 0x0080, 0x1d17: 0x0080,
+	0x1d18: 0x0080, 0x1d19: 0x0080, 0x1d1a: 0x0080, 0x1d1b: 0x0080, 0x1d1c: 0x0080, 0x1d1d: 0x0080,
+	0x1d1e: 0x0080, 0x1d1f: 0x0080, 0x1d20: 0x0080, 0x1d21: 0x0080, 0x1d22: 0x0080, 0x1d23: 0x0080,
+	0x1d24: 0x0080, 0x1d25: 0x0080, 0x1d26: 0x0080, 0x1d27: 0x0080, 0x1d28: 0x0080, 0x1d29: 0x0080,
+	// Block 0x75, offset 0x1d40
+	0x1d40: 0x0080, 0x1d41: 0x0080, 0x1d42: 0x0080, 0x1d43: 0x0080, 0x1d44: 0x0080, 0x1d45: 0x0080,
+	0x1d46: 0x0080, 0x1d47: 0x0080, 0x1d48: 0x0080, 0x1d49: 0x0080, 0x1d4a: 0x0080,
+	0x1d60: 0x0080, 0x1d61: 0x0080, 0x1d62: 0x0080, 0x1d63: 0x0080,
+	0x1d64: 0x0080, 0x1d65: 0x0080, 0x1d66: 0x0080, 0x1d67: 0x0080, 0x1d68: 0x0080, 0x1d69: 0x0080,
+	0x1d6a: 0x0080, 0x1d6b: 0x0080, 0x1d6c: 0x0080, 0x1d6d: 0x0080, 0x1d6e: 0x0080, 0x1d6f: 0x0080,
+	0x1d70: 0x0080, 0x1d71: 0x0080, 0x1d72: 0x0080, 0x1d73: 0x0080, 0x1d74: 0x0080, 0x1d75: 0x0080,
+	0x1d76: 0x0080, 0x1d77: 0x0080, 0x1d78: 0x0080, 0x1d79: 0x0080, 0x1d7a: 0x0080, 0x1d7b: 0x0080,
+	0x1d7c: 0x0080, 0x1d7d: 0x0080, 0x1d7e: 0x0080, 0x1d7f: 0x0080,
+	// Block 0x76, offset 0x1d80
+	0x1d80: 0x0080, 0x1d81: 0x0080, 0x1d82: 0x0080, 0x1d83: 0x0080, 0x1d84: 0x0080, 0x1d85: 0x0080,
+	0x1d86: 0x0080, 0x1d87: 0x0080, 0x1d88: 0x0080, 0x1d89: 0x0080, 0x1d8a: 0x0080, 0x1d8b: 0x0080,
+	0x1d8c: 0x0080, 0x1d8d: 0x0080, 0x1d8e: 0x0080, 0x1d8f: 0x0080, 0x1d90: 0x0080, 0x1d91: 0x0080,
+	0x1d92: 0x0080, 0x1d93: 0x0080, 0x1d94: 0x0080, 0x1d95: 0x0080, 0x1d96: 0x0080, 0x1d97: 0x0080,
+	0x1d98: 0x0080, 0x1d99: 0x0080, 0x1d9a: 0x0080, 0x1d9b: 0x0080, 0x1d9c: 0x0080, 0x1d9d: 0x0080,
+	0x1d9e: 0x0080, 0x1d9f: 0x0080, 0x1da0: 0x0080, 0x1da1: 0x0080, 0x1da2: 0x0080, 0x1da3: 0x0080,
+	0x1da4: 0x0080, 0x1da5: 0x0080, 0x1da6: 0x0080, 0x1da7: 0x0080, 0x1da8: 0x0080, 0x1da9: 0x0080,
+	0x1daa: 0x0080, 0x1dab: 0x0080, 0x1dac: 0x0080, 0x1dad: 0x0080, 0x1dae: 0x0080, 0x1daf: 0x0080,
+	0x1db0: 0x0080, 0x1db1: 0x0080, 0x1db2: 0x0080, 0x1db3: 0x0080,
+	0x1db6: 0x0080, 0x1db7: 0x0080, 0x1db8: 0x0080, 0x1db9: 0x0080, 0x1dba: 0x0080, 0x1dbb: 0x0080,
+	0x1dbc: 0x0080, 0x1dbd: 0x0080, 0x1dbe: 0x0080, 0x1dbf: 0x0080,
+	// Block 0x77, offset 0x1dc0
+	0x1dc0: 0x00c0, 0x1dc1: 0x00c0, 0x1dc2: 0x00c0, 0x1dc3: 0x00c0, 0x1dc4: 0x00c0, 0x1dc5: 0x00c0,
+	0x1dc6: 0x00c0, 0x1dc7: 0x00c0, 0x1dc8: 0x00c0, 0x1dc9: 0x00c0, 0x1dca: 0x00c0, 0x1dcb: 0x00c0,
+	0x1dcc: 0x00c0, 0x1dcd: 0x00c0, 0x1dce: 0x00c0, 0x1dcf: 0x00c0, 0x1dd0: 0x00c0, 0x1dd1: 0x00c0,
+	0x1dd2: 0x00c0, 0x1dd3: 0x00c0, 0x1dd4: 0x00c0, 0x1dd5: 0x00c0, 0x1dd6: 0x00c0, 0x1dd7: 0x00c0,
+	0x1dd8: 0x00c0, 0x1dd9: 0x00c0, 0x1dda: 0x00c0, 0x1ddb: 0x00c0, 0x1ddc: 0x00c0, 0x1ddd: 0x00c0,
+	0x1dde: 0x00c0, 0x1ddf: 0x00c0, 0x1de0: 0x00c0, 0x1de1: 0x00c0, 0x1de2: 0x00c0, 0x1de3: 0x00c0,
+	0x1de4: 0x00c0, 0x1de5: 0x00c0, 0x1de6: 0x00c0, 0x1de7: 0x00c0, 0x1de8: 0x00c0, 0x1de9: 0x00c0,
+	0x1dea: 0x00c0, 0x1deb: 0x00c0, 0x1dec: 0x00c0, 0x1ded: 0x00c0, 0x1dee: 0x00c0, 0x1def: 0x00c0,
+	0x1df0: 0x00c0, 0x1df1: 0x00c0, 0x1df2: 0x00c0, 0x1df3: 0x00c0, 0x1df4: 0x00c0, 0x1df5: 0x00c0,
+	0x1df6: 0x00c0, 0x1df7: 0x00c0, 0x1df8: 0x00c0, 0x1df9: 0x00c0, 0x1dfa: 0x00c0, 0x1dfb: 0x00c0,
+	0x1dfc: 0x0080, 0x1dfd: 0x0080, 0x1dfe: 0x00c0, 0x1dff: 0x00c0,
+	// Block 0x78, offset 0x1e00
+	0x1e00: 0x00c0, 0x1e01: 0x00c0, 0x1e02: 0x00c0, 0x1e03: 0x00c0, 0x1e04: 0x00c0, 0x1e05: 0x00c0,
+	0x1e06: 0x00c0, 0x1e07: 0x00c0, 0x1e08: 0x00c0, 0x1e09: 0x00c0, 0x1e0a: 0x00c0, 0x1e0b: 0x00c0,
+	0x1e0c: 0x00c0, 0x1e0d: 0x00c0, 0x1e0e: 0x00c0, 0x1e0f: 0x00c0, 0x1e10: 0x00c0, 0x1e11: 0x00c0,
+	0x1e12: 0x00c0, 0x1e13: 0x00c0, 0x1e14: 0x00c0, 0x1e15: 0x00c0, 0x1e16: 0x00c0, 0x1e17: 0x00c0,
+	0x1e18: 0x00c0, 0x1e19: 0x00c0, 0x1e1a: 0x00c0, 0x1e1b: 0x00c0, 0x1e1c: 0x00c0, 0x1e1d: 0x00c0,
+	0x1e1e: 0x00c0, 0x1e1f: 0x00c0, 0x1e20: 0x00c0, 0x1e21: 0x00c0, 0x1e22: 0x00c0, 0x1e23: 0x00c0,
+	0x1e24: 0x00c0, 0x1e25: 0x0080, 0x1e26: 0x0080, 0x1e27: 0x0080, 0x1e28: 0x0080, 0x1e29: 0x0080,
+	0x1e2a: 0x0080, 0x1e2b: 0x00c0, 0x1e2c: 0x00c0, 0x1e2d: 0x00c0, 0x1e2e: 0x00c0, 0x1e2f: 0x00c3,
+	0x1e30: 0x00c3, 0x1e31: 0x00c3, 0x1e32: 0x00c0, 0x1e33: 0x00c0,
+	0x1e39: 0x0080, 0x1e3a: 0x0080, 0x1e3b: 0x0080,
+	0x1e3c: 0x0080, 0x1e3d: 0x0080, 0x1e3e: 0x0080, 0x1e3f: 0x0080,
+	// Block 0x79, offset 0x1e40
+	0x1e40: 0x00c0, 0x1e41: 0x00c0, 0x1e42: 0x00c0, 0x1e43: 0x00c0, 0x1e44: 0x00c0, 0x1e45: 0x00c0,
+	0x1e46: 0x00c0, 0x1e47: 0x00c0, 0x1e48: 0x00c0, 0x1e49: 0x00c0, 0x1e4a: 0x00c0, 0x1e4b: 0x00c0,
+	0x1e4c: 0x00c0, 0x1e4d: 0x00c0, 0x1e4e: 0x00c0, 0x1e4f: 0x00c0, 0x1e50: 0x00c0, 0x1e51: 0x00c0,
+	0x1e52: 0x00c0, 0x1e53: 0x00c0, 0x1e54: 0x00c0, 0x1e55: 0x00c0, 0x1e56: 0x00c0, 0x1e57: 0x00c0,
+	0x1e58: 0x00c0, 0x1e59: 0x00c0, 0x1e5a: 0x00c0, 0x1e5b: 0x00c0, 0x1e5c: 0x00c0, 0x1e5d: 0x00c0,
+	0x1e5e: 0x00c0, 0x1e5f: 0x00c0, 0x1e60: 0x00c0, 0x1e61: 0x00c0, 0x1e62: 0x00c0, 0x1e63: 0x00c0,
+	0x1e64: 0x00c0, 0x1e65: 0x00c0, 0x1e67: 0x00c0,
+	0x1e6d: 0x00c0,
+	0x1e70: 0x00c0, 0x1e71: 0x00c0, 0x1e72: 0x00c0, 0x1e73: 0x00c0, 0x1e74: 0x00c0, 0x1e75: 0x00c0,
+	0x1e76: 0x00c0, 0x1e77: 0x00c0, 0x1e78: 0x00c0, 0x1e79: 0x00c0, 0x1e7a: 0x00c0, 0x1e7b: 0x00c0,
+	0x1e7c: 0x00c0, 0x1e7d: 0x00c0, 0x1e7e: 0x00c0, 0x1e7f: 0x00c0,
+	// Block 0x7a, offset 0x1e80
+	0x1e80: 0x00c0, 0x1e81: 0x00c0, 0x1e82: 0x00c0, 0x1e83: 0x00c0, 0x1e84: 0x00c0, 0x1e85: 0x00c0,
+	0x1e86: 0x00c0, 0x1e87: 0x00c0, 0x1e88: 0x00c0, 0x1e89: 0x00c0, 0x1e8a: 0x00c0, 0x1e8b: 0x00c0,
+	0x1e8c: 0x00c0, 0x1e8d: 0x00c0, 0x1e8e: 0x00c0, 0x1e8f: 0x00c0, 0x1e90: 0x00c0, 0x1e91: 0x00c0,
+	0x1e92: 0x00c0, 0x1e93: 0x00c0, 0x1e94: 0x00c0, 0x1e95: 0x00c0, 0x1e96: 0x00c0, 0x1e97: 0x00c0,
+	0x1e98: 0x00c0, 0x1e99: 0x00c0, 0x1e9a: 0x00c0, 0x1e9b: 0x00c0, 0x1e9c: 0x00c0, 0x1e9d: 0x00c0,
+	0x1e9e: 0x00c0, 0x1e9f: 0x00c0, 0x1ea0: 0x00c0, 0x1ea1: 0x00c0, 0x1ea2: 0x00c0, 0x1ea3: 0x00c0,
+	0x1ea4: 0x00c0, 0x1ea5: 0x00c0, 0x1ea6: 0x00c0, 0x1ea7: 0x00c0,
+	0x1eaf: 0x0080,
+	0x1eb0: 0x0080,
+	0x1ebf: 0x00c6,
+	// Block 0x7b, offset 0x1ec0
+	0x1ec0: 0x00c0, 0x1ec1: 0x00c0, 0x1ec2: 0x00c0, 0x1ec3: 0x00c0, 0x1ec4: 0x00c0, 0x1ec5: 0x00c0,
+	0x1ec6: 0x00c0, 0x1ec7: 0x00c0, 0x1ec8: 0x00c0, 0x1ec9: 0x00c0, 0x1eca: 0x00c0, 0x1ecb: 0x00c0,
+	0x1ecc: 0x00c0, 0x1ecd: 0x00c0, 0x1ece: 0x00c0, 0x1ecf: 0x00c0, 0x1ed0: 0x00c0, 0x1ed1: 0x00c0,
+	0x1ed2: 0x00c0, 0x1ed3: 0x00c0, 0x1ed4: 0x00c0, 0x1ed5: 0x00c0, 0x1ed6: 0x00c0,
+	0x1ee0: 0x00c0, 0x1ee1: 0x00c0, 0x1ee2: 0x00c0, 0x1ee3: 0x00c0,
+	0x1ee4: 0x00c0, 0x1ee5: 0x00c0, 0x1ee6: 0x00c0, 0x1ee8: 0x00c0, 0x1ee9: 0x00c0,
+	0x1eea: 0x00c0, 0x1eeb: 0x00c0, 0x1eec: 0x00c0, 0x1eed: 0x00c0, 0x1eee: 0x00c0,
+	0x1ef0: 0x00c0, 0x1ef1: 0x00c0, 0x1ef2: 0x00c0, 0x1ef3: 0x00c0, 0x1ef4: 0x00c0, 0x1ef5: 0x00c0,
+	0x1ef6: 0x00c0, 0x1ef8: 0x00c0, 0x1ef9: 0x00c0, 0x1efa: 0x00c0, 0x1efb: 0x00c0,
+	0x1efc: 0x00c0, 0x1efd: 0x00c0, 0x1efe: 0x00c0,
+	// Block 0x7c, offset 0x1f00
+	0x1f00: 0x00c0, 0x1f01: 0x00c0, 0x1f02: 0x00c0, 0x1f03: 0x00c0, 0x1f04: 0x00c0, 0x1f05: 0x00c0,
+	0x1f06: 0x00c0, 0x1f08: 0x00c0, 0x1f09: 0x00c0, 0x1f0a: 0x00c0, 0x1f0b: 0x00c0,
+	0x1f0c: 0x00c0, 0x1f0d: 0x00c0, 0x1f0e: 0x00c0, 0x1f10: 0x00c0, 0x1f11: 0x00c0,
+	0x1f12: 0x00c0, 0x1f13: 0x00c0, 0x1f14: 0x00c0, 0x1f15: 0x00c0, 0x1f16: 0x00c0,
+	0x1f18: 0x00c0, 0x1f19: 0x00c0, 0x1f1a: 0x00c0, 0x1f1b: 0x00c0, 0x1f1c: 0x00c0, 0x1f1d: 0x00c0,
+	0x1f1e: 0x00c0, 0x1f20: 0x00c3, 0x1f21: 0x00c3, 0x1f22: 0x00c3, 0x1f23: 0x00c3,
+	0x1f24: 0x00c3, 0x1f25: 0x00c3, 0x1f26: 0x00c3, 0x1f27: 0x00c3, 0x1f28: 0x00c3, 0x1f29: 0x00c3,
+	0x1f2a: 0x00c3, 0x1f2b: 0x00c3, 0x1f2c: 0x00c3, 0x1f2d: 0x00c3, 0x1f2e: 0x00c3, 0x1f2f: 0x00c3,
+	0x1f30: 0x00c3, 0x1f31: 0x00c3, 0x1f32: 0x00c3, 0x1f33: 0x00c3, 0x1f34: 0x00c3, 0x1f35: 0x00c3,
+	0x1f36: 0x00c3, 0x1f37: 0x00c3, 0x1f38: 0x00c3, 0x1f39: 0x00c3, 0x1f3a: 0x00c3, 0x1f3b: 0x00c3,
+	0x1f3c: 0x00c3, 0x1f3d: 0x00c3, 0x1f3e: 0x00c3, 0x1f3f: 0x00c3,
+	// Block 0x7d, offset 0x1f40
+	0x1f40: 0x0080, 0x1f41: 0x0080, 0x1f42: 0x0080, 0x1f43: 0x0080, 0x1f44: 0x0080, 0x1f45: 0x0080,
+	0x1f46: 0x0080, 0x1f47: 0x0080, 0x1f48: 0x0080, 0x1f49: 0x0080, 0x1f4a: 0x0080, 0x1f4b: 0x0080,
+	0x1f4c: 0x0080, 0x1f4d: 0x0080, 0x1f4e: 0x0080, 0x1f4f: 0x0080, 0x1f50: 0x0080, 0x1f51: 0x0080,
+	0x1f52: 0x0080, 0x1f53: 0x0080, 0x1f54: 0x0080, 0x1f55: 0x0080, 0x1f56: 0x0080, 0x1f57: 0x0080,
+	0x1f58: 0x0080, 0x1f59: 0x0080, 0x1f5a: 0x0080, 0x1f5b: 0x0080, 0x1f5c: 0x0080, 0x1f5d: 0x0080,
+	0x1f5e: 0x0080, 0x1f5f: 0x0080, 0x1f60: 0x0080, 0x1f61: 0x0080, 0x1f62: 0x0080, 0x1f63: 0x0080,
+	0x1f64: 0x0080, 0x1f65: 0x0080, 0x1f66: 0x0080, 0x1f67: 0x0080, 0x1f68: 0x0080, 0x1f69: 0x0080,
+	0x1f6a: 0x0080, 0x1f6b: 0x0080, 0x1f6c: 0x0080, 0x1f6d: 0x0080, 0x1f6e: 0x0080, 0x1f6f: 0x00c0,
+	0x1f70: 0x0080, 0x1f71: 0x0080, 0x1f72: 0x0080, 0x1f73: 0x0080, 0x1f74: 0x0080, 0x1f75: 0x0080,
+	0x1f76: 0x0080, 0x1f77: 0x0080, 0x1f78: 0x0080, 0x1f79: 0x0080, 0x1f7a: 0x0080, 0x1f7b: 0x0080,
+	0x1f7c: 0x0080, 0x1f7d: 0x0080, 0x1f7e: 0x0080, 0x1f7f: 0x0080,
+	// Block 0x7e, offset 0x1f80
+	0x1f80: 0x0080, 0x1f81: 0x0080, 0x1f82: 0x0080, 0x1f83: 0x0080, 0x1f84: 0x0080, 0x1f85: 0x0080,
+	0x1f86: 0x0080, 0x1f87: 0x0080, 0x1f88: 0x0080, 0x1f89: 0x0080, 0x1f8a: 0x0080, 0x1f8b: 0x0080,
+	0x1f8c: 0x0080, 0x1f8d: 0x0080, 0x1f8e: 0x0080, 0x1f8f: 0x0080, 0x1f90: 0x0080, 0x1f91: 0x0080,
+	0x1f92: 0x0080, 0x1f93: 0x0080, 0x1f94: 0x0080, 0x1f95: 0x0080, 0x1f96: 0x0080, 0x1f97: 0x0080,
+	0x1f98: 0x0080, 0x1f99: 0x0080, 0x1f9a: 0x0080, 0x1f9b: 0x0080, 0x1f9c: 0x0080, 0x1f9d: 0x0080,
+	// Block 0x7f, offset 0x1fc0
+	0x1fc0: 0x008c, 0x1fc1: 0x008c, 0x1fc2: 0x008c, 0x1fc3: 0x008c, 0x1fc4: 0x008c, 0x1fc5: 0x008c,
+	0x1fc6: 0x008c, 0x1fc7: 0x008c, 0x1fc8: 0x008c, 0x1fc9: 0x008c, 0x1fca: 0x008c, 0x1fcb: 0x008c,
+	0x1fcc: 0x008c, 0x1fcd: 0x008c, 0x1fce: 0x008c, 0x1fcf: 0x008c, 0x1fd0: 0x008c, 0x1fd1: 0x008c,
+	0x1fd2: 0x008c, 0x1fd3: 0x008c, 0x1fd4: 0x008c, 0x1fd5: 0x008c, 0x1fd6: 0x008c, 0x1fd7: 0x008c,
+	0x1fd8: 0x008c, 0x1fd9: 0x008c, 0x1fdb: 0x008c, 0x1fdc: 0x008c, 0x1fdd: 0x008c,
+	0x1fde: 0x008c, 0x1fdf: 0x008c, 0x1fe0: 0x008c, 0x1fe1: 0x008c, 0x1fe2: 0x008c, 0x1fe3: 0x008c,
+	0x1fe4: 0x008c, 0x1fe5: 0x008c, 0x1fe6: 0x008c, 0x1fe7: 0x008c, 0x1fe8: 0x008c, 0x1fe9: 0x008c,
+	0x1fea: 0x008c, 0x1feb: 0x008c, 0x1fec: 0x008c, 0x1fed: 0x008c, 0x1fee: 0x008c, 0x1fef: 0x008c,
+	0x1ff0: 0x008c, 0x1ff1: 0x008c, 0x1ff2: 0x008c, 0x1ff3: 0x008c, 0x1ff4: 0x008c, 0x1ff5: 0x008c,
+	0x1ff6: 0x008c, 0x1ff7: 0x008c, 0x1ff8: 0x008c, 0x1ff9: 0x008c, 0x1ffa: 0x008c, 0x1ffb: 0x008c,
+	0x1ffc: 0x008c, 0x1ffd: 0x008c, 0x1ffe: 0x008c, 0x1fff: 0x008c,
+	// Block 0x80, offset 0x2000
+	0x2000: 0x008c, 0x2001: 0x008c, 0x2002: 0x008c, 0x2003: 0x008c, 0x2004: 0x008c, 0x2005: 0x008c,
+	0x2006: 0x008c, 0x2007: 0x008c, 0x2008: 0x008c, 0x2009: 0x008c, 0x200a: 0x008c, 0x200b: 0x008c,
+	0x200c: 0x008c, 0x200d: 0x008c, 0x200e: 0x008c, 0x200f: 0x008c, 0x2010: 0x008c, 0x2011: 0x008c,
+	0x2012: 0x008c, 0x2013: 0x008c, 0x2014: 0x008c, 0x2015: 0x008c, 0x2016: 0x008c, 0x2017: 0x008c,
+	0x2018: 0x008c, 0x2019: 0x008c, 0x201a: 0x008c, 0x201b: 0x008c, 0x201c: 0x008c, 0x201d: 0x008c,
+	0x201e: 0x008c, 0x201f: 0x008c, 0x2020: 0x008c, 0x2021: 0x008c, 0x2022: 0x008c, 0x2023: 0x008c,
+	0x2024: 0x008c, 0x2025: 0x008c, 0x2026: 0x008c, 0x2027: 0x008c, 0x2028: 0x008c, 0x2029: 0x008c,
+	0x202a: 0x008c, 0x202b: 0x008c, 0x202c: 0x008c, 0x202d: 0x008c, 0x202e: 0x008c, 0x202f: 0x008c,
+	0x2030: 0x008c, 0x2031: 0x008c, 0x2032: 0x008c, 0x2033: 0x008c,
+	// Block 0x81, offset 0x2040
+	0x2040: 0x008c, 0x2041: 0x008c, 0x2042: 0x008c, 0x2043: 0x008c, 0x2044: 0x008c, 0x2045: 0x008c,
+	0x2046: 0x008c, 0x2047: 0x008c, 0x2048: 0x008c, 0x2049: 0x008c, 0x204a: 0x008c, 0x204b: 0x008c,
+	0x204c: 0x008c, 0x204d: 0x008c, 0x204e: 0x008c, 0x204f: 0x008c, 0x2050: 0x008c, 0x2051: 0x008c,
+	0x2052: 0x008c, 0x2053: 0x008c, 0x2054: 0x008c, 0x2055: 0x008c, 0x2056: 0x008c, 0x2057: 0x008c,
+	0x2058: 0x008c, 0x2059: 0x008c, 0x205a: 0x008c, 0x205b: 0x008c, 0x205c: 0x008c, 0x205d: 0x008c,
+	0x205e: 0x008c, 0x205f: 0x008c, 0x2060: 0x008c, 0x2061: 0x008c, 0x2062: 0x008c, 0x2063: 0x008c,
+	0x2064: 0x008c, 0x2065: 0x008c, 0x2066: 0x008c, 0x2067: 0x008c, 0x2068: 0x008c, 0x2069: 0x008c,
+	0x206a: 0x008c, 0x206b: 0x008c, 0x206c: 0x008c, 0x206d: 0x008c, 0x206e: 0x008c, 0x206f: 0x008c,
+	0x2070: 0x008c, 0x2071: 0x008c, 0x2072: 0x008c, 0x2073: 0x008c, 0x2074: 0x008c, 0x2075: 0x008c,
+	0x2076: 0x008c, 0x2077: 0x008c, 0x2078: 0x008c, 0x2079: 0x008c, 0x207a: 0x008c, 0x207b: 0x008c,
+	0x207c: 0x008c, 0x207d: 0x008c, 0x207e: 0x008c, 0x207f: 0x008c,
+	// Block 0x82, offset 0x2080
+	0x2080: 0x008c, 0x2081: 0x008c, 0x2082: 0x008c, 0x2083: 0x008c, 0x2084: 0x008c, 0x2085: 0x008c,
+	0x2086: 0x008c, 0x2087: 0x008c, 0x2088: 0x008c, 0x2089: 0x008c, 0x208a: 0x008c, 0x208b: 0x008c,
+	0x208c: 0x008c, 0x208d: 0x008c, 0x208e: 0x008c, 0x208f: 0x008c, 0x2090: 0x008c, 0x2091: 0x008c,
+	0x2092: 0x008c, 0x2093: 0x008c, 0x2094: 0x008c, 0x2095: 0x008c,
+	0x20b0: 0x0080, 0x20b1: 0x0080, 0x20b2: 0x0080, 0x20b3: 0x0080, 0x20b4: 0x0080, 0x20b5: 0x0080,
+	0x20b6: 0x0080, 0x20b7: 0x0080, 0x20b8: 0x0080, 0x20b9: 0x0080, 0x20ba: 0x0080, 0x20bb: 0x0080,
+	0x20bc: 0x0080, 0x20bd: 0x0080, 0x20be: 0x0080, 0x20bf: 0x0080,
+	// Block 0x83, offset 0x20c0
+	0x20c0: 0x0080, 0x20c1: 0x0080, 0x20c2: 0x0080, 0x20c3: 0x0080, 0x20c4: 0x0080, 0x20c5: 0x00cc,
+	0x20c6: 0x00c0, 0x20c7: 0x00cc, 0x20c8: 0x0080, 0x20c9: 0x0080, 0x20ca: 0x0080, 0x20cb: 0x0080,
+	0x20cc: 0x0080, 0x20cd: 0x0080, 0x20ce: 0x0080, 0x20cf: 0x0080, 0x20d0: 0x0080, 0x20d1: 0x0080,
+	0x20d2: 0x0080, 0x20d3: 0x0080, 0x20d4: 0x0080, 0x20d5: 0x0080, 0x20d6: 0x0080, 0x20d7: 0x0080,
+	0x20d8: 0x0080, 0x20d9: 0x0080, 0x20da: 0x0080, 0x20db: 0x0080, 0x20dc: 0x0080, 0x20dd: 0x0080,
+	0x20de: 0x0080, 0x20df: 0x0080, 0x20e0: 0x0080, 0x20e1: 0x008c, 0x20e2: 0x008c, 0x20e3: 0x008c,
+	0x20e4: 0x008c, 0x20e5: 0x008c, 0x20e6: 0x008c, 0x20e7: 0x008c, 0x20e8: 0x008c, 0x20e9: 0x008c,
+	0x20ea: 0x00c3, 0x20eb: 0x00c3, 0x20ec: 0x00c3, 0x20ed: 0x00c3, 0x20ee: 0x0040, 0x20ef: 0x0040,
+	0x20f0: 0x0080, 0x20f1: 0x0040, 0x20f2: 0x0040, 0x20f3: 0x0040, 0x20f4: 0x0040, 0x20f5: 0x0040,
+	0x20f6: 0x0080, 0x20f7: 0x0080, 0x20f8: 0x008c, 0x20f9: 0x008c, 0x20fa: 0x008c, 0x20fb: 0x0040,
+	0x20fc: 0x00c0, 0x20fd: 0x0080, 0x20fe: 0x0080, 0x20ff: 0x0080,
+	// Block 0x84, offset 0x2100
+	0x2101: 0x00cc, 0x2102: 0x00cc, 0x2103: 0x00cc, 0x2104: 0x00cc, 0x2105: 0x00cc,
+	0x2106: 0x00cc, 0x2107: 0x00cc, 0x2108: 0x00cc, 0x2109: 0x00cc, 0x210a: 0x00cc, 0x210b: 0x00cc,
+	0x210c: 0x00cc, 0x210d: 0x00cc, 0x210e: 0x00cc, 0x210f: 0x00cc, 0x2110: 0x00cc, 0x2111: 0x00cc,
+	0x2112: 0x00cc, 0x2113: 0x00cc, 0x2114: 0x00cc, 0x2115: 0x00cc, 0x2116: 0x00cc, 0x2117: 0x00cc,
+	0x2118: 0x00cc, 0x2119: 0x00cc, 0x211a: 0x00cc, 0x211b: 0x00cc, 0x211c: 0x00cc, 0x211d: 0x00cc,
+	0x211e: 0x00cc, 0x211f: 0x00cc, 0x2120: 0x00cc, 0x2121: 0x00cc, 0x2122: 0x00cc, 0x2123: 0x00cc,
+	0x2124: 0x00cc, 0x2125: 0x00cc, 0x2126: 0x00cc, 0x2127: 0x00cc, 0x2128: 0x00cc, 0x2129: 0x00cc,
+	0x212a: 0x00cc, 0x212b: 0x00cc, 0x212c: 0x00cc, 0x212d: 0x00cc, 0x212e: 0x00cc, 0x212f: 0x00cc,
+	0x2130: 0x00cc, 0x2131: 0x00cc, 0x2132: 0x00cc, 0x2133: 0x00cc, 0x2134: 0x00cc, 0x2135: 0x00cc,
+	0x2136: 0x00cc, 0x2137: 0x00cc, 0x2138: 0x00cc, 0x2139: 0x00cc, 0x213a: 0x00cc, 0x213b: 0x00cc,
+	0x213c: 0x00cc, 0x213d: 0x00cc, 0x213e: 0x00cc, 0x213f: 0x00cc,
+	// Block 0x85, offset 0x2140
+	0x2140: 0x00cc, 0x2141: 0x00cc, 0x2142: 0x00cc, 0x2143: 0x00cc, 0x2144: 0x00cc, 0x2145: 0x00cc,
+	0x2146: 0x00cc, 0x2147: 0x00cc, 0x2148: 0x00cc, 0x2149: 0x00cc, 0x214a: 0x00cc, 0x214b: 0x00cc,
+	0x214c: 0x00cc, 0x214d: 0x00cc, 0x214e: 0x00cc, 0x214f: 0x00cc, 0x2150: 0x00cc, 0x2151: 0x00cc,
+	0x2152: 0x00cc, 0x2153: 0x00cc, 0x2154: 0x00cc, 0x2155: 0x00cc, 0x2156: 0x00cc,
+	0x2159: 0x00c3, 0x215a: 0x00c3, 0x215b: 0x0080, 0x215c: 0x0080, 0x215d: 0x00cc,
+	0x215e: 0x00cc, 0x215f: 0x008c, 0x2160: 0x0080, 0x2161: 0x00cc, 0x2162: 0x00cc, 0x2163: 0x00cc,
+	0x2164: 0x00cc, 0x2165: 0x00cc, 0x2166: 0x00cc, 0x2167: 0x00cc, 0x2168: 0x00cc, 0x2169: 0x00cc,
+	0x216a: 0x00cc, 0x216b: 0x00cc, 0x216c: 0x00cc, 0x216d: 0x00cc, 0x216e: 0x00cc, 0x216f: 0x00cc,
+	0x2170: 0x00cc, 0x2171: 0x00cc, 0x2172: 0x00cc, 0x2173: 0x00cc, 0x2174: 0x00cc, 0x2175: 0x00cc,
+	0x2176: 0x00cc, 0x2177: 0x00cc, 0x2178: 0x00cc, 0x2179: 0x00cc, 0x217a: 0x00cc, 0x217b: 0x00cc,
+	0x217c: 0x00cc, 0x217d: 0x00cc, 0x217e: 0x00cc, 0x217f: 0x00cc,
+	// Block 0x86, offset 0x2180
+	0x2180: 0x00cc, 0x2181: 0x00cc, 0x2182: 0x00cc, 0x2183: 0x00cc, 0x2184: 0x00cc, 0x2185: 0x00cc,
+	0x2186: 0x00cc, 0x2187: 0x00cc, 0x2188: 0x00cc, 0x2189: 0x00cc, 0x218a: 0x00cc, 0x218b: 0x00cc,
+	0x218c: 0x00cc, 0x218d: 0x00cc, 0x218e: 0x00cc, 0x218f: 0x00cc, 0x2190: 0x00cc, 0x2191: 0x00cc,
+	0x2192: 0x00cc, 0x2193: 0x00cc, 0x2194: 0x00cc, 0x2195: 0x00cc, 0x2196: 0x00cc, 0x2197: 0x00cc,
+	0x2198: 0x00cc, 0x2199: 0x00cc, 0x219a: 0x00cc, 0x219b: 0x00cc, 0x219c: 0x00cc, 0x219d: 0x00cc,
+	0x219e: 0x00cc, 0x219f: 0x00cc, 0x21a0: 0x00cc, 0x21a1: 0x00cc, 0x21a2: 0x00cc, 0x21a3: 0x00cc,
+	0x21a4: 0x00cc, 0x21a5: 0x00cc, 0x21a6: 0x00cc, 0x21a7: 0x00cc, 0x21a8: 0x00cc, 0x21a9: 0x00cc,
+	0x21aa: 0x00cc, 0x21ab: 0x00cc, 0x21ac: 0x00cc, 0x21ad: 0x00cc, 0x21ae: 0x00cc, 0x21af: 0x00cc,
+	0x21b0: 0x00cc, 0x21b1: 0x00cc, 0x21b2: 0x00cc, 0x21b3: 0x00cc, 0x21b4: 0x00cc, 0x21b5: 0x00cc,
+	0x21b6: 0x00cc, 0x21b7: 0x00cc, 0x21b8: 0x00cc, 0x21b9: 0x00cc, 0x21ba: 0x00cc, 0x21bb: 0x00d2,
+	0x21bc: 0x00c0, 0x21bd: 0x00cc, 0x21be: 0x00cc, 0x21bf: 0x008c,
+	// Block 0x87, offset 0x21c0
+	0x21c5: 0x00c0,
+	0x21c6: 0x00c0, 0x21c7: 0x00c0, 0x21c8: 0x00c0, 0x21c9: 0x00c0, 0x21ca: 0x00c0, 0x21cb: 0x00c0,
+	0x21cc: 0x00c0, 0x21cd: 0x00c0, 0x21ce: 0x00c0, 0x21cf: 0x00c0, 0x21d0: 0x00c0, 0x21d1: 0x00c0,
+	0x21d2: 0x00c0, 0x21d3: 0x00c0, 0x21d4: 0x00c0, 0x21d5: 0x00c0, 0x21d6: 0x00c0, 0x21d7: 0x00c0,
+	0x21d8: 0x00c0, 0x21d9: 0x00c0, 0x21da: 0x00c0, 0x21db: 0x00c0, 0x21dc: 0x00c0, 0x21dd: 0x00c0,
+	0x21de: 0x00c0, 0x21df: 0x00c0, 0x21e0: 0x00c0, 0x21e1: 0x00c0, 0x21e2: 0x00c0, 0x21e3: 0x00c0,
+	0x21e4: 0x00c0, 0x21e5: 0x00c0, 0x21e6: 0x00c0, 0x21e7: 0x00c0, 0x21e8: 0x00c0, 0x21e9: 0x00c0,
+	0x21ea: 0x00c0, 0x21eb: 0x00c0, 0x21ec: 0x00c0, 0x21ed: 0x00c0, 0x21ee: 0x00c0, 0x21ef: 0x00c0,
+	0x21f1: 0x0080, 0x21f2: 0x0080, 0x21f3: 0x0080, 0x21f4: 0x0080, 0x21f5: 0x0080,
+	0x21f6: 0x0080, 0x21f7: 0x0080, 0x21f8: 0x0080, 0x21f9: 0x0080, 0x21fa: 0x0080, 0x21fb: 0x0080,
+	0x21fc: 0x0080, 0x21fd: 0x0080, 0x21fe: 0x0080, 0x21ff: 0x0080,
+	// Block 0x88, offset 0x2200
+	0x2200: 0x0080, 0x2201: 0x0080, 0x2202: 0x0080, 0x2203: 0x0080, 0x2204: 0x0080, 0x2205: 0x0080,
+	0x2206: 0x0080, 0x2207: 0x0080, 0x2208: 0x0080, 0x2209: 0x0080, 0x220a: 0x0080, 0x220b: 0x0080,
+	0x220c: 0x0080, 0x220d: 0x0080, 0x220e: 0x0080, 0x220f: 0x0080, 0x2210: 0x0080, 0x2211: 0x0080,
+	0x2212: 0x0080, 0x2213: 0x0080, 0x2214: 0x0080, 0x2215: 0x0080, 0x2216: 0x0080, 0x2217: 0x0080,
+	0x2218: 0x0080, 0x2219: 0x0080, 0x221a: 0x0080, 0x221b: 0x0080, 0x221c: 0x0080, 0x221d: 0x0080,
+	0x221e: 0x0080, 0x221f: 0x0080, 0x2220: 0x0080, 0x2221: 0x0080, 0x2222: 0x0080, 0x2223: 0x0080,
+	0x2224: 0x0040, 0x2225: 0x0080, 0x2226: 0x0080, 0x2227: 0x0080, 0x2228: 0x0080, 0x2229: 0x0080,
+	0x222a: 0x0080, 0x222b: 0x0080, 0x222c: 0x0080, 0x222d: 0x0080, 0x222e: 0x0080, 0x222f: 0x0080,
+	0x2230: 0x0080, 0x2231: 0x0080, 0x2232: 0x0080, 0x2233: 0x0080, 0x2234: 0x0080, 0x2235: 0x0080,
+	0x2236: 0x0080, 0x2237: 0x0080, 0x2238: 0x0080, 0x2239: 0x0080, 0x223a: 0x0080, 0x223b: 0x0080,
+	0x223c: 0x0080, 0x223d: 0x0080, 0x223e: 0x0080, 0x223f: 0x0080,
+	// Block 0x89, offset 0x2240
+	0x2240: 0x0080, 0x2241: 0x0080, 0x2242: 0x0080, 0x2243: 0x0080, 0x2244: 0x0080, 0x2245: 0x0080,
+	0x2246: 0x0080, 0x2247: 0x0080, 0x2248: 0x0080, 0x2249: 0x0080, 0x224a: 0x0080, 0x224b: 0x0080,
+	0x224c: 0x0080, 0x224d: 0x0080, 0x224e: 0x0080, 0x2250: 0x0080, 0x2251: 0x0080,
+	0x2252: 0x0080, 0x2253: 0x0080, 0x2254: 0x0080, 0x2255: 0x0080, 0x2256: 0x0080, 0x2257: 0x0080,
+	0x2258: 0x0080, 0x2259: 0x0080, 0x225a: 0x0080, 0x225b: 0x0080, 0x225c: 0x0080, 0x225d: 0x0080,
+	0x225e: 0x0080, 0x225f: 0x0080, 0x2260: 0x00c0, 0x2261: 0x00c0, 0x2262: 0x00c0, 0x2263: 0x00c0,
+	0x2264: 0x00c0, 0x2265: 0x00c0, 0x2266: 0x00c0, 0x2267: 0x00c0, 0x2268: 0x00c0, 0x2269: 0x00c0,
+	0x226a: 0x00c0, 0x226b: 0x00c0, 0x226c: 0x00c0, 0x226d: 0x00c0, 0x226e: 0x00c0, 0x226f: 0x00c0,
+	0x2270: 0x00c0, 0x2271: 0x00c0, 0x2272: 0x00c0, 0x2273: 0x00c0, 0x2274: 0x00c0, 0x2275: 0x00c0,
+	0x2276: 0x00c0, 0x2277: 0x00c0, 0x2278: 0x00c0, 0x2279: 0x00c0, 0x227a: 0x00c0, 0x227b: 0x00c0,
+	0x227c: 0x00c0, 0x227d: 0x00c0, 0x227e: 0x00c0, 0x227f: 0x00c0,
+	// Block 0x8a, offset 0x2280
+	0x2280: 0x0080, 0x2281: 0x0080, 0x2282: 0x0080, 0x2283: 0x0080, 0x2284: 0x0080, 0x2285: 0x0080,
+	0x2286: 0x0080, 0x2287: 0x0080, 0x2288: 0x0080, 0x2289: 0x0080, 0x228a: 0x0080, 0x228b: 0x0080,
+	0x228c: 0x0080, 0x228d: 0x0080, 0x228e: 0x0080, 0x228f: 0x0080, 0x2290: 0x0080, 0x2291: 0x0080,
+	0x2292: 0x0080, 0x2293: 0x0080, 0x2294: 0x0080, 0x2295: 0x0080, 0x2296: 0x0080, 0x2297: 0x0080,
+	0x2298: 0x0080, 0x2299: 0x0080, 0x229a: 0x0080, 0x229b: 0x0080, 0x229c: 0x0080, 0x229d: 0x0080,
+	0x229e: 0x0080, 0x229f: 0x0080, 0x22a0: 0x0080, 0x22a1: 0x0080, 0x22a2: 0x0080, 0x22a3: 0x0080,
+	0x22a4: 0x0080, 0x22a5: 0x0080,
+	0x22af: 0x0080,
+	0x22b0: 0x00cc, 0x22b1: 0x00cc, 0x22b2: 0x00cc, 0x22b3: 0x00cc, 0x22b4: 0x00cc, 0x22b5: 0x00cc,
+	0x22b6: 0x00cc, 0x22b7: 0x00cc, 0x22b8: 0x00cc, 0x22b9: 0x00cc, 0x22ba: 0x00cc, 0x22bb: 0x00cc,
+	0x22bc: 0x00cc, 0x22bd: 0x00cc, 0x22be: 0x00cc, 0x22bf: 0x00cc,
+	// Block 0x8b, offset 0x22c0
+	0x22c0: 0x0080, 0x22c1: 0x0080, 0x22c2: 0x0080, 0x22c3: 0x0080, 0x22c4: 0x0080, 0x22c5: 0x0080,
+	0x22c6: 0x0080, 0x22c7: 0x0080, 0x22c8: 0x0080, 0x22c9: 0x0080, 0x22ca: 0x0080, 0x22cb: 0x0080,
+	0x22cc: 0x0080, 0x22cd: 0x0080, 0x22ce: 0x0080, 0x22cf: 0x0080, 0x22d0: 0x0080, 0x22d1: 0x0080,
+	0x22d2: 0x0080, 0x22d3: 0x0080, 0x22d4: 0x0080, 0x22d5: 0x0080, 0x22d6: 0x0080, 0x22d7: 0x0080,
+	0x22d8: 0x0080, 0x22d9: 0x0080, 0x22da: 0x0080, 0x22db: 0x0080, 0x22dc: 0x0080, 0x22dd: 0x0080,
+	0x22de: 0x0080, 0x22e0: 0x0080, 0x22e1: 0x0080, 0x22e2: 0x0080, 0x22e3: 0x0080,
+	0x22e4: 0x0080, 0x22e5: 0x0080, 0x22e6: 0x0080, 0x22e7: 0x0080, 0x22e8: 0x0080, 0x22e9: 0x0080,
+	0x22ea: 0x0080, 0x22eb: 0x0080, 0x22ec: 0x0080, 0x22ed: 0x0080, 0x22ee: 0x0080, 0x22ef: 0x0080,
+	0x22f0: 0x0080, 0x22f1: 0x0080, 0x22f2: 0x0080, 0x22f3: 0x0080, 0x22f4: 0x0080, 0x22f5: 0x0080,
+	0x22f6: 0x0080, 0x22f7: 0x0080, 0x22f8: 0x0080, 0x22f9: 0x0080, 0x22fa: 0x0080, 0x22fb: 0x0080,
+	0x22fc: 0x0080, 0x22fd: 0x0080, 0x22fe: 0x0080, 0x22ff: 0x0080,
+	// Block 0x8c, offset 0x2300
+	0x2300: 0x0080, 0x2301: 0x0080, 0x2302: 0x0080, 0x2303: 0x0080, 0x2304: 0x0080, 0x2305: 0x0080,
+	0x2306: 0x0080, 0x2307: 0x0080, 0x2308: 0x0080, 0x2309: 0x0080, 0x230a: 0x0080, 0x230b: 0x0080,
+	0x230c: 0x0080, 0x230d: 0x0080, 0x230e: 0x0080, 0x230f: 0x0080, 0x2310: 0x008c, 0x2311: 0x008c,
+	0x2312: 0x008c, 0x2313: 0x008c, 0x2314: 0x008c, 0x2315: 0x008c, 0x2316: 0x008c, 0x2317: 0x008c,
+	0x2318: 0x008c, 0x2319: 0x008c, 0x231a: 0x008c, 0x231b: 0x008c, 0x231c: 0x008c, 0x231d: 0x008c,
+	0x231e: 0x008c, 0x231f: 0x008c, 0x2320: 0x008c, 0x2321: 0x008c, 0x2322: 0x008c, 0x2323: 0x008c,
+	0x2324: 0x008c, 0x2325: 0x008c, 0x2326: 0x008c, 0x2327: 0x008c, 0x2328: 0x008c, 0x2329: 0x008c,
+	0x232a: 0x008c, 0x232b: 0x008c, 0x232c: 0x008c, 0x232d: 0x008c, 0x232e: 0x008c, 0x232f: 0x008c,
+	0x2330: 0x008c, 0x2331: 0x008c, 0x2332: 0x008c, 0x2333: 0x008c, 0x2334: 0x008c, 0x2335: 0x008c,
+	0x2336: 0x008c, 0x2337: 0x008c, 0x2338: 0x008c, 0x2339: 0x008c, 0x233a: 0x008c, 0x233b: 0x008c,
+	0x233c: 0x008c, 0x233d: 0x008c, 0x233e: 0x008c, 0x233f: 0x0080,
+	// Block 0x8d, offset 0x2340
+	0x2340: 0x008c, 0x2341: 0x008c, 0x2342: 0x008c, 0x2343: 0x008c, 0x2344: 0x008c, 0x2345: 0x008c,
+	0x2346: 0x008c, 0x2347: 0x008c, 0x2348: 0x008c, 0x2349: 0x008c, 0x234a: 0x008c, 0x234b: 0x008c,
+	0x234c: 0x008c, 0x234d: 0x008c, 0x234e: 0x008c, 0x234f: 0x008c, 0x2350: 0x008c, 0x2351: 0x008c,
+	0x2352: 0x008c, 0x2353: 0x008c, 0x2354: 0x008c, 0x2355: 0x008c, 0x2356: 0x008c, 0x2357: 0x008c,
+	0x2358: 0x0080, 0x2359: 0x0080, 0x235a: 0x0080, 0x235b: 0x0080, 0x235c: 0x0080, 0x235d: 0x0080,
+	0x235e: 0x0080, 0x235f: 0x0080, 0x2360: 0x0080, 0x2361: 0x0080, 0x2362: 0x0080, 0x2363: 0x0080,
+	0x2364: 0x0080, 0x2365: 0x0080, 0x2366: 0x0080, 0x2367: 0x0080, 0x2368: 0x0080, 0x2369: 0x0080,
+	0x236a: 0x0080, 0x236b: 0x0080, 0x236c: 0x0080, 0x236d: 0x0080, 0x236e: 0x0080, 0x236f: 0x0080,
+	0x2370: 0x0080, 0x2371: 0x0080, 0x2372: 0x0080, 0x2373: 0x0080, 0x2374: 0x0080, 0x2375: 0x0080,
+	0x2376: 0x0080, 0x2377: 0x0080, 0x2378: 0x0080, 0x2379: 0x0080, 0x237a: 0x0080, 0x237b: 0x0080,
+	0x237c: 0x0080, 0x237d: 0x0080, 0x237e: 0x0080, 0x237f: 0x0080,
+	// Block 0x8e, offset 0x2380
+	0x2380: 0x00cc, 0x2381: 0x00cc, 0x2382: 0x00cc, 0x2383: 0x00cc, 0x2384: 0x00cc, 0x2385: 0x00cc,
+	0x2386: 0x00cc, 0x2387: 0x00cc, 0x2388: 0x00cc, 0x2389: 0x00cc, 0x238a: 0x00cc, 0x238b: 0x00cc,
+	0x238c: 0x00cc, 0x238d: 0x00cc, 0x238e: 0x00cc, 0x238f: 0x00cc, 0x2390: 0x00cc, 0x2391: 0x00cc,
+	0x2392: 0x00cc, 0x2393: 0x00cc, 0x2394: 0x00cc, 0x2395: 0x00cc, 0x2396: 0x00cc, 0x2397: 0x00cc,
+	0x2398: 0x00cc, 0x2399: 0x00cc, 0x239a: 0x00cc, 0x239b: 0x00cc, 0x239c: 0x00cc, 0x239d: 0x00cc,
+	0x239e: 0x00cc, 0x239f: 0x00cc, 0x23a0: 0x00cc, 0x23a1: 0x00cc, 0x23a2: 0x00cc, 0x23a3: 0x00cc,
+	0x23a4: 0x00cc, 0x23a5: 0x00cc, 0x23a6: 0x00cc, 0x23a7: 0x00cc, 0x23a8: 0x00cc, 0x23a9: 0x00cc,
+	0x23aa: 0x00cc, 0x23ab: 0x00cc, 0x23ac: 0x00cc, 0x23ad: 0x00cc, 0x23ae: 0x00cc, 0x23af: 0x00cc,
+	0x23b0: 0x00cc, 0x23b1: 0x00cc, 0x23b2: 0x00cc, 0x23b3: 0x00cc, 0x23b4: 0x00cc, 0x23b5: 0x00cc,
+	0x23b6: 0x00cc, 0x23b7: 0x00cc, 0x23b8: 0x00cc, 0x23b9: 0x00cc, 0x23ba: 0x00cc, 0x23bb: 0x00cc,
+	0x23bc: 0x00cc, 0x23bd: 0x00cc, 0x23be: 0x00cc, 0x23bf: 0x00cc,
+	// Block 0x8f, offset 0x23c0
+	0x23c0: 0x00c0, 0x23c1: 0x00c0, 0x23c2: 0x00c0, 0x23c3: 0x00c0, 0x23c4: 0x00c0, 0x23c5: 0x00c0,
+	0x23c6: 0x00c0, 0x23c7: 0x00c0, 0x23c8: 0x00c0, 0x23c9: 0x00c0, 0x23ca: 0x00c0, 0x23cb: 0x00c0,
+	0x23cc: 0x00c0, 0x23d0: 0x0080, 0x23d1: 0x0080,
+	0x23d2: 0x0080, 0x23d3: 0x0080, 0x23d4: 0x0080, 0x23d5: 0x0080, 0x23d6: 0x0080, 0x23d7: 0x0080,
+	0x23d8: 0x0080, 0x23d9: 0x0080, 0x23da: 0x0080, 0x23db: 0x0080, 0x23dc: 0x0080, 0x23dd: 0x0080,
+	0x23de: 0x0080, 0x23df: 0x0080, 0x23e0: 0x0080, 0x23e1: 0x0080, 0x23e2: 0x0080, 0x23e3: 0x0080,
+	0x23e4: 0x0080, 0x23e5: 0x0080, 0x23e6: 0x0080, 0x23e7: 0x0080, 0x23e8: 0x0080, 0x23e9: 0x0080,
+	0x23ea: 0x0080, 0x23eb: 0x0080, 0x23ec: 0x0080, 0x23ed: 0x0080, 0x23ee: 0x0080, 0x23ef: 0x0080,
+	0x23f0: 0x0080, 0x23f1: 0x0080, 0x23f2: 0x0080, 0x23f3: 0x0080, 0x23f4: 0x0080, 0x23f5: 0x0080,
+	0x23f6: 0x0080, 0x23f7: 0x0080, 0x23f8: 0x0080, 0x23f9: 0x0080, 0x23fa: 0x0080, 0x23fb: 0x0080,
+	0x23fc: 0x0080, 0x23fd: 0x0080, 0x23fe: 0x0080, 0x23ff: 0x0080,
+	// Block 0x90, offset 0x2400
+	0x2400: 0x0080, 0x2401: 0x0080, 0x2402: 0x0080, 0x2403: 0x0080, 0x2404: 0x0080, 0x2405: 0x0080,
+	0x2406: 0x0080,
+	0x2410: 0x00c0, 0x2411: 0x00c0,
+	0x2412: 0x00c0, 0x2413: 0x00c0, 0x2414: 0x00c0, 0x2415: 0x00c0, 0x2416: 0x00c0, 0x2417: 0x00c0,
+	0x2418: 0x00c0, 0x2419: 0x00c0, 0x241a: 0x00c0, 0x241b: 0x00c0, 0x241c: 0x00c0, 0x241d: 0x00c0,
+	0x241e: 0x00c0, 0x241f: 0x00c0, 0x2420: 0x00c0, 0x2421: 0x00c0, 0x2422: 0x00c0, 0x2423: 0x00c0,
+	0x2424: 0x00c0, 0x2425: 0x00c0, 0x2426: 0x00c0, 0x2427: 0x00c0, 0x2428: 0x00c0, 0x2429: 0x00c0,
+	0x242a: 0x00c0, 0x242b: 0x00c0, 0x242c: 0x00c0, 0x242d: 0x00c0, 0x242e: 0x00c0, 0x242f: 0x00c0,
+	0x2430: 0x00c0, 0x2431: 0x00c0, 0x2432: 0x00c0, 0x2433: 0x00c0, 0x2434: 0x00c0, 0x2435: 0x00c0,
+	0x2436: 0x00c0, 0x2437: 0x00c0, 0x2438: 0x00c0, 0x2439: 0x00c0, 0x243a: 0x00c0, 0x243b: 0x00c0,
+	0x243c: 0x00c0, 0x243d: 0x00c0, 0x243e: 0x0080, 0x243f: 0x0080,
+	// Block 0x91, offset 0x2440
+	0x2440: 0x00c0, 0x2441: 0x00c0, 0x2442: 0x00c0, 0x2443: 0x00c0, 0x2444: 0x00c0, 0x2445: 0x00c0,
+	0x2446: 0x00c0, 0x2447: 0x00c0, 0x2448: 0x00c0, 0x2449: 0x00c0, 0x244a: 0x00c0, 0x244b: 0x00c0,
+	0x244c: 0x00c0, 0x244d: 0x0080, 0x244e: 0x0080, 0x244f: 0x0080, 0x2450: 0x00c0, 0x2451: 0x00c0,
+	0x2452: 0x00c0, 0x2453: 0x00c0, 0x2454: 0x00c0, 0x2455: 0x00c0, 0x2456: 0x00c0, 0x2457: 0x00c0,
+	0x2458: 0x00c0, 0x2459: 0x00c0, 0x245a: 0x00c0, 0x245b: 0x00c0, 0x245c: 0x00c0, 0x245d: 0x00c0,
+	0x245e: 0x00c0, 0x245f: 0x00c0, 0x2460: 0x00c0, 0x2461: 0x00c0, 0x2462: 0x00c0, 0x2463: 0x00c0,
+	0x2464: 0x00c0, 0x2465: 0x00c0, 0x2466: 0x00c0, 0x2467: 0x00c0, 0x2468: 0x00c0, 0x2469: 0x00c0,
+	0x246a: 0x00c0, 0x246b: 0x00c0,
+	// Block 0x92, offset 0x2480
+	0x2480: 0x00c0, 0x2481: 0x00c0, 0x2482: 0x00c0, 0x2483: 0x00c0, 0x2484: 0x00c0, 0x2485: 0x00c0,
+	0x2486: 0x00c0, 0x2487: 0x00c0, 0x2488: 0x00c0, 0x2489: 0x00c0, 0x248a: 0x00c0, 0x248b: 0x00c0,
+	0x248c: 0x00c0, 0x248d: 0x00c0, 0x248e: 0x00c0, 0x248f: 0x00c0, 0x2490: 0x00c0, 0x2491: 0x00c0,
+	0x2492: 0x00c0, 0x2493: 0x00c0, 0x2494: 0x00c0, 0x2495: 0x00c0, 0x2496: 0x00c0, 0x2497: 0x00c0,
+	0x2498: 0x00c0, 0x2499: 0x00c0, 0x249a: 0x00c0, 0x249b: 0x00c0, 0x249c: 0x00c0, 0x249d: 0x00c0,
+	0x249e: 0x00c0, 0x249f: 0x00c0, 0x24a0: 0x00c0, 0x24a1: 0x00c0, 0x24a2: 0x00c0, 0x24a3: 0x00c0,
+	0x24a4: 0x00c0, 0x24a5: 0x00c0, 0x24a6: 0x00c0, 0x24a7: 0x00c0, 0x24a8: 0x00c0, 0x24a9: 0x00c0,
+	0x24aa: 0x00c0, 0x24ab: 0x00c0, 0x24ac: 0x00c0, 0x24ad: 0x00c0, 0x24ae: 0x00c0, 0x24af: 0x00c3,
+	0x24b0: 0x0083, 0x24b1: 0x0083, 0x24b2: 0x0083, 0x24b3: 0x0080, 0x24b4: 0x00c3, 0x24b5: 0x00c3,
+	0x24b6: 0x00c3, 0x24b7: 0x00c3, 0x24b8: 0x00c3, 0x24b9: 0x00c3, 0x24ba: 0x00c3, 0x24bb: 0x00c3,
+	0x24bc: 0x00c3, 0x24bd: 0x00c3, 0x24be: 0x0080, 0x24bf: 0x00c0,
+	// Block 0x93, offset 0x24c0
+	0x24c0: 0x00c0, 0x24c1: 0x00c0, 0x24c2: 0x00c0, 0x24c3: 0x00c0, 0x24c4: 0x00c0, 0x24c5: 0x00c0,
+	0x24c6: 0x00c0, 0x24c7: 0x00c0, 0x24c8: 0x00c0, 0x24c9: 0x00c0, 0x24ca: 0x00c0, 0x24cb: 0x00c0,
+	0x24cc: 0x00c0, 0x24cd: 0x00c0, 0x24ce: 0x00c0, 0x24cf: 0x00c0, 0x24d0: 0x00c0, 0x24d1: 0x00c0,
+	0x24d2: 0x00c0, 0x24d3: 0x00c0, 0x24d4: 0x00c0, 0x24d5: 0x00c0, 0x24d6: 0x00c0, 0x24d7: 0x00c0,
+	0x24d8: 0x00c0, 0x24d9: 0x00c0, 0x24da: 0x00c0, 0x24db: 0x00c0, 0x24dc: 0x0080, 0x24dd: 0x0080,
+	0x24de: 0x00c3, 0x24df: 0x00c3, 0x24e0: 0x00c0, 0x24e1: 0x00c0, 0x24e2: 0x00c0, 0x24e3: 0x00c0,
+	0x24e4: 0x00c0, 0x24e5: 0x00c0, 0x24e6: 0x00c0, 0x24e7: 0x00c0, 0x24e8: 0x00c0, 0x24e9: 0x00c0,
+	0x24ea: 0x00c0, 0x24eb: 0x00c0, 0x24ec: 0x00c0, 0x24ed: 0x00c0, 0x24ee: 0x00c0, 0x24ef: 0x00c0,
+	0x24f0: 0x00c0, 0x24f1: 0x00c0, 0x24f2: 0x00c0, 0x24f3: 0x00c0, 0x24f4: 0x00c0, 0x24f5: 0x00c0,
+	0x24f6: 0x00c0, 0x24f7: 0x00c0, 0x24f8: 0x00c0, 0x24f9: 0x00c0, 0x24fa: 0x00c0, 0x24fb: 0x00c0,
+	0x24fc: 0x00c0, 0x24fd: 0x00c0, 0x24fe: 0x00c0, 0x24ff: 0x00c0,
+	// Block 0x94, offset 0x2500
+	0x2500: 0x00c0, 0x2501: 0x00c0, 0x2502: 0x00c0, 0x2503: 0x00c0, 0x2504: 0x00c0, 0x2505: 0x00c0,
+	0x2506: 0x00c0, 0x2507: 0x00c0, 0x2508: 0x00c0, 0x2509: 0x00c0, 0x250a: 0x00c0, 0x250b: 0x00c0,
+	0x250c: 0x00c0, 0x250d: 0x00c0, 0x250e: 0x00c0, 0x250f: 0x00c0, 0x2510: 0x00c0, 0x2511: 0x00c0,
+	0x2512: 0x00c0, 0x2513: 0x00c0, 0x2514: 0x00c0, 0x2515: 0x00c0, 0x2516: 0x00c0, 0x2517: 0x00c0,
+	0x2518: 0x00c0, 0x2519: 0x00c0, 0x251a: 0x00c0, 0x251b: 0x00c0, 0x251c: 0x00c0, 0x251d: 0x00c0,
+	0x251e: 0x00c0, 0x251f: 0x00c0, 0x2520: 0x00c0, 0x2521: 0x00c0, 0x2522: 0x00c0, 0x2523: 0x00c0,
+	0x2524: 0x00c0, 0x2525: 0x00c0, 0x2526: 0x0080, 0x2527: 0x0080, 0x2528: 0x0080, 0x2529: 0x0080,
+	0x252a: 0x0080, 0x252b: 0x0080, 0x252c: 0x0080, 0x252d: 0x0080, 0x252e: 0x0080, 0x252f: 0x0080,
+	0x2530: 0x00c3, 0x2531: 0x00c3, 0x2532: 0x0080, 0x2533: 0x0080, 0x2534: 0x0080, 0x2535: 0x0080,
+	0x2536: 0x0080, 0x2537: 0x0080,
+	// Block 0x95, offset 0x2540
+	0x2540: 0x0080, 0x2541: 0x0080, 0x2542: 0x0080, 0x2543: 0x0080, 0x2544: 0x0080, 0x2545: 0x0080,
+	0x2546: 0x0080, 0x2547: 0x0080, 0x2548: 0x0080, 0x2549: 0x0080, 0x254a: 0x0080, 0x254b: 0x0080,
+	0x254c: 0x0080, 0x254d: 0x0080, 0x254e: 0x0080, 0x254f: 0x0080, 0x2550: 0x0080, 0x2551: 0x0080,
+	0x2552: 0x0080, 0x2553: 0x0080, 0x2554: 0x0080, 0x2555: 0x0080, 0x2556: 0x0080, 0x2557: 0x00c0,
+	0x2558: 0x00c0, 0x2559: 0x00c0, 0x255a: 0x00c0, 0x255b: 0x00c0, 0x255c: 0x00c0, 0x255d: 0x00c0,
+	0x255e: 0x00c0, 0x255f: 0x00c0, 0x2560: 0x0080, 0x2561: 0x0080, 0x2562: 0x00c0, 0x2563: 0x00c0,
+	0x2564: 0x00c0, 0x2565: 0x00c0, 0x2566: 0x00c0, 0x2567: 0x00c0, 0x2568: 0x00c0, 0x2569: 0x00c0,
+	0x256a: 0x00c0, 0x256b: 0x00c0, 0x256c: 0x00c0, 0x256d: 0x00c0, 0x256e: 0x00c0, 0x256f: 0x00c0,
+	0x2570: 0x00c0, 0x2571: 0x00c0, 0x2572: 0x00c0, 0x2573: 0x00c0, 0x2574: 0x00c0, 0x2575: 0x00c0,
+	0x2576: 0x00c0, 0x2577: 0x00c0, 0x2578: 0x00c0, 0x2579: 0x00c0, 0x257a: 0x00c0, 0x257b: 0x00c0,
+	0x257c: 0x00c0, 0x257d: 0x00c0, 0x257e: 0x00c0, 0x257f: 0x00c0,
+	// Block 0x96, offset 0x2580
+	0x2580: 0x00c0, 0x2581: 0x00c0, 0x2582: 0x00c0, 0x2583: 0x00c0, 0x2584: 0x00c0, 0x2585: 0x00c0,
+	0x2586: 0x00c0, 0x2587: 0x00c0, 0x2588: 0x00c0, 0x2589: 0x00c0, 0x258a: 0x00c0, 0x258b: 0x00c0,
+	0x258c: 0x00c0, 0x258d: 0x00c0, 0x258e: 0x00c0, 0x258f: 0x00c0, 0x2590: 0x00c0, 0x2591: 0x00c0,
+	0x2592: 0x00c0, 0x2593: 0x00c0, 0x2594: 0x00c0, 0x2595: 0x00c0, 0x2596: 0x00c0, 0x2597: 0x00c0,
+	0x2598: 0x00c0, 0x2599: 0x00c0, 0x259a: 0x00c0, 0x259b: 0x00c0, 0x259c: 0x00c0, 0x259d: 0x00c0,
+	0x259e: 0x00c0, 0x259f: 0x00c0, 0x25a0: 0x00c0, 0x25a1: 0x00c0, 0x25a2: 0x00c0, 0x25a3: 0x00c0,
+	0x25a4: 0x00c0, 0x25a5: 0x00c0, 0x25a6: 0x00c0, 0x25a7: 0x00c0, 0x25a8: 0x00c0, 0x25a9: 0x00c0,
+	0x25aa: 0x00c0, 0x25ab: 0x00c0, 0x25ac: 0x00c0, 0x25ad: 0x00c0, 0x25ae: 0x00c0, 0x25af: 0x00c0,
+	0x25b0: 0x0080, 0x25b1: 0x00c0, 0x25b2: 0x00c0, 0x25b3: 0x00c0, 0x25b4: 0x00c0, 0x25b5: 0x00c0,
+	0x25b6: 0x00c0, 0x25b7: 0x00c0, 0x25b8: 0x00c0, 0x25b9: 0x00c0, 0x25ba: 0x00c0, 0x25bb: 0x00c0,
+	0x25bc: 0x00c0, 0x25bd: 0x00c0, 0x25be: 0x00c0, 0x25bf: 0x00c0,
+	// Block 0x97, offset 0x25c0
+	0x25c0: 0x00c0, 0x25c1: 0x00c0, 0x25c2: 0x00c0, 0x25c3: 0x00c0, 0x25c4: 0x00c0, 0x25c5: 0x00c0,
+	0x25c6: 0x00c0, 0x25c7: 0x00c0, 0x25c8: 0x00c0, 0x25c9: 0x0080, 0x25ca: 0x0080, 0x25cb: 0x00c0,
+	0x25cc: 0x00c0, 0x25cd: 0x00c0, 0x25ce: 0x00c0, 0x25cf: 0x00c0, 0x25d0: 0x00c0, 0x25d1: 0x00c0,
+	0x25d2: 0x00c0, 0x25d3: 0x00c0, 0x25d4: 0x00c0, 0x25d5: 0x00c0, 0x25d6: 0x00c0, 0x25d7: 0x00c0,
+	0x25d8: 0x00c0, 0x25d9: 0x00c0, 0x25da: 0x00c0, 0x25db: 0x00c0, 0x25dc: 0x00c0, 0x25dd: 0x00c0,
+	0x25de: 0x00c0, 0x25df: 0x00c0, 0x25e0: 0x00c0, 0x25e1: 0x00c0, 0x25e2: 0x00c0, 0x25e3: 0x00c0,
+	0x25e4: 0x00c0, 0x25e5: 0x00c0, 0x25e6: 0x00c0, 0x25e7: 0x00c0, 0x25e8: 0x00c0, 0x25e9: 0x00c0,
+	0x25ea: 0x00c0, 0x25eb: 0x00c0, 0x25ec: 0x00c0, 0x25ed: 0x00c0, 0x25ee: 0x00c0, 0x25ef: 0x00c0,
+	0x25f0: 0x00c0, 0x25f1: 0x00c0, 0x25f2: 0x00c0, 0x25f3: 0x00c0, 0x25f4: 0x00c0, 0x25f5: 0x00c0,
+	0x25f6: 0x00c0, 0x25f7: 0x00c0, 0x25f8: 0x00c0, 0x25f9: 0x00c0, 0x25fa: 0x00c0, 0x25fb: 0x00c0,
+	0x25fc: 0x00c0, 0x25fd: 0x00c0, 0x25fe: 0x00c0, 0x25ff: 0x00c0,
+	// Block 0x98, offset 0x2600
+	0x2600: 0x00c0, 0x2601: 0x00c0, 0x2602: 0x00c0, 0x2603: 0x00c0, 0x2604: 0x00c0, 0x2605: 0x00c0,
+	0x2606: 0x00c0, 0x2607: 0x00c0, 0x2608: 0x00c0, 0x2609: 0x00c0, 0x260a: 0x00c0, 0x260b: 0x00c0,
+	0x260c: 0x00c0, 0x260d: 0x00c0, 0x260e: 0x00c0, 0x260f: 0x00c0, 0x2610: 0x00c0, 0x2611: 0x00c0,
+	0x2612: 0x00c0, 0x2613: 0x00c0, 0x2614: 0x00c0, 0x2615: 0x00c0, 0x2616: 0x00c0, 0x2617: 0x00c0,
+	0x2618: 0x00c0, 0x2619: 0x00c0, 0x261a: 0x00c0, 0x261b: 0x00c0, 0x261c: 0x00c0,
+	0x2631: 0x0080, 0x2632: 0x0080, 0x2633: 0x0080, 0x2634: 0x0080, 0x2635: 0x00c0,
+	0x2636: 0x00c0, 0x2637: 0x00c0, 0x2638: 0x0080, 0x2639: 0x0080, 0x263a: 0x00c0, 0x263b: 0x00c0,
+	0x263c: 0x00c0, 0x263d: 0x00c0, 0x263e: 0x00c0, 0x263f: 0x00c0,
+	// Block 0x99, offset 0x2640
+	0x2640: 0x00c0, 0x2641: 0x00c0, 0x2642: 0x00c3, 0x2643: 0x00c0, 0x2644: 0x00c0, 0x2645: 0x00c0,
+	0x2646: 0x00c6, 0x2647: 0x00c0, 0x2648: 0x00c0, 0x2649: 0x00c0, 0x264a: 0x00c0, 0x264b: 0x00c3,
+	0x264c: 0x00c0, 0x264d: 0x00c0, 0x264e: 0x00c0, 0x264f: 0x00c0, 0x2650: 0x00c0, 0x2651: 0x00c0,
+	0x2652: 0x00c0, 0x2653: 0x00c0, 0x2654: 0x00c0, 0x2655: 0x00c0, 0x2656: 0x00c0, 0x2657: 0x00c0,
+	0x2658: 0x00c0, 0x2659: 0x00c0, 0x265a: 0x00c0, 0x265b: 0x00c0, 0x265c: 0x00c0, 0x265d: 0x00c0,
+	0x265e: 0x00c0, 0x265f: 0x00c0, 0x2660: 0x00c0, 0x2661: 0x00c0, 0x2662: 0x00c0, 0x2663: 0x00c0,
+	0x2664: 0x00c0, 0x2665: 0x00c3, 0x2666: 0x00c3, 0x2667: 0x00c0, 0x2668: 0x0080, 0x2669: 0x0080,
+	0x266a: 0x0080, 0x266b: 0x0080, 0x266c: 0x00c6,
+	0x2670: 0x0080, 0x2671: 0x0080, 0x2672: 0x0080, 0x2673: 0x0080, 0x2674: 0x0080, 0x2675: 0x0080,
+	0x2676: 0x0080, 0x2677: 0x0080, 0x2678: 0x0080, 0x2679: 0x0080,
+	// Block 0x9a, offset 0x2680
+	0x2680: 0x00c2, 0x2681: 0x00c2, 0x2682: 0x00c2, 0x2683: 0x00c2, 0x2684: 0x00c2, 0x2685: 0x00c2,
+	0x2686: 0x00c2, 0x2687: 0x00c2, 0x2688: 0x00c2, 0x2689: 0x00c2, 0x268a: 0x00c2, 0x268b: 0x00c2,
+	0x268c: 0x00c2, 0x268d: 0x00c2, 0x268e: 0x00c2, 0x268f: 0x00c2, 0x2690: 0x00c2, 0x2691: 0x00c2,
+	0x2692: 0x00c2, 0x2693: 0x00c2, 0x2694: 0x00c2, 0x2695: 0x00c2, 0x2696: 0x00c2, 0x2697: 0x00c2,
+	0x2698: 0x00c2, 0x2699: 0x00c2, 0x269a: 0x00c2, 0x269b: 0x00c2, 0x269c: 0x00c2, 0x269d: 0x00c2,
+	0x269e: 0x00c2, 0x269f: 0x00c2, 0x26a0: 0x00c2, 0x26a1: 0x00c2, 0x26a2: 0x00c2, 0x26a3: 0x00c2,
+	0x26a4: 0x00c2, 0x26a5: 0x00c2, 0x26a6: 0x00c2, 0x26a7: 0x00c2, 0x26a8: 0x00c2, 0x26a9: 0x00c2,
+	0x26aa: 0x00c2, 0x26ab: 0x00c2, 0x26ac: 0x00c2, 0x26ad: 0x00c2, 0x26ae: 0x00c2, 0x26af: 0x00c2,
+	0x26b0: 0x00c2, 0x26b1: 0x00c2, 0x26b2: 0x00c1, 0x26b3: 0x00c0, 0x26b4: 0x0080, 0x26b5: 0x0080,
+	0x26b6: 0x0080, 0x26b7: 0x0080,
+	// Block 0x9b, offset 0x26c0
+	0x26c0: 0x00c0, 0x26c1: 0x00c0, 0x26c2: 0x00c0, 0x26c3: 0x00c0, 0x26c4: 0x00c6, 0x26c5: 0x00c3,
+	0x26ce: 0x0080, 0x26cf: 0x0080, 0x26d0: 0x00c0, 0x26d1: 0x00c0,
+	0x26d2: 0x00c0, 0x26d3: 0x00c0, 0x26d4: 0x00c0, 0x26d5: 0x00c0, 0x26d6: 0x00c0, 0x26d7: 0x00c0,
+	0x26d8: 0x00c0, 0x26d9: 0x00c0,
+	0x26e0: 0x00c3, 0x26e1: 0x00c3, 0x26e2: 0x00c3, 0x26e3: 0x00c3,
+	0x26e4: 0x00c3, 0x26e5: 0x00c3, 0x26e6: 0x00c3, 0x26e7: 0x00c3, 0x26e8: 0x00c3, 0x26e9: 0x00c3,
+	0x26ea: 0x00c3, 0x26eb: 0x00c3, 0x26ec: 0x00c3, 0x26ed: 0x00c3, 0x26ee: 0x00c3, 0x26ef: 0x00c3,
+	0x26f0: 0x00c3, 0x26f1: 0x00c3, 0x26f2: 0x00c0, 0x26f3: 0x00c0, 0x26f4: 0x00c0, 0x26f5: 0x00c0,
+	0x26f6: 0x00c0, 0x26f7: 0x00c0, 0x26f8: 0x0080, 0x26f9: 0x0080, 0x26fa: 0x0080, 0x26fb: 0x00c0,
+	0x26fc: 0x0080, 0x26fd: 0x00c0, 0x26fe: 0x00c0, 0x26ff: 0x00c3,
+	// Block 0x9c, offset 0x2700
+	0x2700: 0x00c0, 0x2701: 0x00c0, 0x2702: 0x00c0, 0x2703: 0x00c0, 0x2704: 0x00c0, 0x2705: 0x00c0,
+	0x2706: 0x00c0, 0x2707: 0x00c0, 0x2708: 0x00c0, 0x2709: 0x00c0, 0x270a: 0x00c0, 0x270b: 0x00c0,
+	0x270c: 0x00c0, 0x270d: 0x00c0, 0x270e: 0x00c0, 0x270f: 0x00c0, 0x2710: 0x00c0, 0x2711: 0x00c0,
+	0x2712: 0x00c0, 0x2713: 0x00c0, 0x2714: 0x00c0, 0x2715: 0x00c0, 0x2716: 0x00c0, 0x2717: 0x00c0,
+	0x2718: 0x00c0, 0x2719: 0x00c0, 0x271a: 0x00c0, 0x271b: 0x00c0, 0x271c: 0x00c0, 0x271d: 0x00c0,
+	0x271e: 0x00c0, 0x271f: 0x00c0, 0x2720: 0x00c0, 0x2721: 0x00c0, 0x2722: 0x00c0, 0x2723: 0x00c0,
+	0x2724: 0x00c0, 0x2725: 0x00c0, 0x2726: 0x00c3, 0x2727: 0x00c3, 0x2728: 0x00c3, 0x2729: 0x00c3,
+	0x272a: 0x00c3, 0x272b: 0x00c3, 0x272c: 0x00c3, 0x272d: 0x00c3, 0x272e: 0x0080, 0x272f: 0x0080,
+	0x2730: 0x00c0, 0x2731: 0x00c0, 0x2732: 0x00c0, 0x2733: 0x00c0, 0x2734: 0x00c0, 0x2735: 0x00c0,
+	0x2736: 0x00c0, 0x2737: 0x00c0, 0x2738: 0x00c0, 0x2739: 0x00c0, 0x273a: 0x00c0, 0x273b: 0x00c0,
+	0x273c: 0x00c0, 0x273d: 0x00c0, 0x273e: 0x00c0, 0x273f: 0x00c0,
+	// Block 0x9d, offset 0x2740
+	0x2740: 0x00c0, 0x2741: 0x00c0, 0x2742: 0x00c0, 0x2743: 0x00c0, 0x2744: 0x00c0, 0x2745: 0x00c0,
+	0x2746: 0x00c0, 0x2747: 0x00c3, 0x2748: 0x00c3, 0x2749: 0x00c3, 0x274a: 0x00c3, 0x274b: 0x00c3,
+	0x274c: 0x00c3, 0x274d: 0x00c3, 0x274e: 0x00c3, 0x274f: 0x00c3, 0x2750: 0x00c3, 0x2751: 0x00c3,
+	0x2752: 0x00c0, 0x2753: 0x00c5,
+	0x275f: 0x0080, 0x2760: 0x0040, 0x2761: 0x0040, 0x2762: 0x0040, 0x2763: 0x0040,
+	0x2764: 0x0040, 0x2765: 0x0040, 0x2766: 0x0040, 0x2767: 0x0040, 0x2768: 0x0040, 0x2769: 0x0040,
+	0x276a: 0x0040, 0x276b: 0x0040, 0x276c: 0x0040, 0x276d: 0x0040, 0x276e: 0x0040, 0x276f: 0x0040,
+	0x2770: 0x0040, 0x2771: 0x0040, 0x2772: 0x0040, 0x2773: 0x0040, 0x2774: 0x0040, 0x2775: 0x0040,
+	0x2776: 0x0040, 0x2777: 0x0040, 0x2778: 0x0040, 0x2779: 0x0040, 0x277a: 0x0040, 0x277b: 0x0040,
+	0x277c: 0x0040,
+	// Block 0x9e, offset 0x2780
+	0x2780: 0x00c3, 0x2781: 0x00c3, 0x2782: 0x00c3, 0x2783: 0x00c0, 0x2784: 0x00c0, 0x2785: 0x00c0,
+	0x2786: 0x00c0, 0x2787: 0x00c0, 0x2788: 0x00c0, 0x2789: 0x00c0, 0x278a: 0x00c0, 0x278b: 0x00c0,
+	0x278c: 0x00c0, 0x278d: 0x00c0, 0x278e: 0x00c0, 0x278f: 0x00c0, 0x2790: 0x00c0, 0x2791: 0x00c0,
+	0x2792: 0x00c0, 0x2793: 0x00c0, 0x2794: 0x00c0, 0x2795: 0x00c0, 0x2796: 0x00c0, 0x2797: 0x00c0,
+	0x2798: 0x00c0, 0x2799: 0x00c0, 0x279a: 0x00c0, 0x279b: 0x00c0, 0x279c: 0x00c0, 0x279d: 0x00c0,
+	0x279e: 0x00c0, 0x279f: 0x00c0, 0x27a0: 0x00c0, 0x27a1: 0x00c0, 0x27a2: 0x00c0, 0x27a3: 0x00c0,
+	0x27a4: 0x00c0, 0x27a5: 0x00c0, 0x27a6: 0x00c0, 0x27a7: 0x00c0, 0x27a8: 0x00c0, 0x27a9: 0x00c0,
+	0x27aa: 0x00c0, 0x27ab: 0x00c0, 0x27ac: 0x00c0, 0x27ad: 0x00c0, 0x27ae: 0x00c0, 0x27af: 0x00c0,
+	0x27b0: 0x00c0, 0x27b1: 0x00c0, 0x27b2: 0x00c0, 0x27b3: 0x00c3, 0x27b4: 0x00c0, 0x27b5: 0x00c0,
+	0x27b6: 0x00c3, 0x27b7: 0x00c3, 0x27b8: 0x00c3, 0x27b9: 0x00c3, 0x27ba: 0x00c0, 0x27bb: 0x00c0,
+	0x27bc: 0x00c3, 0x27bd: 0x00c3, 0x27be: 0x00c0, 0x27bf: 0x00c0,
+	// Block 0x9f, offset 0x27c0
+	0x27c0: 0x00c5, 0x27c1: 0x0080, 0x27c2: 0x0080, 0x27c3: 0x0080, 0x27c4: 0x0080, 0x27c5: 0x0080,
+	0x27c6: 0x0080, 0x27c7: 0x0080, 0x27c8: 0x0080, 0x27c9: 0x0080, 0x27ca: 0x0080, 0x27cb: 0x0080,
+	0x27cc: 0x0080, 0x27cd: 0x0080, 0x27cf: 0x00c0, 0x27d0: 0x00c0, 0x27d1: 0x00c0,
+	0x27d2: 0x00c0, 0x27d3: 0x00c0, 0x27d4: 0x00c0, 0x27d5: 0x00c0, 0x27d6: 0x00c0, 0x27d7: 0x00c0,
+	0x27d8: 0x00c0, 0x27d9: 0x00c0,
+	0x27de: 0x0080, 0x27df: 0x0080, 0x27e0: 0x00c0, 0x27e1: 0x00c0, 0x27e2: 0x00c0, 0x27e3: 0x00c0,
+	0x27e4: 0x00c0, 0x27e5: 0x00c3, 0x27e6: 0x00c0, 0x27e7: 0x00c0, 0x27e8: 0x00c0, 0x27e9: 0x00c0,
+	0x27ea: 0x00c0, 0x27eb: 0x00c0, 0x27ec: 0x00c0, 0x27ed: 0x00c0, 0x27ee: 0x00c0, 0x27ef: 0x00c0,
+	0x27f0: 0x00c0, 0x27f1: 0x00c0, 0x27f2: 0x00c0, 0x27f3: 0x00c0, 0x27f4: 0x00c0, 0x27f5: 0x00c0,
+	0x27f6: 0x00c0, 0x27f7: 0x00c0, 0x27f8: 0x00c0, 0x27f9: 0x00c0, 0x27fa: 0x00c0, 0x27fb: 0x00c0,
+	0x27fc: 0x00c0, 0x27fd: 0x00c0, 0x27fe: 0x00c0,
+	// Block 0xa0, offset 0x2800
+	0x2800: 0x00c0, 0x2801: 0x00c0, 0x2802: 0x00c0, 0x2803: 0x00c0, 0x2804: 0x00c0, 0x2805: 0x00c0,
+	0x2806: 0x00c0, 0x2807: 0x00c0, 0x2808: 0x00c0, 0x2809: 0x00c0, 0x280a: 0x00c0, 0x280b: 0x00c0,
+	0x280c: 0x00c0, 0x280d: 0x00c0, 0x280e: 0x00c0, 0x280f: 0x00c0, 0x2810: 0x00c0, 0x2811: 0x00c0,
+	0x2812: 0x00c0, 0x2813: 0x00c0, 0x2814: 0x00c0, 0x2815: 0x00c0, 0x2816: 0x00c0, 0x2817: 0x00c0,
+	0x2818: 0x00c0, 0x2819: 0x00c0, 0x281a: 0x00c0, 0x281b: 0x00c0, 0x281c: 0x00c0, 0x281d: 0x00c0,
+	0x281e: 0x00c0, 0x281f: 0x00c0, 0x2820: 0x00c0, 0x2821: 0x00c0, 0x2822: 0x00c0, 0x2823: 0x00c0,
+	0x2824: 0x00c0, 0x2825: 0x00c0, 0x2826: 0x00c0, 0x2827: 0x00c0, 0x2828: 0x00c0, 0x2829: 0x00c3,
+	0x282a: 0x00c3, 0x282b: 0x00c3, 0x282c: 0x00c3, 0x282d: 0x00c3, 0x282e: 0x00c3, 0x282f: 0x00c0,
+	0x2830: 0x00c0, 0x2831: 0x00c3, 0x2832: 0x00c3, 0x2833: 0x00c0, 0x2834: 0x00c0, 0x2835: 0x00c3,
+	0x2836: 0x00c3,
+	// Block 0xa1, offset 0x2840
+	0x2840: 0x00c0, 0x2841: 0x00c0, 0x2842: 0x00c0, 0x2843: 0x00c3, 0x2844: 0x00c0, 0x2845: 0x00c0,
+	0x2846: 0x00c0, 0x2847: 0x00c0, 0x2848: 0x00c0, 0x2849: 0x00c0, 0x284a: 0x00c0, 0x284b: 0x00c0,
+	0x284c: 0x00c3, 0x284d: 0x00c0, 0x2850: 0x00c0, 0x2851: 0x00c0,
+	0x2852: 0x00c0, 0x2853: 0x00c0, 0x2854: 0x00c0, 0x2855: 0x00c0, 0x2856: 0x00c0, 0x2857: 0x00c0,
+	0x2858: 0x00c0, 0x2859: 0x00c0, 0x285c: 0x0080, 0x285d: 0x0080,
+	0x285e: 0x0080, 0x285f: 0x0080, 0x2860: 0x00c0, 0x2861: 0x00c0, 0x2862: 0x00c0, 0x2863: 0x00c0,
+	0x2864: 0x00c0, 0x2865: 0x00c0, 0x2866: 0x00c0, 0x2867: 0x00c0, 0x2868: 0x00c0, 0x2869: 0x00c0,
+	0x286a: 0x00c0, 0x286b: 0x00c0, 0x286c: 0x00c0, 0x286d: 0x00c0, 0x286e: 0x00c0, 0x286f: 0x00c0,
+	0x2870: 0x00c0, 0x2871: 0x00c0, 0x2872: 0x00c0, 0x2873: 0x00c0, 0x2874: 0x00c0, 0x2875: 0x00c0,
+	0x2876: 0x00c0, 0x2877: 0x0080, 0x2878: 0x0080, 0x2879: 0x0080, 0x287a: 0x00c0, 0x287b: 0x00c0,
+	0x287c: 0x00c3, 0x287d: 0x00c0, 0x287e: 0x00c0, 0x287f: 0x00c0,
+	// Block 0xa2, offset 0x2880
+	0x2880: 0x00c0, 0x2881: 0x00c0, 0x2882: 0x00c0, 0x2883: 0x00c0, 0x2884: 0x00c0, 0x2885: 0x00c0,
+	0x2886: 0x00c0, 0x2887: 0x00c0, 0x2888: 0x00c0, 0x2889: 0x00c0, 0x288a: 0x00c0, 0x288b: 0x00c0,
+	0x288c: 0x00c0, 0x288d: 0x00c0, 0x288e: 0x00c0, 0x288f: 0x00c0, 0x2890: 0x00c0, 0x2891: 0x00c0,
+	0x2892: 0x00c0, 0x2893: 0x00c0, 0x2894: 0x00c0, 0x2895: 0x00c0, 0x2896: 0x00c0, 0x2897: 0x00c0,
+	0x2898: 0x00c0, 0x2899: 0x00c0, 0x289a: 0x00c0, 0x289b: 0x00c0, 0x289c: 0x00c0, 0x289d: 0x00c0,
+	0x289e: 0x00c0, 0x289f: 0x00c0, 0x28a0: 0x00c0, 0x28a1: 0x00c0, 0x28a2: 0x00c0, 0x28a3: 0x00c0,
+	0x28a4: 0x00c0, 0x28a5: 0x00c0, 0x28a6: 0x00c0, 0x28a7: 0x00c0, 0x28a8: 0x00c0, 0x28a9: 0x00c0,
+	0x28aa: 0x00c0, 0x28ab: 0x00c0, 0x28ac: 0x00c0, 0x28ad: 0x00c0, 0x28ae: 0x00c0, 0x28af: 0x00c0,
+	0x28b0: 0x00c3, 0x28b1: 0x00c0, 0x28b2: 0x00c3, 0x28b3: 0x00c3, 0x28b4: 0x00c3, 0x28b5: 0x00c0,
+	0x28b6: 0x00c0, 0x28b7: 0x00c3, 0x28b8: 0x00c3, 0x28b9: 0x00c0, 0x28ba: 0x00c0, 0x28bb: 0x00c0,
+	0x28bc: 0x00c0, 0x28bd: 0x00c0, 0x28be: 0x00c3, 0x28bf: 0x00c3,
+	// Block 0xa3, offset 0x28c0
+	0x28c0: 0x00c0, 0x28c1: 0x00c3, 0x28c2: 0x00c0,
+	0x28db: 0x00c0, 0x28dc: 0x00c0, 0x28dd: 0x00c0,
+	0x28de: 0x0080, 0x28df: 0x0080, 0x28e0: 0x00c0, 0x28e1: 0x00c0, 0x28e2: 0x00c0, 0x28e3: 0x00c0,
+	0x28e4: 0x00c0, 0x28e5: 0x00c0, 0x28e6: 0x00c0, 0x28e7: 0x00c0, 0x28e8: 0x00c0, 0x28e9: 0x00c0,
+	0x28ea: 0x00c0, 0x28eb: 0x00c0, 0x28ec: 0x00c3, 0x28ed: 0x00c3, 0x28ee: 0x00c0, 0x28ef: 0x00c0,
+	0x28f0: 0x0080, 0x28f1: 0x0080, 0x28f2: 0x00c0, 0x28f3: 0x00c0, 0x28f4: 0x00c0, 0x28f5: 0x00c0,
+	0x28f6: 0x00c6,
+	// Block 0xa4, offset 0x2900
+	0x2901: 0x00c0, 0x2902: 0x00c0, 0x2903: 0x00c0, 0x2904: 0x00c0, 0x2905: 0x00c0,
+	0x2906: 0x00c0, 0x2909: 0x00c0, 0x290a: 0x00c0, 0x290b: 0x00c0,
+	0x290c: 0x00c0, 0x290d: 0x00c0, 0x290e: 0x00c0, 0x2911: 0x00c0,
+	0x2912: 0x00c0, 0x2913: 0x00c0, 0x2914: 0x00c0, 0x2915: 0x00c0, 0x2916: 0x00c0,
+	0x2920: 0x00c0, 0x2921: 0x00c0, 0x2922: 0x00c0, 0x2923: 0x00c0,
+	0x2924: 0x00c0, 0x2925: 0x00c0, 0x2926: 0x00c0, 0x2928: 0x00c0, 0x2929: 0x00c0,
+	0x292a: 0x00c0, 0x292b: 0x00c0, 0x292c: 0x00c0, 0x292d: 0x00c0, 0x292e: 0x00c0,
+	0x2930: 0x00c0, 0x2931: 0x00c0, 0x2932: 0x00c0, 0x2933: 0x00c0, 0x2934: 0x00c0, 0x2935: 0x00c0,
+	0x2936: 0x00c0, 0x2937: 0x00c0, 0x2938: 0x00c0, 0x2939: 0x00c0, 0x293a: 0x00c0, 0x293b: 0x00c0,
+	0x293c: 0x00c0, 0x293d: 0x00c0, 0x293e: 0x00c0, 0x293f: 0x00c0,
+	// Block 0xa5, offset 0x2940
+	0x2940: 0x00c0, 0x2941: 0x00c0, 0x2942: 0x00c0, 0x2943: 0x00c0, 0x2944: 0x00c0, 0x2945: 0x00c0,
+	0x2946: 0x00c0, 0x2947: 0x00c0, 0x2948: 0x00c0, 0x2949: 0x00c0, 0x294a: 0x00c0, 0x294b: 0x00c0,
+	0x294c: 0x00c0, 0x294d: 0x00c0, 0x294e: 0x00c0, 0x294f: 0x00c0, 0x2950: 0x00c0, 0x2951: 0x00c0,
+	0x2952: 0x00c0, 0x2953: 0x00c0, 0x2954: 0x00c0, 0x2955: 0x00c0, 0x2956: 0x00c0, 0x2957: 0x00c0,
+	0x2958: 0x00c0, 0x2959: 0x00c0, 0x295a: 0x00c0, 0x295b: 0x0080, 0x295c: 0x0080, 0x295d: 0x0080,
+	0x295e: 0x0080, 0x295f: 0x0080, 0x2960: 0x00c0, 0x2961: 0x00c0, 0x2962: 0x00c0, 0x2963: 0x00c0,
+	0x2964: 0x00c0, 0x2965: 0x00c8, 0x2966: 0x00c0, 0x2967: 0x00c0, 0x2968: 0x00c0, 0x2969: 0x0080,
+	0x296a: 0x0080, 0x296b: 0x0080,
+	0x2970: 0x00c0, 0x2971: 0x00c0, 0x2972: 0x00c0, 0x2973: 0x00c0, 0x2974: 0x00c0, 0x2975: 0x00c0,
+	0x2976: 0x00c0, 0x2977: 0x00c0, 0x2978: 0x00c0, 0x2979: 0x00c0, 0x297a: 0x00c0, 0x297b: 0x00c0,
+	0x297c: 0x00c0, 0x297d: 0x00c0, 0x297e: 0x00c0, 0x297f: 0x00c0,
+	// Block 0xa6, offset 0x2980
+	0x2980: 0x00c0, 0x2981: 0x00c0, 0x2982: 0x00c0, 0x2983: 0x00c0, 0x2984: 0x00c0, 0x2985: 0x00c0,
+	0x2986: 0x00c0, 0x2987: 0x00c0, 0x2988: 0x00c0, 0x2989: 0x00c0, 0x298a: 0x00c0, 0x298b: 0x00c0,
+	0x298c: 0x00c0, 0x298d: 0x00c0, 0x298e: 0x00c0, 0x298f: 0x00c0, 0x2990: 0x00c0, 0x2991: 0x00c0,
+	0x2992: 0x00c0, 0x2993: 0x00c0, 0x2994: 0x00c0, 0x2995: 0x00c0, 0x2996: 0x00c0, 0x2997: 0x00c0,
+	0x2998: 0x00c0, 0x2999: 0x00c0, 0x299a: 0x00c0, 0x299b: 0x00c0, 0x299c: 0x00c0, 0x299d: 0x00c0,
+	0x299e: 0x00c0, 0x299f: 0x00c0, 0x29a0: 0x00c0, 0x29a1: 0x00c0, 0x29a2: 0x00c0, 0x29a3: 0x00c0,
+	0x29a4: 0x00c0, 0x29a5: 0x00c3, 0x29a6: 0x00c0, 0x29a7: 0x00c0, 0x29a8: 0x00c3, 0x29a9: 0x00c0,
+	0x29aa: 0x00c0, 0x29ab: 0x0080, 0x29ac: 0x00c0, 0x29ad: 0x00c6,
+	0x29b0: 0x00c0, 0x29b1: 0x00c0, 0x29b2: 0x00c0, 0x29b3: 0x00c0, 0x29b4: 0x00c0, 0x29b5: 0x00c0,
+	0x29b6: 0x00c0, 0x29b7: 0x00c0, 0x29b8: 0x00c0, 0x29b9: 0x00c0,
+	// Block 0xa7, offset 0x29c0
+	0x29c0: 0x00c0, 0x29c1: 0x00c0, 0x29c2: 0x00c0, 0x29c3: 0x00c0, 0x29c4: 0x00c0, 0x29c5: 0x00c0,
+	0x29c6: 0x00c0, 0x29c7: 0x00c0, 0x29c8: 0x00c0, 0x29c9: 0x00c0, 0x29ca: 0x00c0, 0x29cb: 0x00c0,
+	0x29cc: 0x00c0, 0x29cd: 0x00c0, 0x29ce: 0x00c0, 0x29cf: 0x00c0, 0x29d0: 0x00c0, 0x29d1: 0x00c0,
+	0x29d2: 0x00c0, 0x29d3: 0x00c0, 0x29d4: 0x00c0, 0x29d5: 0x00c0, 0x29d6: 0x00c0, 0x29d7: 0x00c0,
+	0x29d8: 0x00c0, 0x29d9: 0x00c0, 0x29da: 0x00c0, 0x29db: 0x00c0, 0x29dc: 0x00c0, 0x29dd: 0x00c0,
+	0x29de: 0x00c0, 0x29df: 0x00c0, 0x29e0: 0x00c0, 0x29e1: 0x00c0, 0x29e2: 0x00c0, 0x29e3: 0x00c0,
+	0x29f0: 0x0040, 0x29f1: 0x0040, 0x29f2: 0x0040, 0x29f3: 0x0040, 0x29f4: 0x0040, 0x29f5: 0x0040,
+	0x29f6: 0x0040, 0x29f7: 0x0040, 0x29f8: 0x0040, 0x29f9: 0x0040, 0x29fa: 0x0040, 0x29fb: 0x0040,
+	0x29fc: 0x0040, 0x29fd: 0x0040, 0x29fe: 0x0040, 0x29ff: 0x0040,
+	// Block 0xa8, offset 0x2a00
+	0x2a00: 0x0040, 0x2a01: 0x0040, 0x2a02: 0x0040, 0x2a03: 0x0040, 0x2a04: 0x0040, 0x2a05: 0x0040,
+	0x2a06: 0x0040, 0x2a0b: 0x0040,
+	0x2a0c: 0x0040, 0x2a0d: 0x0040, 0x2a0e: 0x0040, 0x2a0f: 0x0040, 0x2a10: 0x0040, 0x2a11: 0x0040,
+	0x2a12: 0x0040, 0x2a13: 0x0040, 0x2a14: 0x0040, 0x2a15: 0x0040, 0x2a16: 0x0040, 0x2a17: 0x0040,
+	0x2a18: 0x0040, 0x2a19: 0x0040, 0x2a1a: 0x0040, 0x2a1b: 0x0040, 0x2a1c: 0x0040, 0x2a1d: 0x0040,
+	0x2a1e: 0x0040, 0x2a1f: 0x0040, 0x2a20: 0x0040, 0x2a21: 0x0040, 0x2a22: 0x0040, 0x2a23: 0x0040,
+	0x2a24: 0x0040, 0x2a25: 0x0040, 0x2a26: 0x0040, 0x2a27: 0x0040, 0x2a28: 0x0040, 0x2a29: 0x0040,
+	0x2a2a: 0x0040, 0x2a2b: 0x0040, 0x2a2c: 0x0040, 0x2a2d: 0x0040, 0x2a2e: 0x0040, 0x2a2f: 0x0040,
+	0x2a30: 0x0040, 0x2a31: 0x0040, 0x2a32: 0x0040, 0x2a33: 0x0040, 0x2a34: 0x0040, 0x2a35: 0x0040,
+	0x2a36: 0x0040, 0x2a37: 0x0040, 0x2a38: 0x0040, 0x2a39: 0x0040, 0x2a3a: 0x0040, 0x2a3b: 0x0040,
+	// Block 0xa9, offset 0x2a40
+	0x2a40: 0x008c, 0x2a41: 0x008c, 0x2a42: 0x008c, 0x2a43: 0x008c, 0x2a44: 0x008c, 0x2a45: 0x008c,
+	0x2a46: 0x008c, 0x2a47: 0x008c, 0x2a48: 0x008c, 0x2a49: 0x008c, 0x2a4a: 0x008c, 0x2a4b: 0x008c,
+	0x2a4c: 0x008c, 0x2a4d: 0x008c, 0x2a4e: 0x00cc, 0x2a4f: 0x00cc, 0x2a50: 0x008c, 0x2a51: 0x00cc,
+	0x2a52: 0x008c, 0x2a53: 0x00cc, 0x2a54: 0x00cc, 0x2a55: 0x008c, 0x2a56: 0x008c, 0x2a57: 0x008c,
+	0x2a58: 0x008c, 0x2a59: 0x008c, 0x2a5a: 0x008c, 0x2a5b: 0x008c, 0x2a5c: 0x008c, 0x2a5d: 0x008c,
+	0x2a5e: 0x008c, 0x2a5f: 0x00cc, 0x2a60: 0x008c, 0x2a61: 0x00cc, 0x2a62: 0x008c, 0x2a63: 0x00cc,
+	0x2a64: 0x00cc, 0x2a65: 0x008c, 0x2a66: 0x008c, 0x2a67: 0x00cc, 0x2a68: 0x00cc, 0x2a69: 0x00cc,
+	0x2a6a: 0x008c, 0x2a6b: 0x008c, 0x2a6c: 0x008c, 0x2a6d: 0x008c, 0x2a6e: 0x008c, 0x2a6f: 0x008c,
+	0x2a70: 0x008c, 0x2a71: 0x008c, 0x2a72: 0x008c, 0x2a73: 0x008c, 0x2a74: 0x008c, 0x2a75: 0x008c,
+	0x2a76: 0x008c, 0x2a77: 0x008c, 0x2a78: 0x008c, 0x2a79: 0x008c, 0x2a7a: 0x008c, 0x2a7b: 0x008c,
+	0x2a7c: 0x008c, 0x2a7d: 0x008c, 0x2a7e: 0x008c, 0x2a7f: 0x008c,
+	// Block 0xaa, offset 0x2a80
+	0x2a80: 0x008c, 0x2a81: 0x008c, 0x2a82: 0x008c, 0x2a83: 0x008c, 0x2a84: 0x008c, 0x2a85: 0x008c,
+	0x2a86: 0x008c, 0x2a87: 0x008c, 0x2a88: 0x008c, 0x2a89: 0x008c, 0x2a8a: 0x008c, 0x2a8b: 0x008c,
+	0x2a8c: 0x008c, 0x2a8d: 0x008c, 0x2a8e: 0x008c, 0x2a8f: 0x008c, 0x2a90: 0x008c, 0x2a91: 0x008c,
+	0x2a92: 0x008c, 0x2a93: 0x008c, 0x2a94: 0x008c, 0x2a95: 0x008c, 0x2a96: 0x008c, 0x2a97: 0x008c,
+	0x2a98: 0x008c, 0x2a99: 0x008c, 0x2a9a: 0x008c, 0x2a9b: 0x008c, 0x2a9c: 0x008c, 0x2a9d: 0x008c,
+	0x2a9e: 0x008c, 0x2a9f: 0x008c, 0x2aa0: 0x008c, 0x2aa1: 0x008c, 0x2aa2: 0x008c, 0x2aa3: 0x008c,
+	0x2aa4: 0x008c, 0x2aa5: 0x008c, 0x2aa6: 0x008c, 0x2aa7: 0x008c, 0x2aa8: 0x008c, 0x2aa9: 0x008c,
+	0x2aaa: 0x008c, 0x2aab: 0x008c, 0x2aac: 0x008c, 0x2aad: 0x008c,
+	0x2ab0: 0x008c, 0x2ab1: 0x008c, 0x2ab2: 0x008c, 0x2ab3: 0x008c, 0x2ab4: 0x008c, 0x2ab5: 0x008c,
+	0x2ab6: 0x008c, 0x2ab7: 0x008c, 0x2ab8: 0x008c, 0x2ab9: 0x008c, 0x2aba: 0x008c, 0x2abb: 0x008c,
+	0x2abc: 0x008c, 0x2abd: 0x008c, 0x2abe: 0x008c, 0x2abf: 0x008c,
+	// Block 0xab, offset 0x2ac0
+	0x2ac0: 0x008c, 0x2ac1: 0x008c, 0x2ac2: 0x008c, 0x2ac3: 0x008c, 0x2ac4: 0x008c, 0x2ac5: 0x008c,
+	0x2ac6: 0x008c, 0x2ac7: 0x008c, 0x2ac8: 0x008c, 0x2ac9: 0x008c, 0x2aca: 0x008c, 0x2acb: 0x008c,
+	0x2acc: 0x008c, 0x2acd: 0x008c, 0x2ace: 0x008c, 0x2acf: 0x008c, 0x2ad0: 0x008c, 0x2ad1: 0x008c,
+	0x2ad2: 0x008c, 0x2ad3: 0x008c, 0x2ad4: 0x008c, 0x2ad5: 0x008c, 0x2ad6: 0x008c, 0x2ad7: 0x008c,
+	0x2ad8: 0x008c, 0x2ad9: 0x008c,
+	// Block 0xac, offset 0x2b00
+	0x2b00: 0x0080, 0x2b01: 0x0080, 0x2b02: 0x0080, 0x2b03: 0x0080, 0x2b04: 0x0080, 0x2b05: 0x0080,
+	0x2b06: 0x0080,
+	0x2b13: 0x0080, 0x2b14: 0x0080, 0x2b15: 0x0080, 0x2b16: 0x0080, 0x2b17: 0x0080,
+	0x2b1d: 0x008a,
+	0x2b1e: 0x00cb, 0x2b1f: 0x008a, 0x2b20: 0x008a, 0x2b21: 0x008a, 0x2b22: 0x008a, 0x2b23: 0x008a,
+	0x2b24: 0x008a, 0x2b25: 0x008a, 0x2b26: 0x008a, 0x2b27: 0x008a, 0x2b28: 0x008a, 0x2b29: 0x008a,
+	0x2b2a: 0x008a, 0x2b2b: 0x008a, 0x2b2c: 0x008a, 0x2b2d: 0x008a, 0x2b2e: 0x008a, 0x2b2f: 0x008a,
+	0x2b30: 0x008a, 0x2b31: 0x008a, 0x2b32: 0x008a, 0x2b33: 0x008a, 0x2b34: 0x008a, 0x2b35: 0x008a,
+	0x2b36: 0x008a, 0x2b38: 0x008a, 0x2b39: 0x008a, 0x2b3a: 0x008a, 0x2b3b: 0x008a,
+	0x2b3c: 0x008a, 0x2b3e: 0x008a,
+	// Block 0xad, offset 0x2b40
+	0x2b40: 0x008a, 0x2b41: 0x008a, 0x2b43: 0x008a, 0x2b44: 0x008a,
+	0x2b46: 0x008a, 0x2b47: 0x008a, 0x2b48: 0x008a, 0x2b49: 0x008a, 0x2b4a: 0x008a, 0x2b4b: 0x008a,
+	0x2b4c: 0x008a, 0x2b4d: 0x008a, 0x2b4e: 0x008a, 0x2b4f: 0x008a, 0x2b50: 0x0080, 0x2b51: 0x0080,
+	0x2b52: 0x0080, 0x2b53: 0x0080, 0x2b54: 0x0080, 0x2b55: 0x0080, 0x2b56: 0x0080, 0x2b57: 0x0080,
+	0x2b58: 0x0080, 0x2b59: 0x0080, 0x2b5a: 0x0080, 0x2b5b: 0x0080, 0x2b5c: 0x0080, 0x2b5d: 0x0080,
+	0x2b5e: 0x0080, 0x2b5f: 0x0080, 0x2b60: 0x0080, 0x2b61: 0x0080, 0x2b62: 0x0080, 0x2b63: 0x0080,
+	0x2b64: 0x0080, 0x2b65: 0x0080, 0x2b66: 0x0080, 0x2b67: 0x0080, 0x2b68: 0x0080, 0x2b69: 0x0080,
+	0x2b6a: 0x0080, 0x2b6b: 0x0080, 0x2b6c: 0x0080, 0x2b6d: 0x0080, 0x2b6e: 0x0080, 0x2b6f: 0x0080,
+	0x2b70: 0x0080, 0x2b71: 0x0080, 0x2b72: 0x0080, 0x2b73: 0x0080, 0x2b74: 0x0080, 0x2b75: 0x0080,
+	0x2b76: 0x0080, 0x2b77: 0x0080, 0x2b78: 0x0080, 0x2b79: 0x0080, 0x2b7a: 0x0080, 0x2b7b: 0x0080,
+	0x2b7c: 0x0080, 0x2b7d: 0x0080, 0x2b7e: 0x0080, 0x2b7f: 0x0080,
+	// Block 0xae, offset 0x2b80
+	0x2b80: 0x0080, 0x2b81: 0x0080, 0x2b82: 0x0080, 0x2b83: 0x0080, 0x2b84: 0x0080, 0x2b85: 0x0080,
+	0x2b86: 0x0080, 0x2b87: 0x0080, 0x2b88: 0x0080, 0x2b89: 0x0080, 0x2b8a: 0x0080, 0x2b8b: 0x0080,
+	0x2b8c: 0x0080, 0x2b8d: 0x0080, 0x2b8e: 0x0080, 0x2b8f: 0x0080,
+	0x2bb0: 0x0080, 0x2bb1: 0x0080, 0x2bb2: 0x0080, 0x2bb3: 0x0080, 0x2bb4: 0x0080, 0x2bb5: 0x0080,
+	0x2bb6: 0x0080, 0x2bb7: 0x0080, 0x2bb8: 0x0080, 0x2bb9: 0x0080, 0x2bba: 0x0080, 0x2bbb: 0x0080,
+	0x2bbc: 0x0080, 0x2bbd: 0x0080, 0x2bbe: 0x0080, 0x2bbf: 0x0080,
+	// Block 0xaf, offset 0x2bc0
+	0x2bc0: 0x0040, 0x2bc1: 0x0040, 0x2bc2: 0x0040, 0x2bc3: 0x0040, 0x2bc4: 0x0040, 0x2bc5: 0x0040,
+	0x2bc6: 0x0040, 0x2bc7: 0x0040, 0x2bc8: 0x0040, 0x2bc9: 0x0040, 0x2bca: 0x0040, 0x2bcb: 0x0040,
+	0x2bcc: 0x0040, 0x2bcd: 0x0040, 0x2bce: 0x0040, 0x2bcf: 0x0040, 0x2bd0: 0x0080, 0x2bd1: 0x0080,
+	0x2bd2: 0x0080, 0x2bd3: 0x0080, 0x2bd4: 0x0080, 0x2bd5: 0x0080, 0x2bd6: 0x0080, 0x2bd7: 0x0080,
+	0x2bd8: 0x0080, 0x2bd9: 0x0080,
+	0x2be0: 0x00c3, 0x2be1: 0x00c3, 0x2be2: 0x00c3, 0x2be3: 0x00c3,
+	0x2be4: 0x00c3, 0x2be5: 0x00c3, 0x2be6: 0x00c3, 0x2be7: 0x00c3, 0x2be8: 0x00c3, 0x2be9: 0x00c3,
+	0x2bea: 0x00c3, 0x2beb: 0x00c3, 0x2bec: 0x00c3, 0x2bed: 0x00c3, 0x2bee: 0x00c3, 0x2bef: 0x00c3,
+	0x2bf0: 0x0080, 0x2bf1: 0x0080, 0x2bf2: 0x0080, 0x2bf3: 0x0080, 0x2bf4: 0x0080, 0x2bf5: 0x0080,
+	0x2bf6: 0x0080, 0x2bf7: 0x0080, 0x2bf8: 0x0080, 0x2bf9: 0x0080, 0x2bfa: 0x0080, 0x2bfb: 0x0080,
+	0x2bfc: 0x0080, 0x2bfd: 0x0080, 0x2bfe: 0x0080, 0x2bff: 0x0080,
+	// Block 0xb0, offset 0x2c00
+	0x2c00: 0x0080, 0x2c01: 0x0080, 0x2c02: 0x0080, 0x2c03: 0x0080, 0x2c04: 0x0080, 0x2c05: 0x0080,
+	0x2c06: 0x0080, 0x2c07: 0x0080, 0x2c08: 0x0080, 0x2c09: 0x0080, 0x2c0a: 0x0080, 0x2c0b: 0x0080,
+	0x2c0c: 0x0080, 0x2c0d: 0x0080, 0x2c0e: 0x0080, 0x2c0f: 0x0080, 0x2c10: 0x0080, 0x2c11: 0x0080,
+	0x2c12: 0x0080, 0x2c14: 0x0080, 0x2c15: 0x0080, 0x2c16: 0x0080, 0x2c17: 0x0080,
+	0x2c18: 0x0080, 0x2c19: 0x0080, 0x2c1a: 0x0080, 0x2c1b: 0x0080, 0x2c1c: 0x0080, 0x2c1d: 0x0080,
+	0x2c1e: 0x0080, 0x2c1f: 0x0080, 0x2c20: 0x0080, 0x2c21: 0x0080, 0x2c22: 0x0080, 0x2c23: 0x0080,
+	0x2c24: 0x0080, 0x2c25: 0x0080, 0x2c26: 0x0080, 0x2c28: 0x0080, 0x2c29: 0x0080,
+	0x2c2a: 0x0080, 0x2c2b: 0x0080,
+	0x2c30: 0x0080, 0x2c31: 0x0080, 0x2c32: 0x0080, 0x2c33: 0x00c0, 0x2c34: 0x0080,
+	0x2c36: 0x0080, 0x2c37: 0x0080, 0x2c38: 0x0080, 0x2c39: 0x0080, 0x2c3a: 0x0080, 0x2c3b: 0x0080,
+	0x2c3c: 0x0080, 0x2c3d: 0x0080, 0x2c3e: 0x0080, 0x2c3f: 0x0080,
+	// Block 0xb1, offset 0x2c40
+	0x2c40: 0x0080, 0x2c41: 0x0080, 0x2c42: 0x0080, 0x2c43: 0x0080, 0x2c44: 0x0080, 0x2c45: 0x0080,
+	0x2c46: 0x0080, 0x2c47: 0x0080, 0x2c48: 0x0080, 0x2c49: 0x0080, 0x2c4a: 0x0080, 0x2c4b: 0x0080,
+	0x2c4c: 0x0080, 0x2c4d: 0x0080, 0x2c4e: 0x0080, 0x2c4f: 0x0080, 0x2c50: 0x0080, 0x2c51: 0x0080,
+	0x2c52: 0x0080, 0x2c53: 0x0080, 0x2c54: 0x0080, 0x2c55: 0x0080, 0x2c56: 0x0080, 0x2c57: 0x0080,
+	0x2c58: 0x0080, 0x2c59: 0x0080, 0x2c5a: 0x0080, 0x2c5b: 0x0080, 0x2c5c: 0x0080, 0x2c5d: 0x0080,
+	0x2c5e: 0x0080, 0x2c5f: 0x0080, 0x2c60: 0x0080, 0x2c61: 0x0080, 0x2c62: 0x0080, 0x2c63: 0x0080,
+	0x2c64: 0x0080, 0x2c65: 0x0080, 0x2c66: 0x0080, 0x2c67: 0x0080, 0x2c68: 0x0080, 0x2c69: 0x0080,
+	0x2c6a: 0x0080, 0x2c6b: 0x0080, 0x2c6c: 0x0080, 0x2c6d: 0x0080, 0x2c6e: 0x0080, 0x2c6f: 0x0080,
+	0x2c70: 0x0080, 0x2c71: 0x0080, 0x2c72: 0x0080, 0x2c73: 0x0080, 0x2c74: 0x0080, 0x2c75: 0x0080,
+	0x2c76: 0x0080, 0x2c77: 0x0080, 0x2c78: 0x0080, 0x2c79: 0x0080, 0x2c7a: 0x0080, 0x2c7b: 0x0080,
+	0x2c7c: 0x0080, 0x2c7f: 0x0040,
+	// Block 0xb2, offset 0x2c80
+	0x2c81: 0x0080, 0x2c82: 0x0080, 0x2c83: 0x0080, 0x2c84: 0x0080, 0x2c85: 0x0080,
+	0x2c86: 0x0080, 0x2c87: 0x0080, 0x2c88: 0x0080, 0x2c89: 0x0080, 0x2c8a: 0x0080, 0x2c8b: 0x0080,
+	0x2c8c: 0x0080, 0x2c8d: 0x0080, 0x2c8e: 0x0080, 0x2c8f: 0x0080, 0x2c90: 0x0080, 0x2c91: 0x0080,
+	0x2c92: 0x0080, 0x2c93: 0x0080, 0x2c94: 0x0080, 0x2c95: 0x0080, 0x2c96: 0x0080, 0x2c97: 0x0080,
+	0x2c98: 0x0080, 0x2c99: 0x0080, 0x2c9a: 0x0080, 0x2c9b: 0x0080, 0x2c9c: 0x0080, 0x2c9d: 0x0080,
+	0x2c9e: 0x0080, 0x2c9f: 0x0080, 0x2ca0: 0x0080, 0x2ca1: 0x0080, 0x2ca2: 0x0080, 0x2ca3: 0x0080,
+	0x2ca4: 0x0080, 0x2ca5: 0x0080, 0x2ca6: 0x0080, 0x2ca7: 0x0080, 0x2ca8: 0x0080, 0x2ca9: 0x0080,
+	0x2caa: 0x0080, 0x2cab: 0x0080, 0x2cac: 0x0080, 0x2cad: 0x0080, 0x2cae: 0x0080, 0x2caf: 0x0080,
+	0x2cb0: 0x0080, 0x2cb1: 0x0080, 0x2cb2: 0x0080, 0x2cb3: 0x0080, 0x2cb4: 0x0080, 0x2cb5: 0x0080,
+	0x2cb6: 0x0080, 0x2cb7: 0x0080, 0x2cb8: 0x0080, 0x2cb9: 0x0080, 0x2cba: 0x0080, 0x2cbb: 0x0080,
+	0x2cbc: 0x0080, 0x2cbd: 0x0080, 0x2cbe: 0x0080, 0x2cbf: 0x0080,
+	// Block 0xb3, offset 0x2cc0
+	0x2cc0: 0x0080, 0x2cc1: 0x0080, 0x2cc2: 0x0080, 0x2cc3: 0x0080, 0x2cc4: 0x0080, 0x2cc5: 0x0080,
+	0x2cc6: 0x0080, 0x2cc7: 0x0080, 0x2cc8: 0x0080, 0x2cc9: 0x0080, 0x2cca: 0x0080, 0x2ccb: 0x0080,
+	0x2ccc: 0x0080, 0x2ccd: 0x0080, 0x2cce: 0x0080, 0x2ccf: 0x0080, 0x2cd0: 0x0080, 0x2cd1: 0x0080,
+	0x2cd2: 0x0080, 0x2cd3: 0x0080, 0x2cd4: 0x0080, 0x2cd5: 0x0080, 0x2cd6: 0x0080, 0x2cd7: 0x0080,
+	0x2cd8: 0x0080, 0x2cd9: 0x0080, 0x2cda: 0x0080, 0x2cdb: 0x0080, 0x2cdc: 0x0080, 0x2cdd: 0x0080,
+	0x2cde: 0x0080, 0x2cdf: 0x0080, 0x2ce0: 0x0080, 0x2ce1: 0x0080, 0x2ce2: 0x0080, 0x2ce3: 0x0080,
+	0x2ce4: 0x0080, 0x2ce5: 0x0080, 0x2ce6: 0x008c, 0x2ce7: 0x008c, 0x2ce8: 0x008c, 0x2ce9: 0x008c,
+	0x2cea: 0x008c, 0x2ceb: 0x008c, 0x2cec: 0x008c, 0x2ced: 0x008c, 0x2cee: 0x008c, 0x2cef: 0x008c,
+	0x2cf0: 0x0080, 0x2cf1: 0x008c, 0x2cf2: 0x008c, 0x2cf3: 0x008c, 0x2cf4: 0x008c, 0x2cf5: 0x008c,
+	0x2cf6: 0x008c, 0x2cf7: 0x008c, 0x2cf8: 0x008c, 0x2cf9: 0x008c, 0x2cfa: 0x008c, 0x2cfb: 0x008c,
+	0x2cfc: 0x008c, 0x2cfd: 0x008c, 0x2cfe: 0x008c, 0x2cff: 0x008c,
+	// Block 0xb4, offset 0x2d00
+	0x2d00: 0x008c, 0x2d01: 0x008c, 0x2d02: 0x008c, 0x2d03: 0x008c, 0x2d04: 0x008c, 0x2d05: 0x008c,
+	0x2d06: 0x008c, 0x2d07: 0x008c, 0x2d08: 0x008c, 0x2d09: 0x008c, 0x2d0a: 0x008c, 0x2d0b: 0x008c,
+	0x2d0c: 0x008c, 0x2d0d: 0x008c, 0x2d0e: 0x008c, 0x2d0f: 0x008c, 0x2d10: 0x008c, 0x2d11: 0x008c,
+	0x2d12: 0x008c, 0x2d13: 0x008c, 0x2d14: 0x008c, 0x2d15: 0x008c, 0x2d16: 0x008c, 0x2d17: 0x008c,
+	0x2d18: 0x008c, 0x2d19: 0x008c, 0x2d1a: 0x008c, 0x2d1b: 0x008c, 0x2d1c: 0x008c, 0x2d1d: 0x008c,
+	0x2d1e: 0x0080, 0x2d1f: 0x0080, 0x2d20: 0x0040, 0x2d21: 0x0080, 0x2d22: 0x0080, 0x2d23: 0x0080,
+	0x2d24: 0x0080, 0x2d25: 0x0080, 0x2d26: 0x0080, 0x2d27: 0x0080, 0x2d28: 0x0080, 0x2d29: 0x0080,
+	0x2d2a: 0x0080, 0x2d2b: 0x0080, 0x2d2c: 0x0080, 0x2d2d: 0x0080, 0x2d2e: 0x0080, 0x2d2f: 0x0080,
+	0x2d30: 0x0080, 0x2d31: 0x0080, 0x2d32: 0x0080, 0x2d33: 0x0080, 0x2d34: 0x0080, 0x2d35: 0x0080,
+	0x2d36: 0x0080, 0x2d37: 0x0080, 0x2d38: 0x0080, 0x2d39: 0x0080, 0x2d3a: 0x0080, 0x2d3b: 0x0080,
+	0x2d3c: 0x0080, 0x2d3d: 0x0080, 0x2d3e: 0x0080,
+	// Block 0xb5, offset 0x2d40
+	0x2d42: 0x0080, 0x2d43: 0x0080, 0x2d44: 0x0080, 0x2d45: 0x0080,
+	0x2d46: 0x0080, 0x2d47: 0x0080, 0x2d4a: 0x0080, 0x2d4b: 0x0080,
+	0x2d4c: 0x0080, 0x2d4d: 0x0080, 0x2d4e: 0x0080, 0x2d4f: 0x0080,
+	0x2d52: 0x0080, 0x2d53: 0x0080, 0x2d54: 0x0080, 0x2d55: 0x0080, 0x2d56: 0x0080, 0x2d57: 0x0080,
+	0x2d5a: 0x0080, 0x2d5b: 0x0080, 0x2d5c: 0x0080,
+	0x2d60: 0x0080, 0x2d61: 0x0080, 0x2d62: 0x0080, 0x2d63: 0x0080,
+	0x2d64: 0x0080, 0x2d65: 0x0080, 0x2d66: 0x0080, 0x2d68: 0x0080, 0x2d69: 0x0080,
+	0x2d6a: 0x0080, 0x2d6b: 0x0080, 0x2d6c: 0x0080, 0x2d6d: 0x0080, 0x2d6e: 0x0080,
+	0x2d79: 0x0040, 0x2d7a: 0x0040, 0x2d7b: 0x0040,
+	0x2d7c: 0x0080, 0x2d7d: 0x0080,
+	// Block 0xb6, offset 0x2d80
+	0x2d80: 0x00c0, 0x2d81: 0x00c0, 0x2d82: 0x00c0, 0x2d83: 0x00c0, 0x2d84: 0x00c0, 0x2d85: 0x00c0,
+	0x2d86: 0x00c0, 0x2d87: 0x00c0, 0x2d88: 0x00c0, 0x2d89: 0x00c0, 0x2d8a: 0x00c0, 0x2d8b: 0x00c0,
+	0x2d8d: 0x00c0, 0x2d8e: 0x00c0, 0x2d8f: 0x00c0, 0x2d90: 0x00c0, 0x2d91: 0x00c0,
+	0x2d92: 0x00c0, 0x2d93: 0x00c0, 0x2d94: 0x00c0, 0x2d95: 0x00c0, 0x2d96: 0x00c0, 0x2d97: 0x00c0,
+	0x2d98: 0x00c0, 0x2d99: 0x00c0, 0x2d9a: 0x00c0, 0x2d9b: 0x00c0, 0x2d9c: 0x00c0, 0x2d9d: 0x00c0,
+	0x2d9e: 0x00c0, 0x2d9f: 0x00c0, 0x2da0: 0x00c0, 0x2da1: 0x00c0, 0x2da2: 0x00c0, 0x2da3: 0x00c0,
+	0x2da4: 0x00c0, 0x2da5: 0x00c0, 0x2da6: 0x00c0, 0x2da8: 0x00c0, 0x2da9: 0x00c0,
+	0x2daa: 0x00c0, 0x2dab: 0x00c0, 0x2dac: 0x00c0, 0x2dad: 0x00c0, 0x2dae: 0x00c0, 0x2daf: 0x00c0,
+	0x2db0: 0x00c0, 0x2db1: 0x00c0, 0x2db2: 0x00c0, 0x2db3: 0x00c0, 0x2db4: 0x00c0, 0x2db5: 0x00c0,
+	0x2db6: 0x00c0, 0x2db7: 0x00c0, 0x2db8: 0x00c0, 0x2db9: 0x00c0, 0x2dba: 0x00c0,
+	0x2dbc: 0x00c0, 0x2dbd: 0x00c0, 0x2dbf: 0x00c0,
+	// Block 0xb7, offset 0x2dc0
+	0x2dc0: 0x00c0, 0x2dc1: 0x00c0, 0x2dc2: 0x00c0, 0x2dc3: 0x00c0, 0x2dc4: 0x00c0, 0x2dc5: 0x00c0,
+	0x2dc6: 0x00c0, 0x2dc7: 0x00c0, 0x2dc8: 0x00c0, 0x2dc9: 0x00c0, 0x2dca: 0x00c0, 0x2dcb: 0x00c0,
+	0x2dcc: 0x00c0, 0x2dcd: 0x00c0, 0x2dd0: 0x00c0, 0x2dd1: 0x00c0,
+	0x2dd2: 0x00c0, 0x2dd3: 0x00c0, 0x2dd4: 0x00c0, 0x2dd5: 0x00c0, 0x2dd6: 0x00c0, 0x2dd7: 0x00c0,
+	0x2dd8: 0x00c0, 0x2dd9: 0x00c0, 0x2dda: 0x00c0, 0x2ddb: 0x00c0, 0x2ddc: 0x00c0, 0x2ddd: 0x00c0,
+	// Block 0xb8, offset 0x2e00
+	0x2e00: 0x00c0, 0x2e01: 0x00c0, 0x2e02: 0x00c0, 0x2e03: 0x00c0, 0x2e04: 0x00c0, 0x2e05: 0x00c0,
+	0x2e06: 0x00c0, 0x2e07: 0x00c0, 0x2e08: 0x00c0, 0x2e09: 0x00c0, 0x2e0a: 0x00c0, 0x2e0b: 0x00c0,
+	0x2e0c: 0x00c0, 0x2e0d: 0x00c0, 0x2e0e: 0x00c0, 0x2e0f: 0x00c0, 0x2e10: 0x00c0, 0x2e11: 0x00c0,
+	0x2e12: 0x00c0, 0x2e13: 0x00c0, 0x2e14: 0x00c0, 0x2e15: 0x00c0, 0x2e16: 0x00c0, 0x2e17: 0x00c0,
+	0x2e18: 0x00c0, 0x2e19: 0x00c0, 0x2e1a: 0x00c0, 0x2e1b: 0x00c0, 0x2e1c: 0x00c0, 0x2e1d: 0x00c0,
+	0x2e1e: 0x00c0, 0x2e1f: 0x00c0, 0x2e20: 0x00c0, 0x2e21: 0x00c0, 0x2e22: 0x00c0, 0x2e23: 0x00c0,
+	0x2e24: 0x00c0, 0x2e25: 0x00c0, 0x2e26: 0x00c0, 0x2e27: 0x00c0, 0x2e28: 0x00c0, 0x2e29: 0x00c0,
+	0x2e2a: 0x00c0, 0x2e2b: 0x00c0, 0x2e2c: 0x00c0, 0x2e2d: 0x00c0, 0x2e2e: 0x00c0, 0x2e2f: 0x00c0,
+	0x2e30: 0x00c0, 0x2e31: 0x00c0, 0x2e32: 0x00c0, 0x2e33: 0x00c0, 0x2e34: 0x00c0, 0x2e35: 0x00c0,
+	0x2e36: 0x00c0, 0x2e37: 0x00c0, 0x2e38: 0x00c0, 0x2e39: 0x00c0, 0x2e3a: 0x00c0,
+	// Block 0xb9, offset 0x2e40
+	0x2e40: 0x0080, 0x2e41: 0x0080, 0x2e42: 0x0080,
+	0x2e47: 0x0080, 0x2e48: 0x0080, 0x2e49: 0x0080, 0x2e4a: 0x0080, 0x2e4b: 0x0080,
+	0x2e4c: 0x0080, 0x2e4d: 0x0080, 0x2e4e: 0x0080, 0x2e4f: 0x0080, 0x2e50: 0x0080, 0x2e51: 0x0080,
+	0x2e52: 0x0080, 0x2e53: 0x0080, 0x2e54: 0x0080, 0x2e55: 0x0080, 0x2e56: 0x0080, 0x2e57: 0x0080,
+	0x2e58: 0x0080, 0x2e59: 0x0080, 0x2e5a: 0x0080, 0x2e5b: 0x0080, 0x2e5c: 0x0080, 0x2e5d: 0x0080,
+	0x2e5e: 0x0080, 0x2e5f: 0x0080, 0x2e60: 0x0080, 0x2e61: 0x0080, 0x2e62: 0x0080, 0x2e63: 0x0080,
+	0x2e64: 0x0080, 0x2e65: 0x0080, 0x2e66: 0x0080, 0x2e67: 0x0080, 0x2e68: 0x0080, 0x2e69: 0x0080,
+	0x2e6a: 0x0080, 0x2e6b: 0x0080, 0x2e6c: 0x0080, 0x2e6d: 0x0080, 0x2e6e: 0x0080, 0x2e6f: 0x0080,
+	0x2e70: 0x0080, 0x2e71: 0x0080, 0x2e72: 0x0080, 0x2e73: 0x0080,
+	0x2e77: 0x0080, 0x2e78: 0x0080, 0x2e79: 0x0080, 0x2e7a: 0x0080, 0x2e7b: 0x0080,
+	0x2e7c: 0x0080, 0x2e7d: 0x0080, 0x2e7e: 0x0080, 0x2e7f: 0x0080,
+	// Block 0xba, offset 0x2e80
+	0x2e80: 0x0088, 0x2e81: 0x0088, 0x2e82: 0x0088, 0x2e83: 0x0088, 0x2e84: 0x0088, 0x2e85: 0x0088,
+	0x2e86: 0x0088, 0x2e87: 0x0088, 0x2e88: 0x0088, 0x2e89: 0x0088, 0x2e8a: 0x0088, 0x2e8b: 0x0088,
+	0x2e8c: 0x0088, 0x2e8d: 0x0088, 0x2e8e: 0x0088, 0x2e8f: 0x0088, 0x2e90: 0x0088, 0x2e91: 0x0088,
+	0x2e92: 0x0088, 0x2e93: 0x0088, 0x2e94: 0x0088, 0x2e95: 0x0088, 0x2e96: 0x0088, 0x2e97: 0x0088,
+	0x2e98: 0x0088, 0x2e99: 0x0088, 0x2e9a: 0x0088, 0x2e9b: 0x0088, 0x2e9c: 0x0088, 0x2e9d: 0x0088,
+	0x2e9e: 0x0088, 0x2e9f: 0x0088, 0x2ea0: 0x0088, 0x2ea1: 0x0088, 0x2ea2: 0x0088, 0x2ea3: 0x0088,
+	0x2ea4: 0x0088, 0x2ea5: 0x0088, 0x2ea6: 0x0088, 0x2ea7: 0x0088, 0x2ea8: 0x0088, 0x2ea9: 0x0088,
+	0x2eaa: 0x0088, 0x2eab: 0x0088, 0x2eac: 0x0088, 0x2ead: 0x0088, 0x2eae: 0x0088, 0x2eaf: 0x0088,
+	0x2eb0: 0x0088, 0x2eb1: 0x0088, 0x2eb2: 0x0088, 0x2eb3: 0x0088, 0x2eb4: 0x0088, 0x2eb5: 0x0088,
+	0x2eb6: 0x0088, 0x2eb7: 0x0088, 0x2eb8: 0x0088, 0x2eb9: 0x0088, 0x2eba: 0x0088, 0x2ebb: 0x0088,
+	0x2ebc: 0x0088, 0x2ebd: 0x0088, 0x2ebe: 0x0088, 0x2ebf: 0x0088,
+	// Block 0xbb, offset 0x2ec0
+	0x2ec0: 0x0088, 0x2ec1: 0x0088, 0x2ec2: 0x0088, 0x2ec3: 0x0088, 0x2ec4: 0x0088, 0x2ec5: 0x0088,
+	0x2ec6: 0x0088, 0x2ec7: 0x0088, 0x2ec8: 0x0088, 0x2ec9: 0x0088, 0x2eca: 0x0088, 0x2ecb: 0x0088,
+	0x2ecc: 0x0088, 0x2ecd: 0x0088, 0x2ece: 0x0088, 0x2ed0: 0x0080, 0x2ed1: 0x0080,
+	0x2ed2: 0x0080, 0x2ed3: 0x0080, 0x2ed4: 0x0080, 0x2ed5: 0x0080, 0x2ed6: 0x0080, 0x2ed7: 0x0080,
+	0x2ed8: 0x0080, 0x2ed9: 0x0080, 0x2eda: 0x0080, 0x2edb: 0x0080, 0x2edc: 0x0080,
+	0x2ee0: 0x0088,
+	// Block 0xbc, offset 0x2f00
+	0x2f10: 0x0080, 0x2f11: 0x0080,
+	0x2f12: 0x0080, 0x2f13: 0x0080, 0x2f14: 0x0080, 0x2f15: 0x0080, 0x2f16: 0x0080, 0x2f17: 0x0080,
+	0x2f18: 0x0080, 0x2f19: 0x0080, 0x2f1a: 0x0080, 0x2f1b: 0x0080, 0x2f1c: 0x0080, 0x2f1d: 0x0080,
+	0x2f1e: 0x0080, 0x2f1f: 0x0080, 0x2f20: 0x0080, 0x2f21: 0x0080, 0x2f22: 0x0080, 0x2f23: 0x0080,
+	0x2f24: 0x0080, 0x2f25: 0x0080, 0x2f26: 0x0080, 0x2f27: 0x0080, 0x2f28: 0x0080, 0x2f29: 0x0080,
+	0x2f2a: 0x0080, 0x2f2b: 0x0080, 0x2f2c: 0x0080, 0x2f2d: 0x0080, 0x2f2e: 0x0080, 0x2f2f: 0x0080,
+	0x2f30: 0x0080, 0x2f31: 0x0080, 0x2f32: 0x0080, 0x2f33: 0x0080, 0x2f34: 0x0080, 0x2f35: 0x0080,
+	0x2f36: 0x0080, 0x2f37: 0x0080, 0x2f38: 0x0080, 0x2f39: 0x0080, 0x2f3a: 0x0080, 0x2f3b: 0x0080,
+	0x2f3c: 0x0080, 0x2f3d: 0x00c3,
+	// Block 0xbd, offset 0x2f40
+	0x2f40: 0x00c0, 0x2f41: 0x00c0, 0x2f42: 0x00c0, 0x2f43: 0x00c0, 0x2f44: 0x00c0, 0x2f45: 0x00c0,
+	0x2f46: 0x00c0, 0x2f47: 0x00c0, 0x2f48: 0x00c0, 0x2f49: 0x00c0, 0x2f4a: 0x00c0, 0x2f4b: 0x00c0,
+	0x2f4c: 0x00c0, 0x2f4d: 0x00c0, 0x2f4e: 0x00c0, 0x2f4f: 0x00c0, 0x2f50: 0x00c0, 0x2f51: 0x00c0,
+	0x2f52: 0x00c0, 0x2f53: 0x00c0, 0x2f54: 0x00c0, 0x2f55: 0x00c0, 0x2f56: 0x00c0, 0x2f57: 0x00c0,
+	0x2f58: 0x00c0, 0x2f59: 0x00c0, 0x2f5a: 0x00c0, 0x2f5b: 0x00c0, 0x2f5c: 0x00c0,
+	0x2f60: 0x00c0, 0x2f61: 0x00c0, 0x2f62: 0x00c0, 0x2f63: 0x00c0,
+	0x2f64: 0x00c0, 0x2f65: 0x00c0, 0x2f66: 0x00c0, 0x2f67: 0x00c0, 0x2f68: 0x00c0, 0x2f69: 0x00c0,
+	0x2f6a: 0x00c0, 0x2f6b: 0x00c0, 0x2f6c: 0x00c0, 0x2f6d: 0x00c0, 0x2f6e: 0x00c0, 0x2f6f: 0x00c0,
+	0x2f70: 0x00c0, 0x2f71: 0x00c0, 0x2f72: 0x00c0, 0x2f73: 0x00c0, 0x2f74: 0x00c0, 0x2f75: 0x00c0,
+	0x2f76: 0x00c0, 0x2f77: 0x00c0, 0x2f78: 0x00c0, 0x2f79: 0x00c0, 0x2f7a: 0x00c0, 0x2f7b: 0x00c0,
+	0x2f7c: 0x00c0, 0x2f7d: 0x00c0, 0x2f7e: 0x00c0, 0x2f7f: 0x00c0,
+	// Block 0xbe, offset 0x2f80
+	0x2f80: 0x00c0, 0x2f81: 0x00c0, 0x2f82: 0x00c0, 0x2f83: 0x00c0, 0x2f84: 0x00c0, 0x2f85: 0x00c0,
+	0x2f86: 0x00c0, 0x2f87: 0x00c0, 0x2f88: 0x00c0, 0x2f89: 0x00c0, 0x2f8a: 0x00c0, 0x2f8b: 0x00c0,
+	0x2f8c: 0x00c0, 0x2f8d: 0x00c0, 0x2f8e: 0x00c0, 0x2f8f: 0x00c0, 0x2f90: 0x00c0,
+	0x2fa0: 0x00c3, 0x2fa1: 0x0080, 0x2fa2: 0x0080, 0x2fa3: 0x0080,
+	0x2fa4: 0x0080, 0x2fa5: 0x0080, 0x2fa6: 0x0080, 0x2fa7: 0x0080, 0x2fa8: 0x0080, 0x2fa9: 0x0080,
+	0x2faa: 0x0080, 0x2fab: 0x0080, 0x2fac: 0x0080, 0x2fad: 0x0080, 0x2fae: 0x0080, 0x2faf: 0x0080,
+	0x2fb0: 0x0080, 0x2fb1: 0x0080, 0x2fb2: 0x0080, 0x2fb3: 0x0080, 0x2fb4: 0x0080, 0x2fb5: 0x0080,
+	0x2fb6: 0x0080, 0x2fb7: 0x0080, 0x2fb8: 0x0080, 0x2fb9: 0x0080, 0x2fba: 0x0080, 0x2fbb: 0x0080,
+	// Block 0xbf, offset 0x2fc0
+	0x2fc0: 0x00c0, 0x2fc1: 0x00c0, 0x2fc2: 0x00c0, 0x2fc3: 0x00c0, 0x2fc4: 0x00c0, 0x2fc5: 0x00c0,
+	0x2fc6: 0x00c0, 0x2fc7: 0x00c0, 0x2fc8: 0x00c0, 0x2fc9: 0x00c0, 0x2fca: 0x00c0, 0x2fcb: 0x00c0,
+	0x2fcc: 0x00c0, 0x2fcd: 0x00c0, 0x2fce: 0x00c0, 0x2fcf: 0x00c0, 0x2fd0: 0x00c0, 0x2fd1: 0x00c0,
+	0x2fd2: 0x00c0, 0x2fd3: 0x00c0, 0x2fd4: 0x00c0, 0x2fd5: 0x00c0, 0x2fd6: 0x00c0, 0x2fd7: 0x00c0,
+	0x2fd8: 0x00c0, 0x2fd9: 0x00c0, 0x2fda: 0x00c0, 0x2fdb: 0x00c0, 0x2fdc: 0x00c0, 0x2fdd: 0x00c0,
+	0x2fde: 0x00c0, 0x2fdf: 0x00c0, 0x2fe0: 0x0080, 0x2fe1: 0x0080, 0x2fe2: 0x0080, 0x2fe3: 0x0080,
+	0x2fed: 0x00c0, 0x2fee: 0x00c0, 0x2fef: 0x00c0,
+	0x2ff0: 0x00c0, 0x2ff1: 0x00c0, 0x2ff2: 0x00c0, 0x2ff3: 0x00c0, 0x2ff4: 0x00c0, 0x2ff5: 0x00c0,
+	0x2ff6: 0x00c0, 0x2ff7: 0x00c0, 0x2ff8: 0x00c0, 0x2ff9: 0x00c0, 0x2ffa: 0x00c0, 0x2ffb: 0x00c0,
+	0x2ffc: 0x00c0, 0x2ffd: 0x00c0, 0x2ffe: 0x00c0, 0x2fff: 0x00c0,
+	// Block 0xc0, offset 0x3000
+	0x3000: 0x00c0, 0x3001: 0x0080, 0x3002: 0x00c0, 0x3003: 0x00c0, 0x3004: 0x00c0, 0x3005: 0x00c0,
+	0x3006: 0x00c0, 0x3007: 0x00c0, 0x3008: 0x00c0, 0x3009: 0x00c0, 0x300a: 0x0080,
+	0x3010: 0x00c0, 0x3011: 0x00c0,
+	0x3012: 0x00c0, 0x3013: 0x00c0, 0x3014: 0x00c0, 0x3015: 0x00c0, 0x3016: 0x00c0, 0x3017: 0x00c0,
+	0x3018: 0x00c0, 0x3019: 0x00c0, 0x301a: 0x00c0, 0x301b: 0x00c0, 0x301c: 0x00c0, 0x301d: 0x00c0,
+	0x301e: 0x00c0, 0x301f: 0x00c0, 0x3020: 0x00c0, 0x3021: 0x00c0, 0x3022: 0x00c0, 0x3023: 0x00c0,
+	0x3024: 0x00c0, 0x3025: 0x00c0, 0x3026: 0x00c0, 0x3027: 0x00c0, 0x3028: 0x00c0, 0x3029: 0x00c0,
+	0x302a: 0x00c0, 0x302b: 0x00c0, 0x302c: 0x00c0, 0x302d: 0x00c0, 0x302e: 0x00c0, 0x302f: 0x00c0,
+	0x3030: 0x00c0, 0x3031: 0x00c0, 0x3032: 0x00c0, 0x3033: 0x00c0, 0x3034: 0x00c0, 0x3035: 0x00c0,
+	0x3036: 0x00c3, 0x3037: 0x00c3, 0x3038: 0x00c3, 0x3039: 0x00c3, 0x303a: 0x00c3,
+	// Block 0xc1, offset 0x3040
+	0x3040: 0x00c0, 0x3041: 0x00c0, 0x3042: 0x00c0, 0x3043: 0x00c0, 0x3044: 0x00c0, 0x3045: 0x00c0,
+	0x3046: 0x00c0, 0x3047: 0x00c0, 0x3048: 0x00c0, 0x3049: 0x00c0, 0x304a: 0x00c0, 0x304b: 0x00c0,
+	0x304c: 0x00c0, 0x304d: 0x00c0, 0x304e: 0x00c0, 0x304f: 0x00c0, 0x3050: 0x00c0, 0x3051: 0x00c0,
+	0x3052: 0x00c0, 0x3053: 0x00c0, 0x3054: 0x00c0, 0x3055: 0x00c0, 0x3056: 0x00c0, 0x3057: 0x00c0,
+	0x3058: 0x00c0, 0x3059: 0x00c0, 0x305a: 0x00c0, 0x305b: 0x00c0, 0x305c: 0x00c0, 0x305d: 0x00c0,
+	0x305f: 0x0080, 0x3060: 0x00c0, 0x3061: 0x00c0, 0x3062: 0x00c0, 0x3063: 0x00c0,
+	0x3064: 0x00c0, 0x3065: 0x00c0, 0x3066: 0x00c0, 0x3067: 0x00c0, 0x3068: 0x00c0, 0x3069: 0x00c0,
+	0x306a: 0x00c0, 0x306b: 0x00c0, 0x306c: 0x00c0, 0x306d: 0x00c0, 0x306e: 0x00c0, 0x306f: 0x00c0,
+	0x3070: 0x00c0, 0x3071: 0x00c0, 0x3072: 0x00c0, 0x3073: 0x00c0, 0x3074: 0x00c0, 0x3075: 0x00c0,
+	0x3076: 0x00c0, 0x3077: 0x00c0, 0x3078: 0x00c0, 0x3079: 0x00c0, 0x307a: 0x00c0, 0x307b: 0x00c0,
+	0x307c: 0x00c0, 0x307d: 0x00c0, 0x307e: 0x00c0, 0x307f: 0x00c0,
+	// Block 0xc2, offset 0x3080
+	0x3080: 0x00c0, 0x3081: 0x00c0, 0x3082: 0x00c0, 0x3083: 0x00c0,
+	0x3088: 0x00c0, 0x3089: 0x00c0, 0x308a: 0x00c0, 0x308b: 0x00c0,
+	0x308c: 0x00c0, 0x308d: 0x00c0, 0x308e: 0x00c0, 0x308f: 0x00c0, 0x3090: 0x0080, 0x3091: 0x0080,
+	0x3092: 0x0080, 0x3093: 0x0080, 0x3094: 0x0080, 0x3095: 0x0080,
+	// Block 0xc3, offset 0x30c0
+	0x30c0: 0x00c0, 0x30c1: 0x00c0, 0x30c2: 0x00c0, 0x30c3: 0x00c0, 0x30c4: 0x00c0, 0x30c5: 0x00c0,
+	0x30c6: 0x00c0, 0x30c7: 0x00c0, 0x30c8: 0x00c0, 0x30c9: 0x00c0, 0x30ca: 0x00c0, 0x30cb: 0x00c0,
+	0x30cc: 0x00c0, 0x30cd: 0x00c0, 0x30ce: 0x00c0, 0x30cf: 0x00c0, 0x30d0: 0x00c0, 0x30d1: 0x00c0,
+	0x30d2: 0x00c0, 0x30d3: 0x00c0, 0x30d4: 0x00c0, 0x30d5: 0x00c0, 0x30d6: 0x00c0, 0x30d7: 0x00c0,
+	0x30d8: 0x00c0, 0x30d9: 0x00c0, 0x30da: 0x00c0, 0x30db: 0x00c0, 0x30dc: 0x00c0, 0x30dd: 0x00c0,
+	0x30e0: 0x00c0, 0x30e1: 0x00c0, 0x30e2: 0x00c0, 0x30e3: 0x00c0,
+	0x30e4: 0x00c0, 0x30e5: 0x00c0, 0x30e6: 0x00c0, 0x30e7: 0x00c0, 0x30e8: 0x00c0, 0x30e9: 0x00c0,
+	0x30f0: 0x00c0, 0x30f1: 0x00c0, 0x30f2: 0x00c0, 0x30f3: 0x00c0, 0x30f4: 0x00c0, 0x30f5: 0x00c0,
+	0x30f6: 0x00c0, 0x30f7: 0x00c0, 0x30f8: 0x00c0, 0x30f9: 0x00c0, 0x30fa: 0x00c0, 0x30fb: 0x00c0,
+	0x30fc: 0x00c0, 0x30fd: 0x00c0, 0x30fe: 0x00c0, 0x30ff: 0x00c0,
+	// Block 0xc4, offset 0x3100
+	0x3100: 0x00c0, 0x3101: 0x00c0, 0x3102: 0x00c0, 0x3103: 0x00c0, 0x3104: 0x00c0, 0x3105: 0x00c0,
+	0x3106: 0x00c0, 0x3107: 0x00c0, 0x3108: 0x00c0, 0x3109: 0x00c0, 0x310a: 0x00c0, 0x310b: 0x00c0,
+	0x310c: 0x00c0, 0x310d: 0x00c0, 0x310e: 0x00c0, 0x310f: 0x00c0, 0x3110: 0x00c0, 0x3111: 0x00c0,
+	0x3112: 0x00c0, 0x3113: 0x00c0,
+	0x3118: 0x00c0, 0x3119: 0x00c0, 0x311a: 0x00c0, 0x311b: 0x00c0, 0x311c: 0x00c0, 0x311d: 0x00c0,
+	0x311e: 0x00c0, 0x311f: 0x00c0, 0x3120: 0x00c0, 0x3121: 0x00c0, 0x3122: 0x00c0, 0x3123: 0x00c0,
+	0x3124: 0x00c0, 0x3125: 0x00c0, 0x3126: 0x00c0, 0x3127: 0x00c0, 0x3128: 0x00c0, 0x3129: 0x00c0,
+	0x312a: 0x00c0, 0x312b: 0x00c0, 0x312c: 0x00c0, 0x312d: 0x00c0, 0x312e: 0x00c0, 0x312f: 0x00c0,
+	0x3130: 0x00c0, 0x3131: 0x00c0, 0x3132: 0x00c0, 0x3133: 0x00c0, 0x3134: 0x00c0, 0x3135: 0x00c0,
+	0x3136: 0x00c0, 0x3137: 0x00c0, 0x3138: 0x00c0, 0x3139: 0x00c0, 0x313a: 0x00c0, 0x313b: 0x00c0,
+	// Block 0xc5, offset 0x3140
+	0x3140: 0x00c0, 0x3141: 0x00c0, 0x3142: 0x00c0, 0x3143: 0x00c0, 0x3144: 0x00c0, 0x3145: 0x00c0,
+	0x3146: 0x00c0, 0x3147: 0x00c0, 0x3148: 0x00c0, 0x3149: 0x00c0, 0x314a: 0x00c0, 0x314b: 0x00c0,
+	0x314c: 0x00c0, 0x314d: 0x00c0, 0x314e: 0x00c0, 0x314f: 0x00c0, 0x3150: 0x00c0, 0x3151: 0x00c0,
+	0x3152: 0x00c0, 0x3153: 0x00c0, 0x3154: 0x00c0, 0x3155: 0x00c0, 0x3156: 0x00c0, 0x3157: 0x00c0,
+	0x3158: 0x00c0, 0x3159: 0x00c0, 0x315a: 0x00c0, 0x315b: 0x00c0, 0x315c: 0x00c0, 0x315d: 0x00c0,
+	0x315e: 0x00c0, 0x315f: 0x00c0, 0x3160: 0x00c0, 0x3161: 0x00c0, 0x3162: 0x00c0, 0x3163: 0x00c0,
+	0x3164: 0x00c0, 0x3165: 0x00c0, 0x3166: 0x00c0, 0x3167: 0x00c0,
+	0x3170: 0x00c0, 0x3171: 0x00c0, 0x3172: 0x00c0, 0x3173: 0x00c0, 0x3174: 0x00c0, 0x3175: 0x00c0,
+	0x3176: 0x00c0, 0x3177: 0x00c0, 0x3178: 0x00c0, 0x3179: 0x00c0, 0x317a: 0x00c0, 0x317b: 0x00c0,
+	0x317c: 0x00c0, 0x317d: 0x00c0, 0x317e: 0x00c0, 0x317f: 0x00c0,
+	// Block 0xc6, offset 0x3180
+	0x3180: 0x00c0, 0x3181: 0x00c0, 0x3182: 0x00c0, 0x3183: 0x00c0, 0x3184: 0x00c0, 0x3185: 0x00c0,
+	0x3186: 0x00c0, 0x3187: 0x00c0, 0x3188: 0x00c0, 0x3189: 0x00c0, 0x318a: 0x00c0, 0x318b: 0x00c0,
+	0x318c: 0x00c0, 0x318d: 0x00c0, 0x318e: 0x00c0, 0x318f: 0x00c0, 0x3190: 0x00c0, 0x3191: 0x00c0,
+	0x3192: 0x00c0, 0x3193: 0x00c0, 0x3194: 0x00c0, 0x3195: 0x00c0, 0x3196: 0x00c0, 0x3197: 0x00c0,
+	0x3198: 0x00c0, 0x3199: 0x00c0, 0x319a: 0x00c0, 0x319b: 0x00c0, 0x319c: 0x00c0, 0x319d: 0x00c0,
+	0x319e: 0x00c0, 0x319f: 0x00c0, 0x31a0: 0x00c0, 0x31a1: 0x00c0, 0x31a2: 0x00c0, 0x31a3: 0x00c0,
+	0x31af: 0x0080,
+	0x31b0: 0x00c0, 0x31b1: 0x00c0, 0x31b2: 0x00c0, 0x31b3: 0x00c0, 0x31b4: 0x00c0, 0x31b5: 0x00c0,
+	0x31b6: 0x00c0, 0x31b7: 0x00c0, 0x31b8: 0x00c0, 0x31b9: 0x00c0, 0x31ba: 0x00c0,
+	0x31bc: 0x00c0, 0x31bd: 0x00c0, 0x31be: 0x00c0, 0x31bf: 0x00c0,
+	// Block 0xc7, offset 0x31c0
+	0x31c0: 0x00c0, 0x31c1: 0x00c0, 0x31c2: 0x00c0, 0x31c3: 0x00c0, 0x31c4: 0x00c0, 0x31c5: 0x00c0,
+	0x31c6: 0x00c0, 0x31c7: 0x00c0, 0x31c8: 0x00c0, 0x31c9: 0x00c0, 0x31ca: 0x00c0,
+	0x31cc: 0x00c0, 0x31cd: 0x00c0, 0x31ce: 0x00c0, 0x31cf: 0x00c0, 0x31d0: 0x00c0, 0x31d1: 0x00c0,
+	0x31d2: 0x00c0, 0x31d4: 0x00c0, 0x31d5: 0x00c0, 0x31d7: 0x00c0,
+	0x31d8: 0x00c0, 0x31d9: 0x00c0, 0x31da: 0x00c0, 0x31db: 0x00c0, 0x31dc: 0x00c0, 0x31dd: 0x00c0,
+	0x31de: 0x00c0, 0x31df: 0x00c0, 0x31e0: 0x00c0, 0x31e1: 0x00c0, 0x31e3: 0x00c0,
+	0x31e4: 0x00c0, 0x31e5: 0x00c0, 0x31e6: 0x00c0, 0x31e7: 0x00c0, 0x31e8: 0x00c0, 0x31e9: 0x00c0,
+	0x31ea: 0x00c0, 0x31eb: 0x00c0, 0x31ec: 0x00c0, 0x31ed: 0x00c0, 0x31ee: 0x00c0, 0x31ef: 0x00c0,
+	0x31f0: 0x00c0, 0x31f1: 0x00c0, 0x31f3: 0x00c0, 0x31f4: 0x00c0, 0x31f5: 0x00c0,
+	0x31f6: 0x00c0, 0x31f7: 0x00c0, 0x31f8: 0x00c0, 0x31f9: 0x00c0, 0x31fb: 0x00c0,
+	0x31fc: 0x00c0,
+	// Block 0xc8, offset 0x3200
+	0x3200: 0x00c0, 0x3201: 0x00c0, 0x3202: 0x00c0, 0x3203: 0x00c0, 0x3204: 0x00c0, 0x3205: 0x00c0,
+	0x3206: 0x00c0, 0x3207: 0x00c0, 0x3208: 0x00c0, 0x3209: 0x00c0, 0x320a: 0x00c0, 0x320b: 0x00c0,
+	0x320c: 0x00c0, 0x320d: 0x00c0, 0x320e: 0x00c0, 0x320f: 0x00c0, 0x3210: 0x00c0, 0x3211: 0x00c0,
+	0x3212: 0x00c0, 0x3213: 0x00c0, 0x3214: 0x00c0, 0x3215: 0x00c0, 0x3216: 0x00c0, 0x3217: 0x00c0,
+	0x3218: 0x00c0, 0x3219: 0x00c0, 0x321a: 0x00c0, 0x321b: 0x00c0, 0x321c: 0x00c0, 0x321d: 0x00c0,
+	0x321e: 0x00c0, 0x321f: 0x00c0, 0x3220: 0x00c0, 0x3221: 0x00c0, 0x3222: 0x00c0, 0x3223: 0x00c0,
+	0x3224: 0x00c0, 0x3225: 0x00c0, 0x3226: 0x00c0, 0x3227: 0x00c0, 0x3228: 0x00c0, 0x3229: 0x00c0,
+	0x322a: 0x00c0, 0x322b: 0x00c0, 0x322c: 0x00c0, 0x322d: 0x00c0, 0x322e: 0x00c0, 0x322f: 0x00c0,
+	0x3230: 0x00c0, 0x3231: 0x00c0, 0x3232: 0x00c0, 0x3233: 0x00c0,
+	// Block 0xc9, offset 0x3240
+	0x3240: 0x00c0, 0x3241: 0x00c0, 0x3242: 0x00c0, 0x3243: 0x00c0, 0x3244: 0x00c0, 0x3245: 0x00c0,
+	0x3246: 0x00c0, 0x3247: 0x00c0, 0x3248: 0x00c0, 0x3249: 0x00c0, 0x324a: 0x00c0, 0x324b: 0x00c0,
+	0x324c: 0x00c0, 0x324d: 0x00c0, 0x324e: 0x00c0, 0x324f: 0x00c0, 0x3250: 0x00c0, 0x3251: 0x00c0,
+	0x3252: 0x00c0, 0x3253: 0x00c0, 0x3254: 0x00c0, 0x3255: 0x00c0, 0x3256: 0x00c0, 0x3257: 0x00c0,
+	0x3258: 0x00c0, 0x3259: 0x00c0, 0x325a: 0x00c0, 0x325b: 0x00c0, 0x325c: 0x00c0, 0x325d: 0x00c0,
+	0x325e: 0x00c0, 0x325f: 0x00c0, 0x3260: 0x00c0, 0x3261: 0x00c0, 0x3262: 0x00c0, 0x3263: 0x00c0,
+	0x3264: 0x00c0, 0x3265: 0x00c0, 0x3266: 0x00c0, 0x3267: 0x00c0, 0x3268: 0x00c0, 0x3269: 0x00c0,
+	0x326a: 0x00c0, 0x326b: 0x00c0, 0x326c: 0x00c0, 0x326d: 0x00c0, 0x326e: 0x00c0, 0x326f: 0x00c0,
+	0x3270: 0x00c0, 0x3271: 0x00c0, 0x3272: 0x00c0, 0x3273: 0x00c0, 0x3274: 0x00c0, 0x3275: 0x00c0,
+	0x3276: 0x00c0,
+	// Block 0xca, offset 0x3280
+	0x3280: 0x00c0, 0x3281: 0x00c0, 0x3282: 0x00c0, 0x3283: 0x00c0, 0x3284: 0x00c0, 0x3285: 0x00c0,
+	0x3286: 0x00c0, 0x3287: 0x00c0, 0x3288: 0x00c0, 0x3289: 0x00c0, 0x328a: 0x00c0, 0x328b: 0x00c0,
+	0x328c: 0x00c0, 0x328d: 0x00c0, 0x328e: 0x00c0, 0x328f: 0x00c0, 0x3290: 0x00c0, 0x3291: 0x00c0,
+	0x3292: 0x00c0, 0x3293: 0x00c0, 0x3294: 0x00c0, 0x3295: 0x00c0,
+	0x32a0: 0x00c0, 0x32a1: 0x00c0, 0x32a2: 0x00c0, 0x32a3: 0x00c0,
+	0x32a4: 0x00c0, 0x32a5: 0x00c0, 0x32a6: 0x00c0, 0x32a7: 0x00c0,
+	// Block 0xcb, offset 0x32c0
+	0x32c0: 0x00c0, 0x32c1: 0x0080, 0x32c2: 0x0080, 0x32c3: 0x0080, 0x32c4: 0x0080, 0x32c5: 0x0080,
+	0x32c7: 0x0080, 0x32c8: 0x0080, 0x32c9: 0x0080, 0x32ca: 0x0080, 0x32cb: 0x0080,
+	0x32cc: 0x0080, 0x32cd: 0x0080, 0x32ce: 0x0080, 0x32cf: 0x0080, 0x32d0: 0x0080, 0x32d1: 0x0080,
+	0x32d2: 0x0080, 0x32d3: 0x0080, 0x32d4: 0x0080, 0x32d5: 0x0080, 0x32d6: 0x0080, 0x32d7: 0x0080,
+	0x32d8: 0x0080, 0x32d9: 0x0080, 0x32da: 0x0080, 0x32db: 0x0080, 0x32dc: 0x0080, 0x32dd: 0x0080,
+	0x32de: 0x0080, 0x32df: 0x0080, 0x32e0: 0x0080, 0x32e1: 0x0080, 0x32e2: 0x0080, 0x32e3: 0x0080,
+	0x32e4: 0x0080, 0x32e5: 0x0080, 0x32e6: 0x0080, 0x32e7: 0x0080, 0x32e8: 0x0080, 0x32e9: 0x0080,
+	0x32ea: 0x0080, 0x32eb: 0x0080, 0x32ec: 0x0080, 0x32ed: 0x0080, 0x32ee: 0x0080, 0x32ef: 0x0080,
+	0x32f0: 0x0080, 0x32f2: 0x0080, 0x32f3: 0x0080, 0x32f4: 0x0080, 0x32f5: 0x0080,
+	0x32f6: 0x0080, 0x32f7: 0x0080, 0x32f8: 0x0080, 0x32f9: 0x0080, 0x32fa: 0x0080,
+	// Block 0xcc, offset 0x3300
+	0x3300: 0x00c0, 0x3301: 0x00c0, 0x3302: 0x00c0, 0x3303: 0x00c0, 0x3304: 0x00c0, 0x3305: 0x00c0,
+	0x3308: 0x00c0, 0x330a: 0x00c0, 0x330b: 0x00c0,
+	0x330c: 0x00c0, 0x330d: 0x00c0, 0x330e: 0x00c0, 0x330f: 0x00c0, 0x3310: 0x00c0, 0x3311: 0x00c0,
+	0x3312: 0x00c0, 0x3313: 0x00c0, 0x3314: 0x00c0, 0x3315: 0x00c0, 0x3316: 0x00c0, 0x3317: 0x00c0,
+	0x3318: 0x00c0, 0x3319: 0x00c0, 0x331a: 0x00c0, 0x331b: 0x00c0, 0x331c: 0x00c0, 0x331d: 0x00c0,
+	0x331e: 0x00c0, 0x331f: 0x00c0, 0x3320: 0x00c0, 0x3321: 0x00c0, 0x3322: 0x00c0, 0x3323: 0x00c0,
+	0x3324: 0x00c0, 0x3325: 0x00c0, 0x3326: 0x00c0, 0x3327: 0x00c0, 0x3328: 0x00c0, 0x3329: 0x00c0,
+	0x332a: 0x00c0, 0x332b: 0x00c0, 0x332c: 0x00c0, 0x332d: 0x00c0, 0x332e: 0x00c0, 0x332f: 0x00c0,
+	0x3330: 0x00c0, 0x3331: 0x00c0, 0x3332: 0x00c0, 0x3333: 0x00c0, 0x3334: 0x00c0, 0x3335: 0x00c0,
+	0x3337: 0x00c0, 0x3338: 0x00c0,
+	0x333c: 0x00c0, 0x333f: 0x00c0,
+	// Block 0xcd, offset 0x3340
+	0x3340: 0x00c0, 0x3341: 0x00c0, 0x3342: 0x00c0, 0x3343: 0x00c0, 0x3344: 0x00c0, 0x3345: 0x00c0,
+	0x3346: 0x00c0, 0x3347: 0x00c0, 0x3348: 0x00c0, 0x3349: 0x00c0, 0x334a: 0x00c0, 0x334b: 0x00c0,
+	0x334c: 0x00c0, 0x334d: 0x00c0, 0x334e: 0x00c0, 0x334f: 0x00c0, 0x3350: 0x00c0, 0x3351: 0x00c0,
+	0x3352: 0x00c0, 0x3353: 0x00c0, 0x3354: 0x00c0, 0x3355: 0x00c0, 0x3357: 0x0080,
+	0x3358: 0x0080, 0x3359: 0x0080, 0x335a: 0x0080, 0x335b: 0x0080, 0x335c: 0x0080, 0x335d: 0x0080,
+	0x335e: 0x0080, 0x335f: 0x0080, 0x3360: 0x00c0, 0x3361: 0x00c0, 0x3362: 0x00c0, 0x3363: 0x00c0,
+	0x3364: 0x00c0, 0x3365: 0x00c0, 0x3366: 0x00c0, 0x3367: 0x00c0, 0x3368: 0x00c0, 0x3369: 0x00c0,
+	0x336a: 0x00c0, 0x336b: 0x00c0, 0x336c: 0x00c0, 0x336d: 0x00c0, 0x336e: 0x00c0, 0x336f: 0x00c0,
+	0x3370: 0x00c0, 0x3371: 0x00c0, 0x3372: 0x00c0, 0x3373: 0x00c0, 0x3374: 0x00c0, 0x3375: 0x00c0,
+	0x3376: 0x00c0, 0x3377: 0x0080, 0x3378: 0x0080, 0x3379: 0x0080, 0x337a: 0x0080, 0x337b: 0x0080,
+	0x337c: 0x0080, 0x337d: 0x0080, 0x337e: 0x0080, 0x337f: 0x0080,
+	// Block 0xce, offset 0x3380
+	0x3380: 0x00c0, 0x3381: 0x00c0, 0x3382: 0x00c0, 0x3383: 0x00c0, 0x3384: 0x00c0, 0x3385: 0x00c0,
+	0x3386: 0x00c0, 0x3387: 0x00c0, 0x3388: 0x00c0, 0x3389: 0x00c0, 0x338a: 0x00c0, 0x338b: 0x00c0,
+	0x338c: 0x00c0, 0x338d: 0x00c0, 0x338e: 0x00c0, 0x338f: 0x00c0, 0x3390: 0x00c0, 0x3391: 0x00c0,
+	0x3392: 0x00c0, 0x3393: 0x00c0, 0x3394: 0x00c0, 0x3395: 0x00c0, 0x3396: 0x00c0, 0x3397: 0x00c0,
+	0x3398: 0x00c0, 0x3399: 0x00c0, 0x339a: 0x00c0, 0x339b: 0x00c0, 0x339c: 0x00c0, 0x339d: 0x00c0,
+	0x339e: 0x00c0,
+	0x33a7: 0x0080, 0x33a8: 0x0080, 0x33a9: 0x0080,
+	0x33aa: 0x0080, 0x33ab: 0x0080, 0x33ac: 0x0080, 0x33ad: 0x0080, 0x33ae: 0x0080, 0x33af: 0x0080,
+	// Block 0xcf, offset 0x33c0
+	0x33e0: 0x00c0, 0x33e1: 0x00c0, 0x33e2: 0x00c0, 0x33e3: 0x00c0,
+	0x33e4: 0x00c0, 0x33e5: 0x00c0, 0x33e6: 0x00c0, 0x33e7: 0x00c0, 0x33e8: 0x00c0, 0x33e9: 0x00c0,
+	0x33ea: 0x00c0, 0x33eb: 0x00c0, 0x33ec: 0x00c0, 0x33ed: 0x00c0, 0x33ee: 0x00c0, 0x33ef: 0x00c0,
+	0x33f0: 0x00c0, 0x33f1: 0x00c0, 0x33f2: 0x00c0, 0x33f4: 0x00c0, 0x33f5: 0x00c0,
+	0x33fb: 0x0080,
+	0x33fc: 0x0080, 0x33fd: 0x0080, 0x33fe: 0x0080, 0x33ff: 0x0080,
+	// Block 0xd0, offset 0x3400
+	0x3400: 0x00c0, 0x3401: 0x00c0, 0x3402: 0x00c0, 0x3403: 0x00c0, 0x3404: 0x00c0, 0x3405: 0x00c0,
+	0x3406: 0x00c0, 0x3407: 0x00c0, 0x3408: 0x00c0, 0x3409: 0x00c0, 0x340a: 0x00c0, 0x340b: 0x00c0,
+	0x340c: 0x00c0, 0x340d: 0x00c0, 0x340e: 0x00c0, 0x340f: 0x00c0, 0x3410: 0x00c0, 0x3411: 0x00c0,
+	0x3412: 0x00c0, 0x3413: 0x00c0, 0x3414: 0x00c0, 0x3415: 0x00c0, 0x3416: 0x0080, 0x3417: 0x0080,
+	0x3418: 0x0080, 0x3419: 0x0080, 0x341a: 0x0080, 0x341b: 0x0080,
+	0x341f: 0x0080, 0x3420: 0x00c0, 0x3421: 0x00c0, 0x3422: 0x00c0, 0x3423: 0x00c0,
+	0x3424: 0x00c0, 0x3425: 0x00c0, 0x3426: 0x00c0, 0x3427: 0x00c0, 0x3428: 0x00c0, 0x3429: 0x00c0,
+	0x342a: 0x00c0, 0x342b: 0x00c0, 0x342c: 0x00c0, 0x342d: 0x00c0, 0x342e: 0x00c0, 0x342f: 0x00c0,
+	0x3430: 0x00c0, 0x3431: 0x00c0, 0x3432: 0x00c0, 0x3433: 0x00c0, 0x3434: 0x00c0, 0x3435: 0x00c0,
+	0x3436: 0x00c0, 0x3437: 0x00c0, 0x3438: 0x00c0, 0x3439: 0x00c0,
+	0x343f: 0x0080,
+	// Block 0xd1, offset 0x3440
+	0x3440: 0x00c0, 0x3441: 0x00c0, 0x3442: 0x00c0, 0x3443: 0x00c0, 0x3444: 0x00c0, 0x3445: 0x00c0,
+	0x3446: 0x00c0, 0x3447: 0x00c0, 0x3448: 0x00c0, 0x3449: 0x00c0, 0x344a: 0x00c0, 0x344b: 0x00c0,
+	0x344c: 0x00c0, 0x344d: 0x00c0, 0x344e: 0x00c0, 0x344f: 0x00c0, 0x3450: 0x00c0, 0x3451: 0x00c0,
+	0x3452: 0x00c0, 0x3453: 0x00c0, 0x3454: 0x00c0, 0x3455: 0x00c0, 0x3456: 0x00c0, 0x3457: 0x00c0,
+	0x3458: 0x00c0, 0x3459: 0x00c0,
+	// Block 0xd2, offset 0x3480
+	0x3480: 0x00c0, 0x3481: 0x00c0, 0x3482: 0x00c0, 0x3483: 0x00c0, 0x3484: 0x00c0, 0x3485: 0x00c0,
+	0x3486: 0x00c0, 0x3487: 0x00c0, 0x3488: 0x00c0, 0x3489: 0x00c0, 0x348a: 0x00c0, 0x348b: 0x00c0,
+	0x348c: 0x00c0, 0x348d: 0x00c0, 0x348e: 0x00c0, 0x348f: 0x00c0, 0x3490: 0x00c0, 0x3491: 0x00c0,
+	0x3492: 0x00c0, 0x3493: 0x00c0, 0x3494: 0x00c0, 0x3495: 0x00c0, 0x3496: 0x00c0, 0x3497: 0x00c0,
+	0x3498: 0x00c0, 0x3499: 0x00c0, 0x349a: 0x00c0, 0x349b: 0x00c0, 0x349c: 0x00c0, 0x349d: 0x00c0,
+	0x349e: 0x00c0, 0x349f: 0x00c0, 0x34a0: 0x00c0, 0x34a1: 0x00c0, 0x34a2: 0x00c0, 0x34a3: 0x00c0,
+	0x34a4: 0x00c0, 0x34a5: 0x00c0, 0x34a6: 0x00c0, 0x34a7: 0x00c0, 0x34a8: 0x00c0, 0x34a9: 0x00c0,
+	0x34aa: 0x00c0, 0x34ab: 0x00c0, 0x34ac: 0x00c0, 0x34ad: 0x00c0, 0x34ae: 0x00c0, 0x34af: 0x00c0,
+	0x34b0: 0x00c0, 0x34b1: 0x00c0, 0x34b2: 0x00c0, 0x34b3: 0x00c0, 0x34b4: 0x00c0, 0x34b5: 0x00c0,
+	0x34b6: 0x00c0, 0x34b7: 0x00c0,
+	0x34bc: 0x0080, 0x34bd: 0x0080, 0x34be: 0x00c0, 0x34bf: 0x00c0,
+	// Block 0xd3, offset 0x34c0
+	0x34c0: 0x0080, 0x34c1: 0x0080, 0x34c2: 0x0080, 0x34c3: 0x0080, 0x34c4: 0x0080, 0x34c5: 0x0080,
+	0x34c6: 0x0080, 0x34c7: 0x0080, 0x34c8: 0x0080, 0x34c9: 0x0080, 0x34ca: 0x0080, 0x34cb: 0x0080,
+	0x34cc: 0x0080, 0x34cd: 0x0080, 0x34ce: 0x0080, 0x34cf: 0x0080,
+	0x34d2: 0x0080, 0x34d3: 0x0080, 0x34d4: 0x0080, 0x34d5: 0x0080, 0x34d6: 0x0080, 0x34d7: 0x0080,
+	0x34d8: 0x0080, 0x34d9: 0x0080, 0x34da: 0x0080, 0x34db: 0x0080, 0x34dc: 0x0080, 0x34dd: 0x0080,
+	0x34de: 0x0080, 0x34df: 0x0080, 0x34e0: 0x0080, 0x34e1: 0x0080, 0x34e2: 0x0080, 0x34e3: 0x0080,
+	0x34e4: 0x0080, 0x34e5: 0x0080, 0x34e6: 0x0080, 0x34e7: 0x0080, 0x34e8: 0x0080, 0x34e9: 0x0080,
+	0x34ea: 0x0080, 0x34eb: 0x0080, 0x34ec: 0x0080, 0x34ed: 0x0080, 0x34ee: 0x0080, 0x34ef: 0x0080,
+	0x34f0: 0x0080, 0x34f1: 0x0080, 0x34f2: 0x0080, 0x34f3: 0x0080, 0x34f4: 0x0080, 0x34f5: 0x0080,
+	0x34f6: 0x0080, 0x34f7: 0x0080, 0x34f8: 0x0080, 0x34f9: 0x0080, 0x34fa: 0x0080, 0x34fb: 0x0080,
+	0x34fc: 0x0080, 0x34fd: 0x0080, 0x34fe: 0x0080, 0x34ff: 0x0080,
+	// Block 0xd4, offset 0x3500
+	0x3500: 0x00c0, 0x3501: 0x00c3, 0x3502: 0x00c3, 0x3503: 0x00c3, 0x3505: 0x00c3,
+	0x3506: 0x00c3,
+	0x350c: 0x00c3, 0x350d: 0x00c3, 0x350e: 0x00c3, 0x350f: 0x00c3, 0x3510: 0x00c0, 0x3511: 0x00c0,
+	0x3512: 0x00c0, 0x3513: 0x00c0, 0x3515: 0x00c0, 0x3516: 0x00c0, 0x3517: 0x00c0,
+	0x3519: 0x00c0, 0x351a: 0x00c0, 0x351b: 0x00c0, 0x351c: 0x00c0, 0x351d: 0x00c0,
+	0x351e: 0x00c0, 0x351f: 0x00c0, 0x3520: 0x00c0, 0x3521: 0x00c0, 0x3522: 0x00c0, 0x3523: 0x00c0,
+	0x3524: 0x00c0, 0x3525: 0x00c0, 0x3526: 0x00c0, 0x3527: 0x00c0, 0x3528: 0x00c0, 0x3529: 0x00c0,
+	0x352a: 0x00c0, 0x352b: 0x00c0, 0x352c: 0x00c0, 0x352d: 0x00c0, 0x352e: 0x00c0, 0x352f: 0x00c0,
+	0x3530: 0x00c0, 0x3531: 0x00c0, 0x3532: 0x00c0, 0x3533: 0x00c0, 0x3534: 0x00c0, 0x3535: 0x00c0,
+	0x3538: 0x00c3, 0x3539: 0x00c3, 0x353a: 0x00c3,
+	0x353f: 0x00c6,
+	// Block 0xd5, offset 0x3540
+	0x3540: 0x0080, 0x3541: 0x0080, 0x3542: 0x0080, 0x3543: 0x0080, 0x3544: 0x0080, 0x3545: 0x0080,
+	0x3546: 0x0080, 0x3547: 0x0080, 0x3548: 0x0080,
+	0x3550: 0x0080, 0x3551: 0x0080,
+	0x3552: 0x0080, 0x3553: 0x0080, 0x3554: 0x0080, 0x3555: 0x0080, 0x3556: 0x0080, 0x3557: 0x0080,
+	0x3558: 0x0080,
+	0x3560: 0x00c0, 0x3561: 0x00c0, 0x3562: 0x00c0, 0x3563: 0x00c0,
+	0x3564: 0x00c0, 0x3565: 0x00c0, 0x3566: 0x00c0, 0x3567: 0x00c0, 0x3568: 0x00c0, 0x3569: 0x00c0,
+	0x356a: 0x00c0, 0x356b: 0x00c0, 0x356c: 0x00c0, 0x356d: 0x00c0, 0x356e: 0x00c0, 0x356f: 0x00c0,
+	0x3570: 0x00c0, 0x3571: 0x00c0, 0x3572: 0x00c0, 0x3573: 0x00c0, 0x3574: 0x00c0, 0x3575: 0x00c0,
+	0x3576: 0x00c0, 0x3577: 0x00c0, 0x3578: 0x00c0, 0x3579: 0x00c0, 0x357a: 0x00c0, 0x357b: 0x00c0,
+	0x357c: 0x00c0, 0x357d: 0x0080, 0x357e: 0x0080, 0x357f: 0x0080,
+	// Block 0xd6, offset 0x3580
+	0x3580: 0x00c0, 0x3581: 0x00c0, 0x3582: 0x00c0, 0x3583: 0x00c0, 0x3584: 0x00c0, 0x3585: 0x00c0,
+	0x3586: 0x00c0, 0x3587: 0x00c0, 0x3588: 0x00c0, 0x3589: 0x00c0, 0x358a: 0x00c0, 0x358b: 0x00c0,
+	0x358c: 0x00c0, 0x358d: 0x00c0, 0x358e: 0x00c0, 0x358f: 0x00c0, 0x3590: 0x00c0, 0x3591: 0x00c0,
+	0x3592: 0x00c0, 0x3593: 0x00c0, 0x3594: 0x00c0, 0x3595: 0x00c0, 0x3596: 0x00c0, 0x3597: 0x00c0,
+	0x3598: 0x00c0, 0x3599: 0x00c0, 0x359a: 0x00c0, 0x359b: 0x00c0, 0x359c: 0x00c0, 0x359d: 0x0080,
+	0x359e: 0x0080, 0x359f: 0x0080,
+	// Block 0xd7, offset 0x35c0
+	0x35c0: 0x00c2, 0x35c1: 0x00c2, 0x35c2: 0x00c2, 0x35c3: 0x00c2, 0x35c4: 0x00c2, 0x35c5: 0x00c4,
+	0x35c6: 0x00c0, 0x35c7: 0x00c4, 0x35c8: 0x0080, 0x35c9: 0x00c4, 0x35ca: 0x00c4, 0x35cb: 0x00c0,
+	0x35cc: 0x00c0, 0x35cd: 0x00c1, 0x35ce: 0x00c4, 0x35cf: 0x00c4, 0x35d0: 0x00c4, 0x35d1: 0x00c4,
+	0x35d2: 0x00c4, 0x35d3: 0x00c2, 0x35d4: 0x00c2, 0x35d5: 0x00c2, 0x35d6: 0x00c2, 0x35d7: 0x00c1,
+	0x35d8: 0x00c2, 0x35d9: 0x00c2, 0x35da: 0x00c2, 0x35db: 0x00c2, 0x35dc: 0x00c2, 0x35dd: 0x00c4,
+	0x35de: 0x00c2, 0x35df: 0x00c2, 0x35e0: 0x00c2, 0x35e1: 0x00c4, 0x35e2: 0x00c0, 0x35e3: 0x00c0,
+	0x35e4: 0x00c4, 0x35e5: 0x00c3, 0x35e6: 0x00c3,
+	0x35eb: 0x0082, 0x35ec: 0x0082, 0x35ed: 0x0082, 0x35ee: 0x0082, 0x35ef: 0x0084,
+	0x35f0: 0x0080, 0x35f1: 0x0080, 0x35f2: 0x0080, 0x35f3: 0x0080, 0x35f4: 0x0080, 0x35f5: 0x0080,
+	0x35f6: 0x0080,
+	// Block 0xd8, offset 0x3600
+	0x3600: 0x00c0, 0x3601: 0x00c0, 0x3602: 0x00c0, 0x3603: 0x00c0, 0x3604: 0x00c0, 0x3605: 0x00c0,
+	0x3606: 0x00c0, 0x3607: 0x00c0, 0x3608: 0x00c0, 0x3609: 0x00c0, 0x360a: 0x00c0, 0x360b: 0x00c0,
+	0x360c: 0x00c0, 0x360d: 0x00c0, 0x360e: 0x00c0, 0x360f: 0x00c0, 0x3610: 0x00c0, 0x3611: 0x00c0,
+	0x3612: 0x00c0, 0x3613: 0x00c0, 0x3614: 0x00c0, 0x3615: 0x00c0, 0x3616: 0x00c0, 0x3617: 0x00c0,
+	0x3618: 0x00c0, 0x3619: 0x00c0, 0x361a: 0x00c0, 0x361b: 0x00c0, 0x361c: 0x00c0, 0x361d: 0x00c0,
+	0x361e: 0x00c0, 0x361f: 0x00c0, 0x3620: 0x00c0, 0x3621: 0x00c0, 0x3622: 0x00c0, 0x3623: 0x00c0,
+	0x3624: 0x00c0, 0x3625: 0x00c0, 0x3626: 0x00c0, 0x3627: 0x00c0, 0x3628: 0x00c0, 0x3629: 0x00c0,
+	0x362a: 0x00c0, 0x362b: 0x00c0, 0x362c: 0x00c0, 0x362d: 0x00c0, 0x362e: 0x00c0, 0x362f: 0x00c0,
+	0x3630: 0x00c0, 0x3631: 0x00c0, 0x3632: 0x00c0, 0x3633: 0x00c0, 0x3634: 0x00c0, 0x3635: 0x00c0,
+	0x3639: 0x0080, 0x363a: 0x0080, 0x363b: 0x0080,
+	0x363c: 0x0080, 0x363d: 0x0080, 0x363e: 0x0080, 0x363f: 0x0080,
+	// Block 0xd9, offset 0x3640
+	0x3640: 0x00c0, 0x3641: 0x00c0, 0x3642: 0x00c0, 0x3643: 0x00c0, 0x3644: 0x00c0, 0x3645: 0x00c0,
+	0x3646: 0x00c0, 0x3647: 0x00c0, 0x3648: 0x00c0, 0x3649: 0x00c0, 0x364a: 0x00c0, 0x364b: 0x00c0,
+	0x364c: 0x00c0, 0x364d: 0x00c0, 0x364e: 0x00c0, 0x364f: 0x00c0, 0x3650: 0x00c0, 0x3651: 0x00c0,
+	0x3652: 0x00c0, 0x3653: 0x00c0, 0x3654: 0x00c0, 0x3655: 0x00c0,
+	0x3658: 0x0080, 0x3659: 0x0080, 0x365a: 0x0080, 0x365b: 0x0080, 0x365c: 0x0080, 0x365d: 0x0080,
+	0x365e: 0x0080, 0x365f: 0x0080, 0x3660: 0x00c0, 0x3661: 0x00c0, 0x3662: 0x00c0, 0x3663: 0x00c0,
+	0x3664: 0x00c0, 0x3665: 0x00c0, 0x3666: 0x00c0, 0x3667: 0x00c0, 0x3668: 0x00c0, 0x3669: 0x00c0,
+	0x366a: 0x00c0, 0x366b: 0x00c0, 0x366c: 0x00c0, 0x366d: 0x00c0, 0x366e: 0x00c0, 0x366f: 0x00c0,
+	0x3670: 0x00c0, 0x3671: 0x00c0, 0x3672: 0x00c0,
+	0x3678: 0x0080, 0x3679: 0x0080, 0x367a: 0x0080, 0x367b: 0x0080,
+	0x367c: 0x0080, 0x367d: 0x0080, 0x367e: 0x0080, 0x367f: 0x0080,
+	// Block 0xda, offset 0x3680
+	0x3680: 0x00c2, 0x3681: 0x00c4, 0x3682: 0x00c2, 0x3683: 0x00c4, 0x3684: 0x00c4, 0x3685: 0x00c4,
+	0x3686: 0x00c2, 0x3687: 0x00c2, 0x3688: 0x00c2, 0x3689: 0x00c4, 0x368a: 0x00c2, 0x368b: 0x00c2,
+	0x368c: 0x00c4, 0x368d: 0x00c2, 0x368e: 0x00c4, 0x368f: 0x00c4, 0x3690: 0x00c2, 0x3691: 0x00c4,
+	0x3699: 0x0080, 0x369a: 0x0080, 0x369b: 0x0080, 0x369c: 0x0080,
+	0x36a9: 0x0084,
+	0x36aa: 0x0084, 0x36ab: 0x0084, 0x36ac: 0x0084, 0x36ad: 0x0082, 0x36ae: 0x0082, 0x36af: 0x0080,
+	// Block 0xdb, offset 0x36c0
+	0x36c0: 0x00c0, 0x36c1: 0x00c0, 0x36c2: 0x00c0, 0x36c3: 0x00c0, 0x36c4: 0x00c0, 0x36c5: 0x00c0,
+	0x36c6: 0x00c0, 0x36c7: 0x00c0, 0x36c8: 0x00c0,
+	// Block 0xdc, offset 0x3700
+	0x3700: 0x00c0, 0x3701: 0x00c0, 0x3702: 0x00c0, 0x3703: 0x00c0, 0x3704: 0x00c0, 0x3705: 0x00c0,
+	0x3706: 0x00c0, 0x3707: 0x00c0, 0x3708: 0x00c0, 0x3709: 0x00c0, 0x370a: 0x00c0, 0x370b: 0x00c0,
+	0x370c: 0x00c0, 0x370d: 0x00c0, 0x370e: 0x00c0, 0x370f: 0x00c0, 0x3710: 0x00c0, 0x3711: 0x00c0,
+	0x3712: 0x00c0, 0x3713: 0x00c0, 0x3714: 0x00c0, 0x3715: 0x00c0, 0x3716: 0x00c0, 0x3717: 0x00c0,
+	0x3718: 0x00c0, 0x3719: 0x00c0, 0x371a: 0x00c0, 0x371b: 0x00c0, 0x371c: 0x00c0, 0x371d: 0x00c0,
+	0x371e: 0x00c0, 0x371f: 0x00c0, 0x3720: 0x00c0, 0x3721: 0x00c0, 0x3722: 0x00c0, 0x3723: 0x00c0,
+	0x3724: 0x00c0, 0x3725: 0x00c0, 0x3726: 0x00c0, 0x3727: 0x00c0, 0x3728: 0x00c0, 0x3729: 0x00c0,
+	0x372a: 0x00c0, 0x372b: 0x00c0, 0x372c: 0x00c0, 0x372d: 0x00c0, 0x372e: 0x00c0, 0x372f: 0x00c0,
+	0x3730: 0x00c0, 0x3731: 0x00c0, 0x3732: 0x00c0,
+	// Block 0xdd, offset 0x3740
+	0x3740: 0x00c0, 0x3741: 0x00c0, 0x3742: 0x00c0, 0x3743: 0x00c0, 0x3744: 0x00c0, 0x3745: 0x00c0,
+	0x3746: 0x00c0, 0x3747: 0x00c0, 0x3748: 0x00c0, 0x3749: 0x00c0, 0x374a: 0x00c0, 0x374b: 0x00c0,
+	0x374c: 0x00c0, 0x374d: 0x00c0, 0x374e: 0x00c0, 0x374f: 0x00c0, 0x3750: 0x00c0, 0x3751: 0x00c0,
+	0x3752: 0x00c0, 0x3753: 0x00c0, 0x3754: 0x00c0, 0x3755: 0x00c0, 0x3756: 0x00c0, 0x3757: 0x00c0,
+	0x3758: 0x00c0, 0x3759: 0x00c0, 0x375a: 0x00c0, 0x375b: 0x00c0, 0x375c: 0x00c0, 0x375d: 0x00c0,
+	0x375e: 0x00c0, 0x375f: 0x00c0, 0x3760: 0x00c0, 0x3761: 0x00c0, 0x3762: 0x00c0, 0x3763: 0x00c0,
+	0x3764: 0x00c0, 0x3765: 0x00c0, 0x3766: 0x00c0, 0x3767: 0x00c0, 0x3768: 0x00c0, 0x3769: 0x00c0,
+	0x376a: 0x00c0, 0x376b: 0x00c0, 0x376c: 0x00c0, 0x376d: 0x00c0, 0x376e: 0x00c0, 0x376f: 0x00c0,
+	0x3770: 0x00c0, 0x3771: 0x00c0, 0x3772: 0x00c0,
+	0x377a: 0x0080, 0x377b: 0x0080,
+	0x377c: 0x0080, 0x377d: 0x0080, 0x377e: 0x0080, 0x377f: 0x0080,
+	// Block 0xde, offset 0x3780
+	0x3780: 0x00c1, 0x3781: 0x00c2, 0x3782: 0x00c2, 0x3783: 0x00c2, 0x3784: 0x00c2, 0x3785: 0x00c2,
+	0x3786: 0x00c2, 0x3787: 0x00c2, 0x3788: 0x00c2, 0x3789: 0x00c2, 0x378a: 0x00c2, 0x378b: 0x00c2,
+	0x378c: 0x00c2, 0x378d: 0x00c2, 0x378e: 0x00c2, 0x378f: 0x00c2, 0x3790: 0x00c2, 0x3791: 0x00c2,
+	0x3792: 0x00c2, 0x3793: 0x00c2, 0x3794: 0x00c2, 0x3795: 0x00c2, 0x3796: 0x00c2, 0x3797: 0x00c2,
+	0x3798: 0x00c2, 0x3799: 0x00c2, 0x379a: 0x00c2, 0x379b: 0x00c2, 0x379c: 0x00c2, 0x379d: 0x00c2,
+	0x379e: 0x00c2, 0x379f: 0x00c2, 0x37a0: 0x00c2, 0x37a1: 0x00c2, 0x37a2: 0x00c4, 0x37a3: 0x00c2,
+	0x37a4: 0x00c3, 0x37a5: 0x00c3, 0x37a6: 0x00c3, 0x37a7: 0x00c3,
+	0x37b0: 0x00c0, 0x37b1: 0x00c0, 0x37b2: 0x00c0, 0x37b3: 0x00c0, 0x37b4: 0x00c0, 0x37b5: 0x00c0,
+	0x37b6: 0x00c0, 0x37b7: 0x00c0, 0x37b8: 0x00c0, 0x37b9: 0x00c0,
+	// Block 0xdf, offset 0x37c0
+	0x37c0: 0x00c0, 0x37c1: 0x00c0, 0x37c2: 0x00c0, 0x37c3: 0x00c0, 0x37c4: 0x00c0, 0x37c5: 0x00c0,
+	0x37c6: 0x00c0, 0x37c7: 0x00c0, 0x37c8: 0x00c0, 0x37c9: 0x00c0, 0x37ca: 0x00c0, 0x37cb: 0x00c0,
+	0x37cc: 0x00c0, 0x37cd: 0x00c0, 0x37ce: 0x00c0, 0x37cf: 0x00c0, 0x37d0: 0x00c0, 0x37d1: 0x00c0,
+	0x37d2: 0x00c0, 0x37d3: 0x00c0, 0x37d4: 0x00c0, 0x37d5: 0x00c0, 0x37d6: 0x00c0, 0x37d7: 0x00c0,
+	0x37d8: 0x00c0, 0x37d9: 0x00c0, 0x37da: 0x00c0, 0x37db: 0x00c0, 0x37dc: 0x00c0, 0x37dd: 0x00c0,
+	0x37de: 0x00c0, 0x37df: 0x00c0, 0x37e0: 0x00c0, 0x37e1: 0x00c0, 0x37e2: 0x00c0, 0x37e3: 0x00c0,
+	0x37e4: 0x00c0, 0x37e5: 0x00c0, 0x37e9: 0x00c3,
+	0x37ea: 0x00c3, 0x37eb: 0x00c3, 0x37ec: 0x00c3, 0x37ed: 0x00c3, 0x37ee: 0x0080, 0x37ef: 0x00c0,
+	0x37f0: 0x00c0, 0x37f1: 0x00c0, 0x37f2: 0x00c0, 0x37f3: 0x00c0, 0x37f4: 0x00c0, 0x37f5: 0x00c0,
+	0x37f6: 0x00c0, 0x37f7: 0x00c0, 0x37f8: 0x00c0, 0x37f9: 0x00c0, 0x37fa: 0x00c0, 0x37fb: 0x00c0,
+	0x37fc: 0x00c0, 0x37fd: 0x00c0, 0x37fe: 0x00c0, 0x37ff: 0x00c0,
+	// Block 0xe0, offset 0x3800
+	0x3800: 0x00c0, 0x3801: 0x00c0, 0x3802: 0x00c0, 0x3803: 0x00c0, 0x3804: 0x00c0, 0x3805: 0x00c0,
+	0x380e: 0x0080, 0x380f: 0x0080,
+	// Block 0xe1, offset 0x3840
+	0x3860: 0x0080, 0x3861: 0x0080, 0x3862: 0x0080, 0x3863: 0x0080,
+	0x3864: 0x0080, 0x3865: 0x0080, 0x3866: 0x0080, 0x3867: 0x0080, 0x3868: 0x0080, 0x3869: 0x0080,
+	0x386a: 0x0080, 0x386b: 0x0080, 0x386c: 0x0080, 0x386d: 0x0080, 0x386e: 0x0080, 0x386f: 0x0080,
+	0x3870: 0x0080, 0x3871: 0x0080, 0x3872: 0x0080, 0x3873: 0x0080, 0x3874: 0x0080, 0x3875: 0x0080,
+	0x3876: 0x0080, 0x3877: 0x0080, 0x3878: 0x0080, 0x3879: 0x0080, 0x387a: 0x0080, 0x387b: 0x0080,
+	0x387c: 0x0080, 0x387d: 0x0080, 0x387e: 0x0080,
+	// Block 0xe2, offset 0x3880
+	0x3880: 0x00c0, 0x3881: 0x00c0, 0x3882: 0x00c0, 0x3883: 0x00c0, 0x3884: 0x00c0, 0x3885: 0x00c0,
+	0x3886: 0x00c0, 0x3887: 0x00c0, 0x3888: 0x00c0, 0x3889: 0x00c0, 0x388a: 0x00c0, 0x388b: 0x00c0,
+	0x388c: 0x00c0, 0x388d: 0x00c0, 0x388e: 0x00c0, 0x388f: 0x00c0, 0x3890: 0x00c0, 0x3891: 0x00c0,
+	0x3892: 0x00c0, 0x3893: 0x00c0, 0x3894: 0x00c0, 0x3895: 0x00c0, 0x3896: 0x00c0, 0x3897: 0x00c0,
+	0x3898: 0x00c0, 0x3899: 0x00c0, 0x389a: 0x00c0, 0x389b: 0x00c0, 0x389c: 0x00c0, 0x389d: 0x00c0,
+	0x389e: 0x00c0, 0x389f: 0x00c0, 0x38a0: 0x00c0, 0x38a1: 0x00c0, 0x38a2: 0x00c0, 0x38a3: 0x00c0,
+	0x38a4: 0x00c0, 0x38a5: 0x00c0, 0x38a6: 0x00c0, 0x38a7: 0x00c0, 0x38a8: 0x00c0, 0x38a9: 0x00c0,
+	0x38ab: 0x00c3, 0x38ac: 0x00c3, 0x38ad: 0x0080,
+	0x38b0: 0x00c0, 0x38b1: 0x00c0,
+	// Block 0xe3, offset 0x38c0
+	0x38c2: 0x00c4, 0x38c3: 0x00c2, 0x38c4: 0x00c2, 0x38c5: 0x00c0,
+	0x38c6: 0x00c2, 0x38c7: 0x00c2,
+	0x38d0: 0x0080, 0x38d1: 0x0080,
+	0x38d2: 0x0080, 0x38d3: 0x0080, 0x38d4: 0x0080, 0x38d5: 0x0080, 0x38d6: 0x0080, 0x38d7: 0x0080,
+	0x38d8: 0x0080,
+	0x38fa: 0x00c3, 0x38fb: 0x00c3,
+	0x38fc: 0x00c3, 0x38fd: 0x00c3, 0x38fe: 0x00c3, 0x38ff: 0x00c3,
+	// Block 0xe4, offset 0x3900
+	0x3900: 0x00c0, 0x3901: 0x00c0, 0x3902: 0x00c0, 0x3903: 0x00c0, 0x3904: 0x00c0, 0x3905: 0x00c0,
+	0x3906: 0x00c0, 0x3907: 0x00c0, 0x3908: 0x00c0, 0x3909: 0x00c0, 0x390a: 0x00c0, 0x390b: 0x00c0,
+	0x390c: 0x00c0, 0x390d: 0x00c0, 0x390e: 0x00c0, 0x390f: 0x00c0, 0x3910: 0x00c0, 0x3911: 0x00c0,
+	0x3912: 0x00c0, 0x3913: 0x00c0, 0x3914: 0x00c0, 0x3915: 0x00c0, 0x3916: 0x00c0, 0x3917: 0x00c0,
+	0x3918: 0x00c0, 0x3919: 0x00c0, 0x391a: 0x00c0, 0x391b: 0x00c0, 0x391c: 0x00c0, 0x391d: 0x0080,
+	0x391e: 0x0080, 0x391f: 0x0080, 0x3920: 0x0080, 0x3921: 0x0080, 0x3922: 0x0080, 0x3923: 0x0080,
+	0x3924: 0x0080, 0x3925: 0x0080, 0x3926: 0x0080, 0x3927: 0x00c0,
+	0x3930: 0x00c2, 0x3931: 0x00c2, 0x3932: 0x00c2, 0x3933: 0x00c4, 0x3934: 0x00c2, 0x3935: 0x00c2,
+	0x3936: 0x00c2, 0x3937: 0x00c2, 0x3938: 0x00c2, 0x3939: 0x00c2, 0x393a: 0x00c2, 0x393b: 0x00c2,
+	0x393c: 0x00c2, 0x393d: 0x00c2, 0x393e: 0x00c2, 0x393f: 0x00c2,
+	// Block 0xe5, offset 0x3940
+	0x3940: 0x00c2, 0x3941: 0x00c2, 0x3942: 0x00c2, 0x3943: 0x00c2, 0x3944: 0x00c2, 0x3945: 0x00c0,
+	0x3946: 0x00c3, 0x3947: 0x00c3, 0x3948: 0x00c3, 0x3949: 0x00c3, 0x394a: 0x00c3, 0x394b: 0x00c3,
+	0x394c: 0x00c3, 0x394d: 0x00c3, 0x394e: 0x00c3, 0x394f: 0x00c3, 0x3950: 0x00c3, 0x3951: 0x0082,
+	0x3952: 0x0082, 0x3953: 0x0082, 0x3954: 0x0084, 0x3955: 0x0080, 0x3956: 0x0080, 0x3957: 0x0080,
+	0x3958: 0x0080, 0x3959: 0x0080,
+	0x3970: 0x00c2, 0x3971: 0x00c2, 0x3972: 0x00c2, 0x3973: 0x00c2, 0x3974: 0x00c4, 0x3975: 0x00c4,
+	0x3976: 0x00c2, 0x3977: 0x00c2, 0x3978: 0x00c2, 0x3979: 0x00c2, 0x397a: 0x00c2, 0x397b: 0x00c2,
+	0x397c: 0x00c2, 0x397d: 0x00c2, 0x397e: 0x00c2, 0x397f: 0x00c2,
+	// Block 0xe6, offset 0x3980
+	0x3980: 0x00c2, 0x3981: 0x00c2, 0x3982: 0x00c3, 0x3983: 0x00c3, 0x3984: 0x00c3, 0x3985: 0x00c3,
+	0x3986: 0x0080, 0x3987: 0x0080, 0x3988: 0x0080, 0x3989: 0x0080,
+	0x39b0: 0x00c2, 0x39b1: 0x00c0, 0x39b2: 0x00c2, 0x39b3: 0x00c2, 0x39b4: 0x00c4, 0x39b5: 0x00c4,
+	0x39b6: 0x00c4, 0x39b7: 0x00c0, 0x39b8: 0x00c2, 0x39b9: 0x00c4, 0x39ba: 0x00c4, 0x39bb: 0x00c2,
+	0x39bc: 0x00c2, 0x39bd: 0x00c4, 0x39be: 0x00c2, 0x39bf: 0x00c2,
+	// Block 0xe7, offset 0x39c0
+	0x39c0: 0x00c0, 0x39c1: 0x00c2, 0x39c2: 0x00c4, 0x39c3: 0x00c4, 0x39c4: 0x00c2, 0x39c5: 0x0080,
+	0x39c6: 0x0080, 0x39c7: 0x0080, 0x39c8: 0x0080, 0x39c9: 0x0084, 0x39ca: 0x0082, 0x39cb: 0x0081,
+	0x39e0: 0x00c0, 0x39e1: 0x00c0, 0x39e2: 0x00c0, 0x39e3: 0x00c0,
+	0x39e4: 0x00c0, 0x39e5: 0x00c0, 0x39e6: 0x00c0, 0x39e7: 0x00c0, 0x39e8: 0x00c0, 0x39e9: 0x00c0,
+	0x39ea: 0x00c0, 0x39eb: 0x00c0, 0x39ec: 0x00c0, 0x39ed: 0x00c0, 0x39ee: 0x00c0, 0x39ef: 0x00c0,
+	0x39f0: 0x00c0, 0x39f1: 0x00c0, 0x39f2: 0x00c0, 0x39f3: 0x00c0, 0x39f4: 0x00c0, 0x39f5: 0x00c0,
+	0x39f6: 0x00c0,
+	// Block 0xe8, offset 0x3a00
+	0x3a00: 0x00c0, 0x3a01: 0x00c3, 0x3a02: 0x00c0, 0x3a03: 0x00c0, 0x3a04: 0x00c0, 0x3a05: 0x00c0,
+	0x3a06: 0x00c0, 0x3a07: 0x00c0, 0x3a08: 0x00c0, 0x3a09: 0x00c0, 0x3a0a: 0x00c0, 0x3a0b: 0x00c0,
+	0x3a0c: 0x00c0, 0x3a0d: 0x00c0, 0x3a0e: 0x00c0, 0x3a0f: 0x00c0, 0x3a10: 0x00c0, 0x3a11: 0x00c0,
+	0x3a12: 0x00c0, 0x3a13: 0x00c0, 0x3a14: 0x00c0, 0x3a15: 0x00c0, 0x3a16: 0x00c0, 0x3a17: 0x00c0,
+	0x3a18: 0x00c0, 0x3a19: 0x00c0, 0x3a1a: 0x00c0, 0x3a1b: 0x00c0, 0x3a1c: 0x00c0, 0x3a1d: 0x00c0,
+	0x3a1e: 0x00c0, 0x3a1f: 0x00c0, 0x3a20: 0x00c0, 0x3a21: 0x00c0, 0x3a22: 0x00c0, 0x3a23: 0x00c0,
+	0x3a24: 0x00c0, 0x3a25: 0x00c0, 0x3a26: 0x00c0, 0x3a27: 0x00c0, 0x3a28: 0x00c0, 0x3a29: 0x00c0,
+	0x3a2a: 0x00c0, 0x3a2b: 0x00c0, 0x3a2c: 0x00c0, 0x3a2d: 0x00c0, 0x3a2e: 0x00c0, 0x3a2f: 0x00c0,
+	0x3a30: 0x00c0, 0x3a31: 0x00c0, 0x3a32: 0x00c0, 0x3a33: 0x00c0, 0x3a34: 0x00c0, 0x3a35: 0x00c0,
+	0x3a36: 0x00c0, 0x3a37: 0x00c0, 0x3a38: 0x00c3, 0x3a39: 0x00c3, 0x3a3a: 0x00c3, 0x3a3b: 0x00c3,
+	0x3a3c: 0x00c3, 0x3a3d: 0x00c3, 0x3a3e: 0x00c3, 0x3a3f: 0x00c3,
+	// Block 0xe9, offset 0x3a40
+	0x3a40: 0x00c3, 0x3a41: 0x00c3, 0x3a42: 0x00c3, 0x3a43: 0x00c3, 0x3a44: 0x00c3, 0x3a45: 0x00c3,
+	0x3a46: 0x00c6, 0x3a47: 0x0080, 0x3a48: 0x0080, 0x3a49: 0x0080, 0x3a4a: 0x0080, 0x3a4b: 0x0080,
+	0x3a4c: 0x0080, 0x3a4d: 0x0080,
+	0x3a52: 0x0080, 0x3a53: 0x0080, 0x3a54: 0x0080, 0x3a55: 0x0080, 0x3a56: 0x0080, 0x3a57: 0x0080,
+	0x3a58: 0x0080, 0x3a59: 0x0080, 0x3a5a: 0x0080, 0x3a5b: 0x0080, 0x3a5c: 0x0080, 0x3a5d: 0x0080,
+	0x3a5e: 0x0080, 0x3a5f: 0x0080, 0x3a60: 0x0080, 0x3a61: 0x0080, 0x3a62: 0x0080, 0x3a63: 0x0080,
+	0x3a64: 0x0080, 0x3a65: 0x0080, 0x3a66: 0x00c0, 0x3a67: 0x00c0, 0x3a68: 0x00c0, 0x3a69: 0x00c0,
+	0x3a6a: 0x00c0, 0x3a6b: 0x00c0, 0x3a6c: 0x00c0, 0x3a6d: 0x00c0, 0x3a6e: 0x00c0, 0x3a6f: 0x00c0,
+	0x3a70: 0x00c6, 0x3a71: 0x00c0, 0x3a72: 0x00c0, 0x3a73: 0x00c3, 0x3a74: 0x00c3, 0x3a75: 0x00c0,
+	0x3a7f: 0x00c6,
+	// Block 0xea, offset 0x3a80
+	0x3a80: 0x00c3, 0x3a81: 0x00c3, 0x3a82: 0x00c0, 0x3a83: 0x00c0, 0x3a84: 0x00c0, 0x3a85: 0x00c0,
+	0x3a86: 0x00c0, 0x3a87: 0x00c0, 0x3a88: 0x00c0, 0x3a89: 0x00c0, 0x3a8a: 0x00c0, 0x3a8b: 0x00c0,
+	0x3a8c: 0x00c0, 0x3a8d: 0x00c0, 0x3a8e: 0x00c0, 0x3a8f: 0x00c0, 0x3a90: 0x00c0, 0x3a91: 0x00c0,
+	0x3a92: 0x00c0, 0x3a93: 0x00c0, 0x3a94: 0x00c0, 0x3a95: 0x00c0, 0x3a96: 0x00c0, 0x3a97: 0x00c0,
+	0x3a98: 0x00c0, 0x3a99: 0x00c0, 0x3a9a: 0x00c0, 0x3a9b: 0x00c0, 0x3a9c: 0x00c0, 0x3a9d: 0x00c0,
+	0x3a9e: 0x00c0, 0x3a9f: 0x00c0, 0x3aa0: 0x00c0, 0x3aa1: 0x00c0, 0x3aa2: 0x00c0, 0x3aa3: 0x00c0,
+	0x3aa4: 0x00c0, 0x3aa5: 0x00c0, 0x3aa6: 0x00c0, 0x3aa7: 0x00c0, 0x3aa8: 0x00c0, 0x3aa9: 0x00c0,
+	0x3aaa: 0x00c0, 0x3aab: 0x00c0, 0x3aac: 0x00c0, 0x3aad: 0x00c0, 0x3aae: 0x00c0, 0x3aaf: 0x00c0,
+	0x3ab0: 0x00c0, 0x3ab1: 0x00c0, 0x3ab2: 0x00c0, 0x3ab3: 0x00c3, 0x3ab4: 0x00c3, 0x3ab5: 0x00c3,
+	0x3ab6: 0x00c3, 0x3ab7: 0x00c0, 0x3ab8: 0x00c0, 0x3ab9: 0x00c6, 0x3aba: 0x00c3, 0x3abb: 0x0080,
+	0x3abc: 0x0080, 0x3abd: 0x0040, 0x3abe: 0x0080, 0x3abf: 0x0080,
+	// Block 0xeb, offset 0x3ac0
+	0x3ac0: 0x0080, 0x3ac1: 0x0080, 0x3ac2: 0x00c3,
+	0x3acd: 0x0040, 0x3ad0: 0x00c0, 0x3ad1: 0x00c0,
+	0x3ad2: 0x00c0, 0x3ad3: 0x00c0, 0x3ad4: 0x00c0, 0x3ad5: 0x00c0, 0x3ad6: 0x00c0, 0x3ad7: 0x00c0,
+	0x3ad8: 0x00c0, 0x3ad9: 0x00c0, 0x3ada: 0x00c0, 0x3adb: 0x00c0, 0x3adc: 0x00c0, 0x3add: 0x00c0,
+	0x3ade: 0x00c0, 0x3adf: 0x00c0, 0x3ae0: 0x00c0, 0x3ae1: 0x00c0, 0x3ae2: 0x00c0, 0x3ae3: 0x00c0,
+	0x3ae4: 0x00c0, 0x3ae5: 0x00c0, 0x3ae6: 0x00c0, 0x3ae7: 0x00c0, 0x3ae8: 0x00c0,
+	0x3af0: 0x00c0, 0x3af1: 0x00c0, 0x3af2: 0x00c0, 0x3af3: 0x00c0, 0x3af4: 0x00c0, 0x3af5: 0x00c0,
+	0x3af6: 0x00c0, 0x3af7: 0x00c0, 0x3af8: 0x00c0, 0x3af9: 0x00c0,
+	// Block 0xec, offset 0x3b00
+	0x3b00: 0x00c3, 0x3b01: 0x00c3, 0x3b02: 0x00c3, 0x3b03: 0x00c0, 0x3b04: 0x00c0, 0x3b05: 0x00c0,
+	0x3b06: 0x00c0, 0x3b07: 0x00c0, 0x3b08: 0x00c0, 0x3b09: 0x00c0, 0x3b0a: 0x00c0, 0x3b0b: 0x00c0,
+	0x3b0c: 0x00c0, 0x3b0d: 0x00c0, 0x3b0e: 0x00c0, 0x3b0f: 0x00c0, 0x3b10: 0x00c0, 0x3b11: 0x00c0,
+	0x3b12: 0x00c0, 0x3b13: 0x00c0, 0x3b14: 0x00c0, 0x3b15: 0x00c0, 0x3b16: 0x00c0, 0x3b17: 0x00c0,
+	0x3b18: 0x00c0, 0x3b19: 0x00c0, 0x3b1a: 0x00c0, 0x3b1b: 0x00c0, 0x3b1c: 0x00c0, 0x3b1d: 0x00c0,
+	0x3b1e: 0x00c0, 0x3b1f: 0x00c0, 0x3b20: 0x00c0, 0x3b21: 0x00c0, 0x3b22: 0x00c0, 0x3b23: 0x00c0,
+	0x3b24: 0x00c0, 0x3b25: 0x00c0, 0x3b26: 0x00c0, 0x3b27: 0x00c3, 0x3b28: 0x00c3, 0x3b29: 0x00c3,
+	0x3b2a: 0x00c3, 0x3b2b: 0x00c3, 0x3b2c: 0x00c0, 0x3b2d: 0x00c3, 0x3b2e: 0x00c3, 0x3b2f: 0x00c3,
+	0x3b30: 0x00c3, 0x3b31: 0x00c3, 0x3b32: 0x00c3, 0x3b33: 0x00c6, 0x3b34: 0x00c6,
+	0x3b36: 0x00c0, 0x3b37: 0x00c0, 0x3b38: 0x00c0, 0x3b39: 0x00c0, 0x3b3a: 0x00c0, 0x3b3b: 0x00c0,
+	0x3b3c: 0x00c0, 0x3b3d: 0x00c0, 0x3b3e: 0x00c0, 0x3b3f: 0x00c0,
+	// Block 0xed, offset 0x3b40
+	0x3b40: 0x0080, 0x3b41: 0x0080, 0x3b42: 0x0080, 0x3b43: 0x0080, 0x3b44: 0x00c0, 0x3b45: 0x00c0,
+	0x3b46: 0x00c0, 0x3b47: 0x00c0,
+	0x3b50: 0x00c0, 0x3b51: 0x00c0,
+	0x3b52: 0x00c0, 0x3b53: 0x00c0, 0x3b54: 0x00c0, 0x3b55: 0x00c0, 0x3b56: 0x00c0, 0x3b57: 0x00c0,
+	0x3b58: 0x00c0, 0x3b59: 0x00c0, 0x3b5a: 0x00c0, 0x3b5b: 0x00c0, 0x3b5c: 0x00c0, 0x3b5d: 0x00c0,
+	0x3b5e: 0x00c0, 0x3b5f: 0x00c0, 0x3b60: 0x00c0, 0x3b61: 0x00c0, 0x3b62: 0x00c0, 0x3b63: 0x00c0,
+	0x3b64: 0x00c0, 0x3b65: 0x00c0, 0x3b66: 0x00c0, 0x3b67: 0x00c0, 0x3b68: 0x00c0, 0x3b69: 0x00c0,
+	0x3b6a: 0x00c0, 0x3b6b: 0x00c0, 0x3b6c: 0x00c0, 0x3b6d: 0x00c0, 0x3b6e: 0x00c0, 0x3b6f: 0x00c0,
+	0x3b70: 0x00c0, 0x3b71: 0x00c0, 0x3b72: 0x00c0, 0x3b73: 0x00c3, 0x3b74: 0x0080, 0x3b75: 0x0080,
+	0x3b76: 0x00c0,
+	// Block 0xee, offset 0x3b80
+	0x3b80: 0x00c3, 0x3b81: 0x00c3, 0x3b82: 0x00c0, 0x3b83: 0x00c0, 0x3b84: 0x00c0, 0x3b85: 0x00c0,
+	0x3b86: 0x00c0, 0x3b87: 0x00c0, 0x3b88: 0x00c0, 0x3b89: 0x00c0, 0x3b8a: 0x00c0, 0x3b8b: 0x00c0,
+	0x3b8c: 0x00c0, 0x3b8d: 0x00c0, 0x3b8e: 0x00c0, 0x3b8f: 0x00c0, 0x3b90: 0x00c0, 0x3b91: 0x00c0,
+	0x3b92: 0x00c0, 0x3b93: 0x00c0, 0x3b94: 0x00c0, 0x3b95: 0x00c0, 0x3b96: 0x00c0, 0x3b97: 0x00c0,
+	0x3b98: 0x00c0, 0x3b99: 0x00c0, 0x3b9a: 0x00c0, 0x3b9b: 0x00c0, 0x3b9c: 0x00c0, 0x3b9d: 0x00c0,
+	0x3b9e: 0x00c0, 0x3b9f: 0x00c0, 0x3ba0: 0x00c0, 0x3ba1: 0x00c0, 0x3ba2: 0x00c0, 0x3ba3: 0x00c0,
+	0x3ba4: 0x00c0, 0x3ba5: 0x00c0, 0x3ba6: 0x00c0, 0x3ba7: 0x00c0, 0x3ba8: 0x00c0, 0x3ba9: 0x00c0,
+	0x3baa: 0x00c0, 0x3bab: 0x00c0, 0x3bac: 0x00c0, 0x3bad: 0x00c0, 0x3bae: 0x00c0, 0x3baf: 0x00c0,
+	0x3bb0: 0x00c0, 0x3bb1: 0x00c0, 0x3bb2: 0x00c0, 0x3bb3: 0x00c0, 0x3bb4: 0x00c0, 0x3bb5: 0x00c0,
+	0x3bb6: 0x00c3, 0x3bb7: 0x00c3, 0x3bb8: 0x00c3, 0x3bb9: 0x00c3, 0x3bba: 0x00c3, 0x3bbb: 0x00c3,
+	0x3bbc: 0x00c3, 0x3bbd: 0x00c3, 0x3bbe: 0x00c3, 0x3bbf: 0x00c0,
+	// Block 0xef, offset 0x3bc0
+	0x3bc0: 0x00c5, 0x3bc1: 0x00c0, 0x3bc2: 0x00c0, 0x3bc3: 0x00c0, 0x3bc4: 0x00c0, 0x3bc5: 0x0080,
+	0x3bc6: 0x0080, 0x3bc7: 0x0080, 0x3bc8: 0x0080, 0x3bc9: 0x00c3, 0x3bca: 0x00c3, 0x3bcb: 0x00c3,
+	0x3bcc: 0x00c3, 0x3bcd: 0x0080, 0x3bce: 0x00c0, 0x3bcf: 0x00c3, 0x3bd0: 0x00c0, 0x3bd1: 0x00c0,
+	0x3bd2: 0x00c0, 0x3bd3: 0x00c0, 0x3bd4: 0x00c0, 0x3bd5: 0x00c0, 0x3bd6: 0x00c0, 0x3bd7: 0x00c0,
+	0x3bd8: 0x00c0, 0x3bd9: 0x00c0, 0x3bda: 0x00c0, 0x3bdb: 0x0080, 0x3bdc: 0x00c0, 0x3bdd: 0x0080,
+	0x3bde: 0x0080, 0x3bdf: 0x0080, 0x3be1: 0x0080, 0x3be2: 0x0080, 0x3be3: 0x0080,
+	0x3be4: 0x0080, 0x3be5: 0x0080, 0x3be6: 0x0080, 0x3be7: 0x0080, 0x3be8: 0x0080, 0x3be9: 0x0080,
+	0x3bea: 0x0080, 0x3beb: 0x0080, 0x3bec: 0x0080, 0x3bed: 0x0080, 0x3bee: 0x0080, 0x3bef: 0x0080,
+	0x3bf0: 0x0080, 0x3bf1: 0x0080, 0x3bf2: 0x0080, 0x3bf3: 0x0080, 0x3bf4: 0x0080,
+	// Block 0xf0, offset 0x3c00
+	0x3c00: 0x00c0, 0x3c01: 0x00c0, 0x3c02: 0x00c0, 0x3c03: 0x00c0, 0x3c04: 0x00c0, 0x3c05: 0x00c0,
+	0x3c06: 0x00c0, 0x3c07: 0x00c0, 0x3c08: 0x00c0, 0x3c09: 0x00c0, 0x3c0a: 0x00c0, 0x3c0b: 0x00c0,
+	0x3c0c: 0x00c0, 0x3c0d: 0x00c0, 0x3c0e: 0x00c0, 0x3c0f: 0x00c0, 0x3c10: 0x00c0, 0x3c11: 0x00c0,
+	0x3c13: 0x00c0, 0x3c14: 0x00c0, 0x3c15: 0x00c0, 0x3c16: 0x00c0, 0x3c17: 0x00c0,
+	0x3c18: 0x00c0, 0x3c19: 0x00c0, 0x3c1a: 0x00c0, 0x3c1b: 0x00c0, 0x3c1c: 0x00c0, 0x3c1d: 0x00c0,
+	0x3c1e: 0x00c0, 0x3c1f: 0x00c0, 0x3c20: 0x00c0, 0x3c21: 0x00c0, 0x3c22: 0x00c0, 0x3c23: 0x00c0,
+	0x3c24: 0x00c0, 0x3c25: 0x00c0, 0x3c26: 0x00c0, 0x3c27: 0x00c0, 0x3c28: 0x00c0, 0x3c29: 0x00c0,
+	0x3c2a: 0x00c0, 0x3c2b: 0x00c0, 0x3c2c: 0x00c0, 0x3c2d: 0x00c0, 0x3c2e: 0x00c0, 0x3c2f: 0x00c3,
+	0x3c30: 0x00c3, 0x3c31: 0x00c3, 0x3c32: 0x00c0, 0x3c33: 0x00c0, 0x3c34: 0x00c3, 0x3c35: 0x00c5,
+	0x3c36: 0x00c3, 0x3c37: 0x00c3, 0x3c38: 0x0080, 0x3c39: 0x0080, 0x3c3a: 0x0080, 0x3c3b: 0x0080,
+	0x3c3c: 0x0080, 0x3c3d: 0x0080, 0x3c3e: 0x00c3, 0x3c3f: 0x00c0,
+	// Block 0xf1, offset 0x3c40
+	0x3c40: 0x00c0, 0x3c41: 0x00c3,
+	// Block 0xf2, offset 0x3c80
+	0x3c80: 0x00c0, 0x3c81: 0x00c0, 0x3c82: 0x00c0, 0x3c83: 0x00c0, 0x3c84: 0x00c0, 0x3c85: 0x00c0,
+	0x3c86: 0x00c0, 0x3c88: 0x00c0, 0x3c8a: 0x00c0, 0x3c8b: 0x00c0,
+	0x3c8c: 0x00c0, 0x3c8d: 0x00c0, 0x3c8f: 0x00c0, 0x3c90: 0x00c0, 0x3c91: 0x00c0,
+	0x3c92: 0x00c0, 0x3c93: 0x00c0, 0x3c94: 0x00c0, 0x3c95: 0x00c0, 0x3c96: 0x00c0, 0x3c97: 0x00c0,
+	0x3c98: 0x00c0, 0x3c99: 0x00c0, 0x3c9a: 0x00c0, 0x3c9b: 0x00c0, 0x3c9c: 0x00c0, 0x3c9d: 0x00c0,
+	0x3c9f: 0x00c0, 0x3ca0: 0x00c0, 0x3ca1: 0x00c0, 0x3ca2: 0x00c0, 0x3ca3: 0x00c0,
+	0x3ca4: 0x00c0, 0x3ca5: 0x00c0, 0x3ca6: 0x00c0, 0x3ca7: 0x00c0, 0x3ca8: 0x00c0, 0x3ca9: 0x0080,
+	0x3cb0: 0x00c0, 0x3cb1: 0x00c0, 0x3cb2: 0x00c0, 0x3cb3: 0x00c0, 0x3cb4: 0x00c0, 0x3cb5: 0x00c0,
+	0x3cb6: 0x00c0, 0x3cb7: 0x00c0, 0x3cb8: 0x00c0, 0x3cb9: 0x00c0, 0x3cba: 0x00c0, 0x3cbb: 0x00c0,
+	0x3cbc: 0x00c0, 0x3cbd: 0x00c0, 0x3cbe: 0x00c0, 0x3cbf: 0x00c0,
+	// Block 0xf3, offset 0x3cc0
+	0x3cc0: 0x00c0, 0x3cc1: 0x00c0, 0x3cc2: 0x00c0, 0x3cc3: 0x00c0, 0x3cc4: 0x00c0, 0x3cc5: 0x00c0,
+	0x3cc6: 0x00c0, 0x3cc7: 0x00c0, 0x3cc8: 0x00c0, 0x3cc9: 0x00c0, 0x3cca: 0x00c0, 0x3ccb: 0x00c0,
+	0x3ccc: 0x00c0, 0x3ccd: 0x00c0, 0x3cce: 0x00c0, 0x3ccf: 0x00c0, 0x3cd0: 0x00c0, 0x3cd1: 0x00c0,
+	0x3cd2: 0x00c0, 0x3cd3: 0x00c0, 0x3cd4: 0x00c0, 0x3cd5: 0x00c0, 0x3cd6: 0x00c0, 0x3cd7: 0x00c0,
+	0x3cd8: 0x00c0, 0x3cd9: 0x00c0, 0x3cda: 0x00c0, 0x3cdb: 0x00c0, 0x3cdc: 0x00c0, 0x3cdd: 0x00c0,
+	0x3cde: 0x00c0, 0x3cdf: 0x00c3, 0x3ce0: 0x00c0, 0x3ce1: 0x00c0, 0x3ce2: 0x00c0, 0x3ce3: 0x00c3,
+	0x3ce4: 0x00c3, 0x3ce5: 0x00c3, 0x3ce6: 0x00c3, 0x3ce7: 0x00c3, 0x3ce8: 0x00c3, 0x3ce9: 0x00c3,
+	0x3cea: 0x00c6,
+	0x3cf0: 0x00c0, 0x3cf1: 0x00c0, 0x3cf2: 0x00c0, 0x3cf3: 0x00c0, 0x3cf4: 0x00c0, 0x3cf5: 0x00c0,
+	0x3cf6: 0x00c0, 0x3cf7: 0x00c0, 0x3cf8: 0x00c0, 0x3cf9: 0x00c0,
+	// Block 0xf4, offset 0x3d00
+	0x3d00: 0x00c3, 0x3d01: 0x00c3, 0x3d02: 0x00c0, 0x3d03: 0x00c0, 0x3d05: 0x00c0,
+	0x3d06: 0x00c0, 0x3d07: 0x00c0, 0x3d08: 0x00c0, 0x3d09: 0x00c0, 0x3d0a: 0x00c0, 0x3d0b: 0x00c0,
+	0x3d0c: 0x00c0, 0x3d0f: 0x00c0, 0x3d10: 0x00c0,
+	0x3d13: 0x00c0, 0x3d14: 0x00c0, 0x3d15: 0x00c0, 0x3d16: 0x00c0, 0x3d17: 0x00c0,
+	0x3d18: 0x00c0, 0x3d19: 0x00c0, 0x3d1a: 0x00c0, 0x3d1b: 0x00c0, 0x3d1c: 0x00c0, 0x3d1d: 0x00c0,
+	0x3d1e: 0x00c0, 0x3d1f: 0x00c0, 0x3d20: 0x00c0, 0x3d21: 0x00c0, 0x3d22: 0x00c0, 0x3d23: 0x00c0,
+	0x3d24: 0x00c0, 0x3d25: 0x00c0, 0x3d26: 0x00c0, 0x3d27: 0x00c0, 0x3d28: 0x00c0,
+	0x3d2a: 0x00c0, 0x3d2b: 0x00c0, 0x3d2c: 0x00c0, 0x3d2d: 0x00c0, 0x3d2e: 0x00c0, 0x3d2f: 0x00c0,
+	0x3d30: 0x00c0, 0x3d32: 0x00c0, 0x3d33: 0x00c0, 0x3d35: 0x00c0,
+	0x3d36: 0x00c0, 0x3d37: 0x00c0, 0x3d38: 0x00c0, 0x3d39: 0x00c0, 0x3d3b: 0x00c3,
+	0x3d3c: 0x00c3, 0x3d3d: 0x00c0, 0x3d3e: 0x00c0, 0x3d3f: 0x00c0,
+	// Block 0xf5, offset 0x3d40
+	0x3d40: 0x00c3, 0x3d41: 0x00c0, 0x3d42: 0x00c0, 0x3d43: 0x00c0, 0x3d44: 0x00c0,
+	0x3d47: 0x00c0, 0x3d48: 0x00c0, 0x3d4b: 0x00c0,
+	0x3d4c: 0x00c0, 0x3d4d: 0x00c5, 0x3d50: 0x00c0,
+	0x3d57: 0x00c0,
+	0x3d5d: 0x00c0,
+	0x3d5e: 0x00c0, 0x3d5f: 0x00c0, 0x3d60: 0x00c0, 0x3d61: 0x00c0, 0x3d62: 0x00c0, 0x3d63: 0x00c0,
+	0x3d66: 0x00c3, 0x3d67: 0x00c3, 0x3d68: 0x00c3, 0x3d69: 0x00c3,
+	0x3d6a: 0x00c3, 0x3d6b: 0x00c3, 0x3d6c: 0x00c3,
+	0x3d70: 0x00c3, 0x3d71: 0x00c3, 0x3d72: 0x00c3, 0x3d73: 0x00c3, 0x3d74: 0x00c3,
+	// Block 0xf6, offset 0x3d80
+	0x3d80: 0x00c0, 0x3d81: 0x00c0, 0x3d82: 0x00c0, 0x3d83: 0x00c0, 0x3d84: 0x00c0, 0x3d85: 0x00c0,
+	0x3d86: 0x00c0, 0x3d87: 0x00c0, 0x3d88: 0x00c0, 0x3d89: 0x00c0, 0x3d8b: 0x00c0,
+	0x3d8e: 0x00c0, 0x3d90: 0x00c0, 0x3d91: 0x00c0,
+	0x3d92: 0x00c0, 0x3d93: 0x00c0, 0x3d94: 0x00c0, 0x3d95: 0x00c0, 0x3d96: 0x00c0, 0x3d97: 0x00c0,
+	0x3d98: 0x00c0, 0x3d99: 0x00c0, 0x3d9a: 0x00c0, 0x3d9b: 0x00c0, 0x3d9c: 0x00c0, 0x3d9d: 0x00c0,
+	0x3d9e: 0x00c0, 0x3d9f: 0x00c0, 0x3da0: 0x00c0, 0x3da1: 0x00c0, 0x3da2: 0x00c0, 0x3da3: 0x00c0,
+	0x3da4: 0x00c0, 0x3da5: 0x00c0, 0x3da6: 0x00c0, 0x3da7: 0x00c0, 0x3da8: 0x00c0, 0x3da9: 0x00c0,
+	0x3daa: 0x00c0, 0x3dab: 0x00c0, 0x3dac: 0x00c0, 0x3dad: 0x00c0, 0x3dae: 0x00c0, 0x3daf: 0x00c0,
+	0x3db0: 0x00c0, 0x3db1: 0x00c0, 0x3db2: 0x00c0, 0x3db3: 0x00c0, 0x3db4: 0x00c0, 0x3db5: 0x00c0,
+	0x3db7: 0x00c0, 0x3db8: 0x00c0, 0x3db9: 0x00c0, 0x3dba: 0x00c0, 0x3dbb: 0x00c3,
+	0x3dbc: 0x00c3, 0x3dbd: 0x00c3, 0x3dbe: 0x00c3, 0x3dbf: 0x00c3,
+	// Block 0xf7, offset 0x3dc0
+	0x3dc0: 0x00c3, 0x3dc2: 0x00c0, 0x3dc5: 0x00c0,
+	0x3dc7: 0x00c0, 0x3dc8: 0x00c0, 0x3dc9: 0x00c0, 0x3dca: 0x00c0,
+	0x3dcc: 0x00c0, 0x3dcd: 0x00c0, 0x3dce: 0x00c6, 0x3dcf: 0x00c5, 0x3dd0: 0x00c6, 0x3dd1: 0x00c0,
+	0x3dd2: 0x00c3, 0x3dd3: 0x00c0, 0x3dd4: 0x0080, 0x3dd5: 0x0080, 0x3dd7: 0x0080,
+	0x3dd8: 0x0080,
+	0x3de1: 0x00c3, 0x3de2: 0x00c3,
+	// Block 0xf8, offset 0x3e00
+	0x3e00: 0x00c0, 0x3e01: 0x00c0, 0x3e02: 0x00c0, 0x3e03: 0x00c0, 0x3e04: 0x00c0, 0x3e05: 0x00c0,
+	0x3e06: 0x00c0, 0x3e07: 0x00c0, 0x3e08: 0x00c0, 0x3e09: 0x00c0, 0x3e0a: 0x00c0, 0x3e0b: 0x00c0,
+	0x3e0c: 0x00c0, 0x3e0d: 0x00c0, 0x3e0e: 0x00c0, 0x3e0f: 0x00c0, 0x3e10: 0x00c0, 0x3e11: 0x00c0,
+	0x3e12: 0x00c0, 0x3e13: 0x00c0, 0x3e14: 0x00c0, 0x3e15: 0x00c0, 0x3e16: 0x00c0, 0x3e17: 0x00c0,
+	0x3e18: 0x00c0, 0x3e19: 0x00c0, 0x3e1a: 0x00c0, 0x3e1b: 0x00c0, 0x3e1c: 0x00c0, 0x3e1d: 0x00c0,
+	0x3e1e: 0x00c0, 0x3e1f: 0x00c0, 0x3e20: 0x00c0, 0x3e21: 0x00c0, 0x3e22: 0x00c0, 0x3e23: 0x00c0,
+	0x3e24: 0x00c0, 0x3e25: 0x00c0, 0x3e26: 0x00c0, 0x3e27: 0x00c0, 0x3e28: 0x00c0, 0x3e29: 0x00c0,
+	0x3e2a: 0x00c0, 0x3e2b: 0x00c0, 0x3e2c: 0x00c0, 0x3e2d: 0x00c0, 0x3e2e: 0x00c0, 0x3e2f: 0x00c0,
+	0x3e30: 0x00c0, 0x3e31: 0x00c0, 0x3e32: 0x00c0, 0x3e33: 0x00c0, 0x3e34: 0x00c0, 0x3e35: 0x00c0,
+	0x3e36: 0x00c0, 0x3e37: 0x00c0, 0x3e38: 0x00c3, 0x3e39: 0x00c3, 0x3e3a: 0x00c3, 0x3e3b: 0x00c3,
+	0x3e3c: 0x00c3, 0x3e3d: 0x00c3, 0x3e3e: 0x00c3, 0x3e3f: 0x00c3,
+	// Block 0xf9, offset 0x3e40
+	0x3e40: 0x00c0, 0x3e41: 0x00c0, 0x3e42: 0x00c6, 0x3e43: 0x00c3, 0x3e44: 0x00c3, 0x3e45: 0x00c0,
+	0x3e46: 0x00c3, 0x3e47: 0x00c0, 0x3e48: 0x00c0, 0x3e49: 0x00c0, 0x3e4a: 0x00c0, 0x3e4b: 0x0080,
+	0x3e4c: 0x0080, 0x3e4d: 0x0080, 0x3e4e: 0x0080, 0x3e4f: 0x0080, 0x3e50: 0x00c0, 0x3e51: 0x00c0,
+	0x3e52: 0x00c0, 0x3e53: 0x00c0, 0x3e54: 0x00c0, 0x3e55: 0x00c0, 0x3e56: 0x00c0, 0x3e57: 0x00c0,
+	0x3e58: 0x00c0, 0x3e59: 0x00c0, 0x3e5a: 0x0080, 0x3e5b: 0x0080, 0x3e5d: 0x0080,
+	0x3e5e: 0x00c3, 0x3e5f: 0x00c0, 0x3e60: 0x00c0, 0x3e61: 0x00c0,
+	// Block 0xfa, offset 0x3e80
+	0x3e80: 0x00c0, 0x3e81: 0x00c0, 0x3e82: 0x00c0, 0x3e83: 0x00c0, 0x3e84: 0x00c0, 0x3e85: 0x00c0,
+	0x3e86: 0x00c0, 0x3e87: 0x00c0, 0x3e88: 0x00c0, 0x3e89: 0x00c0, 0x3e8a: 0x00c0, 0x3e8b: 0x00c0,
+	0x3e8c: 0x00c0, 0x3e8d: 0x00c0, 0x3e8e: 0x00c0, 0x3e8f: 0x00c0, 0x3e90: 0x00c0, 0x3e91: 0x00c0,
+	0x3e92: 0x00c0, 0x3e93: 0x00c0, 0x3e94: 0x00c0, 0x3e95: 0x00c0, 0x3e96: 0x00c0, 0x3e97: 0x00c0,
+	0x3e98: 0x00c0, 0x3e99: 0x00c0, 0x3e9a: 0x00c0, 0x3e9b: 0x00c0, 0x3e9c: 0x00c0, 0x3e9d: 0x00c0,
+	0x3e9e: 0x00c0, 0x3e9f: 0x00c0, 0x3ea0: 0x00c0, 0x3ea1: 0x00c0, 0x3ea2: 0x00c0, 0x3ea3: 0x00c0,
+	0x3ea4: 0x00c0, 0x3ea5: 0x00c0, 0x3ea6: 0x00c0, 0x3ea7: 0x00c0, 0x3ea8: 0x00c0, 0x3ea9: 0x00c0,
+	0x3eaa: 0x00c0, 0x3eab: 0x00c0, 0x3eac: 0x00c0, 0x3ead: 0x00c0, 0x3eae: 0x00c0, 0x3eaf: 0x00c0,
+	0x3eb0: 0x00c0, 0x3eb1: 0x00c0, 0x3eb2: 0x00c0, 0x3eb3: 0x00c3, 0x3eb4: 0x00c3, 0x3eb5: 0x00c3,
+	0x3eb6: 0x00c3, 0x3eb7: 0x00c3, 0x3eb8: 0x00c3, 0x3eb9: 0x00c0, 0x3eba: 0x00c3, 0x3ebb: 0x00c0,
+	0x3ebc: 0x00c0, 0x3ebd: 0x00c0, 0x3ebe: 0x00c0, 0x3ebf: 0x00c3,
+	// Block 0xfb, offset 0x3ec0
+	0x3ec0: 0x00c3, 0x3ec1: 0x00c0, 0x3ec2: 0x00c6, 0x3ec3: 0x00c3, 0x3ec4: 0x00c0, 0x3ec5: 0x00c0,
+	0x3ec6: 0x0080, 0x3ec7: 0x00c0,
+	0x3ed0: 0x00c0, 0x3ed1: 0x00c0,
+	0x3ed2: 0x00c0, 0x3ed3: 0x00c0, 0x3ed4: 0x00c0, 0x3ed5: 0x00c0, 0x3ed6: 0x00c0, 0x3ed7: 0x00c0,
+	0x3ed8: 0x00c0, 0x3ed9: 0x00c0,
+	// Block 0xfc, offset 0x3f00
+	0x3f00: 0x00c0, 0x3f01: 0x00c0, 0x3f02: 0x00c0, 0x3f03: 0x00c0, 0x3f04: 0x00c0, 0x3f05: 0x00c0,
+	0x3f06: 0x00c0, 0x3f07: 0x00c0, 0x3f08: 0x00c0, 0x3f09: 0x00c0, 0x3f0a: 0x00c0, 0x3f0b: 0x00c0,
+	0x3f0c: 0x00c0, 0x3f0d: 0x00c0, 0x3f0e: 0x00c0, 0x3f0f: 0x00c0, 0x3f10: 0x00c0, 0x3f11: 0x00c0,
+	0x3f12: 0x00c0, 0x3f13: 0x00c0, 0x3f14: 0x00c0, 0x3f15: 0x00c0, 0x3f16: 0x00c0, 0x3f17: 0x00c0,
+	0x3f18: 0x00c0, 0x3f19: 0x00c0, 0x3f1a: 0x00c0, 0x3f1b: 0x00c0, 0x3f1c: 0x00c0, 0x3f1d: 0x00c0,
+	0x3f1e: 0x00c0, 0x3f1f: 0x00c0, 0x3f20: 0x00c0, 0x3f21: 0x00c0, 0x3f22: 0x00c0, 0x3f23: 0x00c0,
+	0x3f24: 0x00c0, 0x3f25: 0x00c0, 0x3f26: 0x00c0, 0x3f27: 0x00c0, 0x3f28: 0x00c0, 0x3f29: 0x00c0,
+	0x3f2a: 0x00c0, 0x3f2b: 0x00c0, 0x3f2c: 0x00c0, 0x3f2d: 0x00c0, 0x3f2e: 0x00c0, 0x3f2f: 0x00c0,
+	0x3f30: 0x00c0, 0x3f31: 0x00c0, 0x3f32: 0x00c3, 0x3f33: 0x00c3, 0x3f34: 0x00c3, 0x3f35: 0x00c3,
+	0x3f38: 0x00c0, 0x3f39: 0x00c0, 0x3f3a: 0x00c0, 0x3f3b: 0x00c0,
+	0x3f3c: 0x00c3, 0x3f3d: 0x00c3, 0x3f3e: 0x00c0, 0x3f3f: 0x00c6,
+	// Block 0xfd, offset 0x3f40
+	0x3f40: 0x00c3, 0x3f41: 0x0080, 0x3f42: 0x0080, 0x3f43: 0x0080, 0x3f44: 0x0080, 0x3f45: 0x0080,
+	0x3f46: 0x0080, 0x3f47: 0x0080, 0x3f48: 0x0080, 0x3f49: 0x0080, 0x3f4a: 0x0080, 0x3f4b: 0x0080,
+	0x3f4c: 0x0080, 0x3f4d: 0x0080, 0x3f4e: 0x0080, 0x3f4f: 0x0080, 0x3f50: 0x0080, 0x3f51: 0x0080,
+	0x3f52: 0x0080, 0x3f53: 0x0080, 0x3f54: 0x0080, 0x3f55: 0x0080, 0x3f56: 0x0080, 0x3f57: 0x0080,
+	0x3f58: 0x00c0, 0x3f59: 0x00c0, 0x3f5a: 0x00c0, 0x3f5b: 0x00c0, 0x3f5c: 0x00c3, 0x3f5d: 0x00c3,
+	// Block 0xfe, offset 0x3f80
+	0x3f80: 0x00c0, 0x3f81: 0x00c0, 0x3f82: 0x00c0, 0x3f83: 0x00c0, 0x3f84: 0x00c0, 0x3f85: 0x00c0,
+	0x3f86: 0x00c0, 0x3f87: 0x00c0, 0x3f88: 0x00c0, 0x3f89: 0x00c0, 0x3f8a: 0x00c0, 0x3f8b: 0x00c0,
+	0x3f8c: 0x00c0, 0x3f8d: 0x00c0, 0x3f8e: 0x00c0, 0x3f8f: 0x00c0, 0x3f90: 0x00c0, 0x3f91: 0x00c0,
+	0x3f92: 0x00c0, 0x3f93: 0x00c0, 0x3f94: 0x00c0, 0x3f95: 0x00c0, 0x3f96: 0x00c0, 0x3f97: 0x00c0,
+	0x3f98: 0x00c0, 0x3f99: 0x00c0, 0x3f9a: 0x00c0, 0x3f9b: 0x00c0, 0x3f9c: 0x00c0, 0x3f9d: 0x00c0,
+	0x3f9e: 0x00c0, 0x3f9f: 0x00c0, 0x3fa0: 0x00c0, 0x3fa1: 0x00c0, 0x3fa2: 0x00c0, 0x3fa3: 0x00c0,
+	0x3fa4: 0x00c0, 0x3fa5: 0x00c0, 0x3fa6: 0x00c0, 0x3fa7: 0x00c0, 0x3fa8: 0x00c0, 0x3fa9: 0x00c0,
+	0x3faa: 0x00c0, 0x3fab: 0x00c0, 0x3fac: 0x00c0, 0x3fad: 0x00c0, 0x3fae: 0x00c0, 0x3faf: 0x00c0,
+	0x3fb0: 0x00c0, 0x3fb1: 0x00c0, 0x3fb2: 0x00c0, 0x3fb3: 0x00c3, 0x3fb4: 0x00c3, 0x3fb5: 0x00c3,
+	0x3fb6: 0x00c3, 0x3fb7: 0x00c3, 0x3fb8: 0x00c3, 0x3fb9: 0x00c3, 0x3fba: 0x00c3, 0x3fbb: 0x00c0,
+	0x3fbc: 0x00c0, 0x3fbd: 0x00c3, 0x3fbe: 0x00c0, 0x3fbf: 0x00c6,
+	// Block 0xff, offset 0x3fc0
+	0x3fc0: 0x00c3, 0x3fc1: 0x0080, 0x3fc2: 0x0080, 0x3fc3: 0x0080, 0x3fc4: 0x00c0,
+	0x3fd0: 0x00c0, 0x3fd1: 0x00c0,
+	0x3fd2: 0x00c0, 0x3fd3: 0x00c0, 0x3fd4: 0x00c0, 0x3fd5: 0x00c0, 0x3fd6: 0x00c0, 0x3fd7: 0x00c0,
+	0x3fd8: 0x00c0, 0x3fd9: 0x00c0,
+	0x3fe0: 0x0080, 0x3fe1: 0x0080, 0x3fe2: 0x0080, 0x3fe3: 0x0080,
+	0x3fe4: 0x0080, 0x3fe5: 0x0080, 0x3fe6: 0x0080, 0x3fe7: 0x0080, 0x3fe8: 0x0080, 0x3fe9: 0x0080,
+	0x3fea: 0x0080, 0x3feb: 0x0080, 0x3fec: 0x0080,
+	// Block 0x100, offset 0x4000
+	0x4000: 0x00c0, 0x4001: 0x00c0, 0x4002: 0x00c0, 0x4003: 0x00c0, 0x4004: 0x00c0, 0x4005: 0x00c0,
+	0x4006: 0x00c0, 0x4007: 0x00c0, 0x4008: 0x00c0, 0x4009: 0x00c0, 0x400a: 0x00c0, 0x400b: 0x00c0,
+	0x400c: 0x00c0, 0x400d: 0x00c0, 0x400e: 0x00c0, 0x400f: 0x00c0, 0x4010: 0x00c0, 0x4011: 0x00c0,
+	0x4012: 0x00c0, 0x4013: 0x00c0, 0x4014: 0x00c0, 0x4015: 0x00c0, 0x4016: 0x00c0, 0x4017: 0x00c0,
+	0x4018: 0x00c0, 0x4019: 0x00c0, 0x401a: 0x00c0, 0x401b: 0x00c0, 0x401c: 0x00c0, 0x401d: 0x00c0,
+	0x401e: 0x00c0, 0x401f: 0x00c0, 0x4020: 0x00c0, 0x4021: 0x00c0, 0x4022: 0x00c0, 0x4023: 0x00c0,
+	0x4024: 0x00c0, 0x4025: 0x00c0, 0x4026: 0x00c0, 0x4027: 0x00c0, 0x4028: 0x00c0, 0x4029: 0x00c0,
+	0x402a: 0x00c0, 0x402b: 0x00c3, 0x402c: 0x00c0, 0x402d: 0x00c3, 0x402e: 0x00c0, 0x402f: 0x00c0,
+	0x4030: 0x00c3, 0x4031: 0x00c3, 0x4032: 0x00c3, 0x4033: 0x00c3, 0x4034: 0x00c3, 0x4035: 0x00c3,
+	0x4036: 0x00c5, 0x4037: 0x00c3, 0x4038: 0x00c0, 0x4039: 0x0080,
+	// Block 0x101, offset 0x4040
+	0x4040: 0x00c0, 0x4041: 0x00c0, 0x4042: 0x00c0, 0x4043: 0x00c0, 0x4044: 0x00c0, 0x4045: 0x00c0,
+	0x4046: 0x00c0, 0x4047: 0x00c0, 0x4048: 0x00c0, 0x4049: 0x00c0,
+	0x4050: 0x00c0, 0x4051: 0x00c0,
+	0x4052: 0x00c0, 0x4053: 0x00c0, 0x4054: 0x00c0, 0x4055: 0x00c0, 0x4056: 0x00c0, 0x4057: 0x00c0,
+	0x4058: 0x00c0, 0x4059: 0x00c0, 0x405a: 0x00c0, 0x405b: 0x00c0, 0x405c: 0x00c0, 0x405d: 0x00c0,
+	0x405e: 0x00c0, 0x405f: 0x00c0, 0x4060: 0x00c0, 0x4061: 0x00c0, 0x4062: 0x00c0, 0x4063: 0x00c0,
+	// Block 0x102, offset 0x4080
+	0x4080: 0x00c0, 0x4081: 0x00c0, 0x4082: 0x00c0, 0x4083: 0x00c0, 0x4084: 0x00c0, 0x4085: 0x00c0,
+	0x4086: 0x00c0, 0x4087: 0x00c0, 0x4088: 0x00c0, 0x4089: 0x00c0, 0x408a: 0x00c0, 0x408b: 0x00c0,
+	0x408c: 0x00c0, 0x408d: 0x00c0, 0x408e: 0x00c0, 0x408f: 0x00c0, 0x4090: 0x00c0, 0x4091: 0x00c0,
+	0x4092: 0x00c0, 0x4093: 0x00c0, 0x4094: 0x00c0, 0x4095: 0x00c0, 0x4096: 0x00c0, 0x4097: 0x00c0,
+	0x4098: 0x00c0, 0x4099: 0x00c0, 0x409a: 0x00c0, 0x409d: 0x00c3,
+	0x409e: 0x00c0, 0x409f: 0x00c3, 0x40a0: 0x00c0, 0x40a1: 0x00c0, 0x40a2: 0x00c3, 0x40a3: 0x00c3,
+	0x40a4: 0x00c3, 0x40a5: 0x00c3, 0x40a6: 0x00c0, 0x40a7: 0x00c3, 0x40a8: 0x00c3, 0x40a9: 0x00c3,
+	0x40aa: 0x00c3, 0x40ab: 0x00c6,
+	0x40b0: 0x00c0, 0x40b1: 0x00c0, 0x40b2: 0x00c0, 0x40b3: 0x00c0, 0x40b4: 0x00c0, 0x40b5: 0x00c0,
+	0x40b6: 0x00c0, 0x40b7: 0x00c0, 0x40b8: 0x00c0, 0x40b9: 0x00c0, 0x40ba: 0x0080, 0x40bb: 0x0080,
+	0x40bc: 0x0080, 0x40bd: 0x0080, 0x40be: 0x0080, 0x40bf: 0x0080,
+	// Block 0x103, offset 0x40c0
+	0x40c0: 0x00c0, 0x40c1: 0x00c0, 0x40c2: 0x00c0, 0x40c3: 0x00c0, 0x40c4: 0x00c0, 0x40c5: 0x00c0,
+	0x40c6: 0x00c0,
+	// Block 0x104, offset 0x4100
+	0x4100: 0x00c0, 0x4101: 0x00c0, 0x4102: 0x00c0, 0x4103: 0x00c0, 0x4104: 0x00c0, 0x4105: 0x00c0,
+	0x4106: 0x00c0, 0x4107: 0x00c0, 0x4108: 0x00c0, 0x4109: 0x00c0, 0x410a: 0x00c0, 0x410b: 0x00c0,
+	0x410c: 0x00c0, 0x410d: 0x00c0, 0x410e: 0x00c0, 0x410f: 0x00c0, 0x4110: 0x00c0, 0x4111: 0x00c0,
+	0x4112: 0x00c0, 0x4113: 0x00c0, 0x4114: 0x00c0, 0x4115: 0x00c0, 0x4116: 0x00c0, 0x4117: 0x00c0,
+	0x4118: 0x00c0, 0x4119: 0x00c0, 0x411a: 0x00c0, 0x411b: 0x00c0, 0x411c: 0x00c0, 0x411d: 0x00c0,
+	0x411e: 0x00c0, 0x411f: 0x00c0, 0x4120: 0x00c0, 0x4121: 0x00c0, 0x4122: 0x00c0, 0x4123: 0x00c0,
+	0x4124: 0x00c0, 0x4125: 0x00c0, 0x4126: 0x00c0, 0x4127: 0x00c0, 0x4128: 0x00c0, 0x4129: 0x00c0,
+	0x412a: 0x00c0, 0x412b: 0x00c0, 0x412c: 0x00c0, 0x412d: 0x00c0, 0x412e: 0x00c0, 0x412f: 0x00c3,
+	0x4130: 0x00c3, 0x4131: 0x00c3, 0x4132: 0x00c3, 0x4133: 0x00c3, 0x4134: 0x00c3, 0x4135: 0x00c3,
+	0x4136: 0x00c3, 0x4137: 0x00c3, 0x4138: 0x00c0, 0x4139: 0x00c6, 0x413a: 0x00c3, 0x413b: 0x0080,
+	// Block 0x105, offset 0x4140
+	0x4160: 0x00c0, 0x4161: 0x00c0, 0x4162: 0x00c0, 0x4163: 0x00c0,
+	0x4164: 0x00c0, 0x4165: 0x00c0, 0x4166: 0x00c0, 0x4167: 0x00c0, 0x4168: 0x00c0, 0x4169: 0x00c0,
+	0x416a: 0x00c0, 0x416b: 0x00c0, 0x416c: 0x00c0, 0x416d: 0x00c0, 0x416e: 0x00c0, 0x416f: 0x00c0,
+	0x4170: 0x00c0, 0x4171: 0x00c0, 0x4172: 0x00c0, 0x4173: 0x00c0, 0x4174: 0x00c0, 0x4175: 0x00c0,
+	0x4176: 0x00c0, 0x4177: 0x00c0, 0x4178: 0x00c0, 0x4179: 0x00c0, 0x417a: 0x00c0, 0x417b: 0x00c0,
+	0x417c: 0x00c0, 0x417d: 0x00c0, 0x417e: 0x00c0, 0x417f: 0x00c0,
+	// Block 0x106, offset 0x4180
+	0x4180: 0x00c0, 0x4181: 0x00c0, 0x4182: 0x00c0, 0x4183: 0x00c0, 0x4184: 0x00c0, 0x4185: 0x00c0,
+	0x4186: 0x00c0, 0x4187: 0x00c0, 0x4188: 0x00c0, 0x4189: 0x00c0, 0x418a: 0x00c0, 0x418b: 0x00c0,
+	0x418c: 0x00c0, 0x418d: 0x00c0, 0x418e: 0x00c0, 0x418f: 0x00c0, 0x4190: 0x00c0, 0x4191: 0x00c0,
+	0x4192: 0x00c0, 0x4193: 0x00c0, 0x4194: 0x00c0, 0x4195: 0x00c0, 0x4196: 0x00c0, 0x4197: 0x00c0,
+	0x4198: 0x00c0, 0x4199: 0x00c0, 0x419a: 0x00c0, 0x419b: 0x00c0, 0x419c: 0x00c0, 0x419d: 0x00c0,
+	0x419e: 0x00c0, 0x419f: 0x00c0, 0x41a0: 0x00c0, 0x41a1: 0x00c0, 0x41a2: 0x00c0, 0x41a3: 0x00c0,
+	0x41a4: 0x00c0, 0x41a5: 0x00c0, 0x41a6: 0x00c0, 0x41a7: 0x00c0, 0x41a8: 0x00c0, 0x41a9: 0x00c0,
+	0x41aa: 0x0080, 0x41ab: 0x0080, 0x41ac: 0x0080, 0x41ad: 0x0080, 0x41ae: 0x0080, 0x41af: 0x0080,
+	0x41b0: 0x0080, 0x41b1: 0x0080, 0x41b2: 0x0080,
+	0x41bf: 0x00c0,
+	// Block 0x107, offset 0x41c0
+	0x41c0: 0x00c0, 0x41c1: 0x00c0, 0x41c2: 0x00c0, 0x41c3: 0x00c0, 0x41c4: 0x00c0, 0x41c5: 0x00c0,
+	0x41c6: 0x00c0, 0x41c9: 0x00c0,
+	0x41cc: 0x00c0, 0x41cd: 0x00c0, 0x41ce: 0x00c0, 0x41cf: 0x00c0, 0x41d0: 0x00c0, 0x41d1: 0x00c0,
+	0x41d2: 0x00c0, 0x41d3: 0x00c0, 0x41d5: 0x00c0, 0x41d6: 0x00c0,
+	0x41d8: 0x00c0, 0x41d9: 0x00c0, 0x41da: 0x00c0, 0x41db: 0x00c0, 0x41dc: 0x00c0, 0x41dd: 0x00c0,
+	0x41de: 0x00c0, 0x41df: 0x00c0, 0x41e0: 0x00c0, 0x41e1: 0x00c0, 0x41e2: 0x00c0, 0x41e3: 0x00c0,
+	0x41e4: 0x00c0, 0x41e5: 0x00c0, 0x41e6: 0x00c0, 0x41e7: 0x00c0, 0x41e8: 0x00c0, 0x41e9: 0x00c0,
+	0x41ea: 0x00c0, 0x41eb: 0x00c0, 0x41ec: 0x00c0, 0x41ed: 0x00c0, 0x41ee: 0x00c0, 0x41ef: 0x00c0,
+	0x41f0: 0x00c0, 0x41f1: 0x00c0, 0x41f2: 0x00c0, 0x41f3: 0x00c0, 0x41f4: 0x00c0, 0x41f5: 0x00c0,
+	0x41f7: 0x00c0, 0x41f8: 0x00c0, 0x41fb: 0x00c3,
+	0x41fc: 0x00c3, 0x41fd: 0x00c5, 0x41fe: 0x00c6, 0x41ff: 0x00c0,
+	// Block 0x108, offset 0x4200
+	0x4200: 0x00c0, 0x4201: 0x00c0, 0x4202: 0x00c0, 0x4203: 0x00c3, 0x4204: 0x0080, 0x4205: 0x0080,
+	0x4206: 0x0080,
+	0x4210: 0x00c0, 0x4211: 0x00c0,
+	0x4212: 0x00c0, 0x4213: 0x00c0, 0x4214: 0x00c0, 0x4215: 0x00c0, 0x4216: 0x00c0, 0x4217: 0x00c0,
+	0x4218: 0x00c0, 0x4219: 0x00c0,
+	// Block 0x109, offset 0x4240
+	0x4260: 0x00c0, 0x4261: 0x00c0, 0x4262: 0x00c0, 0x4263: 0x00c0,
+	0x4264: 0x00c0, 0x4265: 0x00c0, 0x4266: 0x00c0, 0x4267: 0x00c0,
+	0x426a: 0x00c0, 0x426b: 0x00c0, 0x426c: 0x00c0, 0x426d: 0x00c0, 0x426e: 0x00c0, 0x426f: 0x00c0,
+	0x4270: 0x00c0, 0x4271: 0x00c0, 0x4272: 0x00c0, 0x4273: 0x00c0, 0x4274: 0x00c0, 0x4275: 0x00c0,
+	0x4276: 0x00c0, 0x4277: 0x00c0, 0x4278: 0x00c0, 0x4279: 0x00c0, 0x427a: 0x00c0, 0x427b: 0x00c0,
+	0x427c: 0x00c0, 0x427d: 0x00c0, 0x427e: 0x00c0, 0x427f: 0x00c0,
+	// Block 0x10a, offset 0x4280
+	0x4280: 0x00c0, 0x4281: 0x00c0, 0x4282: 0x00c0, 0x4283: 0x00c0, 0x4284: 0x00c0, 0x4285: 0x00c0,
+	0x4286: 0x00c0, 0x4287: 0x00c0, 0x4288: 0x00c0, 0x4289: 0x00c0, 0x428a: 0x00c0, 0x428b: 0x00c0,
+	0x428c: 0x00c0, 0x428d: 0x00c0, 0x428e: 0x00c0, 0x428f: 0x00c0, 0x4290: 0x00c0, 0x4291: 0x00c0,
+	0x4292: 0x00c0, 0x4293: 0x00c0, 0x4294: 0x00c3, 0x4295: 0x00c3, 0x4296: 0x00c3, 0x4297: 0x00c3,
+	0x429a: 0x00c3, 0x429b: 0x00c3, 0x429c: 0x00c0, 0x429d: 0x00c0,
+	0x429e: 0x00c0, 0x429f: 0x00c0, 0x42a0: 0x00c6, 0x42a1: 0x00c0, 0x42a2: 0x0080, 0x42a3: 0x00c0,
+	0x42a4: 0x00c0,
+	// Block 0x10b, offset 0x42c0
+	0x42c0: 0x00c0, 0x42c1: 0x00c3, 0x42c2: 0x00c3, 0x42c3: 0x00c3, 0x42c4: 0x00c3, 0x42c5: 0x00c3,
+	0x42c6: 0x00c3, 0x42c7: 0x00c3, 0x42c8: 0x00c3, 0x42c9: 0x00c3, 0x42ca: 0x00c3, 0x42cb: 0x00c0,
+	0x42cc: 0x00c0, 0x42cd: 0x00c0, 0x42ce: 0x00c0, 0x42cf: 0x00c0, 0x42d0: 0x00c0, 0x42d1: 0x00c0,
+	0x42d2: 0x00c0, 0x42d3: 0x00c0, 0x42d4: 0x00c0, 0x42d5: 0x00c0, 0x42d6: 0x00c0, 0x42d7: 0x00c0,
+	0x42d8: 0x00c0, 0x42d9: 0x00c0, 0x42da: 0x00c0, 0x42db: 0x00c0, 0x42dc: 0x00c0, 0x42dd: 0x00c0,
+	0x42de: 0x00c0, 0x42df: 0x00c0, 0x42e0: 0x00c0, 0x42e1: 0x00c0, 0x42e2: 0x00c0, 0x42e3: 0x00c0,
+	0x42e4: 0x00c0, 0x42e5: 0x00c0, 0x42e6: 0x00c0, 0x42e7: 0x00c0, 0x42e8: 0x00c0, 0x42e9: 0x00c0,
+	0x42ea: 0x00c0, 0x42eb: 0x00c0, 0x42ec: 0x00c0, 0x42ed: 0x00c0, 0x42ee: 0x00c0, 0x42ef: 0x00c0,
+	0x42f0: 0x00c0, 0x42f1: 0x00c0, 0x42f2: 0x00c0, 0x42f3: 0x00c3, 0x42f4: 0x00c6, 0x42f5: 0x00c3,
+	0x42f6: 0x00c3, 0x42f7: 0x00c3, 0x42f8: 0x00c3, 0x42f9: 0x00c0, 0x42fa: 0x00c0, 0x42fb: 0x00c3,
+	0x42fc: 0x00c3, 0x42fd: 0x00c3, 0x42fe: 0x00c3, 0x42ff: 0x0080,
+	// Block 0x10c, offset 0x4300
+	0x4300: 0x0080, 0x4301: 0x0080, 0x4302: 0x0080, 0x4303: 0x0080, 0x4304: 0x0080, 0x4305: 0x0080,
+	0x4306: 0x0080, 0x4307: 0x00c6,
+	0x4310: 0x00c0, 0x4311: 0x00c3,
+	0x4312: 0x00c3, 0x4313: 0x00c3, 0x4314: 0x00c3, 0x4315: 0x00c3, 0x4316: 0x00c3, 0x4317: 0x00c0,
+	0x4318: 0x00c0, 0x4319: 0x00c3, 0x431a: 0x00c3, 0x431b: 0x00c3, 0x431c: 0x00c0, 0x431d: 0x00c0,
+	0x431e: 0x00c0, 0x431f: 0x00c0, 0x4320: 0x00c0, 0x4321: 0x00c0, 0x4322: 0x00c0, 0x4323: 0x00c0,
+	0x4324: 0x00c0, 0x4325: 0x00c0, 0x4326: 0x00c0, 0x4327: 0x00c0, 0x4328: 0x00c0, 0x4329: 0x00c0,
+	0x432a: 0x00c0, 0x432b: 0x00c0, 0x432c: 0x00c0, 0x432d: 0x00c0, 0x432e: 0x00c0, 0x432f: 0x00c0,
+	0x4330: 0x00c0, 0x4331: 0x00c0, 0x4332: 0x00c0, 0x4333: 0x00c0, 0x4334: 0x00c0, 0x4335: 0x00c0,
+	0x4336: 0x00c0, 0x4337: 0x00c0, 0x4338: 0x00c0, 0x4339: 0x00c0, 0x433a: 0x00c0, 0x433b: 0x00c0,
+	0x433c: 0x00c0, 0x433d: 0x00c0, 0x433e: 0x00c0, 0x433f: 0x00c0,
+	// Block 0x10d, offset 0x4340
+	0x4340: 0x00c0, 0x4341: 0x00c0, 0x4342: 0x00c0, 0x4343: 0x00c0, 0x4344: 0x00c0, 0x4345: 0x00c0,
+	0x4346: 0x00c0, 0x4347: 0x00c0, 0x4348: 0x00c0, 0x4349: 0x00c0, 0x434a: 0x00c3, 0x434b: 0x00c3,
+	0x434c: 0x00c3, 0x434d: 0x00c3, 0x434e: 0x00c3, 0x434f: 0x00c3, 0x4350: 0x00c3, 0x4351: 0x00c3,
+	0x4352: 0x00c3, 0x4353: 0x00c3, 0x4354: 0x00c3, 0x4355: 0x00c3, 0x4356: 0x00c3, 0x4357: 0x00c0,
+	0x4358: 0x00c3, 0x4359: 0x00c6, 0x435a: 0x0080, 0x435b: 0x0080, 0x435c: 0x0080, 0x435d: 0x00c0,
+	0x435e: 0x0080, 0x435f: 0x0080, 0x4360: 0x0080, 0x4361: 0x0080, 0x4362: 0x0080,
+	0x4370: 0x00c0, 0x4371: 0x00c0, 0x4372: 0x00c0, 0x4373: 0x00c0, 0x4374: 0x00c0, 0x4375: 0x00c0,
+	0x4376: 0x00c0, 0x4377: 0x00c0, 0x4378: 0x00c0, 0x4379: 0x00c0, 0x437a: 0x00c0, 0x437b: 0x00c0,
+	0x437c: 0x00c0, 0x437d: 0x00c0, 0x437e: 0x00c0, 0x437f: 0x00c0,
+	// Block 0x10e, offset 0x4380
+	0x4380: 0x00c0, 0x4381: 0x00c0, 0x4382: 0x00c0, 0x4383: 0x00c0, 0x4384: 0x00c0, 0x4385: 0x00c0,
+	0x4386: 0x00c0, 0x4387: 0x00c0, 0x4388: 0x00c0, 0x4389: 0x00c0, 0x438a: 0x00c0, 0x438b: 0x00c0,
+	0x438c: 0x00c0, 0x438d: 0x00c0, 0x438e: 0x00c0, 0x438f: 0x00c0, 0x4390: 0x00c0, 0x4391: 0x00c0,
+	0x4392: 0x00c0, 0x4393: 0x00c0, 0x4394: 0x00c0, 0x4395: 0x00c0, 0x4396: 0x00c0, 0x4397: 0x00c0,
+	0x4398: 0x00c0, 0x4399: 0x00c0, 0x439a: 0x00c0, 0x439b: 0x00c0, 0x439c: 0x00c0, 0x439d: 0x00c0,
+	0x439e: 0x00c0, 0x439f: 0x00c0, 0x43a0: 0x00c0, 0x43a1: 0x00c0, 0x43a2: 0x00c0, 0x43a3: 0x00c0,
+	0x43a4: 0x00c0, 0x43a5: 0x00c0, 0x43a6: 0x00c0, 0x43a7: 0x00c0, 0x43a8: 0x00c0, 0x43a9: 0x00c0,
+	0x43aa: 0x00c0, 0x43ab: 0x00c0, 0x43ac: 0x00c0, 0x43ad: 0x00c0, 0x43ae: 0x00c0, 0x43af: 0x00c0,
+	0x43b0: 0x00c0, 0x43b1: 0x00c0, 0x43b2: 0x00c0, 0x43b3: 0x00c0, 0x43b4: 0x00c0, 0x43b5: 0x00c0,
+	0x43b6: 0x00c0, 0x43b7: 0x00c0, 0x43b8: 0x00c0,
+	// Block 0x10f, offset 0x43c0
+	0x43c0: 0x0080, 0x43c1: 0x0080, 0x43c2: 0x0080, 0x43c3: 0x0080, 0x43c4: 0x0080, 0x43c5: 0x0080,
+	0x43c6: 0x0080, 0x43c7: 0x0080, 0x43c8: 0x0080, 0x43c9: 0x0080,
+	// Block 0x110, offset 0x4400
+	0x4420: 0x00c3, 0x4421: 0x00c0, 0x4422: 0x00c3, 0x4423: 0x00c3,
+	0x4424: 0x00c3, 0x4425: 0x00c0, 0x4426: 0x00c3, 0x4427: 0x00c0,
+	// Block 0x111, offset 0x4440
+	0x4440: 0x00c0, 0x4441: 0x00c0, 0x4442: 0x00c0, 0x4443: 0x00c0, 0x4444: 0x00c0, 0x4445: 0x00c0,
+	0x4446: 0x00c0, 0x4447: 0x00c0, 0x4448: 0x00c0, 0x4449: 0x00c0, 0x444a: 0x00c0, 0x444b: 0x00c0,
+	0x444c: 0x00c0, 0x444d: 0x00c0, 0x444e: 0x00c0, 0x444f: 0x00c0, 0x4450: 0x00c0, 0x4451: 0x00c0,
+	0x4452: 0x00c0, 0x4453: 0x00c0, 0x4454: 0x00c0, 0x4455: 0x00c0, 0x4456: 0x00c0, 0x4457: 0x00c0,
+	0x4458: 0x00c0, 0x4459: 0x00c0, 0x445a: 0x00c0, 0x445b: 0x00c0, 0x445c: 0x00c0, 0x445d: 0x00c0,
+	0x445e: 0x00c0, 0x445f: 0x00c0, 0x4460: 0x00c0, 0x4461: 0x0080,
+	0x4470: 0x00c0, 0x4471: 0x00c0, 0x4472: 0x00c0, 0x4473: 0x00c0, 0x4474: 0x00c0, 0x4475: 0x00c0,
+	0x4476: 0x00c0, 0x4477: 0x00c0, 0x4478: 0x00c0, 0x4479: 0x00c0,
+	// Block 0x112, offset 0x4480
+	0x4480: 0x00c0, 0x4481: 0x00c0, 0x4482: 0x00c0, 0x4483: 0x00c0, 0x4484: 0x00c0, 0x4485: 0x00c0,
+	0x4486: 0x00c0, 0x4487: 0x00c0, 0x4488: 0x00c0, 0x448a: 0x00c0, 0x448b: 0x00c0,
+	0x448c: 0x00c0, 0x448d: 0x00c0, 0x448e: 0x00c0, 0x448f: 0x00c0, 0x4490: 0x00c0, 0x4491: 0x00c0,
+	0x4492: 0x00c0, 0x4493: 0x00c0, 0x4494: 0x00c0, 0x4495: 0x00c0, 0x4496: 0x00c0, 0x4497: 0x00c0,
+	0x4498: 0x00c0, 0x4499: 0x00c0, 0x449a: 0x00c0, 0x449b: 0x00c0, 0x449c: 0x00c0, 0x449d: 0x00c0,
+	0x449e: 0x00c0, 0x449f: 0x00c0, 0x44a0: 0x00c0, 0x44a1: 0x00c0, 0x44a2: 0x00c0, 0x44a3: 0x00c0,
+	0x44a4: 0x00c0, 0x44a5: 0x00c0, 0x44a6: 0x00c0, 0x44a7: 0x00c0, 0x44a8: 0x00c0, 0x44a9: 0x00c0,
+	0x44aa: 0x00c0, 0x44ab: 0x00c0, 0x44ac: 0x00c0, 0x44ad: 0x00c0, 0x44ae: 0x00c0, 0x44af: 0x00c0,
+	0x44b0: 0x00c3, 0x44b1: 0x00c3, 0x44b2: 0x00c3, 0x44b3: 0x00c3, 0x44b4: 0x00c3, 0x44b5: 0x00c3,
+	0x44b6: 0x00c3, 0x44b8: 0x00c3, 0x44b9: 0x00c3, 0x44ba: 0x00c3, 0x44bb: 0x00c3,
+	0x44bc: 0x00c3, 0x44bd: 0x00c3, 0x44be: 0x00c0, 0x44bf: 0x00c6,
+	// Block 0x113, offset 0x44c0
+	0x44c0: 0x00c0, 0x44c1: 0x0080, 0x44c2: 0x0080, 0x44c3: 0x0080, 0x44c4: 0x0080, 0x44c5: 0x0080,
+	0x44d0: 0x00c0, 0x44d1: 0x00c0,
+	0x44d2: 0x00c0, 0x44d3: 0x00c0, 0x44d4: 0x00c0, 0x44d5: 0x00c0, 0x44d6: 0x00c0, 0x44d7: 0x00c0,
+	0x44d8: 0x00c0, 0x44d9: 0x00c0, 0x44da: 0x0080, 0x44db: 0x0080, 0x44dc: 0x0080, 0x44dd: 0x0080,
+	0x44de: 0x0080, 0x44df: 0x0080, 0x44e0: 0x0080, 0x44e1: 0x0080, 0x44e2: 0x0080, 0x44e3: 0x0080,
+	0x44e4: 0x0080, 0x44e5: 0x0080, 0x44e6: 0x0080, 0x44e7: 0x0080, 0x44e8: 0x0080, 0x44e9: 0x0080,
+	0x44ea: 0x0080, 0x44eb: 0x0080, 0x44ec: 0x0080,
+	0x44f0: 0x0080, 0x44f1: 0x0080, 0x44f2: 0x00c0, 0x44f3: 0x00c0, 0x44f4: 0x00c0, 0x44f5: 0x00c0,
+	0x44f6: 0x00c0, 0x44f7: 0x00c0, 0x44f8: 0x00c0, 0x44f9: 0x00c0, 0x44fa: 0x00c0, 0x44fb: 0x00c0,
+	0x44fc: 0x00c0, 0x44fd: 0x00c0, 0x44fe: 0x00c0, 0x44ff: 0x00c0,
+	// Block 0x114, offset 0x4500
+	0x4500: 0x00c0, 0x4501: 0x00c0, 0x4502: 0x00c0, 0x4503: 0x00c0, 0x4504: 0x00c0, 0x4505: 0x00c0,
+	0x4506: 0x00c0, 0x4507: 0x00c0, 0x4508: 0x00c0, 0x4509: 0x00c0, 0x450a: 0x00c0, 0x450b: 0x00c0,
+	0x450c: 0x00c0, 0x450d: 0x00c0, 0x450e: 0x00c0, 0x450f: 0x00c0,
+	0x4512: 0x00c3, 0x4513: 0x00c3, 0x4514: 0x00c3, 0x4515: 0x00c3, 0x4516: 0x00c3, 0x4517: 0x00c3,
+	0x4518: 0x00c3, 0x4519: 0x00c3, 0x451a: 0x00c3, 0x451b: 0x00c3, 0x451c: 0x00c3, 0x451d: 0x00c3,
+	0x451e: 0x00c3, 0x451f: 0x00c3, 0x4520: 0x00c3, 0x4521: 0x00c3, 0x4522: 0x00c3, 0x4523: 0x00c3,
+	0x4524: 0x00c3, 0x4525: 0x00c3, 0x4526: 0x00c3, 0x4527: 0x00c3, 0x4529: 0x00c0,
+	0x452a: 0x00c3, 0x452b: 0x00c3, 0x452c: 0x00c3, 0x452d: 0x00c3, 0x452e: 0x00c3, 0x452f: 0x00c3,
+	0x4530: 0x00c3, 0x4531: 0x00c0, 0x4532: 0x00c3, 0x4533: 0x00c3, 0x4534: 0x00c0, 0x4535: 0x00c3,
+	0x4536: 0x00c3,
+	// Block 0x115, offset 0x4540
+	0x4540: 0x00c0, 0x4541: 0x00c0, 0x4542: 0x00c0, 0x4543: 0x00c0, 0x4544: 0x00c0, 0x4545: 0x00c0,
+	0x4546: 0x00c0, 0x4548: 0x00c0, 0x4549: 0x00c0, 0x454b: 0x00c0,
+	0x454c: 0x00c0, 0x454d: 0x00c0, 0x454e: 0x00c0, 0x454f: 0x00c0, 0x4550: 0x00c0, 0x4551: 0x00c0,
+	0x4552: 0x00c0, 0x4553: 0x00c0, 0x4554: 0x00c0, 0x4555: 0x00c0, 0x4556: 0x00c0, 0x4557: 0x00c0,
+	0x4558: 0x00c0, 0x4559: 0x00c0, 0x455a: 0x00c0, 0x455b: 0x00c0, 0x455c: 0x00c0, 0x455d: 0x00c0,
+	0x455e: 0x00c0, 0x455f: 0x00c0, 0x4560: 0x00c0, 0x4561: 0x00c0, 0x4562: 0x00c0, 0x4563: 0x00c0,
+	0x4564: 0x00c0, 0x4565: 0x00c0, 0x4566: 0x00c0, 0x4567: 0x00c0, 0x4568: 0x00c0, 0x4569: 0x00c0,
+	0x456a: 0x00c0, 0x456b: 0x00c0, 0x456c: 0x00c0, 0x456d: 0x00c0, 0x456e: 0x00c0, 0x456f: 0x00c0,
+	0x4570: 0x00c0, 0x4571: 0x00c3, 0x4572: 0x00c3, 0x4573: 0x00c3, 0x4574: 0x00c3, 0x4575: 0x00c3,
+	0x4576: 0x00c3, 0x457a: 0x00c3,
+	0x457c: 0x00c3, 0x457d: 0x00c3, 0x457f: 0x00c3,
+	// Block 0x116, offset 0x4580
+	0x4580: 0x00c3, 0x4581: 0x00c3, 0x4582: 0x00c3, 0x4583: 0x00c3, 0x4584: 0x00c6, 0x4585: 0x00c6,
+	0x4586: 0x00c0, 0x4587: 0x00c3,
+	0x4590: 0x00c0, 0x4591: 0x00c0,
+	0x4592: 0x00c0, 0x4593: 0x00c0, 0x4594: 0x00c0, 0x4595: 0x00c0, 0x4596: 0x00c0, 0x4597: 0x00c0,
+	0x4598: 0x00c0, 0x4599: 0x00c0,
+	0x45a0: 0x00c0, 0x45a1: 0x00c0, 0x45a2: 0x00c0, 0x45a3: 0x00c0,
+	0x45a4: 0x00c0, 0x45a5: 0x00c0, 0x45a7: 0x00c0, 0x45a8: 0x00c0,
+	0x45aa: 0x00c0, 0x45ab: 0x00c0, 0x45ac: 0x00c0, 0x45ad: 0x00c0, 0x45ae: 0x00c0, 0x45af: 0x00c0,
+	0x45b0: 0x00c0, 0x45b1: 0x00c0, 0x45b2: 0x00c0, 0x45b3: 0x00c0, 0x45b4: 0x00c0, 0x45b5: 0x00c0,
+	0x45b6: 0x00c0, 0x45b7: 0x00c0, 0x45b8: 0x00c0, 0x45b9: 0x00c0, 0x45ba: 0x00c0, 0x45bb: 0x00c0,
+	0x45bc: 0x00c0, 0x45bd: 0x00c0, 0x45be: 0x00c0, 0x45bf: 0x00c0,
+	// Block 0x117, offset 0x45c0
+	0x45c0: 0x00c0, 0x45c1: 0x00c0, 0x45c2: 0x00c0, 0x45c3: 0x00c0, 0x45c4: 0x00c0, 0x45c5: 0x00c0,
+	0x45c6: 0x00c0, 0x45c7: 0x00c0, 0x45c8: 0x00c0, 0x45c9: 0x00c0, 0x45ca: 0x00c0, 0x45cb: 0x00c0,
+	0x45cc: 0x00c0, 0x45cd: 0x00c0, 0x45ce: 0x00c0, 0x45d0: 0x00c3, 0x45d1: 0x00c3,
+	0x45d3: 0x00c0, 0x45d4: 0x00c0, 0x45d5: 0x00c3, 0x45d6: 0x00c0, 0x45d7: 0x00c6,
+	0x45d8: 0x00c0,
+	0x45e0: 0x00c0, 0x45e1: 0x00c0, 0x45e2: 0x00c0, 0x45e3: 0x00c0,
+	0x45e4: 0x00c0, 0x45e5: 0x00c0, 0x45e6: 0x00c0, 0x45e7: 0x00c0, 0x45e8: 0x00c0, 0x45e9: 0x00c0,
+	0x45f0: 0x00c0, 0x45f1: 0x00c0, 0x45f2: 0x00c0, 0x45f3: 0x00c0, 0x45f4: 0x00c0, 0x45f5: 0x00c0,
+	0x45f6: 0x00c0, 0x45f7: 0x00c0, 0x45f8: 0x00c0, 0x45f9: 0x00c0, 0x45fa: 0x00c0, 0x45fb: 0x00c0,
+	0x45fc: 0x00c0, 0x45fd: 0x00c0, 0x45fe: 0x00c0, 0x45ff: 0x00c0,
+	// Block 0x118, offset 0x4600
+	0x4600: 0x00c0, 0x4601: 0x00c0, 0x4602: 0x00c0, 0x4603: 0x00c0, 0x4604: 0x00c0, 0x4605: 0x00c0,
+	0x4606: 0x00c0, 0x4607: 0x00c0, 0x4608: 0x00c0, 0x4609: 0x00c0, 0x460a: 0x00c0, 0x460b: 0x00c0,
+	0x460c: 0x00c0, 0x460d: 0x00c0, 0x460e: 0x00c0, 0x460f: 0x00c0, 0x4610: 0x00c0, 0x4611: 0x00c0,
+	0x4612: 0x00c0, 0x4613: 0x00c0, 0x4614: 0x00c0, 0x4615: 0x00c0, 0x4616: 0x00c0, 0x4617: 0x00c0,
+	0x4618: 0x00c0, 0x4619: 0x00c0, 0x461a: 0x00c0, 0x461b: 0x00c0,
+	0x4620: 0x00c0, 0x4621: 0x00c0, 0x4622: 0x00c0, 0x4623: 0x00c0,
+	0x4624: 0x00c0, 0x4625: 0x00c0, 0x4626: 0x00c0, 0x4627: 0x00c0, 0x4628: 0x00c0, 0x4629: 0x00c0,
+	// Block 0x119, offset 0x4640
+	0x4660: 0x00c0, 0x4661: 0x00c0, 0x4662: 0x00c0, 0x4663: 0x00c0,
+	0x4664: 0x00c0, 0x4665: 0x00c0, 0x4666: 0x00c0, 0x4667: 0x00c0, 0x4668: 0x00c0, 0x4669: 0x00c0,
+	0x466a: 0x00c0, 0x466b: 0x00c0, 0x466c: 0x00c0, 0x466d: 0x00c0, 0x466e: 0x00c0, 0x466f: 0x00c0,
+	0x4670: 0x00c0, 0x4671: 0x00c0, 0x4672: 0x00c0, 0x4673: 0x00c3, 0x4674: 0x00c3, 0x4675: 0x00c0,
+	0x4676: 0x00c0, 0x4677: 0x0080, 0x4678: 0x0080,
+	// Block 0x11a, offset 0x4680
+	0x4680: 0x00c3, 0x4681: 0x00c3, 0x4682: 0x00c0, 0x4683: 0x00c0, 0x4684: 0x00c0, 0x4685: 0x00c0,
+	0x4686: 0x00c0, 0x4687: 0x00c0, 0x4688: 0x00c0, 0x4689: 0x00c0, 0x468a: 0x00c0, 0x468b: 0x00c0,
+	0x468c: 0x00c0, 0x468d: 0x00c0, 0x468e: 0x00c0, 0x468f: 0x00c0, 0x4690: 0x00c0,
+	0x4692: 0x00c0, 0x4693: 0x00c0, 0x4694: 0x00c0, 0x4695: 0x00c0, 0x4696: 0x00c0, 0x4697: 0x00c0,
+	0x4698: 0x00c0, 0x4699: 0x00c0, 0x469a: 0x00c0, 0x469b: 0x00c0, 0x469c: 0x00c0, 0x469d: 0x00c0,
+	0x469e: 0x00c0, 0x469f: 0x00c0, 0x46a0: 0x00c0, 0x46a1: 0x00c0, 0x46a2: 0x00c0, 0x46a3: 0x00c0,
+	0x46a4: 0x00c0, 0x46a5: 0x00c0, 0x46a6: 0x00c0, 0x46a7: 0x00c0, 0x46a8: 0x00c0, 0x46a9: 0x00c0,
+	0x46aa: 0x00c0, 0x46ab: 0x00c0, 0x46ac: 0x00c0, 0x46ad: 0x00c0, 0x46ae: 0x00c0, 0x46af: 0x00c0,
+	0x46b0: 0x00c0, 0x46b1: 0x00c0, 0x46b2: 0x00c0, 0x46b3: 0x00c0, 0x46b4: 0x00c0, 0x46b5: 0x00c0,
+	0x46b6: 0x00c3, 0x46b7: 0x00c3, 0x46b8: 0x00c3, 0x46b9: 0x00c3, 0x46ba: 0x00c3,
+	0x46be: 0x00c0, 0x46bf: 0x00c0,
+	// Block 0x11b, offset 0x46c0
+	0x46c0: 0x00c3, 0x46c1: 0x00c5, 0x46c2: 0x00c6, 0x46c3: 0x0080, 0x46c4: 0x0080, 0x46c5: 0x0080,
+	0x46c6: 0x0080, 0x46c7: 0x0080, 0x46c8: 0x0080, 0x46c9: 0x0080, 0x46ca: 0x0080, 0x46cb: 0x0080,
+	0x46cc: 0x0080, 0x46cd: 0x0080, 0x46ce: 0x0080, 0x46cf: 0x0080, 0x46d0: 0x00c0, 0x46d1: 0x00c0,
+	0x46d2: 0x00c0, 0x46d3: 0x00c0, 0x46d4: 0x00c0, 0x46d5: 0x00c0, 0x46d6: 0x00c0, 0x46d7: 0x00c0,
+	0x46d8: 0x00c0, 0x46d9: 0x00c0, 0x46da: 0x00c3,
+	// Block 0x11c, offset 0x4700
+	0x4730: 0x00c0,
+	// Block 0x11d, offset 0x4740
+	0x4740: 0x0080, 0x4741: 0x0080, 0x4742: 0x0080, 0x4743: 0x0080, 0x4744: 0x0080, 0x4745: 0x0080,
+	0x4746: 0x0080, 0x4747: 0x0080, 0x4748: 0x0080, 0x4749: 0x0080, 0x474a: 0x0080, 0x474b: 0x0080,
+	0x474c: 0x0080, 0x474d: 0x0080, 0x474e: 0x0080, 0x474f: 0x0080, 0x4750: 0x0080, 0x4751: 0x0080,
+	0x4752: 0x0080, 0x4753: 0x0080, 0x4754: 0x0080, 0x4755: 0x0080, 0x4756: 0x0080, 0x4757: 0x0080,
+	0x4758: 0x0080, 0x4759: 0x0080, 0x475a: 0x0080, 0x475b: 0x0080, 0x475c: 0x0080, 0x475d: 0x0080,
+	0x475e: 0x0080, 0x475f: 0x0080, 0x4760: 0x0080, 0x4761: 0x0080, 0x4762: 0x0080, 0x4763: 0x0080,
+	0x4764: 0x0080, 0x4765: 0x0080, 0x4766: 0x0080, 0x4767: 0x0080, 0x4768: 0x0080, 0x4769: 0x0080,
+	0x476a: 0x0080, 0x476b: 0x0080, 0x476c: 0x0080, 0x476d: 0x0080, 0x476e: 0x0080, 0x476f: 0x0080,
+	0x4770: 0x0080, 0x4771: 0x0080,
+	0x477f: 0x0080,
+	// Block 0x11e, offset 0x4780
+	0x4780: 0x0080, 0x4781: 0x0080, 0x4782: 0x0080, 0x4783: 0x0080, 0x4784: 0x0080, 0x4785: 0x0080,
+	0x4786: 0x0080, 0x4787: 0x0080, 0x4788: 0x0080, 0x4789: 0x0080, 0x478a: 0x0080, 0x478b: 0x0080,
+	0x478c: 0x0080, 0x478d: 0x0080, 0x478e: 0x0080, 0x478f: 0x0080, 0x4790: 0x0080, 0x4791: 0x0080,
+	0x4792: 0x0080, 0x4793: 0x0080, 0x4794: 0x0080, 0x4795: 0x0080, 0x4796: 0x0080, 0x4797: 0x0080,
+	0x4798: 0x0080, 0x4799: 0x0080, 0x479a: 0x0080, 0x479b: 0x0080, 0x479c: 0x0080, 0x479d: 0x0080,
+	0x479e: 0x0080, 0x479f: 0x0080, 0x47a0: 0x0080, 0x47a1: 0x0080, 0x47a2: 0x0080, 0x47a3: 0x0080,
+	0x47a4: 0x0080, 0x47a5: 0x0080, 0x47a6: 0x0080, 0x47a7: 0x0080, 0x47a8: 0x0080, 0x47a9: 0x0080,
+	0x47aa: 0x0080, 0x47ab: 0x0080, 0x47ac: 0x0080, 0x47ad: 0x0080, 0x47ae: 0x0080,
+	0x47b0: 0x0080, 0x47b1: 0x0080, 0x47b2: 0x0080, 0x47b3: 0x0080, 0x47b4: 0x0080,
+	// Block 0x11f, offset 0x47c0
+	0x47c0: 0x00c0, 0x47c1: 0x00c0, 0x47c2: 0x00c0, 0x47c3: 0x00c0,
+	// Block 0x120, offset 0x4800
+	0x4810: 0x00c0, 0x4811: 0x00c0,
+	0x4812: 0x00c0, 0x4813: 0x00c0, 0x4814: 0x00c0, 0x4815: 0x00c0, 0x4816: 0x00c0, 0x4817: 0x00c0,
+	0x4818: 0x00c0, 0x4819: 0x00c0, 0x481a: 0x00c0, 0x481b: 0x00c0, 0x481c: 0x00c0, 0x481d: 0x00c0,
+	0x481e: 0x00c0, 0x481f: 0x00c0, 0x4820: 0x00c0, 0x4821: 0x00c0, 0x4822: 0x00c0, 0x4823: 0x00c0,
+	0x4824: 0x00c0, 0x4825: 0x00c0, 0x4826: 0x00c0, 0x4827: 0x00c0, 0x4828: 0x00c0, 0x4829: 0x00c0,
+	0x482a: 0x00c0, 0x482b: 0x00c0, 0x482c: 0x00c0, 0x482d: 0x00c0, 0x482e: 0x00c0, 0x482f: 0x00c0,
+	0x4830: 0x00c0, 0x4831: 0x00c0, 0x4832: 0x00c0, 0x4833: 0x00c0, 0x4834: 0x00c0, 0x4835: 0x00c0,
+	0x4836: 0x00c0, 0x4837: 0x00c0, 0x4838: 0x00c0, 0x4839: 0x00c0, 0x483a: 0x00c0, 0x483b: 0x00c0,
+	0x483c: 0x00c0, 0x483d: 0x00c0, 0x483e: 0x00c0, 0x483f: 0x00c0,
+	// Block 0x121, offset 0x4840
+	0x4840: 0x00c0, 0x4841: 0x00c0, 0x4842: 0x00c0, 0x4843: 0x00c0, 0x4844: 0x00c0, 0x4845: 0x00c0,
+	0x4846: 0x00c0, 0x4847: 0x00c0, 0x4848: 0x00c0, 0x4849: 0x00c0, 0x484a: 0x00c0, 0x484b: 0x00c0,
+	0x484c: 0x00c0, 0x484d: 0x00c0, 0x484e: 0x00c0, 0x484f: 0x00c0, 0x4850: 0x00c0, 0x4851: 0x00c0,
+	0x4852: 0x00c0, 0x4853: 0x00c0, 0x4854: 0x00c0, 0x4855: 0x00c0, 0x4856: 0x00c0, 0x4857: 0x00c0,
+	0x4858: 0x00c0, 0x4859: 0x00c0, 0x485a: 0x00c0, 0x485b: 0x00c0, 0x485c: 0x00c0, 0x485d: 0x00c0,
+	0x485e: 0x00c0, 0x485f: 0x00c0, 0x4860: 0x00c0, 0x4861: 0x00c0, 0x4862: 0x00c0, 0x4863: 0x00c0,
+	0x4864: 0x00c0, 0x4865: 0x00c0, 0x4866: 0x00c0, 0x4867: 0x00c0, 0x4868: 0x00c0, 0x4869: 0x00c0,
+	0x486a: 0x00c0, 0x486b: 0x00c0, 0x486c: 0x00c0, 0x486d: 0x00c0, 0x486e: 0x00c0, 0x486f: 0x00c0,
+	0x4870: 0x00c0, 0x4871: 0x0080, 0x4872: 0x0080,
+	// Block 0x122, offset 0x4880
+	0x4880: 0x00c0, 0x4881: 0x00c0, 0x4882: 0x00c0, 0x4883: 0x00c0, 0x4884: 0x00c0, 0x4885: 0x00c0,
+	0x4886: 0x00c0, 0x4887: 0x00c0, 0x4888: 0x00c0, 0x4889: 0x00c0, 0x488a: 0x00c0, 0x488b: 0x00c0,
+	0x488c: 0x00c0, 0x488d: 0x00c0, 0x488e: 0x00c0, 0x488f: 0x00c0, 0x4890: 0x00c0, 0x4891: 0x00c0,
+	0x4892: 0x00c0, 0x4893: 0x00c0, 0x4894: 0x00c0, 0x4895: 0x00c0, 0x4896: 0x00c0, 0x4897: 0x00c0,
+	0x4898: 0x00c0, 0x4899: 0x00c0, 0x489a: 0x00c0, 0x489b: 0x00c0, 0x489c: 0x00c0, 0x489d: 0x00c0,
+	0x489e: 0x00c0, 0x489f: 0x00c0, 0x48a0: 0x00c0, 0x48a1: 0x00c0, 0x48a2: 0x00c0, 0x48a3: 0x00c0,
+	0x48a4: 0x00c0, 0x48a5: 0x00c0, 0x48a6: 0x00c0, 0x48a7: 0x00c0, 0x48a8: 0x00c0, 0x48a9: 0x00c0,
+	0x48aa: 0x00c0, 0x48ab: 0x00c0, 0x48ac: 0x00c0, 0x48ad: 0x00c0, 0x48ae: 0x00c0, 0x48af: 0x00c0,
+	0x48b0: 0x0040, 0x48b1: 0x0040, 0x48b2: 0x0040, 0x48b3: 0x0040, 0x48b4: 0x0040, 0x48b5: 0x0040,
+	0x48b6: 0x0040, 0x48b7: 0x0040, 0x48b8: 0x0040, 0x48b9: 0x0040, 0x48ba: 0x0040, 0x48bb: 0x0040,
+	0x48bc: 0x0040, 0x48bd: 0x0040, 0x48be: 0x0040, 0x48bf: 0x0040,
+	// Block 0x123, offset 0x48c0
+	0x48c0: 0x00c3, 0x48c1: 0x00c0, 0x48c2: 0x00c0, 0x48c3: 0x00c0, 0x48c4: 0x00c0, 0x48c5: 0x00c0,
+	0x48c6: 0x00c0, 0x48c7: 0x00c3, 0x48c8: 0x00c3, 0x48c9: 0x00c3, 0x48ca: 0x00c3, 0x48cb: 0x00c3,
+	0x48cc: 0x00c3, 0x48cd: 0x00c3, 0x48ce: 0x00c3, 0x48cf: 0x00c3, 0x48d0: 0x00c3, 0x48d1: 0x00c3,
+	0x48d2: 0x00c3, 0x48d3: 0x00c3, 0x48d4: 0x00c3, 0x48d5: 0x00c3,
+	0x48e0: 0x00c0, 0x48e1: 0x00c0, 0x48e2: 0x00c0, 0x48e3: 0x00c0,
+	0x48e4: 0x00c0, 0x48e5: 0x00c0, 0x48e6: 0x00c0, 0x48e7: 0x00c0, 0x48e8: 0x00c0, 0x48e9: 0x00c0,
+	0x48ea: 0x00c0, 0x48eb: 0x00c0, 0x48ec: 0x00c0, 0x48ed: 0x00c0, 0x48ee: 0x00c0, 0x48ef: 0x00c0,
+	0x48f0: 0x00c0, 0x48f1: 0x00c0, 0x48f2: 0x00c0, 0x48f3: 0x00c0, 0x48f4: 0x00c0, 0x48f5: 0x00c0,
+	0x48f6: 0x00c0, 0x48f7: 0x00c0, 0x48f8: 0x00c0, 0x48f9: 0x00c0, 0x48fa: 0x00c0, 0x48fb: 0x00c0,
+	0x48fc: 0x00c0, 0x48fd: 0x00c0, 0x48fe: 0x00c0, 0x48ff: 0x00c0,
+	// Block 0x124, offset 0x4900
+	0x4900: 0x00c0, 0x4901: 0x00c0, 0x4902: 0x00c0, 0x4903: 0x00c0, 0x4904: 0x00c0, 0x4905: 0x00c0,
+	0x4906: 0x00c0, 0x4907: 0x00c0, 0x4908: 0x00c0, 0x4909: 0x00c0, 0x490a: 0x00c0, 0x490b: 0x00c0,
+	0x490c: 0x00c0, 0x490d: 0x00c0, 0x490e: 0x00c0, 0x490f: 0x00c0, 0x4910: 0x00c0, 0x4911: 0x00c0,
+	0x4912: 0x00c0, 0x4913: 0x00c0, 0x4914: 0x00c0, 0x4915: 0x00c0, 0x4916: 0x00c0, 0x4917: 0x00c0,
+	0x4918: 0x00c0, 0x4919: 0x00c0, 0x491a: 0x00c0, 0x491b: 0x00c0, 0x491c: 0x00c0, 0x491d: 0x00c0,
+	0x491e: 0x00c3, 0x491f: 0x00c3, 0x4920: 0x00c3, 0x4921: 0x00c3, 0x4922: 0x00c3, 0x4923: 0x00c3,
+	0x4924: 0x00c3, 0x4925: 0x00c3, 0x4926: 0x00c3, 0x4927: 0x00c3, 0x4928: 0x00c3, 0x4929: 0x00c3,
+	0x492a: 0x00c0, 0x492b: 0x00c0, 0x492c: 0x00c0, 0x492d: 0x00c3, 0x492e: 0x00c3, 0x492f: 0x00c6,
+	0x4930: 0x00c0, 0x4931: 0x00c0, 0x4932: 0x00c0, 0x4933: 0x00c0, 0x4934: 0x00c0, 0x4935: 0x00c0,
+	0x4936: 0x00c0, 0x4937: 0x00c0, 0x4938: 0x00c0, 0x4939: 0x00c0,
+	// Block 0x125, offset 0x4940
+	0x4940: 0x00c0, 0x4941: 0x00c0, 0x4942: 0x00c0, 0x4943: 0x00c0, 0x4944: 0x00c0, 0x4945: 0x00c0,
+	0x4946: 0x00c0, 0x4947: 0x00c0, 0x4948: 0x00c0, 0x4949: 0x00c0, 0x494a: 0x00c0, 0x494b: 0x00c0,
+	0x494c: 0x00c0, 0x494d: 0x00c0, 0x494e: 0x00c0, 0x494f: 0x00c0, 0x4950: 0x00c0, 0x4951: 0x00c0,
+	0x4952: 0x00c0, 0x4953: 0x00c0, 0x4954: 0x00c0, 0x4955: 0x00c0, 0x4956: 0x00c0, 0x4957: 0x00c0,
+	0x4958: 0x00c0, 0x4959: 0x00c0, 0x495a: 0x00c0, 0x495b: 0x00c0, 0x495c: 0x00c0, 0x495d: 0x00c0,
+	0x495e: 0x00c0, 0x4960: 0x00c0, 0x4961: 0x00c0, 0x4962: 0x00c0, 0x4963: 0x00c0,
+	0x4964: 0x00c0, 0x4965: 0x00c0, 0x4966: 0x00c0, 0x4967: 0x00c0, 0x4968: 0x00c0, 0x4969: 0x00c0,
+	0x496e: 0x0080, 0x496f: 0x0080,
+	0x4970: 0x00c0, 0x4971: 0x00c0, 0x4972: 0x00c0, 0x4973: 0x00c0, 0x4974: 0x00c0, 0x4975: 0x00c0,
+	0x4976: 0x00c0, 0x4977: 0x00c0, 0x4978: 0x00c0, 0x4979: 0x00c0, 0x497a: 0x00c0, 0x497b: 0x00c0,
+	0x497c: 0x00c0, 0x497d: 0x00c0, 0x497e: 0x00c0, 0x497f: 0x00c0,
+	// Block 0x126, offset 0x4980
+	0x4980: 0x00c0, 0x4981: 0x00c0, 0x4982: 0x00c0, 0x4983: 0x00c0, 0x4984: 0x00c0, 0x4985: 0x00c0,
+	0x4986: 0x00c0, 0x4987: 0x00c0, 0x4988: 0x00c0, 0x4989: 0x00c0, 0x498a: 0x00c0, 0x498b: 0x00c0,
+	0x498c: 0x00c0, 0x498d: 0x00c0, 0x498e: 0x00c0, 0x498f: 0x00c0, 0x4990: 0x00c0, 0x4991: 0x00c0,
+	0x4992: 0x00c0, 0x4993: 0x00c0, 0x4994: 0x00c0, 0x4995: 0x00c0, 0x4996: 0x00c0, 0x4997: 0x00c0,
+	0x4998: 0x00c0, 0x4999: 0x00c0, 0x499a: 0x00c0, 0x499b: 0x00c0, 0x499c: 0x00c0, 0x499d: 0x00c0,
+	0x499e: 0x00c0, 0x499f: 0x00c0, 0x49a0: 0x00c0, 0x49a1: 0x00c0, 0x49a2: 0x00c0, 0x49a3: 0x00c0,
+	0x49a4: 0x00c0, 0x49a5: 0x00c0, 0x49a6: 0x00c0, 0x49a7: 0x00c0, 0x49a8: 0x00c0, 0x49a9: 0x00c0,
+	0x49aa: 0x00c0, 0x49ab: 0x00c0, 0x49ac: 0x00c0, 0x49ad: 0x00c0, 0x49ae: 0x00c0, 0x49af: 0x00c0,
+	0x49b0: 0x00c0, 0x49b1: 0x00c0, 0x49b2: 0x00c0, 0x49b3: 0x00c0, 0x49b4: 0x00c0, 0x49b5: 0x00c0,
+	0x49b6: 0x00c0, 0x49b7: 0x00c0, 0x49b8: 0x00c0, 0x49b9: 0x00c0, 0x49ba: 0x00c0, 0x49bb: 0x00c0,
+	0x49bc: 0x00c0, 0x49bd: 0x00c0, 0x49be: 0x00c0,
+	// Block 0x127, offset 0x49c0
+	0x49c0: 0x00c0, 0x49c1: 0x00c0, 0x49c2: 0x00c0, 0x49c3: 0x00c0, 0x49c4: 0x00c0, 0x49c5: 0x00c0,
+	0x49c6: 0x00c0, 0x49c7: 0x00c0, 0x49c8: 0x00c0, 0x49c9: 0x00c0,
+	0x49d0: 0x00c0, 0x49d1: 0x00c0,
+	0x49d2: 0x00c0, 0x49d3: 0x00c0, 0x49d4: 0x00c0, 0x49d5: 0x00c0, 0x49d6: 0x00c0, 0x49d7: 0x00c0,
+	0x49d8: 0x00c0, 0x49d9: 0x00c0, 0x49da: 0x00c0, 0x49db: 0x00c0, 0x49dc: 0x00c0, 0x49dd: 0x00c0,
+	0x49de: 0x00c0, 0x49df: 0x00c0, 0x49e0: 0x00c0, 0x49e1: 0x00c0, 0x49e2: 0x00c0, 0x49e3: 0x00c0,
+	0x49e4: 0x00c0, 0x49e5: 0x00c0, 0x49e6: 0x00c0, 0x49e7: 0x00c0, 0x49e8: 0x00c0, 0x49e9: 0x00c0,
+	0x49ea: 0x00c0, 0x49eb: 0x00c0, 0x49ec: 0x00c0, 0x49ed: 0x00c0,
+	0x49f0: 0x00c3, 0x49f1: 0x00c3, 0x49f2: 0x00c3, 0x49f3: 0x00c3, 0x49f4: 0x00c3, 0x49f5: 0x0080,
+	// Block 0x128, offset 0x4a00
+	0x4a00: 0x00c0, 0x4a01: 0x00c0, 0x4a02: 0x00c0, 0x4a03: 0x00c0, 0x4a04: 0x00c0, 0x4a05: 0x00c0,
+	0x4a06: 0x00c0, 0x4a07: 0x00c0, 0x4a08: 0x00c0, 0x4a09: 0x00c0, 0x4a0a: 0x00c0, 0x4a0b: 0x00c0,
+	0x4a0c: 0x00c0, 0x4a0d: 0x00c0, 0x4a0e: 0x00c0, 0x4a0f: 0x00c0, 0x4a10: 0x00c0, 0x4a11: 0x00c0,
+	0x4a12: 0x00c0, 0x4a13: 0x00c0, 0x4a14: 0x00c0, 0x4a15: 0x00c0, 0x4a16: 0x00c0, 0x4a17: 0x00c0,
+	0x4a18: 0x00c0, 0x4a19: 0x00c0, 0x4a1a: 0x00c0, 0x4a1b: 0x00c0, 0x4a1c: 0x00c0, 0x4a1d: 0x00c0,
+	0x4a1e: 0x00c0, 0x4a1f: 0x00c0, 0x4a20: 0x00c0, 0x4a21: 0x00c0, 0x4a22: 0x00c0, 0x4a23: 0x00c0,
+	0x4a24: 0x00c0, 0x4a25: 0x00c0, 0x4a26: 0x00c0, 0x4a27: 0x00c0, 0x4a28: 0x00c0, 0x4a29: 0x00c0,
+	0x4a2a: 0x00c0, 0x4a2b: 0x00c0, 0x4a2c: 0x00c0, 0x4a2d: 0x00c0, 0x4a2e: 0x00c0, 0x4a2f: 0x00c0,
+	0x4a30: 0x00c3, 0x4a31: 0x00c3, 0x4a32: 0x00c3, 0x4a33: 0x00c3, 0x4a34: 0x00c3, 0x4a35: 0x00c3,
+	0x4a36: 0x00c3, 0x4a37: 0x0080, 0x4a38: 0x0080, 0x4a39: 0x0080, 0x4a3a: 0x0080, 0x4a3b: 0x0080,
+	0x4a3c: 0x0080, 0x4a3d: 0x0080, 0x4a3e: 0x0080, 0x4a3f: 0x0080,
+	// Block 0x129, offset 0x4a40
+	0x4a40: 0x00c0, 0x4a41: 0x00c0, 0x4a42: 0x00c0, 0x4a43: 0x00c0, 0x4a44: 0x0080, 0x4a45: 0x0080,
+	0x4a50: 0x00c0, 0x4a51: 0x00c0,
+	0x4a52: 0x00c0, 0x4a53: 0x00c0, 0x4a54: 0x00c0, 0x4a55: 0x00c0, 0x4a56: 0x00c0, 0x4a57: 0x00c0,
+	0x4a58: 0x00c0, 0x4a59: 0x00c0, 0x4a5b: 0x0080, 0x4a5c: 0x0080, 0x4a5d: 0x0080,
+	0x4a5e: 0x0080, 0x4a5f: 0x0080, 0x4a60: 0x0080, 0x4a61: 0x0080, 0x4a63: 0x00c0,
+	0x4a64: 0x00c0, 0x4a65: 0x00c0, 0x4a66: 0x00c0, 0x4a67: 0x00c0, 0x4a68: 0x00c0, 0x4a69: 0x00c0,
+	0x4a6a: 0x00c0, 0x4a6b: 0x00c0, 0x4a6c: 0x00c0, 0x4a6d: 0x00c0, 0x4a6e: 0x00c0, 0x4a6f: 0x00c0,
+	0x4a70: 0x00c0, 0x4a71: 0x00c0, 0x4a72: 0x00c0, 0x4a73: 0x00c0, 0x4a74: 0x00c0, 0x4a75: 0x00c0,
+	0x4a76: 0x00c0, 0x4a77: 0x00c0,
+	0x4a7d: 0x00c0, 0x4a7e: 0x00c0, 0x4a7f: 0x00c0,
+	// Block 0x12a, offset 0x4a80
+	0x4a80: 0x00c0, 0x4a81: 0x00c0, 0x4a82: 0x00c0, 0x4a83: 0x00c0, 0x4a84: 0x00c0, 0x4a85: 0x00c0,
+	0x4a86: 0x00c0, 0x4a87: 0x00c0, 0x4a88: 0x00c0, 0x4a89: 0x00c0, 0x4a8a: 0x00c0, 0x4a8b: 0x00c0,
+	0x4a8c: 0x00c0, 0x4a8d: 0x00c0, 0x4a8e: 0x00c0, 0x4a8f: 0x00c0,
+	// Block 0x12b, offset 0x4ac0
+	0x4ac0: 0x00c0, 0x4ac1: 0x00c0, 0x4ac2: 0x00c0, 0x4ac3: 0x00c0, 0x4ac4: 0x00c0, 0x4ac5: 0x00c0,
+	0x4ac6: 0x00c0, 0x4ac7: 0x00c0, 0x4ac8: 0x00c0, 0x4ac9: 0x00c0, 0x4aca: 0x00c0, 0x4acb: 0x00c0,
+	0x4acc: 0x00c0, 0x4acd: 0x00c0, 0x4ace: 0x00c0, 0x4acf: 0x00c0, 0x4ad0: 0x00c0, 0x4ad1: 0x00c0,
+	0x4ad2: 0x00c0, 0x4ad3: 0x00c0, 0x4ad4: 0x00c0, 0x4ad5: 0x00c0, 0x4ad6: 0x00c0, 0x4ad7: 0x00c0,
+	0x4ad8: 0x00c0, 0x4ad9: 0x00c0, 0x4ada: 0x00c0, 0x4adb: 0x00c0, 0x4adc: 0x00c0, 0x4add: 0x00c0,
+	0x4ade: 0x00c0, 0x4adf: 0x00c0, 0x4ae0: 0x00c0, 0x4ae1: 0x00c0, 0x4ae2: 0x00c0, 0x4ae3: 0x00c0,
+	0x4ae4: 0x00c0, 0x4ae5: 0x00c0, 0x4ae6: 0x00c0, 0x4ae7: 0x00c0, 0x4ae8: 0x00c0, 0x4ae9: 0x00c0,
+	0x4aea: 0x00c0, 0x4aeb: 0x00c0, 0x4aec: 0x00c0, 0x4aed: 0x0080, 0x4aee: 0x0080, 0x4aef: 0x0080,
+	0x4af0: 0x00c0, 0x4af1: 0x00c0, 0x4af2: 0x00c0, 0x4af3: 0x00c0, 0x4af4: 0x00c0, 0x4af5: 0x00c0,
+	0x4af6: 0x00c0, 0x4af7: 0x00c0, 0x4af8: 0x00c0, 0x4af9: 0x00c0,
+	// Block 0x12c, offset 0x4b00
+	0x4b00: 0x0080, 0x4b01: 0x0080, 0x4b02: 0x0080, 0x4b03: 0x0080, 0x4b04: 0x0080, 0x4b05: 0x0080,
+	0x4b06: 0x0080, 0x4b07: 0x0080, 0x4b08: 0x0080, 0x4b09: 0x0080, 0x4b0a: 0x0080, 0x4b0b: 0x0080,
+	0x4b0c: 0x0080, 0x4b0d: 0x0080, 0x4b0e: 0x0080, 0x4b0f: 0x0080, 0x4b10: 0x0080, 0x4b11: 0x0080,
+	0x4b12: 0x0080, 0x4b13: 0x0080, 0x4b14: 0x0080, 0x4b15: 0x0080, 0x4b16: 0x0080, 0x4b17: 0x0080,
+	0x4b18: 0x0080, 0x4b19: 0x0080, 0x4b1a: 0x0080,
+	0x4b20: 0x00c0, 0x4b21: 0x00c0, 0x4b22: 0x00c0, 0x4b23: 0x00c0,
+	0x4b24: 0x00c0, 0x4b25: 0x00c0, 0x4b26: 0x00c0, 0x4b27: 0x00c0, 0x4b28: 0x00c0, 0x4b29: 0x00c0,
+	0x4b2a: 0x00c0, 0x4b2b: 0x00c0, 0x4b2c: 0x00c0, 0x4b2d: 0x00c0, 0x4b2e: 0x00c0, 0x4b2f: 0x00c0,
+	0x4b30: 0x00c0, 0x4b31: 0x00c0, 0x4b32: 0x00c0, 0x4b33: 0x00c0, 0x4b34: 0x00c0, 0x4b35: 0x00c0,
+	0x4b36: 0x00c0, 0x4b37: 0x00c0, 0x4b38: 0x00c0, 0x4b3b: 0x00c0,
+	0x4b3c: 0x00c0, 0x4b3d: 0x00c0, 0x4b3e: 0x00c0, 0x4b3f: 0x00c0,
+	// Block 0x12d, offset 0x4b40
+	0x4b40: 0x00c0, 0x4b41: 0x00c0, 0x4b42: 0x00c0, 0x4b43: 0x00c0, 0x4b44: 0x00c0, 0x4b45: 0x00c0,
+	0x4b46: 0x00c0, 0x4b47: 0x00c0, 0x4b48: 0x00c0, 0x4b49: 0x00c0, 0x4b4a: 0x00c0, 0x4b4b: 0x00c0,
+	0x4b4c: 0x00c0, 0x4b4d: 0x00c0, 0x4b4e: 0x00c0, 0x4b4f: 0x00c0, 0x4b50: 0x00c0, 0x4b51: 0x00c0,
+	0x4b52: 0x00c0, 0x4b53: 0x00c0,
+	// Block 0x12e, offset 0x4b80
+	0x4b80: 0x00c0, 0x4b81: 0x00c0, 0x4b82: 0x00c0, 0x4b83: 0x00c0, 0x4b84: 0x00c0, 0x4b85: 0x00c0,
+	0x4b86: 0x00c0, 0x4b87: 0x00c0, 0x4b88: 0x00c0, 0x4b89: 0x00c0, 0x4b8a: 0x00c0,
+	0x4b8f: 0x00c3, 0x4b90: 0x00c0, 0x4b91: 0x00c0,
+	0x4b92: 0x00c0, 0x4b93: 0x00c0, 0x4b94: 0x00c0, 0x4b95: 0x00c0, 0x4b96: 0x00c0, 0x4b97: 0x00c0,
+	0x4b98: 0x00c0, 0x4b99: 0x00c0, 0x4b9a: 0x00c0, 0x4b9b: 0x00c0, 0x4b9c: 0x00c0, 0x4b9d: 0x00c0,
+	0x4b9e: 0x00c0, 0x4b9f: 0x00c0, 0x4ba0: 0x00c0, 0x4ba1: 0x00c0, 0x4ba2: 0x00c0, 0x4ba3: 0x00c0,
+	0x4ba4: 0x00c0, 0x4ba5: 0x00c0, 0x4ba6: 0x00c0, 0x4ba7: 0x00c0, 0x4ba8: 0x00c0, 0x4ba9: 0x00c0,
+	0x4baa: 0x00c0, 0x4bab: 0x00c0, 0x4bac: 0x00c0, 0x4bad: 0x00c0, 0x4bae: 0x00c0, 0x4baf: 0x00c0,
+	0x4bb0: 0x00c0, 0x4bb1: 0x00c0, 0x4bb2: 0x00c0, 0x4bb3: 0x00c0, 0x4bb4: 0x00c0, 0x4bb5: 0x00c0,
+	0x4bb6: 0x00c0, 0x4bb7: 0x00c0, 0x4bb8: 0x00c0, 0x4bb9: 0x00c0, 0x4bba: 0x00c0, 0x4bbb: 0x00c0,
+	0x4bbc: 0x00c0, 0x4bbd: 0x00c0, 0x4bbe: 0x00c0, 0x4bbf: 0x00c0,
+	// Block 0x12f, offset 0x4bc0
+	0x4bc0: 0x00c0, 0x4bc1: 0x00c0, 0x4bc2: 0x00c0, 0x4bc3: 0x00c0, 0x4bc4: 0x00c0, 0x4bc5: 0x00c0,
+	0x4bc6: 0x00c0, 0x4bc7: 0x00c0,
+	0x4bcf: 0x00c3, 0x4bd0: 0x00c3, 0x4bd1: 0x00c3,
+	0x4bd2: 0x00c3, 0x4bd3: 0x00c0, 0x4bd4: 0x00c0, 0x4bd5: 0x00c0, 0x4bd6: 0x00c0, 0x4bd7: 0x00c0,
+	0x4bd8: 0x00c0, 0x4bd9: 0x00c0, 0x4bda: 0x00c0, 0x4bdb: 0x00c0, 0x4bdc: 0x00c0, 0x4bdd: 0x00c0,
+	0x4bde: 0x00c0, 0x4bdf: 0x00c0,
+	// Block 0x130, offset 0x4c00
+	0x4c20: 0x00c0, 0x4c21: 0x00c0, 0x4c22: 0x008c, 0x4c23: 0x00cc,
+	0x4c24: 0x00c3,
+	0x4c30: 0x00cc, 0x4c31: 0x00cc, 0x4c32: 0x00cc, 0x4c33: 0x00cc, 0x4c34: 0x008c, 0x4c35: 0x008c,
+	0x4c36: 0x008c,
+	// Block 0x131, offset 0x4c40
+	0x4c40: 0x00c0, 0x4c41: 0x00c0, 0x4c42: 0x00c0, 0x4c43: 0x00c0, 0x4c44: 0x00c0, 0x4c45: 0x00c0,
+	0x4c46: 0x00c0, 0x4c47: 0x00c0, 0x4c48: 0x00c0, 0x4c49: 0x00c0, 0x4c4a: 0x00c0, 0x4c4b: 0x00c0,
+	0x4c4c: 0x00c0, 0x4c4d: 0x00c0, 0x4c4e: 0x00c0, 0x4c4f: 0x00c0, 0x4c50: 0x00c0, 0x4c51: 0x00c0,
+	0x4c52: 0x00c0, 0x4c53: 0x00c0, 0x4c54: 0x00c0, 0x4c55: 0x00c0,
+	0x4c7f: 0x00c0,
+	// Block 0x132, offset 0x4c80
+	0x4c80: 0x00c0, 0x4c81: 0x00c0, 0x4c82: 0x00c0, 0x4c83: 0x00c0, 0x4c84: 0x00c0, 0x4c85: 0x00c0,
+	0x4c86: 0x00c0, 0x4c87: 0x00c0, 0x4c88: 0x00c0, 0x4c89: 0x00c0, 0x4c8a: 0x00c0, 0x4c8b: 0x00c0,
+	0x4c8c: 0x00c0, 0x4c8d: 0x00c0, 0x4c8e: 0x00c0, 0x4c8f: 0x00c0, 0x4c90: 0x00c0, 0x4c91: 0x00c0,
+	0x4c92: 0x00c0, 0x4c93: 0x00c0, 0x4c94: 0x00c0, 0x4c95: 0x00c0, 0x4c96: 0x00c0, 0x4c97: 0x00c0,
+	0x4c98: 0x00c0, 0x4c99: 0x00c0, 0x4c9a: 0x00c0, 0x4c9b: 0x00c0, 0x4c9c: 0x00c0, 0x4c9d: 0x00c0,
+	0x4c9e: 0x00c0,
+	// Block 0x133, offset 0x4cc0
+	0x4cf0: 0x00cc, 0x4cf1: 0x00cc, 0x4cf2: 0x00cc, 0x4cf3: 0x00cc, 0x4cf5: 0x00cc,
+	0x4cf6: 0x00cc, 0x4cf7: 0x00cc, 0x4cf8: 0x00cc, 0x4cf9: 0x00cc, 0x4cfa: 0x00cc, 0x4cfb: 0x00cc,
+	0x4cfd: 0x00cc, 0x4cfe: 0x00cc,
+	// Block 0x134, offset 0x4d00
+	0x4d00: 0x00cc, 0x4d01: 0x00cc, 0x4d02: 0x00cc, 0x4d03: 0x00cc, 0x4d04: 0x00cc, 0x4d05: 0x00cc,
+	0x4d06: 0x00cc, 0x4d07: 0x00cc, 0x4d08: 0x00cc, 0x4d09: 0x00cc, 0x4d0a: 0x00cc, 0x4d0b: 0x00cc,
+	0x4d0c: 0x00cc, 0x4d0d: 0x00cc, 0x4d0e: 0x00cc, 0x4d0f: 0x00cc, 0x4d10: 0x00cc, 0x4d11: 0x00cc,
+	0x4d12: 0x00cc, 0x4d13: 0x00cc, 0x4d14: 0x00cc, 0x4d15: 0x00cc, 0x4d16: 0x00cc, 0x4d17: 0x00cc,
+	0x4d18: 0x00cc, 0x4d19: 0x00cc, 0x4d1a: 0x00cc, 0x4d1b: 0x00cc, 0x4d1c: 0x00cc, 0x4d1d: 0x00cc,
+	0x4d1e: 0x00cc, 0x4d1f: 0x00cc, 0x4d20: 0x00cc, 0x4d21: 0x00cc, 0x4d22: 0x00cc,
+	0x4d32: 0x00cc,
+	// Block 0x135, offset 0x4d40
+	0x4d50: 0x00cc, 0x4d51: 0x00cc,
+	0x4d52: 0x00cc, 0x4d55: 0x00cc,
+	0x4d64: 0x00cc, 0x4d65: 0x00cc, 0x4d66: 0x00cc, 0x4d67: 0x00cc,
+	0x4d70: 0x00c0, 0x4d71: 0x00c0, 0x4d72: 0x00c0, 0x4d73: 0x00c0, 0x4d74: 0x00c0, 0x4d75: 0x00c0,
+	0x4d76: 0x00c0, 0x4d77: 0x00c0, 0x4d78: 0x00c0, 0x4d79: 0x00c0, 0x4d7a: 0x00c0, 0x4d7b: 0x00c0,
+	0x4d7c: 0x00c0, 0x4d7d: 0x00c0, 0x4d7e: 0x00c0, 0x4d7f: 0x00c0,
+	// Block 0x136, offset 0x4d80
+	0x4d80: 0x00c0, 0x4d81: 0x00c0, 0x4d82: 0x00c0, 0x4d83: 0x00c0, 0x4d84: 0x00c0, 0x4d85: 0x00c0,
+	0x4d86: 0x00c0, 0x4d87: 0x00c0, 0x4d88: 0x00c0, 0x4d89: 0x00c0, 0x4d8a: 0x00c0, 0x4d8b: 0x00c0,
+	0x4d8c: 0x00c0, 0x4d8d: 0x00c0, 0x4d8e: 0x00c0, 0x4d8f: 0x00c0, 0x4d90: 0x00c0, 0x4d91: 0x00c0,
+	0x4d92: 0x00c0, 0x4d93: 0x00c0, 0x4d94: 0x00c0, 0x4d95: 0x00c0, 0x4d96: 0x00c0, 0x4d97: 0x00c0,
+	0x4d98: 0x00c0, 0x4d99: 0x00c0, 0x4d9a: 0x00c0, 0x4d9b: 0x00c0, 0x4d9c: 0x00c0, 0x4d9d: 0x00c0,
+	0x4d9e: 0x00c0, 0x4d9f: 0x00c0, 0x4da0: 0x00c0, 0x4da1: 0x00c0, 0x4da2: 0x00c0, 0x4da3: 0x00c0,
+	0x4da4: 0x00c0, 0x4da5: 0x00c0, 0x4da6: 0x00c0, 0x4da7: 0x00c0, 0x4da8: 0x00c0, 0x4da9: 0x00c0,
+	0x4daa: 0x00c0, 0x4dab: 0x00c0, 0x4dac: 0x00c0, 0x4dad: 0x00c0, 0x4dae: 0x00c0, 0x4daf: 0x00c0,
+	0x4db0: 0x00c0, 0x4db1: 0x00c0, 0x4db2: 0x00c0, 0x4db3: 0x00c0, 0x4db4: 0x00c0, 0x4db5: 0x00c0,
+	0x4db6: 0x00c0, 0x4db7: 0x00c0, 0x4db8: 0x00c0, 0x4db9: 0x00c0, 0x4dba: 0x00c0, 0x4dbb: 0x00c0,
+	// Block 0x137, offset 0x4dc0
+	0x4dc0: 0x00c0, 0x4dc1: 0x00c0, 0x4dc2: 0x00c0, 0x4dc3: 0x00c0, 0x4dc4: 0x00c0, 0x4dc5: 0x00c0,
+	0x4dc6: 0x00c0, 0x4dc7: 0x00c0, 0x4dc8: 0x00c0, 0x4dc9: 0x00c0, 0x4dca: 0x00c0, 0x4dcb: 0x00c0,
+	0x4dcc: 0x00c0, 0x4dcd: 0x00c0, 0x4dce: 0x00c0, 0x4dcf: 0x00c0, 0x4dd0: 0x00c0, 0x4dd1: 0x00c0,
+	0x4dd2: 0x00c0, 0x4dd3: 0x00c0, 0x4dd4: 0x00c0, 0x4dd5: 0x00c0, 0x4dd6: 0x00c0, 0x4dd7: 0x00c0,
+	0x4dd8: 0x00c0, 0x4dd9: 0x00c0, 0x4dda: 0x00c0, 0x4ddb: 0x00c0, 0x4ddc: 0x00c0, 0x4ddd: 0x00c0,
+	0x4dde: 0x00c0, 0x4ddf: 0x00c0, 0x4de0: 0x00c0, 0x4de1: 0x00c0, 0x4de2: 0x00c0, 0x4de3: 0x00c0,
+	0x4de4: 0x00c0, 0x4de5: 0x00c0, 0x4de6: 0x00c0, 0x4de7: 0x00c0, 0x4de8: 0x00c0, 0x4de9: 0x00c0,
+	0x4dea: 0x00c0,
+	0x4df0: 0x00c0, 0x4df1: 0x00c0, 0x4df2: 0x00c0, 0x4df3: 0x00c0, 0x4df4: 0x00c0, 0x4df5: 0x00c0,
+	0x4df6: 0x00c0, 0x4df7: 0x00c0, 0x4df8: 0x00c0, 0x4df9: 0x00c0, 0x4dfa: 0x00c0, 0x4dfb: 0x00c0,
+	0x4dfc: 0x00c0,
+	// Block 0x138, offset 0x4e00
+	0x4e00: 0x00c0, 0x4e01: 0x00c0, 0x4e02: 0x00c0, 0x4e03: 0x00c0, 0x4e04: 0x00c0, 0x4e05: 0x00c0,
+	0x4e06: 0x00c0, 0x4e07: 0x00c0, 0x4e08: 0x00c0,
+	0x4e10: 0x00c0, 0x4e11: 0x00c0,
+	0x4e12: 0x00c0, 0x4e13: 0x00c0, 0x4e14: 0x00c0, 0x4e15: 0x00c0, 0x4e16: 0x00c0, 0x4e17: 0x00c0,
+	0x4e18: 0x00c0, 0x4e19: 0x00c0, 0x4e1c: 0x0080, 0x4e1d: 0x00c3,
+	0x4e1e: 0x00c3, 0x4e1f: 0x0080, 0x4e20: 0x0040, 0x4e21: 0x0040, 0x4e22: 0x0040, 0x4e23: 0x0040,
+	// Block 0x139, offset 0x4e40
+	0x4e40: 0x0080, 0x4e41: 0x0080, 0x4e42: 0x0080, 0x4e43: 0x0080, 0x4e44: 0x0080, 0x4e45: 0x0080,
+	0x4e46: 0x0080, 0x4e47: 0x0080, 0x4e48: 0x0080, 0x4e49: 0x0080, 0x4e4a: 0x0080, 0x4e4b: 0x0080,
+	0x4e4c: 0x0080, 0x4e4d: 0x0080, 0x4e4e: 0x0080, 0x4e4f: 0x0080, 0x4e50: 0x0080, 0x4e51: 0x0080,
+	0x4e52: 0x0080, 0x4e53: 0x0080, 0x4e54: 0x0080, 0x4e55: 0x0080, 0x4e56: 0x0080, 0x4e57: 0x0080,
+	0x4e58: 0x0080, 0x4e59: 0x0080, 0x4e5a: 0x0080, 0x4e5b: 0x0080, 0x4e5c: 0x0080, 0x4e5d: 0x0080,
+	0x4e5e: 0x0080, 0x4e5f: 0x0080, 0x4e60: 0x0080, 0x4e61: 0x0080, 0x4e62: 0x0080, 0x4e63: 0x0080,
+	0x4e64: 0x0080, 0x4e65: 0x0080, 0x4e66: 0x0080, 0x4e67: 0x0080, 0x4e68: 0x0080, 0x4e69: 0x0080,
+	0x4e6a: 0x0080, 0x4e6b: 0x0080, 0x4e6c: 0x0080, 0x4e6d: 0x0080, 0x4e6e: 0x0080, 0x4e6f: 0x0080,
+	0x4e70: 0x0080, 0x4e71: 0x0080, 0x4e72: 0x0080, 0x4e73: 0x0080, 0x4e74: 0x0080, 0x4e75: 0x0080,
+	0x4e76: 0x0080, 0x4e77: 0x0080, 0x4e78: 0x0080, 0x4e79: 0x0080, 0x4e7a: 0x0080, 0x4e7b: 0x0080,
+	0x4e7c: 0x0080,
+	// Block 0x13a, offset 0x4e80
+	0x4e80: 0x0080, 0x4e81: 0x0080, 0x4e82: 0x0080, 0x4e83: 0x0080, 0x4e84: 0x0080, 0x4e85: 0x0080,
+	0x4e86: 0x0080, 0x4e87: 0x0080, 0x4e88: 0x0080, 0x4e89: 0x0080, 0x4e8a: 0x0080, 0x4e8b: 0x0080,
+	0x4e8c: 0x0080, 0x4e8d: 0x0080, 0x4e8e: 0x0080, 0x4e8f: 0x0080, 0x4e90: 0x0080, 0x4e91: 0x0080,
+	0x4e92: 0x0080, 0x4e93: 0x0080, 0x4e94: 0x0080, 0x4e95: 0x0080, 0x4e96: 0x0080, 0x4e97: 0x0080,
+	0x4e98: 0x0080, 0x4e99: 0x0080, 0x4e9a: 0x0080, 0x4e9b: 0x0080, 0x4e9c: 0x0080, 0x4e9d: 0x0080,
+	0x4e9e: 0x0080, 0x4e9f: 0x0080, 0x4ea0: 0x0080, 0x4ea1: 0x0080, 0x4ea2: 0x0080, 0x4ea3: 0x0080,
+	0x4ea4: 0x0080, 0x4ea5: 0x0080, 0x4ea6: 0x0080, 0x4ea7: 0x0080, 0x4ea8: 0x0080, 0x4ea9: 0x0080,
+	0x4eaa: 0x0080, 0x4eab: 0x0080, 0x4eac: 0x0080, 0x4ead: 0x0080, 0x4eae: 0x0080, 0x4eaf: 0x0080,
+	0x4eb0: 0x0080, 0x4eb1: 0x0080, 0x4eb2: 0x0080, 0x4eb3: 0x0080,
+	0x4eba: 0x0080, 0x4ebb: 0x0080,
+	0x4ebc: 0x0080, 0x4ebd: 0x0080, 0x4ebe: 0x0080, 0x4ebf: 0x0080,
+	// Block 0x13b, offset 0x4ec0
+	0x4ec0: 0x0080, 0x4ec1: 0x0080, 0x4ec2: 0x0080, 0x4ec3: 0x0080, 0x4ec4: 0x0080, 0x4ec5: 0x0080,
+	0x4ec6: 0x0080, 0x4ec7: 0x0080, 0x4ec8: 0x0080, 0x4ec9: 0x0080, 0x4eca: 0x0080, 0x4ecb: 0x0080,
+	0x4ecc: 0x0080, 0x4ecd: 0x0080, 0x4ece: 0x0080, 0x4ecf: 0x0080, 0x4ed0: 0x0080,
+	0x4ee0: 0x0080, 0x4ee1: 0x0080, 0x4ee2: 0x0080, 0x4ee3: 0x0080,
+	0x4ee4: 0x0080, 0x4ee5: 0x0080, 0x4ee6: 0x0080, 0x4ee7: 0x0080, 0x4ee8: 0x0080, 0x4ee9: 0x0080,
+	0x4eea: 0x0080, 0x4eeb: 0x0080, 0x4eec: 0x0080, 0x4eed: 0x0080, 0x4eee: 0x0080, 0x4eef: 0x0080,
+	0x4ef0: 0x0080,
+	// Block 0x13c, offset 0x4f00
+	0x4f00: 0x00c3, 0x4f01: 0x00c3, 0x4f02: 0x00c3, 0x4f03: 0x00c3, 0x4f04: 0x00c3, 0x4f05: 0x00c3,
+	0x4f06: 0x00c3, 0x4f07: 0x00c3, 0x4f08: 0x00c3, 0x4f09: 0x00c3, 0x4f0a: 0x00c3, 0x4f0b: 0x00c3,
+	0x4f0c: 0x00c3, 0x4f0d: 0x00c3, 0x4f0e: 0x00c3, 0x4f0f: 0x00c3, 0x4f10: 0x00c3, 0x4f11: 0x00c3,
+	0x4f12: 0x00c3, 0x4f13: 0x00c3, 0x4f14: 0x00c3, 0x4f15: 0x00c3, 0x4f16: 0x00c3, 0x4f17: 0x00c3,
+	0x4f18: 0x00c3, 0x4f19: 0x00c3, 0x4f1a: 0x00c3, 0x4f1b: 0x00c3, 0x4f1c: 0x00c3, 0x4f1d: 0x00c3,
+	0x4f1e: 0x00c3, 0x4f1f: 0x00c3, 0x4f20: 0x00c3, 0x4f21: 0x00c3, 0x4f22: 0x00c3, 0x4f23: 0x00c3,
+	0x4f24: 0x00c3, 0x4f25: 0x00c3, 0x4f26: 0x00c3, 0x4f27: 0x00c3, 0x4f28: 0x00c3, 0x4f29: 0x00c3,
+	0x4f2a: 0x00c3, 0x4f2b: 0x00c3, 0x4f2c: 0x00c3, 0x4f2d: 0x00c3,
+	0x4f30: 0x00c3, 0x4f31: 0x00c3, 0x4f32: 0x00c3, 0x4f33: 0x00c3, 0x4f34: 0x00c3, 0x4f35: 0x00c3,
+	0x4f36: 0x00c3, 0x4f37: 0x00c3, 0x4f38: 0x00c3, 0x4f39: 0x00c3, 0x4f3a: 0x00c3, 0x4f3b: 0x00c3,
+	0x4f3c: 0x00c3, 0x4f3d: 0x00c3, 0x4f3e: 0x00c3, 0x4f3f: 0x00c3,
+	// Block 0x13d, offset 0x4f40
+	0x4f40: 0x00c3, 0x4f41: 0x00c3, 0x4f42: 0x00c3, 0x4f43: 0x00c3, 0x4f44: 0x00c3, 0x4f45: 0x00c3,
+	0x4f46: 0x00c3,
+	0x4f50: 0x0080, 0x4f51: 0x0080,
+	0x4f52: 0x0080, 0x4f53: 0x0080, 0x4f54: 0x0080, 0x4f55: 0x0080, 0x4f56: 0x0080, 0x4f57: 0x0080,
+	0x4f58: 0x0080, 0x4f59: 0x0080, 0x4f5a: 0x0080, 0x4f5b: 0x0080, 0x4f5c: 0x0080, 0x4f5d: 0x0080,
+	0x4f5e: 0x0080, 0x4f5f: 0x0080, 0x4f60: 0x0080, 0x4f61: 0x0080, 0x4f62: 0x0080, 0x4f63: 0x0080,
+	0x4f64: 0x0080, 0x4f65: 0x0080, 0x4f66: 0x0080, 0x4f67: 0x0080, 0x4f68: 0x0080, 0x4f69: 0x0080,
+	0x4f6a: 0x0080, 0x4f6b: 0x0080, 0x4f6c: 0x0080, 0x4f6d: 0x0080, 0x4f6e: 0x0080, 0x4f6f: 0x0080,
+	0x4f70: 0x0080, 0x4f71: 0x0080, 0x4f72: 0x0080, 0x4f73: 0x0080, 0x4f74: 0x0080, 0x4f75: 0x0080,
+	0x4f76: 0x0080, 0x4f77: 0x0080, 0x4f78: 0x0080, 0x4f79: 0x0080, 0x4f7a: 0x0080, 0x4f7b: 0x0080,
+	0x4f7c: 0x0080, 0x4f7d: 0x0080, 0x4f7e: 0x0080, 0x4f7f: 0x0080,
+	// Block 0x13e, offset 0x4f80
+	0x4f80: 0x0080, 0x4f81: 0x0080, 0x4f82: 0x0080, 0x4f83: 0x0080,
+	// Block 0x13f, offset 0x4fc0
+	0x4fc0: 0x0080, 0x4fc1: 0x0080, 0x4fc2: 0x0080, 0x4fc3: 0x0080, 0x4fc4: 0x0080, 0x4fc5: 0x0080,
+	0x4fc6: 0x0080, 0x4fc7: 0x0080, 0x4fc8: 0x0080, 0x4fc9: 0x0080, 0x4fca: 0x0080, 0x4fcb: 0x0080,
+	0x4fcc: 0x0080, 0x4fcd: 0x0080, 0x4fce: 0x0080, 0x4fcf: 0x0080, 0x4fd0: 0x0080, 0x4fd1: 0x0080,
+	0x4fd2: 0x0080, 0x4fd3: 0x0080, 0x4fd4: 0x0080, 0x4fd5: 0x0080, 0x4fd6: 0x0080, 0x4fd7: 0x0080,
+	0x4fd8: 0x0080, 0x4fd9: 0x0080, 0x4fda: 0x0080, 0x4fdb: 0x0080, 0x4fdc: 0x0080, 0x4fdd: 0x0080,
+	0x4fde: 0x0080, 0x4fdf: 0x0080, 0x4fe0: 0x0080, 0x4fe1: 0x0080, 0x4fe2: 0x0080, 0x4fe3: 0x0080,
+	0x4fe4: 0x0080, 0x4fe5: 0x0080, 0x4fe6: 0x0080, 0x4fe7: 0x0080, 0x4fe8: 0x0080, 0x4fe9: 0x0080,
+	0x4fea: 0x0080, 0x4feb: 0x0080, 0x4fec: 0x0080, 0x4fed: 0x0080, 0x4fee: 0x0080, 0x4fef: 0x0080,
+	0x4ff0: 0x0080, 0x4ff1: 0x0080, 0x4ff2: 0x0080, 0x4ff3: 0x0080, 0x4ff4: 0x0080, 0x4ff5: 0x0080,
+	// Block 0x140, offset 0x5000
+	0x5000: 0x0080, 0x5001: 0x0080, 0x5002: 0x0080, 0x5003: 0x0080, 0x5004: 0x0080, 0x5005: 0x0080,
+	0x5006: 0x0080, 0x5007: 0x0080, 0x5008: 0x0080, 0x5009: 0x0080, 0x500a: 0x0080, 0x500b: 0x0080,
+	0x500c: 0x0080, 0x500d: 0x0080, 0x500e: 0x0080, 0x500f: 0x0080, 0x5010: 0x0080, 0x5011: 0x0080,
+	0x5012: 0x0080, 0x5013: 0x0080, 0x5014: 0x0080, 0x5015: 0x0080, 0x5016: 0x0080, 0x5017: 0x0080,
+	0x5018: 0x0080, 0x5019: 0x0080, 0x501a: 0x0080, 0x501b: 0x0080, 0x501c: 0x0080, 0x501d: 0x0080,
+	0x501e: 0x0080, 0x501f: 0x0080, 0x5020: 0x0080, 0x5021: 0x0080, 0x5022: 0x0080, 0x5023: 0x0080,
+	0x5024: 0x0080, 0x5025: 0x0080, 0x5026: 0x0080, 0x5029: 0x0080,
+	0x502a: 0x0080, 0x502b: 0x0080, 0x502c: 0x0080, 0x502d: 0x0080, 0x502e: 0x0080, 0x502f: 0x0080,
+	0x5030: 0x0080, 0x5031: 0x0080, 0x5032: 0x0080, 0x5033: 0x0080, 0x5034: 0x0080, 0x5035: 0x0080,
+	0x5036: 0x0080, 0x5037: 0x0080, 0x5038: 0x0080, 0x5039: 0x0080, 0x503a: 0x0080, 0x503b: 0x0080,
+	0x503c: 0x0080, 0x503d: 0x0080, 0x503e: 0x0080, 0x503f: 0x0080,
+	// Block 0x141, offset 0x5040
+	0x5040: 0x0080, 0x5041: 0x0080, 0x5042: 0x0080, 0x5043: 0x0080, 0x5044: 0x0080, 0x5045: 0x0080,
+	0x5046: 0x0080, 0x5047: 0x0080, 0x5048: 0x0080, 0x5049: 0x0080, 0x504a: 0x0080, 0x504b: 0x0080,
+	0x504c: 0x0080, 0x504d: 0x0080, 0x504e: 0x0080, 0x504f: 0x0080, 0x5050: 0x0080, 0x5051: 0x0080,
+	0x5052: 0x0080, 0x5053: 0x0080, 0x5054: 0x0080, 0x5055: 0x0080, 0x5056: 0x0080, 0x5057: 0x0080,
+	0x5058: 0x0080, 0x5059: 0x0080, 0x505a: 0x0080, 0x505b: 0x0080, 0x505c: 0x0080, 0x505d: 0x0080,
+	0x505e: 0x0080, 0x505f: 0x0080, 0x5060: 0x0080, 0x5061: 0x0080, 0x5062: 0x0080, 0x5063: 0x0080,
+	0x5064: 0x0080, 0x5065: 0x00c0, 0x5066: 0x00c0, 0x5067: 0x00c3, 0x5068: 0x00c3, 0x5069: 0x00c3,
+	0x506a: 0x0080, 0x506b: 0x0080, 0x506c: 0x0080, 0x506d: 0x00c0, 0x506e: 0x00c0, 0x506f: 0x00c0,
+	0x5070: 0x00c0, 0x5071: 0x00c0, 0x5072: 0x00c0, 0x5073: 0x0040, 0x5074: 0x0040, 0x5075: 0x0040,
+	0x5076: 0x0040, 0x5077: 0x0040, 0x5078: 0x0040, 0x5079: 0x0040, 0x507a: 0x0040, 0x507b: 0x00c3,
+	0x507c: 0x00c3, 0x507d: 0x00c3, 0x507e: 0x00c3, 0x507f: 0x00c3,
+	// Block 0x142, offset 0x5080
+	0x5080: 0x00c3, 0x5081: 0x00c3, 0x5082: 0x00c3, 0x5083: 0x0080, 0x5084: 0x0080, 0x5085: 0x00c3,
+	0x5086: 0x00c3, 0x5087: 0x00c3, 0x5088: 0x00c3, 0x5089: 0x00c3, 0x508a: 0x00c3, 0x508b: 0x00c3,
+	0x508c: 0x0080, 0x508d: 0x0080, 0x508e: 0x0080, 0x508f: 0x0080, 0x5090: 0x0080, 0x5091: 0x0080,
+	0x5092: 0x0080, 0x5093: 0x0080, 0x5094: 0x0080, 0x5095: 0x0080, 0x5096: 0x0080, 0x5097: 0x0080,
+	0x5098: 0x0080, 0x5099: 0x0080, 0x509a: 0x0080, 0x509b: 0x0080, 0x509c: 0x0080, 0x509d: 0x0080,
+	0x509e: 0x0080, 0x509f: 0x0080, 0x50a0: 0x0080, 0x50a1: 0x0080, 0x50a2: 0x0080, 0x50a3: 0x0080,
+	0x50a4: 0x0080, 0x50a5: 0x0080, 0x50a6: 0x0080, 0x50a7: 0x0080, 0x50a8: 0x0080, 0x50a9: 0x0080,
+	0x50aa: 0x00c3, 0x50ab: 0x00c3, 0x50ac: 0x00c3, 0x50ad: 0x00c3, 0x50ae: 0x0080, 0x50af: 0x0080,
+	0x50b0: 0x0080, 0x50b1: 0x0080, 0x50b2: 0x0080, 0x50b3: 0x0080, 0x50b4: 0x0080, 0x50b5: 0x0080,
+	0x50b6: 0x0080, 0x50b7: 0x0080, 0x50b8: 0x0080, 0x50b9: 0x0080, 0x50ba: 0x0080, 0x50bb: 0x0080,
+	0x50bc: 0x0080, 0x50bd: 0x0080, 0x50be: 0x0080, 0x50bf: 0x0080,
+	// Block 0x143, offset 0x50c0
+	0x50c0: 0x0080, 0x50c1: 0x0080, 0x50c2: 0x0080, 0x50c3: 0x0080, 0x50c4: 0x0080, 0x50c5: 0x0080,
+	0x50c6: 0x0080, 0x50c7: 0x0080, 0x50c8: 0x0080, 0x50c9: 0x0080, 0x50ca: 0x0080, 0x50cb: 0x0080,
+	0x50cc: 0x0080, 0x50cd: 0x0080, 0x50ce: 0x0080, 0x50cf: 0x0080, 0x50d0: 0x0080, 0x50d1: 0x0080,
+	0x50d2: 0x0080, 0x50d3: 0x0080, 0x50d4: 0x0080, 0x50d5: 0x0080, 0x50d6: 0x0080, 0x50d7: 0x0080,
+	0x50d8: 0x0080, 0x50d9: 0x0080, 0x50da: 0x0080, 0x50db: 0x0080, 0x50dc: 0x0080, 0x50dd: 0x0080,
+	0x50de: 0x0080, 0x50df: 0x0080, 0x50e0: 0x0080, 0x50e1: 0x0080, 0x50e2: 0x0080, 0x50e3: 0x0080,
+	0x50e4: 0x0080, 0x50e5: 0x0080, 0x50e6: 0x0080, 0x50e7: 0x0080, 0x50e8: 0x0080, 0x50e9: 0x0080,
+	0x50ea: 0x0080,
+	// Block 0x144, offset 0x5100
+	0x5100: 0x0088, 0x5101: 0x0088, 0x5102: 0x00c9, 0x5103: 0x00c9, 0x5104: 0x00c9, 0x5105: 0x0088,
+	// Block 0x145, offset 0x5140
+	0x5140: 0x0080, 0x5141: 0x0080, 0x5142: 0x0080, 0x5143: 0x0080, 0x5144: 0x0080, 0x5145: 0x0080,
+	0x5146: 0x0080, 0x5147: 0x0080, 0x5148: 0x0080, 0x5149: 0x0080, 0x514a: 0x0080, 0x514b: 0x0080,
+	0x514c: 0x0080, 0x514d: 0x0080, 0x514e: 0x0080, 0x514f: 0x0080, 0x5150: 0x0080, 0x5151: 0x0080,
+	0x5152: 0x0080, 0x5153: 0x0080,
+	0x5160: 0x0080, 0x5161: 0x0080, 0x5162: 0x0080, 0x5163: 0x0080,
+	0x5164: 0x0080, 0x5165: 0x0080, 0x5166: 0x0080, 0x5167: 0x0080, 0x5168: 0x0080, 0x5169: 0x0080,
+	0x516a: 0x0080, 0x516b: 0x0080, 0x516c: 0x0080, 0x516d: 0x0080, 0x516e: 0x0080, 0x516f: 0x0080,
+	0x5170: 0x0080, 0x5171: 0x0080, 0x5172: 0x0080, 0x5173: 0x0080,
+	// Block 0x146, offset 0x5180
+	0x5180: 0x0080, 0x5181: 0x0080, 0x5182: 0x0080, 0x5183: 0x0080, 0x5184: 0x0080, 0x5185: 0x0080,
+	0x5186: 0x0080, 0x5187: 0x0080, 0x5188: 0x0080, 0x5189: 0x0080, 0x518a: 0x0080, 0x518b: 0x0080,
+	0x518c: 0x0080, 0x518d: 0x0080, 0x518e: 0x0080, 0x518f: 0x0080, 0x5190: 0x0080, 0x5191: 0x0080,
+	0x5192: 0x0080, 0x5193: 0x0080, 0x5194: 0x0080, 0x5195: 0x0080, 0x5196: 0x0080,
+	0x51a0: 0x0080, 0x51a1: 0x0080, 0x51a2: 0x0080, 0x51a3: 0x0080,
+	0x51a4: 0x0080, 0x51a5: 0x0080, 0x51a6: 0x0080, 0x51a7: 0x0080, 0x51a8: 0x0080, 0x51a9: 0x0080,
+	0x51aa: 0x0080, 0x51ab: 0x0080, 0x51ac: 0x0080, 0x51ad: 0x0080, 0x51ae: 0x0080, 0x51af: 0x0080,
+	0x51b0: 0x0080, 0x51b1: 0x0080, 0x51b2: 0x0080, 0x51b3: 0x0080, 0x51b4: 0x0080, 0x51b5: 0x0080,
+	0x51b6: 0x0080, 0x51b7: 0x0080, 0x51b8: 0x0080,
+	// Block 0x147, offset 0x51c0
+	0x51c0: 0x0080, 0x51c1: 0x0080, 0x51c2: 0x0080, 0x51c3: 0x0080, 0x51c4: 0x0080, 0x51c5: 0x0080,
+	0x51c6: 0x0080, 0x51c7: 0x0080, 0x51c8: 0x0080, 0x51c9: 0x0080, 0x51ca: 0x0080, 0x51cb: 0x0080,
+	0x51cc: 0x0080, 0x51cd: 0x0080, 0x51ce: 0x0080, 0x51cf: 0x0080, 0x51d0: 0x0080, 0x51d1: 0x0080,
+	0x51d2: 0x0080, 0x51d3: 0x0080, 0x51d4: 0x0080, 0x51d6: 0x0080, 0x51d7: 0x0080,
+	0x51d8: 0x0080, 0x51d9: 0x0080, 0x51da: 0x0080, 0x51db: 0x0080, 0x51dc: 0x0080, 0x51dd: 0x0080,
+	0x51de: 0x0080, 0x51df: 0x0080, 0x51e0: 0x0080, 0x51e1: 0x0080, 0x51e2: 0x0080, 0x51e3: 0x0080,
+	0x51e4: 0x0080, 0x51e5: 0x0080, 0x51e6: 0x0080, 0x51e7: 0x0080, 0x51e8: 0x0080, 0x51e9: 0x0080,
+	0x51ea: 0x0080, 0x51eb: 0x0080, 0x51ec: 0x0080, 0x51ed: 0x0080, 0x51ee: 0x0080, 0x51ef: 0x0080,
+	0x51f0: 0x0080, 0x51f1: 0x0080, 0x51f2: 0x0080, 0x51f3: 0x0080, 0x51f4: 0x0080, 0x51f5: 0x0080,
+	0x51f6: 0x0080, 0x51f7: 0x0080, 0x51f8: 0x0080, 0x51f9: 0x0080, 0x51fa: 0x0080, 0x51fb: 0x0080,
+	0x51fc: 0x0080, 0x51fd: 0x0080, 0x51fe: 0x0080, 0x51ff: 0x0080,
+	// Block 0x148, offset 0x5200
+	0x5200: 0x0080, 0x5201: 0x0080, 0x5202: 0x0080, 0x5203: 0x0080, 0x5204: 0x0080, 0x5205: 0x0080,
+	0x5206: 0x0080, 0x5207: 0x0080, 0x5208: 0x0080, 0x5209: 0x0080, 0x520a: 0x0080, 0x520b: 0x0080,
+	0x520c: 0x0080, 0x520d: 0x0080, 0x520e: 0x0080, 0x520f: 0x0080, 0x5210: 0x0080, 0x5211: 0x0080,
+	0x5212: 0x0080, 0x5213: 0x0080, 0x5214: 0x0080, 0x5215: 0x0080, 0x5216: 0x0080, 0x5217: 0x0080,
+	0x5218: 0x0080, 0x5219: 0x0080, 0x521a: 0x0080, 0x521b: 0x0080, 0x521c: 0x0080,
+	0x521e: 0x0080, 0x521f: 0x0080, 0x5222: 0x0080,
+	0x5225: 0x0080, 0x5226: 0x0080, 0x5229: 0x0080,
+	0x522a: 0x0080, 0x522b: 0x0080, 0x522c: 0x0080, 0x522e: 0x0080, 0x522f: 0x0080,
+	0x5230: 0x0080, 0x5231: 0x0080, 0x5232: 0x0080, 0x5233: 0x0080, 0x5234: 0x0080, 0x5235: 0x0080,
+	0x5236: 0x0080, 0x5237: 0x0080, 0x5238: 0x0080, 0x5239: 0x0080, 0x523b: 0x0080,
+	0x523d: 0x0080, 0x523e: 0x0080, 0x523f: 0x0080,
+	// Block 0x149, offset 0x5240
+	0x5240: 0x0080, 0x5241: 0x0080, 0x5242: 0x0080, 0x5243: 0x0080, 0x5245: 0x0080,
+	0x5246: 0x0080, 0x5247: 0x0080, 0x5248: 0x0080, 0x5249: 0x0080, 0x524a: 0x0080, 0x524b: 0x0080,
+	0x524c: 0x0080, 0x524d: 0x0080, 0x524e: 0x0080, 0x524f: 0x0080, 0x5250: 0x0080, 0x5251: 0x0080,
+	0x5252: 0x0080, 0x5253: 0x0080, 0x5254: 0x0080, 0x5255: 0x0080, 0x5256: 0x0080, 0x5257: 0x0080,
+	0x5258: 0x0080, 0x5259: 0x0080, 0x525a: 0x0080, 0x525b: 0x0080, 0x525c: 0x0080, 0x525d: 0x0080,
+	0x525e: 0x0080, 0x525f: 0x0080, 0x5260: 0x0080, 0x5261: 0x0080, 0x5262: 0x0080, 0x5263: 0x0080,
+	0x5264: 0x0080, 0x5265: 0x0080, 0x5266: 0x0080, 0x5267: 0x0080, 0x5268: 0x0080, 0x5269: 0x0080,
+	0x526a: 0x0080, 0x526b: 0x0080, 0x526c: 0x0080, 0x526d: 0x0080, 0x526e: 0x0080, 0x526f: 0x0080,
+	0x5270: 0x0080, 0x5271: 0x0080, 0x5272: 0x0080, 0x5273: 0x0080, 0x5274: 0x0080, 0x5275: 0x0080,
+	0x5276: 0x0080, 0x5277: 0x0080, 0x5278: 0x0080, 0x5279: 0x0080, 0x527a: 0x0080, 0x527b: 0x0080,
+	0x527c: 0x0080, 0x527d: 0x0080, 0x527e: 0x0080, 0x527f: 0x0080,
+	// Block 0x14a, offset 0x5280
+	0x5280: 0x0080, 0x5281: 0x0080, 0x5282: 0x0080, 0x5283: 0x0080, 0x5284: 0x0080, 0x5285: 0x0080,
+	0x5287: 0x0080, 0x5288: 0x0080, 0x5289: 0x0080, 0x528a: 0x0080,
+	0x528d: 0x0080, 0x528e: 0x0080, 0x528f: 0x0080, 0x5290: 0x0080, 0x5291: 0x0080,
+	0x5292: 0x0080, 0x5293: 0x0080, 0x5294: 0x0080, 0x5296: 0x0080, 0x5297: 0x0080,
+	0x5298: 0x0080, 0x5299: 0x0080, 0x529a: 0x0080, 0x529b: 0x0080, 0x529c: 0x0080,
+	0x529e: 0x0080, 0x529f: 0x0080, 0x52a0: 0x0080, 0x52a1: 0x0080, 0x52a2: 0x0080, 0x52a3: 0x0080,
+	0x52a4: 0x0080, 0x52a5: 0x0080, 0x52a6: 0x0080, 0x52a7: 0x0080, 0x52a8: 0x0080, 0x52a9: 0x0080,
+	0x52aa: 0x0080, 0x52ab: 0x0080, 0x52ac: 0x0080, 0x52ad: 0x0080, 0x52ae: 0x0080, 0x52af: 0x0080,
+	0x52b0: 0x0080, 0x52b1: 0x0080, 0x52b2: 0x0080, 0x52b3: 0x0080, 0x52b4: 0x0080, 0x52b5: 0x0080,
+	0x52b6: 0x0080, 0x52b7: 0x0080, 0x52b8: 0x0080, 0x52b9: 0x0080, 0x52bb: 0x0080,
+	0x52bc: 0x0080, 0x52bd: 0x0080, 0x52be: 0x0080,
+	// Block 0x14b, offset 0x52c0
+	0x52c0: 0x0080, 0x52c1: 0x0080, 0x52c2: 0x0080, 0x52c3: 0x0080, 0x52c4: 0x0080,
+	0x52c6: 0x0080, 0x52ca: 0x0080, 0x52cb: 0x0080,
+	0x52cc: 0x0080, 0x52cd: 0x0080, 0x52ce: 0x0080, 0x52cf: 0x0080, 0x52d0: 0x0080,
+	0x52d2: 0x0080, 0x52d3: 0x0080, 0x52d4: 0x0080, 0x52d5: 0x0080, 0x52d6: 0x0080, 0x52d7: 0x0080,
+	0x52d8: 0x0080, 0x52d9: 0x0080, 0x52da: 0x0080, 0x52db: 0x0080, 0x52dc: 0x0080, 0x52dd: 0x0080,
+	0x52de: 0x0080, 0x52df: 0x0080, 0x52e0: 0x0080, 0x52e1: 0x0080, 0x52e2: 0x0080, 0x52e3: 0x0080,
+	0x52e4: 0x0080, 0x52e5: 0x0080, 0x52e6: 0x0080, 0x52e7: 0x0080, 0x52e8: 0x0080, 0x52e9: 0x0080,
+	0x52ea: 0x0080, 0x52eb: 0x0080, 0x52ec: 0x0080, 0x52ed: 0x0080, 0x52ee: 0x0080, 0x52ef: 0x0080,
+	0x52f0: 0x0080, 0x52f1: 0x0080, 0x52f2: 0x0080, 0x52f3: 0x0080, 0x52f4: 0x0080, 0x52f5: 0x0080,
+	0x52f6: 0x0080, 0x52f7: 0x0080, 0x52f8: 0x0080, 0x52f9: 0x0080, 0x52fa: 0x0080, 0x52fb: 0x0080,
+	0x52fc: 0x0080, 0x52fd: 0x0080, 0x52fe: 0x0080, 0x52ff: 0x0080,
+	// Block 0x14c, offset 0x5300
+	0x5300: 0x0080, 0x5301: 0x0080, 0x5302: 0x0080, 0x5303: 0x0080, 0x5304: 0x0080, 0x5305: 0x0080,
+	0x5306: 0x0080, 0x5307: 0x0080, 0x5308: 0x0080, 0x5309: 0x0080, 0x530a: 0x0080, 0x530b: 0x0080,
+	0x530c: 0x0080, 0x530d: 0x0080, 0x530e: 0x0080, 0x530f: 0x0080, 0x5310: 0x0080, 0x5311: 0x0080,
+	0x5312: 0x0080, 0x5313: 0x0080, 0x5314: 0x0080, 0x5315: 0x0080, 0x5316: 0x0080, 0x5317: 0x0080,
+	0x5318: 0x0080, 0x5319: 0x0080, 0x531a: 0x0080, 0x531b: 0x0080, 0x531c: 0x0080, 0x531d: 0x0080,
+	0x531e: 0x0080, 0x531f: 0x0080, 0x5320: 0x0080, 0x5321: 0x0080, 0x5322: 0x0080, 0x5323: 0x0080,
+	0x5324: 0x0080, 0x5325: 0x0080, 0x5328: 0x0080, 0x5329: 0x0080,
+	0x532a: 0x0080, 0x532b: 0x0080, 0x532c: 0x0080, 0x532d: 0x0080, 0x532e: 0x0080, 0x532f: 0x0080,
+	0x5330: 0x0080, 0x5331: 0x0080, 0x5332: 0x0080, 0x5333: 0x0080, 0x5334: 0x0080, 0x5335: 0x0080,
+	0x5336: 0x0080, 0x5337: 0x0080, 0x5338: 0x0080, 0x5339: 0x0080, 0x533a: 0x0080, 0x533b: 0x0080,
+	0x533c: 0x0080, 0x533d: 0x0080, 0x533e: 0x0080, 0x533f: 0x0080,
+	// Block 0x14d, offset 0x5340
+	0x5340: 0x0080, 0x5341: 0x0080, 0x5342: 0x0080, 0x5343: 0x0080, 0x5344: 0x0080, 0x5345: 0x0080,
+	0x5346: 0x0080, 0x5347: 0x0080, 0x5348: 0x0080, 0x5349: 0x0080, 0x534a: 0x0080, 0x534b: 0x0080,
+	0x534e: 0x0080, 0x534f: 0x0080, 0x5350: 0x0080, 0x5351: 0x0080,
+	0x5352: 0x0080, 0x5353: 0x0080, 0x5354: 0x0080, 0x5355: 0x0080, 0x5356: 0x0080, 0x5357: 0x0080,
+	0x5358: 0x0080, 0x5359: 0x0080, 0x535a: 0x0080, 0x535b: 0x0080, 0x535c: 0x0080, 0x535d: 0x0080,
+	0x535e: 0x0080, 0x535f: 0x0080, 0x5360: 0x0080, 0x5361: 0x0080, 0x5362: 0x0080, 0x5363: 0x0080,
+	0x5364: 0x0080, 0x5365: 0x0080, 0x5366: 0x0080, 0x5367: 0x0080, 0x5368: 0x0080, 0x5369: 0x0080,
+	0x536a: 0x0080, 0x536b: 0x0080, 0x536c: 0x0080, 0x536d: 0x0080, 0x536e: 0x0080, 0x536f: 0x0080,
+	0x5370: 0x0080, 0x5371: 0x0080, 0x5372: 0x0080, 0x5373: 0x0080, 0x5374: 0x0080, 0x5375: 0x0080,
+	0x5376: 0x0080, 0x5377: 0x0080, 0x5378: 0x0080, 0x5379: 0x0080, 0x537a: 0x0080, 0x537b: 0x0080,
+	0x537c: 0x0080, 0x537d: 0x0080, 0x537e: 0x0080, 0x537f: 0x0080,
+	// Block 0x14e, offset 0x5380
+	0x5380: 0x00c3, 0x5381: 0x00c3, 0x5382: 0x00c3, 0x5383: 0x00c3, 0x5384: 0x00c3, 0x5385: 0x00c3,
+	0x5386: 0x00c3, 0x5387: 0x00c3, 0x5388: 0x00c3, 0x5389: 0x00c3, 0x538a: 0x00c3, 0x538b: 0x00c3,
+	0x538c: 0x00c3, 0x538d: 0x00c3, 0x538e: 0x00c3, 0x538f: 0x00c3, 0x5390: 0x00c3, 0x5391: 0x00c3,
+	0x5392: 0x00c3, 0x5393: 0x00c3, 0x5394: 0x00c3, 0x5395: 0x00c3, 0x5396: 0x00c3, 0x5397: 0x00c3,
+	0x5398: 0x00c3, 0x5399: 0x00c3, 0x539a: 0x00c3, 0x539b: 0x00c3, 0x539c: 0x00c3, 0x539d: 0x00c3,
+	0x539e: 0x00c3, 0x539f: 0x00c3, 0x53a0: 0x00c3, 0x53a1: 0x00c3, 0x53a2: 0x00c3, 0x53a3: 0x00c3,
+	0x53a4: 0x00c3, 0x53a5: 0x00c3, 0x53a6: 0x00c3, 0x53a7: 0x00c3, 0x53a8: 0x00c3, 0x53a9: 0x00c3,
+	0x53aa: 0x00c3, 0x53ab: 0x00c3, 0x53ac: 0x00c3, 0x53ad: 0x00c3, 0x53ae: 0x00c3, 0x53af: 0x00c3,
+	0x53b0: 0x00c3, 0x53b1: 0x00c3, 0x53b2: 0x00c3, 0x53b3: 0x00c3, 0x53b4: 0x00c3, 0x53b5: 0x00c3,
+	0x53b6: 0x00c3, 0x53b7: 0x0080, 0x53b8: 0x0080, 0x53b9: 0x0080, 0x53ba: 0x0080, 0x53bb: 0x00c3,
+	0x53bc: 0x00c3, 0x53bd: 0x00c3, 0x53be: 0x00c3, 0x53bf: 0x00c3,
+	// Block 0x14f, offset 0x53c0
+	0x53c0: 0x00c3, 0x53c1: 0x00c3, 0x53c2: 0x00c3, 0x53c3: 0x00c3, 0x53c4: 0x00c3, 0x53c5: 0x00c3,
+	0x53c6: 0x00c3, 0x53c7: 0x00c3, 0x53c8: 0x00c3, 0x53c9: 0x00c3, 0x53ca: 0x00c3, 0x53cb: 0x00c3,
+	0x53cc: 0x00c3, 0x53cd: 0x00c3, 0x53ce: 0x00c3, 0x53cf: 0x00c3, 0x53d0: 0x00c3, 0x53d1: 0x00c3,
+	0x53d2: 0x00c3, 0x53d3: 0x00c3, 0x53d4: 0x00c3, 0x53d5: 0x00c3, 0x53d6: 0x00c3, 0x53d7: 0x00c3,
+	0x53d8: 0x00c3, 0x53d9: 0x00c3, 0x53da: 0x00c3, 0x53db: 0x00c3, 0x53dc: 0x00c3, 0x53dd: 0x00c3,
+	0x53de: 0x00c3, 0x53df: 0x00c3, 0x53e0: 0x00c3, 0x53e1: 0x00c3, 0x53e2: 0x00c3, 0x53e3: 0x00c3,
+	0x53e4: 0x00c3, 0x53e5: 0x00c3, 0x53e6: 0x00c3, 0x53e7: 0x00c3, 0x53e8: 0x00c3, 0x53e9: 0x00c3,
+	0x53ea: 0x00c3, 0x53eb: 0x00c3, 0x53ec: 0x00c3, 0x53ed: 0x0080, 0x53ee: 0x0080, 0x53ef: 0x0080,
+	0x53f0: 0x0080, 0x53f1: 0x0080, 0x53f2: 0x0080, 0x53f3: 0x0080, 0x53f4: 0x0080, 0x53f5: 0x00c3,
+	0x53f6: 0x0080, 0x53f7: 0x0080, 0x53f8: 0x0080, 0x53f9: 0x0080, 0x53fa: 0x0080, 0x53fb: 0x0080,
+	0x53fc: 0x0080, 0x53fd: 0x0080, 0x53fe: 0x0080, 0x53ff: 0x0080,
+	// Block 0x150, offset 0x5400
+	0x5400: 0x0080, 0x5401: 0x0080, 0x5402: 0x0080, 0x5403: 0x0080, 0x5404: 0x00c3, 0x5405: 0x0080,
+	0x5406: 0x0080, 0x5407: 0x0080, 0x5408: 0x0080, 0x5409: 0x0080, 0x540a: 0x0080, 0x540b: 0x0080,
+	0x541b: 0x00c3, 0x541c: 0x00c3, 0x541d: 0x00c3,
+	0x541e: 0x00c3, 0x541f: 0x00c3, 0x5421: 0x00c3, 0x5422: 0x00c3, 0x5423: 0x00c3,
+	0x5424: 0x00c3, 0x5425: 0x00c3, 0x5426: 0x00c3, 0x5427: 0x00c3, 0x5428: 0x00c3, 0x5429: 0x00c3,
+	0x542a: 0x00c3, 0x542b: 0x00c3, 0x542c: 0x00c3, 0x542d: 0x00c3, 0x542e: 0x00c3, 0x542f: 0x00c3,
+	// Block 0x151, offset 0x5440
+	0x5440: 0x00c0, 0x5441: 0x00c0, 0x5442: 0x00c0, 0x5443: 0x00c0, 0x5444: 0x00c0, 0x5445: 0x00c0,
+	0x5446: 0x00c0, 0x5447: 0x00c0, 0x5448: 0x00c0, 0x5449: 0x00c0, 0x544a: 0x00c0, 0x544b: 0x00c0,
+	0x544c: 0x00c0, 0x544d: 0x00c0, 0x544e: 0x00c0, 0x544f: 0x00c0, 0x5450: 0x00c0, 0x5451: 0x00c0,
+	0x5452: 0x00c0, 0x5453: 0x00c0, 0x5454: 0x00c0, 0x5455: 0x00c0, 0x5456: 0x00c0, 0x5457: 0x00c0,
+	0x5458: 0x00c0, 0x5459: 0x00c0, 0x545a: 0x00c0, 0x545b: 0x00c0, 0x545c: 0x00c0, 0x545d: 0x00c0,
+	0x545e: 0x00c0,
+	0x5465: 0x00c0, 0x5466: 0x00c0, 0x5467: 0x00c0, 0x5468: 0x00c0, 0x5469: 0x00c0,
+	0x546a: 0x00c0,
+	// Block 0x152, offset 0x5480
+	0x5480: 0x00c3, 0x5481: 0x00c3, 0x5482: 0x00c3, 0x5483: 0x00c3, 0x5484: 0x00c3, 0x5485: 0x00c3,
+	0x5486: 0x00c3, 0x5488: 0x00c3, 0x5489: 0x00c3, 0x548a: 0x00c3, 0x548b: 0x00c3,
+	0x548c: 0x00c3, 0x548d: 0x00c3, 0x548e: 0x00c3, 0x548f: 0x00c3, 0x5490: 0x00c3, 0x5491: 0x00c3,
+	0x5492: 0x00c3, 0x5493: 0x00c3, 0x5494: 0x00c3, 0x5495: 0x00c3, 0x5496: 0x00c3, 0x5497: 0x00c3,
+	0x5498: 0x00c3, 0x549b: 0x00c3, 0x549c: 0x00c3, 0x549d: 0x00c3,
+	0x549e: 0x00c3, 0x549f: 0x00c3, 0x54a0: 0x00c3, 0x54a1: 0x00c3, 0x54a3: 0x00c3,
+	0x54a4: 0x00c3, 0x54a6: 0x00c3, 0x54a7: 0x00c3, 0x54a8: 0x00c3, 0x54a9: 0x00c3,
+	0x54aa: 0x00c3,
+	0x54b0: 0x0080, 0x54b1: 0x0080, 0x54b2: 0x0080, 0x54b3: 0x0080, 0x54b4: 0x0080, 0x54b5: 0x0080,
+	0x54b6: 0x0080, 0x54b7: 0x0080, 0x54b8: 0x0080, 0x54b9: 0x0080, 0x54ba: 0x0080, 0x54bb: 0x0080,
+	0x54bc: 0x0080, 0x54bd: 0x0080, 0x54be: 0x0080, 0x54bf: 0x0080,
+	// Block 0x153, offset 0x54c0
+	0x54c0: 0x0080, 0x54c1: 0x0080, 0x54c2: 0x0080, 0x54c3: 0x0080, 0x54c4: 0x0080, 0x54c5: 0x0080,
+	0x54c6: 0x0080, 0x54c7: 0x0080, 0x54c8: 0x0080, 0x54c9: 0x0080, 0x54ca: 0x0080, 0x54cb: 0x0080,
+	0x54cc: 0x0080, 0x54cd: 0x0080, 0x54ce: 0x0080, 0x54cf: 0x0080, 0x54d0: 0x0080, 0x54d1: 0x0080,
+	0x54d2: 0x0080, 0x54d3: 0x0080, 0x54d4: 0x0080, 0x54d5: 0x0080, 0x54d6: 0x0080, 0x54d7: 0x0080,
+	0x54d8: 0x0080, 0x54d9: 0x0080, 0x54da: 0x0080, 0x54db: 0x0080, 0x54dc: 0x0080, 0x54dd: 0x0080,
+	0x54de: 0x0080, 0x54df: 0x0080, 0x54e0: 0x0080, 0x54e1: 0x0080, 0x54e2: 0x0080, 0x54e3: 0x0080,
+	0x54e4: 0x0080, 0x54e5: 0x0080, 0x54e6: 0x0080, 0x54e7: 0x0080, 0x54e8: 0x0080, 0x54e9: 0x0080,
+	0x54ea: 0x0080, 0x54eb: 0x0080, 0x54ec: 0x0080, 0x54ed: 0x0080,
+	// Block 0x154, offset 0x5500
+	0x550f: 0x00c3,
+	// Block 0x155, offset 0x5540
+	0x5540: 0x00c0, 0x5541: 0x00c0, 0x5542: 0x00c0, 0x5543: 0x00c0, 0x5544: 0x00c0, 0x5545: 0x00c0,
+	0x5546: 0x00c0, 0x5547: 0x00c0, 0x5548: 0x00c0, 0x5549: 0x00c0, 0x554a: 0x00c0, 0x554b: 0x00c0,
+	0x554c: 0x00c0, 0x554d: 0x00c0, 0x554e: 0x00c0, 0x554f: 0x00c0, 0x5550: 0x00c0, 0x5551: 0x00c0,
+	0x5552: 0x00c0, 0x5553: 0x00c0, 0x5554: 0x00c0, 0x5555: 0x00c0, 0x5556: 0x00c0, 0x5557: 0x00c0,
+	0x5558: 0x00c0, 0x5559: 0x00c0, 0x555a: 0x00c0, 0x555b: 0x00c0, 0x555c: 0x00c0, 0x555d: 0x00c0,
+	0x555e: 0x00c0, 0x555f: 0x00c0, 0x5560: 0x00c0, 0x5561: 0x00c0, 0x5562: 0x00c0, 0x5563: 0x00c0,
+	0x5564: 0x00c0, 0x5565: 0x00c0, 0x5566: 0x00c0, 0x5567: 0x00c0, 0x5568: 0x00c0, 0x5569: 0x00c0,
+	0x556a: 0x00c0, 0x556b: 0x00c0, 0x556c: 0x00c0,
+	0x5570: 0x00c3, 0x5571: 0x00c3, 0x5572: 0x00c3, 0x5573: 0x00c3, 0x5574: 0x00c3, 0x5575: 0x00c3,
+	0x5576: 0x00c3, 0x5577: 0x00c0, 0x5578: 0x00c0, 0x5579: 0x00c0, 0x557a: 0x00c0, 0x557b: 0x00c0,
+	0x557c: 0x00c0, 0x557d: 0x00c0,
+	// Block 0x156, offset 0x5580
+	0x5580: 0x00c0, 0x5581: 0x00c0, 0x5582: 0x00c0, 0x5583: 0x00c0, 0x5584: 0x00c0, 0x5585: 0x00c0,
+	0x5586: 0x00c0, 0x5587: 0x00c0, 0x5588: 0x00c0, 0x5589: 0x00c0,
+	0x558e: 0x00c0, 0x558f: 0x0080,
+	// Block 0x157, offset 0x55c0
+	0x55d0: 0x00c0, 0x55d1: 0x00c0,
+	0x55d2: 0x00c0, 0x55d3: 0x00c0, 0x55d4: 0x00c0, 0x55d5: 0x00c0, 0x55d6: 0x00c0, 0x55d7: 0x00c0,
+	0x55d8: 0x00c0, 0x55d9: 0x00c0, 0x55da: 0x00c0, 0x55db: 0x00c0, 0x55dc: 0x00c0, 0x55dd: 0x00c0,
+	0x55de: 0x00c0, 0x55df: 0x00c0, 0x55e0: 0x00c0, 0x55e1: 0x00c0, 0x55e2: 0x00c0, 0x55e3: 0x00c0,
+	0x55e4: 0x00c0, 0x55e5: 0x00c0, 0x55e6: 0x00c0, 0x55e7: 0x00c0, 0x55e8: 0x00c0, 0x55e9: 0x00c0,
+	0x55ea: 0x00c0, 0x55eb: 0x00c0, 0x55ec: 0x00c0, 0x55ed: 0x00c0, 0x55ee: 0x00c3,
+	// Block 0x158, offset 0x5600
+	0x5600: 0x00c0, 0x5601: 0x00c0, 0x5602: 0x00c0, 0x5603: 0x00c0, 0x5604: 0x00c0, 0x5605: 0x00c0,
+	0x5606: 0x00c0, 0x5607: 0x00c0, 0x5608: 0x00c0, 0x5609: 0x00c0, 0x560a: 0x00c0, 0x560b: 0x00c0,
+	0x560c: 0x00c0, 0x560d: 0x00c0, 0x560e: 0x00c0, 0x560f: 0x00c0, 0x5610: 0x00c0, 0x5611: 0x00c0,
+	0x5612: 0x00c0, 0x5613: 0x00c0, 0x5614: 0x00c0, 0x5615: 0x00c0, 0x5616: 0x00c0, 0x5617: 0x00c0,
+	0x5618: 0x00c0, 0x5619: 0x00c0, 0x561a: 0x00c0, 0x561b: 0x00c0, 0x561c: 0x00c0, 0x561d: 0x00c0,
+	0x561e: 0x00c0, 0x561f: 0x00c0, 0x5620: 0x00c0, 0x5621: 0x00c0, 0x5622: 0x00c0, 0x5623: 0x00c0,
+	0x5624: 0x00c0, 0x5625: 0x00c0, 0x5626: 0x00c0, 0x5627: 0x00c0, 0x5628: 0x00c0, 0x5629: 0x00c0,
+	0x562a: 0x00c0, 0x562b: 0x00c0, 0x562c: 0x00c3, 0x562d: 0x00c3, 0x562e: 0x00c3, 0x562f: 0x00c3,
+	0x5630: 0x00c0, 0x5631: 0x00c0, 0x5632: 0x00c0, 0x5633: 0x00c0, 0x5634: 0x00c0, 0x5635: 0x00c0,
+	0x5636: 0x00c0, 0x5637: 0x00c0, 0x5638: 0x00c0, 0x5639: 0x00c0,
+	0x563f: 0x0080,
+	// Block 0x159, offset 0x5640
+	0x5650: 0x00c0, 0x5651: 0x00c0,
+	0x5652: 0x00c0, 0x5653: 0x00c0, 0x5654: 0x00c0, 0x5655: 0x00c0, 0x5656: 0x00c0, 0x5657: 0x00c0,
+	0x5658: 0x00c0, 0x5659: 0x00c0, 0x565a: 0x00c0, 0x565b: 0x00c0, 0x565c: 0x00c0, 0x565d: 0x00c0,
+	0x565e: 0x00c0, 0x565f: 0x00c0, 0x5660: 0x00c0, 0x5661: 0x00c0, 0x5662: 0x00c0, 0x5663: 0x00c0,
+	0x5664: 0x00c0, 0x5665: 0x00c0, 0x5666: 0x00c0, 0x5667: 0x00c0, 0x5668: 0x00c0, 0x5669: 0x00c0,
+	0x566a: 0x00c0, 0x566b: 0x00c0, 0x566c: 0x00c3, 0x566d: 0x00c3, 0x566e: 0x00c3, 0x566f: 0x00c3,
+	0x5670: 0x00c0, 0x5671: 0x00c0, 0x5672: 0x00c0, 0x5673: 0x00c0, 0x5674: 0x00c0, 0x5675: 0x00c0,
+	0x5676: 0x00c0, 0x5677: 0x00c0, 0x5678: 0x00c0, 0x5679: 0x00c0,
+	// Block 0x15a, offset 0x5680
+	0x5690: 0x00c0, 0x5691: 0x00c0,
+	0x5692: 0x00c0, 0x5693: 0x00c0, 0x5694: 0x00c0, 0x5695: 0x00c0, 0x5696: 0x00c0, 0x5697: 0x00c0,
+	0x5698: 0x00c0, 0x5699: 0x00c0, 0x569a: 0x00c0, 0x569b: 0x00c0, 0x569c: 0x00c0, 0x569d: 0x00c0,
+	0x569e: 0x00c0, 0x569f: 0x00c0, 0x56a0: 0x00c0, 0x56a1: 0x00c0, 0x56a2: 0x00c0, 0x56a3: 0x00c0,
+	0x56a4: 0x00c0, 0x56a5: 0x00c0, 0x56a6: 0x00c0, 0x56a7: 0x00c0, 0x56a8: 0x00c0, 0x56a9: 0x00c0,
+	0x56aa: 0x00c0, 0x56ab: 0x00c0, 0x56ac: 0x00c0, 0x56ad: 0x00c0, 0x56ae: 0x00c3, 0x56af: 0x00c3,
+	0x56b0: 0x00c0, 0x56b1: 0x00c0, 0x56b2: 0x00c0, 0x56b3: 0x00c0, 0x56b4: 0x00c0, 0x56b5: 0x00c0,
+	0x56b6: 0x00c0, 0x56b7: 0x00c0, 0x56b8: 0x00c0, 0x56b9: 0x00c0, 0x56ba: 0x00c0,
+	0x56bf: 0x0080,
+	// Block 0x15b, offset 0x56c0
+	0x56c0: 0x00c0, 0x56c1: 0x00c0, 0x56c2: 0x00c0, 0x56c3: 0x00c0, 0x56c4: 0x00c0, 0x56c5: 0x00c0,
+	0x56c6: 0x00c0, 0x56c7: 0x00c0, 0x56c8: 0x00c0, 0x56c9: 0x00c0, 0x56ca: 0x00c0, 0x56cb: 0x00c0,
+	0x56cc: 0x00c0, 0x56cd: 0x00c0, 0x56ce: 0x00c0, 0x56cf: 0x00c0, 0x56d0: 0x00c0, 0x56d1: 0x00c0,
+	0x56d2: 0x00c0, 0x56d3: 0x00c0, 0x56d4: 0x00c0, 0x56d5: 0x00c0, 0x56d6: 0x00c0, 0x56d7: 0x00c0,
+	0x56d8: 0x00c0, 0x56d9: 0x00c0, 0x56da: 0x00c0, 0x56db: 0x00c0, 0x56dc: 0x00c0, 0x56dd: 0x00c0,
+	0x56de: 0x00c0, 0x56e0: 0x00c0, 0x56e1: 0x00c0, 0x56e2: 0x00c0, 0x56e3: 0x00c3,
+	0x56e4: 0x00c0, 0x56e5: 0x00c0, 0x56e6: 0x00c3, 0x56e7: 0x00c0, 0x56e8: 0x00c0, 0x56e9: 0x00c0,
+	0x56ea: 0x00c0, 0x56eb: 0x00c0, 0x56ec: 0x00c0, 0x56ed: 0x00c0, 0x56ee: 0x00c3, 0x56ef: 0x00c3,
+	0x56f0: 0x00c0, 0x56f1: 0x00c0, 0x56f2: 0x00c0, 0x56f3: 0x00c0, 0x56f4: 0x00c0, 0x56f5: 0x00c3,
+	0x56fe: 0x00c0, 0x56ff: 0x00c0,
+	// Block 0x15c, offset 0x5700
+	0x5720: 0x00c0, 0x5721: 0x00c0, 0x5722: 0x00c0, 0x5723: 0x00c0,
+	0x5724: 0x00c0, 0x5725: 0x00c0, 0x5726: 0x00c0, 0x5728: 0x00c0, 0x5729: 0x00c0,
+	0x572a: 0x00c0, 0x572b: 0x00c0, 0x572d: 0x00c0, 0x572e: 0x00c0,
+	0x5730: 0x00c0, 0x5731: 0x00c0, 0x5732: 0x00c0, 0x5733: 0x00c0, 0x5734: 0x00c0, 0x5735: 0x00c0,
+	0x5736: 0x00c0, 0x5737: 0x00c0, 0x5738: 0x00c0, 0x5739: 0x00c0, 0x573a: 0x00c0, 0x573b: 0x00c0,
+	0x573c: 0x00c0, 0x573d: 0x00c0, 0x573e: 0x00c0,
+	// Block 0x15d, offset 0x5740
+	0x5740: 0x00c0, 0x5741: 0x00c0, 0x5742: 0x00c0, 0x5743: 0x00c0, 0x5744: 0x00c0,
+	0x5747: 0x0080, 0x5748: 0x0080, 0x5749: 0x0080, 0x574a: 0x0080, 0x574b: 0x0080,
+	0x574c: 0x0080, 0x574d: 0x0080, 0x574e: 0x0080, 0x574f: 0x0080, 0x5750: 0x00c3, 0x5751: 0x00c3,
+	0x5752: 0x00c3, 0x5753: 0x00c3, 0x5754: 0x00c3, 0x5755: 0x00c3, 0x5756: 0x00c3,
+	// Block 0x15e, offset 0x5780
+	0x5780: 0x00c2, 0x5781: 0x00c2, 0x5782: 0x00c2, 0x5783: 0x00c2, 0x5784: 0x00c2, 0x5785: 0x00c2,
+	0x5786: 0x00c2, 0x5787: 0x00c2, 0x5788: 0x00c2, 0x5789: 0x00c2, 0x578a: 0x00c2, 0x578b: 0x00c2,
+	0x578c: 0x00c2, 0x578d: 0x00c2, 0x578e: 0x00c2, 0x578f: 0x00c2, 0x5790: 0x00c2, 0x5791: 0x00c2,
+	0x5792: 0x00c2, 0x5793: 0x00c2, 0x5794: 0x00c2, 0x5795: 0x00c2, 0x5796: 0x00c2, 0x5797: 0x00c2,
+	0x5798: 0x00c2, 0x5799: 0x00c2, 0x579a: 0x00c2, 0x579b: 0x00c2, 0x579c: 0x00c2, 0x579d: 0x00c2,
+	0x579e: 0x00c2, 0x579f: 0x00c2, 0x57a0: 0x00c2, 0x57a1: 0x00c2, 0x57a2: 0x00c2, 0x57a3: 0x00c2,
+	0x57a4: 0x00c2, 0x57a5: 0x00c2, 0x57a6: 0x00c2, 0x57a7: 0x00c2, 0x57a8: 0x00c2, 0x57a9: 0x00c2,
+	0x57aa: 0x00c2, 0x57ab: 0x00c2, 0x57ac: 0x00c2, 0x57ad: 0x00c2, 0x57ae: 0x00c2, 0x57af: 0x00c2,
+	0x57b0: 0x00c2, 0x57b1: 0x00c2, 0x57b2: 0x00c2, 0x57b3: 0x00c2, 0x57b4: 0x00c2, 0x57b5: 0x00c2,
+	0x57b6: 0x00c2, 0x57b7: 0x00c2, 0x57b8: 0x00c2, 0x57b9: 0x00c2, 0x57ba: 0x00c2, 0x57bb: 0x00c2,
+	0x57bc: 0x00c2, 0x57bd: 0x00c2, 0x57be: 0x00c2, 0x57bf: 0x00c2,
+	// Block 0x15f, offset 0x57c0
+	0x57c0: 0x00c2, 0x57c1: 0x00c2, 0x57c2: 0x00c2, 0x57c3: 0x00c2, 0x57c4: 0x00c3, 0x57c5: 0x00c3,
+	0x57c6: 0x00c3, 0x57c7: 0x00c3, 0x57c8: 0x00c3, 0x57c9: 0x00c3, 0x57ca: 0x00c3, 0x57cb: 0x00c3,
+	0x57d0: 0x00c0, 0x57d1: 0x00c0,
+	0x57d2: 0x00c0, 0x57d3: 0x00c0, 0x57d4: 0x00c0, 0x57d5: 0x00c0, 0x57d6: 0x00c0, 0x57d7: 0x00c0,
+	0x57d8: 0x00c0, 0x57d9: 0x00c0,
+	0x57de: 0x0080, 0x57df: 0x0080,
+	// Block 0x160, offset 0x5800
+	0x5831: 0x0080, 0x5832: 0x0080, 0x5833: 0x0080, 0x5834: 0x0080, 0x5835: 0x0080,
+	0x5836: 0x0080, 0x5837: 0x0080, 0x5838: 0x0080, 0x5839: 0x0080, 0x583a: 0x0080, 0x583b: 0x0080,
+	0x583c: 0x0080, 0x583d: 0x0080, 0x583e: 0x0080, 0x583f: 0x0080,
+	// Block 0x161, offset 0x5840
+	0x5840: 0x0080, 0x5841: 0x0080, 0x5842: 0x0080, 0x5843: 0x0080, 0x5844: 0x0080, 0x5845: 0x0080,
+	0x5846: 0x0080, 0x5847: 0x0080, 0x5848: 0x0080, 0x5849: 0x0080, 0x584a: 0x0080, 0x584b: 0x0080,
+	0x584c: 0x0080, 0x584d: 0x0080, 0x584e: 0x0080, 0x584f: 0x0080, 0x5850: 0x0080, 0x5851: 0x0080,
+	0x5852: 0x0080, 0x5853: 0x0080, 0x5854: 0x0080, 0x5855: 0x0080, 0x5856: 0x0080, 0x5857: 0x0080,
+	0x5858: 0x0080, 0x5859: 0x0080, 0x585a: 0x0080, 0x585b: 0x0080, 0x585c: 0x0080, 0x585d: 0x0080,
+	0x585e: 0x0080, 0x585f: 0x0080, 0x5860: 0x0080, 0x5861: 0x0080, 0x5862: 0x0080, 0x5863: 0x0080,
+	0x5864: 0x0080, 0x5865: 0x0080, 0x5866: 0x0080, 0x5867: 0x0080, 0x5868: 0x0080, 0x5869: 0x0080,
+	0x586a: 0x0080, 0x586b: 0x0080, 0x586c: 0x0080, 0x586d: 0x0080, 0x586e: 0x0080, 0x586f: 0x0080,
+	0x5870: 0x0080, 0x5871: 0x0080, 0x5872: 0x0080, 0x5873: 0x0080, 0x5874: 0x0080,
+	// Block 0x162, offset 0x5880
+	0x5881: 0x0080, 0x5882: 0x0080, 0x5883: 0x0080, 0x5884: 0x0080, 0x5885: 0x0080,
+	0x5886: 0x0080, 0x5887: 0x0080, 0x5888: 0x0080, 0x5889: 0x0080, 0x588a: 0x0080, 0x588b: 0x0080,
+	0x588c: 0x0080, 0x588d: 0x0080, 0x588e: 0x0080, 0x588f: 0x0080, 0x5890: 0x0080, 0x5891: 0x0080,
+	0x5892: 0x0080, 0x5893: 0x0080, 0x5894: 0x0080, 0x5895: 0x0080, 0x5896: 0x0080, 0x5897: 0x0080,
+	0x5898: 0x0080, 0x5899: 0x0080, 0x589a: 0x0080, 0x589b: 0x0080, 0x589c: 0x0080, 0x589d: 0x0080,
+	0x589e: 0x0080, 0x589f: 0x0080, 0x58a0: 0x0080, 0x58a1: 0x0080, 0x58a2: 0x0080, 0x58a3: 0x0080,
+	0x58a4: 0x0080, 0x58a5: 0x0080, 0x58a6: 0x0080, 0x58a7: 0x0080, 0x58a8: 0x0080, 0x58a9: 0x0080,
+	0x58aa: 0x0080, 0x58ab: 0x0080, 0x58ac: 0x0080, 0x58ad: 0x0080, 0x58ae: 0x0080, 0x58af: 0x0080,
+	0x58b0: 0x0080, 0x58b1: 0x0080, 0x58b2: 0x0080, 0x58b3: 0x0080, 0x58b4: 0x0080, 0x58b5: 0x0080,
+	0x58b6: 0x0080, 0x58b7: 0x0080, 0x58b8: 0x0080, 0x58b9: 0x0080, 0x58ba: 0x0080, 0x58bb: 0x0080,
+	0x58bc: 0x0080, 0x58bd: 0x0080,
+	// Block 0x163, offset 0x58c0
+	0x58c0: 0x0080, 0x58c1: 0x0080, 0x58c2: 0x0080, 0x58c3: 0x0080, 0x58c5: 0x0080,
+	0x58c6: 0x0080, 0x58c7: 0x0080, 0x58c8: 0x0080, 0x58c9: 0x0080, 0x58ca: 0x0080, 0x58cb: 0x0080,
+	0x58cc: 0x0080, 0x58cd: 0x0080, 0x58ce: 0x0080, 0x58cf: 0x0080, 0x58d0: 0x0080, 0x58d1: 0x0080,
+	0x58d2: 0x0080, 0x58d3: 0x0080, 0x58d4: 0x0080, 0x58d5: 0x0080, 0x58d6: 0x0080, 0x58d7: 0x0080,
+	0x58d8: 0x0080, 0x58d9: 0x0080, 0x58da: 0x0080, 0x58db: 0x0080, 0x58dc: 0x0080, 0x58dd: 0x0080,
+	0x58de: 0x0080, 0x58df: 0x0080, 0x58e1: 0x0080, 0x58e2: 0x0080,
+	0x58e4: 0x0080, 0x58e7: 0x0080, 0x58e9: 0x0080,
+	0x58ea: 0x0080, 0x58eb: 0x0080, 0x58ec: 0x0080, 0x58ed: 0x0080, 0x58ee: 0x0080, 0x58ef: 0x0080,
+	0x58f0: 0x0080, 0x58f1: 0x0080, 0x58f2: 0x0080, 0x58f4: 0x0080, 0x58f5: 0x0080,
+	0x58f6: 0x0080, 0x58f7: 0x0080, 0x58f9: 0x0080, 0x58fb: 0x0080,
+	// Block 0x164, offset 0x5900
+	0x5902: 0x0080,
+	0x5907: 0x0080, 0x5909: 0x0080, 0x590b: 0x0080,
+	0x590d: 0x0080, 0x590e: 0x0080, 0x590f: 0x0080, 0x5911: 0x0080,
+	0x5912: 0x0080, 0x5914: 0x0080, 0x5917: 0x0080,
+	0x5919: 0x0080, 0x591b: 0x0080, 0x591d: 0x0080,
+	0x591f: 0x0080, 0x5921: 0x0080, 0x5922: 0x0080,
+	0x5924: 0x0080, 0x5927: 0x0080, 0x5928: 0x0080, 0x5929: 0x0080,
+	0x592a: 0x0080, 0x592c: 0x0080, 0x592d: 0x0080, 0x592e: 0x0080, 0x592f: 0x0080,
+	0x5930: 0x0080, 0x5931: 0x0080, 0x5932: 0x0080, 0x5934: 0x0080, 0x5935: 0x0080,
+	0x5936: 0x0080, 0x5937: 0x0080, 0x5939: 0x0080, 0x593a: 0x0080, 0x593b: 0x0080,
+	0x593c: 0x0080, 0x593e: 0x0080,
+	// Block 0x165, offset 0x5940
+	0x5940: 0x0080, 0x5941: 0x0080, 0x5942: 0x0080, 0x5943: 0x0080, 0x5944: 0x0080, 0x5945: 0x0080,
+	0x5946: 0x0080, 0x5947: 0x0080, 0x5948: 0x0080, 0x5949: 0x0080, 0x594b: 0x0080,
+	0x594c: 0x0080, 0x594d: 0x0080, 0x594e: 0x0080, 0x594f: 0x0080, 0x5950: 0x0080, 0x5951: 0x0080,
+	0x5952: 0x0080, 0x5953: 0x0080, 0x5954: 0x0080, 0x5955: 0x0080, 0x5956: 0x0080, 0x5957: 0x0080,
+	0x5958: 0x0080, 0x5959: 0x0080, 0x595a: 0x0080, 0x595b: 0x0080,
+	0x5961: 0x0080, 0x5962: 0x0080, 0x5963: 0x0080,
+	0x5965: 0x0080, 0x5966: 0x0080, 0x5967: 0x0080, 0x5968: 0x0080, 0x5969: 0x0080,
+	0x596b: 0x0080, 0x596c: 0x0080, 0x596d: 0x0080, 0x596e: 0x0080, 0x596f: 0x0080,
+	0x5970: 0x0080, 0x5971: 0x0080, 0x5972: 0x0080, 0x5973: 0x0080, 0x5974: 0x0080, 0x5975: 0x0080,
+	0x5976: 0x0080, 0x5977: 0x0080, 0x5978: 0x0080, 0x5979: 0x0080, 0x597a: 0x0080, 0x597b: 0x0080,
+	// Block 0x166, offset 0x5980
+	0x59b0: 0x0080, 0x59b1: 0x0080,
+	// Block 0x167, offset 0x59c0
+	0x59c0: 0x0080, 0x59c1: 0x0080, 0x59c2: 0x0080, 0x59c3: 0x0080, 0x59c4: 0x0080, 0x59c5: 0x0080,
+	0x59c6: 0x0080, 0x59c7: 0x0080, 0x59c8: 0x0080, 0x59c9: 0x0080, 0x59ca: 0x0080, 0x59cb: 0x0080,
+	0x59cc: 0x0080, 0x59cd: 0x0080, 0x59ce: 0x0080, 0x59cf: 0x0080, 0x59d0: 0x0080, 0x59d1: 0x0080,
+	0x59d2: 0x0080, 0x59d3: 0x0080, 0x59d4: 0x0080, 0x59d5: 0x0080, 0x59d6: 0x0080, 0x59d7: 0x0080,
+	0x59d8: 0x0080, 0x59d9: 0x0080, 0x59da: 0x0080, 0x59db: 0x0080, 0x59dc: 0x0080, 0x59dd: 0x0080,
+	0x59de: 0x0080, 0x59df: 0x0080, 0x59e0: 0x0080, 0x59e1: 0x0080, 0x59e2: 0x0080, 0x59e3: 0x0080,
+	0x59e4: 0x0080, 0x59e5: 0x0080, 0x59e6: 0x0080, 0x59e7: 0x0080, 0x59e8: 0x0080, 0x59e9: 0x0080,
+	0x59ea: 0x0080, 0x59eb: 0x0080,
+	0x59f0: 0x0080, 0x59f1: 0x0080, 0x59f2: 0x0080, 0x59f3: 0x0080, 0x59f4: 0x0080, 0x59f5: 0x0080,
+	0x59f6: 0x0080, 0x59f7: 0x0080, 0x59f8: 0x0080, 0x59f9: 0x0080, 0x59fa: 0x0080, 0x59fb: 0x0080,
+	0x59fc: 0x0080, 0x59fd: 0x0080, 0x59fe: 0x0080, 0x59ff: 0x0080,
+	// Block 0x168, offset 0x5a00
+	0x5a00: 0x0080, 0x5a01: 0x0080, 0x5a02: 0x0080, 0x5a03: 0x0080, 0x5a04: 0x0080, 0x5a05: 0x0080,
+	0x5a06: 0x0080, 0x5a07: 0x0080, 0x5a08: 0x0080, 0x5a09: 0x0080, 0x5a0a: 0x0080, 0x5a0b: 0x0080,
+	0x5a0c: 0x0080, 0x5a0d: 0x0080, 0x5a0e: 0x0080, 0x5a0f: 0x0080, 0x5a10: 0x0080, 0x5a11: 0x0080,
+	0x5a12: 0x0080, 0x5a13: 0x0080,
+	0x5a20: 0x0080, 0x5a21: 0x0080, 0x5a22: 0x0080, 0x5a23: 0x0080,
+	0x5a24: 0x0080, 0x5a25: 0x0080, 0x5a26: 0x0080, 0x5a27: 0x0080, 0x5a28: 0x0080, 0x5a29: 0x0080,
+	0x5a2a: 0x0080, 0x5a2b: 0x0080, 0x5a2c: 0x0080, 0x5a2d: 0x0080, 0x5a2e: 0x0080,
+	0x5a31: 0x0080, 0x5a32: 0x0080, 0x5a33: 0x0080, 0x5a34: 0x0080, 0x5a35: 0x0080,
+	0x5a36: 0x0080, 0x5a37: 0x0080, 0x5a38: 0x0080, 0x5a39: 0x0080, 0x5a3a: 0x0080, 0x5a3b: 0x0080,
+	0x5a3c: 0x0080, 0x5a3d: 0x0080, 0x5a3e: 0x0080, 0x5a3f: 0x0080,
+	// Block 0x169, offset 0x5a40
+	0x5a41: 0x0080, 0x5a42: 0x0080, 0x5a43: 0x0080, 0x5a44: 0x0080, 0x5a45: 0x0080,
+	0x5a46: 0x0080, 0x5a47: 0x0080, 0x5a48: 0x0080, 0x5a49: 0x0080, 0x5a4a: 0x0080, 0x5a4b: 0x0080,
+	0x5a4c: 0x0080, 0x5a4d: 0x0080, 0x5a4e: 0x0080, 0x5a4f: 0x0080, 0x5a51: 0x0080,
+	0x5a52: 0x0080, 0x5a53: 0x0080, 0x5a54: 0x0080, 0x5a55: 0x0080, 0x5a56: 0x0080, 0x5a57: 0x0080,
+	0x5a58: 0x0080, 0x5a59: 0x0080, 0x5a5a: 0x0080, 0x5a5b: 0x0080, 0x5a5c: 0x0080, 0x5a5d: 0x0080,
+	0x5a5e: 0x0080, 0x5a5f: 0x0080, 0x5a60: 0x0080, 0x5a61: 0x0080, 0x5a62: 0x0080, 0x5a63: 0x0080,
+	0x5a64: 0x0080, 0x5a65: 0x0080, 0x5a66: 0x0080, 0x5a67: 0x0080, 0x5a68: 0x0080, 0x5a69: 0x0080,
+	0x5a6a: 0x0080, 0x5a6b: 0x0080, 0x5a6c: 0x0080, 0x5a6d: 0x0080, 0x5a6e: 0x0080, 0x5a6f: 0x0080,
+	0x5a70: 0x0080, 0x5a71: 0x0080, 0x5a72: 0x0080, 0x5a73: 0x0080, 0x5a74: 0x0080, 0x5a75: 0x0080,
+	// Block 0x16a, offset 0x5a80
+	0x5aa6: 0x0080, 0x5aa7: 0x0080, 0x5aa8: 0x0080, 0x5aa9: 0x0080,
+	0x5aaa: 0x0080, 0x5aab: 0x0080, 0x5aac: 0x0080, 0x5aad: 0x0080, 0x5aae: 0x0080, 0x5aaf: 0x0080,
+	0x5ab0: 0x0080, 0x5ab1: 0x0080, 0x5ab2: 0x0080, 0x5ab3: 0x0080, 0x5ab4: 0x0080, 0x5ab5: 0x0080,
+	0x5ab6: 0x0080, 0x5ab7: 0x0080, 0x5ab8: 0x0080, 0x5ab9: 0x0080, 0x5aba: 0x0080, 0x5abb: 0x0080,
+	0x5abc: 0x0080, 0x5abd: 0x0080, 0x5abe: 0x0080, 0x5abf: 0x0080,
+	// Block 0x16b, offset 0x5ac0
+	0x5ac0: 0x008c, 0x5ac1: 0x0080, 0x5ac2: 0x0080,
+	0x5ad0: 0x0080, 0x5ad1: 0x0080,
+	0x5ad2: 0x0080, 0x5ad3: 0x0080, 0x5ad4: 0x0080, 0x5ad5: 0x0080, 0x5ad6: 0x0080, 0x5ad7: 0x0080,
+	0x5ad8: 0x0080, 0x5ad9: 0x0080, 0x5ada: 0x0080, 0x5adb: 0x0080, 0x5adc: 0x0080, 0x5add: 0x0080,
+	0x5ade: 0x0080, 0x5adf: 0x0080, 0x5ae0: 0x0080, 0x5ae1: 0x0080, 0x5ae2: 0x0080, 0x5ae3: 0x0080,
+	0x5ae4: 0x0080, 0x5ae5: 0x0080, 0x5ae6: 0x0080, 0x5ae7: 0x0080, 0x5ae8: 0x0080, 0x5ae9: 0x0080,
+	0x5aea: 0x0080, 0x5aeb: 0x0080, 0x5aec: 0x0080, 0x5aed: 0x0080, 0x5aee: 0x0080, 0x5aef: 0x0080,
+	0x5af0: 0x0080, 0x5af1: 0x0080, 0x5af2: 0x0080, 0x5af3: 0x0080, 0x5af4: 0x0080, 0x5af5: 0x0080,
+	0x5af6: 0x0080, 0x5af7: 0x0080, 0x5af8: 0x0080, 0x5af9: 0x0080, 0x5afa: 0x0080, 0x5afb: 0x0080,
+	// Block 0x16c, offset 0x5b00
+	0x5b00: 0x0080, 0x5b01: 0x0080, 0x5b02: 0x0080, 0x5b03: 0x0080, 0x5b04: 0x0080, 0x5b05: 0x0080,
+	0x5b06: 0x0080, 0x5b07: 0x0080, 0x5b08: 0x0080,
+	0x5b10: 0x0080, 0x5b11: 0x0080,
+	0x5b20: 0x0080, 0x5b21: 0x0080, 0x5b22: 0x0080, 0x5b23: 0x0080,
+	0x5b24: 0x0080, 0x5b25: 0x0080,
+	// Block 0x16d, offset 0x5b40
+	0x5b40: 0x0080, 0x5b41: 0x0080, 0x5b42: 0x0080, 0x5b43: 0x0080, 0x5b44: 0x0080, 0x5b45: 0x0080,
+	0x5b46: 0x0080, 0x5b47: 0x0080, 0x5b48: 0x0080, 0x5b49: 0x0080, 0x5b4a: 0x0080, 0x5b4b: 0x0080,
+	0x5b4c: 0x0080, 0x5b4d: 0x0080, 0x5b4e: 0x0080, 0x5b4f: 0x0080, 0x5b50: 0x0080, 0x5b51: 0x0080,
+	0x5b52: 0x0080, 0x5b53: 0x0080, 0x5b54: 0x0080, 0x5b55: 0x0080, 0x5b56: 0x0080, 0x5b57: 0x0080,
+	0x5b58: 0x0080, 0x5b5c: 0x0080, 0x5b5d: 0x0080,
+	0x5b5e: 0x0080, 0x5b5f: 0x0080, 0x5b60: 0x0080, 0x5b61: 0x0080, 0x5b62: 0x0080, 0x5b63: 0x0080,
+	0x5b64: 0x0080, 0x5b65: 0x0080, 0x5b66: 0x0080, 0x5b67: 0x0080, 0x5b68: 0x0080, 0x5b69: 0x0080,
+	0x5b6a: 0x0080, 0x5b6b: 0x0080, 0x5b6c: 0x0080,
+	0x5b70: 0x0080, 0x5b71: 0x0080, 0x5b72: 0x0080, 0x5b73: 0x0080, 0x5b74: 0x0080, 0x5b75: 0x0080,
+	0x5b76: 0x0080, 0x5b77: 0x0080, 0x5b78: 0x0080, 0x5b79: 0x0080, 0x5b7a: 0x0080, 0x5b7b: 0x0080,
+	0x5b7c: 0x0080,
+	// Block 0x16e, offset 0x5b80
+	0x5b80: 0x0080, 0x5b81: 0x0080, 0x5b82: 0x0080, 0x5b83: 0x0080, 0x5b84: 0x0080, 0x5b85: 0x0080,
+	0x5b86: 0x0080, 0x5b87: 0x0080, 0x5b88: 0x0080, 0x5b89: 0x0080, 0x5b8a: 0x0080, 0x5b8b: 0x0080,
+	0x5b8c: 0x0080, 0x5b8d: 0x0080, 0x5b8e: 0x0080, 0x5b8f: 0x0080, 0x5b90: 0x0080, 0x5b91: 0x0080,
+	0x5b92: 0x0080, 0x5b93: 0x0080, 0x5b94: 0x0080, 0x5b95: 0x0080, 0x5b96: 0x0080, 0x5b97: 0x0080,
+	0x5b98: 0x0080, 0x5b99: 0x0080,
+	0x5ba0: 0x0080, 0x5ba1: 0x0080, 0x5ba2: 0x0080, 0x5ba3: 0x0080,
+	0x5ba4: 0x0080, 0x5ba5: 0x0080, 0x5ba6: 0x0080, 0x5ba7: 0x0080, 0x5ba8: 0x0080, 0x5ba9: 0x0080,
+	0x5baa: 0x0080, 0x5bab: 0x0080,
+	0x5bb0: 0x0080,
+	// Block 0x16f, offset 0x5bc0
+	0x5bc0: 0x0080, 0x5bc1: 0x0080, 0x5bc2: 0x0080, 0x5bc3: 0x0080, 0x5bc4: 0x0080, 0x5bc5: 0x0080,
+	0x5bc6: 0x0080, 0x5bc7: 0x0080, 0x5bc8: 0x0080, 0x5bc9: 0x0080, 0x5bca: 0x0080, 0x5bcb: 0x0080,
+	0x5bd0: 0x0080, 0x5bd1: 0x0080,
+	0x5bd2: 0x0080, 0x5bd3: 0x0080, 0x5bd4: 0x0080, 0x5bd5: 0x0080, 0x5bd6: 0x0080, 0x5bd7: 0x0080,
+	0x5bd8: 0x0080, 0x5bd9: 0x0080, 0x5bda: 0x0080, 0x5bdb: 0x0080, 0x5bdc: 0x0080, 0x5bdd: 0x0080,
+	0x5bde: 0x0080, 0x5bdf: 0x0080, 0x5be0: 0x0080, 0x5be1: 0x0080, 0x5be2: 0x0080, 0x5be3: 0x0080,
+	0x5be4: 0x0080, 0x5be5: 0x0080, 0x5be6: 0x0080, 0x5be7: 0x0080, 0x5be8: 0x0080, 0x5be9: 0x0080,
+	0x5bea: 0x0080, 0x5beb: 0x0080, 0x5bec: 0x0080, 0x5bed: 0x0080, 0x5bee: 0x0080, 0x5bef: 0x0080,
+	0x5bf0: 0x0080, 0x5bf1: 0x0080, 0x5bf2: 0x0080, 0x5bf3: 0x0080, 0x5bf4: 0x0080, 0x5bf5: 0x0080,
+	0x5bf6: 0x0080, 0x5bf7: 0x0080, 0x5bf8: 0x0080, 0x5bf9: 0x0080, 0x5bfa: 0x0080, 0x5bfb: 0x0080,
+	0x5bfc: 0x0080, 0x5bfd: 0x0080, 0x5bfe: 0x0080, 0x5bff: 0x0080,
+	// Block 0x170, offset 0x5c00
+	0x5c00: 0x0080, 0x5c01: 0x0080, 0x5c02: 0x0080, 0x5c03: 0x0080, 0x5c04: 0x0080, 0x5c05: 0x0080,
+	0x5c06: 0x0080, 0x5c07: 0x0080,
+	0x5c10: 0x0080, 0x5c11: 0x0080,
+	0x5c12: 0x0080, 0x5c13: 0x0080, 0x5c14: 0x0080, 0x5c15: 0x0080, 0x5c16: 0x0080, 0x5c17: 0x0080,
+	0x5c18: 0x0080, 0x5c19: 0x0080,
+	0x5c20: 0x0080, 0x5c21: 0x0080, 0x5c22: 0x0080, 0x5c23: 0x0080,
+	0x5c24: 0x0080, 0x5c25: 0x0080, 0x5c26: 0x0080, 0x5c27: 0x0080, 0x5c28: 0x0080, 0x5c29: 0x0080,
+	0x5c2a: 0x0080, 0x5c2b: 0x0080, 0x5c2c: 0x0080, 0x5c2d: 0x0080, 0x5c2e: 0x0080, 0x5c2f: 0x0080,
+	0x5c30: 0x0080, 0x5c31: 0x0080, 0x5c32: 0x0080, 0x5c33: 0x0080, 0x5c34: 0x0080, 0x5c35: 0x0080,
+	0x5c36: 0x0080, 0x5c37: 0x0080, 0x5c38: 0x0080, 0x5c39: 0x0080, 0x5c3a: 0x0080, 0x5c3b: 0x0080,
+	0x5c3c: 0x0080, 0x5c3d: 0x0080, 0x5c3e: 0x0080, 0x5c3f: 0x0080,
+	// Block 0x171, offset 0x5c40
+	0x5c40: 0x0080, 0x5c41: 0x0080, 0x5c42: 0x0080, 0x5c43: 0x0080, 0x5c44: 0x0080, 0x5c45: 0x0080,
+	0x5c46: 0x0080, 0x5c47: 0x0080,
+	0x5c50: 0x0080, 0x5c51: 0x0080,
+	0x5c52: 0x0080, 0x5c53: 0x0080, 0x5c54: 0x0080, 0x5c55: 0x0080, 0x5c56: 0x0080, 0x5c57: 0x0080,
+	0x5c58: 0x0080, 0x5c59: 0x0080, 0x5c5a: 0x0080, 0x5c5b: 0x0080, 0x5c5c: 0x0080, 0x5c5d: 0x0080,
+	0x5c5e: 0x0080, 0x5c5f: 0x0080, 0x5c60: 0x0080, 0x5c61: 0x0080, 0x5c62: 0x0080, 0x5c63: 0x0080,
+	0x5c64: 0x0080, 0x5c65: 0x0080, 0x5c66: 0x0080, 0x5c67: 0x0080, 0x5c68: 0x0080, 0x5c69: 0x0080,
+	0x5c6a: 0x0080, 0x5c6b: 0x0080, 0x5c6c: 0x0080, 0x5c6d: 0x0080,
+	0x5c70: 0x0080, 0x5c71: 0x0080, 0x5c72: 0x0080, 0x5c73: 0x0080, 0x5c74: 0x0080, 0x5c75: 0x0080,
+	0x5c76: 0x0080, 0x5c77: 0x0080, 0x5c78: 0x0080, 0x5c79: 0x0080, 0x5c7a: 0x0080, 0x5c7b: 0x0080,
+	// Block 0x172, offset 0x5c80
+	0x5c80: 0x0080, 0x5c81: 0x0080,
+	0x5c90: 0x0080, 0x5c91: 0x0080,
+	0x5c92: 0x0080, 0x5c93: 0x0080, 0x5c94: 0x0080, 0x5c95: 0x0080, 0x5c96: 0x0080, 0x5c97: 0x0080,
+	0x5c98: 0x0080,
+	// Block 0x173, offset 0x5cc0
+	0x5cc0: 0x0080, 0x5cc1: 0x0080, 0x5cc2: 0x0080, 0x5cc3: 0x0080, 0x5cc4: 0x0080, 0x5cc5: 0x0080,
+	0x5cc6: 0x0080, 0x5cc7: 0x0080, 0x5cc8: 0x0080, 0x5cc9: 0x0080, 0x5cca: 0x0080, 0x5ccb: 0x0080,
+	0x5ccc: 0x0080, 0x5ccd: 0x0080, 0x5cce: 0x0080, 0x5ccf: 0x0080, 0x5cd0: 0x0080, 0x5cd1: 0x0080,
+	0x5cd2: 0x0080, 0x5cd3: 0x0080, 0x5cd4: 0x0080, 0x5cd5: 0x0080, 0x5cd6: 0x0080, 0x5cd7: 0x0080,
+	0x5ce0: 0x0080, 0x5ce1: 0x0080, 0x5ce2: 0x0080, 0x5ce3: 0x0080,
+	0x5ce4: 0x0080, 0x5ce5: 0x0080, 0x5ce6: 0x0080, 0x5ce7: 0x0080, 0x5ce8: 0x0080, 0x5ce9: 0x0080,
+	0x5cea: 0x0080, 0x5ceb: 0x0080, 0x5cec: 0x0080, 0x5ced: 0x0080,
+	0x5cf0: 0x0080, 0x5cf1: 0x0080, 0x5cf2: 0x0080, 0x5cf3: 0x0080, 0x5cf4: 0x0080, 0x5cf5: 0x0080,
+	0x5cf6: 0x0080, 0x5cf7: 0x0080, 0x5cf8: 0x0080, 0x5cf9: 0x0080, 0x5cfa: 0x0080, 0x5cfb: 0x0080,
+	0x5cfc: 0x0080,
+	// Block 0x174, offset 0x5d00
+	0x5d00: 0x0080, 0x5d01: 0x0080, 0x5d02: 0x0080, 0x5d03: 0x0080, 0x5d04: 0x0080, 0x5d05: 0x0080,
+	0x5d06: 0x0080, 0x5d07: 0x0080, 0x5d08: 0x0080, 0x5d09: 0x0080, 0x5d0a: 0x0080,
+	0x5d0e: 0x0080, 0x5d0f: 0x0080, 0x5d10: 0x0080, 0x5d11: 0x0080,
+	0x5d12: 0x0080, 0x5d13: 0x0080, 0x5d14: 0x0080, 0x5d15: 0x0080, 0x5d16: 0x0080, 0x5d17: 0x0080,
+	0x5d18: 0x0080, 0x5d19: 0x0080, 0x5d1a: 0x0080, 0x5d1b: 0x0080, 0x5d1c: 0x0080, 0x5d1d: 0x0080,
+	0x5d1e: 0x0080, 0x5d1f: 0x0080, 0x5d20: 0x0080, 0x5d21: 0x0080, 0x5d22: 0x0080, 0x5d23: 0x0080,
+	0x5d24: 0x0080, 0x5d25: 0x0080, 0x5d26: 0x0080, 0x5d27: 0x0080, 0x5d28: 0x0080, 0x5d29: 0x0080,
+	0x5d2a: 0x0080, 0x5d2b: 0x0080, 0x5d2c: 0x0080, 0x5d2d: 0x0080, 0x5d2e: 0x0080, 0x5d2f: 0x0080,
+	0x5d30: 0x0080, 0x5d31: 0x0080, 0x5d32: 0x0080, 0x5d33: 0x0080, 0x5d34: 0x0080, 0x5d35: 0x0080,
+	0x5d36: 0x0080, 0x5d37: 0x0080, 0x5d38: 0x0080, 0x5d39: 0x0080, 0x5d3a: 0x0080, 0x5d3b: 0x0080,
+	0x5d3c: 0x0080, 0x5d3d: 0x0080, 0x5d3e: 0x0080, 0x5d3f: 0x0080,
+	// Block 0x175, offset 0x5d40
+	0x5d40: 0x0080, 0x5d41: 0x0080, 0x5d42: 0x0080, 0x5d43: 0x0080, 0x5d44: 0x0080, 0x5d45: 0x0080,
+	0x5d46: 0x0080, 0x5d48: 0x0080,
+	0x5d4d: 0x0080, 0x5d4e: 0x0080, 0x5d4f: 0x0080, 0x5d50: 0x0080, 0x5d51: 0x0080,
+	0x5d52: 0x0080, 0x5d53: 0x0080, 0x5d54: 0x0080, 0x5d55: 0x0080, 0x5d56: 0x0080, 0x5d57: 0x0080,
+	0x5d58: 0x0080, 0x5d59: 0x0080, 0x5d5a: 0x0080, 0x5d5b: 0x0080, 0x5d5c: 0x0080,
+	0x5d5f: 0x0080, 0x5d60: 0x0080, 0x5d61: 0x0080, 0x5d62: 0x0080, 0x5d63: 0x0080,
+	0x5d64: 0x0080, 0x5d65: 0x0080, 0x5d66: 0x0080, 0x5d67: 0x0080, 0x5d68: 0x0080, 0x5d69: 0x0080,
+	0x5d6a: 0x0080, 0x5d6f: 0x0080,
+	0x5d70: 0x0080, 0x5d71: 0x0080, 0x5d72: 0x0080, 0x5d73: 0x0080, 0x5d74: 0x0080, 0x5d75: 0x0080,
+	0x5d76: 0x0080, 0x5d77: 0x0080, 0x5d78: 0x0080,
+	// Block 0x176, offset 0x5d80
+	0x5d80: 0x0080, 0x5d81: 0x0080, 0x5d82: 0x0080, 0x5d83: 0x0080, 0x5d84: 0x0080, 0x5d85: 0x0080,
+	0x5d86: 0x0080, 0x5d87: 0x0080, 0x5d88: 0x0080, 0x5d89: 0x0080, 0x5d8a: 0x0080, 0x5d8b: 0x0080,
+	0x5d8c: 0x0080, 0x5d8d: 0x0080, 0x5d8e: 0x0080, 0x5d8f: 0x0080, 0x5d90: 0x0080, 0x5d91: 0x0080,
+	0x5d92: 0x0080, 0x5d94: 0x0080, 0x5d95: 0x0080, 0x5d96: 0x0080, 0x5d97: 0x0080,
+	0x5d98: 0x0080, 0x5d99: 0x0080, 0x5d9a: 0x0080, 0x5d9b: 0x0080, 0x5d9c: 0x0080, 0x5d9d: 0x0080,
+	0x5d9e: 0x0080, 0x5d9f: 0x0080, 0x5da0: 0x0080, 0x5da1: 0x0080, 0x5da2: 0x0080, 0x5da3: 0x0080,
+	0x5da4: 0x0080, 0x5da5: 0x0080, 0x5da6: 0x0080, 0x5da7: 0x0080, 0x5da8: 0x0080, 0x5da9: 0x0080,
+	0x5daa: 0x0080, 0x5dab: 0x0080, 0x5dac: 0x0080, 0x5dad: 0x0080, 0x5dae: 0x0080, 0x5daf: 0x0080,
+	0x5db0: 0x0080, 0x5db1: 0x0080, 0x5db2: 0x0080, 0x5db3: 0x0080, 0x5db4: 0x0080, 0x5db5: 0x0080,
+	0x5db6: 0x0080, 0x5db7: 0x0080, 0x5db8: 0x0080, 0x5db9: 0x0080, 0x5dba: 0x0080, 0x5dbb: 0x0080,
+	0x5dbc: 0x0080, 0x5dbd: 0x0080, 0x5dbe: 0x0080, 0x5dbf: 0x0080,
+	// Block 0x177, offset 0x5dc0
+	0x5dc0: 0x0080, 0x5dc1: 0x0080, 0x5dc2: 0x0080, 0x5dc3: 0x0080, 0x5dc4: 0x0080, 0x5dc5: 0x0080,
+	0x5dc6: 0x0080, 0x5dc7: 0x0080, 0x5dc8: 0x0080, 0x5dc9: 0x0080, 0x5dca: 0x0080, 0x5dcb: 0x0080,
+	0x5dcc: 0x0080, 0x5dcd: 0x0080, 0x5dce: 0x0080, 0x5dcf: 0x0080, 0x5dd0: 0x0080, 0x5dd1: 0x0080,
+	0x5dd2: 0x0080, 0x5dd3: 0x0080, 0x5dd4: 0x0080, 0x5dd5: 0x0080, 0x5dd6: 0x0080, 0x5dd7: 0x0080,
+	0x5dd8: 0x0080, 0x5dd9: 0x0080, 0x5dda: 0x0080, 0x5ddb: 0x0080, 0x5ddc: 0x0080, 0x5ddd: 0x0080,
+	0x5dde: 0x0080, 0x5ddf: 0x0080, 0x5de0: 0x0080, 0x5de1: 0x0080, 0x5de2: 0x0080, 0x5de3: 0x0080,
+	0x5de4: 0x0080, 0x5de5: 0x0080, 0x5de6: 0x0080, 0x5de7: 0x0080, 0x5de8: 0x0080, 0x5de9: 0x0080,
+	0x5dea: 0x0080, 0x5deb: 0x0080, 0x5dec: 0x0080, 0x5ded: 0x0080, 0x5dee: 0x0080, 0x5def: 0x0080,
+	0x5df0: 0x0080, 0x5df1: 0x0080, 0x5df2: 0x0080, 0x5df3: 0x0080, 0x5df4: 0x0080, 0x5df5: 0x0080,
+	0x5df6: 0x0080, 0x5df7: 0x0080, 0x5df8: 0x0080, 0x5df9: 0x0080, 0x5dfa: 0x0080,
+	// Block 0x178, offset 0x5e00
+	0x5e00: 0x00cc, 0x5e01: 0x00cc, 0x5e02: 0x00cc, 0x5e03: 0x00cc, 0x5e04: 0x00cc, 0x5e05: 0x00cc,
+	0x5e06: 0x00cc, 0x5e07: 0x00cc, 0x5e08: 0x00cc, 0x5e09: 0x00cc, 0x5e0a: 0x00cc, 0x5e0b: 0x00cc,
+	0x5e0c: 0x00cc, 0x5e0d: 0x00cc, 0x5e0e: 0x00cc, 0x5e0f: 0x00cc, 0x5e10: 0x00cc, 0x5e11: 0x00cc,
+	0x5e12: 0x00cc, 0x5e13: 0x00cc, 0x5e14: 0x00cc, 0x5e15: 0x00cc, 0x5e16: 0x00cc, 0x5e17: 0x00cc,
+	0x5e18: 0x00cc, 0x5e19: 0x00cc, 0x5e1a: 0x00cc, 0x5e1b: 0x00cc, 0x5e1c: 0x00cc, 0x5e1d: 0x00cc,
+	0x5e1e: 0x00cc, 0x5e1f: 0x00cc,
+	// Block 0x179, offset 0x5e40
+	0x5e40: 0x00cc, 0x5e41: 0x00cc, 0x5e42: 0x00cc, 0x5e43: 0x00cc, 0x5e44: 0x00cc, 0x5e45: 0x00cc,
+	0x5e46: 0x00cc, 0x5e47: 0x00cc, 0x5e48: 0x00cc, 0x5e49: 0x00cc, 0x5e4a: 0x00cc, 0x5e4b: 0x00cc,
+	0x5e4c: 0x00cc, 0x5e4d: 0x00cc, 0x5e4e: 0x00cc, 0x5e4f: 0x00cc, 0x5e50: 0x00cc, 0x5e51: 0x00cc,
+	0x5e52: 0x00cc, 0x5e53: 0x00cc, 0x5e54: 0x00cc, 0x5e55: 0x00cc, 0x5e56: 0x00cc, 0x5e57: 0x00cc,
+	0x5e58: 0x00cc, 0x5e59: 0x00cc, 0x5e5a: 0x00cc, 0x5e5b: 0x00cc, 0x5e5c: 0x00cc, 0x5e5d: 0x00cc,
+	0x5e60: 0x00cc, 0x5e61: 0x00cc, 0x5e62: 0x00cc, 0x5e63: 0x00cc,
+	0x5e64: 0x00cc, 0x5e65: 0x00cc, 0x5e66: 0x00cc, 0x5e67: 0x00cc, 0x5e68: 0x00cc, 0x5e69: 0x00cc,
+	0x5e6a: 0x00cc, 0x5e6b: 0x00cc, 0x5e6c: 0x00cc, 0x5e6d: 0x00cc, 0x5e6e: 0x00cc, 0x5e6f: 0x00cc,
+	0x5e70: 0x00cc, 0x5e71: 0x00cc, 0x5e72: 0x00cc, 0x5e73: 0x00cc, 0x5e74: 0x00cc, 0x5e75: 0x00cc,
+	0x5e76: 0x00cc, 0x5e77: 0x00cc, 0x5e78: 0x00cc, 0x5e79: 0x00cc, 0x5e7a: 0x00cc, 0x5e7b: 0x00cc,
+	0x5e7c: 0x00cc, 0x5e7d: 0x00cc, 0x5e7e: 0x00cc, 0x5e7f: 0x00cc,
+	// Block 0x17a, offset 0x5e80
+	0x5e80: 0x00cc, 0x5e81: 0x00cc, 0x5e82: 0x00cc, 0x5e83: 0x00cc, 0x5e84: 0x00cc, 0x5e85: 0x00cc,
+	0x5e86: 0x00cc, 0x5e87: 0x00cc, 0x5e88: 0x00cc, 0x5e89: 0x00cc, 0x5e8a: 0x00cc, 0x5e8b: 0x00cc,
+	0x5e8c: 0x00cc, 0x5e8d: 0x00cc, 0x5e8e: 0x00cc, 0x5e8f: 0x00cc, 0x5e90: 0x00cc, 0x5e91: 0x00cc,
+	0x5e92: 0x00cc, 0x5e93: 0x00cc, 0x5e94: 0x00cc, 0x5e95: 0x00cc, 0x5e96: 0x00cc, 0x5e97: 0x00cc,
+	0x5e98: 0x00cc, 0x5e99: 0x00cc, 0x5e9a: 0x00cc, 0x5e9b: 0x00cc, 0x5e9c: 0x00cc, 0x5e9d: 0x00cc,
+	0x5e9e: 0x00cc, 0x5e9f: 0x00cc, 0x5ea0: 0x00cc, 0x5ea1: 0x00cc, 0x5ea2: 0x00cc, 0x5ea3: 0x00cc,
+	0x5ea4: 0x00cc, 0x5ea5: 0x00cc, 0x5ea6: 0x00cc, 0x5ea7: 0x00cc, 0x5ea8: 0x00cc, 0x5ea9: 0x00cc,
+	0x5eaa: 0x00cc, 0x5eab: 0x00cc, 0x5eac: 0x00cc, 0x5ead: 0x00cc,
+	0x5eb0: 0x00cc, 0x5eb1: 0x00cc, 0x5eb2: 0x00cc, 0x5eb3: 0x00cc, 0x5eb4: 0x00cc, 0x5eb5: 0x00cc,
+	0x5eb6: 0x00cc, 0x5eb7: 0x00cc, 0x5eb8: 0x00cc, 0x5eb9: 0x00cc, 0x5eba: 0x00cc, 0x5ebb: 0x00cc,
+	0x5ebc: 0x00cc, 0x5ebd: 0x00cc, 0x5ebe: 0x00cc, 0x5ebf: 0x00cc,
+	// Block 0x17b, offset 0x5ec0
+	0x5ec0: 0x00cc, 0x5ec1: 0x00cc, 0x5ec2: 0x00cc, 0x5ec3: 0x00cc, 0x5ec4: 0x00cc, 0x5ec5: 0x00cc,
+	0x5ec6: 0x00cc, 0x5ec7: 0x00cc, 0x5ec8: 0x00cc, 0x5ec9: 0x00cc, 0x5eca: 0x00cc, 0x5ecb: 0x00cc,
+	0x5ecc: 0x00cc, 0x5ecd: 0x00cc, 0x5ece: 0x00cc, 0x5ecf: 0x00cc, 0x5ed0: 0x00cc, 0x5ed1: 0x00cc,
+	0x5ed2: 0x00cc, 0x5ed3: 0x00cc, 0x5ed4: 0x00cc, 0x5ed5: 0x00cc, 0x5ed6: 0x00cc, 0x5ed7: 0x00cc,
+	0x5ed8: 0x00cc, 0x5ed9: 0x00cc, 0x5eda: 0x00cc, 0x5edb: 0x00cc, 0x5edc: 0x00cc, 0x5edd: 0x00cc,
+	0x5ede: 0x00cc, 0x5edf: 0x00cc, 0x5ee0: 0x00cc,
+	0x5ef0: 0x00cc, 0x5ef1: 0x00cc, 0x5ef2: 0x00cc, 0x5ef3: 0x00cc, 0x5ef4: 0x00cc, 0x5ef5: 0x00cc,
+	0x5ef6: 0x00cc, 0x5ef7: 0x00cc, 0x5ef8: 0x00cc, 0x5ef9: 0x00cc, 0x5efa: 0x00cc, 0x5efb: 0x00cc,
+	0x5efc: 0x00cc, 0x5efd: 0x00cc, 0x5efe: 0x00cc, 0x5eff: 0x00cc,
+	// Block 0x17c, offset 0x5f00
+	0x5f00: 0x00cc, 0x5f01: 0x00cc, 0x5f02: 0x00cc, 0x5f03: 0x00cc, 0x5f04: 0x00cc, 0x5f05: 0x00cc,
+	0x5f06: 0x00cc, 0x5f07: 0x00cc, 0x5f08: 0x00cc, 0x5f09: 0x00cc, 0x5f0a: 0x00cc, 0x5f0b: 0x00cc,
+	0x5f0c: 0x00cc, 0x5f0d: 0x00cc, 0x5f0e: 0x00cc, 0x5f0f: 0x00cc, 0x5f10: 0x00cc, 0x5f11: 0x00cc,
+	0x5f12: 0x00cc, 0x5f13: 0x00cc, 0x5f14: 0x00cc, 0x5f15: 0x00cc, 0x5f16: 0x00cc, 0x5f17: 0x00cc,
+	0x5f18: 0x00cc, 0x5f19: 0x00cc, 0x5f1a: 0x00cc, 0x5f1b: 0x00cc, 0x5f1c: 0x00cc, 0x5f1d: 0x00cc,
+	// Block 0x17d, offset 0x5f40
+	0x5f40: 0x008c, 0x5f41: 0x008c, 0x5f42: 0x008c, 0x5f43: 0x008c, 0x5f44: 0x008c, 0x5f45: 0x008c,
+	0x5f46: 0x008c, 0x5f47: 0x008c, 0x5f48: 0x008c, 0x5f49: 0x008c, 0x5f4a: 0x008c, 0x5f4b: 0x008c,
+	0x5f4c: 0x008c, 0x5f4d: 0x008c, 0x5f4e: 0x008c, 0x5f4f: 0x008c, 0x5f50: 0x008c, 0x5f51: 0x008c,
+	0x5f52: 0x008c, 0x5f53: 0x008c, 0x5f54: 0x008c, 0x5f55: 0x008c, 0x5f56: 0x008c, 0x5f57: 0x008c,
+	0x5f58: 0x008c, 0x5f59: 0x008c, 0x5f5a: 0x008c, 0x5f5b: 0x008c, 0x5f5c: 0x008c, 0x5f5d: 0x008c,
+	// Block 0x17e, offset 0x5f80
+	0x5f80: 0x00cc, 0x5f81: 0x00cc, 0x5f82: 0x00cc, 0x5f83: 0x00cc, 0x5f84: 0x00cc, 0x5f85: 0x00cc,
+	0x5f86: 0x00cc, 0x5f87: 0x00cc, 0x5f88: 0x00cc, 0x5f89: 0x00cc, 0x5f8a: 0x00cc,
+	0x5f90: 0x00cc, 0x5f91: 0x00cc,
+	0x5f92: 0x00cc, 0x5f93: 0x00cc, 0x5f94: 0x00cc, 0x5f95: 0x00cc, 0x5f96: 0x00cc, 0x5f97: 0x00cc,
+	0x5f98: 0x00cc, 0x5f99: 0x00cc, 0x5f9a: 0x00cc, 0x5f9b: 0x00cc, 0x5f9c: 0x00cc, 0x5f9d: 0x00cc,
+	0x5f9e: 0x00cc, 0x5f9f: 0x00cc, 0x5fa0: 0x00cc, 0x5fa1: 0x00cc, 0x5fa2: 0x00cc, 0x5fa3: 0x00cc,
+	0x5fa4: 0x00cc, 0x5fa5: 0x00cc, 0x5fa6: 0x00cc, 0x5fa7: 0x00cc, 0x5fa8: 0x00cc, 0x5fa9: 0x00cc,
+	0x5faa: 0x00cc, 0x5fab: 0x00cc, 0x5fac: 0x00cc, 0x5fad: 0x00cc, 0x5fae: 0x00cc, 0x5faf: 0x00cc,
+	0x5fb0: 0x00cc, 0x5fb1: 0x00cc, 0x5fb2: 0x00cc, 0x5fb3: 0x00cc, 0x5fb4: 0x00cc, 0x5fb5: 0x00cc,
+	0x5fb6: 0x00cc, 0x5fb7: 0x00cc, 0x5fb8: 0x00cc, 0x5fb9: 0x00cc, 0x5fba: 0x00cc, 0x5fbb: 0x00cc,
+	0x5fbc: 0x00cc, 0x5fbd: 0x00cc, 0x5fbe: 0x00cc, 0x5fbf: 0x00cc,
+	// Block 0x17f, offset 0x5fc0
+	0x5fc0: 0x00cc, 0x5fc1: 0x00cc, 0x5fc2: 0x00cc, 0x5fc3: 0x00cc, 0x5fc4: 0x00cc, 0x5fc5: 0x00cc,
+	0x5fc6: 0x00cc, 0x5fc7: 0x00cc, 0x5fc8: 0x00cc, 0x5fc9: 0x00cc, 0x5fca: 0x00cc, 0x5fcb: 0x00cc,
+	0x5fcc: 0x00cc, 0x5fcd: 0x00cc, 0x5fce: 0x00cc, 0x5fcf: 0x00cc, 0x5fd0: 0x00cc, 0x5fd1: 0x00cc,
+	0x5fd2: 0x00cc, 0x5fd3: 0x00cc, 0x5fd4: 0x00cc, 0x5fd5: 0x00cc, 0x5fd6: 0x00cc, 0x5fd7: 0x00cc,
+	0x5fd8: 0x00cc, 0x5fd9: 0x00cc, 0x5fda: 0x00cc, 0x5fdb: 0x00cc, 0x5fdc: 0x00cc, 0x5fdd: 0x00cc,
+	0x5fde: 0x00cc, 0x5fdf: 0x00cc, 0x5fe0: 0x00cc, 0x5fe1: 0x00cc, 0x5fe2: 0x00cc, 0x5fe3: 0x00cc,
+	0x5fe4: 0x00cc, 0x5fe5: 0x00cc, 0x5fe6: 0x00cc, 0x5fe7: 0x00cc, 0x5fe8: 0x00cc, 0x5fe9: 0x00cc,
+	0x5fea: 0x00cc, 0x5feb: 0x00cc, 0x5fec: 0x00cc, 0x5fed: 0x00cc, 0x5fee: 0x00cc, 0x5fef: 0x00cc,
+	0x5ff0: 0x00cc, 0x5ff1: 0x00cc, 0x5ff2: 0x00cc, 0x5ff3: 0x00cc, 0x5ff4: 0x00cc, 0x5ff5: 0x00cc,
+	0x5ff6: 0x00cc, 0x5ff7: 0x00cc, 0x5ff8: 0x00cc, 0x5ff9: 0x00cc,
+	// Block 0x180, offset 0x6000
+	0x6001: 0x0040,
+	0x6020: 0x0040, 0x6021: 0x0040, 0x6022: 0x0040, 0x6023: 0x0040,
+	0x6024: 0x0040, 0x6025: 0x0040, 0x6026: 0x0040, 0x6027: 0x0040, 0x6028: 0x0040, 0x6029: 0x0040,
+	0x602a: 0x0040, 0x602b: 0x0040, 0x602c: 0x0040, 0x602d: 0x0040, 0x602e: 0x0040, 0x602f: 0x0040,
+	0x6030: 0x0040, 0x6031: 0x0040, 0x6032: 0x0040, 0x6033: 0x0040, 0x6034: 0x0040, 0x6035: 0x0040,
+	0x6036: 0x0040, 0x6037: 0x0040, 0x6038: 0x0040, 0x6039: 0x0040, 0x603a: 0x0040, 0x603b: 0x0040,
+	0x603c: 0x0040, 0x603d: 0x0040, 0x603e: 0x0040, 0x603f: 0x0040,
+	// Block 0x181, offset 0x6040
+	0x6040: 0x0040, 0x6041: 0x0040, 0x6042: 0x0040, 0x6043: 0x0040, 0x6044: 0x0040, 0x6045: 0x0040,
+	0x6046: 0x0040, 0x6047: 0x0040, 0x6048: 0x0040, 0x6049: 0x0040, 0x604a: 0x0040, 0x604b: 0x0040,
+	0x604c: 0x0040, 0x604d: 0x0040, 0x604e: 0x0040, 0x604f: 0x0040, 0x6050: 0x0040, 0x6051: 0x0040,
+	0x6052: 0x0040, 0x6053: 0x0040, 0x6054: 0x0040, 0x6055: 0x0040, 0x6056: 0x0040, 0x6057: 0x0040,
+	0x6058: 0x0040, 0x6059: 0x0040, 0x605a: 0x0040, 0x605b: 0x0040, 0x605c: 0x0040, 0x605d: 0x0040,
+	0x605e: 0x0040, 0x605f: 0x0040, 0x6060: 0x0040, 0x6061: 0x0040, 0x6062: 0x0040, 0x6063: 0x0040,
+	0x6064: 0x0040, 0x6065: 0x0040, 0x6066: 0x0040, 0x6067: 0x0040, 0x6068: 0x0040, 0x6069: 0x0040,
+	0x606a: 0x0040, 0x606b: 0x0040, 0x606c: 0x0040, 0x606d: 0x0040, 0x606e: 0x0040, 0x606f: 0x0040,
+	// Block 0x182, offset 0x6080
+	0x6080: 0x0040, 0x6081: 0x0040, 0x6082: 0x0040, 0x6083: 0x0040, 0x6084: 0x0040, 0x6085: 0x0040,
+	0x6086: 0x0040, 0x6087: 0x0040, 0x6088: 0x0040, 0x6089: 0x0040, 0x608a: 0x0040, 0x608b: 0x0040,
+	0x608c: 0x0040, 0x608d: 0x0040, 0x608e: 0x0040, 0x608f: 0x0040, 0x6090: 0x0040, 0x6091: 0x0040,
+	0x6092: 0x0040, 0x6093: 0x0040, 0x6094: 0x0040, 0x6095: 0x0040, 0x6096: 0x0040, 0x6097: 0x0040,
+	0x6098: 0x0040, 0x6099: 0x0040, 0x609a: 0x0040, 0x609b: 0x0040, 0x609c: 0x0040, 0x609d: 0x0040,
+	0x609e: 0x0040, 0x609f: 0x0040, 0x60a0: 0x0040, 0x60a1: 0x0040, 0x60a2: 0x0040, 0x60a3: 0x0040,
+	0x60a4: 0x0040, 0x60a5: 0x0040, 0x60a6: 0x0040, 0x60a7: 0x0040, 0x60a8: 0x0040, 0x60a9: 0x0040,
+	0x60aa: 0x0040, 0x60ab: 0x0040, 0x60ac: 0x0040, 0x60ad: 0x0040, 0x60ae: 0x0040, 0x60af: 0x0040,
+	0x60b0: 0x0040, 0x60b1: 0x0040, 0x60b2: 0x0040, 0x60b3: 0x0040, 0x60b4: 0x0040, 0x60b5: 0x0040,
+	0x60b6: 0x0040, 0x60b7: 0x0040, 0x60b8: 0x0040, 0x60b9: 0x0040, 0x60ba: 0x0040, 0x60bb: 0x0040,
+	0x60bc: 0x0040, 0x60bd: 0x0040,
+}
+
+// derivedPropertiesIndex: 40 blocks, 2560 entries, 5120 bytes
+// Block 0 is the zero block.
+var derivedPropertiesIndex = [2560]uint16{
+	// Block 0x0, offset 0x0
+	// Block 0x1, offset 0x40
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc6: 0x05, 0xc7: 0x06,
+	0xc8: 0x05, 0xc9: 0x05, 0xca: 0x07, 0xcb: 0x08, 0xcc: 0x09, 0xcd: 0x0a, 0xce: 0x0b, 0xcf: 0x0c,
+	0xd0: 0x05, 0xd1: 0x05, 0xd2: 0x0d, 0xd3: 0x05, 0xd4: 0x0e, 0xd5: 0x0f, 0xd6: 0x10, 0xd7: 0x11,
+	0xd8: 0x12, 0xd9: 0x13, 0xda: 0x14, 0xdb: 0x15, 0xdc: 0x16, 0xdd: 0x17, 0xde: 0x18, 0xdf: 0x19,
+	0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x07, 0xe6: 0x07, 0xe7: 0x07,
+	0xe8: 0x07, 0xe9: 0x07, 0xea: 0x08, 0xeb: 0x09, 0xec: 0x09, 0xed: 0x0a, 0xee: 0x0b, 0xef: 0x0c,
+	0xf0: 0x21, 0xf3: 0x24, 0xf4: 0x25,
+	// Block 0x4, offset 0x100
+	0x120: 0x1a, 0x121: 0x1b, 0x122: 0x1c, 0x123: 0x1d, 0x124: 0x1e, 0x125: 0x1f, 0x126: 0x20, 0x127: 0x21,
+	0x128: 0x22, 0x129: 0x23, 0x12a: 0x24, 0x12b: 0x25, 0x12c: 0x26, 0x12d: 0x27, 0x12e: 0x28, 0x12f: 0x29,
+	0x130: 0x2a, 0x131: 0x2b, 0x132: 0x2c, 0x133: 0x2d, 0x134: 0x2e, 0x135: 0x2f, 0x136: 0x30, 0x137: 0x31,
+	0x138: 0x32, 0x139: 0x33, 0x13a: 0x34, 0x13b: 0x35, 0x13c: 0x36, 0x13d: 0x37, 0x13e: 0x38, 0x13f: 0x39,
+	// Block 0x5, offset 0x140
+	0x140: 0x3a, 0x141: 0x3b, 0x142: 0x3c, 0x143: 0x3d, 0x144: 0x3e, 0x145: 0x3e, 0x146: 0x3e, 0x147: 0x3e,
+	0x148: 0x05, 0x149: 0x3f, 0x14a: 0x40, 0x14b: 0x41, 0x14c: 0x42, 0x14d: 0x43, 0x14e: 0x44, 0x14f: 0x45,
+	0x150: 0x46, 0x151: 0x05, 0x152: 0x05, 0x153: 0x05, 0x154: 0x05, 0x155: 0x05, 0x156: 0x05, 0x157: 0x05,
+	0x158: 0x05, 0x159: 0x47, 0x15a: 0x48, 0x15b: 0x49, 0x15c: 0x4a, 0x15d: 0x4b, 0x15e: 0x4c, 0x15f: 0x4d,
+	0x160: 0x4e, 0x161: 0x4f, 0x162: 0x50, 0x163: 0x51, 0x164: 0x52, 0x165: 0x53, 0x166: 0x54, 0x167: 0x55,
+	0x168: 0x56, 0x169: 0x57, 0x16a: 0x58, 0x16b: 0x59, 0x16c: 0x5a, 0x16d: 0x5b, 0x16e: 0x5c, 0x16f: 0x5d,
+	0x170: 0x5e, 0x171: 0x5f, 0x172: 0x60, 0x173: 0x61, 0x174: 0x62, 0x175: 0x63, 0x176: 0x64, 0x177: 0x09,
+	0x178: 0x05, 0x179: 0x05, 0x17a: 0x65, 0x17b: 0x05, 0x17c: 0x66, 0x17d: 0x67, 0x17e: 0x68, 0x17f: 0x69,
+	// Block 0x6, offset 0x180
+	0x180: 0x6a, 0x181: 0x6b, 0x182: 0x6c, 0x183: 0x6d, 0x184: 0x6e, 0x185: 0x6f, 0x186: 0x70, 0x187: 0x71,
+	0x188: 0x71, 0x189: 0x71, 0x18a: 0x71, 0x18b: 0x71, 0x18c: 0x71, 0x18d: 0x71, 0x18e: 0x71, 0x18f: 0x71,
+	0x190: 0x72, 0x191: 0x73, 0x192: 0x71, 0x193: 0x71, 0x194: 0x71, 0x195: 0x71, 0x196: 0x71, 0x197: 0x71,
+	0x198: 0x71, 0x199: 0x71, 0x19a: 0x71, 0x19b: 0x71, 0x19c: 0x71, 0x19d: 0x71, 0x19e: 0x71, 0x19f: 0x71,
+	0x1a0: 0x71, 0x1a1: 0x71, 0x1a2: 0x71, 0x1a3: 0x71, 0x1a4: 0x71, 0x1a5: 0x71, 0x1a6: 0x71, 0x1a7: 0x71,
+	0x1a8: 0x71, 0x1a9: 0x71, 0x1aa: 0x71, 0x1ab: 0x71, 0x1ac: 0x71, 0x1ad: 0x74, 0x1ae: 0x71, 0x1af: 0x71,
+	0x1b0: 0x05, 0x1b1: 0x75, 0x1b2: 0x05, 0x1b3: 0x76, 0x1b4: 0x77, 0x1b5: 0x78, 0x1b6: 0x79, 0x1b7: 0x7a,
+	0x1b8: 0x7b, 0x1b9: 0x7c, 0x1ba: 0x7d, 0x1bb: 0x7e, 0x1bc: 0x7f, 0x1bd: 0x7f, 0x1be: 0x7f, 0x1bf: 0x80,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x81, 0x1c1: 0x82, 0x1c2: 0x83, 0x1c3: 0x84, 0x1c4: 0x85, 0x1c5: 0x86, 0x1c6: 0x87, 0x1c7: 0x88,
+	0x1c8: 0x89, 0x1c9: 0x71, 0x1ca: 0x71, 0x1cb: 0x8a, 0x1cc: 0x7f, 0x1cd: 0x8b, 0x1ce: 0x71, 0x1cf: 0x71,
+	0x1d0: 0x8c, 0x1d1: 0x8c, 0x1d2: 0x8c, 0x1d3: 0x8c, 0x1d4: 0x8c, 0x1d5: 0x8c, 0x1d6: 0x8c, 0x1d7: 0x8c,
+	0x1d8: 0x8c, 0x1d9: 0x8c, 0x1da: 0x8c, 0x1db: 0x8c, 0x1dc: 0x8c, 0x1dd: 0x8c, 0x1de: 0x8c, 0x1df: 0x8c,
+	0x1e0: 0x8c, 0x1e1: 0x8c, 0x1e2: 0x8c, 0x1e3: 0x8c, 0x1e4: 0x8c, 0x1e5: 0x8c, 0x1e6: 0x8c, 0x1e7: 0x8c,
+	0x1e8: 0x8c, 0x1e9: 0x8c, 0x1ea: 0x8c, 0x1eb: 0x8c, 0x1ec: 0x8c, 0x1ed: 0x8c, 0x1ee: 0x8c, 0x1ef: 0x8c,
+	0x1f0: 0x8c, 0x1f1: 0x8c, 0x1f2: 0x8c, 0x1f3: 0x8c, 0x1f4: 0x8c, 0x1f5: 0x8c, 0x1f6: 0x8c, 0x1f7: 0x8c,
+	0x1f8: 0x8c, 0x1f9: 0x8c, 0x1fa: 0x8c, 0x1fb: 0x8c, 0x1fc: 0x8c, 0x1fd: 0x8c, 0x1fe: 0x8c, 0x1ff: 0x8c,
+	// Block 0x8, offset 0x200
+	0x200: 0x8c, 0x201: 0x8c, 0x202: 0x8c, 0x203: 0x8c, 0x204: 0x8c, 0x205: 0x8c, 0x206: 0x8c, 0x207: 0x8c,
+	0x208: 0x8c, 0x209: 0x8c, 0x20a: 0x8c, 0x20b: 0x8c, 0x20c: 0x8c, 0x20d: 0x8c, 0x20e: 0x8c, 0x20f: 0x8c,
+	0x210: 0x8c, 0x211: 0x8c, 0x212: 0x8c, 0x213: 0x8c, 0x214: 0x8c, 0x215: 0x8c, 0x216: 0x8c, 0x217: 0x8c,
+	0x218: 0x8c, 0x219: 0x8c, 0x21a: 0x8c, 0x21b: 0x8c, 0x21c: 0x8c, 0x21d: 0x8c, 0x21e: 0x8c, 0x21f: 0x8c,
+	0x220: 0x8c, 0x221: 0x8c, 0x222: 0x8c, 0x223: 0x8c, 0x224: 0x8c, 0x225: 0x8c, 0x226: 0x8c, 0x227: 0x8c,
+	0x228: 0x8c, 0x229: 0x8c, 0x22a: 0x8c, 0x22b: 0x8c, 0x22c: 0x8c, 0x22d: 0x8c, 0x22e: 0x8c, 0x22f: 0x8c,
+	0x230: 0x8c, 0x231: 0x8c, 0x232: 0x8c, 0x233: 0x8c, 0x234: 0x8c, 0x235: 0x8c, 0x236: 0x8c, 0x237: 0x71,
+	0x238: 0x8c, 0x239: 0x8c, 0x23a: 0x8c, 0x23b: 0x8c, 0x23c: 0x8c, 0x23d: 0x8c, 0x23e: 0x8c, 0x23f: 0x8c,
+	// Block 0x9, offset 0x240
+	0x240: 0x8c, 0x241: 0x8c, 0x242: 0x8c, 0x243: 0x8c, 0x244: 0x8c, 0x245: 0x8c, 0x246: 0x8c, 0x247: 0x8c,
+	0x248: 0x8c, 0x249: 0x8c, 0x24a: 0x8c, 0x24b: 0x8c, 0x24c: 0x8c, 0x24d: 0x8c, 0x24e: 0x8c, 0x24f: 0x8c,
+	0x250: 0x8c, 0x251: 0x8c, 0x252: 0x8c, 0x253: 0x8c, 0x254: 0x8c, 0x255: 0x8c, 0x256: 0x8c, 0x257: 0x8c,
+	0x258: 0x8c, 0x259: 0x8c, 0x25a: 0x8c, 0x25b: 0x8c, 0x25c: 0x8c, 0x25d: 0x8c, 0x25e: 0x8c, 0x25f: 0x8c,
+	0x260: 0x8c, 0x261: 0x8c, 0x262: 0x8c, 0x263: 0x8c, 0x264: 0x8c, 0x265: 0x8c, 0x266: 0x8c, 0x267: 0x8c,
+	0x268: 0x8c, 0x269: 0x8c, 0x26a: 0x8c, 0x26b: 0x8c, 0x26c: 0x8c, 0x26d: 0x8c, 0x26e: 0x8c, 0x26f: 0x8c,
+	0x270: 0x8c, 0x271: 0x8c, 0x272: 0x8c, 0x273: 0x8c, 0x274: 0x8c, 0x275: 0x8c, 0x276: 0x8c, 0x277: 0x8c,
+	0x278: 0x8c, 0x279: 0x8c, 0x27a: 0x8c, 0x27b: 0x8c, 0x27c: 0x8c, 0x27d: 0x8c, 0x27e: 0x8c, 0x27f: 0x8c,
+	// Block 0xa, offset 0x280
+	0x280: 0x05, 0x281: 0x05, 0x282: 0x05, 0x283: 0x05, 0x284: 0x05, 0x285: 0x05, 0x286: 0x05, 0x287: 0x05,
+	0x288: 0x05, 0x289: 0x05, 0x28a: 0x05, 0x28b: 0x05, 0x28c: 0x05, 0x28d: 0x05, 0x28e: 0x05, 0x28f: 0x05,
+	0x290: 0x05, 0x291: 0x05, 0x292: 0x8d, 0x293: 0x8e, 0x294: 0x05, 0x295: 0x05, 0x296: 0x05, 0x297: 0x05,
+	0x298: 0x8f, 0x299: 0x90, 0x29a: 0x91, 0x29b: 0x92, 0x29c: 0x93, 0x29d: 0x94, 0x29e: 0x95, 0x29f: 0x96,
+	0x2a0: 0x97, 0x2a1: 0x98, 0x2a2: 0x05, 0x2a3: 0x99, 0x2a4: 0x9a, 0x2a5: 0x9b, 0x2a6: 0x9c, 0x2a7: 0x9d,
+	0x2a8: 0x9e, 0x2a9: 0x9f, 0x2aa: 0xa0, 0x2ab: 0xa1, 0x2ac: 0xa2, 0x2ad: 0xa3, 0x2ae: 0x05, 0x2af: 0xa4,
+	0x2b0: 0x05, 0x2b1: 0x05, 0x2b2: 0x05, 0x2b3: 0x05, 0x2b4: 0x05, 0x2b5: 0x05, 0x2b6: 0x05, 0x2b7: 0x05,
+	0x2b8: 0x05, 0x2b9: 0x05, 0x2ba: 0x05, 0x2bb: 0x05, 0x2bc: 0x05, 0x2bd: 0x05, 0x2be: 0x05, 0x2bf: 0x05,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x05, 0x2c1: 0x05, 0x2c2: 0x05, 0x2c3: 0x05, 0x2c4: 0x05, 0x2c5: 0x05, 0x2c6: 0x05, 0x2c7: 0x05,
+	0x2c8: 0x05, 0x2c9: 0x05, 0x2ca: 0x05, 0x2cb: 0x05, 0x2cc: 0x05, 0x2cd: 0x05, 0x2ce: 0x05, 0x2cf: 0x05,
+	0x2d0: 0x05, 0x2d1: 0x05, 0x2d2: 0x05, 0x2d3: 0x05, 0x2d4: 0x05, 0x2d5: 0x05, 0x2d6: 0x05, 0x2d7: 0x05,
+	0x2d8: 0x05, 0x2d9: 0x05, 0x2da: 0x05, 0x2db: 0x05, 0x2dc: 0x05, 0x2dd: 0x05, 0x2de: 0x05, 0x2df: 0x05,
+	0x2e0: 0x05, 0x2e1: 0x05, 0x2e2: 0x05, 0x2e3: 0x05, 0x2e4: 0x05, 0x2e5: 0x05, 0x2e6: 0x05, 0x2e7: 0x05,
+	0x2e8: 0x05, 0x2e9: 0x05, 0x2ea: 0x05, 0x2eb: 0x05, 0x2ec: 0x05, 0x2ed: 0x05, 0x2ee: 0x05, 0x2ef: 0x05,
+	0x2f0: 0x05, 0x2f1: 0x05, 0x2f2: 0x05, 0x2f3: 0x05, 0x2f4: 0x05, 0x2f5: 0x05, 0x2f6: 0x05, 0x2f7: 0x05,
+	0x2f8: 0x05, 0x2f9: 0x05, 0x2fa: 0x05, 0x2fb: 0x05, 0x2fc: 0x05, 0x2fd: 0x05, 0x2fe: 0x05, 0x2ff: 0x05,
+	// Block 0xc, offset 0x300
+	0x300: 0x05, 0x301: 0x05, 0x302: 0x05, 0x303: 0x05, 0x304: 0x05, 0x305: 0x05, 0x306: 0x05, 0x307: 0x05,
+	0x308: 0x05, 0x309: 0x05, 0x30a: 0x05, 0x30b: 0x05, 0x30c: 0x05, 0x30d: 0x05, 0x30e: 0x05, 0x30f: 0x05,
+	0x310: 0x05, 0x311: 0x05, 0x312: 0x05, 0x313: 0x05, 0x314: 0x05, 0x315: 0x05, 0x316: 0x05, 0x317: 0x05,
+	0x318: 0x05, 0x319: 0x05, 0x31a: 0x05, 0x31b: 0x05, 0x31c: 0x05, 0x31d: 0x05, 0x31e: 0xa5, 0x31f: 0xa6,
+	// Block 0xd, offset 0x340
+	0x340: 0x3e, 0x341: 0x3e, 0x342: 0x3e, 0x343: 0x3e, 0x344: 0x3e, 0x345: 0x3e, 0x346: 0x3e, 0x347: 0x3e,
+	0x348: 0x3e, 0x349: 0x3e, 0x34a: 0x3e, 0x34b: 0x3e, 0x34c: 0x3e, 0x34d: 0x3e, 0x34e: 0x3e, 0x34f: 0x3e,
+	0x350: 0x3e, 0x351: 0x3e, 0x352: 0x3e, 0x353: 0x3e, 0x354: 0x3e, 0x355: 0x3e, 0x356: 0x3e, 0x357: 0x3e,
+	0x358: 0x3e, 0x359: 0x3e, 0x35a: 0x3e, 0x35b: 0x3e, 0x35c: 0x3e, 0x35d: 0x3e, 0x35e: 0x3e, 0x35f: 0x3e,
+	0x360: 0x3e, 0x361: 0x3e, 0x362: 0x3e, 0x363: 0x3e, 0x364: 0x3e, 0x365: 0x3e, 0x366: 0x3e, 0x367: 0x3e,
+	0x368: 0x3e, 0x369: 0x3e, 0x36a: 0x3e, 0x36b: 0x3e, 0x36c: 0x3e, 0x36d: 0x3e, 0x36e: 0x3e, 0x36f: 0x3e,
+	0x370: 0x3e, 0x371: 0x3e, 0x372: 0x3e, 0x373: 0x3e, 0x374: 0x3e, 0x375: 0x3e, 0x376: 0x3e, 0x377: 0x3e,
+	0x378: 0x3e, 0x379: 0x3e, 0x37a: 0x3e, 0x37b: 0x3e, 0x37c: 0x3e, 0x37d: 0x3e, 0x37e: 0x3e, 0x37f: 0x3e,
+	// Block 0xe, offset 0x380
+	0x380: 0x3e, 0x381: 0x3e, 0x382: 0x3e, 0x383: 0x3e, 0x384: 0x3e, 0x385: 0x3e, 0x386: 0x3e, 0x387: 0x3e,
+	0x388: 0x3e, 0x389: 0x3e, 0x38a: 0x3e, 0x38b: 0x3e, 0x38c: 0x3e, 0x38d: 0x3e, 0x38e: 0x3e, 0x38f: 0x3e,
+	0x390: 0x3e, 0x391: 0x3e, 0x392: 0x3e, 0x393: 0x3e, 0x394: 0x3e, 0x395: 0x3e, 0x396: 0x3e, 0x397: 0x3e,
+	0x398: 0x3e, 0x399: 0x3e, 0x39a: 0x3e, 0x39b: 0x3e, 0x39c: 0x3e, 0x39d: 0x3e, 0x39e: 0x3e, 0x39f: 0x3e,
+	0x3a0: 0x3e, 0x3a1: 0x3e, 0x3a2: 0x3e, 0x3a3: 0x3e, 0x3a4: 0x7f, 0x3a5: 0x7f, 0x3a6: 0x7f, 0x3a7: 0x7f,
+	0x3a8: 0xa7, 0x3a9: 0xa8, 0x3aa: 0x7f, 0x3ab: 0xa9, 0x3ac: 0xaa, 0x3ad: 0xab, 0x3ae: 0x71, 0x3af: 0x71,
+	0x3b0: 0x71, 0x3b1: 0x71, 0x3b2: 0x71, 0x3b3: 0x71, 0x3b4: 0x71, 0x3b5: 0x71, 0x3b6: 0x71, 0x3b7: 0xac,
+	0x3b8: 0xad, 0x3b9: 0xae, 0x3ba: 0x71, 0x3bb: 0xaf, 0x3bc: 0xb0, 0x3bd: 0xb1, 0x3be: 0xb2, 0x3bf: 0xb3,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0xb4, 0x3c1: 0xb5, 0x3c2: 0x05, 0x3c3: 0xb6, 0x3c4: 0xb7, 0x3c5: 0xb8, 0x3c6: 0xb9, 0x3c7: 0xba,
+	0x3ca: 0xbb, 0x3cb: 0xbc, 0x3cc: 0xbd, 0x3cd: 0xbe, 0x3ce: 0xbf, 0x3cf: 0xc0,
+	0x3d0: 0x05, 0x3d1: 0x05, 0x3d2: 0xc1, 0x3d3: 0xc2, 0x3d4: 0xc3, 0x3d5: 0xc4, 0x3d6: 0xc5, 0x3d7: 0xc6,
+	0x3d8: 0x05, 0x3d9: 0x05, 0x3da: 0x05, 0x3db: 0x05, 0x3dc: 0xc7, 0x3dd: 0xc8, 0x3de: 0xc9,
+	0x3e0: 0xca, 0x3e1: 0xcb, 0x3e2: 0xcc, 0x3e3: 0xcd, 0x3e4: 0xce, 0x3e5: 0xcf, 0x3e6: 0xd0, 0x3e7: 0xd1,
+	0x3e8: 0xd2, 0x3e9: 0xd3, 0x3ea: 0xd4, 0x3eb: 0xd5, 0x3ec: 0xd6, 0x3ed: 0xd7, 0x3ee: 0xd8,
+	0x3f0: 0x05, 0x3f1: 0xd9, 0x3f2: 0xda, 0x3f3: 0xdb, 0x3f4: 0xdc, 0x3f5: 0xdd, 0x3f6: 0xde,
+	0x3f9: 0xdf, 0x3fa: 0xe0, 0x3fb: 0xe1, 0x3fc: 0xe2, 0x3fd: 0xe3, 0x3fe: 0xe4, 0x3ff: 0xe5,
+	// Block 0x10, offset 0x400
+	0x400: 0xe6, 0x401: 0xe7, 0x402: 0xe8, 0x403: 0xe9, 0x404: 0xea, 0x405: 0xeb, 0x406: 0xec, 0x407: 0xed,
+	0x408: 0xee, 0x409: 0xef, 0x40a: 0xf0, 0x40b: 0xf1, 0x40c: 0xf2, 0x40d: 0xf3, 0x40e: 0xf4, 0x40f: 0xf5,
+	0x410: 0xf6, 0x411: 0xf7, 0x412: 0xf8, 0x413: 0xf9, 0x416: 0xfa, 0x417: 0xfb,
+	0x418: 0xfc, 0x419: 0xfd, 0x41a: 0xfe, 0x41b: 0xff, 0x41c: 0x100, 0x41d: 0x101,
+	0x420: 0x102, 0x422: 0x103, 0x423: 0x104, 0x424: 0x105, 0x425: 0x106, 0x426: 0x107, 0x427: 0x108,
+	0x428: 0x109, 0x429: 0x10a, 0x42a: 0x10b, 0x42b: 0x10c, 0x42c: 0x10d, 0x42d: 0x10e, 0x42f: 0x10f,
+	0x430: 0x110, 0x431: 0x111, 0x432: 0x112, 0x434: 0x113, 0x435: 0x114, 0x436: 0x115, 0x437: 0x116,
+	0x43b: 0x117, 0x43c: 0x118, 0x43d: 0x119, 0x43e: 0x11a, 0x43f: 0x11b,
+	// Block 0x11, offset 0x440
+	0x440: 0x05, 0x441: 0x05, 0x442: 0x05, 0x443: 0x05, 0x444: 0x05, 0x445: 0x05, 0x446: 0x05, 0x447: 0x05,
+	0x448: 0x05, 0x449: 0x05, 0x44a: 0x05, 0x44b: 0x05, 0x44c: 0x05, 0x44d: 0x05, 0x44e: 0xcf,
+	0x450: 0x71, 0x451: 0x11c, 0x452: 0x05, 0x453: 0x05, 0x454: 0x05, 0x455: 0x11d,
+	0x47e: 0x11e, 0x47f: 0x11f,
+	// Block 0x12, offset 0x480
+	0x480: 0x05, 0x481: 0x05, 0x482: 0x05, 0x483: 0x05, 0x484: 0x05, 0x485: 0x05, 0x486: 0x05, 0x487: 0x05,
+	0x488: 0x05, 0x489: 0x05, 0x48a: 0x05, 0x48b: 0x05, 0x48c: 0x05, 0x48d: 0x05, 0x48e: 0x05, 0x48f: 0x05,
+	0x490: 0x120, 0x491: 0x121, 0x492: 0x05, 0x493: 0x05, 0x494: 0x05, 0x495: 0x05, 0x496: 0x05, 0x497: 0x05,
+	0x498: 0x05, 0x499: 0x05, 0x49a: 0x05, 0x49b: 0x05, 0x49c: 0x05, 0x49d: 0x05, 0x49e: 0x05, 0x49f: 0x05,
+	0x4a0: 0x05, 0x4a1: 0x05, 0x4a2: 0x05, 0x4a3: 0x05, 0x4a4: 0x05, 0x4a5: 0x05, 0x4a6: 0x05, 0x4a7: 0x05,
+	0x4a8: 0x05, 0x4a9: 0x05, 0x4aa: 0x05, 0x4ab: 0x05, 0x4ac: 0x05, 0x4ad: 0x05, 0x4ae: 0x05, 0x4af: 0x05,
+	0x4b0: 0x05, 0x4b1: 0x05, 0x4b2: 0x05, 0x4b3: 0x05, 0x4b4: 0x05, 0x4b5: 0x05, 0x4b6: 0x05, 0x4b7: 0x05,
+	0x4b8: 0x05, 0x4b9: 0x05, 0x4ba: 0x05, 0x4bb: 0x05, 0x4bc: 0x05, 0x4bd: 0x05, 0x4be: 0x05, 0x4bf: 0x05,
+	// Block 0x13, offset 0x4c0
+	0x4c0: 0x05, 0x4c1: 0x05, 0x4c2: 0x05, 0x4c3: 0x05, 0x4c4: 0x05, 0x4c5: 0x05, 0x4c6: 0x05, 0x4c7: 0x05,
+	0x4c8: 0x05, 0x4c9: 0x05, 0x4ca: 0x05, 0x4cb: 0x05, 0x4cc: 0x05, 0x4cd: 0x05, 0x4ce: 0x05, 0x4cf: 0xb6,
+	0x4d0: 0x05, 0x4d1: 0x05, 0x4d2: 0x05, 0x4d3: 0x05, 0x4d4: 0x05, 0x4d5: 0x05, 0x4d6: 0x05, 0x4d7: 0x05,
+	0x4d8: 0x05, 0x4d9: 0x101,
+	// Block 0x14, offset 0x500
+	0x504: 0x122,
+	0x520: 0x05, 0x521: 0x05, 0x522: 0x05, 0x523: 0x05, 0x524: 0x05, 0x525: 0x05, 0x526: 0x05, 0x527: 0x05,
+	0x528: 0x10c, 0x529: 0x123, 0x52a: 0x124, 0x52b: 0x125, 0x52c: 0x126, 0x52d: 0x127, 0x52e: 0x128,
+	0x535: 0x129,
+	0x539: 0x05, 0x53a: 0x12a, 0x53b: 0x12b, 0x53c: 0x05, 0x53d: 0x12c, 0x53e: 0x12d, 0x53f: 0x12e,
+	// Block 0x15, offset 0x540
+	0x540: 0x05, 0x541: 0x05, 0x542: 0x05, 0x543: 0x05, 0x544: 0x05, 0x545: 0x05, 0x546: 0x05, 0x547: 0x05,
+	0x548: 0x05, 0x549: 0x05, 0x54a: 0x05, 0x54b: 0x05, 0x54c: 0x05, 0x54d: 0x05, 0x54e: 0x05, 0x54f: 0x05,
+	0x550: 0x05, 0x551: 0x05, 0x552: 0x05, 0x553: 0x05, 0x554: 0x05, 0x555: 0x05, 0x556: 0x05, 0x557: 0x05,
+	0x558: 0x05, 0x559: 0x05, 0x55a: 0x05, 0x55b: 0x05, 0x55c: 0x05, 0x55d: 0x05, 0x55e: 0x05, 0x55f: 0x05,
+	0x560: 0x05, 0x561: 0x05, 0x562: 0x05, 0x563: 0x05, 0x564: 0x05, 0x565: 0x05, 0x566: 0x05, 0x567: 0x05,
+	0x568: 0x05, 0x569: 0x05, 0x56a: 0x05, 0x56b: 0x05, 0x56c: 0x05, 0x56d: 0x05, 0x56e: 0x05, 0x56f: 0x05,
+	0x570: 0x05, 0x571: 0x05, 0x572: 0x05, 0x573: 0x12f, 0x574: 0x130, 0x576: 0x05, 0x577: 0xda,
+	// Block 0x16, offset 0x580
+	0x5bf: 0x131,
+	// Block 0x17, offset 0x5c0
+	0x5c0: 0x8c, 0x5c1: 0x8c, 0x5c2: 0x8c, 0x5c3: 0x8c, 0x5c4: 0x132, 0x5c5: 0x133, 0x5c6: 0x05, 0x5c7: 0x05,
+	0x5c8: 0x05, 0x5c9: 0x05, 0x5ca: 0x05, 0x5cb: 0x134,
+	0x5f0: 0x05, 0x5f1: 0x135, 0x5f2: 0x136,
+	// Block 0x18, offset 0x600
+	0x630: 0x71, 0x631: 0x71, 0x632: 0x71, 0x633: 0x137, 0x634: 0x71, 0x635: 0x71, 0x636: 0x71, 0x637: 0x71,
+	0x638: 0x71, 0x639: 0x71, 0x63a: 0x138, 0x63b: 0x139, 0x63c: 0x13a, 0x63d: 0x13b, 0x63e: 0x71, 0x63f: 0x13c,
+	// Block 0x19, offset 0x640
+	0x640: 0x71, 0x641: 0x71, 0x642: 0x71, 0x643: 0x13d, 0x644: 0x13e, 0x645: 0x13f, 0x646: 0x140, 0x647: 0x141,
+	0x648: 0xb8, 0x649: 0x142, 0x64b: 0x143, 0x64c: 0x71, 0x64d: 0x144,
+	0x650: 0x71, 0x651: 0x145, 0x652: 0x146, 0x653: 0x147, 0x654: 0x148, 0x655: 0x149, 0x656: 0x71, 0x657: 0x71,
+	0x658: 0x71, 0x659: 0x71, 0x65a: 0x14a, 0x65b: 0x71, 0x65c: 0x71, 0x65d: 0x71, 0x65e: 0x71, 0x65f: 0x14b,
+	0x660: 0x71, 0x661: 0x71, 0x662: 0x71, 0x663: 0x71, 0x664: 0x71, 0x665: 0x71, 0x666: 0x71, 0x667: 0x71,
+	0x668: 0x14c, 0x669: 0x14d, 0x66a: 0x14e,
+	0x67c: 0x14f,
+	// Block 0x1a, offset 0x680
+	0x680: 0x150, 0x681: 0x151, 0x682: 0x152, 0x684: 0x153, 0x685: 0x154,
+	0x68a: 0x155, 0x68b: 0x156,
+	0x693: 0x157, 0x697: 0x158,
+	0x69b: 0x159, 0x69f: 0x15a,
+	0x6a0: 0x05, 0x6a1: 0x05, 0x6a2: 0x05, 0x6a3: 0x15b, 0x6a4: 0x15c, 0x6a5: 0x15d,
+	0x6b1: 0x15e, 0x6b2: 0x15f, 0x6b4: 0x160,
+	0x6b8: 0x161, 0x6b9: 0x162, 0x6ba: 0x163, 0x6bb: 0x164,
+	// Block 0x1b, offset 0x6c0
+	0x6c0: 0x165, 0x6c1: 0x71, 0x6c2: 0x166, 0x6c3: 0x167, 0x6c4: 0x71, 0x6c5: 0x71, 0x6c6: 0x151, 0x6c7: 0x168,
+	0x6c8: 0x169, 0x6c9: 0x16a, 0x6cc: 0x71, 0x6cd: 0x71, 0x6ce: 0x71, 0x6cf: 0x71,
+	0x6d0: 0x71, 0x6d1: 0x71, 0x6d2: 0x71, 0x6d3: 0x71, 0x6d4: 0x71, 0x6d5: 0x71, 0x6d6: 0x71, 0x6d7: 0x71,
+	0x6d8: 0x71, 0x6d9: 0x71, 0x6da: 0x71, 0x6db: 0x16b, 0x6dc: 0x71, 0x6dd: 0x71, 0x6de: 0x71, 0x6df: 0x16c,
+	0x6e0: 0x16d, 0x6e1: 0x16e, 0x6e2: 0x16f, 0x6e3: 0x170, 0x6e4: 0x71, 0x6e5: 0x71, 0x6e6: 0x71, 0x6e7: 0x71,
+	0x6e8: 0x71, 0x6e9: 0x171, 0x6ea: 0x172, 0x6eb: 0x173, 0x6ec: 0x71, 0x6ed: 0x71, 0x6ee: 0x174, 0x6ef: 0x175,
+	// Block 0x1c, offset 0x700
+	0x700: 0x8c, 0x701: 0x8c, 0x702: 0x8c, 0x703: 0x8c, 0x704: 0x8c, 0x705: 0x8c, 0x706: 0x8c, 0x707: 0x8c,
+	0x708: 0x8c, 0x709: 0x8c, 0x70a: 0x8c, 0x70b: 0x8c, 0x70c: 0x8c, 0x70d: 0x8c, 0x70e: 0x8c, 0x70f: 0x8c,
+	0x710: 0x8c, 0x711: 0x8c, 0x712: 0x8c, 0x713: 0x8c, 0x714: 0x8c, 0x715: 0x8c, 0x716: 0x8c, 0x717: 0x8c,
+	0x718: 0x8c, 0x719: 0x8c, 0x71a: 0x8c, 0x71b: 0x176, 0x71c: 0x8c, 0x71d: 0x8c, 0x71e: 0x8c, 0x71f: 0x8c,
+	0x720: 0x8c, 0x721: 0x8c, 0x722: 0x8c, 0x723: 0x8c, 0x724: 0x8c, 0x725: 0x8c, 0x726: 0x8c, 0x727: 0x8c,
+	0x728: 0x8c, 0x729: 0x8c, 0x72a: 0x8c, 0x72b: 0x8c, 0x72c: 0x8c, 0x72d: 0x8c, 0x72e: 0x8c, 0x72f: 0x8c,
+	0x730: 0x8c, 0x731: 0x8c, 0x732: 0x8c, 0x733: 0x8c, 0x734: 0x8c, 0x735: 0x8c, 0x736: 0x8c, 0x737: 0x8c,
+	0x738: 0x8c, 0x739: 0x8c, 0x73a: 0x8c, 0x73b: 0x8c, 0x73c: 0x8c, 0x73d: 0x8c, 0x73e: 0x8c, 0x73f: 0x8c,
+	// Block 0x1d, offset 0x740
+	0x740: 0x8c, 0x741: 0x8c, 0x742: 0x8c, 0x743: 0x8c, 0x744: 0x8c, 0x745: 0x8c, 0x746: 0x8c, 0x747: 0x8c,
+	0x748: 0x8c, 0x749: 0x8c, 0x74a: 0x8c, 0x74b: 0x8c, 0x74c: 0x8c, 0x74d: 0x8c, 0x74e: 0x8c, 0x74f: 0x8c,
+	0x750: 0x8c, 0x751: 0x8c, 0x752: 0x8c, 0x753: 0x8c, 0x754: 0x8c, 0x755: 0x8c, 0x756: 0x8c, 0x757: 0x8c,
+	0x758: 0x8c, 0x759: 0x8c, 0x75a: 0x8c, 0x75b: 0x8c, 0x75c: 0x8c, 0x75d: 0x8c, 0x75e: 0x8c, 0x75f: 0x8c,
+	0x760: 0x177, 0x761: 0x8c, 0x762: 0x8c, 0x763: 0x8c, 0x764: 0x8c, 0x765: 0x8c, 0x766: 0x8c, 0x767: 0x8c,
+	0x768: 0x8c, 0x769: 0x8c, 0x76a: 0x8c, 0x76b: 0x8c, 0x76c: 0x8c, 0x76d: 0x8c, 0x76e: 0x8c, 0x76f: 0x8c,
+	0x770: 0x8c, 0x771: 0x8c, 0x772: 0x8c, 0x773: 0x8c, 0x774: 0x8c, 0x775: 0x8c, 0x776: 0x8c, 0x777: 0x8c,
+	0x778: 0x8c, 0x779: 0x8c, 0x77a: 0x8c, 0x77b: 0x8c, 0x77c: 0x8c, 0x77d: 0x8c, 0x77e: 0x8c, 0x77f: 0x8c,
+	// Block 0x1e, offset 0x780
+	0x780: 0x8c, 0x781: 0x8c, 0x782: 0x8c, 0x783: 0x8c, 0x784: 0x8c, 0x785: 0x8c, 0x786: 0x8c, 0x787: 0x8c,
+	0x788: 0x8c, 0x789: 0x8c, 0x78a: 0x8c, 0x78b: 0x8c, 0x78c: 0x8c, 0x78d: 0x8c, 0x78e: 0x8c, 0x78f: 0x8c,
+	0x790: 0x8c, 0x791: 0x8c, 0x792: 0x8c, 0x793: 0x8c, 0x794: 0x8c, 0x795: 0x8c, 0x796: 0x8c, 0x797: 0x8c,
+	0x798: 0x8c, 0x799: 0x8c, 0x79a: 0x8c, 0x79b: 0x8c, 0x79c: 0x8c, 0x79d: 0x8c, 0x79e: 0x8c, 0x79f: 0x8c,
+	0x7a0: 0x8c, 0x7a1: 0x8c, 0x7a2: 0x8c, 0x7a3: 0x8c, 0x7a4: 0x8c, 0x7a5: 0x8c, 0x7a6: 0x8c, 0x7a7: 0x8c,
+	0x7a8: 0x8c, 0x7a9: 0x8c, 0x7aa: 0x8c, 0x7ab: 0x8c, 0x7ac: 0x8c, 0x7ad: 0x8c, 0x7ae: 0x8c, 0x7af: 0x8c,
+	0x7b0: 0x8c, 0x7b1: 0x8c, 0x7b2: 0x8c, 0x7b3: 0x8c, 0x7b4: 0x8c, 0x7b5: 0x8c, 0x7b6: 0x8c, 0x7b7: 0x8c,
+	0x7b8: 0x8c, 0x7b9: 0x8c, 0x7ba: 0x178, 0x7bb: 0x8c, 0x7bc: 0x8c, 0x7bd: 0x8c, 0x7be: 0x8c, 0x7bf: 0x8c,
+	// Block 0x1f, offset 0x7c0
+	0x7c0: 0x8c, 0x7c1: 0x8c, 0x7c2: 0x8c, 0x7c3: 0x8c, 0x7c4: 0x8c, 0x7c5: 0x8c, 0x7c6: 0x8c, 0x7c7: 0x8c,
+	0x7c8: 0x8c, 0x7c9: 0x8c, 0x7ca: 0x8c, 0x7cb: 0x8c, 0x7cc: 0x8c, 0x7cd: 0x8c, 0x7ce: 0x8c, 0x7cf: 0x8c,
+	0x7d0: 0x8c, 0x7d1: 0x8c, 0x7d2: 0x8c, 0x7d3: 0x8c, 0x7d4: 0x8c, 0x7d5: 0x8c, 0x7d6: 0x8c, 0x7d7: 0x8c,
+	0x7d8: 0x8c, 0x7d9: 0x8c, 0x7da: 0x8c, 0x7db: 0x8c, 0x7dc: 0x8c, 0x7dd: 0x8c, 0x7de: 0x8c, 0x7df: 0x8c,
+	0x7e0: 0x8c, 0x7e1: 0x8c, 0x7e2: 0x8c, 0x7e3: 0x8c, 0x7e4: 0x8c, 0x7e5: 0x8c, 0x7e6: 0x8c, 0x7e7: 0x8c,
+	0x7e8: 0x8c, 0x7e9: 0x8c, 0x7ea: 0x8c, 0x7eb: 0x8c, 0x7ec: 0x8c, 0x7ed: 0x8c, 0x7ee: 0x8c, 0x7ef: 0x179,
+	0x7f0: 0x8c, 0x7f1: 0x8c, 0x7f2: 0x8c, 0x7f3: 0x8c, 0x7f4: 0x8c, 0x7f5: 0x8c, 0x7f6: 0x8c, 0x7f7: 0x8c,
+	0x7f8: 0x8c, 0x7f9: 0x17a,
+	// Block 0x20, offset 0x800
+	0x820: 0x7f, 0x821: 0x7f, 0x822: 0x7f, 0x823: 0x7f, 0x824: 0x7f, 0x825: 0x7f, 0x826: 0x7f, 0x827: 0x7f,
+	0x828: 0x17b,
+	// Block 0x21, offset 0x840
+	0x840: 0x8c, 0x841: 0x8c, 0x842: 0x8c, 0x843: 0x8c, 0x844: 0x8c, 0x845: 0x8c, 0x846: 0x8c, 0x847: 0x8c,
+	0x848: 0x8c, 0x849: 0x8c, 0x84a: 0x8c, 0x84b: 0x8c, 0x84c: 0x8c, 0x84d: 0x17c, 0x84e: 0x8c, 0x84f: 0x8c,
+	0x850: 0x8c, 0x851: 0x8c, 0x852: 0x8c, 0x853: 0x8c, 0x854: 0x8c, 0x855: 0x8c, 0x856: 0x8c, 0x857: 0x8c,
+	0x858: 0x8c, 0x859: 0x8c, 0x85a: 0x8c, 0x85b: 0x8c, 0x85c: 0x8c, 0x85d: 0x8c, 0x85e: 0x8c, 0x85f: 0x8c,
+	0x860: 0x8c, 0x861: 0x8c, 0x862: 0x8c, 0x863: 0x8c, 0x864: 0x8c, 0x865: 0x8c, 0x866: 0x8c, 0x867: 0x8c,
+	0x868: 0x8c, 0x869: 0x8c, 0x86a: 0x8c, 0x86b: 0x8c, 0x86c: 0x8c, 0x86d: 0x8c, 0x86e: 0x8c, 0x86f: 0x8c,
+	0x870: 0x8c, 0x871: 0x8c, 0x872: 0x8c, 0x873: 0x8c, 0x874: 0x8c, 0x875: 0x8c, 0x876: 0x8c, 0x877: 0x8c,
+	0x878: 0x8c, 0x879: 0x8c, 0x87a: 0x8c, 0x87b: 0x8c, 0x87c: 0x8c, 0x87d: 0x8c, 0x87e: 0x8c, 0x87f: 0x8c,
+	// Block 0x22, offset 0x880
+	0x880: 0x8c, 0x881: 0x8c, 0x882: 0x8c, 0x883: 0x8c, 0x884: 0x8c, 0x885: 0x8c, 0x886: 0x8c, 0x887: 0x8c,
+	0x888: 0x8c, 0x889: 0x8c, 0x88a: 0x8c, 0x88b: 0x8c, 0x88c: 0x8c, 0x88d: 0x8c, 0x88e: 0x8c, 0x88f: 0x8c,
+	0x890: 0x8c, 0x891: 0x17d,
+	// Block 0x23, offset 0x8c0
+	0x8d0: 0x0d, 0x8d1: 0x0e, 0x8d2: 0x0f, 0x8d3: 0x10, 0x8d4: 0x11, 0x8d6: 0x12, 0x8d7: 0x09,
+	0x8d8: 0x13, 0x8da: 0x14, 0x8db: 0x15, 0x8dc: 0x16, 0x8dd: 0x17, 0x8de: 0x18, 0x8df: 0x19,
+	0x8e0: 0x07, 0x8e1: 0x07, 0x8e2: 0x07, 0x8e3: 0x07, 0x8e4: 0x07, 0x8e5: 0x07, 0x8e6: 0x07, 0x8e7: 0x07,
+	0x8e8: 0x07, 0x8e9: 0x07, 0x8ea: 0x1a, 0x8eb: 0x1b, 0x8ec: 0x1c, 0x8ed: 0x07, 0x8ee: 0x1d, 0x8ef: 0x1e,
+	0x8f0: 0x07, 0x8f1: 0x1f, 0x8f2: 0x07, 0x8f3: 0x20,
+	// Block 0x24, offset 0x900
+	0x900: 0x17e, 0x901: 0x3e, 0x904: 0x3e, 0x905: 0x3e, 0x906: 0x3e, 0x907: 0x17f,
+	// Block 0x25, offset 0x940
+	0x940: 0x3e, 0x941: 0x3e, 0x942: 0x3e, 0x943: 0x3e, 0x944: 0x3e, 0x945: 0x3e, 0x946: 0x3e, 0x947: 0x3e,
+	0x948: 0x3e, 0x949: 0x3e, 0x94a: 0x3e, 0x94b: 0x3e, 0x94c: 0x3e, 0x94d: 0x3e, 0x94e: 0x3e, 0x94f: 0x3e,
+	0x950: 0x3e, 0x951: 0x3e, 0x952: 0x3e, 0x953: 0x3e, 0x954: 0x3e, 0x955: 0x3e, 0x956: 0x3e, 0x957: 0x3e,
+	0x958: 0x3e, 0x959: 0x3e, 0x95a: 0x3e, 0x95b: 0x3e, 0x95c: 0x3e, 0x95d: 0x3e, 0x95e: 0x3e, 0x95f: 0x3e,
+	0x960: 0x3e, 0x961: 0x3e, 0x962: 0x3e, 0x963: 0x3e, 0x964: 0x3e, 0x965: 0x3e, 0x966: 0x3e, 0x967: 0x3e,
+	0x968: 0x3e, 0x969: 0x3e, 0x96a: 0x3e, 0x96b: 0x3e, 0x96c: 0x3e, 0x96d: 0x3e, 0x96e: 0x3e, 0x96f: 0x3e,
+	0x970: 0x3e, 0x971: 0x3e, 0x972: 0x3e, 0x973: 0x3e, 0x974: 0x3e, 0x975: 0x3e, 0x976: 0x3e, 0x977: 0x3e,
+	0x978: 0x3e, 0x979: 0x3e, 0x97a: 0x3e, 0x97b: 0x3e, 0x97c: 0x3e, 0x97d: 0x3e, 0x97e: 0x3e, 0x97f: 0x180,
+	// Block 0x26, offset 0x980
+	0x9a0: 0x22,
+	0x9b0: 0x0b, 0x9b1: 0x0b, 0x9b2: 0x0b, 0x9b3: 0x0b, 0x9b4: 0x0b, 0x9b5: 0x0b, 0x9b6: 0x0b, 0x9b7: 0x0b,
+	0x9b8: 0x0b, 0x9b9: 0x0b, 0x9ba: 0x0b, 0x9bb: 0x0b, 0x9bc: 0x0b, 0x9bd: 0x0b, 0x9be: 0x0b, 0x9bf: 0x23,
+	// Block 0x27, offset 0x9c0
+	0x9c0: 0x0b, 0x9c1: 0x0b, 0x9c2: 0x0b, 0x9c3: 0x0b, 0x9c4: 0x0b, 0x9c5: 0x0b, 0x9c6: 0x0b, 0x9c7: 0x0b,
+	0x9c8: 0x0b, 0x9c9: 0x0b, 0x9ca: 0x0b, 0x9cb: 0x0b, 0x9cc: 0x0b, 0x9cd: 0x0b, 0x9ce: 0x0b, 0x9cf: 0x23,
+}
+
+// Total table size 29888 bytes (29KiB); checksum: 811C9DC5
diff --git a/vendor/golang.org/x/text/secure/precis/transformer.go b/vendor/golang.org/x/text/secure/precis/transformer.go
new file mode 100644
index 000000000..97ce5e757
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/transformer.go
@@ -0,0 +1,32 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package precis
+
+import "golang.org/x/text/transform"
+
+// Transformer implements the transform.Transformer interface.
+type Transformer struct {
+	t transform.Transformer
+}
+
+// Reset implements the transform.Transformer interface.
+func (t Transformer) Reset() { t.t.Reset() }
+
+// Transform implements the transform.Transformer interface.
+func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	return t.t.Transform(dst, src, atEOF)
+}
+
+// Bytes returns a new byte slice with the result of applying t to b.
+func (t Transformer) Bytes(b []byte) []byte {
+	b, _, _ = transform.Bytes(t, b)
+	return b
+}
+
+// String returns a string with the result of applying t to s.
+func (t Transformer) String(s string) string {
+	s, _, _ = transform.String(t, s)
+	return s
+}
diff --git a/vendor/golang.org/x/text/secure/precis/trieval.go b/vendor/golang.org/x/text/secure/precis/trieval.go
new file mode 100644
index 000000000..4833f9622
--- /dev/null
+++ b/vendor/golang.org/x/text/secure/precis/trieval.go
@@ -0,0 +1,64 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package precis
+
+// entry is the entry of a trie table
+// 7..6   property (unassigned, disallowed, maybe, valid)
+// 5..0   category
+type entry uint8
+
+const (
+	propShift = 6
+	propMask  = 0xc0
+	catMask   = 0x3f
+)
+
+func (e entry) property() property { return property(e & propMask) }
+func (e entry) category() category { return category(e & catMask) }
+
+type property uint8
+
+// The order of these constants matter. A Profile may consider runes to be
+// allowed either from pValid or idDisOrFreePVal.
+const (
+	unassigned property = iota << propShift
+	disallowed
+	idDisOrFreePVal // disallowed for Identifier, pValid for FreeForm
+	pValid
+)
+
+// compute permutations of all properties and specialCategories.
+type category uint8
+
+const (
+	other category = iota
+
+	// Special rune types
+	joiningL
+	joiningD
+	joiningT
+	joiningR
+	viramaModifier
+	viramaJoinT // Virama + JoiningT
+	latinSmallL // U+006c
+	greek
+	greekJoinT // Greek + JoiningT
+	hebrew
+	hebrewJoinT // Hebrew + JoiningT
+	japanese    // hirigana, katakana, han
+
+	// Special rune types associated with contextual rules defined in
+	// https://tools.ietf.org/html/rfc5892#appendix-A.
+	// ContextO
+	zeroWidthNonJoiner // rule 1
+	zeroWidthJoiner    // rule 2
+	// ContextJ
+	middleDot                // rule 3
+	greekLowerNumeralSign    // rule 4
+	hebrewPreceding          // rule 5 and 6
+	katakanaMiddleDot        // rule 7
+	arabicIndicDigit         // rule 8
+	extendedArabicIndicDigit // rule 9
+
+	numCategories
+)
diff --git a/vendor/golang.org/x/text/width/kind_string.go b/vendor/golang.org/x/text/width/kind_string.go
new file mode 100644
index 000000000..dd3febd43
--- /dev/null
+++ b/vendor/golang.org/x/text/width/kind_string.go
@@ -0,0 +1,28 @@
+// Code generated by "stringer -type=Kind"; DO NOT EDIT.
+
+package width
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[Neutral-0]
+	_ = x[EastAsianAmbiguous-1]
+	_ = x[EastAsianWide-2]
+	_ = x[EastAsianNarrow-3]
+	_ = x[EastAsianFullwidth-4]
+	_ = x[EastAsianHalfwidth-5]
+}
+
+const _Kind_name = "NeutralEastAsianAmbiguousEastAsianWideEastAsianNarrowEastAsianFullwidthEastAsianHalfwidth"
+
+var _Kind_index = [...]uint8{0, 7, 25, 38, 53, 71, 89}
+
+func (i Kind) String() string {
+	if i < 0 || i >= Kind(len(_Kind_index)-1) {
+		return "Kind(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
+}
diff --git a/vendor/golang.org/x/text/width/tables15.0.0.go b/vendor/golang.org/x/text/width/tables15.0.0.go
new file mode 100644
index 000000000..9b2ae82ae
--- /dev/null
+++ b/vendor/golang.org/x/text/width/tables15.0.0.go
@@ -0,0 +1,1367 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+//go:build !go1.27
+
+package width
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "15.0.0"
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *widthTrie) lookup(s []byte) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return widthValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = widthIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = widthIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = widthIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *widthTrie) lookupUnsafe(s []byte) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return widthValues[c0]
+	}
+	i := widthIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = widthIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = widthIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *widthTrie) lookupString(s string) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return widthValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = widthIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = widthIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = widthIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *widthTrie) lookupStringUnsafe(s string) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return widthValues[c0]
+	}
+	i := widthIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = widthIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = widthIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// widthTrie. Total size: 14912 bytes (14.56 KiB). Checksum: 4468b6cd178303d2.
+type widthTrie struct{}
+
+func newWidthTrie(i int) *widthTrie {
+	return &widthTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *widthTrie) lookupValue(n uint32, b byte) uint16 {
+	switch {
+	default:
+		return uint16(widthValues[n<<6+uint32(b)])
+	}
+}
+
+// widthValues: 105 blocks, 6720 entries, 13440 bytes
+// The third block is the zero block.
+var widthValues = [6720]uint16{
+	// Block 0x0, offset 0x0
+	0x20: 0x6001, 0x21: 0x6002, 0x22: 0x6002, 0x23: 0x6002,
+	0x24: 0x6002, 0x25: 0x6002, 0x26: 0x6002, 0x27: 0x6002, 0x28: 0x6002, 0x29: 0x6002,
+	0x2a: 0x6002, 0x2b: 0x6002, 0x2c: 0x6002, 0x2d: 0x6002, 0x2e: 0x6002, 0x2f: 0x6002,
+	0x30: 0x6002, 0x31: 0x6002, 0x32: 0x6002, 0x33: 0x6002, 0x34: 0x6002, 0x35: 0x6002,
+	0x36: 0x6002, 0x37: 0x6002, 0x38: 0x6002, 0x39: 0x6002, 0x3a: 0x6002, 0x3b: 0x6002,
+	0x3c: 0x6002, 0x3d: 0x6002, 0x3e: 0x6002, 0x3f: 0x6002,
+	// Block 0x1, offset 0x40
+	0x40: 0x6003, 0x41: 0x6003, 0x42: 0x6003, 0x43: 0x6003, 0x44: 0x6003, 0x45: 0x6003,
+	0x46: 0x6003, 0x47: 0x6003, 0x48: 0x6003, 0x49: 0x6003, 0x4a: 0x6003, 0x4b: 0x6003,
+	0x4c: 0x6003, 0x4d: 0x6003, 0x4e: 0x6003, 0x4f: 0x6003, 0x50: 0x6003, 0x51: 0x6003,
+	0x52: 0x6003, 0x53: 0x6003, 0x54: 0x6003, 0x55: 0x6003, 0x56: 0x6003, 0x57: 0x6003,
+	0x58: 0x6003, 0x59: 0x6003, 0x5a: 0x6003, 0x5b: 0x6003, 0x5c: 0x6003, 0x5d: 0x6003,
+	0x5e: 0x6003, 0x5f: 0x6003, 0x60: 0x6004, 0x61: 0x6004, 0x62: 0x6004, 0x63: 0x6004,
+	0x64: 0x6004, 0x65: 0x6004, 0x66: 0x6004, 0x67: 0x6004, 0x68: 0x6004, 0x69: 0x6004,
+	0x6a: 0x6004, 0x6b: 0x6004, 0x6c: 0x6004, 0x6d: 0x6004, 0x6e: 0x6004, 0x6f: 0x6004,
+	0x70: 0x6004, 0x71: 0x6004, 0x72: 0x6004, 0x73: 0x6004, 0x74: 0x6004, 0x75: 0x6004,
+	0x76: 0x6004, 0x77: 0x6004, 0x78: 0x6004, 0x79: 0x6004, 0x7a: 0x6004, 0x7b: 0x6004,
+	0x7c: 0x6004, 0x7d: 0x6004, 0x7e: 0x6004,
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xe1: 0x2000, 0xe2: 0x6005, 0xe3: 0x6005,
+	0xe4: 0x2000, 0xe5: 0x6006, 0xe6: 0x6005, 0xe7: 0x2000, 0xe8: 0x2000,
+	0xea: 0x2000, 0xec: 0x6007, 0xed: 0x2000, 0xee: 0x2000, 0xef: 0x6008,
+	0xf0: 0x2000, 0xf1: 0x2000, 0xf2: 0x2000, 0xf3: 0x2000, 0xf4: 0x2000,
+	0xf6: 0x2000, 0xf7: 0x2000, 0xf8: 0x2000, 0xf9: 0x2000, 0xfa: 0x2000,
+	0xfc: 0x2000, 0xfd: 0x2000, 0xfe: 0x2000, 0xff: 0x2000,
+	// Block 0x4, offset 0x100
+	0x106: 0x2000,
+	0x110: 0x2000,
+	0x117: 0x2000,
+	0x118: 0x2000,
+	0x11e: 0x2000, 0x11f: 0x2000, 0x120: 0x2000, 0x121: 0x2000,
+	0x126: 0x2000, 0x128: 0x2000, 0x129: 0x2000,
+	0x12a: 0x2000, 0x12c: 0x2000, 0x12d: 0x2000,
+	0x130: 0x2000, 0x132: 0x2000, 0x133: 0x2000,
+	0x137: 0x2000, 0x138: 0x2000, 0x139: 0x2000, 0x13a: 0x2000,
+	0x13c: 0x2000, 0x13e: 0x2000,
+	// Block 0x5, offset 0x140
+	0x141: 0x2000,
+	0x151: 0x2000,
+	0x153: 0x2000,
+	0x15b: 0x2000,
+	0x166: 0x2000, 0x167: 0x2000,
+	0x16b: 0x2000,
+	0x171: 0x2000, 0x172: 0x2000, 0x173: 0x2000,
+	0x178: 0x2000,
+	0x17f: 0x2000,
+	// Block 0x6, offset 0x180
+	0x180: 0x2000, 0x181: 0x2000, 0x182: 0x2000, 0x184: 0x2000,
+	0x188: 0x2000, 0x189: 0x2000, 0x18a: 0x2000, 0x18b: 0x2000,
+	0x18d: 0x2000,
+	0x192: 0x2000, 0x193: 0x2000,
+	0x1a6: 0x2000, 0x1a7: 0x2000,
+	0x1ab: 0x2000,
+	// Block 0x7, offset 0x1c0
+	0x1ce: 0x2000, 0x1d0: 0x2000,
+	0x1d2: 0x2000, 0x1d4: 0x2000, 0x1d6: 0x2000,
+	0x1d8: 0x2000, 0x1da: 0x2000, 0x1dc: 0x2000,
+	// Block 0x8, offset 0x200
+	0x211: 0x2000,
+	0x221: 0x2000,
+	// Block 0x9, offset 0x240
+	0x244: 0x2000,
+	0x247: 0x2000, 0x249: 0x2000, 0x24a: 0x2000, 0x24b: 0x2000,
+	0x24d: 0x2000, 0x250: 0x2000,
+	0x258: 0x2000, 0x259: 0x2000, 0x25a: 0x2000, 0x25b: 0x2000, 0x25d: 0x2000,
+	0x25f: 0x2000,
+	// Block 0xa, offset 0x280
+	0x280: 0x2000, 0x281: 0x2000, 0x282: 0x2000, 0x283: 0x2000, 0x284: 0x2000, 0x285: 0x2000,
+	0x286: 0x2000, 0x287: 0x2000, 0x288: 0x2000, 0x289: 0x2000, 0x28a: 0x2000, 0x28b: 0x2000,
+	0x28c: 0x2000, 0x28d: 0x2000, 0x28e: 0x2000, 0x28f: 0x2000, 0x290: 0x2000, 0x291: 0x2000,
+	0x292: 0x2000, 0x293: 0x2000, 0x294: 0x2000, 0x295: 0x2000, 0x296: 0x2000, 0x297: 0x2000,
+	0x298: 0x2000, 0x299: 0x2000, 0x29a: 0x2000, 0x29b: 0x2000, 0x29c: 0x2000, 0x29d: 0x2000,
+	0x29e: 0x2000, 0x29f: 0x2000, 0x2a0: 0x2000, 0x2a1: 0x2000, 0x2a2: 0x2000, 0x2a3: 0x2000,
+	0x2a4: 0x2000, 0x2a5: 0x2000, 0x2a6: 0x2000, 0x2a7: 0x2000, 0x2a8: 0x2000, 0x2a9: 0x2000,
+	0x2aa: 0x2000, 0x2ab: 0x2000, 0x2ac: 0x2000, 0x2ad: 0x2000, 0x2ae: 0x2000, 0x2af: 0x2000,
+	0x2b0: 0x2000, 0x2b1: 0x2000, 0x2b2: 0x2000, 0x2b3: 0x2000, 0x2b4: 0x2000, 0x2b5: 0x2000,
+	0x2b6: 0x2000, 0x2b7: 0x2000, 0x2b8: 0x2000, 0x2b9: 0x2000, 0x2ba: 0x2000, 0x2bb: 0x2000,
+	0x2bc: 0x2000, 0x2bd: 0x2000, 0x2be: 0x2000, 0x2bf: 0x2000,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x2000, 0x2c1: 0x2000, 0x2c2: 0x2000, 0x2c3: 0x2000, 0x2c4: 0x2000, 0x2c5: 0x2000,
+	0x2c6: 0x2000, 0x2c7: 0x2000, 0x2c8: 0x2000, 0x2c9: 0x2000, 0x2ca: 0x2000, 0x2cb: 0x2000,
+	0x2cc: 0x2000, 0x2cd: 0x2000, 0x2ce: 0x2000, 0x2cf: 0x2000, 0x2d0: 0x2000, 0x2d1: 0x2000,
+	0x2d2: 0x2000, 0x2d3: 0x2000, 0x2d4: 0x2000, 0x2d5: 0x2000, 0x2d6: 0x2000, 0x2d7: 0x2000,
+	0x2d8: 0x2000, 0x2d9: 0x2000, 0x2da: 0x2000, 0x2db: 0x2000, 0x2dc: 0x2000, 0x2dd: 0x2000,
+	0x2de: 0x2000, 0x2df: 0x2000, 0x2e0: 0x2000, 0x2e1: 0x2000, 0x2e2: 0x2000, 0x2e3: 0x2000,
+	0x2e4: 0x2000, 0x2e5: 0x2000, 0x2e6: 0x2000, 0x2e7: 0x2000, 0x2e8: 0x2000, 0x2e9: 0x2000,
+	0x2ea: 0x2000, 0x2eb: 0x2000, 0x2ec: 0x2000, 0x2ed: 0x2000, 0x2ee: 0x2000, 0x2ef: 0x2000,
+	// Block 0xc, offset 0x300
+	0x311: 0x2000,
+	0x312: 0x2000, 0x313: 0x2000, 0x314: 0x2000, 0x315: 0x2000, 0x316: 0x2000, 0x317: 0x2000,
+	0x318: 0x2000, 0x319: 0x2000, 0x31a: 0x2000, 0x31b: 0x2000, 0x31c: 0x2000, 0x31d: 0x2000,
+	0x31e: 0x2000, 0x31f: 0x2000, 0x320: 0x2000, 0x321: 0x2000, 0x323: 0x2000,
+	0x324: 0x2000, 0x325: 0x2000, 0x326: 0x2000, 0x327: 0x2000, 0x328: 0x2000, 0x329: 0x2000,
+	0x331: 0x2000, 0x332: 0x2000, 0x333: 0x2000, 0x334: 0x2000, 0x335: 0x2000,
+	0x336: 0x2000, 0x337: 0x2000, 0x338: 0x2000, 0x339: 0x2000, 0x33a: 0x2000, 0x33b: 0x2000,
+	0x33c: 0x2000, 0x33d: 0x2000, 0x33e: 0x2000, 0x33f: 0x2000,
+	// Block 0xd, offset 0x340
+	0x340: 0x2000, 0x341: 0x2000, 0x343: 0x2000, 0x344: 0x2000, 0x345: 0x2000,
+	0x346: 0x2000, 0x347: 0x2000, 0x348: 0x2000, 0x349: 0x2000,
+	// Block 0xe, offset 0x380
+	0x381: 0x2000,
+	0x390: 0x2000, 0x391: 0x2000,
+	0x392: 0x2000, 0x393: 0x2000, 0x394: 0x2000, 0x395: 0x2000, 0x396: 0x2000, 0x397: 0x2000,
+	0x398: 0x2000, 0x399: 0x2000, 0x39a: 0x2000, 0x39b: 0x2000, 0x39c: 0x2000, 0x39d: 0x2000,
+	0x39e: 0x2000, 0x39f: 0x2000, 0x3a0: 0x2000, 0x3a1: 0x2000, 0x3a2: 0x2000, 0x3a3: 0x2000,
+	0x3a4: 0x2000, 0x3a5: 0x2000, 0x3a6: 0x2000, 0x3a7: 0x2000, 0x3a8: 0x2000, 0x3a9: 0x2000,
+	0x3aa: 0x2000, 0x3ab: 0x2000, 0x3ac: 0x2000, 0x3ad: 0x2000, 0x3ae: 0x2000, 0x3af: 0x2000,
+	0x3b0: 0x2000, 0x3b1: 0x2000, 0x3b2: 0x2000, 0x3b3: 0x2000, 0x3b4: 0x2000, 0x3b5: 0x2000,
+	0x3b6: 0x2000, 0x3b7: 0x2000, 0x3b8: 0x2000, 0x3b9: 0x2000, 0x3ba: 0x2000, 0x3bb: 0x2000,
+	0x3bc: 0x2000, 0x3bd: 0x2000, 0x3be: 0x2000, 0x3bf: 0x2000,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x2000, 0x3c1: 0x2000, 0x3c2: 0x2000, 0x3c3: 0x2000, 0x3c4: 0x2000, 0x3c5: 0x2000,
+	0x3c6: 0x2000, 0x3c7: 0x2000, 0x3c8: 0x2000, 0x3c9: 0x2000, 0x3ca: 0x2000, 0x3cb: 0x2000,
+	0x3cc: 0x2000, 0x3cd: 0x2000, 0x3ce: 0x2000, 0x3cf: 0x2000, 0x3d1: 0x2000,
+	// Block 0x10, offset 0x400
+	0x400: 0x4000, 0x401: 0x4000, 0x402: 0x4000, 0x403: 0x4000, 0x404: 0x4000, 0x405: 0x4000,
+	0x406: 0x4000, 0x407: 0x4000, 0x408: 0x4000, 0x409: 0x4000, 0x40a: 0x4000, 0x40b: 0x4000,
+	0x40c: 0x4000, 0x40d: 0x4000, 0x40e: 0x4000, 0x40f: 0x4000, 0x410: 0x4000, 0x411: 0x4000,
+	0x412: 0x4000, 0x413: 0x4000, 0x414: 0x4000, 0x415: 0x4000, 0x416: 0x4000, 0x417: 0x4000,
+	0x418: 0x4000, 0x419: 0x4000, 0x41a: 0x4000, 0x41b: 0x4000, 0x41c: 0x4000, 0x41d: 0x4000,
+	0x41e: 0x4000, 0x41f: 0x4000, 0x420: 0x4000, 0x421: 0x4000, 0x422: 0x4000, 0x423: 0x4000,
+	0x424: 0x4000, 0x425: 0x4000, 0x426: 0x4000, 0x427: 0x4000, 0x428: 0x4000, 0x429: 0x4000,
+	0x42a: 0x4000, 0x42b: 0x4000, 0x42c: 0x4000, 0x42d: 0x4000, 0x42e: 0x4000, 0x42f: 0x4000,
+	0x430: 0x4000, 0x431: 0x4000, 0x432: 0x4000, 0x433: 0x4000, 0x434: 0x4000, 0x435: 0x4000,
+	0x436: 0x4000, 0x437: 0x4000, 0x438: 0x4000, 0x439: 0x4000, 0x43a: 0x4000, 0x43b: 0x4000,
+	0x43c: 0x4000, 0x43d: 0x4000, 0x43e: 0x4000, 0x43f: 0x4000,
+	// Block 0x11, offset 0x440
+	0x440: 0x4000, 0x441: 0x4000, 0x442: 0x4000, 0x443: 0x4000, 0x444: 0x4000, 0x445: 0x4000,
+	0x446: 0x4000, 0x447: 0x4000, 0x448: 0x4000, 0x449: 0x4000, 0x44a: 0x4000, 0x44b: 0x4000,
+	0x44c: 0x4000, 0x44d: 0x4000, 0x44e: 0x4000, 0x44f: 0x4000, 0x450: 0x4000, 0x451: 0x4000,
+	0x452: 0x4000, 0x453: 0x4000, 0x454: 0x4000, 0x455: 0x4000, 0x456: 0x4000, 0x457: 0x4000,
+	0x458: 0x4000, 0x459: 0x4000, 0x45a: 0x4000, 0x45b: 0x4000, 0x45c: 0x4000, 0x45d: 0x4000,
+	0x45e: 0x4000, 0x45f: 0x4000,
+	// Block 0x12, offset 0x480
+	0x490: 0x2000,
+	0x493: 0x2000, 0x494: 0x2000, 0x495: 0x2000, 0x496: 0x2000,
+	0x498: 0x2000, 0x499: 0x2000, 0x49c: 0x2000, 0x49d: 0x2000,
+	0x4a0: 0x2000, 0x4a1: 0x2000, 0x4a2: 0x2000,
+	0x4a4: 0x2000, 0x4a5: 0x2000, 0x4a6: 0x2000, 0x4a7: 0x2000,
+	0x4b0: 0x2000, 0x4b2: 0x2000, 0x4b3: 0x2000, 0x4b5: 0x2000,
+	0x4bb: 0x2000,
+	0x4be: 0x2000,
+	// Block 0x13, offset 0x4c0
+	0x4f4: 0x2000,
+	0x4ff: 0x2000,
+	// Block 0x14, offset 0x500
+	0x501: 0x2000, 0x502: 0x2000, 0x503: 0x2000, 0x504: 0x2000,
+	0x529: 0xa009,
+	0x52c: 0x2000,
+	// Block 0x15, offset 0x540
+	0x543: 0x2000, 0x545: 0x2000,
+	0x549: 0x2000,
+	0x553: 0x2000, 0x556: 0x2000,
+	0x561: 0x2000, 0x562: 0x2000,
+	0x566: 0x2000,
+	0x56b: 0x2000,
+	// Block 0x16, offset 0x580
+	0x593: 0x2000, 0x594: 0x2000,
+	0x59b: 0x2000, 0x59c: 0x2000, 0x59d: 0x2000,
+	0x59e: 0x2000, 0x5a0: 0x2000, 0x5a1: 0x2000, 0x5a2: 0x2000, 0x5a3: 0x2000,
+	0x5a4: 0x2000, 0x5a5: 0x2000, 0x5a6: 0x2000, 0x5a7: 0x2000, 0x5a8: 0x2000, 0x5a9: 0x2000,
+	0x5aa: 0x2000, 0x5ab: 0x2000,
+	0x5b0: 0x2000, 0x5b1: 0x2000, 0x5b2: 0x2000, 0x5b3: 0x2000, 0x5b4: 0x2000, 0x5b5: 0x2000,
+	0x5b6: 0x2000, 0x5b7: 0x2000, 0x5b8: 0x2000, 0x5b9: 0x2000,
+	// Block 0x17, offset 0x5c0
+	0x5c9: 0x2000,
+	0x5d0: 0x200a, 0x5d1: 0x200b,
+	0x5d2: 0x200a, 0x5d3: 0x200c, 0x5d4: 0x2000, 0x5d5: 0x2000, 0x5d6: 0x2000, 0x5d7: 0x2000,
+	0x5d8: 0x2000, 0x5d9: 0x2000,
+	0x5f8: 0x2000, 0x5f9: 0x2000,
+	// Block 0x18, offset 0x600
+	0x612: 0x2000, 0x614: 0x2000,
+	0x627: 0x2000,
+	// Block 0x19, offset 0x640
+	0x640: 0x2000, 0x642: 0x2000, 0x643: 0x2000,
+	0x647: 0x2000, 0x648: 0x2000, 0x64b: 0x2000,
+	0x64f: 0x2000, 0x651: 0x2000,
+	0x655: 0x2000,
+	0x65a: 0x2000, 0x65d: 0x2000,
+	0x65e: 0x2000, 0x65f: 0x2000, 0x660: 0x2000, 0x663: 0x2000,
+	0x665: 0x2000, 0x667: 0x2000, 0x668: 0x2000, 0x669: 0x2000,
+	0x66a: 0x2000, 0x66b: 0x2000, 0x66c: 0x2000, 0x66e: 0x2000,
+	0x674: 0x2000, 0x675: 0x2000,
+	0x676: 0x2000, 0x677: 0x2000,
+	0x67c: 0x2000, 0x67d: 0x2000,
+	// Block 0x1a, offset 0x680
+	0x688: 0x2000,
+	0x68c: 0x2000,
+	0x692: 0x2000,
+	0x6a0: 0x2000, 0x6a1: 0x2000,
+	0x6a4: 0x2000, 0x6a5: 0x2000, 0x6a6: 0x2000, 0x6a7: 0x2000,
+	0x6aa: 0x2000, 0x6ab: 0x2000, 0x6ae: 0x2000, 0x6af: 0x2000,
+	// Block 0x1b, offset 0x6c0
+	0x6c2: 0x2000, 0x6c3: 0x2000,
+	0x6c6: 0x2000, 0x6c7: 0x2000,
+	0x6d5: 0x2000,
+	0x6d9: 0x2000,
+	0x6e5: 0x2000,
+	0x6ff: 0x2000,
+	// Block 0x1c, offset 0x700
+	0x712: 0x2000,
+	0x71a: 0x4000, 0x71b: 0x4000,
+	0x729: 0x4000,
+	0x72a: 0x4000,
+	// Block 0x1d, offset 0x740
+	0x769: 0x4000,
+	0x76a: 0x4000, 0x76b: 0x4000, 0x76c: 0x4000,
+	0x770: 0x4000, 0x773: 0x4000,
+	// Block 0x1e, offset 0x780
+	0x7a0: 0x2000, 0x7a1: 0x2000, 0x7a2: 0x2000, 0x7a3: 0x2000,
+	0x7a4: 0x2000, 0x7a5: 0x2000, 0x7a6: 0x2000, 0x7a7: 0x2000, 0x7a8: 0x2000, 0x7a9: 0x2000,
+	0x7aa: 0x2000, 0x7ab: 0x2000, 0x7ac: 0x2000, 0x7ad: 0x2000, 0x7ae: 0x2000, 0x7af: 0x2000,
+	0x7b0: 0x2000, 0x7b1: 0x2000, 0x7b2: 0x2000, 0x7b3: 0x2000, 0x7b4: 0x2000, 0x7b5: 0x2000,
+	0x7b6: 0x2000, 0x7b7: 0x2000, 0x7b8: 0x2000, 0x7b9: 0x2000, 0x7ba: 0x2000, 0x7bb: 0x2000,
+	0x7bc: 0x2000, 0x7bd: 0x2000, 0x7be: 0x2000, 0x7bf: 0x2000,
+	// Block 0x1f, offset 0x7c0
+	0x7c0: 0x2000, 0x7c1: 0x2000, 0x7c2: 0x2000, 0x7c3: 0x2000, 0x7c4: 0x2000, 0x7c5: 0x2000,
+	0x7c6: 0x2000, 0x7c7: 0x2000, 0x7c8: 0x2000, 0x7c9: 0x2000, 0x7ca: 0x2000, 0x7cb: 0x2000,
+	0x7cc: 0x2000, 0x7cd: 0x2000, 0x7ce: 0x2000, 0x7cf: 0x2000, 0x7d0: 0x2000, 0x7d1: 0x2000,
+	0x7d2: 0x2000, 0x7d3: 0x2000, 0x7d4: 0x2000, 0x7d5: 0x2000, 0x7d6: 0x2000, 0x7d7: 0x2000,
+	0x7d8: 0x2000, 0x7d9: 0x2000, 0x7da: 0x2000, 0x7db: 0x2000, 0x7dc: 0x2000, 0x7dd: 0x2000,
+	0x7de: 0x2000, 0x7df: 0x2000, 0x7e0: 0x2000, 0x7e1: 0x2000, 0x7e2: 0x2000, 0x7e3: 0x2000,
+	0x7e4: 0x2000, 0x7e5: 0x2000, 0x7e6: 0x2000, 0x7e7: 0x2000, 0x7e8: 0x2000, 0x7e9: 0x2000,
+	0x7eb: 0x2000, 0x7ec: 0x2000, 0x7ed: 0x2000, 0x7ee: 0x2000, 0x7ef: 0x2000,
+	0x7f0: 0x2000, 0x7f1: 0x2000, 0x7f2: 0x2000, 0x7f3: 0x2000, 0x7f4: 0x2000, 0x7f5: 0x2000,
+	0x7f6: 0x2000, 0x7f7: 0x2000, 0x7f8: 0x2000, 0x7f9: 0x2000, 0x7fa: 0x2000, 0x7fb: 0x2000,
+	0x7fc: 0x2000, 0x7fd: 0x2000, 0x7fe: 0x2000, 0x7ff: 0x2000,
+	// Block 0x20, offset 0x800
+	0x800: 0x2000, 0x801: 0x2000, 0x802: 0x200d, 0x803: 0x2000, 0x804: 0x2000, 0x805: 0x2000,
+	0x806: 0x2000, 0x807: 0x2000, 0x808: 0x2000, 0x809: 0x2000, 0x80a: 0x2000, 0x80b: 0x2000,
+	0x80c: 0x2000, 0x80d: 0x2000, 0x80e: 0x2000, 0x80f: 0x2000, 0x810: 0x2000, 0x811: 0x2000,
+	0x812: 0x2000, 0x813: 0x2000, 0x814: 0x2000, 0x815: 0x2000, 0x816: 0x2000, 0x817: 0x2000,
+	0x818: 0x2000, 0x819: 0x2000, 0x81a: 0x2000, 0x81b: 0x2000, 0x81c: 0x2000, 0x81d: 0x2000,
+	0x81e: 0x2000, 0x81f: 0x2000, 0x820: 0x2000, 0x821: 0x2000, 0x822: 0x2000, 0x823: 0x2000,
+	0x824: 0x2000, 0x825: 0x2000, 0x826: 0x2000, 0x827: 0x2000, 0x828: 0x2000, 0x829: 0x2000,
+	0x82a: 0x2000, 0x82b: 0x2000, 0x82c: 0x2000, 0x82d: 0x2000, 0x82e: 0x2000, 0x82f: 0x2000,
+	0x830: 0x2000, 0x831: 0x2000, 0x832: 0x2000, 0x833: 0x2000, 0x834: 0x2000, 0x835: 0x2000,
+	0x836: 0x2000, 0x837: 0x2000, 0x838: 0x2000, 0x839: 0x2000, 0x83a: 0x2000, 0x83b: 0x2000,
+	0x83c: 0x2000, 0x83d: 0x2000, 0x83e: 0x2000, 0x83f: 0x2000,
+	// Block 0x21, offset 0x840
+	0x840: 0x2000, 0x841: 0x2000, 0x842: 0x2000, 0x843: 0x2000, 0x844: 0x2000, 0x845: 0x2000,
+	0x846: 0x2000, 0x847: 0x2000, 0x848: 0x2000, 0x849: 0x2000, 0x84a: 0x2000, 0x84b: 0x2000,
+	0x850: 0x2000, 0x851: 0x2000,
+	0x852: 0x2000, 0x853: 0x2000, 0x854: 0x2000, 0x855: 0x2000, 0x856: 0x2000, 0x857: 0x2000,
+	0x858: 0x2000, 0x859: 0x2000, 0x85a: 0x2000, 0x85b: 0x2000, 0x85c: 0x2000, 0x85d: 0x2000,
+	0x85e: 0x2000, 0x85f: 0x2000, 0x860: 0x2000, 0x861: 0x2000, 0x862: 0x2000, 0x863: 0x2000,
+	0x864: 0x2000, 0x865: 0x2000, 0x866: 0x2000, 0x867: 0x2000, 0x868: 0x2000, 0x869: 0x2000,
+	0x86a: 0x2000, 0x86b: 0x2000, 0x86c: 0x2000, 0x86d: 0x2000, 0x86e: 0x2000, 0x86f: 0x2000,
+	0x870: 0x2000, 0x871: 0x2000, 0x872: 0x2000, 0x873: 0x2000,
+	// Block 0x22, offset 0x880
+	0x880: 0x2000, 0x881: 0x2000, 0x882: 0x2000, 0x883: 0x2000, 0x884: 0x2000, 0x885: 0x2000,
+	0x886: 0x2000, 0x887: 0x2000, 0x888: 0x2000, 0x889: 0x2000, 0x88a: 0x2000, 0x88b: 0x2000,
+	0x88c: 0x2000, 0x88d: 0x2000, 0x88e: 0x2000, 0x88f: 0x2000,
+	0x892: 0x2000, 0x893: 0x2000, 0x894: 0x2000, 0x895: 0x2000,
+	0x8a0: 0x200e, 0x8a1: 0x2000, 0x8a3: 0x2000,
+	0x8a4: 0x2000, 0x8a5: 0x2000, 0x8a6: 0x2000, 0x8a7: 0x2000, 0x8a8: 0x2000, 0x8a9: 0x2000,
+	0x8b2: 0x2000, 0x8b3: 0x2000,
+	0x8b6: 0x2000, 0x8b7: 0x2000,
+	0x8bc: 0x2000, 0x8bd: 0x2000,
+	// Block 0x23, offset 0x8c0
+	0x8c0: 0x2000, 0x8c1: 0x2000,
+	0x8c6: 0x2000, 0x8c7: 0x2000, 0x8c8: 0x2000, 0x8cb: 0x200f,
+	0x8ce: 0x2000, 0x8cf: 0x2000, 0x8d0: 0x2000, 0x8d1: 0x2000,
+	0x8e2: 0x2000, 0x8e3: 0x2000,
+	0x8e4: 0x2000, 0x8e5: 0x2000,
+	0x8ef: 0x2000,
+	0x8fd: 0x4000, 0x8fe: 0x4000,
+	// Block 0x24, offset 0x900
+	0x905: 0x2000,
+	0x906: 0x2000, 0x909: 0x2000,
+	0x90e: 0x2000, 0x90f: 0x2000,
+	0x914: 0x4000, 0x915: 0x4000,
+	0x91c: 0x2000,
+	0x91e: 0x2000,
+	// Block 0x25, offset 0x940
+	0x940: 0x2000, 0x942: 0x2000,
+	0x948: 0x4000, 0x949: 0x4000, 0x94a: 0x4000, 0x94b: 0x4000,
+	0x94c: 0x4000, 0x94d: 0x4000, 0x94e: 0x4000, 0x94f: 0x4000, 0x950: 0x4000, 0x951: 0x4000,
+	0x952: 0x4000, 0x953: 0x4000,
+	0x960: 0x2000, 0x961: 0x2000, 0x963: 0x2000,
+	0x964: 0x2000, 0x965: 0x2000, 0x967: 0x2000, 0x968: 0x2000, 0x969: 0x2000,
+	0x96a: 0x2000, 0x96c: 0x2000, 0x96d: 0x2000, 0x96f: 0x2000,
+	0x97f: 0x4000,
+	// Block 0x26, offset 0x980
+	0x993: 0x4000,
+	0x99e: 0x2000, 0x99f: 0x2000, 0x9a1: 0x4000,
+	0x9aa: 0x4000, 0x9ab: 0x4000,
+	0x9bd: 0x4000, 0x9be: 0x4000, 0x9bf: 0x2000,
+	// Block 0x27, offset 0x9c0
+	0x9c4: 0x4000, 0x9c5: 0x4000,
+	0x9c6: 0x2000, 0x9c7: 0x2000, 0x9c8: 0x2000, 0x9c9: 0x2000, 0x9ca: 0x2000, 0x9cb: 0x2000,
+	0x9cc: 0x2000, 0x9cd: 0x2000, 0x9ce: 0x4000, 0x9cf: 0x2000, 0x9d0: 0x2000, 0x9d1: 0x2000,
+	0x9d2: 0x2000, 0x9d3: 0x2000, 0x9d4: 0x4000, 0x9d5: 0x2000, 0x9d6: 0x2000, 0x9d7: 0x2000,
+	0x9d8: 0x2000, 0x9d9: 0x2000, 0x9da: 0x2000, 0x9db: 0x2000, 0x9dc: 0x2000, 0x9dd: 0x2000,
+	0x9de: 0x2000, 0x9df: 0x2000, 0x9e0: 0x2000, 0x9e1: 0x2000, 0x9e3: 0x2000,
+	0x9e8: 0x2000, 0x9e9: 0x2000,
+	0x9ea: 0x4000, 0x9eb: 0x2000, 0x9ec: 0x2000, 0x9ed: 0x2000, 0x9ee: 0x2000, 0x9ef: 0x2000,
+	0x9f0: 0x2000, 0x9f1: 0x2000, 0x9f2: 0x4000, 0x9f3: 0x4000, 0x9f4: 0x2000, 0x9f5: 0x4000,
+	0x9f6: 0x2000, 0x9f7: 0x2000, 0x9f8: 0x2000, 0x9f9: 0x2000, 0x9fa: 0x4000, 0x9fb: 0x2000,
+	0x9fc: 0x2000, 0x9fd: 0x4000, 0x9fe: 0x2000, 0x9ff: 0x2000,
+	// Block 0x28, offset 0xa00
+	0xa05: 0x4000,
+	0xa0a: 0x4000, 0xa0b: 0x4000,
+	0xa28: 0x4000,
+	0xa3d: 0x2000,
+	// Block 0x29, offset 0xa40
+	0xa4c: 0x4000, 0xa4e: 0x4000,
+	0xa53: 0x4000, 0xa54: 0x4000, 0xa55: 0x4000, 0xa57: 0x4000,
+	0xa76: 0x2000, 0xa77: 0x2000, 0xa78: 0x2000, 0xa79: 0x2000, 0xa7a: 0x2000, 0xa7b: 0x2000,
+	0xa7c: 0x2000, 0xa7d: 0x2000, 0xa7e: 0x2000, 0xa7f: 0x2000,
+	// Block 0x2a, offset 0xa80
+	0xa95: 0x4000, 0xa96: 0x4000, 0xa97: 0x4000,
+	0xab0: 0x4000,
+	0xabf: 0x4000,
+	// Block 0x2b, offset 0xac0
+	0xae6: 0x6000, 0xae7: 0x6000, 0xae8: 0x6000, 0xae9: 0x6000,
+	0xaea: 0x6000, 0xaeb: 0x6000, 0xaec: 0x6000, 0xaed: 0x6000,
+	// Block 0x2c, offset 0xb00
+	0xb05: 0x6010,
+	0xb06: 0x6011,
+	// Block 0x2d, offset 0xb40
+	0xb5b: 0x4000, 0xb5c: 0x4000,
+	// Block 0x2e, offset 0xb80
+	0xb90: 0x4000,
+	0xb95: 0x4000, 0xb96: 0x2000, 0xb97: 0x2000,
+	0xb98: 0x2000, 0xb99: 0x2000,
+	// Block 0x2f, offset 0xbc0
+	0xbc0: 0x4000, 0xbc1: 0x4000, 0xbc2: 0x4000, 0xbc3: 0x4000, 0xbc4: 0x4000, 0xbc5: 0x4000,
+	0xbc6: 0x4000, 0xbc7: 0x4000, 0xbc8: 0x4000, 0xbc9: 0x4000, 0xbca: 0x4000, 0xbcb: 0x4000,
+	0xbcc: 0x4000, 0xbcd: 0x4000, 0xbce: 0x4000, 0xbcf: 0x4000, 0xbd0: 0x4000, 0xbd1: 0x4000,
+	0xbd2: 0x4000, 0xbd3: 0x4000, 0xbd4: 0x4000, 0xbd5: 0x4000, 0xbd6: 0x4000, 0xbd7: 0x4000,
+	0xbd8: 0x4000, 0xbd9: 0x4000, 0xbdb: 0x4000, 0xbdc: 0x4000, 0xbdd: 0x4000,
+	0xbde: 0x4000, 0xbdf: 0x4000, 0xbe0: 0x4000, 0xbe1: 0x4000, 0xbe2: 0x4000, 0xbe3: 0x4000,
+	0xbe4: 0x4000, 0xbe5: 0x4000, 0xbe6: 0x4000, 0xbe7: 0x4000, 0xbe8: 0x4000, 0xbe9: 0x4000,
+	0xbea: 0x4000, 0xbeb: 0x4000, 0xbec: 0x4000, 0xbed: 0x4000, 0xbee: 0x4000, 0xbef: 0x4000,
+	0xbf0: 0x4000, 0xbf1: 0x4000, 0xbf2: 0x4000, 0xbf3: 0x4000, 0xbf4: 0x4000, 0xbf5: 0x4000,
+	0xbf6: 0x4000, 0xbf7: 0x4000, 0xbf8: 0x4000, 0xbf9: 0x4000, 0xbfa: 0x4000, 0xbfb: 0x4000,
+	0xbfc: 0x4000, 0xbfd: 0x4000, 0xbfe: 0x4000, 0xbff: 0x4000,
+	// Block 0x30, offset 0xc00
+	0xc00: 0x4000, 0xc01: 0x4000, 0xc02: 0x4000, 0xc03: 0x4000, 0xc04: 0x4000, 0xc05: 0x4000,
+	0xc06: 0x4000, 0xc07: 0x4000, 0xc08: 0x4000, 0xc09: 0x4000, 0xc0a: 0x4000, 0xc0b: 0x4000,
+	0xc0c: 0x4000, 0xc0d: 0x4000, 0xc0e: 0x4000, 0xc0f: 0x4000, 0xc10: 0x4000, 0xc11: 0x4000,
+	0xc12: 0x4000, 0xc13: 0x4000, 0xc14: 0x4000, 0xc15: 0x4000, 0xc16: 0x4000, 0xc17: 0x4000,
+	0xc18: 0x4000, 0xc19: 0x4000, 0xc1a: 0x4000, 0xc1b: 0x4000, 0xc1c: 0x4000, 0xc1d: 0x4000,
+	0xc1e: 0x4000, 0xc1f: 0x4000, 0xc20: 0x4000, 0xc21: 0x4000, 0xc22: 0x4000, 0xc23: 0x4000,
+	0xc24: 0x4000, 0xc25: 0x4000, 0xc26: 0x4000, 0xc27: 0x4000, 0xc28: 0x4000, 0xc29: 0x4000,
+	0xc2a: 0x4000, 0xc2b: 0x4000, 0xc2c: 0x4000, 0xc2d: 0x4000, 0xc2e: 0x4000, 0xc2f: 0x4000,
+	0xc30: 0x4000, 0xc31: 0x4000, 0xc32: 0x4000, 0xc33: 0x4000,
+	// Block 0x31, offset 0xc40
+	0xc40: 0x4000, 0xc41: 0x4000, 0xc42: 0x4000, 0xc43: 0x4000, 0xc44: 0x4000, 0xc45: 0x4000,
+	0xc46: 0x4000, 0xc47: 0x4000, 0xc48: 0x4000, 0xc49: 0x4000, 0xc4a: 0x4000, 0xc4b: 0x4000,
+	0xc4c: 0x4000, 0xc4d: 0x4000, 0xc4e: 0x4000, 0xc4f: 0x4000, 0xc50: 0x4000, 0xc51: 0x4000,
+	0xc52: 0x4000, 0xc53: 0x4000, 0xc54: 0x4000, 0xc55: 0x4000,
+	0xc70: 0x4000, 0xc71: 0x4000, 0xc72: 0x4000, 0xc73: 0x4000, 0xc74: 0x4000, 0xc75: 0x4000,
+	0xc76: 0x4000, 0xc77: 0x4000, 0xc78: 0x4000, 0xc79: 0x4000, 0xc7a: 0x4000, 0xc7b: 0x4000,
+	// Block 0x32, offset 0xc80
+	0xc80: 0x9012, 0xc81: 0x4013, 0xc82: 0x4014, 0xc83: 0x4000, 0xc84: 0x4000, 0xc85: 0x4000,
+	0xc86: 0x4000, 0xc87: 0x4000, 0xc88: 0x4000, 0xc89: 0x4000, 0xc8a: 0x4000, 0xc8b: 0x4000,
+	0xc8c: 0x4015, 0xc8d: 0x4015, 0xc8e: 0x4000, 0xc8f: 0x4000, 0xc90: 0x4000, 0xc91: 0x4000,
+	0xc92: 0x4000, 0xc93: 0x4000, 0xc94: 0x4000, 0xc95: 0x4000, 0xc96: 0x4000, 0xc97: 0x4000,
+	0xc98: 0x4000, 0xc99: 0x4000, 0xc9a: 0x4000, 0xc9b: 0x4000, 0xc9c: 0x4000, 0xc9d: 0x4000,
+	0xc9e: 0x4000, 0xc9f: 0x4000, 0xca0: 0x4000, 0xca1: 0x4000, 0xca2: 0x4000, 0xca3: 0x4000,
+	0xca4: 0x4000, 0xca5: 0x4000, 0xca6: 0x4000, 0xca7: 0x4000, 0xca8: 0x4000, 0xca9: 0x4000,
+	0xcaa: 0x4000, 0xcab: 0x4000, 0xcac: 0x4000, 0xcad: 0x4000, 0xcae: 0x4000, 0xcaf: 0x4000,
+	0xcb0: 0x4000, 0xcb1: 0x4000, 0xcb2: 0x4000, 0xcb3: 0x4000, 0xcb4: 0x4000, 0xcb5: 0x4000,
+	0xcb6: 0x4000, 0xcb7: 0x4000, 0xcb8: 0x4000, 0xcb9: 0x4000, 0xcba: 0x4000, 0xcbb: 0x4000,
+	0xcbc: 0x4000, 0xcbd: 0x4000, 0xcbe: 0x4000,
+	// Block 0x33, offset 0xcc0
+	0xcc1: 0x4000, 0xcc2: 0x4000, 0xcc3: 0x4000, 0xcc4: 0x4000, 0xcc5: 0x4000,
+	0xcc6: 0x4000, 0xcc7: 0x4000, 0xcc8: 0x4000, 0xcc9: 0x4000, 0xcca: 0x4000, 0xccb: 0x4000,
+	0xccc: 0x4000, 0xccd: 0x4000, 0xcce: 0x4000, 0xccf: 0x4000, 0xcd0: 0x4000, 0xcd1: 0x4000,
+	0xcd2: 0x4000, 0xcd3: 0x4000, 0xcd4: 0x4000, 0xcd5: 0x4000, 0xcd6: 0x4000, 0xcd7: 0x4000,
+	0xcd8: 0x4000, 0xcd9: 0x4000, 0xcda: 0x4000, 0xcdb: 0x4000, 0xcdc: 0x4000, 0xcdd: 0x4000,
+	0xcde: 0x4000, 0xcdf: 0x4000, 0xce0: 0x4000, 0xce1: 0x4000, 0xce2: 0x4000, 0xce3: 0x4000,
+	0xce4: 0x4000, 0xce5: 0x4000, 0xce6: 0x4000, 0xce7: 0x4000, 0xce8: 0x4000, 0xce9: 0x4000,
+	0xcea: 0x4000, 0xceb: 0x4000, 0xcec: 0x4000, 0xced: 0x4000, 0xcee: 0x4000, 0xcef: 0x4000,
+	0xcf0: 0x4000, 0xcf1: 0x4000, 0xcf2: 0x4000, 0xcf3: 0x4000, 0xcf4: 0x4000, 0xcf5: 0x4000,
+	0xcf6: 0x4000, 0xcf7: 0x4000, 0xcf8: 0x4000, 0xcf9: 0x4000, 0xcfa: 0x4000, 0xcfb: 0x4000,
+	0xcfc: 0x4000, 0xcfd: 0x4000, 0xcfe: 0x4000, 0xcff: 0x4000,
+	// Block 0x34, offset 0xd00
+	0xd00: 0x4000, 0xd01: 0x4000, 0xd02: 0x4000, 0xd03: 0x4000, 0xd04: 0x4000, 0xd05: 0x4000,
+	0xd06: 0x4000, 0xd07: 0x4000, 0xd08: 0x4000, 0xd09: 0x4000, 0xd0a: 0x4000, 0xd0b: 0x4000,
+	0xd0c: 0x4000, 0xd0d: 0x4000, 0xd0e: 0x4000, 0xd0f: 0x4000, 0xd10: 0x4000, 0xd11: 0x4000,
+	0xd12: 0x4000, 0xd13: 0x4000, 0xd14: 0x4000, 0xd15: 0x4000, 0xd16: 0x4000,
+	0xd19: 0x4016, 0xd1a: 0x4017, 0xd1b: 0x4000, 0xd1c: 0x4000, 0xd1d: 0x4000,
+	0xd1e: 0x4000, 0xd1f: 0x4000, 0xd20: 0x4000, 0xd21: 0x4018, 0xd22: 0x4019, 0xd23: 0x401a,
+	0xd24: 0x401b, 0xd25: 0x401c, 0xd26: 0x401d, 0xd27: 0x401e, 0xd28: 0x401f, 0xd29: 0x4020,
+	0xd2a: 0x4021, 0xd2b: 0x4022, 0xd2c: 0x4000, 0xd2d: 0x4010, 0xd2e: 0x4000, 0xd2f: 0x4023,
+	0xd30: 0x4000, 0xd31: 0x4024, 0xd32: 0x4000, 0xd33: 0x4025, 0xd34: 0x4000, 0xd35: 0x4026,
+	0xd36: 0x4000, 0xd37: 0x401a, 0xd38: 0x4000, 0xd39: 0x4027, 0xd3a: 0x4000, 0xd3b: 0x4028,
+	0xd3c: 0x4000, 0xd3d: 0x4020, 0xd3e: 0x4000, 0xd3f: 0x4029,
+	// Block 0x35, offset 0xd40
+	0xd40: 0x4000, 0xd41: 0x402a, 0xd42: 0x4000, 0xd43: 0x402b, 0xd44: 0x402c, 0xd45: 0x4000,
+	0xd46: 0x4017, 0xd47: 0x4000, 0xd48: 0x402d, 0xd49: 0x4000, 0xd4a: 0x402e, 0xd4b: 0x402f,
+	0xd4c: 0x4030, 0xd4d: 0x4017, 0xd4e: 0x4016, 0xd4f: 0x4017, 0xd50: 0x4000, 0xd51: 0x4000,
+	0xd52: 0x4031, 0xd53: 0x4000, 0xd54: 0x4000, 0xd55: 0x4031, 0xd56: 0x4000, 0xd57: 0x4000,
+	0xd58: 0x4032, 0xd59: 0x4000, 0xd5a: 0x4000, 0xd5b: 0x4032, 0xd5c: 0x4000, 0xd5d: 0x4000,
+	0xd5e: 0x4033, 0xd5f: 0x402e, 0xd60: 0x4034, 0xd61: 0x4035, 0xd62: 0x4034, 0xd63: 0x4036,
+	0xd64: 0x4037, 0xd65: 0x4024, 0xd66: 0x4035, 0xd67: 0x4025, 0xd68: 0x4038, 0xd69: 0x4038,
+	0xd6a: 0x4039, 0xd6b: 0x4039, 0xd6c: 0x403a, 0xd6d: 0x403a, 0xd6e: 0x4000, 0xd6f: 0x4035,
+	0xd70: 0x4000, 0xd71: 0x4000, 0xd72: 0x403b, 0xd73: 0x403c, 0xd74: 0x4000, 0xd75: 0x4000,
+	0xd76: 0x4000, 0xd77: 0x4000, 0xd78: 0x4000, 0xd79: 0x4000, 0xd7a: 0x4000, 0xd7b: 0x403d,
+	0xd7c: 0x401c, 0xd7d: 0x4000, 0xd7e: 0x4000, 0xd7f: 0x4000,
+	// Block 0x36, offset 0xd80
+	0xd85: 0x4000,
+	0xd86: 0x4000, 0xd87: 0x4000, 0xd88: 0x4000, 0xd89: 0x4000, 0xd8a: 0x4000, 0xd8b: 0x4000,
+	0xd8c: 0x4000, 0xd8d: 0x4000, 0xd8e: 0x4000, 0xd8f: 0x4000, 0xd90: 0x4000, 0xd91: 0x4000,
+	0xd92: 0x4000, 0xd93: 0x4000, 0xd94: 0x4000, 0xd95: 0x4000, 0xd96: 0x4000, 0xd97: 0x4000,
+	0xd98: 0x4000, 0xd99: 0x4000, 0xd9a: 0x4000, 0xd9b: 0x4000, 0xd9c: 0x4000, 0xd9d: 0x4000,
+	0xd9e: 0x4000, 0xd9f: 0x4000, 0xda0: 0x4000, 0xda1: 0x4000, 0xda2: 0x4000, 0xda3: 0x4000,
+	0xda4: 0x4000, 0xda5: 0x4000, 0xda6: 0x4000, 0xda7: 0x4000, 0xda8: 0x4000, 0xda9: 0x4000,
+	0xdaa: 0x4000, 0xdab: 0x4000, 0xdac: 0x4000, 0xdad: 0x4000, 0xdae: 0x4000, 0xdaf: 0x4000,
+	0xdb1: 0x403e, 0xdb2: 0x403e, 0xdb3: 0x403e, 0xdb4: 0x403e, 0xdb5: 0x403e,
+	0xdb6: 0x403e, 0xdb7: 0x403e, 0xdb8: 0x403e, 0xdb9: 0x403e, 0xdba: 0x403e, 0xdbb: 0x403e,
+	0xdbc: 0x403e, 0xdbd: 0x403e, 0xdbe: 0x403e, 0xdbf: 0x403e,
+	// Block 0x37, offset 0xdc0
+	0xdc0: 0x4037, 0xdc1: 0x4037, 0xdc2: 0x4037, 0xdc3: 0x4037, 0xdc4: 0x4037, 0xdc5: 0x4037,
+	0xdc6: 0x4037, 0xdc7: 0x4037, 0xdc8: 0x4037, 0xdc9: 0x4037, 0xdca: 0x4037, 0xdcb: 0x4037,
+	0xdcc: 0x4037, 0xdcd: 0x4037, 0xdce: 0x4037, 0xdcf: 0x400e, 0xdd0: 0x403f, 0xdd1: 0x4040,
+	0xdd2: 0x4041, 0xdd3: 0x4040, 0xdd4: 0x403f, 0xdd5: 0x4042, 0xdd6: 0x4043, 0xdd7: 0x4044,
+	0xdd8: 0x4040, 0xdd9: 0x4041, 0xdda: 0x4040, 0xddb: 0x4045, 0xddc: 0x4009, 0xddd: 0x4045,
+	0xdde: 0x4046, 0xddf: 0x4045, 0xde0: 0x4047, 0xde1: 0x400b, 0xde2: 0x400a, 0xde3: 0x400c,
+	0xde4: 0x4048, 0xde5: 0x4000, 0xde6: 0x4000, 0xde7: 0x4000, 0xde8: 0x4000, 0xde9: 0x4000,
+	0xdea: 0x4000, 0xdeb: 0x4000, 0xdec: 0x4000, 0xded: 0x4000, 0xdee: 0x4000, 0xdef: 0x4000,
+	0xdf0: 0x4000, 0xdf1: 0x4000, 0xdf2: 0x4000, 0xdf3: 0x4000, 0xdf4: 0x4000, 0xdf5: 0x4000,
+	0xdf6: 0x4000, 0xdf7: 0x4000, 0xdf8: 0x4000, 0xdf9: 0x4000, 0xdfa: 0x4000, 0xdfb: 0x4000,
+	0xdfc: 0x4000, 0xdfd: 0x4000, 0xdfe: 0x4000, 0xdff: 0x4000,
+	// Block 0x38, offset 0xe00
+	0xe00: 0x4000, 0xe01: 0x4000, 0xe02: 0x4000, 0xe03: 0x4000, 0xe04: 0x4000, 0xe05: 0x4000,
+	0xe06: 0x4000, 0xe07: 0x4000, 0xe08: 0x4000, 0xe09: 0x4000, 0xe0a: 0x4000, 0xe0b: 0x4000,
+	0xe0c: 0x4000, 0xe0d: 0x4000, 0xe0e: 0x4000, 0xe10: 0x4000, 0xe11: 0x4000,
+	0xe12: 0x4000, 0xe13: 0x4000, 0xe14: 0x4000, 0xe15: 0x4000, 0xe16: 0x4000, 0xe17: 0x4000,
+	0xe18: 0x4000, 0xe19: 0x4000, 0xe1a: 0x4000, 0xe1b: 0x4000, 0xe1c: 0x4000, 0xe1d: 0x4000,
+	0xe1e: 0x4000, 0xe1f: 0x4000, 0xe20: 0x4000, 0xe21: 0x4000, 0xe22: 0x4000, 0xe23: 0x4000,
+	0xe24: 0x4000, 0xe25: 0x4000, 0xe26: 0x4000, 0xe27: 0x4000, 0xe28: 0x4000, 0xe29: 0x4000,
+	0xe2a: 0x4000, 0xe2b: 0x4000, 0xe2c: 0x4000, 0xe2d: 0x4000, 0xe2e: 0x4000, 0xe2f: 0x4000,
+	0xe30: 0x4000, 0xe31: 0x4000, 0xe32: 0x4000, 0xe33: 0x4000, 0xe34: 0x4000, 0xe35: 0x4000,
+	0xe36: 0x4000, 0xe37: 0x4000, 0xe38: 0x4000, 0xe39: 0x4000, 0xe3a: 0x4000, 0xe3b: 0x4000,
+	0xe3c: 0x4000, 0xe3d: 0x4000, 0xe3e: 0x4000, 0xe3f: 0x4000,
+	// Block 0x39, offset 0xe40
+	0xe40: 0x4000, 0xe41: 0x4000, 0xe42: 0x4000, 0xe43: 0x4000, 0xe44: 0x4000, 0xe45: 0x4000,
+	0xe46: 0x4000, 0xe47: 0x4000, 0xe48: 0x4000, 0xe49: 0x4000, 0xe4a: 0x4000, 0xe4b: 0x4000,
+	0xe4c: 0x4000, 0xe4d: 0x4000, 0xe4e: 0x4000, 0xe4f: 0x4000, 0xe50: 0x4000, 0xe51: 0x4000,
+	0xe52: 0x4000, 0xe53: 0x4000, 0xe54: 0x4000, 0xe55: 0x4000, 0xe56: 0x4000, 0xe57: 0x4000,
+	0xe58: 0x4000, 0xe59: 0x4000, 0xe5a: 0x4000, 0xe5b: 0x4000, 0xe5c: 0x4000, 0xe5d: 0x4000,
+	0xe5e: 0x4000, 0xe5f: 0x4000, 0xe60: 0x4000, 0xe61: 0x4000, 0xe62: 0x4000, 0xe63: 0x4000,
+	0xe70: 0x4000, 0xe71: 0x4000, 0xe72: 0x4000, 0xe73: 0x4000, 0xe74: 0x4000, 0xe75: 0x4000,
+	0xe76: 0x4000, 0xe77: 0x4000, 0xe78: 0x4000, 0xe79: 0x4000, 0xe7a: 0x4000, 0xe7b: 0x4000,
+	0xe7c: 0x4000, 0xe7d: 0x4000, 0xe7e: 0x4000, 0xe7f: 0x4000,
+	// Block 0x3a, offset 0xe80
+	0xe80: 0x4000, 0xe81: 0x4000, 0xe82: 0x4000, 0xe83: 0x4000, 0xe84: 0x4000, 0xe85: 0x4000,
+	0xe86: 0x4000, 0xe87: 0x4000, 0xe88: 0x4000, 0xe89: 0x4000, 0xe8a: 0x4000, 0xe8b: 0x4000,
+	0xe8c: 0x4000, 0xe8d: 0x4000, 0xe8e: 0x4000, 0xe8f: 0x4000, 0xe90: 0x4000, 0xe91: 0x4000,
+	0xe92: 0x4000, 0xe93: 0x4000, 0xe94: 0x4000, 0xe95: 0x4000, 0xe96: 0x4000, 0xe97: 0x4000,
+	0xe98: 0x4000, 0xe99: 0x4000, 0xe9a: 0x4000, 0xe9b: 0x4000, 0xe9c: 0x4000, 0xe9d: 0x4000,
+	0xe9e: 0x4000, 0xea0: 0x4000, 0xea1: 0x4000, 0xea2: 0x4000, 0xea3: 0x4000,
+	0xea4: 0x4000, 0xea5: 0x4000, 0xea6: 0x4000, 0xea7: 0x4000, 0xea8: 0x4000, 0xea9: 0x4000,
+	0xeaa: 0x4000, 0xeab: 0x4000, 0xeac: 0x4000, 0xead: 0x4000, 0xeae: 0x4000, 0xeaf: 0x4000,
+	0xeb0: 0x4000, 0xeb1: 0x4000, 0xeb2: 0x4000, 0xeb3: 0x4000, 0xeb4: 0x4000, 0xeb5: 0x4000,
+	0xeb6: 0x4000, 0xeb7: 0x4000, 0xeb8: 0x4000, 0xeb9: 0x4000, 0xeba: 0x4000, 0xebb: 0x4000,
+	0xebc: 0x4000, 0xebd: 0x4000, 0xebe: 0x4000, 0xebf: 0x4000,
+	// Block 0x3b, offset 0xec0
+	0xec0: 0x4000, 0xec1: 0x4000, 0xec2: 0x4000, 0xec3: 0x4000, 0xec4: 0x4000, 0xec5: 0x4000,
+	0xec6: 0x4000, 0xec7: 0x4000, 0xec8: 0x2000, 0xec9: 0x2000, 0xeca: 0x2000, 0xecb: 0x2000,
+	0xecc: 0x2000, 0xecd: 0x2000, 0xece: 0x2000, 0xecf: 0x2000, 0xed0: 0x4000, 0xed1: 0x4000,
+	0xed2: 0x4000, 0xed3: 0x4000, 0xed4: 0x4000, 0xed5: 0x4000, 0xed6: 0x4000, 0xed7: 0x4000,
+	0xed8: 0x4000, 0xed9: 0x4000, 0xeda: 0x4000, 0xedb: 0x4000, 0xedc: 0x4000, 0xedd: 0x4000,
+	0xede: 0x4000, 0xedf: 0x4000, 0xee0: 0x4000, 0xee1: 0x4000, 0xee2: 0x4000, 0xee3: 0x4000,
+	0xee4: 0x4000, 0xee5: 0x4000, 0xee6: 0x4000, 0xee7: 0x4000, 0xee8: 0x4000, 0xee9: 0x4000,
+	0xeea: 0x4000, 0xeeb: 0x4000, 0xeec: 0x4000, 0xeed: 0x4000, 0xeee: 0x4000, 0xeef: 0x4000,
+	0xef0: 0x4000, 0xef1: 0x4000, 0xef2: 0x4000, 0xef3: 0x4000, 0xef4: 0x4000, 0xef5: 0x4000,
+	0xef6: 0x4000, 0xef7: 0x4000, 0xef8: 0x4000, 0xef9: 0x4000, 0xefa: 0x4000, 0xefb: 0x4000,
+	0xefc: 0x4000, 0xefd: 0x4000, 0xefe: 0x4000, 0xeff: 0x4000,
+	// Block 0x3c, offset 0xf00
+	0xf00: 0x4000, 0xf01: 0x4000, 0xf02: 0x4000, 0xf03: 0x4000, 0xf04: 0x4000, 0xf05: 0x4000,
+	0xf06: 0x4000, 0xf07: 0x4000, 0xf08: 0x4000, 0xf09: 0x4000, 0xf0a: 0x4000, 0xf0b: 0x4000,
+	0xf0c: 0x4000, 0xf10: 0x4000, 0xf11: 0x4000,
+	0xf12: 0x4000, 0xf13: 0x4000, 0xf14: 0x4000, 0xf15: 0x4000, 0xf16: 0x4000, 0xf17: 0x4000,
+	0xf18: 0x4000, 0xf19: 0x4000, 0xf1a: 0x4000, 0xf1b: 0x4000, 0xf1c: 0x4000, 0xf1d: 0x4000,
+	0xf1e: 0x4000, 0xf1f: 0x4000, 0xf20: 0x4000, 0xf21: 0x4000, 0xf22: 0x4000, 0xf23: 0x4000,
+	0xf24: 0x4000, 0xf25: 0x4000, 0xf26: 0x4000, 0xf27: 0x4000, 0xf28: 0x4000, 0xf29: 0x4000,
+	0xf2a: 0x4000, 0xf2b: 0x4000, 0xf2c: 0x4000, 0xf2d: 0x4000, 0xf2e: 0x4000, 0xf2f: 0x4000,
+	0xf30: 0x4000, 0xf31: 0x4000, 0xf32: 0x4000, 0xf33: 0x4000, 0xf34: 0x4000, 0xf35: 0x4000,
+	0xf36: 0x4000, 0xf37: 0x4000, 0xf38: 0x4000, 0xf39: 0x4000, 0xf3a: 0x4000, 0xf3b: 0x4000,
+	0xf3c: 0x4000, 0xf3d: 0x4000, 0xf3e: 0x4000, 0xf3f: 0x4000,
+	// Block 0x3d, offset 0xf40
+	0xf40: 0x4000, 0xf41: 0x4000, 0xf42: 0x4000, 0xf43: 0x4000, 0xf44: 0x4000, 0xf45: 0x4000,
+	0xf46: 0x4000,
+	// Block 0x3e, offset 0xf80
+	0xfa0: 0x4000, 0xfa1: 0x4000, 0xfa2: 0x4000, 0xfa3: 0x4000,
+	0xfa4: 0x4000, 0xfa5: 0x4000, 0xfa6: 0x4000, 0xfa7: 0x4000, 0xfa8: 0x4000, 0xfa9: 0x4000,
+	0xfaa: 0x4000, 0xfab: 0x4000, 0xfac: 0x4000, 0xfad: 0x4000, 0xfae: 0x4000, 0xfaf: 0x4000,
+	0xfb0: 0x4000, 0xfb1: 0x4000, 0xfb2: 0x4000, 0xfb3: 0x4000, 0xfb4: 0x4000, 0xfb5: 0x4000,
+	0xfb6: 0x4000, 0xfb7: 0x4000, 0xfb8: 0x4000, 0xfb9: 0x4000, 0xfba: 0x4000, 0xfbb: 0x4000,
+	0xfbc: 0x4000,
+	// Block 0x3f, offset 0xfc0
+	0xfc0: 0x4000, 0xfc1: 0x4000, 0xfc2: 0x4000, 0xfc3: 0x4000, 0xfc4: 0x4000, 0xfc5: 0x4000,
+	0xfc6: 0x4000, 0xfc7: 0x4000, 0xfc8: 0x4000, 0xfc9: 0x4000, 0xfca: 0x4000, 0xfcb: 0x4000,
+	0xfcc: 0x4000, 0xfcd: 0x4000, 0xfce: 0x4000, 0xfcf: 0x4000, 0xfd0: 0x4000, 0xfd1: 0x4000,
+	0xfd2: 0x4000, 0xfd3: 0x4000, 0xfd4: 0x4000, 0xfd5: 0x4000, 0xfd6: 0x4000, 0xfd7: 0x4000,
+	0xfd8: 0x4000, 0xfd9: 0x4000, 0xfda: 0x4000, 0xfdb: 0x4000, 0xfdc: 0x4000, 0xfdd: 0x4000,
+	0xfde: 0x4000, 0xfdf: 0x4000, 0xfe0: 0x4000, 0xfe1: 0x4000, 0xfe2: 0x4000, 0xfe3: 0x4000,
+	// Block 0x40, offset 0x1000
+	0x1000: 0x2000, 0x1001: 0x2000, 0x1002: 0x2000, 0x1003: 0x2000, 0x1004: 0x2000, 0x1005: 0x2000,
+	0x1006: 0x2000, 0x1007: 0x2000, 0x1008: 0x2000, 0x1009: 0x2000, 0x100a: 0x2000, 0x100b: 0x2000,
+	0x100c: 0x2000, 0x100d: 0x2000, 0x100e: 0x2000, 0x100f: 0x2000, 0x1010: 0x4000, 0x1011: 0x4000,
+	0x1012: 0x4000, 0x1013: 0x4000, 0x1014: 0x4000, 0x1015: 0x4000, 0x1016: 0x4000, 0x1017: 0x4000,
+	0x1018: 0x4000, 0x1019: 0x4000,
+	0x1030: 0x4000, 0x1031: 0x4000, 0x1032: 0x4000, 0x1033: 0x4000, 0x1034: 0x4000, 0x1035: 0x4000,
+	0x1036: 0x4000, 0x1037: 0x4000, 0x1038: 0x4000, 0x1039: 0x4000, 0x103a: 0x4000, 0x103b: 0x4000,
+	0x103c: 0x4000, 0x103d: 0x4000, 0x103e: 0x4000, 0x103f: 0x4000,
+	// Block 0x41, offset 0x1040
+	0x1040: 0x4000, 0x1041: 0x4000, 0x1042: 0x4000, 0x1043: 0x4000, 0x1044: 0x4000, 0x1045: 0x4000,
+	0x1046: 0x4000, 0x1047: 0x4000, 0x1048: 0x4000, 0x1049: 0x4000, 0x104a: 0x4000, 0x104b: 0x4000,
+	0x104c: 0x4000, 0x104d: 0x4000, 0x104e: 0x4000, 0x104f: 0x4000, 0x1050: 0x4000, 0x1051: 0x4000,
+	0x1052: 0x4000, 0x1054: 0x4000, 0x1055: 0x4000, 0x1056: 0x4000, 0x1057: 0x4000,
+	0x1058: 0x4000, 0x1059: 0x4000, 0x105a: 0x4000, 0x105b: 0x4000, 0x105c: 0x4000, 0x105d: 0x4000,
+	0x105e: 0x4000, 0x105f: 0x4000, 0x1060: 0x4000, 0x1061: 0x4000, 0x1062: 0x4000, 0x1063: 0x4000,
+	0x1064: 0x4000, 0x1065: 0x4000, 0x1066: 0x4000, 0x1068: 0x4000, 0x1069: 0x4000,
+	0x106a: 0x4000, 0x106b: 0x4000,
+	// Block 0x42, offset 0x1080
+	0x1081: 0x9012, 0x1082: 0x9012, 0x1083: 0x9012, 0x1084: 0x9012, 0x1085: 0x9012,
+	0x1086: 0x9012, 0x1087: 0x9012, 0x1088: 0x9012, 0x1089: 0x9012, 0x108a: 0x9012, 0x108b: 0x9012,
+	0x108c: 0x9012, 0x108d: 0x9012, 0x108e: 0x9012, 0x108f: 0x9012, 0x1090: 0x9012, 0x1091: 0x9012,
+	0x1092: 0x9012, 0x1093: 0x9012, 0x1094: 0x9012, 0x1095: 0x9012, 0x1096: 0x9012, 0x1097: 0x9012,
+	0x1098: 0x9012, 0x1099: 0x9012, 0x109a: 0x9012, 0x109b: 0x9012, 0x109c: 0x9012, 0x109d: 0x9012,
+	0x109e: 0x9012, 0x109f: 0x9012, 0x10a0: 0x9049, 0x10a1: 0x9049, 0x10a2: 0x9049, 0x10a3: 0x9049,
+	0x10a4: 0x9049, 0x10a5: 0x9049, 0x10a6: 0x9049, 0x10a7: 0x9049, 0x10a8: 0x9049, 0x10a9: 0x9049,
+	0x10aa: 0x9049, 0x10ab: 0x9049, 0x10ac: 0x9049, 0x10ad: 0x9049, 0x10ae: 0x9049, 0x10af: 0x9049,
+	0x10b0: 0x9049, 0x10b1: 0x9049, 0x10b2: 0x9049, 0x10b3: 0x9049, 0x10b4: 0x9049, 0x10b5: 0x9049,
+	0x10b6: 0x9049, 0x10b7: 0x9049, 0x10b8: 0x9049, 0x10b9: 0x9049, 0x10ba: 0x9049, 0x10bb: 0x9049,
+	0x10bc: 0x9049, 0x10bd: 0x9049, 0x10be: 0x9049, 0x10bf: 0x9049,
+	// Block 0x43, offset 0x10c0
+	0x10c0: 0x9049, 0x10c1: 0x9049, 0x10c2: 0x9049, 0x10c3: 0x9049, 0x10c4: 0x9049, 0x10c5: 0x9049,
+	0x10c6: 0x9049, 0x10c7: 0x9049, 0x10c8: 0x9049, 0x10c9: 0x9049, 0x10ca: 0x9049, 0x10cb: 0x9049,
+	0x10cc: 0x9049, 0x10cd: 0x9049, 0x10ce: 0x9049, 0x10cf: 0x9049, 0x10d0: 0x9049, 0x10d1: 0x9049,
+	0x10d2: 0x9049, 0x10d3: 0x9049, 0x10d4: 0x9049, 0x10d5: 0x9049, 0x10d6: 0x9049, 0x10d7: 0x9049,
+	0x10d8: 0x9049, 0x10d9: 0x9049, 0x10da: 0x9049, 0x10db: 0x9049, 0x10dc: 0x9049, 0x10dd: 0x9049,
+	0x10de: 0x9049, 0x10df: 0x904a, 0x10e0: 0x904b, 0x10e1: 0xb04c, 0x10e2: 0xb04d, 0x10e3: 0xb04d,
+	0x10e4: 0xb04e, 0x10e5: 0xb04f, 0x10e6: 0xb050, 0x10e7: 0xb051, 0x10e8: 0xb052, 0x10e9: 0xb053,
+	0x10ea: 0xb054, 0x10eb: 0xb055, 0x10ec: 0xb056, 0x10ed: 0xb057, 0x10ee: 0xb058, 0x10ef: 0xb059,
+	0x10f0: 0xb05a, 0x10f1: 0xb05b, 0x10f2: 0xb05c, 0x10f3: 0xb05d, 0x10f4: 0xb05e, 0x10f5: 0xb05f,
+	0x10f6: 0xb060, 0x10f7: 0xb061, 0x10f8: 0xb062, 0x10f9: 0xb063, 0x10fa: 0xb064, 0x10fb: 0xb065,
+	0x10fc: 0xb052, 0x10fd: 0xb066, 0x10fe: 0xb067, 0x10ff: 0xb055,
+	// Block 0x44, offset 0x1100
+	0x1100: 0xb068, 0x1101: 0xb069, 0x1102: 0xb06a, 0x1103: 0xb06b, 0x1104: 0xb05a, 0x1105: 0xb056,
+	0x1106: 0xb06c, 0x1107: 0xb06d, 0x1108: 0xb06b, 0x1109: 0xb06e, 0x110a: 0xb06b, 0x110b: 0xb06f,
+	0x110c: 0xb06f, 0x110d: 0xb070, 0x110e: 0xb070, 0x110f: 0xb071, 0x1110: 0xb056, 0x1111: 0xb072,
+	0x1112: 0xb073, 0x1113: 0xb072, 0x1114: 0xb074, 0x1115: 0xb073, 0x1116: 0xb075, 0x1117: 0xb075,
+	0x1118: 0xb076, 0x1119: 0xb076, 0x111a: 0xb077, 0x111b: 0xb077, 0x111c: 0xb073, 0x111d: 0xb078,
+	0x111e: 0xb079, 0x111f: 0xb067, 0x1120: 0xb07a, 0x1121: 0xb07b, 0x1122: 0xb07b, 0x1123: 0xb07b,
+	0x1124: 0xb07b, 0x1125: 0xb07b, 0x1126: 0xb07b, 0x1127: 0xb07b, 0x1128: 0xb07b, 0x1129: 0xb07b,
+	0x112a: 0xb07b, 0x112b: 0xb07b, 0x112c: 0xb07b, 0x112d: 0xb07b, 0x112e: 0xb07b, 0x112f: 0xb07b,
+	0x1130: 0xb07c, 0x1131: 0xb07c, 0x1132: 0xb07c, 0x1133: 0xb07c, 0x1134: 0xb07c, 0x1135: 0xb07c,
+	0x1136: 0xb07c, 0x1137: 0xb07c, 0x1138: 0xb07c, 0x1139: 0xb07c, 0x113a: 0xb07c, 0x113b: 0xb07c,
+	0x113c: 0xb07c, 0x113d: 0xb07c, 0x113e: 0xb07c,
+	// Block 0x45, offset 0x1140
+	0x1142: 0xb07d, 0x1143: 0xb07e, 0x1144: 0xb07f, 0x1145: 0xb080,
+	0x1146: 0xb07f, 0x1147: 0xb07e, 0x114a: 0xb081, 0x114b: 0xb082,
+	0x114c: 0xb083, 0x114d: 0xb07f, 0x114e: 0xb080, 0x114f: 0xb07f,
+	0x1152: 0xb084, 0x1153: 0xb085, 0x1154: 0xb084, 0x1155: 0xb086, 0x1156: 0xb084, 0x1157: 0xb087,
+	0x115a: 0xb088, 0x115b: 0xb089, 0x115c: 0xb08a,
+	0x1160: 0x908b, 0x1161: 0x908b, 0x1162: 0x908c, 0x1163: 0x908d,
+	0x1164: 0x908b, 0x1165: 0x908e, 0x1166: 0x908f, 0x1168: 0xb090, 0x1169: 0xb091,
+	0x116a: 0xb092, 0x116b: 0xb091, 0x116c: 0xb093, 0x116d: 0xb094, 0x116e: 0xb095,
+	0x117d: 0x2000,
+	// Block 0x46, offset 0x1180
+	0x11a0: 0x4000, 0x11a1: 0x4000, 0x11a2: 0x4000, 0x11a3: 0x4000,
+	0x11a4: 0x4000,
+	0x11b0: 0x4000, 0x11b1: 0x4000,
+	// Block 0x47, offset 0x11c0
+	0x11c0: 0x4000, 0x11c1: 0x4000, 0x11c2: 0x4000, 0x11c3: 0x4000, 0x11c4: 0x4000, 0x11c5: 0x4000,
+	0x11c6: 0x4000, 0x11c7: 0x4000, 0x11c8: 0x4000, 0x11c9: 0x4000, 0x11ca: 0x4000, 0x11cb: 0x4000,
+	0x11cc: 0x4000, 0x11cd: 0x4000, 0x11ce: 0x4000, 0x11cf: 0x4000, 0x11d0: 0x4000, 0x11d1: 0x4000,
+	0x11d2: 0x4000, 0x11d3: 0x4000, 0x11d4: 0x4000, 0x11d5: 0x4000, 0x11d6: 0x4000, 0x11d7: 0x4000,
+	0x11d8: 0x4000, 0x11d9: 0x4000, 0x11da: 0x4000, 0x11db: 0x4000, 0x11dc: 0x4000, 0x11dd: 0x4000,
+	0x11de: 0x4000, 0x11df: 0x4000, 0x11e0: 0x4000, 0x11e1: 0x4000, 0x11e2: 0x4000, 0x11e3: 0x4000,
+	0x11e4: 0x4000, 0x11e5: 0x4000, 0x11e6: 0x4000, 0x11e7: 0x4000, 0x11e8: 0x4000, 0x11e9: 0x4000,
+	0x11ea: 0x4000, 0x11eb: 0x4000, 0x11ec: 0x4000, 0x11ed: 0x4000, 0x11ee: 0x4000, 0x11ef: 0x4000,
+	0x11f0: 0x4000, 0x11f1: 0x4000, 0x11f2: 0x4000, 0x11f3: 0x4000, 0x11f4: 0x4000, 0x11f5: 0x4000,
+	0x11f6: 0x4000, 0x11f7: 0x4000,
+	// Block 0x48, offset 0x1200
+	0x1200: 0x4000, 0x1201: 0x4000, 0x1202: 0x4000, 0x1203: 0x4000, 0x1204: 0x4000, 0x1205: 0x4000,
+	0x1206: 0x4000, 0x1207: 0x4000, 0x1208: 0x4000, 0x1209: 0x4000, 0x120a: 0x4000, 0x120b: 0x4000,
+	0x120c: 0x4000, 0x120d: 0x4000, 0x120e: 0x4000, 0x120f: 0x4000, 0x1210: 0x4000, 0x1211: 0x4000,
+	0x1212: 0x4000, 0x1213: 0x4000, 0x1214: 0x4000, 0x1215: 0x4000,
+	// Block 0x49, offset 0x1240
+	0x1240: 0x4000, 0x1241: 0x4000, 0x1242: 0x4000, 0x1243: 0x4000, 0x1244: 0x4000, 0x1245: 0x4000,
+	0x1246: 0x4000, 0x1247: 0x4000, 0x1248: 0x4000,
+	// Block 0x4a, offset 0x1280
+	0x12b0: 0x4000, 0x12b1: 0x4000, 0x12b2: 0x4000, 0x12b3: 0x4000, 0x12b5: 0x4000,
+	0x12b6: 0x4000, 0x12b7: 0x4000, 0x12b8: 0x4000, 0x12b9: 0x4000, 0x12ba: 0x4000, 0x12bb: 0x4000,
+	0x12bd: 0x4000, 0x12be: 0x4000,
+	// Block 0x4b, offset 0x12c0
+	0x12c0: 0x4000, 0x12c1: 0x4000, 0x12c2: 0x4000, 0x12c3: 0x4000, 0x12c4: 0x4000, 0x12c5: 0x4000,
+	0x12c6: 0x4000, 0x12c7: 0x4000, 0x12c8: 0x4000, 0x12c9: 0x4000, 0x12ca: 0x4000, 0x12cb: 0x4000,
+	0x12cc: 0x4000, 0x12cd: 0x4000, 0x12ce: 0x4000, 0x12cf: 0x4000, 0x12d0: 0x4000, 0x12d1: 0x4000,
+	0x12d2: 0x4000, 0x12d3: 0x4000, 0x12d4: 0x4000, 0x12d5: 0x4000, 0x12d6: 0x4000, 0x12d7: 0x4000,
+	0x12d8: 0x4000, 0x12d9: 0x4000, 0x12da: 0x4000, 0x12db: 0x4000, 0x12dc: 0x4000, 0x12dd: 0x4000,
+	0x12de: 0x4000, 0x12df: 0x4000, 0x12e0: 0x4000, 0x12e1: 0x4000, 0x12e2: 0x4000,
+	0x12f2: 0x4000,
+	// Block 0x4c, offset 0x1300
+	0x1310: 0x4000, 0x1311: 0x4000,
+	0x1312: 0x4000, 0x1315: 0x4000,
+	0x1324: 0x4000, 0x1325: 0x4000, 0x1326: 0x4000, 0x1327: 0x4000,
+	0x1330: 0x4000, 0x1331: 0x4000, 0x1332: 0x4000, 0x1333: 0x4000, 0x1334: 0x4000, 0x1335: 0x4000,
+	0x1336: 0x4000, 0x1337: 0x4000, 0x1338: 0x4000, 0x1339: 0x4000, 0x133a: 0x4000, 0x133b: 0x4000,
+	0x133c: 0x4000, 0x133d: 0x4000, 0x133e: 0x4000, 0x133f: 0x4000,
+	// Block 0x4d, offset 0x1340
+	0x1340: 0x4000, 0x1341: 0x4000, 0x1342: 0x4000, 0x1343: 0x4000, 0x1344: 0x4000, 0x1345: 0x4000,
+	0x1346: 0x4000, 0x1347: 0x4000, 0x1348: 0x4000, 0x1349: 0x4000, 0x134a: 0x4000, 0x134b: 0x4000,
+	0x134c: 0x4000, 0x134d: 0x4000, 0x134e: 0x4000, 0x134f: 0x4000, 0x1350: 0x4000, 0x1351: 0x4000,
+	0x1352: 0x4000, 0x1353: 0x4000, 0x1354: 0x4000, 0x1355: 0x4000, 0x1356: 0x4000, 0x1357: 0x4000,
+	0x1358: 0x4000, 0x1359: 0x4000, 0x135a: 0x4000, 0x135b: 0x4000, 0x135c: 0x4000, 0x135d: 0x4000,
+	0x135e: 0x4000, 0x135f: 0x4000, 0x1360: 0x4000, 0x1361: 0x4000, 0x1362: 0x4000, 0x1363: 0x4000,
+	0x1364: 0x4000, 0x1365: 0x4000, 0x1366: 0x4000, 0x1367: 0x4000, 0x1368: 0x4000, 0x1369: 0x4000,
+	0x136a: 0x4000, 0x136b: 0x4000, 0x136c: 0x4000, 0x136d: 0x4000, 0x136e: 0x4000, 0x136f: 0x4000,
+	0x1370: 0x4000, 0x1371: 0x4000, 0x1372: 0x4000, 0x1373: 0x4000, 0x1374: 0x4000, 0x1375: 0x4000,
+	0x1376: 0x4000, 0x1377: 0x4000, 0x1378: 0x4000, 0x1379: 0x4000, 0x137a: 0x4000, 0x137b: 0x4000,
+	// Block 0x4e, offset 0x1380
+	0x1384: 0x4000,
+	// Block 0x4f, offset 0x13c0
+	0x13cf: 0x4000,
+	// Block 0x50, offset 0x1400
+	0x1400: 0x2000, 0x1401: 0x2000, 0x1402: 0x2000, 0x1403: 0x2000, 0x1404: 0x2000, 0x1405: 0x2000,
+	0x1406: 0x2000, 0x1407: 0x2000, 0x1408: 0x2000, 0x1409: 0x2000, 0x140a: 0x2000,
+	0x1410: 0x2000, 0x1411: 0x2000,
+	0x1412: 0x2000, 0x1413: 0x2000, 0x1414: 0x2000, 0x1415: 0x2000, 0x1416: 0x2000, 0x1417: 0x2000,
+	0x1418: 0x2000, 0x1419: 0x2000, 0x141a: 0x2000, 0x141b: 0x2000, 0x141c: 0x2000, 0x141d: 0x2000,
+	0x141e: 0x2000, 0x141f: 0x2000, 0x1420: 0x2000, 0x1421: 0x2000, 0x1422: 0x2000, 0x1423: 0x2000,
+	0x1424: 0x2000, 0x1425: 0x2000, 0x1426: 0x2000, 0x1427: 0x2000, 0x1428: 0x2000, 0x1429: 0x2000,
+	0x142a: 0x2000, 0x142b: 0x2000, 0x142c: 0x2000, 0x142d: 0x2000,
+	0x1430: 0x2000, 0x1431: 0x2000, 0x1432: 0x2000, 0x1433: 0x2000, 0x1434: 0x2000, 0x1435: 0x2000,
+	0x1436: 0x2000, 0x1437: 0x2000, 0x1438: 0x2000, 0x1439: 0x2000, 0x143a: 0x2000, 0x143b: 0x2000,
+	0x143c: 0x2000, 0x143d: 0x2000, 0x143e: 0x2000, 0x143f: 0x2000,
+	// Block 0x51, offset 0x1440
+	0x1440: 0x2000, 0x1441: 0x2000, 0x1442: 0x2000, 0x1443: 0x2000, 0x1444: 0x2000, 0x1445: 0x2000,
+	0x1446: 0x2000, 0x1447: 0x2000, 0x1448: 0x2000, 0x1449: 0x2000, 0x144a: 0x2000, 0x144b: 0x2000,
+	0x144c: 0x2000, 0x144d: 0x2000, 0x144e: 0x2000, 0x144f: 0x2000, 0x1450: 0x2000, 0x1451: 0x2000,
+	0x1452: 0x2000, 0x1453: 0x2000, 0x1454: 0x2000, 0x1455: 0x2000, 0x1456: 0x2000, 0x1457: 0x2000,
+	0x1458: 0x2000, 0x1459: 0x2000, 0x145a: 0x2000, 0x145b: 0x2000, 0x145c: 0x2000, 0x145d: 0x2000,
+	0x145e: 0x2000, 0x145f: 0x2000, 0x1460: 0x2000, 0x1461: 0x2000, 0x1462: 0x2000, 0x1463: 0x2000,
+	0x1464: 0x2000, 0x1465: 0x2000, 0x1466: 0x2000, 0x1467: 0x2000, 0x1468: 0x2000, 0x1469: 0x2000,
+	0x1470: 0x2000, 0x1471: 0x2000, 0x1472: 0x2000, 0x1473: 0x2000, 0x1474: 0x2000, 0x1475: 0x2000,
+	0x1476: 0x2000, 0x1477: 0x2000, 0x1478: 0x2000, 0x1479: 0x2000, 0x147a: 0x2000, 0x147b: 0x2000,
+	0x147c: 0x2000, 0x147d: 0x2000, 0x147e: 0x2000, 0x147f: 0x2000,
+	// Block 0x52, offset 0x1480
+	0x1480: 0x2000, 0x1481: 0x2000, 0x1482: 0x2000, 0x1483: 0x2000, 0x1484: 0x2000, 0x1485: 0x2000,
+	0x1486: 0x2000, 0x1487: 0x2000, 0x1488: 0x2000, 0x1489: 0x2000, 0x148a: 0x2000, 0x148b: 0x2000,
+	0x148c: 0x2000, 0x148d: 0x2000, 0x148e: 0x4000, 0x148f: 0x2000, 0x1490: 0x2000, 0x1491: 0x4000,
+	0x1492: 0x4000, 0x1493: 0x4000, 0x1494: 0x4000, 0x1495: 0x4000, 0x1496: 0x4000, 0x1497: 0x4000,
+	0x1498: 0x4000, 0x1499: 0x4000, 0x149a: 0x4000, 0x149b: 0x2000, 0x149c: 0x2000, 0x149d: 0x2000,
+	0x149e: 0x2000, 0x149f: 0x2000, 0x14a0: 0x2000, 0x14a1: 0x2000, 0x14a2: 0x2000, 0x14a3: 0x2000,
+	0x14a4: 0x2000, 0x14a5: 0x2000, 0x14a6: 0x2000, 0x14a7: 0x2000, 0x14a8: 0x2000, 0x14a9: 0x2000,
+	0x14aa: 0x2000, 0x14ab: 0x2000, 0x14ac: 0x2000,
+	// Block 0x53, offset 0x14c0
+	0x14c0: 0x4000, 0x14c1: 0x4000, 0x14c2: 0x4000,
+	0x14d0: 0x4000, 0x14d1: 0x4000,
+	0x14d2: 0x4000, 0x14d3: 0x4000, 0x14d4: 0x4000, 0x14d5: 0x4000, 0x14d6: 0x4000, 0x14d7: 0x4000,
+	0x14d8: 0x4000, 0x14d9: 0x4000, 0x14da: 0x4000, 0x14db: 0x4000, 0x14dc: 0x4000, 0x14dd: 0x4000,
+	0x14de: 0x4000, 0x14df: 0x4000, 0x14e0: 0x4000, 0x14e1: 0x4000, 0x14e2: 0x4000, 0x14e3: 0x4000,
+	0x14e4: 0x4000, 0x14e5: 0x4000, 0x14e6: 0x4000, 0x14e7: 0x4000, 0x14e8: 0x4000, 0x14e9: 0x4000,
+	0x14ea: 0x4000, 0x14eb: 0x4000, 0x14ec: 0x4000, 0x14ed: 0x4000, 0x14ee: 0x4000, 0x14ef: 0x4000,
+	0x14f0: 0x4000, 0x14f1: 0x4000, 0x14f2: 0x4000, 0x14f3: 0x4000, 0x14f4: 0x4000, 0x14f5: 0x4000,
+	0x14f6: 0x4000, 0x14f7: 0x4000, 0x14f8: 0x4000, 0x14f9: 0x4000, 0x14fa: 0x4000, 0x14fb: 0x4000,
+	// Block 0x54, offset 0x1500
+	0x1500: 0x4000, 0x1501: 0x4000, 0x1502: 0x4000, 0x1503: 0x4000, 0x1504: 0x4000, 0x1505: 0x4000,
+	0x1506: 0x4000, 0x1507: 0x4000, 0x1508: 0x4000,
+	0x1510: 0x4000, 0x1511: 0x4000,
+	0x1520: 0x4000, 0x1521: 0x4000, 0x1522: 0x4000, 0x1523: 0x4000,
+	0x1524: 0x4000, 0x1525: 0x4000,
+	// Block 0x55, offset 0x1540
+	0x1540: 0x4000, 0x1541: 0x4000, 0x1542: 0x4000, 0x1543: 0x4000, 0x1544: 0x4000, 0x1545: 0x4000,
+	0x1546: 0x4000, 0x1547: 0x4000, 0x1548: 0x4000, 0x1549: 0x4000, 0x154a: 0x4000, 0x154b: 0x4000,
+	0x154c: 0x4000, 0x154d: 0x4000, 0x154e: 0x4000, 0x154f: 0x4000, 0x1550: 0x4000, 0x1551: 0x4000,
+	0x1552: 0x4000, 0x1553: 0x4000, 0x1554: 0x4000, 0x1555: 0x4000, 0x1556: 0x4000, 0x1557: 0x4000,
+	0x1558: 0x4000, 0x1559: 0x4000, 0x155a: 0x4000, 0x155b: 0x4000, 0x155c: 0x4000, 0x155d: 0x4000,
+	0x155e: 0x4000, 0x155f: 0x4000, 0x1560: 0x4000,
+	0x156d: 0x4000, 0x156e: 0x4000, 0x156f: 0x4000,
+	0x1570: 0x4000, 0x1571: 0x4000, 0x1572: 0x4000, 0x1573: 0x4000, 0x1574: 0x4000, 0x1575: 0x4000,
+	0x1577: 0x4000, 0x1578: 0x4000, 0x1579: 0x4000, 0x157a: 0x4000, 0x157b: 0x4000,
+	0x157c: 0x4000, 0x157d: 0x4000, 0x157e: 0x4000, 0x157f: 0x4000,
+	// Block 0x56, offset 0x1580
+	0x1580: 0x4000, 0x1581: 0x4000, 0x1582: 0x4000, 0x1583: 0x4000, 0x1584: 0x4000, 0x1585: 0x4000,
+	0x1586: 0x4000, 0x1587: 0x4000, 0x1588: 0x4000, 0x1589: 0x4000, 0x158a: 0x4000, 0x158b: 0x4000,
+	0x158c: 0x4000, 0x158d: 0x4000, 0x158e: 0x4000, 0x158f: 0x4000, 0x1590: 0x4000, 0x1591: 0x4000,
+	0x1592: 0x4000, 0x1593: 0x4000, 0x1594: 0x4000, 0x1595: 0x4000, 0x1596: 0x4000, 0x1597: 0x4000,
+	0x1598: 0x4000, 0x1599: 0x4000, 0x159a: 0x4000, 0x159b: 0x4000, 0x159c: 0x4000, 0x159d: 0x4000,
+	0x159e: 0x4000, 0x159f: 0x4000, 0x15a0: 0x4000, 0x15a1: 0x4000, 0x15a2: 0x4000, 0x15a3: 0x4000,
+	0x15a4: 0x4000, 0x15a5: 0x4000, 0x15a6: 0x4000, 0x15a7: 0x4000, 0x15a8: 0x4000, 0x15a9: 0x4000,
+	0x15aa: 0x4000, 0x15ab: 0x4000, 0x15ac: 0x4000, 0x15ad: 0x4000, 0x15ae: 0x4000, 0x15af: 0x4000,
+	0x15b0: 0x4000, 0x15b1: 0x4000, 0x15b2: 0x4000, 0x15b3: 0x4000, 0x15b4: 0x4000, 0x15b5: 0x4000,
+	0x15b6: 0x4000, 0x15b7: 0x4000, 0x15b8: 0x4000, 0x15b9: 0x4000, 0x15ba: 0x4000, 0x15bb: 0x4000,
+	0x15bc: 0x4000, 0x15be: 0x4000, 0x15bf: 0x4000,
+	// Block 0x57, offset 0x15c0
+	0x15c0: 0x4000, 0x15c1: 0x4000, 0x15c2: 0x4000, 0x15c3: 0x4000, 0x15c4: 0x4000, 0x15c5: 0x4000,
+	0x15c6: 0x4000, 0x15c7: 0x4000, 0x15c8: 0x4000, 0x15c9: 0x4000, 0x15ca: 0x4000, 0x15cb: 0x4000,
+	0x15cc: 0x4000, 0x15cd: 0x4000, 0x15ce: 0x4000, 0x15cf: 0x4000, 0x15d0: 0x4000, 0x15d1: 0x4000,
+	0x15d2: 0x4000, 0x15d3: 0x4000,
+	0x15e0: 0x4000, 0x15e1: 0x4000, 0x15e2: 0x4000, 0x15e3: 0x4000,
+	0x15e4: 0x4000, 0x15e5: 0x4000, 0x15e6: 0x4000, 0x15e7: 0x4000, 0x15e8: 0x4000, 0x15e9: 0x4000,
+	0x15ea: 0x4000, 0x15eb: 0x4000, 0x15ec: 0x4000, 0x15ed: 0x4000, 0x15ee: 0x4000, 0x15ef: 0x4000,
+	0x15f0: 0x4000, 0x15f1: 0x4000, 0x15f2: 0x4000, 0x15f3: 0x4000, 0x15f4: 0x4000, 0x15f5: 0x4000,
+	0x15f6: 0x4000, 0x15f7: 0x4000, 0x15f8: 0x4000, 0x15f9: 0x4000, 0x15fa: 0x4000, 0x15fb: 0x4000,
+	0x15fc: 0x4000, 0x15fd: 0x4000, 0x15fe: 0x4000, 0x15ff: 0x4000,
+	// Block 0x58, offset 0x1600
+	0x1600: 0x4000, 0x1601: 0x4000, 0x1602: 0x4000, 0x1603: 0x4000, 0x1604: 0x4000, 0x1605: 0x4000,
+	0x1606: 0x4000, 0x1607: 0x4000, 0x1608: 0x4000, 0x1609: 0x4000, 0x160a: 0x4000,
+	0x160f: 0x4000, 0x1610: 0x4000, 0x1611: 0x4000,
+	0x1612: 0x4000, 0x1613: 0x4000,
+	0x1620: 0x4000, 0x1621: 0x4000, 0x1622: 0x4000, 0x1623: 0x4000,
+	0x1624: 0x4000, 0x1625: 0x4000, 0x1626: 0x4000, 0x1627: 0x4000, 0x1628: 0x4000, 0x1629: 0x4000,
+	0x162a: 0x4000, 0x162b: 0x4000, 0x162c: 0x4000, 0x162d: 0x4000, 0x162e: 0x4000, 0x162f: 0x4000,
+	0x1630: 0x4000, 0x1634: 0x4000,
+	0x1638: 0x4000, 0x1639: 0x4000, 0x163a: 0x4000, 0x163b: 0x4000,
+	0x163c: 0x4000, 0x163d: 0x4000, 0x163e: 0x4000, 0x163f: 0x4000,
+	// Block 0x59, offset 0x1640
+	0x1640: 0x4000, 0x1641: 0x4000, 0x1642: 0x4000, 0x1643: 0x4000, 0x1644: 0x4000, 0x1645: 0x4000,
+	0x1646: 0x4000, 0x1647: 0x4000, 0x1648: 0x4000, 0x1649: 0x4000, 0x164a: 0x4000, 0x164b: 0x4000,
+	0x164c: 0x4000, 0x164d: 0x4000, 0x164e: 0x4000, 0x164f: 0x4000, 0x1650: 0x4000, 0x1651: 0x4000,
+	0x1652: 0x4000, 0x1653: 0x4000, 0x1654: 0x4000, 0x1655: 0x4000, 0x1656: 0x4000, 0x1657: 0x4000,
+	0x1658: 0x4000, 0x1659: 0x4000, 0x165a: 0x4000, 0x165b: 0x4000, 0x165c: 0x4000, 0x165d: 0x4000,
+	0x165e: 0x4000, 0x165f: 0x4000, 0x1660: 0x4000, 0x1661: 0x4000, 0x1662: 0x4000, 0x1663: 0x4000,
+	0x1664: 0x4000, 0x1665: 0x4000, 0x1666: 0x4000, 0x1667: 0x4000, 0x1668: 0x4000, 0x1669: 0x4000,
+	0x166a: 0x4000, 0x166b: 0x4000, 0x166c: 0x4000, 0x166d: 0x4000, 0x166e: 0x4000, 0x166f: 0x4000,
+	0x1670: 0x4000, 0x1671: 0x4000, 0x1672: 0x4000, 0x1673: 0x4000, 0x1674: 0x4000, 0x1675: 0x4000,
+	0x1676: 0x4000, 0x1677: 0x4000, 0x1678: 0x4000, 0x1679: 0x4000, 0x167a: 0x4000, 0x167b: 0x4000,
+	0x167c: 0x4000, 0x167d: 0x4000, 0x167e: 0x4000,
+	// Block 0x5a, offset 0x1680
+	0x1680: 0x4000, 0x1682: 0x4000, 0x1683: 0x4000, 0x1684: 0x4000, 0x1685: 0x4000,
+	0x1686: 0x4000, 0x1687: 0x4000, 0x1688: 0x4000, 0x1689: 0x4000, 0x168a: 0x4000, 0x168b: 0x4000,
+	0x168c: 0x4000, 0x168d: 0x4000, 0x168e: 0x4000, 0x168f: 0x4000, 0x1690: 0x4000, 0x1691: 0x4000,
+	0x1692: 0x4000, 0x1693: 0x4000, 0x1694: 0x4000, 0x1695: 0x4000, 0x1696: 0x4000, 0x1697: 0x4000,
+	0x1698: 0x4000, 0x1699: 0x4000, 0x169a: 0x4000, 0x169b: 0x4000, 0x169c: 0x4000, 0x169d: 0x4000,
+	0x169e: 0x4000, 0x169f: 0x4000, 0x16a0: 0x4000, 0x16a1: 0x4000, 0x16a2: 0x4000, 0x16a3: 0x4000,
+	0x16a4: 0x4000, 0x16a5: 0x4000, 0x16a6: 0x4000, 0x16a7: 0x4000, 0x16a8: 0x4000, 0x16a9: 0x4000,
+	0x16aa: 0x4000, 0x16ab: 0x4000, 0x16ac: 0x4000, 0x16ad: 0x4000, 0x16ae: 0x4000, 0x16af: 0x4000,
+	0x16b0: 0x4000, 0x16b1: 0x4000, 0x16b2: 0x4000, 0x16b3: 0x4000, 0x16b4: 0x4000, 0x16b5: 0x4000,
+	0x16b6: 0x4000, 0x16b7: 0x4000, 0x16b8: 0x4000, 0x16b9: 0x4000, 0x16ba: 0x4000, 0x16bb: 0x4000,
+	0x16bc: 0x4000, 0x16bd: 0x4000, 0x16be: 0x4000, 0x16bf: 0x4000,
+	// Block 0x5b, offset 0x16c0
+	0x16c0: 0x4000, 0x16c1: 0x4000, 0x16c2: 0x4000, 0x16c3: 0x4000, 0x16c4: 0x4000, 0x16c5: 0x4000,
+	0x16c6: 0x4000, 0x16c7: 0x4000, 0x16c8: 0x4000, 0x16c9: 0x4000, 0x16ca: 0x4000, 0x16cb: 0x4000,
+	0x16cc: 0x4000, 0x16cd: 0x4000, 0x16ce: 0x4000, 0x16cf: 0x4000, 0x16d0: 0x4000, 0x16d1: 0x4000,
+	0x16d2: 0x4000, 0x16d3: 0x4000, 0x16d4: 0x4000, 0x16d5: 0x4000, 0x16d6: 0x4000, 0x16d7: 0x4000,
+	0x16d8: 0x4000, 0x16d9: 0x4000, 0x16da: 0x4000, 0x16db: 0x4000, 0x16dc: 0x4000, 0x16dd: 0x4000,
+	0x16de: 0x4000, 0x16df: 0x4000, 0x16e0: 0x4000, 0x16e1: 0x4000, 0x16e2: 0x4000, 0x16e3: 0x4000,
+	0x16e4: 0x4000, 0x16e5: 0x4000, 0x16e6: 0x4000, 0x16e7: 0x4000, 0x16e8: 0x4000, 0x16e9: 0x4000,
+	0x16ea: 0x4000, 0x16eb: 0x4000, 0x16ec: 0x4000, 0x16ed: 0x4000, 0x16ee: 0x4000, 0x16ef: 0x4000,
+	0x16f0: 0x4000, 0x16f1: 0x4000, 0x16f2: 0x4000, 0x16f3: 0x4000, 0x16f4: 0x4000, 0x16f5: 0x4000,
+	0x16f6: 0x4000, 0x16f7: 0x4000, 0x16f8: 0x4000, 0x16f9: 0x4000, 0x16fa: 0x4000, 0x16fb: 0x4000,
+	0x16fc: 0x4000, 0x16ff: 0x4000,
+	// Block 0x5c, offset 0x1700
+	0x1700: 0x4000, 0x1701: 0x4000, 0x1702: 0x4000, 0x1703: 0x4000, 0x1704: 0x4000, 0x1705: 0x4000,
+	0x1706: 0x4000, 0x1707: 0x4000, 0x1708: 0x4000, 0x1709: 0x4000, 0x170a: 0x4000, 0x170b: 0x4000,
+	0x170c: 0x4000, 0x170d: 0x4000, 0x170e: 0x4000, 0x170f: 0x4000, 0x1710: 0x4000, 0x1711: 0x4000,
+	0x1712: 0x4000, 0x1713: 0x4000, 0x1714: 0x4000, 0x1715: 0x4000, 0x1716: 0x4000, 0x1717: 0x4000,
+	0x1718: 0x4000, 0x1719: 0x4000, 0x171a: 0x4000, 0x171b: 0x4000, 0x171c: 0x4000, 0x171d: 0x4000,
+	0x171e: 0x4000, 0x171f: 0x4000, 0x1720: 0x4000, 0x1721: 0x4000, 0x1722: 0x4000, 0x1723: 0x4000,
+	0x1724: 0x4000, 0x1725: 0x4000, 0x1726: 0x4000, 0x1727: 0x4000, 0x1728: 0x4000, 0x1729: 0x4000,
+	0x172a: 0x4000, 0x172b: 0x4000, 0x172c: 0x4000, 0x172d: 0x4000, 0x172e: 0x4000, 0x172f: 0x4000,
+	0x1730: 0x4000, 0x1731: 0x4000, 0x1732: 0x4000, 0x1733: 0x4000, 0x1734: 0x4000, 0x1735: 0x4000,
+	0x1736: 0x4000, 0x1737: 0x4000, 0x1738: 0x4000, 0x1739: 0x4000, 0x173a: 0x4000, 0x173b: 0x4000,
+	0x173c: 0x4000, 0x173d: 0x4000,
+	// Block 0x5d, offset 0x1740
+	0x174b: 0x4000,
+	0x174c: 0x4000, 0x174d: 0x4000, 0x174e: 0x4000, 0x1750: 0x4000, 0x1751: 0x4000,
+	0x1752: 0x4000, 0x1753: 0x4000, 0x1754: 0x4000, 0x1755: 0x4000, 0x1756: 0x4000, 0x1757: 0x4000,
+	0x1758: 0x4000, 0x1759: 0x4000, 0x175a: 0x4000, 0x175b: 0x4000, 0x175c: 0x4000, 0x175d: 0x4000,
+	0x175e: 0x4000, 0x175f: 0x4000, 0x1760: 0x4000, 0x1761: 0x4000, 0x1762: 0x4000, 0x1763: 0x4000,
+	0x1764: 0x4000, 0x1765: 0x4000, 0x1766: 0x4000, 0x1767: 0x4000,
+	0x177a: 0x4000,
+	// Block 0x5e, offset 0x1780
+	0x1795: 0x4000, 0x1796: 0x4000,
+	0x17a4: 0x4000,
+	// Block 0x5f, offset 0x17c0
+	0x17fb: 0x4000,
+	0x17fc: 0x4000, 0x17fd: 0x4000, 0x17fe: 0x4000, 0x17ff: 0x4000,
+	// Block 0x60, offset 0x1800
+	0x1800: 0x4000, 0x1801: 0x4000, 0x1802: 0x4000, 0x1803: 0x4000, 0x1804: 0x4000, 0x1805: 0x4000,
+	0x1806: 0x4000, 0x1807: 0x4000, 0x1808: 0x4000, 0x1809: 0x4000, 0x180a: 0x4000, 0x180b: 0x4000,
+	0x180c: 0x4000, 0x180d: 0x4000, 0x180e: 0x4000, 0x180f: 0x4000,
+	// Block 0x61, offset 0x1840
+	0x1840: 0x4000, 0x1841: 0x4000, 0x1842: 0x4000, 0x1843: 0x4000, 0x1844: 0x4000, 0x1845: 0x4000,
+	0x184c: 0x4000, 0x1850: 0x4000, 0x1851: 0x4000,
+	0x1852: 0x4000, 0x1855: 0x4000, 0x1856: 0x4000, 0x1857: 0x4000,
+	0x185c: 0x4000, 0x185d: 0x4000,
+	0x185e: 0x4000, 0x185f: 0x4000,
+	0x186b: 0x4000, 0x186c: 0x4000,
+	0x1874: 0x4000, 0x1875: 0x4000,
+	0x1876: 0x4000, 0x1877: 0x4000, 0x1878: 0x4000, 0x1879: 0x4000, 0x187a: 0x4000, 0x187b: 0x4000,
+	0x187c: 0x4000,
+	// Block 0x62, offset 0x1880
+	0x18a0: 0x4000, 0x18a1: 0x4000, 0x18a2: 0x4000, 0x18a3: 0x4000,
+	0x18a4: 0x4000, 0x18a5: 0x4000, 0x18a6: 0x4000, 0x18a7: 0x4000, 0x18a8: 0x4000, 0x18a9: 0x4000,
+	0x18aa: 0x4000, 0x18ab: 0x4000,
+	0x18b0: 0x4000,
+	// Block 0x63, offset 0x18c0
+	0x18cc: 0x4000, 0x18cd: 0x4000, 0x18ce: 0x4000, 0x18cf: 0x4000, 0x18d0: 0x4000, 0x18d1: 0x4000,
+	0x18d2: 0x4000, 0x18d3: 0x4000, 0x18d4: 0x4000, 0x18d5: 0x4000, 0x18d6: 0x4000, 0x18d7: 0x4000,
+	0x18d8: 0x4000, 0x18d9: 0x4000, 0x18da: 0x4000, 0x18db: 0x4000, 0x18dc: 0x4000, 0x18dd: 0x4000,
+	0x18de: 0x4000, 0x18df: 0x4000, 0x18e0: 0x4000, 0x18e1: 0x4000, 0x18e2: 0x4000, 0x18e3: 0x4000,
+	0x18e4: 0x4000, 0x18e5: 0x4000, 0x18e6: 0x4000, 0x18e7: 0x4000, 0x18e8: 0x4000, 0x18e9: 0x4000,
+	0x18ea: 0x4000, 0x18eb: 0x4000, 0x18ec: 0x4000, 0x18ed: 0x4000, 0x18ee: 0x4000, 0x18ef: 0x4000,
+	0x18f0: 0x4000, 0x18f1: 0x4000, 0x18f2: 0x4000, 0x18f3: 0x4000, 0x18f4: 0x4000, 0x18f5: 0x4000,
+	0x18f6: 0x4000, 0x18f7: 0x4000, 0x18f8: 0x4000, 0x18f9: 0x4000, 0x18fa: 0x4000,
+	0x18fc: 0x4000, 0x18fd: 0x4000, 0x18fe: 0x4000, 0x18ff: 0x4000,
+	// Block 0x64, offset 0x1900
+	0x1900: 0x4000, 0x1901: 0x4000, 0x1902: 0x4000, 0x1903: 0x4000, 0x1904: 0x4000, 0x1905: 0x4000,
+	0x1907: 0x4000, 0x1908: 0x4000, 0x1909: 0x4000, 0x190a: 0x4000, 0x190b: 0x4000,
+	0x190c: 0x4000, 0x190d: 0x4000, 0x190e: 0x4000, 0x190f: 0x4000, 0x1910: 0x4000, 0x1911: 0x4000,
+	0x1912: 0x4000, 0x1913: 0x4000, 0x1914: 0x4000, 0x1915: 0x4000, 0x1916: 0x4000, 0x1917: 0x4000,
+	0x1918: 0x4000, 0x1919: 0x4000, 0x191a: 0x4000, 0x191b: 0x4000, 0x191c: 0x4000, 0x191d: 0x4000,
+	0x191e: 0x4000, 0x191f: 0x4000, 0x1920: 0x4000, 0x1921: 0x4000, 0x1922: 0x4000, 0x1923: 0x4000,
+	0x1924: 0x4000, 0x1925: 0x4000, 0x1926: 0x4000, 0x1927: 0x4000, 0x1928: 0x4000, 0x1929: 0x4000,
+	0x192a: 0x4000, 0x192b: 0x4000, 0x192c: 0x4000, 0x192d: 0x4000, 0x192e: 0x4000, 0x192f: 0x4000,
+	0x1930: 0x4000, 0x1931: 0x4000, 0x1932: 0x4000, 0x1933: 0x4000, 0x1934: 0x4000, 0x1935: 0x4000,
+	0x1936: 0x4000, 0x1937: 0x4000, 0x1938: 0x4000, 0x1939: 0x4000, 0x193a: 0x4000, 0x193b: 0x4000,
+	0x193c: 0x4000, 0x193d: 0x4000, 0x193e: 0x4000, 0x193f: 0x4000,
+	// Block 0x65, offset 0x1940
+	0x1970: 0x4000, 0x1971: 0x4000, 0x1972: 0x4000, 0x1973: 0x4000, 0x1974: 0x4000, 0x1975: 0x4000,
+	0x1976: 0x4000, 0x1977: 0x4000, 0x1978: 0x4000, 0x1979: 0x4000, 0x197a: 0x4000, 0x197b: 0x4000,
+	0x197c: 0x4000,
+	// Block 0x66, offset 0x1980
+	0x1980: 0x4000, 0x1981: 0x4000, 0x1982: 0x4000, 0x1983: 0x4000, 0x1984: 0x4000, 0x1985: 0x4000,
+	0x1986: 0x4000, 0x1987: 0x4000, 0x1988: 0x4000,
+	0x1990: 0x4000, 0x1991: 0x4000,
+	0x1992: 0x4000, 0x1993: 0x4000, 0x1994: 0x4000, 0x1995: 0x4000, 0x1996: 0x4000, 0x1997: 0x4000,
+	0x1998: 0x4000, 0x1999: 0x4000, 0x199a: 0x4000, 0x199b: 0x4000, 0x199c: 0x4000, 0x199d: 0x4000,
+	0x199e: 0x4000, 0x199f: 0x4000, 0x19a0: 0x4000, 0x19a1: 0x4000, 0x19a2: 0x4000, 0x19a3: 0x4000,
+	0x19a4: 0x4000, 0x19a5: 0x4000, 0x19a6: 0x4000, 0x19a7: 0x4000, 0x19a8: 0x4000, 0x19a9: 0x4000,
+	0x19aa: 0x4000, 0x19ab: 0x4000, 0x19ac: 0x4000, 0x19ad: 0x4000, 0x19ae: 0x4000, 0x19af: 0x4000,
+	0x19b0: 0x4000, 0x19b1: 0x4000, 0x19b2: 0x4000, 0x19b3: 0x4000, 0x19b4: 0x4000, 0x19b5: 0x4000,
+	0x19b6: 0x4000, 0x19b7: 0x4000, 0x19b8: 0x4000, 0x19b9: 0x4000, 0x19ba: 0x4000, 0x19bb: 0x4000,
+	0x19bc: 0x4000, 0x19bd: 0x4000, 0x19bf: 0x4000,
+	// Block 0x67, offset 0x19c0
+	0x19c0: 0x4000, 0x19c1: 0x4000, 0x19c2: 0x4000, 0x19c3: 0x4000, 0x19c4: 0x4000, 0x19c5: 0x4000,
+	0x19ce: 0x4000, 0x19cf: 0x4000, 0x19d0: 0x4000, 0x19d1: 0x4000,
+	0x19d2: 0x4000, 0x19d3: 0x4000, 0x19d4: 0x4000, 0x19d5: 0x4000, 0x19d6: 0x4000, 0x19d7: 0x4000,
+	0x19d8: 0x4000, 0x19d9: 0x4000, 0x19da: 0x4000, 0x19db: 0x4000,
+	0x19e0: 0x4000, 0x19e1: 0x4000, 0x19e2: 0x4000, 0x19e3: 0x4000,
+	0x19e4: 0x4000, 0x19e5: 0x4000, 0x19e6: 0x4000, 0x19e7: 0x4000, 0x19e8: 0x4000,
+	0x19f0: 0x4000, 0x19f1: 0x4000, 0x19f2: 0x4000, 0x19f3: 0x4000, 0x19f4: 0x4000, 0x19f5: 0x4000,
+	0x19f6: 0x4000, 0x19f7: 0x4000, 0x19f8: 0x4000,
+	// Block 0x68, offset 0x1a00
+	0x1a00: 0x2000, 0x1a01: 0x2000, 0x1a02: 0x2000, 0x1a03: 0x2000, 0x1a04: 0x2000, 0x1a05: 0x2000,
+	0x1a06: 0x2000, 0x1a07: 0x2000, 0x1a08: 0x2000, 0x1a09: 0x2000, 0x1a0a: 0x2000, 0x1a0b: 0x2000,
+	0x1a0c: 0x2000, 0x1a0d: 0x2000, 0x1a0e: 0x2000, 0x1a0f: 0x2000, 0x1a10: 0x2000, 0x1a11: 0x2000,
+	0x1a12: 0x2000, 0x1a13: 0x2000, 0x1a14: 0x2000, 0x1a15: 0x2000, 0x1a16: 0x2000, 0x1a17: 0x2000,
+	0x1a18: 0x2000, 0x1a19: 0x2000, 0x1a1a: 0x2000, 0x1a1b: 0x2000, 0x1a1c: 0x2000, 0x1a1d: 0x2000,
+	0x1a1e: 0x2000, 0x1a1f: 0x2000, 0x1a20: 0x2000, 0x1a21: 0x2000, 0x1a22: 0x2000, 0x1a23: 0x2000,
+	0x1a24: 0x2000, 0x1a25: 0x2000, 0x1a26: 0x2000, 0x1a27: 0x2000, 0x1a28: 0x2000, 0x1a29: 0x2000,
+	0x1a2a: 0x2000, 0x1a2b: 0x2000, 0x1a2c: 0x2000, 0x1a2d: 0x2000, 0x1a2e: 0x2000, 0x1a2f: 0x2000,
+	0x1a30: 0x2000, 0x1a31: 0x2000, 0x1a32: 0x2000, 0x1a33: 0x2000, 0x1a34: 0x2000, 0x1a35: 0x2000,
+	0x1a36: 0x2000, 0x1a37: 0x2000, 0x1a38: 0x2000, 0x1a39: 0x2000, 0x1a3a: 0x2000, 0x1a3b: 0x2000,
+	0x1a3c: 0x2000, 0x1a3d: 0x2000,
+}
+
+// widthIndex: 23 blocks, 1472 entries, 1472 bytes
+// Block 0 is the zero block.
+var widthIndex = [1472]uint8{
+	// Block 0x0, offset 0x0
+	// Block 0x1, offset 0x40
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc7: 0x05,
+	0xc9: 0x06, 0xcb: 0x07, 0xcc: 0x08, 0xcd: 0x09, 0xce: 0x0a, 0xcf: 0x0b,
+	0xd0: 0x0c, 0xd1: 0x0d,
+	0xe1: 0x02, 0xe2: 0x03, 0xe3: 0x04, 0xe4: 0x05, 0xe5: 0x06, 0xe6: 0x06, 0xe7: 0x06,
+	0xe8: 0x06, 0xe9: 0x06, 0xea: 0x07, 0xeb: 0x06, 0xec: 0x06, 0xed: 0x08, 0xee: 0x09, 0xef: 0x0a,
+	0xf0: 0x10, 0xf3: 0x13, 0xf4: 0x14,
+	// Block 0x4, offset 0x100
+	0x104: 0x0e, 0x105: 0x0f,
+	// Block 0x5, offset 0x140
+	0x140: 0x10, 0x141: 0x11, 0x142: 0x12, 0x144: 0x13, 0x145: 0x14, 0x146: 0x15, 0x147: 0x16,
+	0x148: 0x17, 0x149: 0x18, 0x14a: 0x19, 0x14c: 0x1a, 0x14f: 0x1b,
+	0x151: 0x1c, 0x152: 0x08, 0x153: 0x1d, 0x154: 0x1e, 0x155: 0x1f, 0x156: 0x20, 0x157: 0x21,
+	0x158: 0x22, 0x159: 0x23, 0x15a: 0x24, 0x15b: 0x25, 0x15c: 0x26, 0x15d: 0x27, 0x15e: 0x28, 0x15f: 0x29,
+	0x166: 0x2a,
+	0x16c: 0x2b, 0x16d: 0x2c,
+	0x17a: 0x2d, 0x17b: 0x2e, 0x17c: 0x0e, 0x17d: 0x0e, 0x17e: 0x0e, 0x17f: 0x2f,
+	// Block 0x6, offset 0x180
+	0x180: 0x30, 0x181: 0x31, 0x182: 0x32, 0x183: 0x33, 0x184: 0x34, 0x185: 0x35, 0x186: 0x36, 0x187: 0x37,
+	0x188: 0x38, 0x189: 0x39, 0x18a: 0x0e, 0x18b: 0x0e, 0x18c: 0x0e, 0x18d: 0x0e, 0x18e: 0x0e, 0x18f: 0x0e,
+	0x190: 0x0e, 0x191: 0x0e, 0x192: 0x0e, 0x193: 0x0e, 0x194: 0x0e, 0x195: 0x0e, 0x196: 0x0e, 0x197: 0x0e,
+	0x198: 0x0e, 0x199: 0x0e, 0x19a: 0x0e, 0x19b: 0x0e, 0x19c: 0x0e, 0x19d: 0x0e, 0x19e: 0x0e, 0x19f: 0x0e,
+	0x1a0: 0x0e, 0x1a1: 0x0e, 0x1a2: 0x0e, 0x1a3: 0x0e, 0x1a4: 0x0e, 0x1a5: 0x0e, 0x1a6: 0x0e, 0x1a7: 0x0e,
+	0x1a8: 0x0e, 0x1a9: 0x0e, 0x1aa: 0x0e, 0x1ab: 0x0e, 0x1ac: 0x0e, 0x1ad: 0x0e, 0x1ae: 0x0e, 0x1af: 0x0e,
+	0x1b0: 0x0e, 0x1b1: 0x0e, 0x1b2: 0x0e, 0x1b3: 0x0e, 0x1b4: 0x0e, 0x1b5: 0x0e, 0x1b6: 0x0e, 0x1b7: 0x0e,
+	0x1b8: 0x0e, 0x1b9: 0x0e, 0x1ba: 0x0e, 0x1bb: 0x0e, 0x1bc: 0x0e, 0x1bd: 0x0e, 0x1be: 0x0e, 0x1bf: 0x0e,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x0e, 0x1c1: 0x0e, 0x1c2: 0x0e, 0x1c3: 0x0e, 0x1c4: 0x0e, 0x1c5: 0x0e, 0x1c6: 0x0e, 0x1c7: 0x0e,
+	0x1c8: 0x0e, 0x1c9: 0x0e, 0x1ca: 0x0e, 0x1cb: 0x0e, 0x1cc: 0x0e, 0x1cd: 0x0e, 0x1ce: 0x0e, 0x1cf: 0x0e,
+	0x1d0: 0x0e, 0x1d1: 0x0e, 0x1d2: 0x0e, 0x1d3: 0x0e, 0x1d4: 0x0e, 0x1d5: 0x0e, 0x1d6: 0x0e, 0x1d7: 0x0e,
+	0x1d8: 0x0e, 0x1d9: 0x0e, 0x1da: 0x0e, 0x1db: 0x0e, 0x1dc: 0x0e, 0x1dd: 0x0e, 0x1de: 0x0e, 0x1df: 0x0e,
+	0x1e0: 0x0e, 0x1e1: 0x0e, 0x1e2: 0x0e, 0x1e3: 0x0e, 0x1e4: 0x0e, 0x1e5: 0x0e, 0x1e6: 0x0e, 0x1e7: 0x0e,
+	0x1e8: 0x0e, 0x1e9: 0x0e, 0x1ea: 0x0e, 0x1eb: 0x0e, 0x1ec: 0x0e, 0x1ed: 0x0e, 0x1ee: 0x0e, 0x1ef: 0x0e,
+	0x1f0: 0x0e, 0x1f1: 0x0e, 0x1f2: 0x0e, 0x1f3: 0x0e, 0x1f4: 0x0e, 0x1f5: 0x0e, 0x1f6: 0x0e,
+	0x1f8: 0x0e, 0x1f9: 0x0e, 0x1fa: 0x0e, 0x1fb: 0x0e, 0x1fc: 0x0e, 0x1fd: 0x0e, 0x1fe: 0x0e, 0x1ff: 0x0e,
+	// Block 0x8, offset 0x200
+	0x200: 0x0e, 0x201: 0x0e, 0x202: 0x0e, 0x203: 0x0e, 0x204: 0x0e, 0x205: 0x0e, 0x206: 0x0e, 0x207: 0x0e,
+	0x208: 0x0e, 0x209: 0x0e, 0x20a: 0x0e, 0x20b: 0x0e, 0x20c: 0x0e, 0x20d: 0x0e, 0x20e: 0x0e, 0x20f: 0x0e,
+	0x210: 0x0e, 0x211: 0x0e, 0x212: 0x0e, 0x213: 0x0e, 0x214: 0x0e, 0x215: 0x0e, 0x216: 0x0e, 0x217: 0x0e,
+	0x218: 0x0e, 0x219: 0x0e, 0x21a: 0x0e, 0x21b: 0x0e, 0x21c: 0x0e, 0x21d: 0x0e, 0x21e: 0x0e, 0x21f: 0x0e,
+	0x220: 0x0e, 0x221: 0x0e, 0x222: 0x0e, 0x223: 0x0e, 0x224: 0x0e, 0x225: 0x0e, 0x226: 0x0e, 0x227: 0x0e,
+	0x228: 0x0e, 0x229: 0x0e, 0x22a: 0x0e, 0x22b: 0x0e, 0x22c: 0x0e, 0x22d: 0x0e, 0x22e: 0x0e, 0x22f: 0x0e,
+	0x230: 0x0e, 0x231: 0x0e, 0x232: 0x0e, 0x233: 0x0e, 0x234: 0x0e, 0x235: 0x0e, 0x236: 0x0e, 0x237: 0x0e,
+	0x238: 0x0e, 0x239: 0x0e, 0x23a: 0x0e, 0x23b: 0x0e, 0x23c: 0x0e, 0x23d: 0x0e, 0x23e: 0x0e, 0x23f: 0x0e,
+	// Block 0x9, offset 0x240
+	0x240: 0x0e, 0x241: 0x0e, 0x242: 0x0e, 0x243: 0x0e, 0x244: 0x0e, 0x245: 0x0e, 0x246: 0x0e, 0x247: 0x0e,
+	0x248: 0x0e, 0x249: 0x0e, 0x24a: 0x0e, 0x24b: 0x0e, 0x24c: 0x0e, 0x24d: 0x0e, 0x24e: 0x0e, 0x24f: 0x0e,
+	0x250: 0x0e, 0x251: 0x0e, 0x252: 0x3a, 0x253: 0x3b,
+	0x265: 0x3c,
+	0x270: 0x0e, 0x271: 0x0e, 0x272: 0x0e, 0x273: 0x0e, 0x274: 0x0e, 0x275: 0x0e, 0x276: 0x0e, 0x277: 0x0e,
+	0x278: 0x0e, 0x279: 0x0e, 0x27a: 0x0e, 0x27b: 0x0e, 0x27c: 0x0e, 0x27d: 0x0e, 0x27e: 0x0e, 0x27f: 0x0e,
+	// Block 0xa, offset 0x280
+	0x280: 0x0e, 0x281: 0x0e, 0x282: 0x0e, 0x283: 0x0e, 0x284: 0x0e, 0x285: 0x0e, 0x286: 0x0e, 0x287: 0x0e,
+	0x288: 0x0e, 0x289: 0x0e, 0x28a: 0x0e, 0x28b: 0x0e, 0x28c: 0x0e, 0x28d: 0x0e, 0x28e: 0x0e, 0x28f: 0x0e,
+	0x290: 0x0e, 0x291: 0x0e, 0x292: 0x0e, 0x293: 0x0e, 0x294: 0x0e, 0x295: 0x0e, 0x296: 0x0e, 0x297: 0x0e,
+	0x298: 0x0e, 0x299: 0x0e, 0x29a: 0x0e, 0x29b: 0x0e, 0x29c: 0x0e, 0x29d: 0x0e, 0x29e: 0x3d,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x08, 0x2c1: 0x08, 0x2c2: 0x08, 0x2c3: 0x08, 0x2c4: 0x08, 0x2c5: 0x08, 0x2c6: 0x08, 0x2c7: 0x08,
+	0x2c8: 0x08, 0x2c9: 0x08, 0x2ca: 0x08, 0x2cb: 0x08, 0x2cc: 0x08, 0x2cd: 0x08, 0x2ce: 0x08, 0x2cf: 0x08,
+	0x2d0: 0x08, 0x2d1: 0x08, 0x2d2: 0x08, 0x2d3: 0x08, 0x2d4: 0x08, 0x2d5: 0x08, 0x2d6: 0x08, 0x2d7: 0x08,
+	0x2d8: 0x08, 0x2d9: 0x08, 0x2da: 0x08, 0x2db: 0x08, 0x2dc: 0x08, 0x2dd: 0x08, 0x2de: 0x08, 0x2df: 0x08,
+	0x2e0: 0x08, 0x2e1: 0x08, 0x2e2: 0x08, 0x2e3: 0x08, 0x2e4: 0x08, 0x2e5: 0x08, 0x2e6: 0x08, 0x2e7: 0x08,
+	0x2e8: 0x08, 0x2e9: 0x08, 0x2ea: 0x08, 0x2eb: 0x08, 0x2ec: 0x08, 0x2ed: 0x08, 0x2ee: 0x08, 0x2ef: 0x08,
+	0x2f0: 0x08, 0x2f1: 0x08, 0x2f2: 0x08, 0x2f3: 0x08, 0x2f4: 0x08, 0x2f5: 0x08, 0x2f6: 0x08, 0x2f7: 0x08,
+	0x2f8: 0x08, 0x2f9: 0x08, 0x2fa: 0x08, 0x2fb: 0x08, 0x2fc: 0x08, 0x2fd: 0x08, 0x2fe: 0x08, 0x2ff: 0x08,
+	// Block 0xc, offset 0x300
+	0x300: 0x08, 0x301: 0x08, 0x302: 0x08, 0x303: 0x08, 0x304: 0x08, 0x305: 0x08, 0x306: 0x08, 0x307: 0x08,
+	0x308: 0x08, 0x309: 0x08, 0x30a: 0x08, 0x30b: 0x08, 0x30c: 0x08, 0x30d: 0x08, 0x30e: 0x08, 0x30f: 0x08,
+	0x310: 0x08, 0x311: 0x08, 0x312: 0x08, 0x313: 0x08, 0x314: 0x08, 0x315: 0x08, 0x316: 0x08, 0x317: 0x08,
+	0x318: 0x08, 0x319: 0x08, 0x31a: 0x08, 0x31b: 0x08, 0x31c: 0x08, 0x31d: 0x08, 0x31e: 0x08, 0x31f: 0x08,
+	0x320: 0x08, 0x321: 0x08, 0x322: 0x08, 0x323: 0x08, 0x324: 0x0e, 0x325: 0x0e, 0x326: 0x0e, 0x327: 0x0e,
+	0x328: 0x0e, 0x329: 0x0e, 0x32a: 0x0e, 0x32b: 0x0e,
+	0x338: 0x3e, 0x339: 0x3f, 0x33c: 0x40, 0x33d: 0x41, 0x33e: 0x42, 0x33f: 0x43,
+	// Block 0xd, offset 0x340
+	0x37f: 0x44,
+	// Block 0xe, offset 0x380
+	0x380: 0x0e, 0x381: 0x0e, 0x382: 0x0e, 0x383: 0x0e, 0x384: 0x0e, 0x385: 0x0e, 0x386: 0x0e, 0x387: 0x0e,
+	0x388: 0x0e, 0x389: 0x0e, 0x38a: 0x0e, 0x38b: 0x0e, 0x38c: 0x0e, 0x38d: 0x0e, 0x38e: 0x0e, 0x38f: 0x0e,
+	0x390: 0x0e, 0x391: 0x0e, 0x392: 0x0e, 0x393: 0x0e, 0x394: 0x0e, 0x395: 0x0e, 0x396: 0x0e, 0x397: 0x0e,
+	0x398: 0x0e, 0x399: 0x0e, 0x39a: 0x0e, 0x39b: 0x0e, 0x39c: 0x0e, 0x39d: 0x0e, 0x39e: 0x0e, 0x39f: 0x45,
+	0x3a0: 0x0e, 0x3a1: 0x0e, 0x3a2: 0x0e, 0x3a3: 0x0e, 0x3a4: 0x0e, 0x3a5: 0x0e, 0x3a6: 0x0e, 0x3a7: 0x0e,
+	0x3a8: 0x0e, 0x3a9: 0x0e, 0x3aa: 0x0e, 0x3ab: 0x0e, 0x3ac: 0x0e, 0x3ad: 0x0e, 0x3ae: 0x0e, 0x3af: 0x0e,
+	0x3b0: 0x0e, 0x3b1: 0x0e, 0x3b2: 0x0e, 0x3b3: 0x46, 0x3b4: 0x47,
+	// Block 0xf, offset 0x3c0
+	0x3ff: 0x48,
+	// Block 0x10, offset 0x400
+	0x400: 0x0e, 0x401: 0x0e, 0x402: 0x0e, 0x403: 0x0e, 0x404: 0x49, 0x405: 0x4a, 0x406: 0x0e, 0x407: 0x0e,
+	0x408: 0x0e, 0x409: 0x0e, 0x40a: 0x0e, 0x40b: 0x4b,
+	// Block 0x11, offset 0x440
+	0x440: 0x4c, 0x443: 0x4d, 0x444: 0x4e, 0x445: 0x4f, 0x446: 0x50,
+	0x448: 0x51, 0x449: 0x52, 0x44c: 0x53, 0x44d: 0x54, 0x44e: 0x55, 0x44f: 0x56,
+	0x450: 0x57, 0x451: 0x58, 0x452: 0x0e, 0x453: 0x59, 0x454: 0x5a, 0x455: 0x5b, 0x456: 0x5c, 0x457: 0x5d,
+	0x458: 0x0e, 0x459: 0x5e, 0x45a: 0x0e, 0x45b: 0x5f, 0x45f: 0x60,
+	0x464: 0x61, 0x465: 0x62, 0x466: 0x0e, 0x467: 0x0e,
+	0x469: 0x63, 0x46a: 0x64, 0x46b: 0x65,
+	// Block 0x12, offset 0x480
+	0x496: 0x0b, 0x497: 0x06,
+	0x498: 0x0c, 0x49a: 0x0d, 0x49b: 0x0e, 0x49f: 0x0f,
+	0x4a0: 0x06, 0x4a1: 0x06, 0x4a2: 0x06, 0x4a3: 0x06, 0x4a4: 0x06, 0x4a5: 0x06, 0x4a6: 0x06, 0x4a7: 0x06,
+	0x4a8: 0x06, 0x4a9: 0x06, 0x4aa: 0x06, 0x4ab: 0x06, 0x4ac: 0x06, 0x4ad: 0x06, 0x4ae: 0x06, 0x4af: 0x06,
+	0x4b0: 0x06, 0x4b1: 0x06, 0x4b2: 0x06, 0x4b3: 0x06, 0x4b4: 0x06, 0x4b5: 0x06, 0x4b6: 0x06, 0x4b7: 0x06,
+	0x4b8: 0x06, 0x4b9: 0x06, 0x4ba: 0x06, 0x4bb: 0x06, 0x4bc: 0x06, 0x4bd: 0x06, 0x4be: 0x06, 0x4bf: 0x06,
+	// Block 0x13, offset 0x4c0
+	0x4c4: 0x08, 0x4c5: 0x08, 0x4c6: 0x08, 0x4c7: 0x09,
+	// Block 0x14, offset 0x500
+	0x500: 0x08, 0x501: 0x08, 0x502: 0x08, 0x503: 0x08, 0x504: 0x08, 0x505: 0x08, 0x506: 0x08, 0x507: 0x08,
+	0x508: 0x08, 0x509: 0x08, 0x50a: 0x08, 0x50b: 0x08, 0x50c: 0x08, 0x50d: 0x08, 0x50e: 0x08, 0x50f: 0x08,
+	0x510: 0x08, 0x511: 0x08, 0x512: 0x08, 0x513: 0x08, 0x514: 0x08, 0x515: 0x08, 0x516: 0x08, 0x517: 0x08,
+	0x518: 0x08, 0x519: 0x08, 0x51a: 0x08, 0x51b: 0x08, 0x51c: 0x08, 0x51d: 0x08, 0x51e: 0x08, 0x51f: 0x08,
+	0x520: 0x08, 0x521: 0x08, 0x522: 0x08, 0x523: 0x08, 0x524: 0x08, 0x525: 0x08, 0x526: 0x08, 0x527: 0x08,
+	0x528: 0x08, 0x529: 0x08, 0x52a: 0x08, 0x52b: 0x08, 0x52c: 0x08, 0x52d: 0x08, 0x52e: 0x08, 0x52f: 0x08,
+	0x530: 0x08, 0x531: 0x08, 0x532: 0x08, 0x533: 0x08, 0x534: 0x08, 0x535: 0x08, 0x536: 0x08, 0x537: 0x08,
+	0x538: 0x08, 0x539: 0x08, 0x53a: 0x08, 0x53b: 0x08, 0x53c: 0x08, 0x53d: 0x08, 0x53e: 0x08, 0x53f: 0x66,
+	// Block 0x15, offset 0x540
+	0x560: 0x11,
+	0x570: 0x09, 0x571: 0x09, 0x572: 0x09, 0x573: 0x09, 0x574: 0x09, 0x575: 0x09, 0x576: 0x09, 0x577: 0x09,
+	0x578: 0x09, 0x579: 0x09, 0x57a: 0x09, 0x57b: 0x09, 0x57c: 0x09, 0x57d: 0x09, 0x57e: 0x09, 0x57f: 0x12,
+	// Block 0x16, offset 0x580
+	0x580: 0x09, 0x581: 0x09, 0x582: 0x09, 0x583: 0x09, 0x584: 0x09, 0x585: 0x09, 0x586: 0x09, 0x587: 0x09,
+	0x588: 0x09, 0x589: 0x09, 0x58a: 0x09, 0x58b: 0x09, 0x58c: 0x09, 0x58d: 0x09, 0x58e: 0x09, 0x58f: 0x12,
+}
+
+// inverseData contains 4-byte entries of the following format:
+//
+//	<length> <modified UTF-8-encoded rune> <0 padding>
+//
+// The last byte of the UTF-8-encoded rune is xor-ed with the last byte of the
+// UTF-8 encoding of the original rune. Mappings often have the following
+// pattern:
+//
+//	Ａ -> A  (U+FF21 -> U+0041)
+//	Ｂ -> B  (U+FF22 -> U+0042)
+//	...
+//
+// By xor-ing the last byte the same entry can be shared by many mappings. This
+// reduces the total number of distinct entries by about two thirds.
+// The resulting entry for the aforementioned mappings is
+//
+//	{ 0x01, 0xE0, 0x00, 0x00 }
+//
+// Using this entry to map U+FF21 (UTF-8 [EF BC A1]), we get
+//
+//	E0 ^ A1 = 41.
+//
+// Similarly, for U+FF22 (UTF-8 [EF BC A2]), we get
+//
+//	E0 ^ A2 = 42.
+//
+// Note that because of the xor-ing, the byte sequence stored in the entry is
+// not valid UTF-8.
+var inverseData = [150][4]byte{
+	{0x00, 0x00, 0x00, 0x00},
+	{0x03, 0xe3, 0x80, 0xa0},
+	{0x03, 0xef, 0xbc, 0xa0},
+	{0x03, 0xef, 0xbc, 0xe0},
+	{0x03, 0xef, 0xbd, 0xe0},
+	{0x03, 0xef, 0xbf, 0x02},
+	{0x03, 0xef, 0xbf, 0x00},
+	{0x03, 0xef, 0xbf, 0x0e},
+	{0x03, 0xef, 0xbf, 0x0c},
+	{0x03, 0xef, 0xbf, 0x0f},
+	{0x03, 0xef, 0xbf, 0x39},
+	{0x03, 0xef, 0xbf, 0x3b},
+	{0x03, 0xef, 0xbf, 0x3f},
+	{0x03, 0xef, 0xbf, 0x2a},
+	{0x03, 0xef, 0xbf, 0x0d},
+	{0x03, 0xef, 0xbf, 0x25},
+	{0x03, 0xef, 0xbd, 0x1a},
+	{0x03, 0xef, 0xbd, 0x26},
+	{0x01, 0xa0, 0x00, 0x00},
+	{0x03, 0xef, 0xbd, 0x25},
+	{0x03, 0xef, 0xbd, 0x23},
+	{0x03, 0xef, 0xbd, 0x2e},
+	{0x03, 0xef, 0xbe, 0x07},
+	{0x03, 0xef, 0xbe, 0x05},
+	{0x03, 0xef, 0xbd, 0x06},
+	{0x03, 0xef, 0xbd, 0x13},
+	{0x03, 0xef, 0xbd, 0x0b},
+	{0x03, 0xef, 0xbd, 0x16},
+	{0x03, 0xef, 0xbd, 0x0c},
+	{0x03, 0xef, 0xbd, 0x15},
+	{0x03, 0xef, 0xbd, 0x0d},
+	{0x03, 0xef, 0xbd, 0x1c},
+	{0x03, 0xef, 0xbd, 0x02},
+	{0x03, 0xef, 0xbd, 0x1f},
+	{0x03, 0xef, 0xbd, 0x1d},
+	{0x03, 0xef, 0xbd, 0x17},
+	{0x03, 0xef, 0xbd, 0x08},
+	{0x03, 0xef, 0xbd, 0x09},
+	{0x03, 0xef, 0xbd, 0x0e},
+	{0x03, 0xef, 0xbd, 0x04},
+	{0x03, 0xef, 0xbd, 0x05},
+	{0x03, 0xef, 0xbe, 0x3f},
+	{0x03, 0xef, 0xbe, 0x00},
+	{0x03, 0xef, 0xbd, 0x2c},
+	{0x03, 0xef, 0xbe, 0x06},
+	{0x03, 0xef, 0xbe, 0x0c},
+	{0x03, 0xef, 0xbe, 0x0f},
+	{0x03, 0xef, 0xbe, 0x0d},
+	{0x03, 0xef, 0xbe, 0x0b},
+	{0x03, 0xef, 0xbe, 0x19},
+	{0x03, 0xef, 0xbe, 0x15},
+	{0x03, 0xef, 0xbe, 0x11},
+	{0x03, 0xef, 0xbe, 0x31},
+	{0x03, 0xef, 0xbe, 0x33},
+	{0x03, 0xef, 0xbd, 0x0f},
+	{0x03, 0xef, 0xbe, 0x30},
+	{0x03, 0xef, 0xbe, 0x3e},
+	{0x03, 0xef, 0xbe, 0x32},
+	{0x03, 0xef, 0xbe, 0x36},
+	{0x03, 0xef, 0xbd, 0x14},
+	{0x03, 0xef, 0xbe, 0x2e},
+	{0x03, 0xef, 0xbd, 0x1e},
+	{0x03, 0xef, 0xbe, 0x10},
+	{0x03, 0xef, 0xbf, 0x13},
+	{0x03, 0xef, 0xbf, 0x15},
+	{0x03, 0xef, 0xbf, 0x17},
+	{0x03, 0xef, 0xbf, 0x1f},
+	{0x03, 0xef, 0xbf, 0x1d},
+	{0x03, 0xef, 0xbf, 0x1b},
+	{0x03, 0xef, 0xbf, 0x09},
+	{0x03, 0xef, 0xbf, 0x0b},
+	{0x03, 0xef, 0xbf, 0x37},
+	{0x03, 0xef, 0xbe, 0x04},
+	{0x01, 0xe0, 0x00, 0x00},
+	{0x03, 0xe2, 0xa6, 0x1a},
+	{0x03, 0xe2, 0xa6, 0x26},
+	{0x03, 0xe3, 0x80, 0x23},
+	{0x03, 0xe3, 0x80, 0x2e},
+	{0x03, 0xe3, 0x80, 0x25},
+	{0x03, 0xe3, 0x83, 0x1e},
+	{0x03, 0xe3, 0x83, 0x14},
+	{0x03, 0xe3, 0x82, 0x06},
+	{0x03, 0xe3, 0x82, 0x0b},
+	{0x03, 0xe3, 0x82, 0x0c},
+	{0x03, 0xe3, 0x82, 0x0d},
+	{0x03, 0xe3, 0x82, 0x02},
+	{0x03, 0xe3, 0x83, 0x0f},
+	{0x03, 0xe3, 0x83, 0x08},
+	{0x03, 0xe3, 0x83, 0x09},
+	{0x03, 0xe3, 0x83, 0x2c},
+	{0x03, 0xe3, 0x83, 0x0c},
+	{0x03, 0xe3, 0x82, 0x13},
+	{0x03, 0xe3, 0x82, 0x16},
+	{0x03, 0xe3, 0x82, 0x15},
+	{0x03, 0xe3, 0x82, 0x1c},
+	{0x03, 0xe3, 0x82, 0x1f},
+	{0x03, 0xe3, 0x82, 0x1d},
+	{0x03, 0xe3, 0x82, 0x1a},
+	{0x03, 0xe3, 0x82, 0x17},
+	{0x03, 0xe3, 0x82, 0x08},
+	{0x03, 0xe3, 0x82, 0x09},
+	{0x03, 0xe3, 0x82, 0x0e},
+	{0x03, 0xe3, 0x82, 0x04},
+	{0x03, 0xe3, 0x82, 0x05},
+	{0x03, 0xe3, 0x82, 0x3f},
+	{0x03, 0xe3, 0x83, 0x00},
+	{0x03, 0xe3, 0x83, 0x06},
+	{0x03, 0xe3, 0x83, 0x05},
+	{0x03, 0xe3, 0x83, 0x0d},
+	{0x03, 0xe3, 0x83, 0x0b},
+	{0x03, 0xe3, 0x83, 0x07},
+	{0x03, 0xe3, 0x83, 0x19},
+	{0x03, 0xe3, 0x83, 0x15},
+	{0x03, 0xe3, 0x83, 0x11},
+	{0x03, 0xe3, 0x83, 0x31},
+	{0x03, 0xe3, 0x83, 0x33},
+	{0x03, 0xe3, 0x83, 0x30},
+	{0x03, 0xe3, 0x83, 0x3e},
+	{0x03, 0xe3, 0x83, 0x32},
+	{0x03, 0xe3, 0x83, 0x36},
+	{0x03, 0xe3, 0x83, 0x2e},
+	{0x03, 0xe3, 0x82, 0x07},
+	{0x03, 0xe3, 0x85, 0x04},
+	{0x03, 0xe3, 0x84, 0x10},
+	{0x03, 0xe3, 0x85, 0x30},
+	{0x03, 0xe3, 0x85, 0x0d},
+	{0x03, 0xe3, 0x85, 0x13},
+	{0x03, 0xe3, 0x85, 0x15},
+	{0x03, 0xe3, 0x85, 0x17},
+	{0x03, 0xe3, 0x85, 0x1f},
+	{0x03, 0xe3, 0x85, 0x1d},
+	{0x03, 0xe3, 0x85, 0x1b},
+	{0x03, 0xe3, 0x85, 0x09},
+	{0x03, 0xe3, 0x85, 0x0f},
+	{0x03, 0xe3, 0x85, 0x0b},
+	{0x03, 0xe3, 0x85, 0x37},
+	{0x03, 0xe3, 0x85, 0x3b},
+	{0x03, 0xe3, 0x85, 0x39},
+	{0x03, 0xe3, 0x85, 0x3f},
+	{0x02, 0xc2, 0x02, 0x00},
+	{0x02, 0xc2, 0x0e, 0x00},
+	{0x02, 0xc2, 0x0c, 0x00},
+	{0x02, 0xc2, 0x00, 0x00},
+	{0x03, 0xe2, 0x82, 0x0f},
+	{0x03, 0xe2, 0x94, 0x2a},
+	{0x03, 0xe2, 0x86, 0x39},
+	{0x03, 0xe2, 0x86, 0x3b},
+	{0x03, 0xe2, 0x86, 0x3f},
+	{0x03, 0xe2, 0x96, 0x0d},
+	{0x03, 0xe2, 0x97, 0x25},
+}
+
+// Total table size 15512 bytes (15KiB)
diff --git a/vendor/golang.org/x/text/width/tables17.0.0.go b/vendor/golang.org/x/text/width/tables17.0.0.go
new file mode 100644
index 000000000..026e27f4b
--- /dev/null
+++ b/vendor/golang.org/x/text/width/tables17.0.0.go
@@ -0,0 +1,1384 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+//go:build go1.27
+
+package width
+
+// UnicodeVersion is the Unicode version from which the tables in this package are derived.
+const UnicodeVersion = "17.0.0"
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *widthTrie) lookup(s []byte) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return widthValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = widthIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = widthIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = widthIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *widthTrie) lookupUnsafe(s []byte) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return widthValues[c0]
+	}
+	i := widthIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = widthIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = widthIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *widthTrie) lookupString(s string) (v uint16, sz int) {
+	c0 := s[0]
+	switch {
+	case c0 < 0x80: // is ASCII
+		return widthValues[c0], 1
+	case c0 < 0xC2:
+		return 0, 1 // Illegal UTF-8: not a starter, not ASCII.
+	case c0 < 0xE0: // 2-byte UTF-8
+		if len(s) < 2 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c1), 2
+	case c0 < 0xF0: // 3-byte UTF-8
+		if len(s) < 3 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = widthIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c2), 3
+	case c0 < 0xF8: // 4-byte UTF-8
+		if len(s) < 4 {
+			return 0, 0
+		}
+		i := widthIndex[c0]
+		c1 := s[1]
+		if c1 < 0x80 || 0xC0 <= c1 {
+			return 0, 1 // Illegal UTF-8: not a continuation byte.
+		}
+		o := uint32(i)<<6 + uint32(c1)
+		i = widthIndex[o]
+		c2 := s[2]
+		if c2 < 0x80 || 0xC0 <= c2 {
+			return 0, 2 // Illegal UTF-8: not a continuation byte.
+		}
+		o = uint32(i)<<6 + uint32(c2)
+		i = widthIndex[o]
+		c3 := s[3]
+		if c3 < 0x80 || 0xC0 <= c3 {
+			return 0, 3 // Illegal UTF-8: not a continuation byte.
+		}
+		return t.lookupValue(uint32(i), c3), 4
+	}
+	// Illegal rune
+	return 0, 1
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must start with a full and valid UTF-8 encoded rune.
+func (t *widthTrie) lookupStringUnsafe(s string) uint16 {
+	c0 := s[0]
+	if c0 < 0x80 { // is ASCII
+		return widthValues[c0]
+	}
+	i := widthIndex[c0]
+	if c0 < 0xE0 { // 2-byte UTF-8
+		return t.lookupValue(uint32(i), s[1])
+	}
+	i = widthIndex[uint32(i)<<6+uint32(s[1])]
+	if c0 < 0xF0 { // 3-byte UTF-8
+		return t.lookupValue(uint32(i), s[2])
+	}
+	i = widthIndex[uint32(i)<<6+uint32(s[2])]
+	if c0 < 0xF8 { // 4-byte UTF-8
+		return t.lookupValue(uint32(i), s[3])
+	}
+	return 0
+}
+
+// widthTrie. Total size: 15040 bytes (14.69 KiB). Checksum: 1c37fc66dcf8f532.
+type widthTrie struct{}
+
+func newWidthTrie(i int) *widthTrie {
+	return &widthTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *widthTrie) lookupValue(n uint32, b byte) uint16 {
+	switch {
+	default:
+		return uint16(widthValues[n<<6+uint32(b)])
+	}
+}
+
+// widthValues: 106 blocks, 6784 entries, 13568 bytes
+// The third block is the zero block.
+var widthValues = [6784]uint16{
+	// Block 0x0, offset 0x0
+	0x20: 0x6001, 0x21: 0x6002, 0x22: 0x6002, 0x23: 0x6002,
+	0x24: 0x6002, 0x25: 0x6002, 0x26: 0x6002, 0x27: 0x6002, 0x28: 0x6002, 0x29: 0x6002,
+	0x2a: 0x6002, 0x2b: 0x6002, 0x2c: 0x6002, 0x2d: 0x6002, 0x2e: 0x6002, 0x2f: 0x6002,
+	0x30: 0x6002, 0x31: 0x6002, 0x32: 0x6002, 0x33: 0x6002, 0x34: 0x6002, 0x35: 0x6002,
+	0x36: 0x6002, 0x37: 0x6002, 0x38: 0x6002, 0x39: 0x6002, 0x3a: 0x6002, 0x3b: 0x6002,
+	0x3c: 0x6002, 0x3d: 0x6002, 0x3e: 0x6002, 0x3f: 0x6002,
+	// Block 0x1, offset 0x40
+	0x40: 0x6003, 0x41: 0x6003, 0x42: 0x6003, 0x43: 0x6003, 0x44: 0x6003, 0x45: 0x6003,
+	0x46: 0x6003, 0x47: 0x6003, 0x48: 0x6003, 0x49: 0x6003, 0x4a: 0x6003, 0x4b: 0x6003,
+	0x4c: 0x6003, 0x4d: 0x6003, 0x4e: 0x6003, 0x4f: 0x6003, 0x50: 0x6003, 0x51: 0x6003,
+	0x52: 0x6003, 0x53: 0x6003, 0x54: 0x6003, 0x55: 0x6003, 0x56: 0x6003, 0x57: 0x6003,
+	0x58: 0x6003, 0x59: 0x6003, 0x5a: 0x6003, 0x5b: 0x6003, 0x5c: 0x6003, 0x5d: 0x6003,
+	0x5e: 0x6003, 0x5f: 0x6003, 0x60: 0x6004, 0x61: 0x6004, 0x62: 0x6004, 0x63: 0x6004,
+	0x64: 0x6004, 0x65: 0x6004, 0x66: 0x6004, 0x67: 0x6004, 0x68: 0x6004, 0x69: 0x6004,
+	0x6a: 0x6004, 0x6b: 0x6004, 0x6c: 0x6004, 0x6d: 0x6004, 0x6e: 0x6004, 0x6f: 0x6004,
+	0x70: 0x6004, 0x71: 0x6004, 0x72: 0x6004, 0x73: 0x6004, 0x74: 0x6004, 0x75: 0x6004,
+	0x76: 0x6004, 0x77: 0x6004, 0x78: 0x6004, 0x79: 0x6004, 0x7a: 0x6004, 0x7b: 0x6004,
+	0x7c: 0x6004, 0x7d: 0x6004, 0x7e: 0x6004,
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xe1: 0x2000, 0xe2: 0x6005, 0xe3: 0x6005,
+	0xe4: 0x2000, 0xe5: 0x6006, 0xe6: 0x6005, 0xe7: 0x2000, 0xe8: 0x2000,
+	0xea: 0x2000, 0xec: 0x6007, 0xed: 0x2000, 0xee: 0x2000, 0xef: 0x6008,
+	0xf0: 0x2000, 0xf1: 0x2000, 0xf2: 0x2000, 0xf3: 0x2000, 0xf4: 0x2000,
+	0xf6: 0x2000, 0xf7: 0x2000, 0xf8: 0x2000, 0xf9: 0x2000, 0xfa: 0x2000,
+	0xfc: 0x2000, 0xfd: 0x2000, 0xfe: 0x2000, 0xff: 0x2000,
+	// Block 0x4, offset 0x100
+	0x106: 0x2000,
+	0x110: 0x2000,
+	0x117: 0x2000,
+	0x118: 0x2000,
+	0x11e: 0x2000, 0x11f: 0x2000, 0x120: 0x2000, 0x121: 0x2000,
+	0x126: 0x2000, 0x128: 0x2000, 0x129: 0x2000,
+	0x12a: 0x2000, 0x12c: 0x2000, 0x12d: 0x2000,
+	0x130: 0x2000, 0x132: 0x2000, 0x133: 0x2000,
+	0x137: 0x2000, 0x138: 0x2000, 0x139: 0x2000, 0x13a: 0x2000,
+	0x13c: 0x2000, 0x13e: 0x2000,
+	// Block 0x5, offset 0x140
+	0x141: 0x2000,
+	0x151: 0x2000,
+	0x153: 0x2000,
+	0x15b: 0x2000,
+	0x166: 0x2000, 0x167: 0x2000,
+	0x16b: 0x2000,
+	0x171: 0x2000, 0x172: 0x2000, 0x173: 0x2000,
+	0x178: 0x2000,
+	0x17f: 0x2000,
+	// Block 0x6, offset 0x180
+	0x180: 0x2000, 0x181: 0x2000, 0x182: 0x2000, 0x184: 0x2000,
+	0x188: 0x2000, 0x189: 0x2000, 0x18a: 0x2000, 0x18b: 0x2000,
+	0x18d: 0x2000,
+	0x192: 0x2000, 0x193: 0x2000,
+	0x1a6: 0x2000, 0x1a7: 0x2000,
+	0x1ab: 0x2000,
+	// Block 0x7, offset 0x1c0
+	0x1ce: 0x2000, 0x1d0: 0x2000,
+	0x1d2: 0x2000, 0x1d4: 0x2000, 0x1d6: 0x2000,
+	0x1d8: 0x2000, 0x1da: 0x2000, 0x1dc: 0x2000,
+	// Block 0x8, offset 0x200
+	0x211: 0x2000,
+	0x221: 0x2000,
+	// Block 0x9, offset 0x240
+	0x244: 0x2000,
+	0x247: 0x2000, 0x249: 0x2000, 0x24a: 0x2000, 0x24b: 0x2000,
+	0x24d: 0x2000, 0x250: 0x2000,
+	0x258: 0x2000, 0x259: 0x2000, 0x25a: 0x2000, 0x25b: 0x2000, 0x25d: 0x2000,
+	0x25f: 0x2000,
+	// Block 0xa, offset 0x280
+	0x280: 0x2000, 0x281: 0x2000, 0x282: 0x2000, 0x283: 0x2000, 0x284: 0x2000, 0x285: 0x2000,
+	0x286: 0x2000, 0x287: 0x2000, 0x288: 0x2000, 0x289: 0x2000, 0x28a: 0x2000, 0x28b: 0x2000,
+	0x28c: 0x2000, 0x28d: 0x2000, 0x28e: 0x2000, 0x28f: 0x2000, 0x290: 0x2000, 0x291: 0x2000,
+	0x292: 0x2000, 0x293: 0x2000, 0x294: 0x2000, 0x295: 0x2000, 0x296: 0x2000, 0x297: 0x2000,
+	0x298: 0x2000, 0x299: 0x2000, 0x29a: 0x2000, 0x29b: 0x2000, 0x29c: 0x2000, 0x29d: 0x2000,
+	0x29e: 0x2000, 0x29f: 0x2000, 0x2a0: 0x2000, 0x2a1: 0x2000, 0x2a2: 0x2000, 0x2a3: 0x2000,
+	0x2a4: 0x2000, 0x2a5: 0x2000, 0x2a6: 0x2000, 0x2a7: 0x2000, 0x2a8: 0x2000, 0x2a9: 0x2000,
+	0x2aa: 0x2000, 0x2ab: 0x2000, 0x2ac: 0x2000, 0x2ad: 0x2000, 0x2ae: 0x2000, 0x2af: 0x2000,
+	0x2b0: 0x2000, 0x2b1: 0x2000, 0x2b2: 0x2000, 0x2b3: 0x2000, 0x2b4: 0x2000, 0x2b5: 0x2000,
+	0x2b6: 0x2000, 0x2b7: 0x2000, 0x2b8: 0x2000, 0x2b9: 0x2000, 0x2ba: 0x2000, 0x2bb: 0x2000,
+	0x2bc: 0x2000, 0x2bd: 0x2000, 0x2be: 0x2000, 0x2bf: 0x2000,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x2000, 0x2c1: 0x2000, 0x2c2: 0x2000, 0x2c3: 0x2000, 0x2c4: 0x2000, 0x2c5: 0x2000,
+	0x2c6: 0x2000, 0x2c7: 0x2000, 0x2c8: 0x2000, 0x2c9: 0x2000, 0x2ca: 0x2000, 0x2cb: 0x2000,
+	0x2cc: 0x2000, 0x2cd: 0x2000, 0x2ce: 0x2000, 0x2cf: 0x2000, 0x2d0: 0x2000, 0x2d1: 0x2000,
+	0x2d2: 0x2000, 0x2d3: 0x2000, 0x2d4: 0x2000, 0x2d5: 0x2000, 0x2d6: 0x2000, 0x2d7: 0x2000,
+	0x2d8: 0x2000, 0x2d9: 0x2000, 0x2da: 0x2000, 0x2db: 0x2000, 0x2dc: 0x2000, 0x2dd: 0x2000,
+	0x2de: 0x2000, 0x2df: 0x2000, 0x2e0: 0x2000, 0x2e1: 0x2000, 0x2e2: 0x2000, 0x2e3: 0x2000,
+	0x2e4: 0x2000, 0x2e5: 0x2000, 0x2e6: 0x2000, 0x2e7: 0x2000, 0x2e8: 0x2000, 0x2e9: 0x2000,
+	0x2ea: 0x2000, 0x2eb: 0x2000, 0x2ec: 0x2000, 0x2ed: 0x2000, 0x2ee: 0x2000, 0x2ef: 0x2000,
+	// Block 0xc, offset 0x300
+	0x311: 0x2000,
+	0x312: 0x2000, 0x313: 0x2000, 0x314: 0x2000, 0x315: 0x2000, 0x316: 0x2000, 0x317: 0x2000,
+	0x318: 0x2000, 0x319: 0x2000, 0x31a: 0x2000, 0x31b: 0x2000, 0x31c: 0x2000, 0x31d: 0x2000,
+	0x31e: 0x2000, 0x31f: 0x2000, 0x320: 0x2000, 0x321: 0x2000, 0x323: 0x2000,
+	0x324: 0x2000, 0x325: 0x2000, 0x326: 0x2000, 0x327: 0x2000, 0x328: 0x2000, 0x329: 0x2000,
+	0x331: 0x2000, 0x332: 0x2000, 0x333: 0x2000, 0x334: 0x2000, 0x335: 0x2000,
+	0x336: 0x2000, 0x337: 0x2000, 0x338: 0x2000, 0x339: 0x2000, 0x33a: 0x2000, 0x33b: 0x2000,
+	0x33c: 0x2000, 0x33d: 0x2000, 0x33e: 0x2000, 0x33f: 0x2000,
+	// Block 0xd, offset 0x340
+	0x340: 0x2000, 0x341: 0x2000, 0x343: 0x2000, 0x344: 0x2000, 0x345: 0x2000,
+	0x346: 0x2000, 0x347: 0x2000, 0x348: 0x2000, 0x349: 0x2000,
+	// Block 0xe, offset 0x380
+	0x381: 0x2000,
+	0x390: 0x2000, 0x391: 0x2000,
+	0x392: 0x2000, 0x393: 0x2000, 0x394: 0x2000, 0x395: 0x2000, 0x396: 0x2000, 0x397: 0x2000,
+	0x398: 0x2000, 0x399: 0x2000, 0x39a: 0x2000, 0x39b: 0x2000, 0x39c: 0x2000, 0x39d: 0x2000,
+	0x39e: 0x2000, 0x39f: 0x2000, 0x3a0: 0x2000, 0x3a1: 0x2000, 0x3a2: 0x2000, 0x3a3: 0x2000,
+	0x3a4: 0x2000, 0x3a5: 0x2000, 0x3a6: 0x2000, 0x3a7: 0x2000, 0x3a8: 0x2000, 0x3a9: 0x2000,
+	0x3aa: 0x2000, 0x3ab: 0x2000, 0x3ac: 0x2000, 0x3ad: 0x2000, 0x3ae: 0x2000, 0x3af: 0x2000,
+	0x3b0: 0x2000, 0x3b1: 0x2000, 0x3b2: 0x2000, 0x3b3: 0x2000, 0x3b4: 0x2000, 0x3b5: 0x2000,
+	0x3b6: 0x2000, 0x3b7: 0x2000, 0x3b8: 0x2000, 0x3b9: 0x2000, 0x3ba: 0x2000, 0x3bb: 0x2000,
+	0x3bc: 0x2000, 0x3bd: 0x2000, 0x3be: 0x2000, 0x3bf: 0x2000,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x2000, 0x3c1: 0x2000, 0x3c2: 0x2000, 0x3c3: 0x2000, 0x3c4: 0x2000, 0x3c5: 0x2000,
+	0x3c6: 0x2000, 0x3c7: 0x2000, 0x3c8: 0x2000, 0x3c9: 0x2000, 0x3ca: 0x2000, 0x3cb: 0x2000,
+	0x3cc: 0x2000, 0x3cd: 0x2000, 0x3ce: 0x2000, 0x3cf: 0x2000, 0x3d1: 0x2000,
+	// Block 0x10, offset 0x400
+	0x400: 0x4000, 0x401: 0x4000, 0x402: 0x4000, 0x403: 0x4000, 0x404: 0x4000, 0x405: 0x4000,
+	0x406: 0x4000, 0x407: 0x4000, 0x408: 0x4000, 0x409: 0x4000, 0x40a: 0x4000, 0x40b: 0x4000,
+	0x40c: 0x4000, 0x40d: 0x4000, 0x40e: 0x4000, 0x40f: 0x4000, 0x410: 0x4000, 0x411: 0x4000,
+	0x412: 0x4000, 0x413: 0x4000, 0x414: 0x4000, 0x415: 0x4000, 0x416: 0x4000, 0x417: 0x4000,
+	0x418: 0x4000, 0x419: 0x4000, 0x41a: 0x4000, 0x41b: 0x4000, 0x41c: 0x4000, 0x41d: 0x4000,
+	0x41e: 0x4000, 0x41f: 0x4000, 0x420: 0x4000, 0x421: 0x4000, 0x422: 0x4000, 0x423: 0x4000,
+	0x424: 0x4000, 0x425: 0x4000, 0x426: 0x4000, 0x427: 0x4000, 0x428: 0x4000, 0x429: 0x4000,
+	0x42a: 0x4000, 0x42b: 0x4000, 0x42c: 0x4000, 0x42d: 0x4000, 0x42e: 0x4000, 0x42f: 0x4000,
+	0x430: 0x4000, 0x431: 0x4000, 0x432: 0x4000, 0x433: 0x4000, 0x434: 0x4000, 0x435: 0x4000,
+	0x436: 0x4000, 0x437: 0x4000, 0x438: 0x4000, 0x439: 0x4000, 0x43a: 0x4000, 0x43b: 0x4000,
+	0x43c: 0x4000, 0x43d: 0x4000, 0x43e: 0x4000, 0x43f: 0x4000,
+	// Block 0x11, offset 0x440
+	0x440: 0x4000, 0x441: 0x4000, 0x442: 0x4000, 0x443: 0x4000, 0x444: 0x4000, 0x445: 0x4000,
+	0x446: 0x4000, 0x447: 0x4000, 0x448: 0x4000, 0x449: 0x4000, 0x44a: 0x4000, 0x44b: 0x4000,
+	0x44c: 0x4000, 0x44d: 0x4000, 0x44e: 0x4000, 0x44f: 0x4000, 0x450: 0x4000, 0x451: 0x4000,
+	0x452: 0x4000, 0x453: 0x4000, 0x454: 0x4000, 0x455: 0x4000, 0x456: 0x4000, 0x457: 0x4000,
+	0x458: 0x4000, 0x459: 0x4000, 0x45a: 0x4000, 0x45b: 0x4000, 0x45c: 0x4000, 0x45d: 0x4000,
+	0x45e: 0x4000, 0x45f: 0x4000,
+	// Block 0x12, offset 0x480
+	0x490: 0x2000,
+	0x493: 0x2000, 0x494: 0x2000, 0x495: 0x2000, 0x496: 0x2000,
+	0x498: 0x2000, 0x499: 0x2000, 0x49c: 0x2000, 0x49d: 0x2000,
+	0x4a0: 0x2000, 0x4a1: 0x2000, 0x4a2: 0x2000,
+	0x4a4: 0x2000, 0x4a5: 0x2000, 0x4a6: 0x2000, 0x4a7: 0x2000,
+	0x4b0: 0x2000, 0x4b2: 0x2000, 0x4b3: 0x2000, 0x4b5: 0x2000,
+	0x4bb: 0x2000,
+	0x4be: 0x2000,
+	// Block 0x13, offset 0x4c0
+	0x4f4: 0x2000,
+	0x4ff: 0x2000,
+	// Block 0x14, offset 0x500
+	0x501: 0x2000, 0x502: 0x2000, 0x503: 0x2000, 0x504: 0x2000,
+	0x529: 0xa009,
+	0x52c: 0x2000,
+	// Block 0x15, offset 0x540
+	0x543: 0x2000, 0x545: 0x2000,
+	0x549: 0x2000,
+	0x553: 0x2000, 0x556: 0x2000,
+	0x561: 0x2000, 0x562: 0x2000,
+	0x566: 0x2000,
+	0x56b: 0x2000,
+	// Block 0x16, offset 0x580
+	0x593: 0x2000, 0x594: 0x2000,
+	0x59b: 0x2000, 0x59c: 0x2000, 0x59d: 0x2000,
+	0x59e: 0x2000, 0x5a0: 0x2000, 0x5a1: 0x2000, 0x5a2: 0x2000, 0x5a3: 0x2000,
+	0x5a4: 0x2000, 0x5a5: 0x2000, 0x5a6: 0x2000, 0x5a7: 0x2000, 0x5a8: 0x2000, 0x5a9: 0x2000,
+	0x5aa: 0x2000, 0x5ab: 0x2000,
+	0x5b0: 0x2000, 0x5b1: 0x2000, 0x5b2: 0x2000, 0x5b3: 0x2000, 0x5b4: 0x2000, 0x5b5: 0x2000,
+	0x5b6: 0x2000, 0x5b7: 0x2000, 0x5b8: 0x2000, 0x5b9: 0x2000,
+	// Block 0x17, offset 0x5c0
+	0x5c9: 0x2000,
+	0x5d0: 0x200a, 0x5d1: 0x200b,
+	0x5d2: 0x200a, 0x5d3: 0x200c, 0x5d4: 0x2000, 0x5d5: 0x2000, 0x5d6: 0x2000, 0x5d7: 0x2000,
+	0x5d8: 0x2000, 0x5d9: 0x2000,
+	0x5f8: 0x2000, 0x5f9: 0x2000,
+	// Block 0x18, offset 0x600
+	0x612: 0x2000, 0x614: 0x2000,
+	0x627: 0x2000,
+	// Block 0x19, offset 0x640
+	0x640: 0x2000, 0x642: 0x2000, 0x643: 0x2000,
+	0x647: 0x2000, 0x648: 0x2000, 0x64b: 0x2000,
+	0x64f: 0x2000, 0x651: 0x2000,
+	0x655: 0x2000,
+	0x65a: 0x2000, 0x65d: 0x2000,
+	0x65e: 0x2000, 0x65f: 0x2000, 0x660: 0x2000, 0x663: 0x2000,
+	0x665: 0x2000, 0x667: 0x2000, 0x668: 0x2000, 0x669: 0x2000,
+	0x66a: 0x2000, 0x66b: 0x2000, 0x66c: 0x2000, 0x66e: 0x2000,
+	0x674: 0x2000, 0x675: 0x2000,
+	0x676: 0x2000, 0x677: 0x2000,
+	0x67c: 0x2000, 0x67d: 0x2000,
+	// Block 0x1a, offset 0x680
+	0x688: 0x2000,
+	0x68c: 0x2000,
+	0x692: 0x2000,
+	0x6a0: 0x2000, 0x6a1: 0x2000,
+	0x6a4: 0x2000, 0x6a5: 0x2000, 0x6a6: 0x2000, 0x6a7: 0x2000,
+	0x6aa: 0x2000, 0x6ab: 0x2000, 0x6ae: 0x2000, 0x6af: 0x2000,
+	// Block 0x1b, offset 0x6c0
+	0x6c2: 0x2000, 0x6c3: 0x2000,
+	0x6c6: 0x2000, 0x6c7: 0x2000,
+	0x6d5: 0x2000,
+	0x6d9: 0x2000,
+	0x6e5: 0x2000,
+	0x6ff: 0x2000,
+	// Block 0x1c, offset 0x700
+	0x712: 0x2000,
+	0x71a: 0x4000, 0x71b: 0x4000,
+	0x729: 0x4000,
+	0x72a: 0x4000,
+	// Block 0x1d, offset 0x740
+	0x769: 0x4000,
+	0x76a: 0x4000, 0x76b: 0x4000, 0x76c: 0x4000,
+	0x770: 0x4000, 0x773: 0x4000,
+	// Block 0x1e, offset 0x780
+	0x7a0: 0x2000, 0x7a1: 0x2000, 0x7a2: 0x2000, 0x7a3: 0x2000,
+	0x7a4: 0x2000, 0x7a5: 0x2000, 0x7a6: 0x2000, 0x7a7: 0x2000, 0x7a8: 0x2000, 0x7a9: 0x2000,
+	0x7aa: 0x2000, 0x7ab: 0x2000, 0x7ac: 0x2000, 0x7ad: 0x2000, 0x7ae: 0x2000, 0x7af: 0x2000,
+	0x7b0: 0x2000, 0x7b1: 0x2000, 0x7b2: 0x2000, 0x7b3: 0x2000, 0x7b4: 0x2000, 0x7b5: 0x2000,
+	0x7b6: 0x2000, 0x7b7: 0x2000, 0x7b8: 0x2000, 0x7b9: 0x2000, 0x7ba: 0x2000, 0x7bb: 0x2000,
+	0x7bc: 0x2000, 0x7bd: 0x2000, 0x7be: 0x2000, 0x7bf: 0x2000,
+	// Block 0x1f, offset 0x7c0
+	0x7c0: 0x2000, 0x7c1: 0x2000, 0x7c2: 0x2000, 0x7c3: 0x2000, 0x7c4: 0x2000, 0x7c5: 0x2000,
+	0x7c6: 0x2000, 0x7c7: 0x2000, 0x7c8: 0x2000, 0x7c9: 0x2000, 0x7ca: 0x2000, 0x7cb: 0x2000,
+	0x7cc: 0x2000, 0x7cd: 0x2000, 0x7ce: 0x2000, 0x7cf: 0x2000, 0x7d0: 0x2000, 0x7d1: 0x2000,
+	0x7d2: 0x2000, 0x7d3: 0x2000, 0x7d4: 0x2000, 0x7d5: 0x2000, 0x7d6: 0x2000, 0x7d7: 0x2000,
+	0x7d8: 0x2000, 0x7d9: 0x2000, 0x7da: 0x2000, 0x7db: 0x2000, 0x7dc: 0x2000, 0x7dd: 0x2000,
+	0x7de: 0x2000, 0x7df: 0x2000, 0x7e0: 0x2000, 0x7e1: 0x2000, 0x7e2: 0x2000, 0x7e3: 0x2000,
+	0x7e4: 0x2000, 0x7e5: 0x2000, 0x7e6: 0x2000, 0x7e7: 0x2000, 0x7e8: 0x2000, 0x7e9: 0x2000,
+	0x7eb: 0x2000, 0x7ec: 0x2000, 0x7ed: 0x2000, 0x7ee: 0x2000, 0x7ef: 0x2000,
+	0x7f0: 0x2000, 0x7f1: 0x2000, 0x7f2: 0x2000, 0x7f3: 0x2000, 0x7f4: 0x2000, 0x7f5: 0x2000,
+	0x7f6: 0x2000, 0x7f7: 0x2000, 0x7f8: 0x2000, 0x7f9: 0x2000, 0x7fa: 0x2000, 0x7fb: 0x2000,
+	0x7fc: 0x2000, 0x7fd: 0x2000, 0x7fe: 0x2000, 0x7ff: 0x2000,
+	// Block 0x20, offset 0x800
+	0x800: 0x2000, 0x801: 0x2000, 0x802: 0x200d, 0x803: 0x2000, 0x804: 0x2000, 0x805: 0x2000,
+	0x806: 0x2000, 0x807: 0x2000, 0x808: 0x2000, 0x809: 0x2000, 0x80a: 0x2000, 0x80b: 0x2000,
+	0x80c: 0x2000, 0x80d: 0x2000, 0x80e: 0x2000, 0x80f: 0x2000, 0x810: 0x2000, 0x811: 0x2000,
+	0x812: 0x2000, 0x813: 0x2000, 0x814: 0x2000, 0x815: 0x2000, 0x816: 0x2000, 0x817: 0x2000,
+	0x818: 0x2000, 0x819: 0x2000, 0x81a: 0x2000, 0x81b: 0x2000, 0x81c: 0x2000, 0x81d: 0x2000,
+	0x81e: 0x2000, 0x81f: 0x2000, 0x820: 0x2000, 0x821: 0x2000, 0x822: 0x2000, 0x823: 0x2000,
+	0x824: 0x2000, 0x825: 0x2000, 0x826: 0x2000, 0x827: 0x2000, 0x828: 0x2000, 0x829: 0x2000,
+	0x82a: 0x2000, 0x82b: 0x2000, 0x82c: 0x2000, 0x82d: 0x2000, 0x82e: 0x2000, 0x82f: 0x2000,
+	0x830: 0x2000, 0x831: 0x2000, 0x832: 0x2000, 0x833: 0x2000, 0x834: 0x2000, 0x835: 0x2000,
+	0x836: 0x2000, 0x837: 0x2000, 0x838: 0x2000, 0x839: 0x2000, 0x83a: 0x2000, 0x83b: 0x2000,
+	0x83c: 0x2000, 0x83d: 0x2000, 0x83e: 0x2000, 0x83f: 0x2000,
+	// Block 0x21, offset 0x840
+	0x840: 0x2000, 0x841: 0x2000, 0x842: 0x2000, 0x843: 0x2000, 0x844: 0x2000, 0x845: 0x2000,
+	0x846: 0x2000, 0x847: 0x2000, 0x848: 0x2000, 0x849: 0x2000, 0x84a: 0x2000, 0x84b: 0x2000,
+	0x850: 0x2000, 0x851: 0x2000,
+	0x852: 0x2000, 0x853: 0x2000, 0x854: 0x2000, 0x855: 0x2000, 0x856: 0x2000, 0x857: 0x2000,
+	0x858: 0x2000, 0x859: 0x2000, 0x85a: 0x2000, 0x85b: 0x2000, 0x85c: 0x2000, 0x85d: 0x2000,
+	0x85e: 0x2000, 0x85f: 0x2000, 0x860: 0x2000, 0x861: 0x2000, 0x862: 0x2000, 0x863: 0x2000,
+	0x864: 0x2000, 0x865: 0x2000, 0x866: 0x2000, 0x867: 0x2000, 0x868: 0x2000, 0x869: 0x2000,
+	0x86a: 0x2000, 0x86b: 0x2000, 0x86c: 0x2000, 0x86d: 0x2000, 0x86e: 0x2000, 0x86f: 0x2000,
+	0x870: 0x2000, 0x871: 0x2000, 0x872: 0x2000, 0x873: 0x2000,
+	// Block 0x22, offset 0x880
+	0x880: 0x2000, 0x881: 0x2000, 0x882: 0x2000, 0x883: 0x2000, 0x884: 0x2000, 0x885: 0x2000,
+	0x886: 0x2000, 0x887: 0x2000, 0x888: 0x2000, 0x889: 0x2000, 0x88a: 0x2000, 0x88b: 0x2000,
+	0x88c: 0x2000, 0x88d: 0x2000, 0x88e: 0x2000, 0x88f: 0x2000,
+	0x892: 0x2000, 0x893: 0x2000, 0x894: 0x2000, 0x895: 0x2000,
+	0x8a0: 0x200e, 0x8a1: 0x2000, 0x8a3: 0x2000,
+	0x8a4: 0x2000, 0x8a5: 0x2000, 0x8a6: 0x2000, 0x8a7: 0x2000, 0x8a8: 0x2000, 0x8a9: 0x2000,
+	0x8b2: 0x2000, 0x8b3: 0x2000,
+	0x8b6: 0x2000, 0x8b7: 0x2000,
+	0x8bc: 0x2000, 0x8bd: 0x2000,
+	// Block 0x23, offset 0x8c0
+	0x8c0: 0x2000, 0x8c1: 0x2000,
+	0x8c6: 0x2000, 0x8c7: 0x2000, 0x8c8: 0x2000, 0x8cb: 0x200f,
+	0x8ce: 0x2000, 0x8cf: 0x2000, 0x8d0: 0x2000, 0x8d1: 0x2000,
+	0x8e2: 0x2000, 0x8e3: 0x2000,
+	0x8e4: 0x2000, 0x8e5: 0x2000,
+	0x8ef: 0x2000,
+	0x8fd: 0x4000, 0x8fe: 0x4000,
+	// Block 0x24, offset 0x900
+	0x905: 0x2000,
+	0x906: 0x2000, 0x909: 0x2000,
+	0x90e: 0x2000, 0x90f: 0x2000,
+	0x914: 0x4000, 0x915: 0x4000,
+	0x91c: 0x2000,
+	0x91e: 0x2000,
+	0x930: 0x4000, 0x931: 0x4000, 0x932: 0x4000, 0x933: 0x4000, 0x934: 0x4000, 0x935: 0x4000,
+	0x936: 0x4000, 0x937: 0x4000,
+	// Block 0x25, offset 0x940
+	0x940: 0x2000, 0x942: 0x2000,
+	0x948: 0x4000, 0x949: 0x4000, 0x94a: 0x4000, 0x94b: 0x4000,
+	0x94c: 0x4000, 0x94d: 0x4000, 0x94e: 0x4000, 0x94f: 0x4000, 0x950: 0x4000, 0x951: 0x4000,
+	0x952: 0x4000, 0x953: 0x4000,
+	0x960: 0x2000, 0x961: 0x2000, 0x963: 0x2000,
+	0x964: 0x2000, 0x965: 0x2000, 0x967: 0x2000, 0x968: 0x2000, 0x969: 0x2000,
+	0x96a: 0x2000, 0x96c: 0x2000, 0x96d: 0x2000, 0x96f: 0x2000,
+	0x97f: 0x4000,
+	// Block 0x26, offset 0x980
+	0x98a: 0x4000, 0x98b: 0x4000,
+	0x98c: 0x4000, 0x98d: 0x4000, 0x98e: 0x4000, 0x98f: 0x4000,
+	0x993: 0x4000,
+	0x99e: 0x2000, 0x99f: 0x2000, 0x9a1: 0x4000,
+	0x9aa: 0x4000, 0x9ab: 0x4000,
+	0x9bd: 0x4000, 0x9be: 0x4000, 0x9bf: 0x2000,
+	// Block 0x27, offset 0x9c0
+	0x9c4: 0x4000, 0x9c5: 0x4000,
+	0x9c6: 0x2000, 0x9c7: 0x2000, 0x9c8: 0x2000, 0x9c9: 0x2000, 0x9ca: 0x2000, 0x9cb: 0x2000,
+	0x9cc: 0x2000, 0x9cd: 0x2000, 0x9ce: 0x4000, 0x9cf: 0x2000, 0x9d0: 0x2000, 0x9d1: 0x2000,
+	0x9d2: 0x2000, 0x9d3: 0x2000, 0x9d4: 0x4000, 0x9d5: 0x2000, 0x9d6: 0x2000, 0x9d7: 0x2000,
+	0x9d8: 0x2000, 0x9d9: 0x2000, 0x9da: 0x2000, 0x9db: 0x2000, 0x9dc: 0x2000, 0x9dd: 0x2000,
+	0x9de: 0x2000, 0x9df: 0x2000, 0x9e0: 0x2000, 0x9e1: 0x2000, 0x9e3: 0x2000,
+	0x9e8: 0x2000, 0x9e9: 0x2000,
+	0x9ea: 0x4000, 0x9eb: 0x2000, 0x9ec: 0x2000, 0x9ed: 0x2000, 0x9ee: 0x2000, 0x9ef: 0x2000,
+	0x9f0: 0x2000, 0x9f1: 0x2000, 0x9f2: 0x4000, 0x9f3: 0x4000, 0x9f4: 0x2000, 0x9f5: 0x4000,
+	0x9f6: 0x2000, 0x9f7: 0x2000, 0x9f8: 0x2000, 0x9f9: 0x2000, 0x9fa: 0x4000, 0x9fb: 0x2000,
+	0x9fc: 0x2000, 0x9fd: 0x4000, 0x9fe: 0x2000, 0x9ff: 0x2000,
+	// Block 0x28, offset 0xa00
+	0xa05: 0x4000,
+	0xa0a: 0x4000, 0xa0b: 0x4000,
+	0xa28: 0x4000,
+	0xa3d: 0x2000,
+	// Block 0x29, offset 0xa40
+	0xa4c: 0x4000, 0xa4e: 0x4000,
+	0xa53: 0x4000, 0xa54: 0x4000, 0xa55: 0x4000, 0xa57: 0x4000,
+	0xa76: 0x2000, 0xa77: 0x2000, 0xa78: 0x2000, 0xa79: 0x2000, 0xa7a: 0x2000, 0xa7b: 0x2000,
+	0xa7c: 0x2000, 0xa7d: 0x2000, 0xa7e: 0x2000, 0xa7f: 0x2000,
+	// Block 0x2a, offset 0xa80
+	0xa95: 0x4000, 0xa96: 0x4000, 0xa97: 0x4000,
+	0xab0: 0x4000,
+	0xabf: 0x4000,
+	// Block 0x2b, offset 0xac0
+	0xae6: 0x6000, 0xae7: 0x6000, 0xae8: 0x6000, 0xae9: 0x6000,
+	0xaea: 0x6000, 0xaeb: 0x6000, 0xaec: 0x6000, 0xaed: 0x6000,
+	// Block 0x2c, offset 0xb00
+	0xb05: 0x6010,
+	0xb06: 0x6011,
+	// Block 0x2d, offset 0xb40
+	0xb5b: 0x4000, 0xb5c: 0x4000,
+	// Block 0x2e, offset 0xb80
+	0xb90: 0x4000,
+	0xb95: 0x4000, 0xb96: 0x2000, 0xb97: 0x2000,
+	0xb98: 0x2000, 0xb99: 0x2000,
+	// Block 0x2f, offset 0xbc0
+	0xbc0: 0x4000, 0xbc1: 0x4000, 0xbc2: 0x4000, 0xbc3: 0x4000, 0xbc4: 0x4000, 0xbc5: 0x4000,
+	0xbc6: 0x4000, 0xbc7: 0x4000, 0xbc8: 0x4000, 0xbc9: 0x4000, 0xbca: 0x4000, 0xbcb: 0x4000,
+	0xbcc: 0x4000, 0xbcd: 0x4000, 0xbce: 0x4000, 0xbcf: 0x4000, 0xbd0: 0x4000, 0xbd1: 0x4000,
+	0xbd2: 0x4000, 0xbd3: 0x4000, 0xbd4: 0x4000, 0xbd5: 0x4000, 0xbd6: 0x4000, 0xbd7: 0x4000,
+	0xbd8: 0x4000, 0xbd9: 0x4000, 0xbdb: 0x4000, 0xbdc: 0x4000, 0xbdd: 0x4000,
+	0xbde: 0x4000, 0xbdf: 0x4000, 0xbe0: 0x4000, 0xbe1: 0x4000, 0xbe2: 0x4000, 0xbe3: 0x4000,
+	0xbe4: 0x4000, 0xbe5: 0x4000, 0xbe6: 0x4000, 0xbe7: 0x4000, 0xbe8: 0x4000, 0xbe9: 0x4000,
+	0xbea: 0x4000, 0xbeb: 0x4000, 0xbec: 0x4000, 0xbed: 0x4000, 0xbee: 0x4000, 0xbef: 0x4000,
+	0xbf0: 0x4000, 0xbf1: 0x4000, 0xbf2: 0x4000, 0xbf3: 0x4000, 0xbf4: 0x4000, 0xbf5: 0x4000,
+	0xbf6: 0x4000, 0xbf7: 0x4000, 0xbf8: 0x4000, 0xbf9: 0x4000, 0xbfa: 0x4000, 0xbfb: 0x4000,
+	0xbfc: 0x4000, 0xbfd: 0x4000, 0xbfe: 0x4000, 0xbff: 0x4000,
+	// Block 0x30, offset 0xc00
+	0xc00: 0x4000, 0xc01: 0x4000, 0xc02: 0x4000, 0xc03: 0x4000, 0xc04: 0x4000, 0xc05: 0x4000,
+	0xc06: 0x4000, 0xc07: 0x4000, 0xc08: 0x4000, 0xc09: 0x4000, 0xc0a: 0x4000, 0xc0b: 0x4000,
+	0xc0c: 0x4000, 0xc0d: 0x4000, 0xc0e: 0x4000, 0xc0f: 0x4000, 0xc10: 0x4000, 0xc11: 0x4000,
+	0xc12: 0x4000, 0xc13: 0x4000, 0xc14: 0x4000, 0xc15: 0x4000, 0xc16: 0x4000, 0xc17: 0x4000,
+	0xc18: 0x4000, 0xc19: 0x4000, 0xc1a: 0x4000, 0xc1b: 0x4000, 0xc1c: 0x4000, 0xc1d: 0x4000,
+	0xc1e: 0x4000, 0xc1f: 0x4000, 0xc20: 0x4000, 0xc21: 0x4000, 0xc22: 0x4000, 0xc23: 0x4000,
+	0xc24: 0x4000, 0xc25: 0x4000, 0xc26: 0x4000, 0xc27: 0x4000, 0xc28: 0x4000, 0xc29: 0x4000,
+	0xc2a: 0x4000, 0xc2b: 0x4000, 0xc2c: 0x4000, 0xc2d: 0x4000, 0xc2e: 0x4000, 0xc2f: 0x4000,
+	0xc30: 0x4000, 0xc31: 0x4000, 0xc32: 0x4000, 0xc33: 0x4000,
+	// Block 0x31, offset 0xc40
+	0xc40: 0x4000, 0xc41: 0x4000, 0xc42: 0x4000, 0xc43: 0x4000, 0xc44: 0x4000, 0xc45: 0x4000,
+	0xc46: 0x4000, 0xc47: 0x4000, 0xc48: 0x4000, 0xc49: 0x4000, 0xc4a: 0x4000, 0xc4b: 0x4000,
+	0xc4c: 0x4000, 0xc4d: 0x4000, 0xc4e: 0x4000, 0xc4f: 0x4000, 0xc50: 0x4000, 0xc51: 0x4000,
+	0xc52: 0x4000, 0xc53: 0x4000, 0xc54: 0x4000, 0xc55: 0x4000,
+	0xc70: 0x4000, 0xc71: 0x4000, 0xc72: 0x4000, 0xc73: 0x4000, 0xc74: 0x4000, 0xc75: 0x4000,
+	0xc76: 0x4000, 0xc77: 0x4000, 0xc78: 0x4000, 0xc79: 0x4000, 0xc7a: 0x4000, 0xc7b: 0x4000,
+	0xc7c: 0x4000, 0xc7d: 0x4000, 0xc7e: 0x4000, 0xc7f: 0x4000,
+	// Block 0x32, offset 0xc80
+	0xc80: 0x9012, 0xc81: 0x4013, 0xc82: 0x4014, 0xc83: 0x4000, 0xc84: 0x4000, 0xc85: 0x4000,
+	0xc86: 0x4000, 0xc87: 0x4000, 0xc88: 0x4000, 0xc89: 0x4000, 0xc8a: 0x4000, 0xc8b: 0x4000,
+	0xc8c: 0x4015, 0xc8d: 0x4015, 0xc8e: 0x4000, 0xc8f: 0x4000, 0xc90: 0x4000, 0xc91: 0x4000,
+	0xc92: 0x4000, 0xc93: 0x4000, 0xc94: 0x4000, 0xc95: 0x4000, 0xc96: 0x4000, 0xc97: 0x4000,
+	0xc98: 0x4000, 0xc99: 0x4000, 0xc9a: 0x4000, 0xc9b: 0x4000, 0xc9c: 0x4000, 0xc9d: 0x4000,
+	0xc9e: 0x4000, 0xc9f: 0x4000, 0xca0: 0x4000, 0xca1: 0x4000, 0xca2: 0x4000, 0xca3: 0x4000,
+	0xca4: 0x4000, 0xca5: 0x4000, 0xca6: 0x4000, 0xca7: 0x4000, 0xca8: 0x4000, 0xca9: 0x4000,
+	0xcaa: 0x4000, 0xcab: 0x4000, 0xcac: 0x4000, 0xcad: 0x4000, 0xcae: 0x4000, 0xcaf: 0x4000,
+	0xcb0: 0x4000, 0xcb1: 0x4000, 0xcb2: 0x4000, 0xcb3: 0x4000, 0xcb4: 0x4000, 0xcb5: 0x4000,
+	0xcb6: 0x4000, 0xcb7: 0x4000, 0xcb8: 0x4000, 0xcb9: 0x4000, 0xcba: 0x4000, 0xcbb: 0x4000,
+	0xcbc: 0x4000, 0xcbd: 0x4000, 0xcbe: 0x4000,
+	// Block 0x33, offset 0xcc0
+	0xcc1: 0x4000, 0xcc2: 0x4000, 0xcc3: 0x4000, 0xcc4: 0x4000, 0xcc5: 0x4000,
+	0xcc6: 0x4000, 0xcc7: 0x4000, 0xcc8: 0x4000, 0xcc9: 0x4000, 0xcca: 0x4000, 0xccb: 0x4000,
+	0xccc: 0x4000, 0xccd: 0x4000, 0xcce: 0x4000, 0xccf: 0x4000, 0xcd0: 0x4000, 0xcd1: 0x4000,
+	0xcd2: 0x4000, 0xcd3: 0x4000, 0xcd4: 0x4000, 0xcd5: 0x4000, 0xcd6: 0x4000, 0xcd7: 0x4000,
+	0xcd8: 0x4000, 0xcd9: 0x4000, 0xcda: 0x4000, 0xcdb: 0x4000, 0xcdc: 0x4000, 0xcdd: 0x4000,
+	0xcde: 0x4000, 0xcdf: 0x4000, 0xce0: 0x4000, 0xce1: 0x4000, 0xce2: 0x4000, 0xce3: 0x4000,
+	0xce4: 0x4000, 0xce5: 0x4000, 0xce6: 0x4000, 0xce7: 0x4000, 0xce8: 0x4000, 0xce9: 0x4000,
+	0xcea: 0x4000, 0xceb: 0x4000, 0xcec: 0x4000, 0xced: 0x4000, 0xcee: 0x4000, 0xcef: 0x4000,
+	0xcf0: 0x4000, 0xcf1: 0x4000, 0xcf2: 0x4000, 0xcf3: 0x4000, 0xcf4: 0x4000, 0xcf5: 0x4000,
+	0xcf6: 0x4000, 0xcf7: 0x4000, 0xcf8: 0x4000, 0xcf9: 0x4000, 0xcfa: 0x4000, 0xcfb: 0x4000,
+	0xcfc: 0x4000, 0xcfd: 0x4000, 0xcfe: 0x4000, 0xcff: 0x4000,
+	// Block 0x34, offset 0xd00
+	0xd00: 0x4000, 0xd01: 0x4000, 0xd02: 0x4000, 0xd03: 0x4000, 0xd04: 0x4000, 0xd05: 0x4000,
+	0xd06: 0x4000, 0xd07: 0x4000, 0xd08: 0x4000, 0xd09: 0x4000, 0xd0a: 0x4000, 0xd0b: 0x4000,
+	0xd0c: 0x4000, 0xd0d: 0x4000, 0xd0e: 0x4000, 0xd0f: 0x4000, 0xd10: 0x4000, 0xd11: 0x4000,
+	0xd12: 0x4000, 0xd13: 0x4000, 0xd14: 0x4000, 0xd15: 0x4000, 0xd16: 0x4000,
+	0xd19: 0x4016, 0xd1a: 0x4017, 0xd1b: 0x4000, 0xd1c: 0x4000, 0xd1d: 0x4000,
+	0xd1e: 0x4000, 0xd1f: 0x4000, 0xd20: 0x4000, 0xd21: 0x4018, 0xd22: 0x4019, 0xd23: 0x401a,
+	0xd24: 0x401b, 0xd25: 0x401c, 0xd26: 0x401d, 0xd27: 0x401e, 0xd28: 0x401f, 0xd29: 0x4020,
+	0xd2a: 0x4021, 0xd2b: 0x4022, 0xd2c: 0x4000, 0xd2d: 0x4010, 0xd2e: 0x4000, 0xd2f: 0x4023,
+	0xd30: 0x4000, 0xd31: 0x4024, 0xd32: 0x4000, 0xd33: 0x4025, 0xd34: 0x4000, 0xd35: 0x4026,
+	0xd36: 0x4000, 0xd37: 0x401a, 0xd38: 0x4000, 0xd39: 0x4027, 0xd3a: 0x4000, 0xd3b: 0x4028,
+	0xd3c: 0x4000, 0xd3d: 0x4020, 0xd3e: 0x4000, 0xd3f: 0x4029,
+	// Block 0x35, offset 0xd40
+	0xd40: 0x4000, 0xd41: 0x402a, 0xd42: 0x4000, 0xd43: 0x402b, 0xd44: 0x402c, 0xd45: 0x4000,
+	0xd46: 0x4017, 0xd47: 0x4000, 0xd48: 0x402d, 0xd49: 0x4000, 0xd4a: 0x402e, 0xd4b: 0x402f,
+	0xd4c: 0x4030, 0xd4d: 0x4017, 0xd4e: 0x4016, 0xd4f: 0x4017, 0xd50: 0x4000, 0xd51: 0x4000,
+	0xd52: 0x4031, 0xd53: 0x4000, 0xd54: 0x4000, 0xd55: 0x4031, 0xd56: 0x4000, 0xd57: 0x4000,
+	0xd58: 0x4032, 0xd59: 0x4000, 0xd5a: 0x4000, 0xd5b: 0x4032, 0xd5c: 0x4000, 0xd5d: 0x4000,
+	0xd5e: 0x4033, 0xd5f: 0x402e, 0xd60: 0x4034, 0xd61: 0x4035, 0xd62: 0x4034, 0xd63: 0x4036,
+	0xd64: 0x4037, 0xd65: 0x4024, 0xd66: 0x4035, 0xd67: 0x4025, 0xd68: 0x4038, 0xd69: 0x4038,
+	0xd6a: 0x4039, 0xd6b: 0x4039, 0xd6c: 0x403a, 0xd6d: 0x403a, 0xd6e: 0x4000, 0xd6f: 0x4035,
+	0xd70: 0x4000, 0xd71: 0x4000, 0xd72: 0x403b, 0xd73: 0x403c, 0xd74: 0x4000, 0xd75: 0x4000,
+	0xd76: 0x4000, 0xd77: 0x4000, 0xd78: 0x4000, 0xd79: 0x4000, 0xd7a: 0x4000, 0xd7b: 0x403d,
+	0xd7c: 0x401c, 0xd7d: 0x4000, 0xd7e: 0x4000, 0xd7f: 0x4000,
+	// Block 0x36, offset 0xd80
+	0xd85: 0x4000,
+	0xd86: 0x4000, 0xd87: 0x4000, 0xd88: 0x4000, 0xd89: 0x4000, 0xd8a: 0x4000, 0xd8b: 0x4000,
+	0xd8c: 0x4000, 0xd8d: 0x4000, 0xd8e: 0x4000, 0xd8f: 0x4000, 0xd90: 0x4000, 0xd91: 0x4000,
+	0xd92: 0x4000, 0xd93: 0x4000, 0xd94: 0x4000, 0xd95: 0x4000, 0xd96: 0x4000, 0xd97: 0x4000,
+	0xd98: 0x4000, 0xd99: 0x4000, 0xd9a: 0x4000, 0xd9b: 0x4000, 0xd9c: 0x4000, 0xd9d: 0x4000,
+	0xd9e: 0x4000, 0xd9f: 0x4000, 0xda0: 0x4000, 0xda1: 0x4000, 0xda2: 0x4000, 0xda3: 0x4000,
+	0xda4: 0x4000, 0xda5: 0x4000, 0xda6: 0x4000, 0xda7: 0x4000, 0xda8: 0x4000, 0xda9: 0x4000,
+	0xdaa: 0x4000, 0xdab: 0x4000, 0xdac: 0x4000, 0xdad: 0x4000, 0xdae: 0x4000, 0xdaf: 0x4000,
+	0xdb1: 0x403e, 0xdb2: 0x403e, 0xdb3: 0x403e, 0xdb4: 0x403e, 0xdb5: 0x403e,
+	0xdb6: 0x403e, 0xdb7: 0x403e, 0xdb8: 0x403e, 0xdb9: 0x403e, 0xdba: 0x403e, 0xdbb: 0x403e,
+	0xdbc: 0x403e, 0xdbd: 0x403e, 0xdbe: 0x403e, 0xdbf: 0x403e,
+	// Block 0x37, offset 0xdc0
+	0xdc0: 0x4037, 0xdc1: 0x4037, 0xdc2: 0x4037, 0xdc3: 0x4037, 0xdc4: 0x4037, 0xdc5: 0x4037,
+	0xdc6: 0x4037, 0xdc7: 0x4037, 0xdc8: 0x4037, 0xdc9: 0x4037, 0xdca: 0x4037, 0xdcb: 0x4037,
+	0xdcc: 0x4037, 0xdcd: 0x4037, 0xdce: 0x4037, 0xdcf: 0x400e, 0xdd0: 0x403f, 0xdd1: 0x4040,
+	0xdd2: 0x4041, 0xdd3: 0x4040, 0xdd4: 0x403f, 0xdd5: 0x4042, 0xdd6: 0x4043, 0xdd7: 0x4044,
+	0xdd8: 0x4040, 0xdd9: 0x4041, 0xdda: 0x4040, 0xddb: 0x4045, 0xddc: 0x4009, 0xddd: 0x4045,
+	0xdde: 0x4046, 0xddf: 0x4045, 0xde0: 0x4047, 0xde1: 0x400b, 0xde2: 0x400a, 0xde3: 0x400c,
+	0xde4: 0x4048, 0xde5: 0x4000, 0xde6: 0x4000, 0xde7: 0x4000, 0xde8: 0x4000, 0xde9: 0x4000,
+	0xdea: 0x4000, 0xdeb: 0x4000, 0xdec: 0x4000, 0xded: 0x4000, 0xdee: 0x4000, 0xdef: 0x4000,
+	0xdf0: 0x4000, 0xdf1: 0x4000, 0xdf2: 0x4000, 0xdf3: 0x4000, 0xdf4: 0x4000, 0xdf5: 0x4000,
+	0xdf6: 0x4000, 0xdf7: 0x4000, 0xdf8: 0x4000, 0xdf9: 0x4000, 0xdfa: 0x4000, 0xdfb: 0x4000,
+	0xdfc: 0x4000, 0xdfd: 0x4000, 0xdfe: 0x4000, 0xdff: 0x4000,
+	// Block 0x38, offset 0xe00
+	0xe00: 0x4000, 0xe01: 0x4000, 0xe02: 0x4000, 0xe03: 0x4000, 0xe04: 0x4000, 0xe05: 0x4000,
+	0xe06: 0x4000, 0xe07: 0x4000, 0xe08: 0x4000, 0xe09: 0x4000, 0xe0a: 0x4000, 0xe0b: 0x4000,
+	0xe0c: 0x4000, 0xe0d: 0x4000, 0xe0e: 0x4000, 0xe10: 0x4000, 0xe11: 0x4000,
+	0xe12: 0x4000, 0xe13: 0x4000, 0xe14: 0x4000, 0xe15: 0x4000, 0xe16: 0x4000, 0xe17: 0x4000,
+	0xe18: 0x4000, 0xe19: 0x4000, 0xe1a: 0x4000, 0xe1b: 0x4000, 0xe1c: 0x4000, 0xe1d: 0x4000,
+	0xe1e: 0x4000, 0xe1f: 0x4000, 0xe20: 0x4000, 0xe21: 0x4000, 0xe22: 0x4000, 0xe23: 0x4000,
+	0xe24: 0x4000, 0xe25: 0x4000, 0xe26: 0x4000, 0xe27: 0x4000, 0xe28: 0x4000, 0xe29: 0x4000,
+	0xe2a: 0x4000, 0xe2b: 0x4000, 0xe2c: 0x4000, 0xe2d: 0x4000, 0xe2e: 0x4000, 0xe2f: 0x4000,
+	0xe30: 0x4000, 0xe31: 0x4000, 0xe32: 0x4000, 0xe33: 0x4000, 0xe34: 0x4000, 0xe35: 0x4000,
+	0xe36: 0x4000, 0xe37: 0x4000, 0xe38: 0x4000, 0xe39: 0x4000, 0xe3a: 0x4000, 0xe3b: 0x4000,
+	0xe3c: 0x4000, 0xe3d: 0x4000, 0xe3e: 0x4000, 0xe3f: 0x4000,
+	// Block 0x39, offset 0xe40
+	0xe40: 0x4000, 0xe41: 0x4000, 0xe42: 0x4000, 0xe43: 0x4000, 0xe44: 0x4000, 0xe45: 0x4000,
+	0xe46: 0x4000, 0xe47: 0x4000, 0xe48: 0x4000, 0xe49: 0x4000, 0xe4a: 0x4000, 0xe4b: 0x4000,
+	0xe4c: 0x4000, 0xe4d: 0x4000, 0xe4e: 0x4000, 0xe4f: 0x4000, 0xe50: 0x4000, 0xe51: 0x4000,
+	0xe52: 0x4000, 0xe53: 0x4000, 0xe54: 0x4000, 0xe55: 0x4000, 0xe56: 0x4000, 0xe57: 0x4000,
+	0xe58: 0x4000, 0xe59: 0x4000, 0xe5a: 0x4000, 0xe5b: 0x4000, 0xe5c: 0x4000, 0xe5d: 0x4000,
+	0xe5e: 0x4000, 0xe5f: 0x4000, 0xe60: 0x4000, 0xe61: 0x4000, 0xe62: 0x4000, 0xe63: 0x4000,
+	0xe64: 0x4000, 0xe65: 0x4000,
+	0xe6f: 0x4000,
+	0xe70: 0x4000, 0xe71: 0x4000, 0xe72: 0x4000, 0xe73: 0x4000, 0xe74: 0x4000, 0xe75: 0x4000,
+	0xe76: 0x4000, 0xe77: 0x4000, 0xe78: 0x4000, 0xe79: 0x4000, 0xe7a: 0x4000, 0xe7b: 0x4000,
+	0xe7c: 0x4000, 0xe7d: 0x4000, 0xe7e: 0x4000, 0xe7f: 0x4000,
+	// Block 0x3a, offset 0xe80
+	0xe80: 0x4000, 0xe81: 0x4000, 0xe82: 0x4000, 0xe83: 0x4000, 0xe84: 0x4000, 0xe85: 0x4000,
+	0xe86: 0x4000, 0xe87: 0x4000, 0xe88: 0x4000, 0xe89: 0x4000, 0xe8a: 0x4000, 0xe8b: 0x4000,
+	0xe8c: 0x4000, 0xe8d: 0x4000, 0xe8e: 0x4000, 0xe8f: 0x4000, 0xe90: 0x4000, 0xe91: 0x4000,
+	0xe92: 0x4000, 0xe93: 0x4000, 0xe94: 0x4000, 0xe95: 0x4000, 0xe96: 0x4000, 0xe97: 0x4000,
+	0xe98: 0x4000, 0xe99: 0x4000, 0xe9a: 0x4000, 0xe9b: 0x4000, 0xe9c: 0x4000, 0xe9d: 0x4000,
+	0xe9e: 0x4000, 0xea0: 0x4000, 0xea1: 0x4000, 0xea2: 0x4000, 0xea3: 0x4000,
+	0xea4: 0x4000, 0xea5: 0x4000, 0xea6: 0x4000, 0xea7: 0x4000, 0xea8: 0x4000, 0xea9: 0x4000,
+	0xeaa: 0x4000, 0xeab: 0x4000, 0xeac: 0x4000, 0xead: 0x4000, 0xeae: 0x4000, 0xeaf: 0x4000,
+	0xeb0: 0x4000, 0xeb1: 0x4000, 0xeb2: 0x4000, 0xeb3: 0x4000, 0xeb4: 0x4000, 0xeb5: 0x4000,
+	0xeb6: 0x4000, 0xeb7: 0x4000, 0xeb8: 0x4000, 0xeb9: 0x4000, 0xeba: 0x4000, 0xebb: 0x4000,
+	0xebc: 0x4000, 0xebd: 0x4000, 0xebe: 0x4000, 0xebf: 0x4000,
+	// Block 0x3b, offset 0xec0
+	0xec0: 0x4000, 0xec1: 0x4000, 0xec2: 0x4000, 0xec3: 0x4000, 0xec4: 0x4000, 0xec5: 0x4000,
+	0xec6: 0x4000, 0xec7: 0x4000, 0xec8: 0x2000, 0xec9: 0x2000, 0xeca: 0x2000, 0xecb: 0x2000,
+	0xecc: 0x2000, 0xecd: 0x2000, 0xece: 0x2000, 0xecf: 0x2000, 0xed0: 0x4000, 0xed1: 0x4000,
+	0xed2: 0x4000, 0xed3: 0x4000, 0xed4: 0x4000, 0xed5: 0x4000, 0xed6: 0x4000, 0xed7: 0x4000,
+	0xed8: 0x4000, 0xed9: 0x4000, 0xeda: 0x4000, 0xedb: 0x4000, 0xedc: 0x4000, 0xedd: 0x4000,
+	0xede: 0x4000, 0xedf: 0x4000, 0xee0: 0x4000, 0xee1: 0x4000, 0xee2: 0x4000, 0xee3: 0x4000,
+	0xee4: 0x4000, 0xee5: 0x4000, 0xee6: 0x4000, 0xee7: 0x4000, 0xee8: 0x4000, 0xee9: 0x4000,
+	0xeea: 0x4000, 0xeeb: 0x4000, 0xeec: 0x4000, 0xeed: 0x4000, 0xeee: 0x4000, 0xeef: 0x4000,
+	0xef0: 0x4000, 0xef1: 0x4000, 0xef2: 0x4000, 0xef3: 0x4000, 0xef4: 0x4000, 0xef5: 0x4000,
+	0xef6: 0x4000, 0xef7: 0x4000, 0xef8: 0x4000, 0xef9: 0x4000, 0xefa: 0x4000, 0xefb: 0x4000,
+	0xefc: 0x4000, 0xefd: 0x4000, 0xefe: 0x4000, 0xeff: 0x4000,
+	// Block 0x3c, offset 0xf00
+	0xf00: 0x4000, 0xf01: 0x4000, 0xf02: 0x4000, 0xf03: 0x4000, 0xf04: 0x4000, 0xf05: 0x4000,
+	0xf06: 0x4000, 0xf07: 0x4000, 0xf08: 0x4000, 0xf09: 0x4000, 0xf0a: 0x4000, 0xf0b: 0x4000,
+	0xf0c: 0x4000, 0xf10: 0x4000, 0xf11: 0x4000,
+	0xf12: 0x4000, 0xf13: 0x4000, 0xf14: 0x4000, 0xf15: 0x4000, 0xf16: 0x4000, 0xf17: 0x4000,
+	0xf18: 0x4000, 0xf19: 0x4000, 0xf1a: 0x4000, 0xf1b: 0x4000, 0xf1c: 0x4000, 0xf1d: 0x4000,
+	0xf1e: 0x4000, 0xf1f: 0x4000, 0xf20: 0x4000, 0xf21: 0x4000, 0xf22: 0x4000, 0xf23: 0x4000,
+	0xf24: 0x4000, 0xf25: 0x4000, 0xf26: 0x4000, 0xf27: 0x4000, 0xf28: 0x4000, 0xf29: 0x4000,
+	0xf2a: 0x4000, 0xf2b: 0x4000, 0xf2c: 0x4000, 0xf2d: 0x4000, 0xf2e: 0x4000, 0xf2f: 0x4000,
+	0xf30: 0x4000, 0xf31: 0x4000, 0xf32: 0x4000, 0xf33: 0x4000, 0xf34: 0x4000, 0xf35: 0x4000,
+	0xf36: 0x4000, 0xf37: 0x4000, 0xf38: 0x4000, 0xf39: 0x4000, 0xf3a: 0x4000, 0xf3b: 0x4000,
+	0xf3c: 0x4000, 0xf3d: 0x4000, 0xf3e: 0x4000, 0xf3f: 0x4000,
+	// Block 0x3d, offset 0xf40
+	0xf40: 0x4000, 0xf41: 0x4000, 0xf42: 0x4000, 0xf43: 0x4000, 0xf44: 0x4000, 0xf45: 0x4000,
+	0xf46: 0x4000,
+	// Block 0x3e, offset 0xf80
+	0xfa0: 0x4000, 0xfa1: 0x4000, 0xfa2: 0x4000, 0xfa3: 0x4000,
+	0xfa4: 0x4000, 0xfa5: 0x4000, 0xfa6: 0x4000, 0xfa7: 0x4000, 0xfa8: 0x4000, 0xfa9: 0x4000,
+	0xfaa: 0x4000, 0xfab: 0x4000, 0xfac: 0x4000, 0xfad: 0x4000, 0xfae: 0x4000, 0xfaf: 0x4000,
+	0xfb0: 0x4000, 0xfb1: 0x4000, 0xfb2: 0x4000, 0xfb3: 0x4000, 0xfb4: 0x4000, 0xfb5: 0x4000,
+	0xfb6: 0x4000, 0xfb7: 0x4000, 0xfb8: 0x4000, 0xfb9: 0x4000, 0xfba: 0x4000, 0xfbb: 0x4000,
+	0xfbc: 0x4000,
+	// Block 0x3f, offset 0xfc0
+	0xfc0: 0x4000, 0xfc1: 0x4000, 0xfc2: 0x4000, 0xfc3: 0x4000, 0xfc4: 0x4000, 0xfc5: 0x4000,
+	0xfc6: 0x4000, 0xfc7: 0x4000, 0xfc8: 0x4000, 0xfc9: 0x4000, 0xfca: 0x4000, 0xfcb: 0x4000,
+	0xfcc: 0x4000, 0xfcd: 0x4000, 0xfce: 0x4000, 0xfcf: 0x4000, 0xfd0: 0x4000, 0xfd1: 0x4000,
+	0xfd2: 0x4000, 0xfd3: 0x4000, 0xfd4: 0x4000, 0xfd5: 0x4000, 0xfd6: 0x4000, 0xfd7: 0x4000,
+	0xfd8: 0x4000, 0xfd9: 0x4000, 0xfda: 0x4000, 0xfdb: 0x4000, 0xfdc: 0x4000, 0xfdd: 0x4000,
+	0xfde: 0x4000, 0xfdf: 0x4000, 0xfe0: 0x4000, 0xfe1: 0x4000, 0xfe2: 0x4000, 0xfe3: 0x4000,
+	// Block 0x40, offset 0x1000
+	0x1000: 0x2000, 0x1001: 0x2000, 0x1002: 0x2000, 0x1003: 0x2000, 0x1004: 0x2000, 0x1005: 0x2000,
+	0x1006: 0x2000, 0x1007: 0x2000, 0x1008: 0x2000, 0x1009: 0x2000, 0x100a: 0x2000, 0x100b: 0x2000,
+	0x100c: 0x2000, 0x100d: 0x2000, 0x100e: 0x2000, 0x100f: 0x2000, 0x1010: 0x4000, 0x1011: 0x4000,
+	0x1012: 0x4000, 0x1013: 0x4000, 0x1014: 0x4000, 0x1015: 0x4000, 0x1016: 0x4000, 0x1017: 0x4000,
+	0x1018: 0x4000, 0x1019: 0x4000,
+	0x1030: 0x4000, 0x1031: 0x4000, 0x1032: 0x4000, 0x1033: 0x4000, 0x1034: 0x4000, 0x1035: 0x4000,
+	0x1036: 0x4000, 0x1037: 0x4000, 0x1038: 0x4000, 0x1039: 0x4000, 0x103a: 0x4000, 0x103b: 0x4000,
+	0x103c: 0x4000, 0x103d: 0x4000, 0x103e: 0x4000, 0x103f: 0x4000,
+	// Block 0x41, offset 0x1040
+	0x1040: 0x4000, 0x1041: 0x4000, 0x1042: 0x4000, 0x1043: 0x4000, 0x1044: 0x4000, 0x1045: 0x4000,
+	0x1046: 0x4000, 0x1047: 0x4000, 0x1048: 0x4000, 0x1049: 0x4000, 0x104a: 0x4000, 0x104b: 0x4000,
+	0x104c: 0x4000, 0x104d: 0x4000, 0x104e: 0x4000, 0x104f: 0x4000, 0x1050: 0x4000, 0x1051: 0x4000,
+	0x1052: 0x4000, 0x1054: 0x4000, 0x1055: 0x4000, 0x1056: 0x4000, 0x1057: 0x4000,
+	0x1058: 0x4000, 0x1059: 0x4000, 0x105a: 0x4000, 0x105b: 0x4000, 0x105c: 0x4000, 0x105d: 0x4000,
+	0x105e: 0x4000, 0x105f: 0x4000, 0x1060: 0x4000, 0x1061: 0x4000, 0x1062: 0x4000, 0x1063: 0x4000,
+	0x1064: 0x4000, 0x1065: 0x4000, 0x1066: 0x4000, 0x1068: 0x4000, 0x1069: 0x4000,
+	0x106a: 0x4000, 0x106b: 0x4000,
+	// Block 0x42, offset 0x1080
+	0x1081: 0x9012, 0x1082: 0x9012, 0x1083: 0x9012, 0x1084: 0x9012, 0x1085: 0x9012,
+	0x1086: 0x9012, 0x1087: 0x9012, 0x1088: 0x9012, 0x1089: 0x9012, 0x108a: 0x9012, 0x108b: 0x9012,
+	0x108c: 0x9012, 0x108d: 0x9012, 0x108e: 0x9012, 0x108f: 0x9012, 0x1090: 0x9012, 0x1091: 0x9012,
+	0x1092: 0x9012, 0x1093: 0x9012, 0x1094: 0x9012, 0x1095: 0x9012, 0x1096: 0x9012, 0x1097: 0x9012,
+	0x1098: 0x9012, 0x1099: 0x9012, 0x109a: 0x9012, 0x109b: 0x9012, 0x109c: 0x9012, 0x109d: 0x9012,
+	0x109e: 0x9012, 0x109f: 0x9012, 0x10a0: 0x9049, 0x10a1: 0x9049, 0x10a2: 0x9049, 0x10a3: 0x9049,
+	0x10a4: 0x9049, 0x10a5: 0x9049, 0x10a6: 0x9049, 0x10a7: 0x9049, 0x10a8: 0x9049, 0x10a9: 0x9049,
+	0x10aa: 0x9049, 0x10ab: 0x9049, 0x10ac: 0x9049, 0x10ad: 0x9049, 0x10ae: 0x9049, 0x10af: 0x9049,
+	0x10b0: 0x9049, 0x10b1: 0x9049, 0x10b2: 0x9049, 0x10b3: 0x9049, 0x10b4: 0x9049, 0x10b5: 0x9049,
+	0x10b6: 0x9049, 0x10b7: 0x9049, 0x10b8: 0x9049, 0x10b9: 0x9049, 0x10ba: 0x9049, 0x10bb: 0x9049,
+	0x10bc: 0x9049, 0x10bd: 0x9049, 0x10be: 0x9049, 0x10bf: 0x9049,
+	// Block 0x43, offset 0x10c0
+	0x10c0: 0x9049, 0x10c1: 0x9049, 0x10c2: 0x9049, 0x10c3: 0x9049, 0x10c4: 0x9049, 0x10c5: 0x9049,
+	0x10c6: 0x9049, 0x10c7: 0x9049, 0x10c8: 0x9049, 0x10c9: 0x9049, 0x10ca: 0x9049, 0x10cb: 0x9049,
+	0x10cc: 0x9049, 0x10cd: 0x9049, 0x10ce: 0x9049, 0x10cf: 0x9049, 0x10d0: 0x9049, 0x10d1: 0x9049,
+	0x10d2: 0x9049, 0x10d3: 0x9049, 0x10d4: 0x9049, 0x10d5: 0x9049, 0x10d6: 0x9049, 0x10d7: 0x9049,
+	0x10d8: 0x9049, 0x10d9: 0x9049, 0x10da: 0x9049, 0x10db: 0x9049, 0x10dc: 0x9049, 0x10dd: 0x9049,
+	0x10de: 0x9049, 0x10df: 0x904a, 0x10e0: 0x904b, 0x10e1: 0xb04c, 0x10e2: 0xb04d, 0x10e3: 0xb04d,
+	0x10e4: 0xb04e, 0x10e5: 0xb04f, 0x10e6: 0xb050, 0x10e7: 0xb051, 0x10e8: 0xb052, 0x10e9: 0xb053,
+	0x10ea: 0xb054, 0x10eb: 0xb055, 0x10ec: 0xb056, 0x10ed: 0xb057, 0x10ee: 0xb058, 0x10ef: 0xb059,
+	0x10f0: 0xb05a, 0x10f1: 0xb05b, 0x10f2: 0xb05c, 0x10f3: 0xb05d, 0x10f4: 0xb05e, 0x10f5: 0xb05f,
+	0x10f6: 0xb060, 0x10f7: 0xb061, 0x10f8: 0xb062, 0x10f9: 0xb063, 0x10fa: 0xb064, 0x10fb: 0xb065,
+	0x10fc: 0xb052, 0x10fd: 0xb066, 0x10fe: 0xb067, 0x10ff: 0xb055,
+	// Block 0x44, offset 0x1100
+	0x1100: 0xb068, 0x1101: 0xb069, 0x1102: 0xb06a, 0x1103: 0xb06b, 0x1104: 0xb05a, 0x1105: 0xb056,
+	0x1106: 0xb06c, 0x1107: 0xb06d, 0x1108: 0xb06b, 0x1109: 0xb06e, 0x110a: 0xb06b, 0x110b: 0xb06f,
+	0x110c: 0xb06f, 0x110d: 0xb070, 0x110e: 0xb070, 0x110f: 0xb071, 0x1110: 0xb056, 0x1111: 0xb072,
+	0x1112: 0xb073, 0x1113: 0xb072, 0x1114: 0xb074, 0x1115: 0xb073, 0x1116: 0xb075, 0x1117: 0xb075,
+	0x1118: 0xb076, 0x1119: 0xb076, 0x111a: 0xb077, 0x111b: 0xb077, 0x111c: 0xb073, 0x111d: 0xb078,
+	0x111e: 0xb079, 0x111f: 0xb067, 0x1120: 0xb07a, 0x1121: 0xb07b, 0x1122: 0xb07b, 0x1123: 0xb07b,
+	0x1124: 0xb07b, 0x1125: 0xb07b, 0x1126: 0xb07b, 0x1127: 0xb07b, 0x1128: 0xb07b, 0x1129: 0xb07b,
+	0x112a: 0xb07b, 0x112b: 0xb07b, 0x112c: 0xb07b, 0x112d: 0xb07b, 0x112e: 0xb07b, 0x112f: 0xb07b,
+	0x1130: 0xb07c, 0x1131: 0xb07c, 0x1132: 0xb07c, 0x1133: 0xb07c, 0x1134: 0xb07c, 0x1135: 0xb07c,
+	0x1136: 0xb07c, 0x1137: 0xb07c, 0x1138: 0xb07c, 0x1139: 0xb07c, 0x113a: 0xb07c, 0x113b: 0xb07c,
+	0x113c: 0xb07c, 0x113d: 0xb07c, 0x113e: 0xb07c,
+	// Block 0x45, offset 0x1140
+	0x1142: 0xb07d, 0x1143: 0xb07e, 0x1144: 0xb07f, 0x1145: 0xb080,
+	0x1146: 0xb07f, 0x1147: 0xb07e, 0x114a: 0xb081, 0x114b: 0xb082,
+	0x114c: 0xb083, 0x114d: 0xb07f, 0x114e: 0xb080, 0x114f: 0xb07f,
+	0x1152: 0xb084, 0x1153: 0xb085, 0x1154: 0xb084, 0x1155: 0xb086, 0x1156: 0xb084, 0x1157: 0xb087,
+	0x115a: 0xb088, 0x115b: 0xb089, 0x115c: 0xb08a,
+	0x1160: 0x908b, 0x1161: 0x908b, 0x1162: 0x908c, 0x1163: 0x908d,
+	0x1164: 0x908b, 0x1165: 0x908e, 0x1166: 0x908f, 0x1168: 0xb090, 0x1169: 0xb091,
+	0x116a: 0xb092, 0x116b: 0xb091, 0x116c: 0xb093, 0x116d: 0xb094, 0x116e: 0xb095,
+	0x117d: 0x2000,
+	// Block 0x46, offset 0x1180
+	0x11a0: 0x4000, 0x11a1: 0x4000, 0x11a2: 0x4000, 0x11a3: 0x4000,
+	0x11a4: 0x4000,
+	0x11b0: 0x4000, 0x11b1: 0x4000, 0x11b2: 0x4000, 0x11b3: 0x4000, 0x11b4: 0x4000, 0x11b5: 0x4000,
+	0x11b6: 0x4000,
+	// Block 0x47, offset 0x11c0
+	0x11c0: 0x4000, 0x11c1: 0x4000, 0x11c2: 0x4000, 0x11c3: 0x4000, 0x11c4: 0x4000, 0x11c5: 0x4000,
+	0x11c6: 0x4000, 0x11c7: 0x4000, 0x11c8: 0x4000, 0x11c9: 0x4000, 0x11ca: 0x4000, 0x11cb: 0x4000,
+	0x11cc: 0x4000, 0x11cd: 0x4000, 0x11ce: 0x4000, 0x11cf: 0x4000, 0x11d0: 0x4000, 0x11d1: 0x4000,
+	0x11d2: 0x4000, 0x11d3: 0x4000, 0x11d4: 0x4000, 0x11d5: 0x4000,
+	0x11ff: 0x4000,
+	// Block 0x48, offset 0x1200
+	0x1200: 0x4000, 0x1201: 0x4000, 0x1202: 0x4000, 0x1203: 0x4000, 0x1204: 0x4000, 0x1205: 0x4000,
+	0x1206: 0x4000, 0x1207: 0x4000, 0x1208: 0x4000, 0x1209: 0x4000, 0x120a: 0x4000, 0x120b: 0x4000,
+	0x120c: 0x4000, 0x120d: 0x4000, 0x120e: 0x4000, 0x120f: 0x4000, 0x1210: 0x4000, 0x1211: 0x4000,
+	0x1212: 0x4000, 0x1213: 0x4000, 0x1214: 0x4000, 0x1215: 0x4000, 0x1216: 0x4000, 0x1217: 0x4000,
+	0x1218: 0x4000, 0x1219: 0x4000, 0x121a: 0x4000, 0x121b: 0x4000, 0x121c: 0x4000, 0x121d: 0x4000,
+	0x121e: 0x4000,
+	// Block 0x49, offset 0x1240
+	0x1240: 0x4000, 0x1241: 0x4000, 0x1242: 0x4000, 0x1243: 0x4000, 0x1244: 0x4000, 0x1245: 0x4000,
+	0x1246: 0x4000, 0x1247: 0x4000, 0x1248: 0x4000, 0x1249: 0x4000, 0x124a: 0x4000, 0x124b: 0x4000,
+	0x124c: 0x4000, 0x124d: 0x4000, 0x124e: 0x4000, 0x124f: 0x4000, 0x1250: 0x4000, 0x1251: 0x4000,
+	0x1252: 0x4000, 0x1253: 0x4000, 0x1254: 0x4000, 0x1255: 0x4000, 0x1256: 0x4000, 0x1257: 0x4000,
+	0x1258: 0x4000, 0x1259: 0x4000, 0x125a: 0x4000, 0x125b: 0x4000, 0x125c: 0x4000, 0x125d: 0x4000,
+	0x125e: 0x4000, 0x125f: 0x4000, 0x1260: 0x4000, 0x1261: 0x4000, 0x1262: 0x4000, 0x1263: 0x4000,
+	0x1264: 0x4000, 0x1265: 0x4000, 0x1266: 0x4000, 0x1267: 0x4000, 0x1268: 0x4000, 0x1269: 0x4000,
+	0x126a: 0x4000, 0x126b: 0x4000, 0x126c: 0x4000, 0x126d: 0x4000, 0x126e: 0x4000, 0x126f: 0x4000,
+	0x1270: 0x4000, 0x1271: 0x4000, 0x1272: 0x4000,
+	// Block 0x4a, offset 0x1280
+	0x12b0: 0x4000, 0x12b1: 0x4000, 0x12b2: 0x4000, 0x12b3: 0x4000, 0x12b5: 0x4000,
+	0x12b6: 0x4000, 0x12b7: 0x4000, 0x12b8: 0x4000, 0x12b9: 0x4000, 0x12ba: 0x4000, 0x12bb: 0x4000,
+	0x12bd: 0x4000, 0x12be: 0x4000,
+	// Block 0x4b, offset 0x12c0
+	0x12c0: 0x4000, 0x12c1: 0x4000, 0x12c2: 0x4000, 0x12c3: 0x4000, 0x12c4: 0x4000, 0x12c5: 0x4000,
+	0x12c6: 0x4000, 0x12c7: 0x4000, 0x12c8: 0x4000, 0x12c9: 0x4000, 0x12ca: 0x4000, 0x12cb: 0x4000,
+	0x12cc: 0x4000, 0x12cd: 0x4000, 0x12ce: 0x4000, 0x12cf: 0x4000, 0x12d0: 0x4000, 0x12d1: 0x4000,
+	0x12d2: 0x4000, 0x12d3: 0x4000, 0x12d4: 0x4000, 0x12d5: 0x4000, 0x12d6: 0x4000, 0x12d7: 0x4000,
+	0x12d8: 0x4000, 0x12d9: 0x4000, 0x12da: 0x4000, 0x12db: 0x4000, 0x12dc: 0x4000, 0x12dd: 0x4000,
+	0x12de: 0x4000, 0x12df: 0x4000, 0x12e0: 0x4000, 0x12e1: 0x4000, 0x12e2: 0x4000,
+	0x12f2: 0x4000,
+	// Block 0x4c, offset 0x1300
+	0x1310: 0x4000, 0x1311: 0x4000,
+	0x1312: 0x4000, 0x1315: 0x4000,
+	0x1324: 0x4000, 0x1325: 0x4000, 0x1326: 0x4000, 0x1327: 0x4000,
+	0x1330: 0x4000, 0x1331: 0x4000, 0x1332: 0x4000, 0x1333: 0x4000, 0x1334: 0x4000, 0x1335: 0x4000,
+	0x1336: 0x4000, 0x1337: 0x4000, 0x1338: 0x4000, 0x1339: 0x4000, 0x133a: 0x4000, 0x133b: 0x4000,
+	0x133c: 0x4000, 0x133d: 0x4000, 0x133e: 0x4000, 0x133f: 0x4000,
+	// Block 0x4d, offset 0x1340
+	0x1340: 0x4000, 0x1341: 0x4000, 0x1342: 0x4000, 0x1343: 0x4000, 0x1344: 0x4000, 0x1345: 0x4000,
+	0x1346: 0x4000, 0x1347: 0x4000, 0x1348: 0x4000, 0x1349: 0x4000, 0x134a: 0x4000, 0x134b: 0x4000,
+	0x134c: 0x4000, 0x134d: 0x4000, 0x134e: 0x4000, 0x134f: 0x4000, 0x1350: 0x4000, 0x1351: 0x4000,
+	0x1352: 0x4000, 0x1353: 0x4000, 0x1354: 0x4000, 0x1355: 0x4000, 0x1356: 0x4000, 0x1357: 0x4000,
+	0x1358: 0x4000, 0x1359: 0x4000, 0x135a: 0x4000, 0x135b: 0x4000, 0x135c: 0x4000, 0x135d: 0x4000,
+	0x135e: 0x4000, 0x135f: 0x4000, 0x1360: 0x4000, 0x1361: 0x4000, 0x1362: 0x4000, 0x1363: 0x4000,
+	0x1364: 0x4000, 0x1365: 0x4000, 0x1366: 0x4000, 0x1367: 0x4000, 0x1368: 0x4000, 0x1369: 0x4000,
+	0x136a: 0x4000, 0x136b: 0x4000, 0x136c: 0x4000, 0x136d: 0x4000, 0x136e: 0x4000, 0x136f: 0x4000,
+	0x1370: 0x4000, 0x1371: 0x4000, 0x1372: 0x4000, 0x1373: 0x4000, 0x1374: 0x4000, 0x1375: 0x4000,
+	0x1376: 0x4000, 0x1377: 0x4000, 0x1378: 0x4000, 0x1379: 0x4000, 0x137a: 0x4000, 0x137b: 0x4000,
+	// Block 0x4e, offset 0x1380
+	0x1380: 0x4000, 0x1381: 0x4000, 0x1382: 0x4000, 0x1383: 0x4000, 0x1384: 0x4000, 0x1385: 0x4000,
+	0x1386: 0x4000, 0x1387: 0x4000, 0x1388: 0x4000, 0x1389: 0x4000, 0x138a: 0x4000, 0x138b: 0x4000,
+	0x138c: 0x4000, 0x138d: 0x4000, 0x138e: 0x4000, 0x138f: 0x4000, 0x1390: 0x4000, 0x1391: 0x4000,
+	0x1392: 0x4000, 0x1393: 0x4000, 0x1394: 0x4000, 0x1395: 0x4000, 0x1396: 0x4000,
+	0x13a0: 0x4000, 0x13a1: 0x4000, 0x13a2: 0x4000, 0x13a3: 0x4000,
+	0x13a4: 0x4000, 0x13a5: 0x4000, 0x13a6: 0x4000, 0x13a7: 0x4000, 0x13a8: 0x4000, 0x13a9: 0x4000,
+	0x13aa: 0x4000, 0x13ab: 0x4000, 0x13ac: 0x4000, 0x13ad: 0x4000, 0x13ae: 0x4000, 0x13af: 0x4000,
+	0x13b0: 0x4000, 0x13b1: 0x4000, 0x13b2: 0x4000, 0x13b3: 0x4000, 0x13b4: 0x4000, 0x13b5: 0x4000,
+	0x13b6: 0x4000,
+	// Block 0x4f, offset 0x13c0
+	0x13c4: 0x4000,
+	// Block 0x50, offset 0x1400
+	0x140f: 0x4000,
+	// Block 0x51, offset 0x1440
+	0x1440: 0x2000, 0x1441: 0x2000, 0x1442: 0x2000, 0x1443: 0x2000, 0x1444: 0x2000, 0x1445: 0x2000,
+	0x1446: 0x2000, 0x1447: 0x2000, 0x1448: 0x2000, 0x1449: 0x2000, 0x144a: 0x2000,
+	0x1450: 0x2000, 0x1451: 0x2000,
+	0x1452: 0x2000, 0x1453: 0x2000, 0x1454: 0x2000, 0x1455: 0x2000, 0x1456: 0x2000, 0x1457: 0x2000,
+	0x1458: 0x2000, 0x1459: 0x2000, 0x145a: 0x2000, 0x145b: 0x2000, 0x145c: 0x2000, 0x145d: 0x2000,
+	0x145e: 0x2000, 0x145f: 0x2000, 0x1460: 0x2000, 0x1461: 0x2000, 0x1462: 0x2000, 0x1463: 0x2000,
+	0x1464: 0x2000, 0x1465: 0x2000, 0x1466: 0x2000, 0x1467: 0x2000, 0x1468: 0x2000, 0x1469: 0x2000,
+	0x146a: 0x2000, 0x146b: 0x2000, 0x146c: 0x2000, 0x146d: 0x2000,
+	0x1470: 0x2000, 0x1471: 0x2000, 0x1472: 0x2000, 0x1473: 0x2000, 0x1474: 0x2000, 0x1475: 0x2000,
+	0x1476: 0x2000, 0x1477: 0x2000, 0x1478: 0x2000, 0x1479: 0x2000, 0x147a: 0x2000, 0x147b: 0x2000,
+	0x147c: 0x2000, 0x147d: 0x2000, 0x147e: 0x2000, 0x147f: 0x2000,
+	// Block 0x52, offset 0x1480
+	0x1480: 0x2000, 0x1481: 0x2000, 0x1482: 0x2000, 0x1483: 0x2000, 0x1484: 0x2000, 0x1485: 0x2000,
+	0x1486: 0x2000, 0x1487: 0x2000, 0x1488: 0x2000, 0x1489: 0x2000, 0x148a: 0x2000, 0x148b: 0x2000,
+	0x148c: 0x2000, 0x148d: 0x2000, 0x148e: 0x2000, 0x148f: 0x2000, 0x1490: 0x2000, 0x1491: 0x2000,
+	0x1492: 0x2000, 0x1493: 0x2000, 0x1494: 0x2000, 0x1495: 0x2000, 0x1496: 0x2000, 0x1497: 0x2000,
+	0x1498: 0x2000, 0x1499: 0x2000, 0x149a: 0x2000, 0x149b: 0x2000, 0x149c: 0x2000, 0x149d: 0x2000,
+	0x149e: 0x2000, 0x149f: 0x2000, 0x14a0: 0x2000, 0x14a1: 0x2000, 0x14a2: 0x2000, 0x14a3: 0x2000,
+	0x14a4: 0x2000, 0x14a5: 0x2000, 0x14a6: 0x2000, 0x14a7: 0x2000, 0x14a8: 0x2000, 0x14a9: 0x2000,
+	0x14b0: 0x2000, 0x14b1: 0x2000, 0x14b2: 0x2000, 0x14b3: 0x2000, 0x14b4: 0x2000, 0x14b5: 0x2000,
+	0x14b6: 0x2000, 0x14b7: 0x2000, 0x14b8: 0x2000, 0x14b9: 0x2000, 0x14ba: 0x2000, 0x14bb: 0x2000,
+	0x14bc: 0x2000, 0x14bd: 0x2000, 0x14be: 0x2000, 0x14bf: 0x2000,
+	// Block 0x53, offset 0x14c0
+	0x14c0: 0x2000, 0x14c1: 0x2000, 0x14c2: 0x2000, 0x14c3: 0x2000, 0x14c4: 0x2000, 0x14c5: 0x2000,
+	0x14c6: 0x2000, 0x14c7: 0x2000, 0x14c8: 0x2000, 0x14c9: 0x2000, 0x14ca: 0x2000, 0x14cb: 0x2000,
+	0x14cc: 0x2000, 0x14cd: 0x2000, 0x14ce: 0x4000, 0x14cf: 0x2000, 0x14d0: 0x2000, 0x14d1: 0x4000,
+	0x14d2: 0x4000, 0x14d3: 0x4000, 0x14d4: 0x4000, 0x14d5: 0x4000, 0x14d6: 0x4000, 0x14d7: 0x4000,
+	0x14d8: 0x4000, 0x14d9: 0x4000, 0x14da: 0x4000, 0x14db: 0x2000, 0x14dc: 0x2000, 0x14dd: 0x2000,
+	0x14de: 0x2000, 0x14df: 0x2000, 0x14e0: 0x2000, 0x14e1: 0x2000, 0x14e2: 0x2000, 0x14e3: 0x2000,
+	0x14e4: 0x2000, 0x14e5: 0x2000, 0x14e6: 0x2000, 0x14e7: 0x2000, 0x14e8: 0x2000, 0x14e9: 0x2000,
+	0x14ea: 0x2000, 0x14eb: 0x2000, 0x14ec: 0x2000,
+	// Block 0x54, offset 0x1500
+	0x1500: 0x4000, 0x1501: 0x4000, 0x1502: 0x4000,
+	0x1510: 0x4000, 0x1511: 0x4000,
+	0x1512: 0x4000, 0x1513: 0x4000, 0x1514: 0x4000, 0x1515: 0x4000, 0x1516: 0x4000, 0x1517: 0x4000,
+	0x1518: 0x4000, 0x1519: 0x4000, 0x151a: 0x4000, 0x151b: 0x4000, 0x151c: 0x4000, 0x151d: 0x4000,
+	0x151e: 0x4000, 0x151f: 0x4000, 0x1520: 0x4000, 0x1521: 0x4000, 0x1522: 0x4000, 0x1523: 0x4000,
+	0x1524: 0x4000, 0x1525: 0x4000, 0x1526: 0x4000, 0x1527: 0x4000, 0x1528: 0x4000, 0x1529: 0x4000,
+	0x152a: 0x4000, 0x152b: 0x4000, 0x152c: 0x4000, 0x152d: 0x4000, 0x152e: 0x4000, 0x152f: 0x4000,
+	0x1530: 0x4000, 0x1531: 0x4000, 0x1532: 0x4000, 0x1533: 0x4000, 0x1534: 0x4000, 0x1535: 0x4000,
+	0x1536: 0x4000, 0x1537: 0x4000, 0x1538: 0x4000, 0x1539: 0x4000, 0x153a: 0x4000, 0x153b: 0x4000,
+	// Block 0x55, offset 0x1540
+	0x1540: 0x4000, 0x1541: 0x4000, 0x1542: 0x4000, 0x1543: 0x4000, 0x1544: 0x4000, 0x1545: 0x4000,
+	0x1546: 0x4000, 0x1547: 0x4000, 0x1548: 0x4000,
+	0x1550: 0x4000, 0x1551: 0x4000,
+	0x1560: 0x4000, 0x1561: 0x4000, 0x1562: 0x4000, 0x1563: 0x4000,
+	0x1564: 0x4000, 0x1565: 0x4000,
+	// Block 0x56, offset 0x1580
+	0x1580: 0x4000, 0x1581: 0x4000, 0x1582: 0x4000, 0x1583: 0x4000, 0x1584: 0x4000, 0x1585: 0x4000,
+	0x1586: 0x4000, 0x1587: 0x4000, 0x1588: 0x4000, 0x1589: 0x4000, 0x158a: 0x4000, 0x158b: 0x4000,
+	0x158c: 0x4000, 0x158d: 0x4000, 0x158e: 0x4000, 0x158f: 0x4000, 0x1590: 0x4000, 0x1591: 0x4000,
+	0x1592: 0x4000, 0x1593: 0x4000, 0x1594: 0x4000, 0x1595: 0x4000, 0x1596: 0x4000, 0x1597: 0x4000,
+	0x1598: 0x4000, 0x1599: 0x4000, 0x159a: 0x4000, 0x159b: 0x4000, 0x159c: 0x4000, 0x159d: 0x4000,
+	0x159e: 0x4000, 0x159f: 0x4000, 0x15a0: 0x4000,
+	0x15ad: 0x4000, 0x15ae: 0x4000, 0x15af: 0x4000,
+	0x15b0: 0x4000, 0x15b1: 0x4000, 0x15b2: 0x4000, 0x15b3: 0x4000, 0x15b4: 0x4000, 0x15b5: 0x4000,
+	0x15b7: 0x4000, 0x15b8: 0x4000, 0x15b9: 0x4000, 0x15ba: 0x4000, 0x15bb: 0x4000,
+	0x15bc: 0x4000, 0x15bd: 0x4000, 0x15be: 0x4000, 0x15bf: 0x4000,
+	// Block 0x57, offset 0x15c0
+	0x15c0: 0x4000, 0x15c1: 0x4000, 0x15c2: 0x4000, 0x15c3: 0x4000, 0x15c4: 0x4000, 0x15c5: 0x4000,
+	0x15c6: 0x4000, 0x15c7: 0x4000, 0x15c8: 0x4000, 0x15c9: 0x4000, 0x15ca: 0x4000, 0x15cb: 0x4000,
+	0x15cc: 0x4000, 0x15cd: 0x4000, 0x15ce: 0x4000, 0x15cf: 0x4000, 0x15d0: 0x4000, 0x15d1: 0x4000,
+	0x15d2: 0x4000, 0x15d3: 0x4000, 0x15d4: 0x4000, 0x15d5: 0x4000, 0x15d6: 0x4000, 0x15d7: 0x4000,
+	0x15d8: 0x4000, 0x15d9: 0x4000, 0x15da: 0x4000, 0x15db: 0x4000, 0x15dc: 0x4000, 0x15dd: 0x4000,
+	0x15de: 0x4000, 0x15df: 0x4000, 0x15e0: 0x4000, 0x15e1: 0x4000, 0x15e2: 0x4000, 0x15e3: 0x4000,
+	0x15e4: 0x4000, 0x15e5: 0x4000, 0x15e6: 0x4000, 0x15e7: 0x4000, 0x15e8: 0x4000, 0x15e9: 0x4000,
+	0x15ea: 0x4000, 0x15eb: 0x4000, 0x15ec: 0x4000, 0x15ed: 0x4000, 0x15ee: 0x4000, 0x15ef: 0x4000,
+	0x15f0: 0x4000, 0x15f1: 0x4000, 0x15f2: 0x4000, 0x15f3: 0x4000, 0x15f4: 0x4000, 0x15f5: 0x4000,
+	0x15f6: 0x4000, 0x15f7: 0x4000, 0x15f8: 0x4000, 0x15f9: 0x4000, 0x15fa: 0x4000, 0x15fb: 0x4000,
+	0x15fc: 0x4000, 0x15fe: 0x4000, 0x15ff: 0x4000,
+	// Block 0x58, offset 0x1600
+	0x1600: 0x4000, 0x1601: 0x4000, 0x1602: 0x4000, 0x1603: 0x4000, 0x1604: 0x4000, 0x1605: 0x4000,
+	0x1606: 0x4000, 0x1607: 0x4000, 0x1608: 0x4000, 0x1609: 0x4000, 0x160a: 0x4000, 0x160b: 0x4000,
+	0x160c: 0x4000, 0x160d: 0x4000, 0x160e: 0x4000, 0x160f: 0x4000, 0x1610: 0x4000, 0x1611: 0x4000,
+	0x1612: 0x4000, 0x1613: 0x4000,
+	0x1620: 0x4000, 0x1621: 0x4000, 0x1622: 0x4000, 0x1623: 0x4000,
+	0x1624: 0x4000, 0x1625: 0x4000, 0x1626: 0x4000, 0x1627: 0x4000, 0x1628: 0x4000, 0x1629: 0x4000,
+	0x162a: 0x4000, 0x162b: 0x4000, 0x162c: 0x4000, 0x162d: 0x4000, 0x162e: 0x4000, 0x162f: 0x4000,
+	0x1630: 0x4000, 0x1631: 0x4000, 0x1632: 0x4000, 0x1633: 0x4000, 0x1634: 0x4000, 0x1635: 0x4000,
+	0x1636: 0x4000, 0x1637: 0x4000, 0x1638: 0x4000, 0x1639: 0x4000, 0x163a: 0x4000, 0x163b: 0x4000,
+	0x163c: 0x4000, 0x163d: 0x4000, 0x163e: 0x4000, 0x163f: 0x4000,
+	// Block 0x59, offset 0x1640
+	0x1640: 0x4000, 0x1641: 0x4000, 0x1642: 0x4000, 0x1643: 0x4000, 0x1644: 0x4000, 0x1645: 0x4000,
+	0x1646: 0x4000, 0x1647: 0x4000, 0x1648: 0x4000, 0x1649: 0x4000, 0x164a: 0x4000,
+	0x164f: 0x4000, 0x1650: 0x4000, 0x1651: 0x4000,
+	0x1652: 0x4000, 0x1653: 0x4000,
+	0x1660: 0x4000, 0x1661: 0x4000, 0x1662: 0x4000, 0x1663: 0x4000,
+	0x1664: 0x4000, 0x1665: 0x4000, 0x1666: 0x4000, 0x1667: 0x4000, 0x1668: 0x4000, 0x1669: 0x4000,
+	0x166a: 0x4000, 0x166b: 0x4000, 0x166c: 0x4000, 0x166d: 0x4000, 0x166e: 0x4000, 0x166f: 0x4000,
+	0x1670: 0x4000, 0x1674: 0x4000,
+	0x1678: 0x4000, 0x1679: 0x4000, 0x167a: 0x4000, 0x167b: 0x4000,
+	0x167c: 0x4000, 0x167d: 0x4000, 0x167e: 0x4000, 0x167f: 0x4000,
+	// Block 0x5a, offset 0x1680
+	0x1680: 0x4000, 0x1681: 0x4000, 0x1682: 0x4000, 0x1683: 0x4000, 0x1684: 0x4000, 0x1685: 0x4000,
+	0x1686: 0x4000, 0x1687: 0x4000, 0x1688: 0x4000, 0x1689: 0x4000, 0x168a: 0x4000, 0x168b: 0x4000,
+	0x168c: 0x4000, 0x168d: 0x4000, 0x168e: 0x4000, 0x168f: 0x4000, 0x1690: 0x4000, 0x1691: 0x4000,
+	0x1692: 0x4000, 0x1693: 0x4000, 0x1694: 0x4000, 0x1695: 0x4000, 0x1696: 0x4000, 0x1697: 0x4000,
+	0x1698: 0x4000, 0x1699: 0x4000, 0x169a: 0x4000, 0x169b: 0x4000, 0x169c: 0x4000, 0x169d: 0x4000,
+	0x169e: 0x4000, 0x169f: 0x4000, 0x16a0: 0x4000, 0x16a1: 0x4000, 0x16a2: 0x4000, 0x16a3: 0x4000,
+	0x16a4: 0x4000, 0x16a5: 0x4000, 0x16a6: 0x4000, 0x16a7: 0x4000, 0x16a8: 0x4000, 0x16a9: 0x4000,
+	0x16aa: 0x4000, 0x16ab: 0x4000, 0x16ac: 0x4000, 0x16ad: 0x4000, 0x16ae: 0x4000, 0x16af: 0x4000,
+	0x16b0: 0x4000, 0x16b1: 0x4000, 0x16b2: 0x4000, 0x16b3: 0x4000, 0x16b4: 0x4000, 0x16b5: 0x4000,
+	0x16b6: 0x4000, 0x16b7: 0x4000, 0x16b8: 0x4000, 0x16b9: 0x4000, 0x16ba: 0x4000, 0x16bb: 0x4000,
+	0x16bc: 0x4000, 0x16bd: 0x4000, 0x16be: 0x4000,
+	// Block 0x5b, offset 0x16c0
+	0x16c0: 0x4000, 0x16c2: 0x4000, 0x16c3: 0x4000, 0x16c4: 0x4000, 0x16c5: 0x4000,
+	0x16c6: 0x4000, 0x16c7: 0x4000, 0x16c8: 0x4000, 0x16c9: 0x4000, 0x16ca: 0x4000, 0x16cb: 0x4000,
+	0x16cc: 0x4000, 0x16cd: 0x4000, 0x16ce: 0x4000, 0x16cf: 0x4000, 0x16d0: 0x4000, 0x16d1: 0x4000,
+	0x16d2: 0x4000, 0x16d3: 0x4000, 0x16d4: 0x4000, 0x16d5: 0x4000, 0x16d6: 0x4000, 0x16d7: 0x4000,
+	0x16d8: 0x4000, 0x16d9: 0x4000, 0x16da: 0x4000, 0x16db: 0x4000, 0x16dc: 0x4000, 0x16dd: 0x4000,
+	0x16de: 0x4000, 0x16df: 0x4000, 0x16e0: 0x4000, 0x16e1: 0x4000, 0x16e2: 0x4000, 0x16e3: 0x4000,
+	0x16e4: 0x4000, 0x16e5: 0x4000, 0x16e6: 0x4000, 0x16e7: 0x4000, 0x16e8: 0x4000, 0x16e9: 0x4000,
+	0x16ea: 0x4000, 0x16eb: 0x4000, 0x16ec: 0x4000, 0x16ed: 0x4000, 0x16ee: 0x4000, 0x16ef: 0x4000,
+	0x16f0: 0x4000, 0x16f1: 0x4000, 0x16f2: 0x4000, 0x16f3: 0x4000, 0x16f4: 0x4000, 0x16f5: 0x4000,
+	0x16f6: 0x4000, 0x16f7: 0x4000, 0x16f8: 0x4000, 0x16f9: 0x4000, 0x16fa: 0x4000, 0x16fb: 0x4000,
+	0x16fc: 0x4000, 0x16fd: 0x4000, 0x16fe: 0x4000, 0x16ff: 0x4000,
+	// Block 0x5c, offset 0x1700
+	0x1700: 0x4000, 0x1701: 0x4000, 0x1702: 0x4000, 0x1703: 0x4000, 0x1704: 0x4000, 0x1705: 0x4000,
+	0x1706: 0x4000, 0x1707: 0x4000, 0x1708: 0x4000, 0x1709: 0x4000, 0x170a: 0x4000, 0x170b: 0x4000,
+	0x170c: 0x4000, 0x170d: 0x4000, 0x170e: 0x4000, 0x170f: 0x4000, 0x1710: 0x4000, 0x1711: 0x4000,
+	0x1712: 0x4000, 0x1713: 0x4000, 0x1714: 0x4000, 0x1715: 0x4000, 0x1716: 0x4000, 0x1717: 0x4000,
+	0x1718: 0x4000, 0x1719: 0x4000, 0x171a: 0x4000, 0x171b: 0x4000, 0x171c: 0x4000, 0x171d: 0x4000,
+	0x171e: 0x4000, 0x171f: 0x4000, 0x1720: 0x4000, 0x1721: 0x4000, 0x1722: 0x4000, 0x1723: 0x4000,
+	0x1724: 0x4000, 0x1725: 0x4000, 0x1726: 0x4000, 0x1727: 0x4000, 0x1728: 0x4000, 0x1729: 0x4000,
+	0x172a: 0x4000, 0x172b: 0x4000, 0x172c: 0x4000, 0x172d: 0x4000, 0x172e: 0x4000, 0x172f: 0x4000,
+	0x1730: 0x4000, 0x1731: 0x4000, 0x1732: 0x4000, 0x1733: 0x4000, 0x1734: 0x4000, 0x1735: 0x4000,
+	0x1736: 0x4000, 0x1737: 0x4000, 0x1738: 0x4000, 0x1739: 0x4000, 0x173a: 0x4000, 0x173b: 0x4000,
+	0x173c: 0x4000, 0x173f: 0x4000,
+	// Block 0x5d, offset 0x1740
+	0x1740: 0x4000, 0x1741: 0x4000, 0x1742: 0x4000, 0x1743: 0x4000, 0x1744: 0x4000, 0x1745: 0x4000,
+	0x1746: 0x4000, 0x1747: 0x4000, 0x1748: 0x4000, 0x1749: 0x4000, 0x174a: 0x4000, 0x174b: 0x4000,
+	0x174c: 0x4000, 0x174d: 0x4000, 0x174e: 0x4000, 0x174f: 0x4000, 0x1750: 0x4000, 0x1751: 0x4000,
+	0x1752: 0x4000, 0x1753: 0x4000, 0x1754: 0x4000, 0x1755: 0x4000, 0x1756: 0x4000, 0x1757: 0x4000,
+	0x1758: 0x4000, 0x1759: 0x4000, 0x175a: 0x4000, 0x175b: 0x4000, 0x175c: 0x4000, 0x175d: 0x4000,
+	0x175e: 0x4000, 0x175f: 0x4000, 0x1760: 0x4000, 0x1761: 0x4000, 0x1762: 0x4000, 0x1763: 0x4000,
+	0x1764: 0x4000, 0x1765: 0x4000, 0x1766: 0x4000, 0x1767: 0x4000, 0x1768: 0x4000, 0x1769: 0x4000,
+	0x176a: 0x4000, 0x176b: 0x4000, 0x176c: 0x4000, 0x176d: 0x4000, 0x176e: 0x4000, 0x176f: 0x4000,
+	0x1770: 0x4000, 0x1771: 0x4000, 0x1772: 0x4000, 0x1773: 0x4000, 0x1774: 0x4000, 0x1775: 0x4000,
+	0x1776: 0x4000, 0x1777: 0x4000, 0x1778: 0x4000, 0x1779: 0x4000, 0x177a: 0x4000, 0x177b: 0x4000,
+	0x177c: 0x4000, 0x177d: 0x4000,
+	// Block 0x5e, offset 0x1780
+	0x178b: 0x4000,
+	0x178c: 0x4000, 0x178d: 0x4000, 0x178e: 0x4000, 0x1790: 0x4000, 0x1791: 0x4000,
+	0x1792: 0x4000, 0x1793: 0x4000, 0x1794: 0x4000, 0x1795: 0x4000, 0x1796: 0x4000, 0x1797: 0x4000,
+	0x1798: 0x4000, 0x1799: 0x4000, 0x179a: 0x4000, 0x179b: 0x4000, 0x179c: 0x4000, 0x179d: 0x4000,
+	0x179e: 0x4000, 0x179f: 0x4000, 0x17a0: 0x4000, 0x17a1: 0x4000, 0x17a2: 0x4000, 0x17a3: 0x4000,
+	0x17a4: 0x4000, 0x17a5: 0x4000, 0x17a6: 0x4000, 0x17a7: 0x4000,
+	0x17ba: 0x4000,
+	// Block 0x5f, offset 0x17c0
+	0x17d5: 0x4000, 0x17d6: 0x4000,
+	0x17e4: 0x4000,
+	// Block 0x60, offset 0x1800
+	0x183b: 0x4000,
+	0x183c: 0x4000, 0x183d: 0x4000, 0x183e: 0x4000, 0x183f: 0x4000,
+	// Block 0x61, offset 0x1840
+	0x1840: 0x4000, 0x1841: 0x4000, 0x1842: 0x4000, 0x1843: 0x4000, 0x1844: 0x4000, 0x1845: 0x4000,
+	0x1846: 0x4000, 0x1847: 0x4000, 0x1848: 0x4000, 0x1849: 0x4000, 0x184a: 0x4000, 0x184b: 0x4000,
+	0x184c: 0x4000, 0x184d: 0x4000, 0x184e: 0x4000, 0x184f: 0x4000,
+	// Block 0x62, offset 0x1880
+	0x1880: 0x4000, 0x1881: 0x4000, 0x1882: 0x4000, 0x1883: 0x4000, 0x1884: 0x4000, 0x1885: 0x4000,
+	0x188c: 0x4000, 0x1890: 0x4000, 0x1891: 0x4000,
+	0x1892: 0x4000, 0x1895: 0x4000, 0x1896: 0x4000, 0x1897: 0x4000,
+	0x1898: 0x4000, 0x189c: 0x4000, 0x189d: 0x4000,
+	0x189e: 0x4000, 0x189f: 0x4000,
+	0x18ab: 0x4000, 0x18ac: 0x4000,
+	0x18b4: 0x4000, 0x18b5: 0x4000,
+	0x18b6: 0x4000, 0x18b7: 0x4000, 0x18b8: 0x4000, 0x18b9: 0x4000, 0x18ba: 0x4000, 0x18bb: 0x4000,
+	0x18bc: 0x4000,
+	// Block 0x63, offset 0x18c0
+	0x18e0: 0x4000, 0x18e1: 0x4000, 0x18e2: 0x4000, 0x18e3: 0x4000,
+	0x18e4: 0x4000, 0x18e5: 0x4000, 0x18e6: 0x4000, 0x18e7: 0x4000, 0x18e8: 0x4000, 0x18e9: 0x4000,
+	0x18ea: 0x4000, 0x18eb: 0x4000,
+	0x18f0: 0x4000,
+	// Block 0x64, offset 0x1900
+	0x190c: 0x4000, 0x190d: 0x4000, 0x190e: 0x4000, 0x190f: 0x4000, 0x1910: 0x4000, 0x1911: 0x4000,
+	0x1912: 0x4000, 0x1913: 0x4000, 0x1914: 0x4000, 0x1915: 0x4000, 0x1916: 0x4000, 0x1917: 0x4000,
+	0x1918: 0x4000, 0x1919: 0x4000, 0x191a: 0x4000, 0x191b: 0x4000, 0x191c: 0x4000, 0x191d: 0x4000,
+	0x191e: 0x4000, 0x191f: 0x4000, 0x1920: 0x4000, 0x1921: 0x4000, 0x1922: 0x4000, 0x1923: 0x4000,
+	0x1924: 0x4000, 0x1925: 0x4000, 0x1926: 0x4000, 0x1927: 0x4000, 0x1928: 0x4000, 0x1929: 0x4000,
+	0x192a: 0x4000, 0x192b: 0x4000, 0x192c: 0x4000, 0x192d: 0x4000, 0x192e: 0x4000, 0x192f: 0x4000,
+	0x1930: 0x4000, 0x1931: 0x4000, 0x1932: 0x4000, 0x1933: 0x4000, 0x1934: 0x4000, 0x1935: 0x4000,
+	0x1936: 0x4000, 0x1937: 0x4000, 0x1938: 0x4000, 0x1939: 0x4000, 0x193a: 0x4000,
+	0x193c: 0x4000, 0x193d: 0x4000, 0x193e: 0x4000, 0x193f: 0x4000,
+	// Block 0x65, offset 0x1940
+	0x1940: 0x4000, 0x1941: 0x4000, 0x1942: 0x4000, 0x1943: 0x4000, 0x1944: 0x4000, 0x1945: 0x4000,
+	0x1947: 0x4000, 0x1948: 0x4000, 0x1949: 0x4000, 0x194a: 0x4000, 0x194b: 0x4000,
+	0x194c: 0x4000, 0x194d: 0x4000, 0x194e: 0x4000, 0x194f: 0x4000, 0x1950: 0x4000, 0x1951: 0x4000,
+	0x1952: 0x4000, 0x1953: 0x4000, 0x1954: 0x4000, 0x1955: 0x4000, 0x1956: 0x4000, 0x1957: 0x4000,
+	0x1958: 0x4000, 0x1959: 0x4000, 0x195a: 0x4000, 0x195b: 0x4000, 0x195c: 0x4000, 0x195d: 0x4000,
+	0x195e: 0x4000, 0x195f: 0x4000, 0x1960: 0x4000, 0x1961: 0x4000, 0x1962: 0x4000, 0x1963: 0x4000,
+	0x1964: 0x4000, 0x1965: 0x4000, 0x1966: 0x4000, 0x1967: 0x4000, 0x1968: 0x4000, 0x1969: 0x4000,
+	0x196a: 0x4000, 0x196b: 0x4000, 0x196c: 0x4000, 0x196d: 0x4000, 0x196e: 0x4000, 0x196f: 0x4000,
+	0x1970: 0x4000, 0x1971: 0x4000, 0x1972: 0x4000, 0x1973: 0x4000, 0x1974: 0x4000, 0x1975: 0x4000,
+	0x1976: 0x4000, 0x1977: 0x4000, 0x1978: 0x4000, 0x1979: 0x4000, 0x197a: 0x4000, 0x197b: 0x4000,
+	0x197c: 0x4000, 0x197d: 0x4000, 0x197e: 0x4000, 0x197f: 0x4000,
+	// Block 0x66, offset 0x1980
+	0x19b0: 0x4000, 0x19b1: 0x4000, 0x19b2: 0x4000, 0x19b3: 0x4000, 0x19b4: 0x4000, 0x19b5: 0x4000,
+	0x19b6: 0x4000, 0x19b7: 0x4000, 0x19b8: 0x4000, 0x19b9: 0x4000, 0x19ba: 0x4000, 0x19bb: 0x4000,
+	0x19bc: 0x4000,
+	// Block 0x67, offset 0x19c0
+	0x19c0: 0x4000, 0x19c1: 0x4000, 0x19c2: 0x4000, 0x19c3: 0x4000, 0x19c4: 0x4000, 0x19c5: 0x4000,
+	0x19c6: 0x4000, 0x19c7: 0x4000, 0x19c8: 0x4000, 0x19c9: 0x4000, 0x19ca: 0x4000,
+	0x19ce: 0x4000, 0x19cf: 0x4000, 0x19d0: 0x4000, 0x19d1: 0x4000,
+	0x19d2: 0x4000, 0x19d3: 0x4000, 0x19d4: 0x4000, 0x19d5: 0x4000, 0x19d6: 0x4000, 0x19d7: 0x4000,
+	0x19d8: 0x4000, 0x19d9: 0x4000, 0x19da: 0x4000, 0x19db: 0x4000, 0x19dc: 0x4000, 0x19dd: 0x4000,
+	0x19de: 0x4000, 0x19df: 0x4000, 0x19e0: 0x4000, 0x19e1: 0x4000, 0x19e2: 0x4000, 0x19e3: 0x4000,
+	0x19e4: 0x4000, 0x19e5: 0x4000, 0x19e6: 0x4000, 0x19e7: 0x4000, 0x19e8: 0x4000, 0x19e9: 0x4000,
+	0x19ea: 0x4000, 0x19eb: 0x4000, 0x19ec: 0x4000, 0x19ed: 0x4000, 0x19ee: 0x4000, 0x19ef: 0x4000,
+	0x19f0: 0x4000, 0x19f1: 0x4000, 0x19f2: 0x4000, 0x19f3: 0x4000, 0x19f4: 0x4000, 0x19f5: 0x4000,
+	0x19f6: 0x4000, 0x19f7: 0x4000, 0x19f8: 0x4000, 0x19f9: 0x4000, 0x19fa: 0x4000, 0x19fb: 0x4000,
+	0x19fc: 0x4000, 0x19fd: 0x4000, 0x19fe: 0x4000, 0x19ff: 0x4000,
+	// Block 0x68, offset 0x1a00
+	0x1a00: 0x4000, 0x1a01: 0x4000, 0x1a02: 0x4000, 0x1a03: 0x4000, 0x1a04: 0x4000, 0x1a05: 0x4000,
+	0x1a06: 0x4000, 0x1a08: 0x4000,
+	0x1a0d: 0x4000, 0x1a0e: 0x4000, 0x1a0f: 0x4000, 0x1a10: 0x4000, 0x1a11: 0x4000,
+	0x1a12: 0x4000, 0x1a13: 0x4000, 0x1a14: 0x4000, 0x1a15: 0x4000, 0x1a16: 0x4000, 0x1a17: 0x4000,
+	0x1a18: 0x4000, 0x1a19: 0x4000, 0x1a1a: 0x4000, 0x1a1b: 0x4000, 0x1a1c: 0x4000,
+	0x1a1f: 0x4000, 0x1a20: 0x4000, 0x1a21: 0x4000, 0x1a22: 0x4000, 0x1a23: 0x4000,
+	0x1a24: 0x4000, 0x1a25: 0x4000, 0x1a26: 0x4000, 0x1a27: 0x4000, 0x1a28: 0x4000, 0x1a29: 0x4000,
+	0x1a2a: 0x4000, 0x1a2f: 0x4000,
+	0x1a30: 0x4000, 0x1a31: 0x4000, 0x1a32: 0x4000, 0x1a33: 0x4000, 0x1a34: 0x4000, 0x1a35: 0x4000,
+	0x1a36: 0x4000, 0x1a37: 0x4000, 0x1a38: 0x4000,
+	// Block 0x69, offset 0x1a40
+	0x1a40: 0x2000, 0x1a41: 0x2000, 0x1a42: 0x2000, 0x1a43: 0x2000, 0x1a44: 0x2000, 0x1a45: 0x2000,
+	0x1a46: 0x2000, 0x1a47: 0x2000, 0x1a48: 0x2000, 0x1a49: 0x2000, 0x1a4a: 0x2000, 0x1a4b: 0x2000,
+	0x1a4c: 0x2000, 0x1a4d: 0x2000, 0x1a4e: 0x2000, 0x1a4f: 0x2000, 0x1a50: 0x2000, 0x1a51: 0x2000,
+	0x1a52: 0x2000, 0x1a53: 0x2000, 0x1a54: 0x2000, 0x1a55: 0x2000, 0x1a56: 0x2000, 0x1a57: 0x2000,
+	0x1a58: 0x2000, 0x1a59: 0x2000, 0x1a5a: 0x2000, 0x1a5b: 0x2000, 0x1a5c: 0x2000, 0x1a5d: 0x2000,
+	0x1a5e: 0x2000, 0x1a5f: 0x2000, 0x1a60: 0x2000, 0x1a61: 0x2000, 0x1a62: 0x2000, 0x1a63: 0x2000,
+	0x1a64: 0x2000, 0x1a65: 0x2000, 0x1a66: 0x2000, 0x1a67: 0x2000, 0x1a68: 0x2000, 0x1a69: 0x2000,
+	0x1a6a: 0x2000, 0x1a6b: 0x2000, 0x1a6c: 0x2000, 0x1a6d: 0x2000, 0x1a6e: 0x2000, 0x1a6f: 0x2000,
+	0x1a70: 0x2000, 0x1a71: 0x2000, 0x1a72: 0x2000, 0x1a73: 0x2000, 0x1a74: 0x2000, 0x1a75: 0x2000,
+	0x1a76: 0x2000, 0x1a77: 0x2000, 0x1a78: 0x2000, 0x1a79: 0x2000, 0x1a7a: 0x2000, 0x1a7b: 0x2000,
+	0x1a7c: 0x2000, 0x1a7d: 0x2000,
+}
+
+// widthIndex: 23 blocks, 1472 entries, 1472 bytes
+// Block 0 is the zero block.
+var widthIndex = [1472]uint8{
+	// Block 0x0, offset 0x0
+	// Block 0x1, offset 0x40
+	// Block 0x2, offset 0x80
+	// Block 0x3, offset 0xc0
+	0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc7: 0x05,
+	0xc9: 0x06, 0xcb: 0x07, 0xcc: 0x08, 0xcd: 0x09, 0xce: 0x0a, 0xcf: 0x0b,
+	0xd0: 0x0c, 0xd1: 0x0d,
+	0xe1: 0x02, 0xe2: 0x03, 0xe3: 0x04, 0xe4: 0x05, 0xe5: 0x05, 0xe6: 0x05, 0xe7: 0x05,
+	0xe8: 0x05, 0xe9: 0x05, 0xea: 0x06, 0xeb: 0x05, 0xec: 0x05, 0xed: 0x07, 0xee: 0x08, 0xef: 0x09,
+	0xf0: 0x10, 0xf3: 0x13, 0xf4: 0x14,
+	// Block 0x4, offset 0x100
+	0x104: 0x0e, 0x105: 0x0f,
+	// Block 0x5, offset 0x140
+	0x140: 0x10, 0x141: 0x11, 0x142: 0x12, 0x144: 0x13, 0x145: 0x14, 0x146: 0x15, 0x147: 0x16,
+	0x148: 0x17, 0x149: 0x18, 0x14a: 0x19, 0x14c: 0x1a, 0x14f: 0x1b,
+	0x151: 0x1c, 0x152: 0x08, 0x153: 0x1d, 0x154: 0x1e, 0x155: 0x1f, 0x156: 0x20, 0x157: 0x21,
+	0x158: 0x22, 0x159: 0x23, 0x15a: 0x24, 0x15b: 0x25, 0x15c: 0x26, 0x15d: 0x27, 0x15e: 0x28, 0x15f: 0x29,
+	0x166: 0x2a,
+	0x16c: 0x2b, 0x16d: 0x2c,
+	0x17a: 0x2d, 0x17b: 0x2e, 0x17c: 0x0e, 0x17d: 0x0e, 0x17e: 0x0e, 0x17f: 0x2f,
+	// Block 0x6, offset 0x180
+	0x180: 0x30, 0x181: 0x31, 0x182: 0x32, 0x183: 0x33, 0x184: 0x34, 0x185: 0x35, 0x186: 0x36, 0x187: 0x37,
+	0x188: 0x38, 0x189: 0x39, 0x18a: 0x0e, 0x18b: 0x0e, 0x18c: 0x0e, 0x18d: 0x0e, 0x18e: 0x0e, 0x18f: 0x0e,
+	0x190: 0x0e, 0x191: 0x0e, 0x192: 0x0e, 0x193: 0x0e, 0x194: 0x0e, 0x195: 0x0e, 0x196: 0x0e, 0x197: 0x0e,
+	0x198: 0x0e, 0x199: 0x0e, 0x19a: 0x0e, 0x19b: 0x0e, 0x19c: 0x0e, 0x19d: 0x0e, 0x19e: 0x0e, 0x19f: 0x0e,
+	0x1a0: 0x0e, 0x1a1: 0x0e, 0x1a2: 0x0e, 0x1a3: 0x0e, 0x1a4: 0x0e, 0x1a5: 0x0e, 0x1a6: 0x0e, 0x1a7: 0x0e,
+	0x1a8: 0x0e, 0x1a9: 0x0e, 0x1aa: 0x0e, 0x1ab: 0x0e, 0x1ac: 0x0e, 0x1ad: 0x0e, 0x1ae: 0x0e, 0x1af: 0x0e,
+	0x1b0: 0x0e, 0x1b1: 0x0e, 0x1b2: 0x0e, 0x1b3: 0x0e, 0x1b4: 0x0e, 0x1b5: 0x0e, 0x1b6: 0x0e, 0x1b7: 0x0e,
+	0x1b8: 0x0e, 0x1b9: 0x0e, 0x1ba: 0x0e, 0x1bb: 0x0e, 0x1bc: 0x0e, 0x1bd: 0x0e, 0x1be: 0x0e, 0x1bf: 0x0e,
+	// Block 0x7, offset 0x1c0
+	0x1c0: 0x0e, 0x1c1: 0x0e, 0x1c2: 0x0e, 0x1c3: 0x0e, 0x1c4: 0x0e, 0x1c5: 0x0e, 0x1c6: 0x0e, 0x1c7: 0x0e,
+	0x1c8: 0x0e, 0x1c9: 0x0e, 0x1ca: 0x0e, 0x1cb: 0x0e, 0x1cc: 0x0e, 0x1cd: 0x0e, 0x1ce: 0x0e, 0x1cf: 0x0e,
+	0x1d0: 0x0e, 0x1d1: 0x0e, 0x1d2: 0x0e, 0x1d3: 0x0e, 0x1d4: 0x0e, 0x1d5: 0x0e, 0x1d6: 0x0e, 0x1d7: 0x0e,
+	0x1d8: 0x0e, 0x1d9: 0x0e, 0x1da: 0x0e, 0x1db: 0x0e, 0x1dc: 0x0e, 0x1dd: 0x0e, 0x1de: 0x0e, 0x1df: 0x0e,
+	0x1e0: 0x0e, 0x1e1: 0x0e, 0x1e2: 0x0e, 0x1e3: 0x0e, 0x1e4: 0x0e, 0x1e5: 0x0e, 0x1e6: 0x0e, 0x1e7: 0x0e,
+	0x1e8: 0x0e, 0x1e9: 0x0e, 0x1ea: 0x0e, 0x1eb: 0x0e, 0x1ec: 0x0e, 0x1ed: 0x0e, 0x1ee: 0x0e, 0x1ef: 0x0e,
+	0x1f0: 0x0e, 0x1f1: 0x0e, 0x1f2: 0x0e, 0x1f3: 0x0e, 0x1f4: 0x0e, 0x1f5: 0x0e, 0x1f6: 0x0e, 0x1f7: 0x0e,
+	0x1f8: 0x0e, 0x1f9: 0x0e, 0x1fa: 0x0e, 0x1fb: 0x0e, 0x1fc: 0x0e, 0x1fd: 0x0e, 0x1fe: 0x0e, 0x1ff: 0x0e,
+	// Block 0x8, offset 0x200
+	0x200: 0x0e, 0x201: 0x0e, 0x202: 0x0e, 0x203: 0x0e, 0x204: 0x0e, 0x205: 0x0e, 0x206: 0x0e, 0x207: 0x0e,
+	0x208: 0x0e, 0x209: 0x0e, 0x20a: 0x0e, 0x20b: 0x0e, 0x20c: 0x0e, 0x20d: 0x0e, 0x20e: 0x0e, 0x20f: 0x0e,
+	0x210: 0x0e, 0x211: 0x0e, 0x212: 0x3a, 0x213: 0x3b,
+	0x225: 0x3c,
+	0x230: 0x0e, 0x231: 0x0e, 0x232: 0x0e, 0x233: 0x0e, 0x234: 0x0e, 0x235: 0x0e, 0x236: 0x0e, 0x237: 0x0e,
+	0x238: 0x0e, 0x239: 0x0e, 0x23a: 0x0e, 0x23b: 0x0e, 0x23c: 0x0e, 0x23d: 0x0e, 0x23e: 0x0e, 0x23f: 0x0e,
+	// Block 0x9, offset 0x240
+	0x240: 0x0e, 0x241: 0x0e, 0x242: 0x0e, 0x243: 0x0e, 0x244: 0x0e, 0x245: 0x0e, 0x246: 0x0e, 0x247: 0x0e,
+	0x248: 0x0e, 0x249: 0x0e, 0x24a: 0x0e, 0x24b: 0x0e, 0x24c: 0x0e, 0x24d: 0x0e, 0x24e: 0x0e, 0x24f: 0x0e,
+	0x250: 0x0e, 0x251: 0x0e, 0x252: 0x0e, 0x253: 0x0e, 0x254: 0x0e, 0x255: 0x0e, 0x256: 0x0e, 0x257: 0x0e,
+	0x258: 0x0e, 0x259: 0x0e, 0x25a: 0x0e, 0x25b: 0x0e, 0x25c: 0x0e, 0x25d: 0x0e, 0x25e: 0x3d,
+	// Block 0xa, offset 0x280
+	0x280: 0x08, 0x281: 0x08, 0x282: 0x08, 0x283: 0x08, 0x284: 0x08, 0x285: 0x08, 0x286: 0x08, 0x287: 0x08,
+	0x288: 0x08, 0x289: 0x08, 0x28a: 0x08, 0x28b: 0x08, 0x28c: 0x08, 0x28d: 0x08, 0x28e: 0x08, 0x28f: 0x08,
+	0x290: 0x08, 0x291: 0x08, 0x292: 0x08, 0x293: 0x08, 0x294: 0x08, 0x295: 0x08, 0x296: 0x08, 0x297: 0x08,
+	0x298: 0x08, 0x299: 0x08, 0x29a: 0x08, 0x29b: 0x08, 0x29c: 0x08, 0x29d: 0x08, 0x29e: 0x08, 0x29f: 0x08,
+	0x2a0: 0x08, 0x2a1: 0x08, 0x2a2: 0x08, 0x2a3: 0x08, 0x2a4: 0x08, 0x2a5: 0x08, 0x2a6: 0x08, 0x2a7: 0x08,
+	0x2a8: 0x08, 0x2a9: 0x08, 0x2aa: 0x08, 0x2ab: 0x08, 0x2ac: 0x08, 0x2ad: 0x08, 0x2ae: 0x08, 0x2af: 0x08,
+	0x2b0: 0x08, 0x2b1: 0x08, 0x2b2: 0x08, 0x2b3: 0x08, 0x2b4: 0x08, 0x2b5: 0x08, 0x2b6: 0x08, 0x2b7: 0x08,
+	0x2b8: 0x08, 0x2b9: 0x08, 0x2ba: 0x08, 0x2bb: 0x08, 0x2bc: 0x08, 0x2bd: 0x08, 0x2be: 0x08, 0x2bf: 0x08,
+	// Block 0xb, offset 0x2c0
+	0x2c0: 0x08, 0x2c1: 0x08, 0x2c2: 0x08, 0x2c3: 0x08, 0x2c4: 0x08, 0x2c5: 0x08, 0x2c6: 0x08, 0x2c7: 0x08,
+	0x2c8: 0x08, 0x2c9: 0x08, 0x2ca: 0x08, 0x2cb: 0x08, 0x2cc: 0x08, 0x2cd: 0x08, 0x2ce: 0x08, 0x2cf: 0x08,
+	0x2d0: 0x08, 0x2d1: 0x08, 0x2d2: 0x08, 0x2d3: 0x08, 0x2d4: 0x08, 0x2d5: 0x08, 0x2d6: 0x08, 0x2d7: 0x08,
+	0x2d8: 0x08, 0x2d9: 0x08, 0x2da: 0x08, 0x2db: 0x08, 0x2dc: 0x08, 0x2dd: 0x08, 0x2de: 0x08, 0x2df: 0x08,
+	0x2e0: 0x08, 0x2e1: 0x08, 0x2e2: 0x08, 0x2e3: 0x08, 0x2e4: 0x0e, 0x2e5: 0x0e, 0x2e6: 0x0e, 0x2e7: 0x0e,
+	0x2e8: 0x0e, 0x2e9: 0x0e, 0x2ea: 0x0e, 0x2eb: 0x0e,
+	0x2f8: 0x3e, 0x2f9: 0x3f, 0x2fc: 0x40, 0x2fd: 0x41, 0x2fe: 0x42, 0x2ff: 0x43,
+	// Block 0xc, offset 0x300
+	0x33f: 0x44,
+	// Block 0xd, offset 0x340
+	0x340: 0x0e, 0x341: 0x0e, 0x342: 0x0e, 0x343: 0x0e, 0x344: 0x0e, 0x345: 0x0e, 0x346: 0x0e, 0x347: 0x0e,
+	0x348: 0x0e, 0x349: 0x0e, 0x34a: 0x0e, 0x34b: 0x0e, 0x34c: 0x0e, 0x34d: 0x0e, 0x34e: 0x0e, 0x34f: 0x0e,
+	0x350: 0x0e, 0x351: 0x0e, 0x352: 0x0e, 0x353: 0x0e, 0x354: 0x0e, 0x355: 0x0e, 0x356: 0x0e, 0x357: 0x0e,
+	0x358: 0x0e, 0x359: 0x0e, 0x35a: 0x0e, 0x35b: 0x0e, 0x35c: 0x0e, 0x35d: 0x0e, 0x35e: 0x0e, 0x35f: 0x0e,
+	0x360: 0x0e, 0x361: 0x0e, 0x362: 0x0e, 0x363: 0x0e, 0x364: 0x0e, 0x365: 0x0e, 0x366: 0x0e, 0x367: 0x0e,
+	0x368: 0x0e, 0x369: 0x0e, 0x36a: 0x0e, 0x36b: 0x0e, 0x36c: 0x0e, 0x36d: 0x0e, 0x36e: 0x0e, 0x36f: 0x0e,
+	0x370: 0x0e, 0x371: 0x0e, 0x372: 0x0e, 0x373: 0x45, 0x374: 0x46, 0x376: 0x0e, 0x377: 0x47,
+	// Block 0xe, offset 0x380
+	0x3bf: 0x48,
+	// Block 0xf, offset 0x3c0
+	0x3c0: 0x0e, 0x3c1: 0x0e, 0x3c2: 0x0e, 0x3c3: 0x0e, 0x3c4: 0x49, 0x3c5: 0x4a, 0x3c6: 0x0e, 0x3c7: 0x0e,
+	0x3c8: 0x0e, 0x3c9: 0x0e, 0x3ca: 0x0e, 0x3cb: 0x4b,
+	// Block 0x10, offset 0x400
+	0x40c: 0x0e, 0x40d: 0x4c,
+	// Block 0x11, offset 0x440
+	0x440: 0x4d, 0x443: 0x4e, 0x444: 0x4f, 0x445: 0x50, 0x446: 0x51,
+	0x448: 0x52, 0x449: 0x53, 0x44c: 0x54, 0x44d: 0x55, 0x44e: 0x56, 0x44f: 0x57,
+	0x450: 0x58, 0x451: 0x59, 0x452: 0x0e, 0x453: 0x5a, 0x454: 0x5b, 0x455: 0x5c, 0x456: 0x5d, 0x457: 0x5e,
+	0x458: 0x0e, 0x459: 0x5f, 0x45a: 0x0e, 0x45b: 0x60, 0x45f: 0x61,
+	0x464: 0x62, 0x465: 0x63, 0x466: 0x0e, 0x467: 0x0e,
+	0x469: 0x64, 0x46a: 0x65, 0x46b: 0x66,
+	// Block 0x12, offset 0x480
+	0x496: 0x0a, 0x497: 0x05,
+	0x498: 0x0b, 0x49a: 0x0c, 0x49b: 0x0d, 0x49d: 0x0e, 0x49f: 0x0f,
+	0x4a0: 0x05, 0x4a1: 0x05, 0x4a2: 0x05, 0x4a3: 0x05, 0x4a4: 0x05, 0x4a5: 0x05, 0x4a6: 0x05, 0x4a7: 0x05,
+	0x4a8: 0x05, 0x4a9: 0x05, 0x4aa: 0x05, 0x4ab: 0x05, 0x4ac: 0x05, 0x4ad: 0x05, 0x4ae: 0x05, 0x4af: 0x05,
+	0x4b0: 0x05, 0x4b1: 0x05, 0x4b2: 0x05, 0x4b3: 0x05, 0x4b4: 0x05, 0x4b5: 0x05, 0x4b6: 0x05, 0x4b7: 0x05,
+	0x4b8: 0x05, 0x4b9: 0x05, 0x4ba: 0x05, 0x4bb: 0x05, 0x4bc: 0x05, 0x4bd: 0x05, 0x4be: 0x05, 0x4bf: 0x05,
+	// Block 0x13, offset 0x4c0
+	0x4c4: 0x08, 0x4c5: 0x08, 0x4c6: 0x08, 0x4c7: 0x09,
+	// Block 0x14, offset 0x500
+	0x500: 0x08, 0x501: 0x08, 0x502: 0x08, 0x503: 0x08, 0x504: 0x08, 0x505: 0x08, 0x506: 0x08, 0x507: 0x08,
+	0x508: 0x08, 0x509: 0x08, 0x50a: 0x08, 0x50b: 0x08, 0x50c: 0x08, 0x50d: 0x08, 0x50e: 0x08, 0x50f: 0x08,
+	0x510: 0x08, 0x511: 0x08, 0x512: 0x08, 0x513: 0x08, 0x514: 0x08, 0x515: 0x08, 0x516: 0x08, 0x517: 0x08,
+	0x518: 0x08, 0x519: 0x08, 0x51a: 0x08, 0x51b: 0x08, 0x51c: 0x08, 0x51d: 0x08, 0x51e: 0x08, 0x51f: 0x08,
+	0x520: 0x08, 0x521: 0x08, 0x522: 0x08, 0x523: 0x08, 0x524: 0x08, 0x525: 0x08, 0x526: 0x08, 0x527: 0x08,
+	0x528: 0x08, 0x529: 0x08, 0x52a: 0x08, 0x52b: 0x08, 0x52c: 0x08, 0x52d: 0x08, 0x52e: 0x08, 0x52f: 0x08,
+	0x530: 0x08, 0x531: 0x08, 0x532: 0x08, 0x533: 0x08, 0x534: 0x08, 0x535: 0x08, 0x536: 0x08, 0x537: 0x08,
+	0x538: 0x08, 0x539: 0x08, 0x53a: 0x08, 0x53b: 0x08, 0x53c: 0x08, 0x53d: 0x08, 0x53e: 0x08, 0x53f: 0x67,
+	// Block 0x15, offset 0x540
+	0x560: 0x11,
+	0x570: 0x08, 0x571: 0x08, 0x572: 0x08, 0x573: 0x08, 0x574: 0x08, 0x575: 0x08, 0x576: 0x08, 0x577: 0x08,
+	0x578: 0x08, 0x579: 0x08, 0x57a: 0x08, 0x57b: 0x08, 0x57c: 0x08, 0x57d: 0x08, 0x57e: 0x08, 0x57f: 0x12,
+	// Block 0x16, offset 0x580
+	0x580: 0x08, 0x581: 0x08, 0x582: 0x08, 0x583: 0x08, 0x584: 0x08, 0x585: 0x08, 0x586: 0x08, 0x587: 0x08,
+	0x588: 0x08, 0x589: 0x08, 0x58a: 0x08, 0x58b: 0x08, 0x58c: 0x08, 0x58d: 0x08, 0x58e: 0x08, 0x58f: 0x12,
+}
+
+// inverseData contains 4-byte entries of the following format:
+//
+//	<length> <modified UTF-8-encoded rune> <0 padding>
+//
+// The last byte of the UTF-8-encoded rune is xor-ed with the last byte of the
+// UTF-8 encoding of the original rune. Mappings often have the following
+// pattern:
+//
+//	Ａ -> A  (U+FF21 -> U+0041)
+//	Ｂ -> B  (U+FF22 -> U+0042)
+//	...
+//
+// By xor-ing the last byte the same entry can be shared by many mappings. This
+// reduces the total number of distinct entries by about two thirds.
+// The resulting entry for the aforementioned mappings is
+//
+//	{ 0x01, 0xE0, 0x00, 0x00 }
+//
+// Using this entry to map U+FF21 (UTF-8 [EF BC A1]), we get
+//
+//	E0 ^ A1 = 41.
+//
+// Similarly, for U+FF22 (UTF-8 [EF BC A2]), we get
+//
+//	E0 ^ A2 = 42.
+//
+// Note that because of the xor-ing, the byte sequence stored in the entry is
+// not valid UTF-8.
+var inverseData = [150][4]byte{
+	{0x00, 0x00, 0x00, 0x00},
+	{0x03, 0xe3, 0x80, 0xa0},
+	{0x03, 0xef, 0xbc, 0xa0},
+	{0x03, 0xef, 0xbc, 0xe0},
+	{0x03, 0xef, 0xbd, 0xe0},
+	{0x03, 0xef, 0xbf, 0x02},
+	{0x03, 0xef, 0xbf, 0x00},
+	{0x03, 0xef, 0xbf, 0x0e},
+	{0x03, 0xef, 0xbf, 0x0c},
+	{0x03, 0xef, 0xbf, 0x0f},
+	{0x03, 0xef, 0xbf, 0x39},
+	{0x03, 0xef, 0xbf, 0x3b},
+	{0x03, 0xef, 0xbf, 0x3f},
+	{0x03, 0xef, 0xbf, 0x2a},
+	{0x03, 0xef, 0xbf, 0x0d},
+	{0x03, 0xef, 0xbf, 0x25},
+	{0x03, 0xef, 0xbd, 0x1a},
+	{0x03, 0xef, 0xbd, 0x26},
+	{0x01, 0xa0, 0x00, 0x00},
+	{0x03, 0xef, 0xbd, 0x25},
+	{0x03, 0xef, 0xbd, 0x23},
+	{0x03, 0xef, 0xbd, 0x2e},
+	{0x03, 0xef, 0xbe, 0x07},
+	{0x03, 0xef, 0xbe, 0x05},
+	{0x03, 0xef, 0xbd, 0x06},
+	{0x03, 0xef, 0xbd, 0x13},
+	{0x03, 0xef, 0xbd, 0x0b},
+	{0x03, 0xef, 0xbd, 0x16},
+	{0x03, 0xef, 0xbd, 0x0c},
+	{0x03, 0xef, 0xbd, 0x15},
+	{0x03, 0xef, 0xbd, 0x0d},
+	{0x03, 0xef, 0xbd, 0x1c},
+	{0x03, 0xef, 0xbd, 0x02},
+	{0x03, 0xef, 0xbd, 0x1f},
+	{0x03, 0xef, 0xbd, 0x1d},
+	{0x03, 0xef, 0xbd, 0x17},
+	{0x03, 0xef, 0xbd, 0x08},
+	{0x03, 0xef, 0xbd, 0x09},
+	{0x03, 0xef, 0xbd, 0x0e},
+	{0x03, 0xef, 0xbd, 0x04},
+	{0x03, 0xef, 0xbd, 0x05},
+	{0x03, 0xef, 0xbe, 0x3f},
+	{0x03, 0xef, 0xbe, 0x00},
+	{0x03, 0xef, 0xbd, 0x2c},
+	{0x03, 0xef, 0xbe, 0x06},
+	{0x03, 0xef, 0xbe, 0x0c},
+	{0x03, 0xef, 0xbe, 0x0f},
+	{0x03, 0xef, 0xbe, 0x0d},
+	{0x03, 0xef, 0xbe, 0x0b},
+	{0x03, 0xef, 0xbe, 0x19},
+	{0x03, 0xef, 0xbe, 0x15},
+	{0x03, 0xef, 0xbe, 0x11},
+	{0x03, 0xef, 0xbe, 0x31},
+	{0x03, 0xef, 0xbe, 0x33},
+	{0x03, 0xef, 0xbd, 0x0f},
+	{0x03, 0xef, 0xbe, 0x30},
+	{0x03, 0xef, 0xbe, 0x3e},
+	{0x03, 0xef, 0xbe, 0x32},
+	{0x03, 0xef, 0xbe, 0x36},
+	{0x03, 0xef, 0xbd, 0x14},
+	{0x03, 0xef, 0xbe, 0x2e},
+	{0x03, 0xef, 0xbd, 0x1e},
+	{0x03, 0xef, 0xbe, 0x10},
+	{0x03, 0xef, 0xbf, 0x13},
+	{0x03, 0xef, 0xbf, 0x15},
+	{0x03, 0xef, 0xbf, 0x17},
+	{0x03, 0xef, 0xbf, 0x1f},
+	{0x03, 0xef, 0xbf, 0x1d},
+	{0x03, 0xef, 0xbf, 0x1b},
+	{0x03, 0xef, 0xbf, 0x09},
+	{0x03, 0xef, 0xbf, 0x0b},
+	{0x03, 0xef, 0xbf, 0x37},
+	{0x03, 0xef, 0xbe, 0x04},
+	{0x01, 0xe0, 0x00, 0x00},
+	{0x03, 0xe2, 0xa6, 0x1a},
+	{0x03, 0xe2, 0xa6, 0x26},
+	{0x03, 0xe3, 0x80, 0x23},
+	{0x03, 0xe3, 0x80, 0x2e},
+	{0x03, 0xe3, 0x80, 0x25},
+	{0x03, 0xe3, 0x83, 0x1e},
+	{0x03, 0xe3, 0x83, 0x14},
+	{0x03, 0xe3, 0x82, 0x06},
+	{0x03, 0xe3, 0x82, 0x0b},
+	{0x03, 0xe3, 0x82, 0x0c},
+	{0x03, 0xe3, 0x82, 0x0d},
+	{0x03, 0xe3, 0x82, 0x02},
+	{0x03, 0xe3, 0x83, 0x0f},
+	{0x03, 0xe3, 0x83, 0x08},
+	{0x03, 0xe3, 0x83, 0x09},
+	{0x03, 0xe3, 0x83, 0x2c},
+	{0x03, 0xe3, 0x83, 0x0c},
+	{0x03, 0xe3, 0x82, 0x13},
+	{0x03, 0xe3, 0x82, 0x16},
+	{0x03, 0xe3, 0x82, 0x15},
+	{0x03, 0xe3, 0x82, 0x1c},
+	{0x03, 0xe3, 0x82, 0x1f},
+	{0x03, 0xe3, 0x82, 0x1d},
+	{0x03, 0xe3, 0x82, 0x1a},
+	{0x03, 0xe3, 0x82, 0x17},
+	{0x03, 0xe3, 0x82, 0x08},
+	{0x03, 0xe3, 0x82, 0x09},
+	{0x03, 0xe3, 0x82, 0x0e},
+	{0x03, 0xe3, 0x82, 0x04},
+	{0x03, 0xe3, 0x82, 0x05},
+	{0x03, 0xe3, 0x82, 0x3f},
+	{0x03, 0xe3, 0x83, 0x00},
+	{0x03, 0xe3, 0x83, 0x06},
+	{0x03, 0xe3, 0x83, 0x05},
+	{0x03, 0xe3, 0x83, 0x0d},
+	{0x03, 0xe3, 0x83, 0x0b},
+	{0x03, 0xe3, 0x83, 0x07},
+	{0x03, 0xe3, 0x83, 0x19},
+	{0x03, 0xe3, 0x83, 0x15},
+	{0x03, 0xe3, 0x83, 0x11},
+	{0x03, 0xe3, 0x83, 0x31},
+	{0x03, 0xe3, 0x83, 0x33},
+	{0x03, 0xe3, 0x83, 0x30},
+	{0x03, 0xe3, 0x83, 0x3e},
+	{0x03, 0xe3, 0x83, 0x32},
+	{0x03, 0xe3, 0x83, 0x36},
+	{0x03, 0xe3, 0x83, 0x2e},
+	{0x03, 0xe3, 0x82, 0x07},
+	{0x03, 0xe3, 0x85, 0x04},
+	{0x03, 0xe3, 0x84, 0x10},
+	{0x03, 0xe3, 0x85, 0x30},
+	{0x03, 0xe3, 0x85, 0x0d},
+	{0x03, 0xe3, 0x85, 0x13},
+	{0x03, 0xe3, 0x85, 0x15},
+	{0x03, 0xe3, 0x85, 0x17},
+	{0x03, 0xe3, 0x85, 0x1f},
+	{0x03, 0xe3, 0x85, 0x1d},
+	{0x03, 0xe3, 0x85, 0x1b},
+	{0x03, 0xe3, 0x85, 0x09},
+	{0x03, 0xe3, 0x85, 0x0f},
+	{0x03, 0xe3, 0x85, 0x0b},
+	{0x03, 0xe3, 0x85, 0x37},
+	{0x03, 0xe3, 0x85, 0x3b},
+	{0x03, 0xe3, 0x85, 0x39},
+	{0x03, 0xe3, 0x85, 0x3f},
+	{0x02, 0xc2, 0x02, 0x00},
+	{0x02, 0xc2, 0x0e, 0x00},
+	{0x02, 0xc2, 0x0c, 0x00},
+	{0x02, 0xc2, 0x00, 0x00},
+	{0x03, 0xe2, 0x82, 0x0f},
+	{0x03, 0xe2, 0x94, 0x2a},
+	{0x03, 0xe2, 0x86, 0x39},
+	{0x03, 0xe2, 0x86, 0x3b},
+	{0x03, 0xe2, 0x86, 0x3f},
+	{0x03, 0xe2, 0x96, 0x0d},
+	{0x03, 0xe2, 0x97, 0x25},
+}
+
+// Total table size 15640 bytes (15KiB)
diff --git a/vendor/golang.org/x/text/width/transform.go b/vendor/golang.org/x/text/width/transform.go
new file mode 100644
index 000000000..0049f700a
--- /dev/null
+++ b/vendor/golang.org/x/text/width/transform.go
@@ -0,0 +1,239 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package width
+
+import (
+	"unicode/utf8"
+
+	"golang.org/x/text/transform"
+)
+
+type foldTransform struct {
+	transform.NopResetter
+}
+
+func (foldTransform) Span(src []byte, atEOF bool) (n int, err error) {
+	for n < len(src) {
+		if src[n] < utf8.RuneSelf {
+			// ASCII fast path.
+			for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
+			}
+			continue
+		}
+		v, size := trie.lookup(src[n:])
+		if size == 0 { // incomplete UTF-8 encoding
+			if !atEOF {
+				err = transform.ErrShortSrc
+			} else {
+				n = len(src)
+			}
+			break
+		}
+		if elem(v)&tagNeedsFold != 0 {
+			err = transform.ErrEndOfSpan
+			break
+		}
+		n += size
+	}
+	return n, err
+}
+
+func (foldTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	for nSrc < len(src) {
+		if src[nSrc] < utf8.RuneSelf {
+			// ASCII fast path.
+			start, end := nSrc, len(src)
+			if d := len(dst) - nDst; d < end-start {
+				end = nSrc + d
+			}
+			for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
+			}
+			n := copy(dst[nDst:], src[start:nSrc])
+			if nDst += n; nDst == len(dst) {
+				nSrc = start + n
+				if nSrc == len(src) {
+					return nDst, nSrc, nil
+				}
+				if src[nSrc] < utf8.RuneSelf {
+					return nDst, nSrc, transform.ErrShortDst
+				}
+			}
+			continue
+		}
+		v, size := trie.lookup(src[nSrc:])
+		if size == 0 { // incomplete UTF-8 encoding
+			if !atEOF {
+				return nDst, nSrc, transform.ErrShortSrc
+			}
+			size = 1 // gobble 1 byte
+		}
+		if elem(v)&tagNeedsFold == 0 {
+			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+				return nDst, nSrc, transform.ErrShortDst
+			}
+			nDst += size
+		} else {
+			data := inverseData[byte(v)]
+			if len(dst)-nDst < int(data[0]) {
+				return nDst, nSrc, transform.ErrShortDst
+			}
+			i := 1
+			for end := int(data[0]); i < end; i++ {
+				dst[nDst] = data[i]
+				nDst++
+			}
+			dst[nDst] = data[i] ^ src[nSrc+size-1]
+			nDst++
+		}
+		nSrc += size
+	}
+	return nDst, nSrc, nil
+}
+
+type narrowTransform struct {
+	transform.NopResetter
+}
+
+func (narrowTransform) Span(src []byte, atEOF bool) (n int, err error) {
+	for n < len(src) {
+		if src[n] < utf8.RuneSelf {
+			// ASCII fast path.
+			for n++; n < len(src) && src[n] < utf8.RuneSelf; n++ {
+			}
+			continue
+		}
+		v, size := trie.lookup(src[n:])
+		if size == 0 { // incomplete UTF-8 encoding
+			if !atEOF {
+				err = transform.ErrShortSrc
+			} else {
+				n = len(src)
+			}
+			break
+		}
+		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
+		} else {
+			err = transform.ErrEndOfSpan
+			break
+		}
+		n += size
+	}
+	return n, err
+}
+
+func (narrowTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	for nSrc < len(src) {
+		if src[nSrc] < utf8.RuneSelf {
+			// ASCII fast path.
+			start, end := nSrc, len(src)
+			if d := len(dst) - nDst; d < end-start {
+				end = nSrc + d
+			}
+			for nSrc++; nSrc < end && src[nSrc] < utf8.RuneSelf; nSrc++ {
+			}
+			n := copy(dst[nDst:], src[start:nSrc])
+			if nDst += n; nDst == len(dst) {
+				nSrc = start + n
+				if nSrc == len(src) {
+					return nDst, nSrc, nil
+				}
+				if src[nSrc] < utf8.RuneSelf {
+					return nDst, nSrc, transform.ErrShortDst
+				}
+			}
+			continue
+		}
+		v, size := trie.lookup(src[nSrc:])
+		if size == 0 { // incomplete UTF-8 encoding
+			if !atEOF {
+				return nDst, nSrc, transform.ErrShortSrc
+			}
+			size = 1 // gobble 1 byte
+		}
+		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianFullwidth && k != EastAsianWide && k != EastAsianAmbiguous {
+			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+				return nDst, nSrc, transform.ErrShortDst
+			}
+			nDst += size
+		} else {
+			data := inverseData[byte(v)]
+			if len(dst)-nDst < int(data[0]) {
+				return nDst, nSrc, transform.ErrShortDst
+			}
+			i := 1
+			for end := int(data[0]); i < end; i++ {
+				dst[nDst] = data[i]
+				nDst++
+			}
+			dst[nDst] = data[i] ^ src[nSrc+size-1]
+			nDst++
+		}
+		nSrc += size
+	}
+	return nDst, nSrc, nil
+}
+
+type wideTransform struct {
+	transform.NopResetter
+}
+
+func (wideTransform) Span(src []byte, atEOF bool) (n int, err error) {
+	for n < len(src) {
+		// TODO: Consider ASCII fast path. Special-casing ASCII handling can
+		// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
+		// not enough to warrant the extra code and complexity.
+		v, size := trie.lookup(src[n:])
+		if size == 0 { // incomplete UTF-8 encoding
+			if !atEOF {
+				err = transform.ErrShortSrc
+			} else {
+				n = len(src)
+			}
+			break
+		}
+		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
+		} else {
+			err = transform.ErrEndOfSpan
+			break
+		}
+		n += size
+	}
+	return n, err
+}
+
+func (wideTransform) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	for nSrc < len(src) {
+		// TODO: Consider ASCII fast path. Special-casing ASCII handling can
+		// reduce the ns/op of BenchmarkWideASCII by about 30%. This is probably
+		// not enough to warrant the extra code and complexity.
+		v, size := trie.lookup(src[nSrc:])
+		if size == 0 { // incomplete UTF-8 encoding
+			if !atEOF {
+				return nDst, nSrc, transform.ErrShortSrc
+			}
+			size = 1 // gobble 1 byte
+		}
+		if k := elem(v).kind(); byte(v) == 0 || k != EastAsianHalfwidth && k != EastAsianNarrow {
+			if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+				return nDst, nSrc, transform.ErrShortDst
+			}
+			nDst += size
+		} else {
+			data := inverseData[byte(v)]
+			if len(dst)-nDst < int(data[0]) {
+				return nDst, nSrc, transform.ErrShortDst
+			}
+			i := 1
+			for end := int(data[0]); i < end; i++ {
+				dst[nDst] = data[i]
+				nDst++
+			}
+			dst[nDst] = data[i] ^ src[nSrc+size-1]
+			nDst++
+		}
+		nSrc += size
+	}
+	return nDst, nSrc, nil
+}
diff --git a/vendor/golang.org/x/text/width/trieval.go b/vendor/golang.org/x/text/width/trieval.go
new file mode 100644
index 000000000..ca8e45fd1
--- /dev/null
+++ b/vendor/golang.org/x/text/width/trieval.go
@@ -0,0 +1,30 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package width
+
+// elem is an entry of the width trie. The high byte is used to encode the type
+// of the rune. The low byte is used to store the index to a mapping entry in
+// the inverseData array.
+type elem uint16
+
+const (
+	tagNeutral elem = iota << typeShift
+	tagAmbiguous
+	tagWide
+	tagNarrow
+	tagFullwidth
+	tagHalfwidth
+)
+
+const (
+	numTypeBits = 3
+	typeShift   = 16 - numTypeBits
+
+	// tagNeedsFold is true for all fullwidth and halfwidth runes except for
+	// the Won sign U+20A9.
+	tagNeedsFold = 0x1000
+
+	// The Korean Won sign is halfwidth, but SHOULD NOT be mapped to a wide
+	// variant.
+	wonSign rune = 0x20A9
+)
diff --git a/vendor/golang.org/x/text/width/width.go b/vendor/golang.org/x/text/width/width.go
new file mode 100644
index 000000000..29c7509be
--- /dev/null
+++ b/vendor/golang.org/x/text/width/width.go
@@ -0,0 +1,206 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate stringer -type=Kind
+//go:generate go run gen.go gen_common.go gen_trieval.go
+
+// Package width provides functionality for handling different widths in text.
+//
+// Wide characters behave like ideographs; they tend to allow line breaks after
+// each character and remain upright in vertical text layout. Narrow characters
+// are kept together in words or runs that are rotated sideways in vertical text
+// layout.
+//
+// For more information, see https://unicode.org/reports/tr11/.
+package width // import "golang.org/x/text/width"
+
+import (
+	"unicode/utf8"
+
+	"golang.org/x/text/transform"
+)
+
+// TODO
+// 1) Reduce table size by compressing blocks.
+// 2) API proposition for computing display length
+//    (approximation, fixed pitch only).
+// 3) Implement display length.
+
+// Kind indicates the type of width property as defined in https://unicode.org/reports/tr11/.
+type Kind int
+
+const (
+	// Neutral characters do not occur in legacy East Asian character sets.
+	Neutral Kind = iota
+
+	// EastAsianAmbiguous characters that can be sometimes wide and sometimes
+	// narrow and require additional information not contained in the character
+	// code to further resolve their width.
+	EastAsianAmbiguous
+
+	// EastAsianWide characters are wide in its usual form. They occur only in
+	// the context of East Asian typography. These runes may have explicit
+	// halfwidth counterparts.
+	EastAsianWide
+
+	// EastAsianNarrow characters are narrow in its usual form. They often have
+	// fullwidth counterparts.
+	EastAsianNarrow
+
+	// Note: there exist Narrow runes that do not have fullwidth or wide
+	// counterparts, despite what the definition says (e.g. U+27E6).
+
+	// EastAsianFullwidth characters have a compatibility decompositions of type
+	// wide that map to a narrow counterpart.
+	EastAsianFullwidth
+
+	// EastAsianHalfwidth characters have a compatibility decomposition of type
+	// narrow that map to a wide or ambiguous counterpart, plus U+20A9 ₩ WON
+	// SIGN.
+	EastAsianHalfwidth
+
+	// Note: there exist runes that have a halfwidth counterparts but that are
+	// classified as Ambiguous, rather than wide (e.g. U+2190).
+)
+
+// TODO: the generated tries need to return size 1 for invalid runes for the
+// width to be computed correctly (each byte should render width 1)
+
+var trie = newWidthTrie(0)
+
+// Lookup reports the Properties of the first rune in b and the number of bytes
+// of its UTF-8 encoding.
+func Lookup(b []byte) (p Properties, size int) {
+	v, sz := trie.lookup(b)
+	return Properties{elem(v), b[sz-1]}, sz
+}
+
+// LookupString reports the Properties of the first rune in s and the number of
+// bytes of its UTF-8 encoding.
+func LookupString(s string) (p Properties, size int) {
+	v, sz := trie.lookupString(s)
+	return Properties{elem(v), s[sz-1]}, sz
+}
+
+// LookupRune reports the Properties of rune r.
+func LookupRune(r rune) Properties {
+	var buf [4]byte
+	n := utf8.EncodeRune(buf[:], r)
+	v, _ := trie.lookup(buf[:n])
+	last := byte(r)
+	if r >= utf8.RuneSelf {
+		last = 0x80 + byte(r&0x3f)
+	}
+	return Properties{elem(v), last}
+}
+
+// Properties provides access to width properties of a rune.
+type Properties struct {
+	elem elem
+	last byte
+}
+
+func (e elem) kind() Kind {
+	return Kind(e >> typeShift)
+}
+
+// Kind returns the Kind of a rune as defined in Unicode TR #11.
+// See https://unicode.org/reports/tr11/ for more details.
+func (p Properties) Kind() Kind {
+	return p.elem.kind()
+}
+
+// Folded returns the folded variant of a rune or 0 if the rune is canonical.
+func (p Properties) Folded() rune {
+	if p.elem&tagNeedsFold != 0 {
+		buf := inverseData[byte(p.elem)]
+		buf[buf[0]] ^= p.last
+		r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
+		return r
+	}
+	return 0
+}
+
+// Narrow returns the narrow variant of a rune or 0 if the rune is already
+// narrow or doesn't have a narrow variant.
+func (p Properties) Narrow() rune {
+	if k := p.elem.kind(); byte(p.elem) != 0 && (k == EastAsianFullwidth || k == EastAsianWide || k == EastAsianAmbiguous) {
+		buf := inverseData[byte(p.elem)]
+		buf[buf[0]] ^= p.last
+		r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
+		return r
+	}
+	return 0
+}
+
+// Wide returns the wide variant of a rune or 0 if the rune is already
+// wide or doesn't have a wide variant.
+func (p Properties) Wide() rune {
+	if k := p.elem.kind(); byte(p.elem) != 0 && (k == EastAsianHalfwidth || k == EastAsianNarrow) {
+		buf := inverseData[byte(p.elem)]
+		buf[buf[0]] ^= p.last
+		r, _ := utf8.DecodeRune(buf[1 : 1+buf[0]])
+		return r
+	}
+	return 0
+}
+
+// TODO for Properties:
+// - Add Fullwidth/Halfwidth or Inverted methods for computing variants
+// mapping.
+// - Add width information (including information on non-spacing runes).
+
+// Transformer implements the transform.Transformer interface.
+type Transformer struct {
+	t transform.SpanningTransformer
+}
+
+// Reset implements the transform.Transformer interface.
+func (t Transformer) Reset() { t.t.Reset() }
+
+// Transform implements the transform.Transformer interface.
+func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+	return t.t.Transform(dst, src, atEOF)
+}
+
+// Span implements the transform.SpanningTransformer interface.
+func (t Transformer) Span(src []byte, atEOF bool) (n int, err error) {
+	return t.t.Span(src, atEOF)
+}
+
+// Bytes returns a new byte slice with the result of applying t to b.
+func (t Transformer) Bytes(b []byte) []byte {
+	b, _, _ = transform.Bytes(t, b)
+	return b
+}
+
+// String returns a string with the result of applying t to s.
+func (t Transformer) String(s string) string {
+	s, _, _ = transform.String(t, s)
+	return s
+}
+
+var (
+	// Fold is a transform that maps all runes to their canonical width.
+	//
+	// Note that the NFKC and NFKD transforms in golang.org/x/text/unicode/norm
+	// provide a more generic folding mechanism.
+	Fold Transformer = Transformer{foldTransform{}}
+
+	// Widen is a transform that maps runes to their wide variant, if
+	// available.
+	Widen Transformer = Transformer{wideTransform{}}
+
+	// Narrow is a transform that maps runes to their narrow variant, if
+	// available.
+	Narrow Transformer = Transformer{narrowTransform{}}
+)
+
+// TODO: Consider the following options:
+// - Treat Ambiguous runes that have a halfwidth counterpart as wide, or some
+//   generalized variant of this.
+// - Consider a wide Won character to be the default width (or some generalized
+//   variant of this).
+// - Filter the set of characters that gets converted (the preferred approach is
+//   to allow applying filters to transforms).
diff --git a/vendor/gopkg.in/yaml.v3/LICENSE b/vendor/gopkg.in/yaml.v3/LICENSE
new file mode 100644
index 000000000..2683e4bb1
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/LICENSE
@@ -0,0 +1,50 @@
+
+This project is covered by two different licenses: MIT and Apache.
+
+#### MIT License ####
+
+The following files were ported to Go from C files of libyaml, and thus
+are still covered by their original MIT license, with the additional
+copyright staring in 2011 when the project was ported over:
+
+    apic.go emitterc.go parserc.go readerc.go scannerc.go
+    writerc.go yamlh.go yamlprivateh.go
+
+Copyright (c) 2006-2010 Kirill Simonov
+Copyright (c) 2006-2011 Kirill Simonov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+### Apache License ###
+
+All the remaining project files are covered by the Apache license:
+
+Copyright (c) 2011-2019 Canonical Ltd
+
+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.
diff --git a/vendor/gopkg.in/yaml.v3/NOTICE b/vendor/gopkg.in/yaml.v3/NOTICE
new file mode 100644
index 000000000..866d74a7a
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/NOTICE
@@ -0,0 +1,13 @@
+Copyright 2011-2016 Canonical Ltd.
+
+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.
diff --git a/vendor/gopkg.in/yaml.v3/README.md b/vendor/gopkg.in/yaml.v3/README.md
new file mode 100644
index 000000000..08eb1babd
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/README.md
@@ -0,0 +1,150 @@
+# YAML support for the Go language
+
+Introduction
+------------
+
+The yaml package enables Go programs to comfortably encode and decode YAML
+values. It was developed within [Canonical](https://www.canonical.com) as
+part of the [juju](https://juju.ubuntu.com) project, and is based on a
+pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
+C library to parse and generate YAML data quickly and reliably.
+
+Compatibility
+-------------
+
+The yaml package supports most of YAML 1.2, but preserves some behavior
+from 1.1 for backwards compatibility.
+
+Specifically, as of v3 of the yaml package:
+
+ - YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being
+   decoded into a typed bool value. Otherwise they behave as a string. Booleans
+   in YAML 1.2 are _true/false_ only.
+ - Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_
+   as specified in YAML 1.2, because most parsers still use the old format.
+   Octals in the  _0o777_ format are supported though, so new files work.
+ - Does not support base-60 floats. These are gone from YAML 1.2, and were
+   actually never supported by this package as it's clearly a poor choice.
+
+and offers backwards
+compatibility with YAML 1.1 in some cases.
+1.2, including support for
+anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
+implemented, and base-60 floats from YAML 1.1 are purposefully not
+supported since they're a poor design and are gone in YAML 1.2.
+
+Installation and usage
+----------------------
+
+The import path for the package is *gopkg.in/yaml.v3*.
+
+To install it, run:
+
+    go get gopkg.in/yaml.v3
+
+API documentation
+-----------------
+
+If opened in a browser, the import path itself leads to the API documentation:
+
+  - [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3)
+
+API stability
+-------------
+
+The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in).
+
+
+License
+-------
+
+The yaml package is licensed under the MIT and Apache License 2.0 licenses.
+Please see the LICENSE file for details.
+
+
+Example
+-------
+
+```Go
+package main
+
+import (
+        "fmt"
+        "log"
+
+        "gopkg.in/yaml.v3"
+)
+
+var data = `
+a: Easy!
+b:
+  c: 2
+  d: [3, 4]
+`
+
+// Note: struct fields must be public in order for unmarshal to
+// correctly populate the data.
+type T struct {
+        A string
+        B struct {
+                RenamedC int   `yaml:"c"`
+                D        []int `yaml:",flow"`
+        }
+}
+
+func main() {
+        t := T{}
+    
+        err := yaml.Unmarshal([]byte(data), &t)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- t:\n%v\n\n", t)
+    
+        d, err := yaml.Marshal(&t)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- t dump:\n%s\n\n", string(d))
+    
+        m := make(map[interface{}]interface{})
+    
+        err = yaml.Unmarshal([]byte(data), &m)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- m:\n%v\n\n", m)
+    
+        d, err = yaml.Marshal(&m)
+        if err != nil {
+                log.Fatalf("error: %v", err)
+        }
+        fmt.Printf("--- m dump:\n%s\n\n", string(d))
+}
+```
+
+This example will generate the following output:
+
+```
+--- t:
+{Easy! {2 [3 4]}}
+
+--- t dump:
+a: Easy!
+b:
+  c: 2
+  d: [3, 4]
+
+
+--- m:
+map[a:Easy! b:map[c:2 d:[3 4]]]
+
+--- m dump:
+a: Easy!
+b:
+  c: 2
+  d:
+  - 3
+  - 4
+```
+
diff --git a/vendor/gopkg.in/yaml.v3/apic.go b/vendor/gopkg.in/yaml.v3/apic.go
new file mode 100644
index 000000000..ae7d049f1
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/apic.go
@@ -0,0 +1,747 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+	"io"
+)
+
+func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
+	//fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
+
+	// Check if we can move the queue at the beginning of the buffer.
+	if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
+		if parser.tokens_head != len(parser.tokens) {
+			copy(parser.tokens, parser.tokens[parser.tokens_head:])
+		}
+		parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
+		parser.tokens_head = 0
+	}
+	parser.tokens = append(parser.tokens, *token)
+	if pos < 0 {
+		return
+	}
+	copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
+	parser.tokens[parser.tokens_head+pos] = *token
+}
+
+// Create a new parser object.
+func yaml_parser_initialize(parser *yaml_parser_t) bool {
+	*parser = yaml_parser_t{
+		raw_buffer: make([]byte, 0, input_raw_buffer_size),
+		buffer:     make([]byte, 0, input_buffer_size),
+	}
+	return true
+}
+
+// Destroy a parser object.
+func yaml_parser_delete(parser *yaml_parser_t) {
+	*parser = yaml_parser_t{}
+}
+
+// String read handler.
+func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
+	if parser.input_pos == len(parser.input) {
+		return 0, io.EOF
+	}
+	n = copy(buffer, parser.input[parser.input_pos:])
+	parser.input_pos += n
+	return n, nil
+}
+
+// Reader read handler.
+func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
+	return parser.input_reader.Read(buffer)
+}
+
+// Set a string input.
+func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
+	if parser.read_handler != nil {
+		panic("must set the input source only once")
+	}
+	parser.read_handler = yaml_string_read_handler
+	parser.input = input
+	parser.input_pos = 0
+}
+
+// Set a file input.
+func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
+	if parser.read_handler != nil {
+		panic("must set the input source only once")
+	}
+	parser.read_handler = yaml_reader_read_handler
+	parser.input_reader = r
+}
+
+// Set the source encoding.
+func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
+	if parser.encoding != yaml_ANY_ENCODING {
+		panic("must set the encoding only once")
+	}
+	parser.encoding = encoding
+}
+
+// Create a new emitter object.
+func yaml_emitter_initialize(emitter *yaml_emitter_t) {
+	*emitter = yaml_emitter_t{
+		buffer:     make([]byte, output_buffer_size),
+		raw_buffer: make([]byte, 0, output_raw_buffer_size),
+		states:     make([]yaml_emitter_state_t, 0, initial_stack_size),
+		events:     make([]yaml_event_t, 0, initial_queue_size),
+		best_width: -1,
+	}
+}
+
+// Destroy an emitter object.
+func yaml_emitter_delete(emitter *yaml_emitter_t) {
+	*emitter = yaml_emitter_t{}
+}
+
+// String write handler.
+func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
+	*emitter.output_buffer = append(*emitter.output_buffer, buffer...)
+	return nil
+}
+
+// yaml_writer_write_handler uses emitter.output_writer to write the
+// emitted text.
+func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
+	_, err := emitter.output_writer.Write(buffer)
+	return err
+}
+
+// Set a string output.
+func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
+	if emitter.write_handler != nil {
+		panic("must set the output target only once")
+	}
+	emitter.write_handler = yaml_string_write_handler
+	emitter.output_buffer = output_buffer
+}
+
+// Set a file output.
+func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
+	if emitter.write_handler != nil {
+		panic("must set the output target only once")
+	}
+	emitter.write_handler = yaml_writer_write_handler
+	emitter.output_writer = w
+}
+
+// Set the output encoding.
+func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
+	if emitter.encoding != yaml_ANY_ENCODING {
+		panic("must set the output encoding only once")
+	}
+	emitter.encoding = encoding
+}
+
+// Set the canonical output style.
+func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
+	emitter.canonical = canonical
+}
+
+// Set the indentation increment.
+func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
+	if indent < 2 || indent > 9 {
+		indent = 2
+	}
+	emitter.best_indent = indent
+}
+
+// Set the preferred line width.
+func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
+	if width < 0 {
+		width = -1
+	}
+	emitter.best_width = width
+}
+
+// Set if unescaped non-ASCII characters are allowed.
+func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
+	emitter.unicode = unicode
+}
+
+// Set the preferred line break character.
+func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
+	emitter.line_break = line_break
+}
+
+///*
+// * Destroy a token object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_token_delete(yaml_token_t *token)
+//{
+//    assert(token);  // Non-NULL token object expected.
+//
+//    switch (token.type)
+//    {
+//        case YAML_TAG_DIRECTIVE_TOKEN:
+//            yaml_free(token.data.tag_directive.handle);
+//            yaml_free(token.data.tag_directive.prefix);
+//            break;
+//
+//        case YAML_ALIAS_TOKEN:
+//            yaml_free(token.data.alias.value);
+//            break;
+//
+//        case YAML_ANCHOR_TOKEN:
+//            yaml_free(token.data.anchor.value);
+//            break;
+//
+//        case YAML_TAG_TOKEN:
+//            yaml_free(token.data.tag.handle);
+//            yaml_free(token.data.tag.suffix);
+//            break;
+//
+//        case YAML_SCALAR_TOKEN:
+//            yaml_free(token.data.scalar.value);
+//            break;
+//
+//        default:
+//            break;
+//    }
+//
+//    memset(token, 0, sizeof(yaml_token_t));
+//}
+//
+///*
+// * Check if a string is a valid UTF-8 sequence.
+// *
+// * Check 'reader.c' for more details on UTF-8 encoding.
+// */
+//
+//static int
+//yaml_check_utf8(yaml_char_t *start, size_t length)
+//{
+//    yaml_char_t *end = start+length;
+//    yaml_char_t *pointer = start;
+//
+//    while (pointer < end) {
+//        unsigned char octet;
+//        unsigned int width;
+//        unsigned int value;
+//        size_t k;
+//
+//        octet = pointer[0];
+//        width = (octet & 0x80) == 0x00 ? 1 :
+//                (octet & 0xE0) == 0xC0 ? 2 :
+//                (octet & 0xF0) == 0xE0 ? 3 :
+//                (octet & 0xF8) == 0xF0 ? 4 : 0;
+//        value = (octet & 0x80) == 0x00 ? octet & 0x7F :
+//                (octet & 0xE0) == 0xC0 ? octet & 0x1F :
+//                (octet & 0xF0) == 0xE0 ? octet & 0x0F :
+//                (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
+//        if (!width) return 0;
+//        if (pointer+width > end) return 0;
+//        for (k = 1; k < width; k ++) {
+//            octet = pointer[k];
+//            if ((octet & 0xC0) != 0x80) return 0;
+//            value = (value << 6) + (octet & 0x3F);
+//        }
+//        if (!((width == 1) ||
+//            (width == 2 && value >= 0x80) ||
+//            (width == 3 && value >= 0x800) ||
+//            (width == 4 && value >= 0x10000))) return 0;
+//
+//        pointer += width;
+//    }
+//
+//    return 1;
+//}
+//
+
+// Create STREAM-START.
+func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
+	*event = yaml_event_t{
+		typ:      yaml_STREAM_START_EVENT,
+		encoding: encoding,
+	}
+}
+
+// Create STREAM-END.
+func yaml_stream_end_event_initialize(event *yaml_event_t) {
+	*event = yaml_event_t{
+		typ: yaml_STREAM_END_EVENT,
+	}
+}
+
+// Create DOCUMENT-START.
+func yaml_document_start_event_initialize(
+	event *yaml_event_t,
+	version_directive *yaml_version_directive_t,
+	tag_directives []yaml_tag_directive_t,
+	implicit bool,
+) {
+	*event = yaml_event_t{
+		typ:               yaml_DOCUMENT_START_EVENT,
+		version_directive: version_directive,
+		tag_directives:    tag_directives,
+		implicit:          implicit,
+	}
+}
+
+// Create DOCUMENT-END.
+func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
+	*event = yaml_event_t{
+		typ:      yaml_DOCUMENT_END_EVENT,
+		implicit: implicit,
+	}
+}
+
+// Create ALIAS.
+func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) bool {
+	*event = yaml_event_t{
+		typ:    yaml_ALIAS_EVENT,
+		anchor: anchor,
+	}
+	return true
+}
+
+// Create SCALAR.
+func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
+	*event = yaml_event_t{
+		typ:             yaml_SCALAR_EVENT,
+		anchor:          anchor,
+		tag:             tag,
+		value:           value,
+		implicit:        plain_implicit,
+		quoted_implicit: quoted_implicit,
+		style:           yaml_style_t(style),
+	}
+	return true
+}
+
+// Create SEQUENCE-START.
+func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
+	*event = yaml_event_t{
+		typ:      yaml_SEQUENCE_START_EVENT,
+		anchor:   anchor,
+		tag:      tag,
+		implicit: implicit,
+		style:    yaml_style_t(style),
+	}
+	return true
+}
+
+// Create SEQUENCE-END.
+func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
+	*event = yaml_event_t{
+		typ: yaml_SEQUENCE_END_EVENT,
+	}
+	return true
+}
+
+// Create MAPPING-START.
+func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
+	*event = yaml_event_t{
+		typ:      yaml_MAPPING_START_EVENT,
+		anchor:   anchor,
+		tag:      tag,
+		implicit: implicit,
+		style:    yaml_style_t(style),
+	}
+}
+
+// Create MAPPING-END.
+func yaml_mapping_end_event_initialize(event *yaml_event_t) {
+	*event = yaml_event_t{
+		typ: yaml_MAPPING_END_EVENT,
+	}
+}
+
+// Destroy an event object.
+func yaml_event_delete(event *yaml_event_t) {
+	*event = yaml_event_t{}
+}
+
+///*
+// * Create a document object.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_initialize(document *yaml_document_t,
+//        version_directive *yaml_version_directive_t,
+//        tag_directives_start *yaml_tag_directive_t,
+//        tag_directives_end *yaml_tag_directive_t,
+//        start_implicit int, end_implicit int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    struct {
+//        start *yaml_node_t
+//        end *yaml_node_t
+//        top *yaml_node_t
+//    } nodes = { NULL, NULL, NULL }
+//    version_directive_copy *yaml_version_directive_t = NULL
+//    struct {
+//        start *yaml_tag_directive_t
+//        end *yaml_tag_directive_t
+//        top *yaml_tag_directive_t
+//    } tag_directives_copy = { NULL, NULL, NULL }
+//    value yaml_tag_directive_t = { NULL, NULL }
+//    mark yaml_mark_t = { 0, 0, 0 }
+//
+//    assert(document) // Non-NULL document object is expected.
+//    assert((tag_directives_start && tag_directives_end) ||
+//            (tag_directives_start == tag_directives_end))
+//                            // Valid tag directives are expected.
+//
+//    if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
+//
+//    if (version_directive) {
+//        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
+//        if (!version_directive_copy) goto error
+//        version_directive_copy.major = version_directive.major
+//        version_directive_copy.minor = version_directive.minor
+//    }
+//
+//    if (tag_directives_start != tag_directives_end) {
+//        tag_directive *yaml_tag_directive_t
+//        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
+//            goto error
+//        for (tag_directive = tag_directives_start
+//                tag_directive != tag_directives_end; tag_directive ++) {
+//            assert(tag_directive.handle)
+//            assert(tag_directive.prefix)
+//            if (!yaml_check_utf8(tag_directive.handle,
+//                        strlen((char *)tag_directive.handle)))
+//                goto error
+//            if (!yaml_check_utf8(tag_directive.prefix,
+//                        strlen((char *)tag_directive.prefix)))
+//                goto error
+//            value.handle = yaml_strdup(tag_directive.handle)
+//            value.prefix = yaml_strdup(tag_directive.prefix)
+//            if (!value.handle || !value.prefix) goto error
+//            if (!PUSH(&context, tag_directives_copy, value))
+//                goto error
+//            value.handle = NULL
+//            value.prefix = NULL
+//        }
+//    }
+//
+//    DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
+//            tag_directives_copy.start, tag_directives_copy.top,
+//            start_implicit, end_implicit, mark, mark)
+//
+//    return 1
+//
+//error:
+//    STACK_DEL(&context, nodes)
+//    yaml_free(version_directive_copy)
+//    while (!STACK_EMPTY(&context, tag_directives_copy)) {
+//        value yaml_tag_directive_t = POP(&context, tag_directives_copy)
+//        yaml_free(value.handle)
+//        yaml_free(value.prefix)
+//    }
+//    STACK_DEL(&context, tag_directives_copy)
+//    yaml_free(value.handle)
+//    yaml_free(value.prefix)
+//
+//    return 0
+//}
+//
+///*
+// * Destroy a document object.
+// */
+//
+//YAML_DECLARE(void)
+//yaml_document_delete(document *yaml_document_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    tag_directive *yaml_tag_directive_t
+//
+//    context.error = YAML_NO_ERROR // Eliminate a compiler warning.
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    while (!STACK_EMPTY(&context, document.nodes)) {
+//        node yaml_node_t = POP(&context, document.nodes)
+//        yaml_free(node.tag)
+//        switch (node.type) {
+//            case YAML_SCALAR_NODE:
+//                yaml_free(node.data.scalar.value)
+//                break
+//            case YAML_SEQUENCE_NODE:
+//                STACK_DEL(&context, node.data.sequence.items)
+//                break
+//            case YAML_MAPPING_NODE:
+//                STACK_DEL(&context, node.data.mapping.pairs)
+//                break
+//            default:
+//                assert(0) // Should not happen.
+//        }
+//    }
+//    STACK_DEL(&context, document.nodes)
+//
+//    yaml_free(document.version_directive)
+//    for (tag_directive = document.tag_directives.start
+//            tag_directive != document.tag_directives.end
+//            tag_directive++) {
+//        yaml_free(tag_directive.handle)
+//        yaml_free(tag_directive.prefix)
+//    }
+//    yaml_free(document.tag_directives.start)
+//
+//    memset(document, 0, sizeof(yaml_document_t))
+//}
+//
+///**
+// * Get a document node.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_node(document *yaml_document_t, index int)
+//{
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (index > 0 && document.nodes.start + index <= document.nodes.top) {
+//        return document.nodes.start + index - 1
+//    }
+//    return NULL
+//}
+//
+///**
+// * Get the root object.
+// */
+//
+//YAML_DECLARE(yaml_node_t *)
+//yaml_document_get_root_node(document *yaml_document_t)
+//{
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (document.nodes.top != document.nodes.start) {
+//        return document.nodes.start
+//    }
+//    return NULL
+//}
+//
+///*
+// * Add a scalar node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_scalar(document *yaml_document_t,
+//        tag *yaml_char_t, value *yaml_char_t, length int,
+//        style yaml_scalar_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    value_copy *yaml_char_t = NULL
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//    assert(value) // Non-NULL value is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (length < 0) {
+//        length = strlen((char *)value)
+//    }
+//
+//    if (!yaml_check_utf8(value, length)) goto error
+//    value_copy = yaml_malloc(length+1)
+//    if (!value_copy) goto error
+//    memcpy(value_copy, value, length)
+//    value_copy[length] = '\0'
+//
+//    SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    yaml_free(tag_copy)
+//    yaml_free(value_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Add a sequence node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_sequence(document *yaml_document_t,
+//        tag *yaml_char_t, style yaml_sequence_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    struct {
+//        start *yaml_node_item_t
+//        end *yaml_node_item_t
+//        top *yaml_node_item_t
+//    } items = { NULL, NULL, NULL }
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
+//
+//    SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
+//            style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    STACK_DEL(&context, items)
+//    yaml_free(tag_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Add a mapping node to a document.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_add_mapping(document *yaml_document_t,
+//        tag *yaml_char_t, style yaml_mapping_style_t)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//    mark yaml_mark_t = { 0, 0, 0 }
+//    tag_copy *yaml_char_t = NULL
+//    struct {
+//        start *yaml_node_pair_t
+//        end *yaml_node_pair_t
+//        top *yaml_node_pair_t
+//    } pairs = { NULL, NULL, NULL }
+//    node yaml_node_t
+//
+//    assert(document) // Non-NULL document object is expected.
+//
+//    if (!tag) {
+//        tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
+//    }
+//
+//    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
+//    tag_copy = yaml_strdup(tag)
+//    if (!tag_copy) goto error
+//
+//    if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
+//
+//    MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
+//            style, mark, mark)
+//    if (!PUSH(&context, document.nodes, node)) goto error
+//
+//    return document.nodes.top - document.nodes.start
+//
+//error:
+//    STACK_DEL(&context, pairs)
+//    yaml_free(tag_copy)
+//
+//    return 0
+//}
+//
+///*
+// * Append an item to a sequence node.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_sequence_item(document *yaml_document_t,
+//        sequence int, item int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//
+//    assert(document) // Non-NULL document is required.
+//    assert(sequence > 0
+//            && document.nodes.start + sequence <= document.nodes.top)
+//                            // Valid sequence id is required.
+//    assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
+//                            // A sequence node is required.
+//    assert(item > 0 && document.nodes.start + item <= document.nodes.top)
+//                            // Valid item id is required.
+//
+//    if (!PUSH(&context,
+//                document.nodes.start[sequence-1].data.sequence.items, item))
+//        return 0
+//
+//    return 1
+//}
+//
+///*
+// * Append a pair of a key and a value to a mapping node.
+// */
+//
+//YAML_DECLARE(int)
+//yaml_document_append_mapping_pair(document *yaml_document_t,
+//        mapping int, key int, value int)
+//{
+//    struct {
+//        error yaml_error_type_t
+//    } context
+//
+//    pair yaml_node_pair_t
+//
+//    assert(document) // Non-NULL document is required.
+//    assert(mapping > 0
+//            && document.nodes.start + mapping <= document.nodes.top)
+//                            // Valid mapping id is required.
+//    assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
+//                            // A mapping node is required.
+//    assert(key > 0 && document.nodes.start + key <= document.nodes.top)
+//                            // Valid key id is required.
+//    assert(value > 0 && document.nodes.start + value <= document.nodes.top)
+//                            // Valid value id is required.
+//
+//    pair.key = key
+//    pair.value = value
+//
+//    if (!PUSH(&context,
+//                document.nodes.start[mapping-1].data.mapping.pairs, pair))
+//        return 0
+//
+//    return 1
+//}
+//
+//
diff --git a/vendor/gopkg.in/yaml.v3/decode.go b/vendor/gopkg.in/yaml.v3/decode.go
new file mode 100644
index 000000000..0173b6982
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/decode.go
@@ -0,0 +1,1000 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// 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 yaml
+
+import (
+	"encoding"
+	"encoding/base64"
+	"fmt"
+	"io"
+	"math"
+	"reflect"
+	"strconv"
+	"time"
+)
+
+// ----------------------------------------------------------------------------
+// Parser, produces a node tree out of a libyaml event stream.
+
+type parser struct {
+	parser   yaml_parser_t
+	event    yaml_event_t
+	doc      *Node
+	anchors  map[string]*Node
+	doneInit bool
+	textless bool
+}
+
+func newParser(b []byte) *parser {
+	p := parser{}
+	if !yaml_parser_initialize(&p.parser) {
+		panic("failed to initialize YAML emitter")
+	}
+	if len(b) == 0 {
+		b = []byte{'\n'}
+	}
+	yaml_parser_set_input_string(&p.parser, b)
+	return &p
+}
+
+func newParserFromReader(r io.Reader) *parser {
+	p := parser{}
+	if !yaml_parser_initialize(&p.parser) {
+		panic("failed to initialize YAML emitter")
+	}
+	yaml_parser_set_input_reader(&p.parser, r)
+	return &p
+}
+
+func (p *parser) init() {
+	if p.doneInit {
+		return
+	}
+	p.anchors = make(map[string]*Node)
+	p.expect(yaml_STREAM_START_EVENT)
+	p.doneInit = true
+}
+
+func (p *parser) destroy() {
+	if p.event.typ != yaml_NO_EVENT {
+		yaml_event_delete(&p.event)
+	}
+	yaml_parser_delete(&p.parser)
+}
+
+// expect consumes an event from the event stream and
+// checks that it's of the expected type.
+func (p *parser) expect(e yaml_event_type_t) {
+	if p.event.typ == yaml_NO_EVENT {
+		if !yaml_parser_parse(&p.parser, &p.event) {
+			p.fail()
+		}
+	}
+	if p.event.typ == yaml_STREAM_END_EVENT {
+		failf("attempted to go past the end of stream; corrupted value?")
+	}
+	if p.event.typ != e {
+		p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
+		p.fail()
+	}
+	yaml_event_delete(&p.event)
+	p.event.typ = yaml_NO_EVENT
+}
+
+// peek peeks at the next event in the event stream,
+// puts the results into p.event and returns the event type.
+func (p *parser) peek() yaml_event_type_t {
+	if p.event.typ != yaml_NO_EVENT {
+		return p.event.typ
+	}
+	// It's curious choice from the underlying API to generally return a
+	// positive result on success, but on this case return true in an error
+	// scenario. This was the source of bugs in the past (issue #666).
+	if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {
+		p.fail()
+	}
+	return p.event.typ
+}
+
+func (p *parser) fail() {
+	var where string
+	var line int
+	if p.parser.context_mark.line != 0 {
+		line = p.parser.context_mark.line
+		// Scanner errors don't iterate line before returning error
+		if p.parser.error == yaml_SCANNER_ERROR {
+			line++
+		}
+	} else if p.parser.problem_mark.line != 0 {
+		line = p.parser.problem_mark.line
+		// Scanner errors don't iterate line before returning error
+		if p.parser.error == yaml_SCANNER_ERROR {
+			line++
+		}
+	}
+	if line != 0 {
+		where = "line " + strconv.Itoa(line) + ": "
+	}
+	var msg string
+	if len(p.parser.problem) > 0 {
+		msg = p.parser.problem
+	} else {
+		msg = "unknown problem parsing YAML content"
+	}
+	failf("%s%s", where, msg)
+}
+
+func (p *parser) anchor(n *Node, anchor []byte) {
+	if anchor != nil {
+		n.Anchor = string(anchor)
+		p.anchors[n.Anchor] = n
+	}
+}
+
+func (p *parser) parse() *Node {
+	p.init()
+	switch p.peek() {
+	case yaml_SCALAR_EVENT:
+		return p.scalar()
+	case yaml_ALIAS_EVENT:
+		return p.alias()
+	case yaml_MAPPING_START_EVENT:
+		return p.mapping()
+	case yaml_SEQUENCE_START_EVENT:
+		return p.sequence()
+	case yaml_DOCUMENT_START_EVENT:
+		return p.document()
+	case yaml_STREAM_END_EVENT:
+		// Happens when attempting to decode an empty buffer.
+		return nil
+	case yaml_TAIL_COMMENT_EVENT:
+		panic("internal error: unexpected tail comment event (please report)")
+	default:
+		panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())
+	}
+}
+
+func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
+	var style Style
+	if tag != "" && tag != "!" {
+		tag = shortTag(tag)
+		style = TaggedStyle
+	} else if defaultTag != "" {
+		tag = defaultTag
+	} else if kind == ScalarNode {
+		tag, _ = resolve("", value)
+	}
+	n := &Node{
+		Kind:  kind,
+		Tag:   tag,
+		Value: value,
+		Style: style,
+	}
+	if !p.textless {
+		n.Line = p.event.start_mark.line + 1
+		n.Column = p.event.start_mark.column + 1
+		n.HeadComment = string(p.event.head_comment)
+		n.LineComment = string(p.event.line_comment)
+		n.FootComment = string(p.event.foot_comment)
+	}
+	return n
+}
+
+func (p *parser) parseChild(parent *Node) *Node {
+	child := p.parse()
+	parent.Content = append(parent.Content, child)
+	return child
+}
+
+func (p *parser) document() *Node {
+	n := p.node(DocumentNode, "", "", "")
+	p.doc = n
+	p.expect(yaml_DOCUMENT_START_EVENT)
+	p.parseChild(n)
+	if p.peek() == yaml_DOCUMENT_END_EVENT {
+		n.FootComment = string(p.event.foot_comment)
+	}
+	p.expect(yaml_DOCUMENT_END_EVENT)
+	return n
+}
+
+func (p *parser) alias() *Node {
+	n := p.node(AliasNode, "", "", string(p.event.anchor))
+	n.Alias = p.anchors[n.Value]
+	if n.Alias == nil {
+		failf("unknown anchor '%s' referenced", n.Value)
+	}
+	p.expect(yaml_ALIAS_EVENT)
+	return n
+}
+
+func (p *parser) scalar() *Node {
+	var parsedStyle = p.event.scalar_style()
+	var nodeStyle Style
+	switch {
+	case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
+		nodeStyle = DoubleQuotedStyle
+	case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
+		nodeStyle = SingleQuotedStyle
+	case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:
+		nodeStyle = LiteralStyle
+	case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:
+		nodeStyle = FoldedStyle
+	}
+	var nodeValue = string(p.event.value)
+	var nodeTag = string(p.event.tag)
+	var defaultTag string
+	if nodeStyle == 0 {
+		if nodeValue == "<<" {
+			defaultTag = mergeTag
+		}
+	} else {
+		defaultTag = strTag
+	}
+	n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)
+	n.Style |= nodeStyle
+	p.anchor(n, p.event.anchor)
+	p.expect(yaml_SCALAR_EVENT)
+	return n
+}
+
+func (p *parser) sequence() *Node {
+	n := p.node(SequenceNode, seqTag, string(p.event.tag), "")
+	if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
+		n.Style |= FlowStyle
+	}
+	p.anchor(n, p.event.anchor)
+	p.expect(yaml_SEQUENCE_START_EVENT)
+	for p.peek() != yaml_SEQUENCE_END_EVENT {
+		p.parseChild(n)
+	}
+	n.LineComment = string(p.event.line_comment)
+	n.FootComment = string(p.event.foot_comment)
+	p.expect(yaml_SEQUENCE_END_EVENT)
+	return n
+}
+
+func (p *parser) mapping() *Node {
+	n := p.node(MappingNode, mapTag, string(p.event.tag), "")
+	block := true
+	if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
+		block = false
+		n.Style |= FlowStyle
+	}
+	p.anchor(n, p.event.anchor)
+	p.expect(yaml_MAPPING_START_EVENT)
+	for p.peek() != yaml_MAPPING_END_EVENT {
+		k := p.parseChild(n)
+		if block && k.FootComment != "" {
+			// Must be a foot comment for the prior value when being dedented.
+			if len(n.Content) > 2 {
+				n.Content[len(n.Content)-3].FootComment = k.FootComment
+				k.FootComment = ""
+			}
+		}
+		v := p.parseChild(n)
+		if k.FootComment == "" && v.FootComment != "" {
+			k.FootComment = v.FootComment
+			v.FootComment = ""
+		}
+		if p.peek() == yaml_TAIL_COMMENT_EVENT {
+			if k.FootComment == "" {
+				k.FootComment = string(p.event.foot_comment)
+			}
+			p.expect(yaml_TAIL_COMMENT_EVENT)
+		}
+	}
+	n.LineComment = string(p.event.line_comment)
+	n.FootComment = string(p.event.foot_comment)
+	if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {
+		n.Content[len(n.Content)-2].FootComment = n.FootComment
+		n.FootComment = ""
+	}
+	p.expect(yaml_MAPPING_END_EVENT)
+	return n
+}
+
+// ----------------------------------------------------------------------------
+// Decoder, unmarshals a node into a provided value.
+
+type decoder struct {
+	doc     *Node
+	aliases map[*Node]bool
+	terrors []string
+
+	stringMapType  reflect.Type
+	generalMapType reflect.Type
+
+	knownFields bool
+	uniqueKeys  bool
+	decodeCount int
+	aliasCount  int
+	aliasDepth  int
+
+	mergedFields map[interface{}]bool
+}
+
+var (
+	nodeType       = reflect.TypeOf(Node{})
+	durationType   = reflect.TypeOf(time.Duration(0))
+	stringMapType  = reflect.TypeOf(map[string]interface{}{})
+	generalMapType = reflect.TypeOf(map[interface{}]interface{}{})
+	ifaceType      = generalMapType.Elem()
+	timeType       = reflect.TypeOf(time.Time{})
+	ptrTimeType    = reflect.TypeOf(&time.Time{})
+)
+
+func newDecoder() *decoder {
+	d := &decoder{
+		stringMapType:  stringMapType,
+		generalMapType: generalMapType,
+		uniqueKeys:     true,
+	}
+	d.aliases = make(map[*Node]bool)
+	return d
+}
+
+func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
+	if n.Tag != "" {
+		tag = n.Tag
+	}
+	value := n.Value
+	if tag != seqTag && tag != mapTag {
+		if len(value) > 10 {
+			value = " `" + value[:7] + "...`"
+		} else {
+			value = " `" + value + "`"
+		}
+	}
+	d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))
+}
+
+func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
+	err := u.UnmarshalYAML(n)
+	if e, ok := err.(*TypeError); ok {
+		d.terrors = append(d.terrors, e.Errors...)
+		return false
+	}
+	if err != nil {
+		fail(err)
+	}
+	return true
+}
+
+func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {
+	terrlen := len(d.terrors)
+	err := u.UnmarshalYAML(func(v interface{}) (err error) {
+		defer handleErr(&err)
+		d.unmarshal(n, reflect.ValueOf(v))
+		if len(d.terrors) > terrlen {
+			issues := d.terrors[terrlen:]
+			d.terrors = d.terrors[:terrlen]
+			return &TypeError{issues}
+		}
+		return nil
+	})
+	if e, ok := err.(*TypeError); ok {
+		d.terrors = append(d.terrors, e.Errors...)
+		return false
+	}
+	if err != nil {
+		fail(err)
+	}
+	return true
+}
+
+// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
+// if a value is found to implement it.
+// It returns the initialized and dereferenced out value, whether
+// unmarshalling was already done by UnmarshalYAML, and if so whether
+// its types unmarshalled appropriately.
+//
+// If n holds a null value, prepare returns before doing anything.
+func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
+	if n.ShortTag() == nullTag {
+		return out, false, false
+	}
+	again := true
+	for again {
+		again = false
+		if out.Kind() == reflect.Ptr {
+			if out.IsNil() {
+				out.Set(reflect.New(out.Type().Elem()))
+			}
+			out = out.Elem()
+			again = true
+		}
+		if out.CanAddr() {
+			outi := out.Addr().Interface()
+			if u, ok := outi.(Unmarshaler); ok {
+				good = d.callUnmarshaler(n, u)
+				return out, true, good
+			}
+			if u, ok := outi.(obsoleteUnmarshaler); ok {
+				good = d.callObsoleteUnmarshaler(n, u)
+				return out, true, good
+			}
+		}
+	}
+	return out, false, false
+}
+
+func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {
+	if n.ShortTag() == nullTag {
+		return reflect.Value{}
+	}
+	for _, num := range index {
+		for {
+			if v.Kind() == reflect.Ptr {
+				if v.IsNil() {
+					v.Set(reflect.New(v.Type().Elem()))
+				}
+				v = v.Elem()
+				continue
+			}
+			break
+		}
+		v = v.Field(num)
+	}
+	return v
+}
+
+const (
+	// 400,000 decode operations is ~500kb of dense object declarations, or
+	// ~5kb of dense object declarations with 10000% alias expansion
+	alias_ratio_range_low = 400000
+
+	// 4,000,000 decode operations is ~5MB of dense object declarations, or
+	// ~4.5MB of dense object declarations with 10% alias expansion
+	alias_ratio_range_high = 4000000
+
+	// alias_ratio_range is the range over which we scale allowed alias ratios
+	alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
+)
+
+func allowedAliasRatio(decodeCount int) float64 {
+	switch {
+	case decodeCount <= alias_ratio_range_low:
+		// allow 99% to come from alias expansion for small-to-medium documents
+		return 0.99
+	case decodeCount >= alias_ratio_range_high:
+		// allow 10% to come from alias expansion for very large documents
+		return 0.10
+	default:
+		// scale smoothly from 99% down to 10% over the range.
+		// this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
+		// 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
+		return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
+	}
+}
+
+func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
+	d.decodeCount++
+	if d.aliasDepth > 0 {
+		d.aliasCount++
+	}
+	if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
+		failf("document contains excessive aliasing")
+	}
+	if out.Type() == nodeType {
+		out.Set(reflect.ValueOf(n).Elem())
+		return true
+	}
+	switch n.Kind {
+	case DocumentNode:
+		return d.document(n, out)
+	case AliasNode:
+		return d.alias(n, out)
+	}
+	out, unmarshaled, good := d.prepare(n, out)
+	if unmarshaled {
+		return good
+	}
+	switch n.Kind {
+	case ScalarNode:
+		good = d.scalar(n, out)
+	case MappingNode:
+		good = d.mapping(n, out)
+	case SequenceNode:
+		good = d.sequence(n, out)
+	case 0:
+		if n.IsZero() {
+			return d.null(out)
+		}
+		fallthrough
+	default:
+		failf("cannot decode node with unknown kind %d", n.Kind)
+	}
+	return good
+}
+
+func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
+	if len(n.Content) == 1 {
+		d.doc = n
+		d.unmarshal(n.Content[0], out)
+		return true
+	}
+	return false
+}
+
+func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
+	if d.aliases[n] {
+		// TODO this could actually be allowed in some circumstances.
+		failf("anchor '%s' value contains itself", n.Value)
+	}
+	d.aliases[n] = true
+	d.aliasDepth++
+	good = d.unmarshal(n.Alias, out)
+	d.aliasDepth--
+	delete(d.aliases, n)
+	return good
+}
+
+var zeroValue reflect.Value
+
+func resetMap(out reflect.Value) {
+	for _, k := range out.MapKeys() {
+		out.SetMapIndex(k, zeroValue)
+	}
+}
+
+func (d *decoder) null(out reflect.Value) bool {
+	if out.CanAddr() {
+		switch out.Kind() {
+		case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
+			out.Set(reflect.Zero(out.Type()))
+			return true
+		}
+	}
+	return false
+}
+
+func (d *decoder) scalar(n *Node, out reflect.Value) bool {
+	var tag string
+	var resolved interface{}
+	if n.indicatedString() {
+		tag = strTag
+		resolved = n.Value
+	} else {
+		tag, resolved = resolve(n.Tag, n.Value)
+		if tag == binaryTag {
+			data, err := base64.StdEncoding.DecodeString(resolved.(string))
+			if err != nil {
+				failf("!!binary value contains invalid base64 data")
+			}
+			resolved = string(data)
+		}
+	}
+	if resolved == nil {
+		return d.null(out)
+	}
+	if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
+		// We've resolved to exactly the type we want, so use that.
+		out.Set(resolvedv)
+		return true
+	}
+	// Perhaps we can use the value as a TextUnmarshaler to
+	// set its value.
+	if out.CanAddr() {
+		u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
+		if ok {
+			var text []byte
+			if tag == binaryTag {
+				text = []byte(resolved.(string))
+			} else {
+				// We let any value be unmarshaled into TextUnmarshaler.
+				// That might be more lax than we'd like, but the
+				// TextUnmarshaler itself should bowl out any dubious values.
+				text = []byte(n.Value)
+			}
+			err := u.UnmarshalText(text)
+			if err != nil {
+				fail(err)
+			}
+			return true
+		}
+	}
+	switch out.Kind() {
+	case reflect.String:
+		if tag == binaryTag {
+			out.SetString(resolved.(string))
+			return true
+		}
+		out.SetString(n.Value)
+		return true
+	case reflect.Interface:
+		out.Set(reflect.ValueOf(resolved))
+		return true
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		// This used to work in v2, but it's very unfriendly.
+		isDuration := out.Type() == durationType
+
+		switch resolved := resolved.(type) {
+		case int:
+			if !isDuration && !out.OverflowInt(int64(resolved)) {
+				out.SetInt(int64(resolved))
+				return true
+			}
+		case int64:
+			if !isDuration && !out.OverflowInt(resolved) {
+				out.SetInt(resolved)
+				return true
+			}
+		case uint64:
+			if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+				out.SetInt(int64(resolved))
+				return true
+			}
+		case float64:
+			if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+				out.SetInt(int64(resolved))
+				return true
+			}
+		case string:
+			if out.Type() == durationType {
+				d, err := time.ParseDuration(resolved)
+				if err == nil {
+					out.SetInt(int64(d))
+					return true
+				}
+			}
+		}
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		switch resolved := resolved.(type) {
+		case int:
+			if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				return true
+			}
+		case int64:
+			if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				return true
+			}
+		case uint64:
+			if !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				return true
+			}
+		case float64:
+			if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				return true
+			}
+		}
+	case reflect.Bool:
+		switch resolved := resolved.(type) {
+		case bool:
+			out.SetBool(resolved)
+			return true
+		case string:
+			// This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).
+			// It only works if explicitly attempting to unmarshal into a typed bool value.
+			switch resolved {
+			case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
+				out.SetBool(true)
+				return true
+			case "n", "N", "no", "No", "NO", "off", "Off", "OFF":
+				out.SetBool(false)
+				return true
+			}
+		}
+	case reflect.Float32, reflect.Float64:
+		switch resolved := resolved.(type) {
+		case int:
+			out.SetFloat(float64(resolved))
+			return true
+		case int64:
+			out.SetFloat(float64(resolved))
+			return true
+		case uint64:
+			out.SetFloat(float64(resolved))
+			return true
+		case float64:
+			out.SetFloat(resolved)
+			return true
+		}
+	case reflect.Struct:
+		if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
+			out.Set(resolvedv)
+			return true
+		}
+	case reflect.Ptr:
+		panic("yaml internal error: please report the issue")
+	}
+	d.terror(n, tag, out)
+	return false
+}
+
+func settableValueOf(i interface{}) reflect.Value {
+	v := reflect.ValueOf(i)
+	sv := reflect.New(v.Type()).Elem()
+	sv.Set(v)
+	return sv
+}
+
+func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
+	l := len(n.Content)
+
+	var iface reflect.Value
+	switch out.Kind() {
+	case reflect.Slice:
+		out.Set(reflect.MakeSlice(out.Type(), l, l))
+	case reflect.Array:
+		if l != out.Len() {
+			failf("invalid array: want %d elements but got %d", out.Len(), l)
+		}
+	case reflect.Interface:
+		// No type hints. Will have to use a generic sequence.
+		iface = out
+		out = settableValueOf(make([]interface{}, l))
+	default:
+		d.terror(n, seqTag, out)
+		return false
+	}
+	et := out.Type().Elem()
+
+	j := 0
+	for i := 0; i < l; i++ {
+		e := reflect.New(et).Elem()
+		if ok := d.unmarshal(n.Content[i], e); ok {
+			out.Index(j).Set(e)
+			j++
+		}
+	}
+	if out.Kind() != reflect.Array {
+		out.Set(out.Slice(0, j))
+	}
+	if iface.IsValid() {
+		iface.Set(out)
+	}
+	return true
+}
+
+func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
+	l := len(n.Content)
+	if d.uniqueKeys {
+		nerrs := len(d.terrors)
+		for i := 0; i < l; i += 2 {
+			ni := n.Content[i]
+			for j := i + 2; j < l; j += 2 {
+				nj := n.Content[j]
+				if ni.Kind == nj.Kind && ni.Value == nj.Value {
+					d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
+				}
+			}
+		}
+		if len(d.terrors) > nerrs {
+			return false
+		}
+	}
+	switch out.Kind() {
+	case reflect.Struct:
+		return d.mappingStruct(n, out)
+	case reflect.Map:
+		// okay
+	case reflect.Interface:
+		iface := out
+		if isStringMap(n) {
+			out = reflect.MakeMap(d.stringMapType)
+		} else {
+			out = reflect.MakeMap(d.generalMapType)
+		}
+		iface.Set(out)
+	default:
+		d.terror(n, mapTag, out)
+		return false
+	}
+
+	outt := out.Type()
+	kt := outt.Key()
+	et := outt.Elem()
+
+	stringMapType := d.stringMapType
+	generalMapType := d.generalMapType
+	if outt.Elem() == ifaceType {
+		if outt.Key().Kind() == reflect.String {
+			d.stringMapType = outt
+		} else if outt.Key() == ifaceType {
+			d.generalMapType = outt
+		}
+	}
+
+	mergedFields := d.mergedFields
+	d.mergedFields = nil
+
+	var mergeNode *Node
+
+	mapIsNew := false
+	if out.IsNil() {
+		out.Set(reflect.MakeMap(outt))
+		mapIsNew = true
+	}
+	for i := 0; i < l; i += 2 {
+		if isMerge(n.Content[i]) {
+			mergeNode = n.Content[i+1]
+			continue
+		}
+		k := reflect.New(kt).Elem()
+		if d.unmarshal(n.Content[i], k) {
+			if mergedFields != nil {
+				ki := k.Interface()
+				if mergedFields[ki] {
+					continue
+				}
+				mergedFields[ki] = true
+			}
+			kkind := k.Kind()
+			if kkind == reflect.Interface {
+				kkind = k.Elem().Kind()
+			}
+			if kkind == reflect.Map || kkind == reflect.Slice {
+				failf("invalid map key: %#v", k.Interface())
+			}
+			e := reflect.New(et).Elem()
+			if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) {
+				out.SetMapIndex(k, e)
+			}
+		}
+	}
+
+	d.mergedFields = mergedFields
+	if mergeNode != nil {
+		d.merge(n, mergeNode, out)
+	}
+
+	d.stringMapType = stringMapType
+	d.generalMapType = generalMapType
+	return true
+}
+
+func isStringMap(n *Node) bool {
+	if n.Kind != MappingNode {
+		return false
+	}
+	l := len(n.Content)
+	for i := 0; i < l; i += 2 {
+		shortTag := n.Content[i].ShortTag()
+		if shortTag != strTag && shortTag != mergeTag {
+			return false
+		}
+	}
+	return true
+}
+
+func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
+	sinfo, err := getStructInfo(out.Type())
+	if err != nil {
+		panic(err)
+	}
+
+	var inlineMap reflect.Value
+	var elemType reflect.Type
+	if sinfo.InlineMap != -1 {
+		inlineMap = out.Field(sinfo.InlineMap)
+		elemType = inlineMap.Type().Elem()
+	}
+
+	for _, index := range sinfo.InlineUnmarshalers {
+		field := d.fieldByIndex(n, out, index)
+		d.prepare(n, field)
+	}
+
+	mergedFields := d.mergedFields
+	d.mergedFields = nil
+	var mergeNode *Node
+	var doneFields []bool
+	if d.uniqueKeys {
+		doneFields = make([]bool, len(sinfo.FieldsList))
+	}
+	name := settableValueOf("")
+	l := len(n.Content)
+	for i := 0; i < l; i += 2 {
+		ni := n.Content[i]
+		if isMerge(ni) {
+			mergeNode = n.Content[i+1]
+			continue
+		}
+		if !d.unmarshal(ni, name) {
+			continue
+		}
+		sname := name.String()
+		if mergedFields != nil {
+			if mergedFields[sname] {
+				continue
+			}
+			mergedFields[sname] = true
+		}
+		if info, ok := sinfo.FieldsMap[sname]; ok {
+			if d.uniqueKeys {
+				if doneFields[info.Id] {
+					d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
+					continue
+				}
+				doneFields[info.Id] = true
+			}
+			var field reflect.Value
+			if info.Inline == nil {
+				field = out.Field(info.Num)
+			} else {
+				field = d.fieldByIndex(n, out, info.Inline)
+			}
+			d.unmarshal(n.Content[i+1], field)
+		} else if sinfo.InlineMap != -1 {
+			if inlineMap.IsNil() {
+				inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
+			}
+			value := reflect.New(elemType).Elem()
+			d.unmarshal(n.Content[i+1], value)
+			inlineMap.SetMapIndex(name, value)
+		} else if d.knownFields {
+			d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
+		}
+	}
+
+	d.mergedFields = mergedFields
+	if mergeNode != nil {
+		d.merge(n, mergeNode, out)
+	}
+	return true
+}
+
+func failWantMap() {
+	failf("map merge requires map or sequence of maps as the value")
+}
+
+func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {
+	mergedFields := d.mergedFields
+	if mergedFields == nil {
+		d.mergedFields = make(map[interface{}]bool)
+		for i := 0; i < len(parent.Content); i += 2 {
+			k := reflect.New(ifaceType).Elem()
+			if d.unmarshal(parent.Content[i], k) {
+				d.mergedFields[k.Interface()] = true
+			}
+		}
+	}
+
+	switch merge.Kind {
+	case MappingNode:
+		d.unmarshal(merge, out)
+	case AliasNode:
+		if merge.Alias != nil && merge.Alias.Kind != MappingNode {
+			failWantMap()
+		}
+		d.unmarshal(merge, out)
+	case SequenceNode:
+		for i := 0; i < len(merge.Content); i++ {
+			ni := merge.Content[i]
+			if ni.Kind == AliasNode {
+				if ni.Alias != nil && ni.Alias.Kind != MappingNode {
+					failWantMap()
+				}
+			} else if ni.Kind != MappingNode {
+				failWantMap()
+			}
+			d.unmarshal(ni, out)
+		}
+	default:
+		failWantMap()
+	}
+
+	d.mergedFields = mergedFields
+}
+
+func isMerge(n *Node) bool {
+	return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)
+}
diff --git a/vendor/gopkg.in/yaml.v3/emitterc.go b/vendor/gopkg.in/yaml.v3/emitterc.go
new file mode 100644
index 000000000..0f47c9ca8
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/emitterc.go
@@ -0,0 +1,2020 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// Flush the buffer if needed.
+func flush(emitter *yaml_emitter_t) bool {
+	if emitter.buffer_pos+5 >= len(emitter.buffer) {
+		return yaml_emitter_flush(emitter)
+	}
+	return true
+}
+
+// Put a character to the output buffer.
+func put(emitter *yaml_emitter_t, value byte) bool {
+	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+		return false
+	}
+	emitter.buffer[emitter.buffer_pos] = value
+	emitter.buffer_pos++
+	emitter.column++
+	return true
+}
+
+// Put a line break to the output buffer.
+func put_break(emitter *yaml_emitter_t) bool {
+	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+		return false
+	}
+	switch emitter.line_break {
+	case yaml_CR_BREAK:
+		emitter.buffer[emitter.buffer_pos] = '\r'
+		emitter.buffer_pos += 1
+	case yaml_LN_BREAK:
+		emitter.buffer[emitter.buffer_pos] = '\n'
+		emitter.buffer_pos += 1
+	case yaml_CRLN_BREAK:
+		emitter.buffer[emitter.buffer_pos+0] = '\r'
+		emitter.buffer[emitter.buffer_pos+1] = '\n'
+		emitter.buffer_pos += 2
+	default:
+		panic("unknown line break setting")
+	}
+	if emitter.column == 0 {
+		emitter.space_above = true
+	}
+	emitter.column = 0
+	emitter.line++
+	// [Go] Do this here and below and drop from everywhere else (see commented lines).
+	emitter.indention = true
+	return true
+}
+
+// Copy a character from a string into buffer.
+func write(emitter *yaml_emitter_t, s []byte, i *int) bool {
+	if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) {
+		return false
+	}
+	p := emitter.buffer_pos
+	w := width(s[*i])
+	switch w {
+	case 4:
+		emitter.buffer[p+3] = s[*i+3]
+		fallthrough
+	case 3:
+		emitter.buffer[p+2] = s[*i+2]
+		fallthrough
+	case 2:
+		emitter.buffer[p+1] = s[*i+1]
+		fallthrough
+	case 1:
+		emitter.buffer[p+0] = s[*i+0]
+	default:
+		panic("unknown character width")
+	}
+	emitter.column++
+	emitter.buffer_pos += w
+	*i += w
+	return true
+}
+
+// Write a whole string into buffer.
+func write_all(emitter *yaml_emitter_t, s []byte) bool {
+	for i := 0; i < len(s); {
+		if !write(emitter, s, &i) {
+			return false
+		}
+	}
+	return true
+}
+
+// Copy a line break character from a string into buffer.
+func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool {
+	if s[*i] == '\n' {
+		if !put_break(emitter) {
+			return false
+		}
+		*i++
+	} else {
+		if !write(emitter, s, i) {
+			return false
+		}
+		if emitter.column == 0 {
+			emitter.space_above = true
+		}
+		emitter.column = 0
+		emitter.line++
+		// [Go] Do this here and above and drop from everywhere else (see commented lines).
+		emitter.indention = true
+	}
+	return true
+}
+
+// Set an emitter error and return false.
+func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool {
+	emitter.error = yaml_EMITTER_ERROR
+	emitter.problem = problem
+	return false
+}
+
+// Emit an event.
+func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	emitter.events = append(emitter.events, *event)
+	for !yaml_emitter_need_more_events(emitter) {
+		event := &emitter.events[emitter.events_head]
+		if !yaml_emitter_analyze_event(emitter, event) {
+			return false
+		}
+		if !yaml_emitter_state_machine(emitter, event) {
+			return false
+		}
+		yaml_event_delete(event)
+		emitter.events_head++
+	}
+	return true
+}
+
+// Check if we need to accumulate more events before emitting.
+//
+// We accumulate extra
+//  - 1 event for DOCUMENT-START
+//  - 2 events for SEQUENCE-START
+//  - 3 events for MAPPING-START
+//
+func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool {
+	if emitter.events_head == len(emitter.events) {
+		return true
+	}
+	var accumulate int
+	switch emitter.events[emitter.events_head].typ {
+	case yaml_DOCUMENT_START_EVENT:
+		accumulate = 1
+		break
+	case yaml_SEQUENCE_START_EVENT:
+		accumulate = 2
+		break
+	case yaml_MAPPING_START_EVENT:
+		accumulate = 3
+		break
+	default:
+		return false
+	}
+	if len(emitter.events)-emitter.events_head > accumulate {
+		return false
+	}
+	var level int
+	for i := emitter.events_head; i < len(emitter.events); i++ {
+		switch emitter.events[i].typ {
+		case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT:
+			level++
+		case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT:
+			level--
+		}
+		if level == 0 {
+			return false
+		}
+	}
+	return true
+}
+
+// Append a directive to the directives stack.
+func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool {
+	for i := 0; i < len(emitter.tag_directives); i++ {
+		if bytes.Equal(value.handle, emitter.tag_directives[i].handle) {
+			if allow_duplicates {
+				return true
+			}
+			return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive")
+		}
+	}
+
+	// [Go] Do we actually need to copy this given garbage collection
+	// and the lack of deallocating destructors?
+	tag_copy := yaml_tag_directive_t{
+		handle: make([]byte, len(value.handle)),
+		prefix: make([]byte, len(value.prefix)),
+	}
+	copy(tag_copy.handle, value.handle)
+	copy(tag_copy.prefix, value.prefix)
+	emitter.tag_directives = append(emitter.tag_directives, tag_copy)
+	return true
+}
+
+// Increase the indentation level.
+func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool {
+	emitter.indents = append(emitter.indents, emitter.indent)
+	if emitter.indent < 0 {
+		if flow {
+			emitter.indent = emitter.best_indent
+		} else {
+			emitter.indent = 0
+		}
+	} else if !indentless {
+		// [Go] This was changed so that indentations are more regular.
+		if emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE {
+			// The first indent inside a sequence will just skip the "- " indicator.
+			emitter.indent += 2
+		} else {
+			// Everything else aligns to the chosen indentation.
+			emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent)
+		}
+	}
+	return true
+}
+
+// State dispatcher.
+func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	switch emitter.state {
+	default:
+	case yaml_EMIT_STREAM_START_STATE:
+		return yaml_emitter_emit_stream_start(emitter, event)
+
+	case yaml_EMIT_FIRST_DOCUMENT_START_STATE:
+		return yaml_emitter_emit_document_start(emitter, event, true)
+
+	case yaml_EMIT_DOCUMENT_START_STATE:
+		return yaml_emitter_emit_document_start(emitter, event, false)
+
+	case yaml_EMIT_DOCUMENT_CONTENT_STATE:
+		return yaml_emitter_emit_document_content(emitter, event)
+
+	case yaml_EMIT_DOCUMENT_END_STATE:
+		return yaml_emitter_emit_document_end(emitter, event)
+
+	case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE:
+		return yaml_emitter_emit_flow_sequence_item(emitter, event, true, false)
+
+	case yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE:
+		return yaml_emitter_emit_flow_sequence_item(emitter, event, false, true)
+
+	case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE:
+		return yaml_emitter_emit_flow_sequence_item(emitter, event, false, false)
+
+	case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE:
+		return yaml_emitter_emit_flow_mapping_key(emitter, event, true, false)
+
+	case yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE:
+		return yaml_emitter_emit_flow_mapping_key(emitter, event, false, true)
+
+	case yaml_EMIT_FLOW_MAPPING_KEY_STATE:
+		return yaml_emitter_emit_flow_mapping_key(emitter, event, false, false)
+
+	case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE:
+		return yaml_emitter_emit_flow_mapping_value(emitter, event, true)
+
+	case yaml_EMIT_FLOW_MAPPING_VALUE_STATE:
+		return yaml_emitter_emit_flow_mapping_value(emitter, event, false)
+
+	case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE:
+		return yaml_emitter_emit_block_sequence_item(emitter, event, true)
+
+	case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE:
+		return yaml_emitter_emit_block_sequence_item(emitter, event, false)
+
+	case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE:
+		return yaml_emitter_emit_block_mapping_key(emitter, event, true)
+
+	case yaml_EMIT_BLOCK_MAPPING_KEY_STATE:
+		return yaml_emitter_emit_block_mapping_key(emitter, event, false)
+
+	case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE:
+		return yaml_emitter_emit_block_mapping_value(emitter, event, true)
+
+	case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE:
+		return yaml_emitter_emit_block_mapping_value(emitter, event, false)
+
+	case yaml_EMIT_END_STATE:
+		return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END")
+	}
+	panic("invalid emitter state")
+}
+
+// Expect STREAM-START.
+func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if event.typ != yaml_STREAM_START_EVENT {
+		return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START")
+	}
+	if emitter.encoding == yaml_ANY_ENCODING {
+		emitter.encoding = event.encoding
+		if emitter.encoding == yaml_ANY_ENCODING {
+			emitter.encoding = yaml_UTF8_ENCODING
+		}
+	}
+	if emitter.best_indent < 2 || emitter.best_indent > 9 {
+		emitter.best_indent = 2
+	}
+	if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 {
+		emitter.best_width = 80
+	}
+	if emitter.best_width < 0 {
+		emitter.best_width = 1<<31 - 1
+	}
+	if emitter.line_break == yaml_ANY_BREAK {
+		emitter.line_break = yaml_LN_BREAK
+	}
+
+	emitter.indent = -1
+	emitter.line = 0
+	emitter.column = 0
+	emitter.whitespace = true
+	emitter.indention = true
+	emitter.space_above = true
+	emitter.foot_indent = -1
+
+	if emitter.encoding != yaml_UTF8_ENCODING {
+		if !yaml_emitter_write_bom(emitter) {
+			return false
+		}
+	}
+	emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE
+	return true
+}
+
+// Expect DOCUMENT-START or STREAM-END.
+func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+
+	if event.typ == yaml_DOCUMENT_START_EVENT {
+
+		if event.version_directive != nil {
+			if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) {
+				return false
+			}
+		}
+
+		for i := 0; i < len(event.tag_directives); i++ {
+			tag_directive := &event.tag_directives[i]
+			if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) {
+				return false
+			}
+			if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) {
+				return false
+			}
+		}
+
+		for i := 0; i < len(default_tag_directives); i++ {
+			tag_directive := &default_tag_directives[i]
+			if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) {
+				return false
+			}
+		}
+
+		implicit := event.implicit
+		if !first || emitter.canonical {
+			implicit = false
+		}
+
+		if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) {
+			if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+
+		if event.version_directive != nil {
+			implicit = false
+			if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+
+		if len(event.tag_directives) > 0 {
+			implicit = false
+			for i := 0; i < len(event.tag_directives); i++ {
+				tag_directive := &event.tag_directives[i]
+				if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) {
+					return false
+				}
+				if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) {
+					return false
+				}
+				if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) {
+					return false
+				}
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+		}
+
+		if yaml_emitter_check_empty_document(emitter) {
+			implicit = false
+		}
+		if !implicit {
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+			if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) {
+				return false
+			}
+			if emitter.canonical || true {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+		}
+
+		if len(emitter.head_comment) > 0 {
+			if !yaml_emitter_process_head_comment(emitter) {
+				return false
+			}
+			if !put_break(emitter) {
+				return false
+			}
+		}
+
+		emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE
+		return true
+	}
+
+	if event.typ == yaml_STREAM_END_EVENT {
+		if emitter.open_ended {
+			if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+				return false
+			}
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+		if !yaml_emitter_flush(emitter) {
+			return false
+		}
+		emitter.state = yaml_EMIT_END_STATE
+		return true
+	}
+
+	return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END")
+}
+
+// Expect the root node.
+func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE)
+
+	if !yaml_emitter_process_head_comment(emitter) {
+		return false
+	}
+	if !yaml_emitter_emit_node(emitter, event, true, false, false, false) {
+		return false
+	}
+	if !yaml_emitter_process_line_comment(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_foot_comment(emitter) {
+		return false
+	}
+	return true
+}
+
+// Expect DOCUMENT-END.
+func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if event.typ != yaml_DOCUMENT_END_EVENT {
+		return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END")
+	}
+	// [Go] Force document foot separation.
+	emitter.foot_indent = 0
+	if !yaml_emitter_process_foot_comment(emitter) {
+		return false
+	}
+	emitter.foot_indent = -1
+	if !yaml_emitter_write_indent(emitter) {
+		return false
+	}
+	if !event.implicit {
+		// [Go] Allocate the slice elsewhere.
+		if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) {
+			return false
+		}
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+	}
+	if !yaml_emitter_flush(emitter) {
+		return false
+	}
+	emitter.state = yaml_EMIT_DOCUMENT_START_STATE
+	emitter.tag_directives = emitter.tag_directives[:0]
+	return true
+}
+
+// Expect a flow item node.
+func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool {
+	if first {
+		if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) {
+			return false
+		}
+		if !yaml_emitter_increase_indent(emitter, true, false) {
+			return false
+		}
+		emitter.flow_level++
+	}
+
+	if event.typ == yaml_SEQUENCE_END_EVENT {
+		if emitter.canonical && !first && !trail {
+			if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+				return false
+			}
+		}
+		emitter.flow_level--
+		emitter.indent = emitter.indents[len(emitter.indents)-1]
+		emitter.indents = emitter.indents[:len(emitter.indents)-1]
+		if emitter.column == 0 || emitter.canonical && !first {
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) {
+			return false
+		}
+		if !yaml_emitter_process_line_comment(emitter) {
+			return false
+		}
+		if !yaml_emitter_process_foot_comment(emitter) {
+			return false
+		}
+		emitter.state = emitter.states[len(emitter.states)-1]
+		emitter.states = emitter.states[:len(emitter.states)-1]
+
+		return true
+	}
+
+	if !first && !trail {
+		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+			return false
+		}
+	}
+
+	if !yaml_emitter_process_head_comment(emitter) {
+		return false
+	}
+	if emitter.column == 0 {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+	}
+
+	if emitter.canonical || emitter.column > emitter.best_width {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+	}
+	if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
+		emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE)
+	} else {
+		emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
+	}
+	if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
+		return false
+	}
+	if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
+		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+			return false
+		}
+	}
+	if !yaml_emitter_process_line_comment(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_foot_comment(emitter) {
+		return false
+	}
+	return true
+}
+
+// Expect a flow key node.
+func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool {
+	if first {
+		if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) {
+			return false
+		}
+		if !yaml_emitter_increase_indent(emitter, true, false) {
+			return false
+		}
+		emitter.flow_level++
+	}
+
+	if event.typ == yaml_MAPPING_END_EVENT {
+		if (emitter.canonical || len(emitter.head_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0) && !first && !trail {
+			if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+				return false
+			}
+		}
+		if !yaml_emitter_process_head_comment(emitter) {
+			return false
+		}
+		emitter.flow_level--
+		emitter.indent = emitter.indents[len(emitter.indents)-1]
+		emitter.indents = emitter.indents[:len(emitter.indents)-1]
+		if emitter.canonical && !first {
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) {
+			return false
+		}
+		if !yaml_emitter_process_line_comment(emitter) {
+			return false
+		}
+		if !yaml_emitter_process_foot_comment(emitter) {
+			return false
+		}
+		emitter.state = emitter.states[len(emitter.states)-1]
+		emitter.states = emitter.states[:len(emitter.states)-1]
+		return true
+	}
+
+	if !first && !trail {
+		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+			return false
+		}
+	}
+
+	if !yaml_emitter_process_head_comment(emitter) {
+		return false
+	}
+
+	if emitter.column == 0 {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+	}
+
+	if emitter.canonical || emitter.column > emitter.best_width {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+	}
+
+	if !emitter.canonical && yaml_emitter_check_simple_key(emitter) {
+		emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)
+		return yaml_emitter_emit_node(emitter, event, false, false, true, true)
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) {
+		return false
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE)
+	return yaml_emitter_emit_node(emitter, event, false, false, true, false)
+}
+
+// Expect a flow value node.
+func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
+	if simple {
+		if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
+			return false
+		}
+	} else {
+		if emitter.canonical || emitter.column > emitter.best_width {
+			if !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) {
+			return false
+		}
+	}
+	if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
+		emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE)
+	} else {
+		emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
+	}
+	if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
+		return false
+	}
+	if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
+		if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
+			return false
+		}
+	}
+	if !yaml_emitter_process_line_comment(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_foot_comment(emitter) {
+		return false
+	}
+	return true
+}
+
+// Expect a block item node.
+func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+	if first {
+		if !yaml_emitter_increase_indent(emitter, false, false) {
+			return false
+		}
+	}
+	if event.typ == yaml_SEQUENCE_END_EVENT {
+		emitter.indent = emitter.indents[len(emitter.indents)-1]
+		emitter.indents = emitter.indents[:len(emitter.indents)-1]
+		emitter.state = emitter.states[len(emitter.states)-1]
+		emitter.states = emitter.states[:len(emitter.states)-1]
+		return true
+	}
+	if !yaml_emitter_process_head_comment(emitter) {
+		return false
+	}
+	if !yaml_emitter_write_indent(emitter) {
+		return false
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) {
+		return false
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE)
+	if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
+		return false
+	}
+	if !yaml_emitter_process_line_comment(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_foot_comment(emitter) {
+		return false
+	}
+	return true
+}
+
+// Expect a block key node.
+func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool {
+	if first {
+		if !yaml_emitter_increase_indent(emitter, false, false) {
+			return false
+		}
+	}
+	if !yaml_emitter_process_head_comment(emitter) {
+		return false
+	}
+	if event.typ == yaml_MAPPING_END_EVENT {
+		emitter.indent = emitter.indents[len(emitter.indents)-1]
+		emitter.indents = emitter.indents[:len(emitter.indents)-1]
+		emitter.state = emitter.states[len(emitter.states)-1]
+		emitter.states = emitter.states[:len(emitter.states)-1]
+		return true
+	}
+	if !yaml_emitter_write_indent(emitter) {
+		return false
+	}
+	if len(emitter.line_comment) > 0 {
+		// [Go] A line comment was provided for the key. That's unusual as the
+		//      scanner associates line comments with the value. Either way,
+		//      save the line comment and render it appropriately later.
+		emitter.key_line_comment = emitter.line_comment
+		emitter.line_comment = nil
+	}
+	if yaml_emitter_check_simple_key(emitter) {
+		emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)
+		return yaml_emitter_emit_node(emitter, event, false, false, true, true)
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) {
+		return false
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE)
+	return yaml_emitter_emit_node(emitter, event, false, false, true, false)
+}
+
+// Expect a block value node.
+func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool {
+	if simple {
+		if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) {
+			return false
+		}
+	} else {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) {
+			return false
+		}
+	}
+	if len(emitter.key_line_comment) > 0 {
+		// [Go] Line comments are generally associated with the value, but when there's
+		//      no value on the same line as a mapping key they end up attached to the
+		//      key itself.
+		if event.typ == yaml_SCALAR_EVENT {
+			if len(emitter.line_comment) == 0 {
+				// A scalar is coming and it has no line comments by itself yet,
+				// so just let it handle the line comment as usual. If it has a
+				// line comment, we can't have both so the one from the key is lost.
+				emitter.line_comment = emitter.key_line_comment
+				emitter.key_line_comment = nil
+			}
+		} else if event.sequence_style() != yaml_FLOW_SEQUENCE_STYLE && (event.typ == yaml_MAPPING_START_EVENT || event.typ == yaml_SEQUENCE_START_EVENT) {
+			// An indented block follows, so write the comment right now.
+			emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment
+			if !yaml_emitter_process_line_comment(emitter) {
+				return false
+			}
+			emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment
+		}
+	}
+	emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE)
+	if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
+		return false
+	}
+	if !yaml_emitter_process_line_comment(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_foot_comment(emitter) {
+		return false
+	}
+	return true
+}
+
+func yaml_emitter_silent_nil_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	return event.typ == yaml_SCALAR_EVENT && event.implicit && !emitter.canonical && len(emitter.scalar_data.value) == 0
+}
+
+// Expect a node.
+func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
+	root bool, sequence bool, mapping bool, simple_key bool) bool {
+
+	emitter.root_context = root
+	emitter.sequence_context = sequence
+	emitter.mapping_context = mapping
+	emitter.simple_key_context = simple_key
+
+	switch event.typ {
+	case yaml_ALIAS_EVENT:
+		return yaml_emitter_emit_alias(emitter, event)
+	case yaml_SCALAR_EVENT:
+		return yaml_emitter_emit_scalar(emitter, event)
+	case yaml_SEQUENCE_START_EVENT:
+		return yaml_emitter_emit_sequence_start(emitter, event)
+	case yaml_MAPPING_START_EVENT:
+		return yaml_emitter_emit_mapping_start(emitter, event)
+	default:
+		return yaml_emitter_set_emitter_error(emitter,
+			fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ))
+	}
+}
+
+// Expect ALIAS.
+func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if !yaml_emitter_process_anchor(emitter) {
+		return false
+	}
+	emitter.state = emitter.states[len(emitter.states)-1]
+	emitter.states = emitter.states[:len(emitter.states)-1]
+	return true
+}
+
+// Expect SCALAR.
+func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if !yaml_emitter_select_scalar_style(emitter, event) {
+		return false
+	}
+	if !yaml_emitter_process_anchor(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_tag(emitter) {
+		return false
+	}
+	if !yaml_emitter_increase_indent(emitter, true, false) {
+		return false
+	}
+	if !yaml_emitter_process_scalar(emitter) {
+		return false
+	}
+	emitter.indent = emitter.indents[len(emitter.indents)-1]
+	emitter.indents = emitter.indents[:len(emitter.indents)-1]
+	emitter.state = emitter.states[len(emitter.states)-1]
+	emitter.states = emitter.states[:len(emitter.states)-1]
+	return true
+}
+
+// Expect SEQUENCE-START.
+func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if !yaml_emitter_process_anchor(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_tag(emitter) {
+		return false
+	}
+	if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE ||
+		yaml_emitter_check_empty_sequence(emitter) {
+		emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE
+	} else {
+		emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE
+	}
+	return true
+}
+
+// Expect MAPPING-START.
+func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+	if !yaml_emitter_process_anchor(emitter) {
+		return false
+	}
+	if !yaml_emitter_process_tag(emitter) {
+		return false
+	}
+	if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE ||
+		yaml_emitter_check_empty_mapping(emitter) {
+		emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE
+	} else {
+		emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE
+	}
+	return true
+}
+
+// Check if the document content is an empty scalar.
+func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool {
+	return false // [Go] Huh?
+}
+
+// Check if the next events represent an empty sequence.
+func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool {
+	if len(emitter.events)-emitter.events_head < 2 {
+		return false
+	}
+	return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT &&
+		emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT
+}
+
+// Check if the next events represent an empty mapping.
+func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool {
+	if len(emitter.events)-emitter.events_head < 2 {
+		return false
+	}
+	return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT &&
+		emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT
+}
+
+// Check if the next node can be expressed as a simple key.
+func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool {
+	length := 0
+	switch emitter.events[emitter.events_head].typ {
+	case yaml_ALIAS_EVENT:
+		length += len(emitter.anchor_data.anchor)
+	case yaml_SCALAR_EVENT:
+		if emitter.scalar_data.multiline {
+			return false
+		}
+		length += len(emitter.anchor_data.anchor) +
+			len(emitter.tag_data.handle) +
+			len(emitter.tag_data.suffix) +
+			len(emitter.scalar_data.value)
+	case yaml_SEQUENCE_START_EVENT:
+		if !yaml_emitter_check_empty_sequence(emitter) {
+			return false
+		}
+		length += len(emitter.anchor_data.anchor) +
+			len(emitter.tag_data.handle) +
+			len(emitter.tag_data.suffix)
+	case yaml_MAPPING_START_EVENT:
+		if !yaml_emitter_check_empty_mapping(emitter) {
+			return false
+		}
+		length += len(emitter.anchor_data.anchor) +
+			len(emitter.tag_data.handle) +
+			len(emitter.tag_data.suffix)
+	default:
+		return false
+	}
+	return length <= 128
+}
+
+// Determine an acceptable scalar style.
+func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+
+	no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0
+	if no_tag && !event.implicit && !event.quoted_implicit {
+		return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified")
+	}
+
+	style := event.scalar_style()
+	if style == yaml_ANY_SCALAR_STYLE {
+		style = yaml_PLAIN_SCALAR_STYLE
+	}
+	if emitter.canonical {
+		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+	}
+	if emitter.simple_key_context && emitter.scalar_data.multiline {
+		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+	}
+
+	if style == yaml_PLAIN_SCALAR_STYLE {
+		if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed ||
+			emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed {
+			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+		}
+		if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) {
+			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+		}
+		if no_tag && !event.implicit {
+			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+		}
+	}
+	if style == yaml_SINGLE_QUOTED_SCALAR_STYLE {
+		if !emitter.scalar_data.single_quoted_allowed {
+			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+		}
+	}
+	if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE {
+		if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context {
+			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+		}
+	}
+
+	if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE {
+		emitter.tag_data.handle = []byte{'!'}
+	}
+	emitter.scalar_data.style = style
+	return true
+}
+
+// Write an anchor.
+func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
+	if emitter.anchor_data.anchor == nil {
+		return true
+	}
+	c := []byte{'&'}
+	if emitter.anchor_data.alias {
+		c[0] = '*'
+	}
+	if !yaml_emitter_write_indicator(emitter, c, true, false, false) {
+		return false
+	}
+	return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor)
+}
+
+// Write a tag.
+func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool {
+	if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 {
+		return true
+	}
+	if len(emitter.tag_data.handle) > 0 {
+		if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) {
+			return false
+		}
+		if len(emitter.tag_data.suffix) > 0 {
+			if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
+				return false
+			}
+		}
+	} else {
+		// [Go] Allocate these slices elsewhere.
+		if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) {
+			return false
+		}
+		if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) {
+			return false
+		}
+		if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) {
+			return false
+		}
+	}
+	return true
+}
+
+// Write a scalar.
+func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {
+	switch emitter.scalar_data.style {
+	case yaml_PLAIN_SCALAR_STYLE:
+		return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+	case yaml_SINGLE_QUOTED_SCALAR_STYLE:
+		return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+	case yaml_DOUBLE_QUOTED_SCALAR_STYLE:
+		return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context)
+
+	case yaml_LITERAL_SCALAR_STYLE:
+		return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value)
+
+	case yaml_FOLDED_SCALAR_STYLE:
+		return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value)
+	}
+	panic("unknown scalar style")
+}
+
+// Write a head comment.
+func yaml_emitter_process_head_comment(emitter *yaml_emitter_t) bool {
+	if len(emitter.tail_comment) > 0 {
+		if !yaml_emitter_write_indent(emitter) {
+			return false
+		}
+		if !yaml_emitter_write_comment(emitter, emitter.tail_comment) {
+			return false
+		}
+		emitter.tail_comment = emitter.tail_comment[:0]
+		emitter.foot_indent = emitter.indent
+		if emitter.foot_indent < 0 {
+			emitter.foot_indent = 0
+		}
+	}
+
+	if len(emitter.head_comment) == 0 {
+		return true
+	}
+	if !yaml_emitter_write_indent(emitter) {
+		return false
+	}
+	if !yaml_emitter_write_comment(emitter, emitter.head_comment) {
+		return false
+	}
+	emitter.head_comment = emitter.head_comment[:0]
+	return true
+}
+
+// Write an line comment.
+func yaml_emitter_process_line_comment(emitter *yaml_emitter_t) bool {
+	if len(emitter.line_comment) == 0 {
+		return true
+	}
+	if !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	if !yaml_emitter_write_comment(emitter, emitter.line_comment) {
+		return false
+	}
+	emitter.line_comment = emitter.line_comment[:0]
+	return true
+}
+
+// Write a foot comment.
+func yaml_emitter_process_foot_comment(emitter *yaml_emitter_t) bool {
+	if len(emitter.foot_comment) == 0 {
+		return true
+	}
+	if !yaml_emitter_write_indent(emitter) {
+		return false
+	}
+	if !yaml_emitter_write_comment(emitter, emitter.foot_comment) {
+		return false
+	}
+	emitter.foot_comment = emitter.foot_comment[:0]
+	emitter.foot_indent = emitter.indent
+	if emitter.foot_indent < 0 {
+		emitter.foot_indent = 0
+	}
+	return true
+}
+
+// Check if a %YAML directive is valid.
+func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool {
+	if version_directive.major != 1 || version_directive.minor != 1 {
+		return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive")
+	}
+	return true
+}
+
+// Check if a %TAG directive is valid.
+func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool {
+	handle := tag_directive.handle
+	prefix := tag_directive.prefix
+	if len(handle) == 0 {
+		return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty")
+	}
+	if handle[0] != '!' {
+		return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'")
+	}
+	if handle[len(handle)-1] != '!' {
+		return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'")
+	}
+	for i := 1; i < len(handle)-1; i += width(handle[i]) {
+		if !is_alpha(handle, i) {
+			return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only")
+		}
+	}
+	if len(prefix) == 0 {
+		return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty")
+	}
+	return true
+}
+
+// Check if an anchor is valid.
+func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool {
+	if len(anchor) == 0 {
+		problem := "anchor value must not be empty"
+		if alias {
+			problem = "alias value must not be empty"
+		}
+		return yaml_emitter_set_emitter_error(emitter, problem)
+	}
+	for i := 0; i < len(anchor); i += width(anchor[i]) {
+		if !is_alpha(anchor, i) {
+			problem := "anchor value must contain alphanumerical characters only"
+			if alias {
+				problem = "alias value must contain alphanumerical characters only"
+			}
+			return yaml_emitter_set_emitter_error(emitter, problem)
+		}
+	}
+	emitter.anchor_data.anchor = anchor
+	emitter.anchor_data.alias = alias
+	return true
+}
+
+// Check if a tag is valid.
+func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool {
+	if len(tag) == 0 {
+		return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty")
+	}
+	for i := 0; i < len(emitter.tag_directives); i++ {
+		tag_directive := &emitter.tag_directives[i]
+		if bytes.HasPrefix(tag, tag_directive.prefix) {
+			emitter.tag_data.handle = tag_directive.handle
+			emitter.tag_data.suffix = tag[len(tag_directive.prefix):]
+			return true
+		}
+	}
+	emitter.tag_data.suffix = tag
+	return true
+}
+
+// Check if a scalar is valid.
+func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
+	var (
+		block_indicators   = false
+		flow_indicators    = false
+		line_breaks        = false
+		special_characters = false
+		tab_characters     = false
+
+		leading_space  = false
+		leading_break  = false
+		trailing_space = false
+		trailing_break = false
+		break_space    = false
+		space_break    = false
+
+		preceded_by_whitespace = false
+		followed_by_whitespace = false
+		previous_space         = false
+		previous_break         = false
+	)
+
+	emitter.scalar_data.value = value
+
+	if len(value) == 0 {
+		emitter.scalar_data.multiline = false
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = true
+		emitter.scalar_data.single_quoted_allowed = true
+		emitter.scalar_data.block_allowed = false
+		return true
+	}
+
+	if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) {
+		block_indicators = true
+		flow_indicators = true
+	}
+
+	preceded_by_whitespace = true
+	for i, w := 0, 0; i < len(value); i += w {
+		w = width(value[i])
+		followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
+
+		if i == 0 {
+			switch value[i] {
+			case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`':
+				flow_indicators = true
+				block_indicators = true
+			case '?', ':':
+				flow_indicators = true
+				if followed_by_whitespace {
+					block_indicators = true
+				}
+			case '-':
+				if followed_by_whitespace {
+					flow_indicators = true
+					block_indicators = true
+				}
+			}
+		} else {
+			switch value[i] {
+			case ',', '?', '[', ']', '{', '}':
+				flow_indicators = true
+			case ':':
+				flow_indicators = true
+				if followed_by_whitespace {
+					block_indicators = true
+				}
+			case '#':
+				if preceded_by_whitespace {
+					flow_indicators = true
+					block_indicators = true
+				}
+			}
+		}
+
+		if value[i] == '\t' {
+			tab_characters = true
+		} else if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode {
+			special_characters = true
+		}
+		if is_space(value, i) {
+			if i == 0 {
+				leading_space = true
+			}
+			if i+width(value[i]) == len(value) {
+				trailing_space = true
+			}
+			if previous_break {
+				break_space = true
+			}
+			previous_space = true
+			previous_break = false
+		} else if is_break(value, i) {
+			line_breaks = true
+			if i == 0 {
+				leading_break = true
+			}
+			if i+width(value[i]) == len(value) {
+				trailing_break = true
+			}
+			if previous_space {
+				space_break = true
+			}
+			previous_space = false
+			previous_break = true
+		} else {
+			previous_space = false
+			previous_break = false
+		}
+
+		// [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
+		preceded_by_whitespace = is_blankz(value, i)
+	}
+
+	emitter.scalar_data.multiline = line_breaks
+	emitter.scalar_data.flow_plain_allowed = true
+	emitter.scalar_data.block_plain_allowed = true
+	emitter.scalar_data.single_quoted_allowed = true
+	emitter.scalar_data.block_allowed = true
+
+	if leading_space || leading_break || trailing_space || trailing_break {
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = false
+	}
+	if trailing_space {
+		emitter.scalar_data.block_allowed = false
+	}
+	if break_space {
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = false
+		emitter.scalar_data.single_quoted_allowed = false
+	}
+	if space_break || tab_characters || special_characters {
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = false
+		emitter.scalar_data.single_quoted_allowed = false
+	}
+	if space_break || special_characters {
+		emitter.scalar_data.block_allowed = false
+	}
+	if line_breaks {
+		emitter.scalar_data.flow_plain_allowed = false
+		emitter.scalar_data.block_plain_allowed = false
+	}
+	if flow_indicators {
+		emitter.scalar_data.flow_plain_allowed = false
+	}
+	if block_indicators {
+		emitter.scalar_data.block_plain_allowed = false
+	}
+	return true
+}
+
+// Check if the event data is valid.
+func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool {
+
+	emitter.anchor_data.anchor = nil
+	emitter.tag_data.handle = nil
+	emitter.tag_data.suffix = nil
+	emitter.scalar_data.value = nil
+
+	if len(event.head_comment) > 0 {
+		emitter.head_comment = event.head_comment
+	}
+	if len(event.line_comment) > 0 {
+		emitter.line_comment = event.line_comment
+	}
+	if len(event.foot_comment) > 0 {
+		emitter.foot_comment = event.foot_comment
+	}
+	if len(event.tail_comment) > 0 {
+		emitter.tail_comment = event.tail_comment
+	}
+
+	switch event.typ {
+	case yaml_ALIAS_EVENT:
+		if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) {
+			return false
+		}
+
+	case yaml_SCALAR_EVENT:
+		if len(event.anchor) > 0 {
+			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+				return false
+			}
+		}
+		if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) {
+			if !yaml_emitter_analyze_tag(emitter, event.tag) {
+				return false
+			}
+		}
+		if !yaml_emitter_analyze_scalar(emitter, event.value) {
+			return false
+		}
+
+	case yaml_SEQUENCE_START_EVENT:
+		if len(event.anchor) > 0 {
+			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+				return false
+			}
+		}
+		if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
+			if !yaml_emitter_analyze_tag(emitter, event.tag) {
+				return false
+			}
+		}
+
+	case yaml_MAPPING_START_EVENT:
+		if len(event.anchor) > 0 {
+			if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) {
+				return false
+			}
+		}
+		if len(event.tag) > 0 && (emitter.canonical || !event.implicit) {
+			if !yaml_emitter_analyze_tag(emitter, event.tag) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// Write the BOM character.
+func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool {
+	if !flush(emitter) {
+		return false
+	}
+	pos := emitter.buffer_pos
+	emitter.buffer[pos+0] = '\xEF'
+	emitter.buffer[pos+1] = '\xBB'
+	emitter.buffer[pos+2] = '\xBF'
+	emitter.buffer_pos += 3
+	return true
+}
+
+func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool {
+	indent := emitter.indent
+	if indent < 0 {
+		indent = 0
+	}
+	if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) {
+		if !put_break(emitter) {
+			return false
+		}
+	}
+	if emitter.foot_indent == indent {
+		if !put_break(emitter) {
+			return false
+		}
+	}
+	for emitter.column < indent {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	emitter.whitespace = true
+	//emitter.indention = true
+	emitter.space_above = false
+	emitter.foot_indent = -1
+	return true
+}
+
+func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool {
+	if need_whitespace && !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	if !write_all(emitter, indicator) {
+		return false
+	}
+	emitter.whitespace = is_whitespace
+	emitter.indention = (emitter.indention && is_indention)
+	emitter.open_ended = false
+	return true
+}
+
+func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool {
+	if !write_all(emitter, value) {
+		return false
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool {
+	if !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	if !write_all(emitter, value) {
+		return false
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool {
+	if need_whitespace && !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+	for i := 0; i < len(value); {
+		var must_write bool
+		switch value[i] {
+		case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']':
+			must_write = true
+		default:
+			must_write = is_alpha(value, i)
+		}
+		if must_write {
+			if !write(emitter, value, &i) {
+				return false
+			}
+		} else {
+			w := width(value[i])
+			for k := 0; k < w; k++ {
+				octet := value[i]
+				i++
+				if !put(emitter, '%') {
+					return false
+				}
+
+				c := octet >> 4
+				if c < 10 {
+					c += '0'
+				} else {
+					c += 'A' - 10
+				}
+				if !put(emitter, c) {
+					return false
+				}
+
+				c = octet & 0x0f
+				if c < 10 {
+					c += '0'
+				} else {
+					c += 'A' - 10
+				}
+				if !put(emitter, c) {
+					return false
+				}
+			}
+		}
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+	if len(value) > 0 && !emitter.whitespace {
+		if !put(emitter, ' ') {
+			return false
+		}
+	}
+
+	spaces := false
+	breaks := false
+	for i := 0; i < len(value); {
+		if is_space(value, i) {
+			if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				i += width(value[i])
+			} else {
+				if !write(emitter, value, &i) {
+					return false
+				}
+			}
+			spaces = true
+		} else if is_break(value, i) {
+			if !breaks && value[i] == '\n' {
+				if !put_break(emitter) {
+					return false
+				}
+			}
+			if !write_break(emitter, value, &i) {
+				return false
+			}
+			//emitter.indention = true
+			breaks = true
+		} else {
+			if breaks {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+			if !write(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = false
+			spaces = false
+			breaks = false
+		}
+	}
+
+	if len(value) > 0 {
+		emitter.whitespace = false
+	}
+	emitter.indention = false
+	if emitter.root_context {
+		emitter.open_ended = true
+	}
+
+	return true
+}
+
+func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+
+	if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) {
+		return false
+	}
+
+	spaces := false
+	breaks := false
+	for i := 0; i < len(value); {
+		if is_space(value, i) {
+			if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				i += width(value[i])
+			} else {
+				if !write(emitter, value, &i) {
+					return false
+				}
+			}
+			spaces = true
+		} else if is_break(value, i) {
+			if !breaks && value[i] == '\n' {
+				if !put_break(emitter) {
+					return false
+				}
+			}
+			if !write_break(emitter, value, &i) {
+				return false
+			}
+			//emitter.indention = true
+			breaks = true
+		} else {
+			if breaks {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+			if value[i] == '\'' {
+				if !put(emitter, '\'') {
+					return false
+				}
+			}
+			if !write(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = false
+			spaces = false
+			breaks = false
+		}
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) {
+		return false
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool {
+	spaces := false
+	if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) {
+		return false
+	}
+
+	for i := 0; i < len(value); {
+		if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) ||
+			is_bom(value, i) || is_break(value, i) ||
+			value[i] == '"' || value[i] == '\\' {
+
+			octet := value[i]
+
+			var w int
+			var v rune
+			switch {
+			case octet&0x80 == 0x00:
+				w, v = 1, rune(octet&0x7F)
+			case octet&0xE0 == 0xC0:
+				w, v = 2, rune(octet&0x1F)
+			case octet&0xF0 == 0xE0:
+				w, v = 3, rune(octet&0x0F)
+			case octet&0xF8 == 0xF0:
+				w, v = 4, rune(octet&0x07)
+			}
+			for k := 1; k < w; k++ {
+				octet = value[i+k]
+				v = (v << 6) + (rune(octet) & 0x3F)
+			}
+			i += w
+
+			if !put(emitter, '\\') {
+				return false
+			}
+
+			var ok bool
+			switch v {
+			case 0x00:
+				ok = put(emitter, '0')
+			case 0x07:
+				ok = put(emitter, 'a')
+			case 0x08:
+				ok = put(emitter, 'b')
+			case 0x09:
+				ok = put(emitter, 't')
+			case 0x0A:
+				ok = put(emitter, 'n')
+			case 0x0b:
+				ok = put(emitter, 'v')
+			case 0x0c:
+				ok = put(emitter, 'f')
+			case 0x0d:
+				ok = put(emitter, 'r')
+			case 0x1b:
+				ok = put(emitter, 'e')
+			case 0x22:
+				ok = put(emitter, '"')
+			case 0x5c:
+				ok = put(emitter, '\\')
+			case 0x85:
+				ok = put(emitter, 'N')
+			case 0xA0:
+				ok = put(emitter, '_')
+			case 0x2028:
+				ok = put(emitter, 'L')
+			case 0x2029:
+				ok = put(emitter, 'P')
+			default:
+				if v <= 0xFF {
+					ok = put(emitter, 'x')
+					w = 2
+				} else if v <= 0xFFFF {
+					ok = put(emitter, 'u')
+					w = 4
+				} else {
+					ok = put(emitter, 'U')
+					w = 8
+				}
+				for k := (w - 1) * 4; ok && k >= 0; k -= 4 {
+					digit := byte((v >> uint(k)) & 0x0F)
+					if digit < 10 {
+						ok = put(emitter, digit+'0')
+					} else {
+						ok = put(emitter, digit+'A'-10)
+					}
+				}
+			}
+			if !ok {
+				return false
+			}
+			spaces = false
+		} else if is_space(value, i) {
+			if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				if is_space(value, i+1) {
+					if !put(emitter, '\\') {
+						return false
+					}
+				}
+				i += width(value[i])
+			} else if !write(emitter, value, &i) {
+				return false
+			}
+			spaces = true
+		} else {
+			if !write(emitter, value, &i) {
+				return false
+			}
+			spaces = false
+		}
+	}
+	if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) {
+		return false
+	}
+	emitter.whitespace = false
+	emitter.indention = false
+	return true
+}
+
+func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool {
+	if is_space(value, 0) || is_break(value, 0) {
+		indent_hint := []byte{'0' + byte(emitter.best_indent)}
+		if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) {
+			return false
+		}
+	}
+
+	emitter.open_ended = false
+
+	var chomp_hint [1]byte
+	if len(value) == 0 {
+		chomp_hint[0] = '-'
+	} else {
+		i := len(value) - 1
+		for value[i]&0xC0 == 0x80 {
+			i--
+		}
+		if !is_break(value, i) {
+			chomp_hint[0] = '-'
+		} else if i == 0 {
+			chomp_hint[0] = '+'
+			emitter.open_ended = true
+		} else {
+			i--
+			for value[i]&0xC0 == 0x80 {
+				i--
+			}
+			if is_break(value, i) {
+				chomp_hint[0] = '+'
+				emitter.open_ended = true
+			}
+		}
+	}
+	if chomp_hint[0] != 0 {
+		if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) {
+			return false
+		}
+	}
+	return true
+}
+
+func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool {
+	if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) {
+		return false
+	}
+	if !yaml_emitter_write_block_scalar_hints(emitter, value) {
+		return false
+	}
+	if !yaml_emitter_process_line_comment(emitter) {
+		return false
+	}
+	//emitter.indention = true
+	emitter.whitespace = true
+	breaks := true
+	for i := 0; i < len(value); {
+		if is_break(value, i) {
+			if !write_break(emitter, value, &i) {
+				return false
+			}
+			//emitter.indention = true
+			breaks = true
+		} else {
+			if breaks {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+			}
+			if !write(emitter, value, &i) {
+				return false
+			}
+			emitter.indention = false
+			breaks = false
+		}
+	}
+
+	return true
+}
+
+func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool {
+	if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) {
+		return false
+	}
+	if !yaml_emitter_write_block_scalar_hints(emitter, value) {
+		return false
+	}
+	if !yaml_emitter_process_line_comment(emitter) {
+		return false
+	}
+
+	//emitter.indention = true
+	emitter.whitespace = true
+
+	breaks := true
+	leading_spaces := true
+	for i := 0; i < len(value); {
+		if is_break(value, i) {
+			if !breaks && !leading_spaces && value[i] == '\n' {
+				k := 0
+				for is_break(value, k) {
+					k += width(value[k])
+				}
+				if !is_blankz(value, k) {
+					if !put_break(emitter) {
+						return false
+					}
+				}
+			}
+			if !write_break(emitter, value, &i) {
+				return false
+			}
+			//emitter.indention = true
+			breaks = true
+		} else {
+			if breaks {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				leading_spaces = is_blank(value, i)
+			}
+			if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width {
+				if !yaml_emitter_write_indent(emitter) {
+					return false
+				}
+				i += width(value[i])
+			} else {
+				if !write(emitter, value, &i) {
+					return false
+				}
+			}
+			emitter.indention = false
+			breaks = false
+		}
+	}
+	return true
+}
+
+func yaml_emitter_write_comment(emitter *yaml_emitter_t, comment []byte) bool {
+	breaks := false
+	pound := false
+	for i := 0; i < len(comment); {
+		if is_break(comment, i) {
+			if !write_break(emitter, comment, &i) {
+				return false
+			}
+			//emitter.indention = true
+			breaks = true
+			pound = false
+		} else {
+			if breaks && !yaml_emitter_write_indent(emitter) {
+				return false
+			}
+			if !pound {
+				if comment[i] != '#' && (!put(emitter, '#') || !put(emitter, ' ')) {
+					return false
+				}
+				pound = true
+			}
+			if !write(emitter, comment, &i) {
+				return false
+			}
+			emitter.indention = false
+			breaks = false
+		}
+	}
+	if !breaks && !put_break(emitter) {
+		return false
+	}
+
+	emitter.whitespace = true
+	//emitter.indention = true
+	return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/encode.go b/vendor/gopkg.in/yaml.v3/encode.go
new file mode 100644
index 000000000..de9e72a3e
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/encode.go
@@ -0,0 +1,577 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// 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 yaml
+
+import (
+	"encoding"
+	"fmt"
+	"io"
+	"reflect"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+	"unicode/utf8"
+)
+
+type encoder struct {
+	emitter  yaml_emitter_t
+	event    yaml_event_t
+	out      []byte
+	flow     bool
+	indent   int
+	doneInit bool
+}
+
+func newEncoder() *encoder {
+	e := &encoder{}
+	yaml_emitter_initialize(&e.emitter)
+	yaml_emitter_set_output_string(&e.emitter, &e.out)
+	yaml_emitter_set_unicode(&e.emitter, true)
+	return e
+}
+
+func newEncoderWithWriter(w io.Writer) *encoder {
+	e := &encoder{}
+	yaml_emitter_initialize(&e.emitter)
+	yaml_emitter_set_output_writer(&e.emitter, w)
+	yaml_emitter_set_unicode(&e.emitter, true)
+	return e
+}
+
+func (e *encoder) init() {
+	if e.doneInit {
+		return
+	}
+	if e.indent == 0 {
+		e.indent = 4
+	}
+	e.emitter.best_indent = e.indent
+	yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
+	e.emit()
+	e.doneInit = true
+}
+
+func (e *encoder) finish() {
+	e.emitter.open_ended = false
+	yaml_stream_end_event_initialize(&e.event)
+	e.emit()
+}
+
+func (e *encoder) destroy() {
+	yaml_emitter_delete(&e.emitter)
+}
+
+func (e *encoder) emit() {
+	// This will internally delete the e.event value.
+	e.must(yaml_emitter_emit(&e.emitter, &e.event))
+}
+
+func (e *encoder) must(ok bool) {
+	if !ok {
+		msg := e.emitter.problem
+		if msg == "" {
+			msg = "unknown problem generating YAML content"
+		}
+		failf("%s", msg)
+	}
+}
+
+func (e *encoder) marshalDoc(tag string, in reflect.Value) {
+	e.init()
+	var node *Node
+	if in.IsValid() {
+		node, _ = in.Interface().(*Node)
+	}
+	if node != nil && node.Kind == DocumentNode {
+		e.nodev(in)
+	} else {
+		yaml_document_start_event_initialize(&e.event, nil, nil, true)
+		e.emit()
+		e.marshal(tag, in)
+		yaml_document_end_event_initialize(&e.event, true)
+		e.emit()
+	}
+}
+
+func (e *encoder) marshal(tag string, in reflect.Value) {
+	tag = shortTag(tag)
+	if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
+		e.nilv()
+		return
+	}
+	iface := in.Interface()
+	switch value := iface.(type) {
+	case *Node:
+		e.nodev(in)
+		return
+	case Node:
+		if !in.CanAddr() {
+			var n = reflect.New(in.Type()).Elem()
+			n.Set(in)
+			in = n
+		}
+		e.nodev(in.Addr())
+		return
+	case time.Time:
+		e.timev(tag, in)
+		return
+	case *time.Time:
+		e.timev(tag, in.Elem())
+		return
+	case time.Duration:
+		e.stringv(tag, reflect.ValueOf(value.String()))
+		return
+	case Marshaler:
+		v, err := value.MarshalYAML()
+		if err != nil {
+			fail(err)
+		}
+		if v == nil {
+			e.nilv()
+			return
+		}
+		e.marshal(tag, reflect.ValueOf(v))
+		return
+	case encoding.TextMarshaler:
+		text, err := value.MarshalText()
+		if err != nil {
+			fail(err)
+		}
+		in = reflect.ValueOf(string(text))
+	case nil:
+		e.nilv()
+		return
+	}
+	switch in.Kind() {
+	case reflect.Interface:
+		e.marshal(tag, in.Elem())
+	case reflect.Map:
+		e.mapv(tag, in)
+	case reflect.Ptr:
+		e.marshal(tag, in.Elem())
+	case reflect.Struct:
+		e.structv(tag, in)
+	case reflect.Slice, reflect.Array:
+		e.slicev(tag, in)
+	case reflect.String:
+		e.stringv(tag, in)
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		e.intv(tag, in)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		e.uintv(tag, in)
+	case reflect.Float32, reflect.Float64:
+		e.floatv(tag, in)
+	case reflect.Bool:
+		e.boolv(tag, in)
+	default:
+		panic("cannot marshal type: " + in.Type().String())
+	}
+}
+
+func (e *encoder) mapv(tag string, in reflect.Value) {
+	e.mappingv(tag, func() {
+		keys := keyList(in.MapKeys())
+		sort.Sort(keys)
+		for _, k := range keys {
+			e.marshal("", k)
+			e.marshal("", in.MapIndex(k))
+		}
+	})
+}
+
+func (e *encoder) fieldByIndex(v reflect.Value, index []int) (field reflect.Value) {
+	for _, num := range index {
+		for {
+			if v.Kind() == reflect.Ptr {
+				if v.IsNil() {
+					return reflect.Value{}
+				}
+				v = v.Elem()
+				continue
+			}
+			break
+		}
+		v = v.Field(num)
+	}
+	return v
+}
+
+func (e *encoder) structv(tag string, in reflect.Value) {
+	sinfo, err := getStructInfo(in.Type())
+	if err != nil {
+		panic(err)
+	}
+	e.mappingv(tag, func() {
+		for _, info := range sinfo.FieldsList {
+			var value reflect.Value
+			if info.Inline == nil {
+				value = in.Field(info.Num)
+			} else {
+				value = e.fieldByIndex(in, info.Inline)
+				if !value.IsValid() {
+					continue
+				}
+			}
+			if info.OmitEmpty && isZero(value) {
+				continue
+			}
+			e.marshal("", reflect.ValueOf(info.Key))
+			e.flow = info.Flow
+			e.marshal("", value)
+		}
+		if sinfo.InlineMap >= 0 {
+			m := in.Field(sinfo.InlineMap)
+			if m.Len() > 0 {
+				e.flow = false
+				keys := keyList(m.MapKeys())
+				sort.Sort(keys)
+				for _, k := range keys {
+					if _, found := sinfo.FieldsMap[k.String()]; found {
+						panic(fmt.Sprintf("cannot have key %q in inlined map: conflicts with struct field", k.String()))
+					}
+					e.marshal("", k)
+					e.flow = false
+					e.marshal("", m.MapIndex(k))
+				}
+			}
+		}
+	})
+}
+
+func (e *encoder) mappingv(tag string, f func()) {
+	implicit := tag == ""
+	style := yaml_BLOCK_MAPPING_STYLE
+	if e.flow {
+		e.flow = false
+		style = yaml_FLOW_MAPPING_STYLE
+	}
+	yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
+	e.emit()
+	f()
+	yaml_mapping_end_event_initialize(&e.event)
+	e.emit()
+}
+
+func (e *encoder) slicev(tag string, in reflect.Value) {
+	implicit := tag == ""
+	style := yaml_BLOCK_SEQUENCE_STYLE
+	if e.flow {
+		e.flow = false
+		style = yaml_FLOW_SEQUENCE_STYLE
+	}
+	e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
+	e.emit()
+	n := in.Len()
+	for i := 0; i < n; i++ {
+		e.marshal("", in.Index(i))
+	}
+	e.must(yaml_sequence_end_event_initialize(&e.event))
+	e.emit()
+}
+
+// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
+//
+// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
+// in YAML 1.2 and by this package, but these should be marshalled quoted for
+// the time being for compatibility with other parsers.
+func isBase60Float(s string) (result bool) {
+	// Fast path.
+	if s == "" {
+		return false
+	}
+	c := s[0]
+	if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
+		return false
+	}
+	// Do the full match.
+	return base60float.MatchString(s)
+}
+
+// From http://yaml.org/type/float.html, except the regular expression there
+// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
+var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
+
+// isOldBool returns whether s is bool notation as defined in YAML 1.1.
+//
+// We continue to force strings that YAML 1.1 would interpret as booleans to be
+// rendered as quotes strings so that the marshalled output valid for YAML 1.1
+// parsing.
+func isOldBool(s string) (result bool) {
+	switch s {
+	case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON",
+		"n", "N", "no", "No", "NO", "off", "Off", "OFF":
+		return true
+	default:
+		return false
+	}
+}
+
+func (e *encoder) stringv(tag string, in reflect.Value) {
+	var style yaml_scalar_style_t
+	s := in.String()
+	canUsePlain := true
+	switch {
+	case !utf8.ValidString(s):
+		if tag == binaryTag {
+			failf("explicitly tagged !!binary data must be base64-encoded")
+		}
+		if tag != "" {
+			failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
+		}
+		// It can't be encoded directly as YAML so use a binary tag
+		// and encode it as base64.
+		tag = binaryTag
+		s = encodeBase64(s)
+	case tag == "":
+		// Check to see if it would resolve to a specific
+		// tag when encoded unquoted. If it doesn't,
+		// there's no need to quote it.
+		rtag, _ := resolve("", s)
+		canUsePlain = rtag == strTag && !(isBase60Float(s) || isOldBool(s))
+	}
+	// Note: it's possible for user code to emit invalid YAML
+	// if they explicitly specify a tag and a string containing
+	// text that's incompatible with that tag.
+	switch {
+	case strings.Contains(s, "\n"):
+		if e.flow {
+			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+		} else {
+			style = yaml_LITERAL_SCALAR_STYLE
+		}
+	case canUsePlain:
+		style = yaml_PLAIN_SCALAR_STYLE
+	default:
+		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+	}
+	e.emitScalar(s, "", tag, style, nil, nil, nil, nil)
+}
+
+func (e *encoder) boolv(tag string, in reflect.Value) {
+	var s string
+	if in.Bool() {
+		s = "true"
+	} else {
+		s = "false"
+	}
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
+}
+
+func (e *encoder) intv(tag string, in reflect.Value) {
+	s := strconv.FormatInt(in.Int(), 10)
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
+}
+
+func (e *encoder) uintv(tag string, in reflect.Value) {
+	s := strconv.FormatUint(in.Uint(), 10)
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
+}
+
+func (e *encoder) timev(tag string, in reflect.Value) {
+	t := in.Interface().(time.Time)
+	s := t.Format(time.RFC3339Nano)
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
+}
+
+func (e *encoder) floatv(tag string, in reflect.Value) {
+	// Issue #352: When formatting, use the precision of the underlying value
+	precision := 64
+	if in.Kind() == reflect.Float32 {
+		precision = 32
+	}
+
+	s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
+	switch s {
+	case "+Inf":
+		s = ".inf"
+	case "-Inf":
+		s = "-.inf"
+	case "NaN":
+		s = ".nan"
+	}
+	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
+}
+
+func (e *encoder) nilv() {
+	e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
+}
+
+func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot, tail []byte) {
+	// TODO Kill this function. Replace all initialize calls by their underlining Go literals.
+	implicit := tag == ""
+	if !implicit {
+		tag = longTag(tag)
+	}
+	e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
+	e.event.head_comment = head
+	e.event.line_comment = line
+	e.event.foot_comment = foot
+	e.event.tail_comment = tail
+	e.emit()
+}
+
+func (e *encoder) nodev(in reflect.Value) {
+	e.node(in.Interface().(*Node), "")
+}
+
+func (e *encoder) node(node *Node, tail string) {
+	// Zero nodes behave as nil.
+	if node.Kind == 0 && node.IsZero() {
+		e.nilv()
+		return
+	}
+
+	// If the tag was not explicitly requested, and dropping it won't change the
+	// implicit tag of the value, don't include it in the presentation.
+	var tag = node.Tag
+	var stag = shortTag(tag)
+	var forceQuoting bool
+	if tag != "" && node.Style&TaggedStyle == 0 {
+		if node.Kind == ScalarNode {
+			if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 {
+				tag = ""
+			} else {
+				rtag, _ := resolve("", node.Value)
+				if rtag == stag {
+					tag = ""
+				} else if stag == strTag {
+					tag = ""
+					forceQuoting = true
+				}
+			}
+		} else {
+			var rtag string
+			switch node.Kind {
+			case MappingNode:
+				rtag = mapTag
+			case SequenceNode:
+				rtag = seqTag
+			}
+			if rtag == stag {
+				tag = ""
+			}
+		}
+	}
+
+	switch node.Kind {
+	case DocumentNode:
+		yaml_document_start_event_initialize(&e.event, nil, nil, true)
+		e.event.head_comment = []byte(node.HeadComment)
+		e.emit()
+		for _, node := range node.Content {
+			e.node(node, "")
+		}
+		yaml_document_end_event_initialize(&e.event, true)
+		e.event.foot_comment = []byte(node.FootComment)
+		e.emit()
+
+	case SequenceNode:
+		style := yaml_BLOCK_SEQUENCE_STYLE
+		if node.Style&FlowStyle != 0 {
+			style = yaml_FLOW_SEQUENCE_STYLE
+		}
+		e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style))
+		e.event.head_comment = []byte(node.HeadComment)
+		e.emit()
+		for _, node := range node.Content {
+			e.node(node, "")
+		}
+		e.must(yaml_sequence_end_event_initialize(&e.event))
+		e.event.line_comment = []byte(node.LineComment)
+		e.event.foot_comment = []byte(node.FootComment)
+		e.emit()
+
+	case MappingNode:
+		style := yaml_BLOCK_MAPPING_STYLE
+		if node.Style&FlowStyle != 0 {
+			style = yaml_FLOW_MAPPING_STYLE
+		}
+		yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style)
+		e.event.tail_comment = []byte(tail)
+		e.event.head_comment = []byte(node.HeadComment)
+		e.emit()
+
+		// The tail logic below moves the foot comment of prior keys to the following key,
+		// since the value for each key may be a nested structure and the foot needs to be
+		// processed only the entirety of the value is streamed. The last tail is processed
+		// with the mapping end event.
+		var tail string
+		for i := 0; i+1 < len(node.Content); i += 2 {
+			k := node.Content[i]
+			foot := k.FootComment
+			if foot != "" {
+				kopy := *k
+				kopy.FootComment = ""
+				k = &kopy
+			}
+			e.node(k, tail)
+			tail = foot
+
+			v := node.Content[i+1]
+			e.node(v, "")
+		}
+
+		yaml_mapping_end_event_initialize(&e.event)
+		e.event.tail_comment = []byte(tail)
+		e.event.line_comment = []byte(node.LineComment)
+		e.event.foot_comment = []byte(node.FootComment)
+		e.emit()
+
+	case AliasNode:
+		yaml_alias_event_initialize(&e.event, []byte(node.Value))
+		e.event.head_comment = []byte(node.HeadComment)
+		e.event.line_comment = []byte(node.LineComment)
+		e.event.foot_comment = []byte(node.FootComment)
+		e.emit()
+
+	case ScalarNode:
+		value := node.Value
+		if !utf8.ValidString(value) {
+			if stag == binaryTag {
+				failf("explicitly tagged !!binary data must be base64-encoded")
+			}
+			if stag != "" {
+				failf("cannot marshal invalid UTF-8 data as %s", stag)
+			}
+			// It can't be encoded directly as YAML so use a binary tag
+			// and encode it as base64.
+			tag = binaryTag
+			value = encodeBase64(value)
+		}
+
+		style := yaml_PLAIN_SCALAR_STYLE
+		switch {
+		case node.Style&DoubleQuotedStyle != 0:
+			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+		case node.Style&SingleQuotedStyle != 0:
+			style = yaml_SINGLE_QUOTED_SCALAR_STYLE
+		case node.Style&LiteralStyle != 0:
+			style = yaml_LITERAL_SCALAR_STYLE
+		case node.Style&FoldedStyle != 0:
+			style = yaml_FOLDED_SCALAR_STYLE
+		case strings.Contains(value, "\n"):
+			style = yaml_LITERAL_SCALAR_STYLE
+		case forceQuoting:
+			style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+		}
+
+		e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail))
+	default:
+		failf("cannot encode node with unknown kind %d", node.Kind)
+	}
+}
diff --git a/vendor/gopkg.in/yaml.v3/parserc.go b/vendor/gopkg.in/yaml.v3/parserc.go
new file mode 100644
index 000000000..268558a0d
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/parserc.go
@@ -0,0 +1,1258 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+	"bytes"
+)
+
+// The parser implements the following grammar:
+//
+// stream               ::= STREAM-START implicit_document? explicit_document* STREAM-END
+// implicit_document    ::= block_node DOCUMENT-END*
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+// block_node_or_indentless_sequence    ::=
+//                          ALIAS
+//                          | properties (block_content | indentless_block_sequence)?
+//                          | block_content
+//                          | indentless_block_sequence
+// block_node           ::= ALIAS
+//                          | properties block_content?
+//                          | block_content
+// flow_node            ::= ALIAS
+//                          | properties flow_content?
+//                          | flow_content
+// properties           ::= TAG ANCHOR? | ANCHOR TAG?
+// block_content        ::= block_collection | flow_collection | SCALAR
+// flow_content         ::= flow_collection | SCALAR
+// block_collection     ::= block_sequence | block_mapping
+// flow_collection      ::= flow_sequence | flow_mapping
+// block_sequence       ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+// indentless_sequence  ::= (BLOCK-ENTRY block_node?)+
+// block_mapping        ::= BLOCK-MAPPING_START
+//                          ((KEY block_node_or_indentless_sequence?)?
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//                          BLOCK-END
+// flow_sequence        ::= FLOW-SEQUENCE-START
+//                          (flow_sequence_entry FLOW-ENTRY)*
+//                          flow_sequence_entry?
+//                          FLOW-SEQUENCE-END
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+// flow_mapping         ::= FLOW-MAPPING-START
+//                          (flow_mapping_entry FLOW-ENTRY)*
+//                          flow_mapping_entry?
+//                          FLOW-MAPPING-END
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+
+// Peek the next token in the token queue.
+func peek_token(parser *yaml_parser_t) *yaml_token_t {
+	if parser.token_available || yaml_parser_fetch_more_tokens(parser) {
+		token := &parser.tokens[parser.tokens_head]
+		yaml_parser_unfold_comments(parser, token)
+		return token
+	}
+	return nil
+}
+
+// yaml_parser_unfold_comments walks through the comments queue and joins all
+// comments behind the position of the provided token into the respective
+// top-level comment slices in the parser.
+func yaml_parser_unfold_comments(parser *yaml_parser_t, token *yaml_token_t) {
+	for parser.comments_head < len(parser.comments) && token.start_mark.index >= parser.comments[parser.comments_head].token_mark.index {
+		comment := &parser.comments[parser.comments_head]
+		if len(comment.head) > 0 {
+			if token.typ == yaml_BLOCK_END_TOKEN {
+				// No heads on ends, so keep comment.head for a follow up token.
+				break
+			}
+			if len(parser.head_comment) > 0 {
+				parser.head_comment = append(parser.head_comment, '\n')
+			}
+			parser.head_comment = append(parser.head_comment, comment.head...)
+		}
+		if len(comment.foot) > 0 {
+			if len(parser.foot_comment) > 0 {
+				parser.foot_comment = append(parser.foot_comment, '\n')
+			}
+			parser.foot_comment = append(parser.foot_comment, comment.foot...)
+		}
+		if len(comment.line) > 0 {
+			if len(parser.line_comment) > 0 {
+				parser.line_comment = append(parser.line_comment, '\n')
+			}
+			parser.line_comment = append(parser.line_comment, comment.line...)
+		}
+		*comment = yaml_comment_t{}
+		parser.comments_head++
+	}
+}
+
+// Remove the next token from the queue (must be called after peek_token).
+func skip_token(parser *yaml_parser_t) {
+	parser.token_available = false
+	parser.tokens_parsed++
+	parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN
+	parser.tokens_head++
+}
+
+// Get the next event.
+func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool {
+	// Erase the event object.
+	*event = yaml_event_t{}
+
+	// No events after the end of the stream or error.
+	if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE {
+		return true
+	}
+
+	// Generate the next event.
+	return yaml_parser_state_machine(parser, event)
+}
+
+// Set parser error.
+func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool {
+	parser.error = yaml_PARSER_ERROR
+	parser.problem = problem
+	parser.problem_mark = problem_mark
+	return false
+}
+
+func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool {
+	parser.error = yaml_PARSER_ERROR
+	parser.context = context
+	parser.context_mark = context_mark
+	parser.problem = problem
+	parser.problem_mark = problem_mark
+	return false
+}
+
+// State dispatcher.
+func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool {
+	//trace("yaml_parser_state_machine", "state:", parser.state.String())
+
+	switch parser.state {
+	case yaml_PARSE_STREAM_START_STATE:
+		return yaml_parser_parse_stream_start(parser, event)
+
+	case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
+		return yaml_parser_parse_document_start(parser, event, true)
+
+	case yaml_PARSE_DOCUMENT_START_STATE:
+		return yaml_parser_parse_document_start(parser, event, false)
+
+	case yaml_PARSE_DOCUMENT_CONTENT_STATE:
+		return yaml_parser_parse_document_content(parser, event)
+
+	case yaml_PARSE_DOCUMENT_END_STATE:
+		return yaml_parser_parse_document_end(parser, event)
+
+	case yaml_PARSE_BLOCK_NODE_STATE:
+		return yaml_parser_parse_node(parser, event, true, false)
+
+	case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
+		return yaml_parser_parse_node(parser, event, true, true)
+
+	case yaml_PARSE_FLOW_NODE_STATE:
+		return yaml_parser_parse_node(parser, event, false, false)
+
+	case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
+		return yaml_parser_parse_block_sequence_entry(parser, event, true)
+
+	case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
+		return yaml_parser_parse_block_sequence_entry(parser, event, false)
+
+	case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
+		return yaml_parser_parse_indentless_sequence_entry(parser, event)
+
+	case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
+		return yaml_parser_parse_block_mapping_key(parser, event, true)
+
+	case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
+		return yaml_parser_parse_block_mapping_key(parser, event, false)
+
+	case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
+		return yaml_parser_parse_block_mapping_value(parser, event)
+
+	case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
+		return yaml_parser_parse_flow_sequence_entry(parser, event, true)
+
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
+		return yaml_parser_parse_flow_sequence_entry(parser, event, false)
+
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
+		return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event)
+
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
+		return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event)
+
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
+		return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event)
+
+	case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
+		return yaml_parser_parse_flow_mapping_key(parser, event, true)
+
+	case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
+		return yaml_parser_parse_flow_mapping_key(parser, event, false)
+
+	case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
+		return yaml_parser_parse_flow_mapping_value(parser, event, false)
+
+	case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
+		return yaml_parser_parse_flow_mapping_value(parser, event, true)
+
+	default:
+		panic("invalid parser state")
+	}
+}
+
+// Parse the production:
+// stream   ::= STREAM-START implicit_document? explicit_document* STREAM-END
+//              ************
+func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ != yaml_STREAM_START_TOKEN {
+		return yaml_parser_set_parser_error(parser, "did not find expected <stream-start>", token.start_mark)
+	}
+	parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE
+	*event = yaml_event_t{
+		typ:        yaml_STREAM_START_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.end_mark,
+		encoding:   token.encoding,
+	}
+	skip_token(parser)
+	return true
+}
+
+// Parse the productions:
+// implicit_document    ::= block_node DOCUMENT-END*
+//                          *
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//                          *************************
+func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool {
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	// Parse extra document end indicators.
+	if !implicit {
+		for token.typ == yaml_DOCUMENT_END_TOKEN {
+			skip_token(parser)
+			token = peek_token(parser)
+			if token == nil {
+				return false
+			}
+		}
+	}
+
+	if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN &&
+		token.typ != yaml_TAG_DIRECTIVE_TOKEN &&
+		token.typ != yaml_DOCUMENT_START_TOKEN &&
+		token.typ != yaml_STREAM_END_TOKEN {
+		// Parse an implicit document.
+		if !yaml_parser_process_directives(parser, nil, nil) {
+			return false
+		}
+		parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
+		parser.state = yaml_PARSE_BLOCK_NODE_STATE
+
+		var head_comment []byte
+		if len(parser.head_comment) > 0 {
+			// [Go] Scan the header comment backwards, and if an empty line is found, break
+			//      the header so the part before the last empty line goes into the
+			//      document header, while the bottom of it goes into a follow up event.
+			for i := len(parser.head_comment) - 1; i > 0; i-- {
+				if parser.head_comment[i] == '\n' {
+					if i == len(parser.head_comment)-1 {
+						head_comment = parser.head_comment[:i]
+						parser.head_comment = parser.head_comment[i+1:]
+						break
+					} else if parser.head_comment[i-1] == '\n' {
+						head_comment = parser.head_comment[:i-1]
+						parser.head_comment = parser.head_comment[i+1:]
+						break
+					}
+				}
+			}
+		}
+
+		*event = yaml_event_t{
+			typ:        yaml_DOCUMENT_START_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+
+			head_comment: head_comment,
+		}
+
+	} else if token.typ != yaml_STREAM_END_TOKEN {
+		// Parse an explicit document.
+		var version_directive *yaml_version_directive_t
+		var tag_directives []yaml_tag_directive_t
+		start_mark := token.start_mark
+		if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) {
+			return false
+		}
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_DOCUMENT_START_TOKEN {
+			yaml_parser_set_parser_error(parser,
+				"did not find expected <document start>", token.start_mark)
+			return false
+		}
+		parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE)
+		parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE
+		end_mark := token.end_mark
+
+		*event = yaml_event_t{
+			typ:               yaml_DOCUMENT_START_EVENT,
+			start_mark:        start_mark,
+			end_mark:          end_mark,
+			version_directive: version_directive,
+			tag_directives:    tag_directives,
+			implicit:          false,
+		}
+		skip_token(parser)
+
+	} else {
+		// Parse the stream end.
+		parser.state = yaml_PARSE_END_STATE
+		*event = yaml_event_t{
+			typ:        yaml_STREAM_END_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+		}
+		skip_token(parser)
+	}
+
+	return true
+}
+
+// Parse the productions:
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//                                                    ***********
+//
+func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ == yaml_VERSION_DIRECTIVE_TOKEN ||
+		token.typ == yaml_TAG_DIRECTIVE_TOKEN ||
+		token.typ == yaml_DOCUMENT_START_TOKEN ||
+		token.typ == yaml_DOCUMENT_END_TOKEN ||
+		token.typ == yaml_STREAM_END_TOKEN {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+		return yaml_parser_process_empty_scalar(parser, event,
+			token.start_mark)
+	}
+	return yaml_parser_parse_node(parser, event, true, false)
+}
+
+// Parse the productions:
+// implicit_document    ::= block_node DOCUMENT-END*
+//                                     *************
+// explicit_document    ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
+//
+func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	start_mark := token.start_mark
+	end_mark := token.start_mark
+
+	implicit := true
+	if token.typ == yaml_DOCUMENT_END_TOKEN {
+		end_mark = token.end_mark
+		skip_token(parser)
+		implicit = false
+	}
+
+	parser.tag_directives = parser.tag_directives[:0]
+
+	parser.state = yaml_PARSE_DOCUMENT_START_STATE
+	*event = yaml_event_t{
+		typ:        yaml_DOCUMENT_END_EVENT,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		implicit:   implicit,
+	}
+	yaml_parser_set_event_comments(parser, event)
+	if len(event.head_comment) > 0 && len(event.foot_comment) == 0 {
+		event.foot_comment = event.head_comment
+		event.head_comment = nil
+	}
+	return true
+}
+
+func yaml_parser_set_event_comments(parser *yaml_parser_t, event *yaml_event_t) {
+	event.head_comment = parser.head_comment
+	event.line_comment = parser.line_comment
+	event.foot_comment = parser.foot_comment
+	parser.head_comment = nil
+	parser.line_comment = nil
+	parser.foot_comment = nil
+	parser.tail_comment = nil
+	parser.stem_comment = nil
+}
+
+// Parse the productions:
+// block_node_or_indentless_sequence    ::=
+//                          ALIAS
+//                          *****
+//                          | properties (block_content | indentless_block_sequence)?
+//                            **********  *
+//                          | block_content | indentless_block_sequence
+//                            *
+// block_node           ::= ALIAS
+//                          *****
+//                          | properties block_content?
+//                            ********** *
+//                          | block_content
+//                            *
+// flow_node            ::= ALIAS
+//                          *****
+//                          | properties flow_content?
+//                            ********** *
+//                          | flow_content
+//                            *
+// properties           ::= TAG ANCHOR? | ANCHOR TAG?
+//                          *************************
+// block_content        ::= block_collection | flow_collection | SCALAR
+//                                                               ******
+// flow_content         ::= flow_collection | SCALAR
+//                                            ******
+func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool {
+	//defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)()
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ == yaml_ALIAS_TOKEN {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+		*event = yaml_event_t{
+			typ:        yaml_ALIAS_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+			anchor:     token.value,
+		}
+		yaml_parser_set_event_comments(parser, event)
+		skip_token(parser)
+		return true
+	}
+
+	start_mark := token.start_mark
+	end_mark := token.start_mark
+
+	var tag_token bool
+	var tag_handle, tag_suffix, anchor []byte
+	var tag_mark yaml_mark_t
+	if token.typ == yaml_ANCHOR_TOKEN {
+		anchor = token.value
+		start_mark = token.start_mark
+		end_mark = token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ == yaml_TAG_TOKEN {
+			tag_token = true
+			tag_handle = token.value
+			tag_suffix = token.suffix
+			tag_mark = token.start_mark
+			end_mark = token.end_mark
+			skip_token(parser)
+			token = peek_token(parser)
+			if token == nil {
+				return false
+			}
+		}
+	} else if token.typ == yaml_TAG_TOKEN {
+		tag_token = true
+		tag_handle = token.value
+		tag_suffix = token.suffix
+		start_mark = token.start_mark
+		tag_mark = token.start_mark
+		end_mark = token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ == yaml_ANCHOR_TOKEN {
+			anchor = token.value
+			end_mark = token.end_mark
+			skip_token(parser)
+			token = peek_token(parser)
+			if token == nil {
+				return false
+			}
+		}
+	}
+
+	var tag []byte
+	if tag_token {
+		if len(tag_handle) == 0 {
+			tag = tag_suffix
+			tag_suffix = nil
+		} else {
+			for i := range parser.tag_directives {
+				if bytes.Equal(parser.tag_directives[i].handle, tag_handle) {
+					tag = append([]byte(nil), parser.tag_directives[i].prefix...)
+					tag = append(tag, tag_suffix...)
+					break
+				}
+			}
+			if len(tag) == 0 {
+				yaml_parser_set_parser_error_context(parser,
+					"while parsing a node", start_mark,
+					"found undefined tag handle", tag_mark)
+				return false
+			}
+		}
+	}
+
+	implicit := len(tag) == 0
+	if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN {
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_SEQUENCE_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
+		}
+		return true
+	}
+	if token.typ == yaml_SCALAR_TOKEN {
+		var plain_implicit, quoted_implicit bool
+		end_mark = token.end_mark
+		if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') {
+			plain_implicit = true
+		} else if len(tag) == 0 {
+			quoted_implicit = true
+		}
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+
+		*event = yaml_event_t{
+			typ:             yaml_SCALAR_EVENT,
+			start_mark:      start_mark,
+			end_mark:        end_mark,
+			anchor:          anchor,
+			tag:             tag,
+			value:           token.value,
+			implicit:        plain_implicit,
+			quoted_implicit: quoted_implicit,
+			style:           yaml_style_t(token.style),
+		}
+		yaml_parser_set_event_comments(parser, event)
+		skip_token(parser)
+		return true
+	}
+	if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN {
+		// [Go] Some of the events below can be merged as they differ only on style.
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_SEQUENCE_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_FLOW_SEQUENCE_STYLE),
+		}
+		yaml_parser_set_event_comments(parser, event)
+		return true
+	}
+	if token.typ == yaml_FLOW_MAPPING_START_TOKEN {
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_MAPPING_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_FLOW_MAPPING_STYLE),
+		}
+		yaml_parser_set_event_comments(parser, event)
+		return true
+	}
+	if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN {
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_SEQUENCE_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE),
+		}
+		if parser.stem_comment != nil {
+			event.head_comment = parser.stem_comment
+			parser.stem_comment = nil
+		}
+		return true
+	}
+	if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN {
+		end_mark = token.end_mark
+		parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE
+		*event = yaml_event_t{
+			typ:        yaml_MAPPING_START_EVENT,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			anchor:     anchor,
+			tag:        tag,
+			implicit:   implicit,
+			style:      yaml_style_t(yaml_BLOCK_MAPPING_STYLE),
+		}
+		if parser.stem_comment != nil {
+			event.head_comment = parser.stem_comment
+			parser.stem_comment = nil
+		}
+		return true
+	}
+	if len(anchor) > 0 || len(tag) > 0 {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+
+		*event = yaml_event_t{
+			typ:             yaml_SCALAR_EVENT,
+			start_mark:      start_mark,
+			end_mark:        end_mark,
+			anchor:          anchor,
+			tag:             tag,
+			implicit:        implicit,
+			quoted_implicit: false,
+			style:           yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
+		}
+		return true
+	}
+
+	context := "while parsing a flow node"
+	if block {
+		context = "while parsing a block node"
+	}
+	yaml_parser_set_parser_error_context(parser, context, start_mark,
+		"did not find expected node content", token.start_mark)
+	return false
+}
+
+// Parse the productions:
+// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
+//                    ********************  *********** *             *********
+//
+func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+	if first {
+		token := peek_token(parser)
+		if token == nil {
+			return false
+		}
+		parser.marks = append(parser.marks, token.start_mark)
+		skip_token(parser)
+	}
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ == yaml_BLOCK_ENTRY_TOKEN {
+		mark := token.end_mark
+		prior_head_len := len(parser.head_comment)
+		skip_token(parser)
+		yaml_parser_split_stem_comment(parser, prior_head_len)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)
+			return yaml_parser_parse_node(parser, event, true, false)
+		} else {
+			parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE
+			return yaml_parser_process_empty_scalar(parser, event, mark)
+		}
+	}
+	if token.typ == yaml_BLOCK_END_TOKEN {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+		parser.marks = parser.marks[:len(parser.marks)-1]
+
+		*event = yaml_event_t{
+			typ:        yaml_SEQUENCE_END_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+		}
+
+		skip_token(parser)
+		return true
+	}
+
+	context_mark := parser.marks[len(parser.marks)-1]
+	parser.marks = parser.marks[:len(parser.marks)-1]
+	return yaml_parser_set_parser_error_context(parser,
+		"while parsing a block collection", context_mark,
+		"did not find expected '-' indicator", token.start_mark)
+}
+
+// Parse the productions:
+// indentless_sequence  ::= (BLOCK-ENTRY block_node?)+
+//                           *********** *
+func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ == yaml_BLOCK_ENTRY_TOKEN {
+		mark := token.end_mark
+		prior_head_len := len(parser.head_comment)
+		skip_token(parser)
+		yaml_parser_split_stem_comment(parser, prior_head_len)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_BLOCK_ENTRY_TOKEN &&
+			token.typ != yaml_KEY_TOKEN &&
+			token.typ != yaml_VALUE_TOKEN &&
+			token.typ != yaml_BLOCK_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)
+			return yaml_parser_parse_node(parser, event, true, false)
+		}
+		parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE
+		return yaml_parser_process_empty_scalar(parser, event, mark)
+	}
+	parser.state = parser.states[len(parser.states)-1]
+	parser.states = parser.states[:len(parser.states)-1]
+
+	*event = yaml_event_t{
+		typ:        yaml_SEQUENCE_END_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.start_mark, // [Go] Shouldn't this be token.end_mark?
+	}
+	return true
+}
+
+// Split stem comment from head comment.
+//
+// When a sequence or map is found under a sequence entry, the former head comment
+// is assigned to the underlying sequence or map as a whole, not the individual
+// sequence or map entry as would be expected otherwise. To handle this case the
+// previous head comment is moved aside as the stem comment.
+func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
+	if stem_len == 0 {
+		return
+	}
+
+	token := peek_token(parser)
+	if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
+		return
+	}
+
+	parser.stem_comment = parser.head_comment[:stem_len]
+	if len(parser.head_comment) == stem_len {
+		parser.head_comment = nil
+	} else {
+		// Copy suffix to prevent very strange bugs if someone ever appends
+		// further bytes to the prefix in the stem_comment slice above.
+		parser.head_comment = append([]byte(nil), parser.head_comment[stem_len+1:]...)
+	}
+}
+
+// Parse the productions:
+// block_mapping        ::= BLOCK-MAPPING_START
+//                          *******************
+//                          ((KEY block_node_or_indentless_sequence?)?
+//                            *** *
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//
+//                          BLOCK-END
+//                          *********
+//
+func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+	if first {
+		token := peek_token(parser)
+		if token == nil {
+			return false
+		}
+		parser.marks = append(parser.marks, token.start_mark)
+		skip_token(parser)
+	}
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	// [Go] A tail comment was left from the prior mapping value processed. Emit an event
+	//      as it needs to be processed with that value and not the following key.
+	if len(parser.tail_comment) > 0 {
+		*event = yaml_event_t{
+			typ:          yaml_TAIL_COMMENT_EVENT,
+			start_mark:   token.start_mark,
+			end_mark:     token.end_mark,
+			foot_comment: parser.tail_comment,
+		}
+		parser.tail_comment = nil
+		return true
+	}
+
+	if token.typ == yaml_KEY_TOKEN {
+		mark := token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_KEY_TOKEN &&
+			token.typ != yaml_VALUE_TOKEN &&
+			token.typ != yaml_BLOCK_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE)
+			return yaml_parser_parse_node(parser, event, true, true)
+		} else {
+			parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE
+			return yaml_parser_process_empty_scalar(parser, event, mark)
+		}
+	} else if token.typ == yaml_BLOCK_END_TOKEN {
+		parser.state = parser.states[len(parser.states)-1]
+		parser.states = parser.states[:len(parser.states)-1]
+		parser.marks = parser.marks[:len(parser.marks)-1]
+		*event = yaml_event_t{
+			typ:        yaml_MAPPING_END_EVENT,
+			start_mark: token.start_mark,
+			end_mark:   token.end_mark,
+		}
+		yaml_parser_set_event_comments(parser, event)
+		skip_token(parser)
+		return true
+	}
+
+	context_mark := parser.marks[len(parser.marks)-1]
+	parser.marks = parser.marks[:len(parser.marks)-1]
+	return yaml_parser_set_parser_error_context(parser,
+		"while parsing a block mapping", context_mark,
+		"did not find expected key", token.start_mark)
+}
+
+// Parse the productions:
+// block_mapping        ::= BLOCK-MAPPING_START
+//
+//                          ((KEY block_node_or_indentless_sequence?)?
+//
+//                          (VALUE block_node_or_indentless_sequence?)?)*
+//                           ***** *
+//                          BLOCK-END
+//
+//
+func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ == yaml_VALUE_TOKEN {
+		mark := token.end_mark
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_KEY_TOKEN &&
+			token.typ != yaml_VALUE_TOKEN &&
+			token.typ != yaml_BLOCK_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE)
+			return yaml_parser_parse_node(parser, event, true, true)
+		}
+		parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
+		return yaml_parser_process_empty_scalar(parser, event, mark)
+	}
+	parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE
+	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Parse the productions:
+// flow_sequence        ::= FLOW-SEQUENCE-START
+//                          *******************
+//                          (flow_sequence_entry FLOW-ENTRY)*
+//                           *                   **********
+//                          flow_sequence_entry?
+//                          *
+//                          FLOW-SEQUENCE-END
+//                          *****************
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                          *
+//
+func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+	if first {
+		token := peek_token(parser)
+		if token == nil {
+			return false
+		}
+		parser.marks = append(parser.marks, token.start_mark)
+		skip_token(parser)
+	}
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+		if !first {
+			if token.typ == yaml_FLOW_ENTRY_TOKEN {
+				skip_token(parser)
+				token = peek_token(parser)
+				if token == nil {
+					return false
+				}
+			} else {
+				context_mark := parser.marks[len(parser.marks)-1]
+				parser.marks = parser.marks[:len(parser.marks)-1]
+				return yaml_parser_set_parser_error_context(parser,
+					"while parsing a flow sequence", context_mark,
+					"did not find expected ',' or ']'", token.start_mark)
+			}
+		}
+
+		if token.typ == yaml_KEY_TOKEN {
+			parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE
+			*event = yaml_event_t{
+				typ:        yaml_MAPPING_START_EVENT,
+				start_mark: token.start_mark,
+				end_mark:   token.end_mark,
+				implicit:   true,
+				style:      yaml_style_t(yaml_FLOW_MAPPING_STYLE),
+			}
+			skip_token(parser)
+			return true
+		} else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE)
+			return yaml_parser_parse_node(parser, event, false, false)
+		}
+	}
+
+	parser.state = parser.states[len(parser.states)-1]
+	parser.states = parser.states[:len(parser.states)-1]
+	parser.marks = parser.marks[:len(parser.marks)-1]
+
+	*event = yaml_event_t{
+		typ:        yaml_SEQUENCE_END_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.end_mark,
+	}
+	yaml_parser_set_event_comments(parser, event)
+
+	skip_token(parser)
+	return true
+}
+
+//
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                      *** *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ != yaml_VALUE_TOKEN &&
+		token.typ != yaml_FLOW_ENTRY_TOKEN &&
+		token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+		parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)
+		return yaml_parser_parse_node(parser, event, false, false)
+	}
+	mark := token.end_mark
+	skip_token(parser)
+	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE
+	return yaml_parser_process_empty_scalar(parser, event, mark)
+}
+
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                                      ***** *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if token.typ == yaml_VALUE_TOKEN {
+		skip_token(parser)
+		token := peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)
+			return yaml_parser_parse_node(parser, event, false, false)
+		}
+	}
+	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE
+	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Parse the productions:
+// flow_sequence_entry  ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                                                      *
+//
+func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE
+	*event = yaml_event_t{
+		typ:        yaml_MAPPING_END_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.start_mark, // [Go] Shouldn't this be end_mark?
+	}
+	return true
+}
+
+// Parse the productions:
+// flow_mapping         ::= FLOW-MAPPING-START
+//                          ******************
+//                          (flow_mapping_entry FLOW-ENTRY)*
+//                           *                  **********
+//                          flow_mapping_entry?
+//                          ******************
+//                          FLOW-MAPPING-END
+//                          ****************
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                          *           *** *
+//
+func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
+	if first {
+		token := peek_token(parser)
+		parser.marks = append(parser.marks, token.start_mark)
+		skip_token(parser)
+	}
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+		if !first {
+			if token.typ == yaml_FLOW_ENTRY_TOKEN {
+				skip_token(parser)
+				token = peek_token(parser)
+				if token == nil {
+					return false
+				}
+			} else {
+				context_mark := parser.marks[len(parser.marks)-1]
+				parser.marks = parser.marks[:len(parser.marks)-1]
+				return yaml_parser_set_parser_error_context(parser,
+					"while parsing a flow mapping", context_mark,
+					"did not find expected ',' or '}'", token.start_mark)
+			}
+		}
+
+		if token.typ == yaml_KEY_TOKEN {
+			skip_token(parser)
+			token = peek_token(parser)
+			if token == nil {
+				return false
+			}
+			if token.typ != yaml_VALUE_TOKEN &&
+				token.typ != yaml_FLOW_ENTRY_TOKEN &&
+				token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+				parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE)
+				return yaml_parser_parse_node(parser, event, false, false)
+			} else {
+				parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE
+				return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+			}
+		} else if token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)
+			return yaml_parser_parse_node(parser, event, false, false)
+		}
+	}
+
+	parser.state = parser.states[len(parser.states)-1]
+	parser.states = parser.states[:len(parser.states)-1]
+	parser.marks = parser.marks[:len(parser.marks)-1]
+	*event = yaml_event_t{
+		typ:        yaml_MAPPING_END_EVENT,
+		start_mark: token.start_mark,
+		end_mark:   token.end_mark,
+	}
+	yaml_parser_set_event_comments(parser, event)
+	skip_token(parser)
+	return true
+}
+
+// Parse the productions:
+// flow_mapping_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
+//                                   *                  ***** *
+//
+func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool {
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+	if empty {
+		parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
+		return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+	}
+	if token.typ == yaml_VALUE_TOKEN {
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+		if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN {
+			parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE)
+			return yaml_parser_parse_node(parser, event, false, false)
+		}
+	}
+	parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE
+	return yaml_parser_process_empty_scalar(parser, event, token.start_mark)
+}
+
+// Generate an empty scalar event.
+func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool {
+	*event = yaml_event_t{
+		typ:        yaml_SCALAR_EVENT,
+		start_mark: mark,
+		end_mark:   mark,
+		value:      nil, // Empty
+		implicit:   true,
+		style:      yaml_style_t(yaml_PLAIN_SCALAR_STYLE),
+	}
+	return true
+}
+
+var default_tag_directives = []yaml_tag_directive_t{
+	{[]byte("!"), []byte("!")},
+	{[]byte("!!"), []byte("tag:yaml.org,2002:")},
+}
+
+// Parse directives.
+func yaml_parser_process_directives(parser *yaml_parser_t,
+	version_directive_ref **yaml_version_directive_t,
+	tag_directives_ref *[]yaml_tag_directive_t) bool {
+
+	var version_directive *yaml_version_directive_t
+	var tag_directives []yaml_tag_directive_t
+
+	token := peek_token(parser)
+	if token == nil {
+		return false
+	}
+
+	for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN {
+		if token.typ == yaml_VERSION_DIRECTIVE_TOKEN {
+			if version_directive != nil {
+				yaml_parser_set_parser_error(parser,
+					"found duplicate %YAML directive", token.start_mark)
+				return false
+			}
+			if token.major != 1 || token.minor != 1 {
+				yaml_parser_set_parser_error(parser,
+					"found incompatible YAML document", token.start_mark)
+				return false
+			}
+			version_directive = &yaml_version_directive_t{
+				major: token.major,
+				minor: token.minor,
+			}
+		} else if token.typ == yaml_TAG_DIRECTIVE_TOKEN {
+			value := yaml_tag_directive_t{
+				handle: token.value,
+				prefix: token.prefix,
+			}
+			if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) {
+				return false
+			}
+			tag_directives = append(tag_directives, value)
+		}
+
+		skip_token(parser)
+		token = peek_token(parser)
+		if token == nil {
+			return false
+		}
+	}
+
+	for i := range default_tag_directives {
+		if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) {
+			return false
+		}
+	}
+
+	if version_directive_ref != nil {
+		*version_directive_ref = version_directive
+	}
+	if tag_directives_ref != nil {
+		*tag_directives_ref = tag_directives
+	}
+	return true
+}
+
+// Append a tag directive to the directives stack.
+func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool {
+	for i := range parser.tag_directives {
+		if bytes.Equal(value.handle, parser.tag_directives[i].handle) {
+			if allow_duplicates {
+				return true
+			}
+			return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark)
+		}
+	}
+
+	// [Go] I suspect the copy is unnecessary. This was likely done
+	// because there was no way to track ownership of the data.
+	value_copy := yaml_tag_directive_t{
+		handle: make([]byte, len(value.handle)),
+		prefix: make([]byte, len(value.prefix)),
+	}
+	copy(value_copy.handle, value.handle)
+	copy(value_copy.prefix, value.prefix)
+	parser.tag_directives = append(parser.tag_directives, value_copy)
+	return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/readerc.go b/vendor/gopkg.in/yaml.v3/readerc.go
new file mode 100644
index 000000000..b7de0a89c
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/readerc.go
@@ -0,0 +1,434 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+	"io"
+)
+
+// Set the reader error and return 0.
+func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
+	parser.error = yaml_READER_ERROR
+	parser.problem = problem
+	parser.problem_offset = offset
+	parser.problem_value = value
+	return false
+}
+
+// Byte order marks.
+const (
+	bom_UTF8    = "\xef\xbb\xbf"
+	bom_UTF16LE = "\xff\xfe"
+	bom_UTF16BE = "\xfe\xff"
+)
+
+// Determine the input stream encoding by checking the BOM symbol. If no BOM is
+// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
+func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
+	// Ensure that we had enough bytes in the raw buffer.
+	for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
+		if !yaml_parser_update_raw_buffer(parser) {
+			return false
+		}
+	}
+
+	// Determine the encoding.
+	buf := parser.raw_buffer
+	pos := parser.raw_buffer_pos
+	avail := len(buf) - pos
+	if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
+		parser.encoding = yaml_UTF16LE_ENCODING
+		parser.raw_buffer_pos += 2
+		parser.offset += 2
+	} else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
+		parser.encoding = yaml_UTF16BE_ENCODING
+		parser.raw_buffer_pos += 2
+		parser.offset += 2
+	} else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
+		parser.encoding = yaml_UTF8_ENCODING
+		parser.raw_buffer_pos += 3
+		parser.offset += 3
+	} else {
+		parser.encoding = yaml_UTF8_ENCODING
+	}
+	return true
+}
+
+// Update the raw buffer.
+func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
+	size_read := 0
+
+	// Return if the raw buffer is full.
+	if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
+		return true
+	}
+
+	// Return on EOF.
+	if parser.eof {
+		return true
+	}
+
+	// Move the remaining bytes in the raw buffer to the beginning.
+	if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
+		copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
+	}
+	parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
+	parser.raw_buffer_pos = 0
+
+	// Call the read handler to fill the buffer.
+	size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
+	parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
+	if err == io.EOF {
+		parser.eof = true
+	} else if err != nil {
+		return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
+	}
+	return true
+}
+
+// Ensure that the buffer contains at least `length` characters.
+// Return true on success, false on failure.
+//
+// The length is supposed to be significantly less that the buffer size.
+func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
+	if parser.read_handler == nil {
+		panic("read handler must be set")
+	}
+
+	// [Go] This function was changed to guarantee the requested length size at EOF.
+	// The fact we need to do this is pretty awful, but the description above implies
+	// for that to be the case, and there are tests
+
+	// If the EOF flag is set and the raw buffer is empty, do nothing.
+	if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
+		// [Go] ACTUALLY! Read the documentation of this function above.
+		// This is just broken. To return true, we need to have the
+		// given length in the buffer. Not doing that means every single
+		// check that calls this function to make sure the buffer has a
+		// given length is Go) panicking; or C) accessing invalid memory.
+		//return true
+	}
+
+	// Return if the buffer contains enough characters.
+	if parser.unread >= length {
+		return true
+	}
+
+	// Determine the input encoding if it is not known yet.
+	if parser.encoding == yaml_ANY_ENCODING {
+		if !yaml_parser_determine_encoding(parser) {
+			return false
+		}
+	}
+
+	// Move the unread characters to the beginning of the buffer.
+	buffer_len := len(parser.buffer)
+	if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
+		copy(parser.buffer, parser.buffer[parser.buffer_pos:])
+		buffer_len -= parser.buffer_pos
+		parser.buffer_pos = 0
+	} else if parser.buffer_pos == buffer_len {
+		buffer_len = 0
+		parser.buffer_pos = 0
+	}
+
+	// Open the whole buffer for writing, and cut it before returning.
+	parser.buffer = parser.buffer[:cap(parser.buffer)]
+
+	// Fill the buffer until it has enough characters.
+	first := true
+	for parser.unread < length {
+
+		// Fill the raw buffer if necessary.
+		if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
+			if !yaml_parser_update_raw_buffer(parser) {
+				parser.buffer = parser.buffer[:buffer_len]
+				return false
+			}
+		}
+		first = false
+
+		// Decode the raw buffer.
+	inner:
+		for parser.raw_buffer_pos != len(parser.raw_buffer) {
+			var value rune
+			var width int
+
+			raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
+
+			// Decode the next character.
+			switch parser.encoding {
+			case yaml_UTF8_ENCODING:
+				// Decode a UTF-8 character.  Check RFC 3629
+				// (http://www.ietf.org/rfc/rfc3629.txt) for more details.
+				//
+				// The following table (taken from the RFC) is used for
+				// decoding.
+				//
+				//    Char. number range |        UTF-8 octet sequence
+				//      (hexadecimal)    |              (binary)
+				//   --------------------+------------------------------------
+				//   0000 0000-0000 007F | 0xxxxxxx
+				//   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+				//   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+				//   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+				//
+				// Additionally, the characters in the range 0xD800-0xDFFF
+				// are prohibited as they are reserved for use with UTF-16
+				// surrogate pairs.
+
+				// Determine the length of the UTF-8 sequence.
+				octet := parser.raw_buffer[parser.raw_buffer_pos]
+				switch {
+				case octet&0x80 == 0x00:
+					width = 1
+				case octet&0xE0 == 0xC0:
+					width = 2
+				case octet&0xF0 == 0xE0:
+					width = 3
+				case octet&0xF8 == 0xF0:
+					width = 4
+				default:
+					// The leading octet is invalid.
+					return yaml_parser_set_reader_error(parser,
+						"invalid leading UTF-8 octet",
+						parser.offset, int(octet))
+				}
+
+				// Check if the raw buffer contains an incomplete character.
+				if width > raw_unread {
+					if parser.eof {
+						return yaml_parser_set_reader_error(parser,
+							"incomplete UTF-8 octet sequence",
+							parser.offset, -1)
+					}
+					break inner
+				}
+
+				// Decode the leading octet.
+				switch {
+				case octet&0x80 == 0x00:
+					value = rune(octet & 0x7F)
+				case octet&0xE0 == 0xC0:
+					value = rune(octet & 0x1F)
+				case octet&0xF0 == 0xE0:
+					value = rune(octet & 0x0F)
+				case octet&0xF8 == 0xF0:
+					value = rune(octet & 0x07)
+				default:
+					value = 0
+				}
+
+				// Check and decode the trailing octets.
+				for k := 1; k < width; k++ {
+					octet = parser.raw_buffer[parser.raw_buffer_pos+k]
+
+					// Check if the octet is valid.
+					if (octet & 0xC0) != 0x80 {
+						return yaml_parser_set_reader_error(parser,
+							"invalid trailing UTF-8 octet",
+							parser.offset+k, int(octet))
+					}
+
+					// Decode the octet.
+					value = (value << 6) + rune(octet&0x3F)
+				}
+
+				// Check the length of the sequence against the value.
+				switch {
+				case width == 1:
+				case width == 2 && value >= 0x80:
+				case width == 3 && value >= 0x800:
+				case width == 4 && value >= 0x10000:
+				default:
+					return yaml_parser_set_reader_error(parser,
+						"invalid length of a UTF-8 sequence",
+						parser.offset, -1)
+				}
+
+				// Check the range of the value.
+				if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
+					return yaml_parser_set_reader_error(parser,
+						"invalid Unicode character",
+						parser.offset, int(value))
+				}
+
+			case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
+				var low, high int
+				if parser.encoding == yaml_UTF16LE_ENCODING {
+					low, high = 0, 1
+				} else {
+					low, high = 1, 0
+				}
+
+				// The UTF-16 encoding is not as simple as one might
+				// naively think.  Check RFC 2781
+				// (http://www.ietf.org/rfc/rfc2781.txt).
+				//
+				// Normally, two subsequent bytes describe a Unicode
+				// character.  However a special technique (called a
+				// surrogate pair) is used for specifying character
+				// values larger than 0xFFFF.
+				//
+				// A surrogate pair consists of two pseudo-characters:
+				//      high surrogate area (0xD800-0xDBFF)
+				//      low surrogate area (0xDC00-0xDFFF)
+				//
+				// The following formulas are used for decoding
+				// and encoding characters using surrogate pairs:
+				//
+				//  U  = U' + 0x10000   (0x01 00 00 <= U <= 0x10 FF FF)
+				//  U' = yyyyyyyyyyxxxxxxxxxx   (0 <= U' <= 0x0F FF FF)
+				//  W1 = 110110yyyyyyyyyy
+				//  W2 = 110111xxxxxxxxxx
+				//
+				// where U is the character value, W1 is the high surrogate
+				// area, W2 is the low surrogate area.
+
+				// Check for incomplete UTF-16 character.
+				if raw_unread < 2 {
+					if parser.eof {
+						return yaml_parser_set_reader_error(parser,
+							"incomplete UTF-16 character",
+							parser.offset, -1)
+					}
+					break inner
+				}
+
+				// Get the character.
+				value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
+					(rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
+
+				// Check for unexpected low surrogate area.
+				if value&0xFC00 == 0xDC00 {
+					return yaml_parser_set_reader_error(parser,
+						"unexpected low surrogate area",
+						parser.offset, int(value))
+				}
+
+				// Check for a high surrogate area.
+				if value&0xFC00 == 0xD800 {
+					width = 4
+
+					// Check for incomplete surrogate pair.
+					if raw_unread < 4 {
+						if parser.eof {
+							return yaml_parser_set_reader_error(parser,
+								"incomplete UTF-16 surrogate pair",
+								parser.offset, -1)
+						}
+						break inner
+					}
+
+					// Get the next character.
+					value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
+						(rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
+
+					// Check for a low surrogate area.
+					if value2&0xFC00 != 0xDC00 {
+						return yaml_parser_set_reader_error(parser,
+							"expected low surrogate area",
+							parser.offset+2, int(value2))
+					}
+
+					// Generate the value of the surrogate pair.
+					value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
+				} else {
+					width = 2
+				}
+
+			default:
+				panic("impossible")
+			}
+
+			// Check if the character is in the allowed range:
+			//      #x9 | #xA | #xD | [#x20-#x7E]               (8 bit)
+			//      | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD]    (16 bit)
+			//      | [#x10000-#x10FFFF]                        (32 bit)
+			switch {
+			case value == 0x09:
+			case value == 0x0A:
+			case value == 0x0D:
+			case value >= 0x20 && value <= 0x7E:
+			case value == 0x85:
+			case value >= 0xA0 && value <= 0xD7FF:
+			case value >= 0xE000 && value <= 0xFFFD:
+			case value >= 0x10000 && value <= 0x10FFFF:
+			default:
+				return yaml_parser_set_reader_error(parser,
+					"control characters are not allowed",
+					parser.offset, int(value))
+			}
+
+			// Move the raw pointers.
+			parser.raw_buffer_pos += width
+			parser.offset += width
+
+			// Finally put the character into the buffer.
+			if value <= 0x7F {
+				// 0000 0000-0000 007F . 0xxxxxxx
+				parser.buffer[buffer_len+0] = byte(value)
+				buffer_len += 1
+			} else if value <= 0x7FF {
+				// 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
+				parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
+				parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
+				buffer_len += 2
+			} else if value <= 0xFFFF {
+				// 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
+				parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
+				parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
+				parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
+				buffer_len += 3
+			} else {
+				// 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+				parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
+				parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
+				parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
+				parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
+				buffer_len += 4
+			}
+
+			parser.unread++
+		}
+
+		// On EOF, put NUL into the buffer and return.
+		if parser.eof {
+			parser.buffer[buffer_len] = 0
+			buffer_len++
+			parser.unread++
+			break
+		}
+	}
+	// [Go] Read the documentation of this function above. To return true,
+	// we need to have the given length in the buffer. Not doing that means
+	// every single check that calls this function to make sure the buffer
+	// has a given length is Go) panicking; or C) accessing invalid memory.
+	// This happens here due to the EOF above breaking early.
+	for buffer_len < length {
+		parser.buffer[buffer_len] = 0
+		buffer_len++
+	}
+	parser.buffer = parser.buffer[:buffer_len]
+	return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/resolve.go b/vendor/gopkg.in/yaml.v3/resolve.go
new file mode 100644
index 000000000..64ae88805
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/resolve.go
@@ -0,0 +1,326 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// 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 yaml
+
+import (
+	"encoding/base64"
+	"math"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type resolveMapItem struct {
+	value interface{}
+	tag   string
+}
+
+var resolveTable = make([]byte, 256)
+var resolveMap = make(map[string]resolveMapItem)
+
+func init() {
+	t := resolveTable
+	t[int('+')] = 'S' // Sign
+	t[int('-')] = 'S'
+	for _, c := range "0123456789" {
+		t[int(c)] = 'D' // Digit
+	}
+	for _, c := range "yYnNtTfFoO~" {
+		t[int(c)] = 'M' // In map
+	}
+	t[int('.')] = '.' // Float (potentially in map)
+
+	var resolveMapList = []struct {
+		v   interface{}
+		tag string
+		l   []string
+	}{
+		{true, boolTag, []string{"true", "True", "TRUE"}},
+		{false, boolTag, []string{"false", "False", "FALSE"}},
+		{nil, nullTag, []string{"", "~", "null", "Null", "NULL"}},
+		{math.NaN(), floatTag, []string{".nan", ".NaN", ".NAN"}},
+		{math.Inf(+1), floatTag, []string{".inf", ".Inf", ".INF"}},
+		{math.Inf(+1), floatTag, []string{"+.inf", "+.Inf", "+.INF"}},
+		{math.Inf(-1), floatTag, []string{"-.inf", "-.Inf", "-.INF"}},
+		{"<<", mergeTag, []string{"<<"}},
+	}
+
+	m := resolveMap
+	for _, item := range resolveMapList {
+		for _, s := range item.l {
+			m[s] = resolveMapItem{item.v, item.tag}
+		}
+	}
+}
+
+const (
+	nullTag      = "!!null"
+	boolTag      = "!!bool"
+	strTag       = "!!str"
+	intTag       = "!!int"
+	floatTag     = "!!float"
+	timestampTag = "!!timestamp"
+	seqTag       = "!!seq"
+	mapTag       = "!!map"
+	binaryTag    = "!!binary"
+	mergeTag     = "!!merge"
+)
+
+var longTags = make(map[string]string)
+var shortTags = make(map[string]string)
+
+func init() {
+	for _, stag := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} {
+		ltag := longTag(stag)
+		longTags[stag] = ltag
+		shortTags[ltag] = stag
+	}
+}
+
+const longTagPrefix = "tag:yaml.org,2002:"
+
+func shortTag(tag string) string {
+	if strings.HasPrefix(tag, longTagPrefix) {
+		if stag, ok := shortTags[tag]; ok {
+			return stag
+		}
+		return "!!" + tag[len(longTagPrefix):]
+	}
+	return tag
+}
+
+func longTag(tag string) string {
+	if strings.HasPrefix(tag, "!!") {
+		if ltag, ok := longTags[tag]; ok {
+			return ltag
+		}
+		return longTagPrefix + tag[2:]
+	}
+	return tag
+}
+
+func resolvableTag(tag string) bool {
+	switch tag {
+	case "", strTag, boolTag, intTag, floatTag, nullTag, timestampTag:
+		return true
+	}
+	return false
+}
+
+var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
+
+func resolve(tag string, in string) (rtag string, out interface{}) {
+	tag = shortTag(tag)
+	if !resolvableTag(tag) {
+		return tag, in
+	}
+
+	defer func() {
+		switch tag {
+		case "", rtag, strTag, binaryTag:
+			return
+		case floatTag:
+			if rtag == intTag {
+				switch v := out.(type) {
+				case int64:
+					rtag = floatTag
+					out = float64(v)
+					return
+				case int:
+					rtag = floatTag
+					out = float64(v)
+					return
+				}
+			}
+		}
+		failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
+	}()
+
+	// Any data is accepted as a !!str or !!binary.
+	// Otherwise, the prefix is enough of a hint about what it might be.
+	hint := byte('N')
+	if in != "" {
+		hint = resolveTable[in[0]]
+	}
+	if hint != 0 && tag != strTag && tag != binaryTag {
+		// Handle things we can lookup in a map.
+		if item, ok := resolveMap[in]; ok {
+			return item.tag, item.value
+		}
+
+		// Base 60 floats are a bad idea, were dropped in YAML 1.2, and
+		// are purposefully unsupported here. They're still quoted on
+		// the way out for compatibility with other parser, though.
+
+		switch hint {
+		case 'M':
+			// We've already checked the map above.
+
+		case '.':
+			// Not in the map, so maybe a normal float.
+			floatv, err := strconv.ParseFloat(in, 64)
+			if err == nil {
+				return floatTag, floatv
+			}
+
+		case 'D', 'S':
+			// Int, float, or timestamp.
+			// Only try values as a timestamp if the value is unquoted or there's an explicit
+			// !!timestamp tag.
+			if tag == "" || tag == timestampTag {
+				t, ok := parseTimestamp(in)
+				if ok {
+					return timestampTag, t
+				}
+			}
+
+			plain := strings.Replace(in, "_", "", -1)
+			intv, err := strconv.ParseInt(plain, 0, 64)
+			if err == nil {
+				if intv == int64(int(intv)) {
+					return intTag, int(intv)
+				} else {
+					return intTag, intv
+				}
+			}
+			uintv, err := strconv.ParseUint(plain, 0, 64)
+			if err == nil {
+				return intTag, uintv
+			}
+			if yamlStyleFloat.MatchString(plain) {
+				floatv, err := strconv.ParseFloat(plain, 64)
+				if err == nil {
+					return floatTag, floatv
+				}
+			}
+			if strings.HasPrefix(plain, "0b") {
+				intv, err := strconv.ParseInt(plain[2:], 2, 64)
+				if err == nil {
+					if intv == int64(int(intv)) {
+						return intTag, int(intv)
+					} else {
+						return intTag, intv
+					}
+				}
+				uintv, err := strconv.ParseUint(plain[2:], 2, 64)
+				if err == nil {
+					return intTag, uintv
+				}
+			} else if strings.HasPrefix(plain, "-0b") {
+				intv, err := strconv.ParseInt("-"+plain[3:], 2, 64)
+				if err == nil {
+					if true || intv == int64(int(intv)) {
+						return intTag, int(intv)
+					} else {
+						return intTag, intv
+					}
+				}
+			}
+			// Octals as introduced in version 1.2 of the spec.
+			// Octals from the 1.1 spec, spelled as 0777, are still
+			// decoded by default in v3 as well for compatibility.
+			// May be dropped in v4 depending on how usage evolves.
+			if strings.HasPrefix(plain, "0o") {
+				intv, err := strconv.ParseInt(plain[2:], 8, 64)
+				if err == nil {
+					if intv == int64(int(intv)) {
+						return intTag, int(intv)
+					} else {
+						return intTag, intv
+					}
+				}
+				uintv, err := strconv.ParseUint(plain[2:], 8, 64)
+				if err == nil {
+					return intTag, uintv
+				}
+			} else if strings.HasPrefix(plain, "-0o") {
+				intv, err := strconv.ParseInt("-"+plain[3:], 8, 64)
+				if err == nil {
+					if true || intv == int64(int(intv)) {
+						return intTag, int(intv)
+					} else {
+						return intTag, intv
+					}
+				}
+			}
+		default:
+			panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")")
+		}
+	}
+	return strTag, in
+}
+
+// encodeBase64 encodes s as base64 that is broken up into multiple lines
+// as appropriate for the resulting length.
+func encodeBase64(s string) string {
+	const lineLen = 70
+	encLen := base64.StdEncoding.EncodedLen(len(s))
+	lines := encLen/lineLen + 1
+	buf := make([]byte, encLen*2+lines)
+	in := buf[0:encLen]
+	out := buf[encLen:]
+	base64.StdEncoding.Encode(in, []byte(s))
+	k := 0
+	for i := 0; i < len(in); i += lineLen {
+		j := i + lineLen
+		if j > len(in) {
+			j = len(in)
+		}
+		k += copy(out[k:], in[i:j])
+		if lines > 1 {
+			out[k] = '\n'
+			k++
+		}
+	}
+	return string(out[:k])
+}
+
+// This is a subset of the formats allowed by the regular expression
+// defined at http://yaml.org/type/timestamp.html.
+var allowedTimestampFormats = []string{
+	"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
+	"2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
+	"2006-1-2 15:4:5.999999999",       // space separated with no time zone
+	"2006-1-2",                        // date only
+	// Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
+	// from the set of examples.
+}
+
+// parseTimestamp parses s as a timestamp string and
+// returns the timestamp and reports whether it succeeded.
+// Timestamp formats are defined at http://yaml.org/type/timestamp.html
+func parseTimestamp(s string) (time.Time, bool) {
+	// TODO write code to check all the formats supported by
+	// http://yaml.org/type/timestamp.html instead of using time.Parse.
+
+	// Quick check: all date formats start with YYYY-.
+	i := 0
+	for ; i < len(s); i++ {
+		if c := s[i]; c < '0' || c > '9' {
+			break
+		}
+	}
+	if i != 4 || i == len(s) || s[i] != '-' {
+		return time.Time{}, false
+	}
+	for _, format := range allowedTimestampFormats {
+		if t, err := time.Parse(format, s); err == nil {
+			return t, true
+		}
+	}
+	return time.Time{}, false
+}
diff --git a/vendor/gopkg.in/yaml.v3/scannerc.go b/vendor/gopkg.in/yaml.v3/scannerc.go
new file mode 100644
index 000000000..ca0070108
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/scannerc.go
@@ -0,0 +1,3038 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// Introduction
+// ************
+//
+// The following notes assume that you are familiar with the YAML specification
+// (http://yaml.org/spec/1.2/spec.html).  We mostly follow it, although in
+// some cases we are less restrictive that it requires.
+//
+// The process of transforming a YAML stream into a sequence of events is
+// divided on two steps: Scanning and Parsing.
+//
+// The Scanner transforms the input stream into a sequence of tokens, while the
+// parser transform the sequence of tokens produced by the Scanner into a
+// sequence of parsing events.
+//
+// The Scanner is rather clever and complicated. The Parser, on the contrary,
+// is a straightforward implementation of a recursive-descendant parser (or,
+// LL(1) parser, as it is usually called).
+//
+// Actually there are two issues of Scanning that might be called "clever", the
+// rest is quite straightforward.  The issues are "block collection start" and
+// "simple keys".  Both issues are explained below in details.
+//
+// Here the Scanning step is explained and implemented.  We start with the list
+// of all the tokens produced by the Scanner together with short descriptions.
+//
+// Now, tokens:
+//
+//      STREAM-START(encoding)          # The stream start.
+//      STREAM-END                      # The stream end.
+//      VERSION-DIRECTIVE(major,minor)  # The '%YAML' directive.
+//      TAG-DIRECTIVE(handle,prefix)    # The '%TAG' directive.
+//      DOCUMENT-START                  # '---'
+//      DOCUMENT-END                    # '...'
+//      BLOCK-SEQUENCE-START            # Indentation increase denoting a block
+//      BLOCK-MAPPING-START             # sequence or a block mapping.
+//      BLOCK-END                       # Indentation decrease.
+//      FLOW-SEQUENCE-START             # '['
+//      FLOW-SEQUENCE-END               # ']'
+//      BLOCK-SEQUENCE-START            # '{'
+//      BLOCK-SEQUENCE-END              # '}'
+//      BLOCK-ENTRY                     # '-'
+//      FLOW-ENTRY                      # ','
+//      KEY                             # '?' or nothing (simple keys).
+//      VALUE                           # ':'
+//      ALIAS(anchor)                   # '*anchor'
+//      ANCHOR(anchor)                  # '&anchor'
+//      TAG(handle,suffix)              # '!handle!suffix'
+//      SCALAR(value,style)             # A scalar.
+//
+// The following two tokens are "virtual" tokens denoting the beginning and the
+// end of the stream:
+//
+//      STREAM-START(encoding)
+//      STREAM-END
+//
+// We pass the information about the input stream encoding with the
+// STREAM-START token.
+//
+// The next two tokens are responsible for tags:
+//
+//      VERSION-DIRECTIVE(major,minor)
+//      TAG-DIRECTIVE(handle,prefix)
+//
+// Example:
+//
+//      %YAML   1.1
+//      %TAG    !   !foo
+//      %TAG    !yaml!  tag:yaml.org,2002:
+//      ---
+//
+// The correspoding sequence of tokens:
+//
+//      STREAM-START(utf-8)
+//      VERSION-DIRECTIVE(1,1)
+//      TAG-DIRECTIVE("!","!foo")
+//      TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
+//      DOCUMENT-START
+//      STREAM-END
+//
+// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
+// line.
+//
+// The document start and end indicators are represented by:
+//
+//      DOCUMENT-START
+//      DOCUMENT-END
+//
+// Note that if a YAML stream contains an implicit document (without '---'
+// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
+// produced.
+//
+// In the following examples, we present whole documents together with the
+// produced tokens.
+//
+//      1. An implicit document:
+//
+//          'a scalar'
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          SCALAR("a scalar",single-quoted)
+//          STREAM-END
+//
+//      2. An explicit document:
+//
+//          ---
+//          'a scalar'
+//          ...
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          DOCUMENT-START
+//          SCALAR("a scalar",single-quoted)
+//          DOCUMENT-END
+//          STREAM-END
+//
+//      3. Several documents in a stream:
+//
+//          'a scalar'
+//          ---
+//          'another scalar'
+//          ---
+//          'yet another scalar'
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          SCALAR("a scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("another scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("yet another scalar",single-quoted)
+//          STREAM-END
+//
+// We have already introduced the SCALAR token above.  The following tokens are
+// used to describe aliases, anchors, tag, and scalars:
+//
+//      ALIAS(anchor)
+//      ANCHOR(anchor)
+//      TAG(handle,suffix)
+//      SCALAR(value,style)
+//
+// The following series of examples illustrate the usage of these tokens:
+//
+//      1. A recursive sequence:
+//
+//          &A [ *A ]
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          ANCHOR("A")
+//          FLOW-SEQUENCE-START
+//          ALIAS("A")
+//          FLOW-SEQUENCE-END
+//          STREAM-END
+//
+//      2. A tagged scalar:
+//
+//          !!float "3.14"  # A good approximation.
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          TAG("!!","float")
+//          SCALAR("3.14",double-quoted)
+//          STREAM-END
+//
+//      3. Various scalar styles:
+//
+//          --- # Implicit empty plain scalars do not produce tokens.
+//          --- a plain scalar
+//          --- 'a single-quoted scalar'
+//          --- "a double-quoted scalar"
+//          --- |-
+//            a literal scalar
+//          --- >-
+//            a folded
+//            scalar
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          DOCUMENT-START
+//          DOCUMENT-START
+//          SCALAR("a plain scalar",plain)
+//          DOCUMENT-START
+//          SCALAR("a single-quoted scalar",single-quoted)
+//          DOCUMENT-START
+//          SCALAR("a double-quoted scalar",double-quoted)
+//          DOCUMENT-START
+//          SCALAR("a literal scalar",literal)
+//          DOCUMENT-START
+//          SCALAR("a folded scalar",folded)
+//          STREAM-END
+//
+// Now it's time to review collection-related tokens. We will start with
+// flow collections:
+//
+//      FLOW-SEQUENCE-START
+//      FLOW-SEQUENCE-END
+//      FLOW-MAPPING-START
+//      FLOW-MAPPING-END
+//      FLOW-ENTRY
+//      KEY
+//      VALUE
+//
+// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
+// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
+// correspondingly.  FLOW-ENTRY represent the ',' indicator.  Finally the
+// indicators '?' and ':', which are used for denoting mapping keys and values,
+// are represented by the KEY and VALUE tokens.
+//
+// The following examples show flow collections:
+//
+//      1. A flow sequence:
+//
+//          [item 1, item 2, item 3]
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          FLOW-SEQUENCE-START
+//          SCALAR("item 1",plain)
+//          FLOW-ENTRY
+//          SCALAR("item 2",plain)
+//          FLOW-ENTRY
+//          SCALAR("item 3",plain)
+//          FLOW-SEQUENCE-END
+//          STREAM-END
+//
+//      2. A flow mapping:
+//
+//          {
+//              a simple key: a value,  # Note that the KEY token is produced.
+//              ? a complex key: another value,
+//          }
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          FLOW-MAPPING-START
+//          KEY
+//          SCALAR("a simple key",plain)
+//          VALUE
+//          SCALAR("a value",plain)
+//          FLOW-ENTRY
+//          KEY
+//          SCALAR("a complex key",plain)
+//          VALUE
+//          SCALAR("another value",plain)
+//          FLOW-ENTRY
+//          FLOW-MAPPING-END
+//          STREAM-END
+//
+// A simple key is a key which is not denoted by the '?' indicator.  Note that
+// the Scanner still produce the KEY token whenever it encounters a simple key.
+//
+// For scanning block collections, the following tokens are used (note that we
+// repeat KEY and VALUE here):
+//
+//      BLOCK-SEQUENCE-START
+//      BLOCK-MAPPING-START
+//      BLOCK-END
+//      BLOCK-ENTRY
+//      KEY
+//      VALUE
+//
+// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
+// increase that precedes a block collection (cf. the INDENT token in Python).
+// The token BLOCK-END denote indentation decrease that ends a block collection
+// (cf. the DEDENT token in Python).  However YAML has some syntax pecularities
+// that makes detections of these tokens more complex.
+//
+// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
+// '-', '?', and ':' correspondingly.
+//
+// The following examples show how the tokens BLOCK-SEQUENCE-START,
+// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
+//
+//      1. Block sequences:
+//
+//          - item 1
+//          - item 2
+//          -
+//            - item 3.1
+//            - item 3.2
+//          -
+//            key 1: value 1
+//            key 2: value 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-ENTRY
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 3.1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 3.2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+//      2. Block mappings:
+//
+//          a simple key: a value   # The KEY token is produced here.
+//          ? a complex key
+//          : another value
+//          a mapping:
+//            key 1: value 1
+//            key 2: value 2
+//          a sequence:
+//            - item 1
+//            - item 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("a simple key",plain)
+//          VALUE
+//          SCALAR("a value",plain)
+//          KEY
+//          SCALAR("a complex key",plain)
+//          VALUE
+//          SCALAR("another value",plain)
+//          KEY
+//          SCALAR("a mapping",plain)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          KEY
+//          SCALAR("a sequence",plain)
+//          VALUE
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+// YAML does not always require to start a new block collection from a new
+// line.  If the current line contains only '-', '?', and ':' indicators, a new
+// block collection may start at the current line.  The following examples
+// illustrate this case:
+//
+//      1. Collections in a sequence:
+//
+//          - - item 1
+//            - item 2
+//          - key 1: value 1
+//            key 2: value 2
+//          - ? complex key
+//            : complex value
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-ENTRY
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("complex key")
+//          VALUE
+//          SCALAR("complex value")
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+//      2. Collections in a mapping:
+//
+//          ? a sequence
+//          : - item 1
+//            - item 2
+//          ? a mapping
+//          : key 1: value 1
+//            key 2: value 2
+//
+//      Tokens:
+//
+//          STREAM-START(utf-8)
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("a sequence",plain)
+//          VALUE
+//          BLOCK-SEQUENCE-START
+//          BLOCK-ENTRY
+//          SCALAR("item 1",plain)
+//          BLOCK-ENTRY
+//          SCALAR("item 2",plain)
+//          BLOCK-END
+//          KEY
+//          SCALAR("a mapping",plain)
+//          VALUE
+//          BLOCK-MAPPING-START
+//          KEY
+//          SCALAR("key 1",plain)
+//          VALUE
+//          SCALAR("value 1",plain)
+//          KEY
+//          SCALAR("key 2",plain)
+//          VALUE
+//          SCALAR("value 2",plain)
+//          BLOCK-END
+//          BLOCK-END
+//          STREAM-END
+//
+// YAML also permits non-indented sequences if they are included into a block
+// mapping.  In this case, the token BLOCK-SEQUENCE-START is not produced:
+//
+//      key:
+//      - item 1    # BLOCK-SEQUENCE-START is NOT produced here.
+//      - item 2
+//
+// Tokens:
+//
+//      STREAM-START(utf-8)
+//      BLOCK-MAPPING-START
+//      KEY
+//      SCALAR("key",plain)
+//      VALUE
+//      BLOCK-ENTRY
+//      SCALAR("item 1",plain)
+//      BLOCK-ENTRY
+//      SCALAR("item 2",plain)
+//      BLOCK-END
+//
+
+// Ensure that the buffer contains the required number of characters.
+// Return true on success, false on failure (reader error or memory error).
+func cache(parser *yaml_parser_t, length int) bool {
+	// [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B)
+	return parser.unread >= length || yaml_parser_update_buffer(parser, length)
+}
+
+// Advance the buffer pointer.
+func skip(parser *yaml_parser_t) {
+	if !is_blank(parser.buffer, parser.buffer_pos) {
+		parser.newlines = 0
+	}
+	parser.mark.index++
+	parser.mark.column++
+	parser.unread--
+	parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
+}
+
+func skip_line(parser *yaml_parser_t) {
+	if is_crlf(parser.buffer, parser.buffer_pos) {
+		parser.mark.index += 2
+		parser.mark.column = 0
+		parser.mark.line++
+		parser.unread -= 2
+		parser.buffer_pos += 2
+		parser.newlines++
+	} else if is_break(parser.buffer, parser.buffer_pos) {
+		parser.mark.index++
+		parser.mark.column = 0
+		parser.mark.line++
+		parser.unread--
+		parser.buffer_pos += width(parser.buffer[parser.buffer_pos])
+		parser.newlines++
+	}
+}
+
+// Copy a character to a string buffer and advance pointers.
+func read(parser *yaml_parser_t, s []byte) []byte {
+	if !is_blank(parser.buffer, parser.buffer_pos) {
+		parser.newlines = 0
+	}
+	w := width(parser.buffer[parser.buffer_pos])
+	if w == 0 {
+		panic("invalid character sequence")
+	}
+	if len(s) == 0 {
+		s = make([]byte, 0, 32)
+	}
+	if w == 1 && len(s)+w <= cap(s) {
+		s = s[:len(s)+1]
+		s[len(s)-1] = parser.buffer[parser.buffer_pos]
+		parser.buffer_pos++
+	} else {
+		s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...)
+		parser.buffer_pos += w
+	}
+	parser.mark.index++
+	parser.mark.column++
+	parser.unread--
+	return s
+}
+
+// Copy a line break character to a string buffer and advance pointers.
+func read_line(parser *yaml_parser_t, s []byte) []byte {
+	buf := parser.buffer
+	pos := parser.buffer_pos
+	switch {
+	case buf[pos] == '\r' && buf[pos+1] == '\n':
+		// CR LF . LF
+		s = append(s, '\n')
+		parser.buffer_pos += 2
+		parser.mark.index++
+		parser.unread--
+	case buf[pos] == '\r' || buf[pos] == '\n':
+		// CR|LF . LF
+		s = append(s, '\n')
+		parser.buffer_pos += 1
+	case buf[pos] == '\xC2' && buf[pos+1] == '\x85':
+		// NEL . LF
+		s = append(s, '\n')
+		parser.buffer_pos += 2
+	case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'):
+		// LS|PS . LS|PS
+		s = append(s, buf[parser.buffer_pos:pos+3]...)
+		parser.buffer_pos += 3
+	default:
+		return s
+	}
+	parser.mark.index++
+	parser.mark.column = 0
+	parser.mark.line++
+	parser.unread--
+	parser.newlines++
+	return s
+}
+
+// Get the next token.
+func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool {
+	// Erase the token object.
+	*token = yaml_token_t{} // [Go] Is this necessary?
+
+	// No tokens after STREAM-END or error.
+	if parser.stream_end_produced || parser.error != yaml_NO_ERROR {
+		return true
+	}
+
+	// Ensure that the tokens queue contains enough tokens.
+	if !parser.token_available {
+		if !yaml_parser_fetch_more_tokens(parser) {
+			return false
+		}
+	}
+
+	// Fetch the next token from the queue.
+	*token = parser.tokens[parser.tokens_head]
+	parser.tokens_head++
+	parser.tokens_parsed++
+	parser.token_available = false
+
+	if token.typ == yaml_STREAM_END_TOKEN {
+		parser.stream_end_produced = true
+	}
+	return true
+}
+
+// Set the scanner error and return false.
+func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool {
+	parser.error = yaml_SCANNER_ERROR
+	parser.context = context
+	parser.context_mark = context_mark
+	parser.problem = problem
+	parser.problem_mark = parser.mark
+	return false
+}
+
+func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool {
+	context := "while parsing a tag"
+	if directive {
+		context = "while parsing a %TAG directive"
+	}
+	return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
+}
+
+func trace(args ...interface{}) func() {
+	pargs := append([]interface{}{"+++"}, args...)
+	fmt.Println(pargs...)
+	pargs = append([]interface{}{"---"}, args...)
+	return func() { fmt.Println(pargs...) }
+}
+
+// Ensure that the tokens queue contains at least one token which can be
+// returned to the Parser.
+func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
+	// While we need more tokens to fetch, do it.
+	for {
+		// [Go] The comment parsing logic requires a lookahead of two tokens
+		// so that foot comments may be parsed in time of associating them
+		// with the tokens that are parsed before them, and also for line
+		// comments to be transformed into head comments in some edge cases.
+		if parser.tokens_head < len(parser.tokens)-2 {
+			// If a potential simple key is at the head position, we need to fetch
+			// the next token to disambiguate it.
+			head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
+			if !ok {
+				break
+			} else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
+				return false
+			} else if !valid {
+				break
+			}
+		}
+		// Fetch the next token.
+		if !yaml_parser_fetch_next_token(parser) {
+			return false
+		}
+	}
+
+	parser.token_available = true
+	return true
+}
+
+// The dispatcher for token fetchers.
+func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) {
+	// Ensure that the buffer is initialized.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	// Check if we just started scanning.  Fetch STREAM-START then.
+	if !parser.stream_start_produced {
+		return yaml_parser_fetch_stream_start(parser)
+	}
+
+	scan_mark := parser.mark
+
+	// Eat whitespaces and comments until we reach the next token.
+	if !yaml_parser_scan_to_next_token(parser) {
+		return false
+	}
+
+	// [Go] While unrolling indents, transform the head comments of prior
+	// indentation levels observed after scan_start into foot comments at
+	// the respective indexes.
+
+	// Check the indentation level against the current column.
+	if !yaml_parser_unroll_indent(parser, parser.mark.column, scan_mark) {
+		return false
+	}
+
+	// Ensure that the buffer contains at least 4 characters.  4 is the length
+	// of the longest indicators ('--- ' and '... ').
+	if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+		return false
+	}
+
+	// Is it the end of the stream?
+	if is_z(parser.buffer, parser.buffer_pos) {
+		return yaml_parser_fetch_stream_end(parser)
+	}
+
+	// Is it a directive?
+	if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' {
+		return yaml_parser_fetch_directive(parser)
+	}
+
+	buf := parser.buffer
+	pos := parser.buffer_pos
+
+	// Is it the document start indicator?
+	if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) {
+		return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN)
+	}
+
+	// Is it the document end indicator?
+	if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) {
+		return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN)
+	}
+
+	comment_mark := parser.mark
+	if len(parser.tokens) > 0 && (parser.flow_level == 0 && buf[pos] == ':' || parser.flow_level > 0 && buf[pos] == ',') {
+		// Associate any following comments with the prior token.
+		comment_mark = parser.tokens[len(parser.tokens)-1].start_mark
+	}
+	defer func() {
+		if !ok {
+			return
+		}
+		if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN {
+			// Sequence indicators alone have no line comments. It becomes
+			// a head comment for whatever follows.
+			return
+		}
+		if !yaml_parser_scan_line_comment(parser, comment_mark) {
+			ok = false
+			return
+		}
+	}()
+
+	// Is it the flow sequence start indicator?
+	if buf[pos] == '[' {
+		return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN)
+	}
+
+	// Is it the flow mapping start indicator?
+	if parser.buffer[parser.buffer_pos] == '{' {
+		return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN)
+	}
+
+	// Is it the flow sequence end indicator?
+	if parser.buffer[parser.buffer_pos] == ']' {
+		return yaml_parser_fetch_flow_collection_end(parser,
+			yaml_FLOW_SEQUENCE_END_TOKEN)
+	}
+
+	// Is it the flow mapping end indicator?
+	if parser.buffer[parser.buffer_pos] == '}' {
+		return yaml_parser_fetch_flow_collection_end(parser,
+			yaml_FLOW_MAPPING_END_TOKEN)
+	}
+
+	// Is it the flow entry indicator?
+	if parser.buffer[parser.buffer_pos] == ',' {
+		return yaml_parser_fetch_flow_entry(parser)
+	}
+
+	// Is it the block entry indicator?
+	if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) {
+		return yaml_parser_fetch_block_entry(parser)
+	}
+
+	// Is it the key indicator?
+	if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
+		return yaml_parser_fetch_key(parser)
+	}
+
+	// Is it the value indicator?
+	if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) {
+		return yaml_parser_fetch_value(parser)
+	}
+
+	// Is it an alias?
+	if parser.buffer[parser.buffer_pos] == '*' {
+		return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN)
+	}
+
+	// Is it an anchor?
+	if parser.buffer[parser.buffer_pos] == '&' {
+		return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN)
+	}
+
+	// Is it a tag?
+	if parser.buffer[parser.buffer_pos] == '!' {
+		return yaml_parser_fetch_tag(parser)
+	}
+
+	// Is it a literal scalar?
+	if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 {
+		return yaml_parser_fetch_block_scalar(parser, true)
+	}
+
+	// Is it a folded scalar?
+	if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 {
+		return yaml_parser_fetch_block_scalar(parser, false)
+	}
+
+	// Is it a single-quoted scalar?
+	if parser.buffer[parser.buffer_pos] == '\'' {
+		return yaml_parser_fetch_flow_scalar(parser, true)
+	}
+
+	// Is it a double-quoted scalar?
+	if parser.buffer[parser.buffer_pos] == '"' {
+		return yaml_parser_fetch_flow_scalar(parser, false)
+	}
+
+	// Is it a plain scalar?
+	//
+	// A plain scalar may start with any non-blank characters except
+	//
+	//      '-', '?', ':', ',', '[', ']', '{', '}',
+	//      '#', '&', '*', '!', '|', '>', '\'', '\"',
+	//      '%', '@', '`'.
+	//
+	// In the block context (and, for the '-' indicator, in the flow context
+	// too), it may also start with the characters
+	//
+	//      '-', '?', ':'
+	//
+	// if it is followed by a non-space character.
+	//
+	// The last rule is more restrictive than the specification requires.
+	// [Go] TODO Make this logic more reasonable.
+	//switch parser.buffer[parser.buffer_pos] {
+	//case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`':
+	//}
+	if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' ||
+		parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' ||
+		parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' ||
+		parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
+		parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' ||
+		parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' ||
+		parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' ||
+		parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' ||
+		parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' ||
+		parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') ||
+		(parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) ||
+		(parser.flow_level == 0 &&
+			(parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') &&
+			!is_blankz(parser.buffer, parser.buffer_pos+1)) {
+		return yaml_parser_fetch_plain_scalar(parser)
+	}
+
+	// If we don't determine the token type so far, it is an error.
+	return yaml_parser_set_scanner_error(parser,
+		"while scanning for the next token", parser.mark,
+		"found character that cannot start any token")
+}
+
+func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
+	if !simple_key.possible {
+		return false, true
+	}
+
+	// The 1.2 specification says:
+	//
+	//     "If the ? indicator is omitted, parsing needs to see past the
+	//     implicit key to recognize it as such. To limit the amount of
+	//     lookahead required, the “:” indicator must appear at most 1024
+	//     Unicode characters beyond the start of the key. In addition, the key
+	//     is restricted to a single line."
+	//
+	if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
+		// Check if the potential simple key to be removed is required.
+		if simple_key.required {
+			return false, yaml_parser_set_scanner_error(parser,
+				"while scanning a simple key", simple_key.mark,
+				"could not find expected ':'")
+		}
+		simple_key.possible = false
+		return false, true
+	}
+	return true, true
+}
+
+// Check if a simple key may start at the current position and add it if
+// needed.
+func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
+	// A simple key is required at the current position if the scanner is in
+	// the block context and the current column coincides with the indentation
+	// level.
+
+	required := parser.flow_level == 0 && parser.indent == parser.mark.column
+
+	//
+	// If the current position may start a simple key, save it.
+	//
+	if parser.simple_key_allowed {
+		simple_key := yaml_simple_key_t{
+			possible:     true,
+			required:     required,
+			token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
+			mark:         parser.mark,
+		}
+
+		if !yaml_parser_remove_simple_key(parser) {
+			return false
+		}
+		parser.simple_keys[len(parser.simple_keys)-1] = simple_key
+		parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
+	}
+	return true
+}
+
+// Remove a potential simple key at the current flow level.
+func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
+	i := len(parser.simple_keys) - 1
+	if parser.simple_keys[i].possible {
+		// If the key is required, it is an error.
+		if parser.simple_keys[i].required {
+			return yaml_parser_set_scanner_error(parser,
+				"while scanning a simple key", parser.simple_keys[i].mark,
+				"could not find expected ':'")
+		}
+		// Remove the key from the stack.
+		parser.simple_keys[i].possible = false
+		delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
+	}
+	return true
+}
+
+// max_flow_level limits the flow_level
+const max_flow_level = 10000
+
+// Increase the flow level and resize the simple key list if needed.
+func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
+	// Reset the simple key on the next level.
+	parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
+		possible:     false,
+		required:     false,
+		token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
+		mark:         parser.mark,
+	})
+
+	// Increase the flow level.
+	parser.flow_level++
+	if parser.flow_level > max_flow_level {
+		return yaml_parser_set_scanner_error(parser,
+			"while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark,
+			fmt.Sprintf("exceeded max depth of %d", max_flow_level))
+	}
+	return true
+}
+
+// Decrease the flow level.
+func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
+	if parser.flow_level > 0 {
+		parser.flow_level--
+		last := len(parser.simple_keys) - 1
+		delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
+		parser.simple_keys = parser.simple_keys[:last]
+	}
+	return true
+}
+
+// max_indents limits the indents stack size
+const max_indents = 10000
+
+// Push the current indentation level to the stack and set the new level
+// the current column is greater than the indentation level.  In this case,
+// append or insert the specified token into the token queue.
+func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool {
+	// In the flow context, do nothing.
+	if parser.flow_level > 0 {
+		return true
+	}
+
+	if parser.indent < column {
+		// Push the current indentation level to the stack and set the new
+		// indentation level.
+		parser.indents = append(parser.indents, parser.indent)
+		parser.indent = column
+		if len(parser.indents) > max_indents {
+			return yaml_parser_set_scanner_error(parser,
+				"while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark,
+				fmt.Sprintf("exceeded max depth of %d", max_indents))
+		}
+
+		// Create a token and insert it into the queue.
+		token := yaml_token_t{
+			typ:        typ,
+			start_mark: mark,
+			end_mark:   mark,
+		}
+		if number > -1 {
+			number -= parser.tokens_parsed
+		}
+		yaml_insert_token(parser, number, &token)
+	}
+	return true
+}
+
+// Pop indentation levels from the indents stack until the current level
+// becomes less or equal to the column.  For each indentation level, append
+// the BLOCK-END token.
+func yaml_parser_unroll_indent(parser *yaml_parser_t, column int, scan_mark yaml_mark_t) bool {
+	// In the flow context, do nothing.
+	if parser.flow_level > 0 {
+		return true
+	}
+
+	block_mark := scan_mark
+	block_mark.index--
+
+	// Loop through the indentation levels in the stack.
+	for parser.indent > column {
+
+		// [Go] Reposition the end token before potential following
+		//      foot comments of parent blocks. For that, search
+		//      backwards for recent comments that were at the same
+		//      indent as the block that is ending now.
+		stop_index := block_mark.index
+		for i := len(parser.comments) - 1; i >= 0; i-- {
+			comment := &parser.comments[i]
+
+			if comment.end_mark.index < stop_index {
+				// Don't go back beyond the start of the comment/whitespace scan, unless column < 0.
+				// If requested indent column is < 0, then the document is over and everything else
+				// is a foot anyway.
+				break
+			}
+			if comment.start_mark.column == parser.indent+1 {
+				// This is a good match. But maybe there's a former comment
+				// at that same indent level, so keep searching.
+				block_mark = comment.start_mark
+			}
+
+			// While the end of the former comment matches with
+			// the start of the following one, we know there's
+			// nothing in between and scanning is still safe.
+			stop_index = comment.scan_mark.index
+		}
+
+		// Create a token and append it to the queue.
+		token := yaml_token_t{
+			typ:        yaml_BLOCK_END_TOKEN,
+			start_mark: block_mark,
+			end_mark:   block_mark,
+		}
+		yaml_insert_token(parser, -1, &token)
+
+		// Pop the indentation level.
+		parser.indent = parser.indents[len(parser.indents)-1]
+		parser.indents = parser.indents[:len(parser.indents)-1]
+	}
+	return true
+}
+
+// Initialize the scanner and produce the STREAM-START token.
+func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
+
+	// Set the initial indentation.
+	parser.indent = -1
+
+	// Initialize the simple key stack.
+	parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+
+	parser.simple_keys_by_tok = make(map[int]int)
+
+	// A simple key is allowed at the beginning of the stream.
+	parser.simple_key_allowed = true
+
+	// We have started.
+	parser.stream_start_produced = true
+
+	// Create the STREAM-START token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_STREAM_START_TOKEN,
+		start_mark: parser.mark,
+		end_mark:   parser.mark,
+		encoding:   parser.encoding,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the STREAM-END token and shut down the scanner.
+func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool {
+
+	// Force new line.
+	if parser.mark.column != 0 {
+		parser.mark.column = 0
+		parser.mark.line++
+	}
+
+	// Reset the indentation level.
+	if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
+		return false
+	}
+
+	// Reset simple keys.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	parser.simple_key_allowed = false
+
+	// Create the STREAM-END token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_STREAM_END_TOKEN,
+		start_mark: parser.mark,
+		end_mark:   parser.mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
+func yaml_parser_fetch_directive(parser *yaml_parser_t) bool {
+	// Reset the indentation level.
+	if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
+		return false
+	}
+
+	// Reset simple keys.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	parser.simple_key_allowed = false
+
+	// Create the YAML-DIRECTIVE or TAG-DIRECTIVE token.
+	token := yaml_token_t{}
+	if !yaml_parser_scan_directive(parser, &token) {
+		return false
+	}
+	// Append the token to the queue.
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the DOCUMENT-START or DOCUMENT-END token.
+func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+	// Reset the indentation level.
+	if !yaml_parser_unroll_indent(parser, -1, parser.mark) {
+		return false
+	}
+
+	// Reset simple keys.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	parser.simple_key_allowed = false
+
+	// Consume the token.
+	start_mark := parser.mark
+
+	skip(parser)
+	skip(parser)
+	skip(parser)
+
+	end_mark := parser.mark
+
+	// Create the DOCUMENT-START or DOCUMENT-END token.
+	token := yaml_token_t{
+		typ:        typ,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	// Append the token to the queue.
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
+func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+
+	// The indicators '[' and '{' may start a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// Increase the flow level.
+	if !yaml_parser_increase_flow_level(parser) {
+		return false
+	}
+
+	// A simple key may follow the indicators '[' and '{'.
+	parser.simple_key_allowed = true
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token.
+	token := yaml_token_t{
+		typ:        typ,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	// Append the token to the queue.
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
+func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+	// Reset any potential simple key on the current flow level.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// Decrease the flow level.
+	if !yaml_parser_decrease_flow_level(parser) {
+		return false
+	}
+
+	// No simple keys after the indicators ']' and '}'.
+	parser.simple_key_allowed = false
+
+	// Consume the token.
+
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token.
+	token := yaml_token_t{
+		typ:        typ,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	// Append the token to the queue.
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the FLOW-ENTRY token.
+func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool {
+	// Reset any potential simple keys on the current flow level.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// Simple keys are allowed after ','.
+	parser.simple_key_allowed = true
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the FLOW-ENTRY token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_FLOW_ENTRY_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the BLOCK-ENTRY token.
+func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool {
+	// Check if the scanner is in the block context.
+	if parser.flow_level == 0 {
+		// Check if we are allowed to start a new entry.
+		if !parser.simple_key_allowed {
+			return yaml_parser_set_scanner_error(parser, "", parser.mark,
+				"block sequence entries are not allowed in this context")
+		}
+		// Add the BLOCK-SEQUENCE-START token if needed.
+		if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) {
+			return false
+		}
+	} else {
+		// It is an error for the '-' indicator to occur in the flow context,
+		// but we let the Parser detect and report about it because the Parser
+		// is able to point to the context.
+	}
+
+	// Reset any potential simple keys on the current flow level.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// Simple keys are allowed after '-'.
+	parser.simple_key_allowed = true
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the BLOCK-ENTRY token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_BLOCK_ENTRY_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the KEY token.
+func yaml_parser_fetch_key(parser *yaml_parser_t) bool {
+
+	// In the block context, additional checks are required.
+	if parser.flow_level == 0 {
+		// Check if we are allowed to start a new key (not nessesary simple).
+		if !parser.simple_key_allowed {
+			return yaml_parser_set_scanner_error(parser, "", parser.mark,
+				"mapping keys are not allowed in this context")
+		}
+		// Add the BLOCK-MAPPING-START token if needed.
+		if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
+			return false
+		}
+	}
+
+	// Reset any potential simple keys on the current flow level.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// Simple keys are allowed after '?' in the block context.
+	parser.simple_key_allowed = parser.flow_level == 0
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the KEY token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_KEY_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the VALUE token.
+func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
+
+	simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
+
+	// Have we found a simple key?
+	if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
+		return false
+
+	} else if valid {
+
+		// Create the KEY token and insert it into the queue.
+		token := yaml_token_t{
+			typ:        yaml_KEY_TOKEN,
+			start_mark: simple_key.mark,
+			end_mark:   simple_key.mark,
+		}
+		yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token)
+
+		// In the block context, we may need to add the BLOCK-MAPPING-START token.
+		if !yaml_parser_roll_indent(parser, simple_key.mark.column,
+			simple_key.token_number,
+			yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) {
+			return false
+		}
+
+		// Remove the simple key.
+		simple_key.possible = false
+		delete(parser.simple_keys_by_tok, simple_key.token_number)
+
+		// A simple key cannot follow another simple key.
+		parser.simple_key_allowed = false
+
+	} else {
+		// The ':' indicator follows a complex key.
+
+		// In the block context, extra checks are required.
+		if parser.flow_level == 0 {
+
+			// Check if we are allowed to start a complex value.
+			if !parser.simple_key_allowed {
+				return yaml_parser_set_scanner_error(parser, "", parser.mark,
+					"mapping values are not allowed in this context")
+			}
+
+			// Add the BLOCK-MAPPING-START token if needed.
+			if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) {
+				return false
+			}
+		}
+
+		// Simple keys after ':' are allowed in the block context.
+		parser.simple_key_allowed = parser.flow_level == 0
+	}
+
+	// Consume the token.
+	start_mark := parser.mark
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create the VALUE token and append it to the queue.
+	token := yaml_token_t{
+		typ:        yaml_VALUE_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the ALIAS or ANCHOR token.
+func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool {
+	// An anchor or an alias could be a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// A simple key cannot follow an anchor or an alias.
+	parser.simple_key_allowed = false
+
+	// Create the ALIAS or ANCHOR token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_anchor(parser, &token, typ) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the TAG token.
+func yaml_parser_fetch_tag(parser *yaml_parser_t) bool {
+	// A tag could be a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// A simple key cannot follow a tag.
+	parser.simple_key_allowed = false
+
+	// Create the TAG token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_tag(parser, &token) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
+func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool {
+	// Remove any potential simple keys.
+	if !yaml_parser_remove_simple_key(parser) {
+		return false
+	}
+
+	// A simple key may follow a block scalar.
+	parser.simple_key_allowed = true
+
+	// Create the SCALAR token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_block_scalar(parser, &token, literal) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
+func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool {
+	// A plain scalar could be a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// A simple key cannot follow a flow scalar.
+	parser.simple_key_allowed = false
+
+	// Create the SCALAR token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_flow_scalar(parser, &token, single) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Produce the SCALAR(...,plain) token.
+func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool {
+	// A plain scalar could be a simple key.
+	if !yaml_parser_save_simple_key(parser) {
+		return false
+	}
+
+	// A simple key cannot follow a flow scalar.
+	parser.simple_key_allowed = false
+
+	// Create the SCALAR token and append it to the queue.
+	var token yaml_token_t
+	if !yaml_parser_scan_plain_scalar(parser, &token) {
+		return false
+	}
+	yaml_insert_token(parser, -1, &token)
+	return true
+}
+
+// Eat whitespaces and comments until the next token is found.
+func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool {
+
+	scan_mark := parser.mark
+
+	// Until the next token is not found.
+	for {
+		// Allow the BOM mark to start a line.
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) {
+			skip(parser)
+		}
+
+		// Eat whitespaces.
+		// Tabs are allowed:
+		//  - in the flow context
+		//  - in the block context, but not at the beginning of the line or
+		//  after '-', '?', or ':' (complex value).
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+
+		for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') {
+			skip(parser)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+
+		// Check if we just had a line comment under a sequence entry that
+		// looks more like a header to the following content. Similar to this:
+		//
+		// - # The comment
+		//   - Some data
+		//
+		// If so, transform the line comment to a head comment and reposition.
+		if len(parser.comments) > 0 && len(parser.tokens) > 1 {
+			tokenA := parser.tokens[len(parser.tokens)-2]
+			tokenB := parser.tokens[len(parser.tokens)-1]
+			comment := &parser.comments[len(parser.comments)-1]
+			if tokenA.typ == yaml_BLOCK_SEQUENCE_START_TOKEN && tokenB.typ == yaml_BLOCK_ENTRY_TOKEN && len(comment.line) > 0 && !is_break(parser.buffer, parser.buffer_pos) {
+				// If it was in the prior line, reposition so it becomes a
+				// header of the follow up token. Otherwise, keep it in place
+				// so it becomes a header of the former.
+				comment.head = comment.line
+				comment.line = nil
+				if comment.start_mark.line == parser.mark.line-1 {
+					comment.token_mark = parser.mark
+				}
+			}
+		}
+
+		// Eat a comment until a line break.
+		if parser.buffer[parser.buffer_pos] == '#' {
+			if !yaml_parser_scan_comments(parser, scan_mark) {
+				return false
+			}
+		}
+
+		// If it is a line break, eat it.
+		if is_break(parser.buffer, parser.buffer_pos) {
+			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+				return false
+			}
+			skip_line(parser)
+
+			// In the block context, a new line may start a simple key.
+			if parser.flow_level == 0 {
+				parser.simple_key_allowed = true
+			}
+		} else {
+			break // We have found a token.
+		}
+	}
+
+	return true
+}
+
+// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
+//
+// Scope:
+//      %YAML    1.1    # a comment \n
+//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool {
+	// Eat '%'.
+	start_mark := parser.mark
+	skip(parser)
+
+	// Scan the directive name.
+	var name []byte
+	if !yaml_parser_scan_directive_name(parser, start_mark, &name) {
+		return false
+	}
+
+	// Is it a YAML directive?
+	if bytes.Equal(name, []byte("YAML")) {
+		// Scan the VERSION directive value.
+		var major, minor int8
+		if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) {
+			return false
+		}
+		end_mark := parser.mark
+
+		// Create a VERSION-DIRECTIVE token.
+		*token = yaml_token_t{
+			typ:        yaml_VERSION_DIRECTIVE_TOKEN,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			major:      major,
+			minor:      minor,
+		}
+
+		// Is it a TAG directive?
+	} else if bytes.Equal(name, []byte("TAG")) {
+		// Scan the TAG directive value.
+		var handle, prefix []byte
+		if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) {
+			return false
+		}
+		end_mark := parser.mark
+
+		// Create a TAG-DIRECTIVE token.
+		*token = yaml_token_t{
+			typ:        yaml_TAG_DIRECTIVE_TOKEN,
+			start_mark: start_mark,
+			end_mark:   end_mark,
+			value:      handle,
+			prefix:     prefix,
+		}
+
+		// Unknown directive.
+	} else {
+		yaml_parser_set_scanner_error(parser, "while scanning a directive",
+			start_mark, "found unknown directive name")
+		return false
+	}
+
+	// Eat the rest of the line including any comments.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	if parser.buffer[parser.buffer_pos] == '#' {
+		// [Go] Discard this inline comment for the time being.
+		//if !yaml_parser_scan_line_comment(parser, start_mark) {
+		//	return false
+		//}
+		for !is_breakz(parser.buffer, parser.buffer_pos) {
+			skip(parser)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+	}
+
+	// Check if we are at the end of the line.
+	if !is_breakz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a directive",
+			start_mark, "did not find expected comment or line break")
+		return false
+	}
+
+	// Eat a line break.
+	if is_break(parser.buffer, parser.buffer_pos) {
+		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+			return false
+		}
+		skip_line(parser)
+	}
+
+	return true
+}
+
+// Scan the directive name.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//       ^^^^
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//       ^^^
+//
+func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool {
+	// Consume the directive name.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	var s []byte
+	for is_alpha(parser.buffer, parser.buffer_pos) {
+		s = read(parser, s)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Check if the name is empty.
+	if len(s) == 0 {
+		yaml_parser_set_scanner_error(parser, "while scanning a directive",
+			start_mark, "could not find expected directive name")
+		return false
+	}
+
+	// Check for an blank character after the name.
+	if !is_blankz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a directive",
+			start_mark, "found unexpected non-alphabetical character")
+		return false
+	}
+	*name = s
+	return true
+}
+
+// Scan the value of VERSION-DIRECTIVE.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//           ^^^^^^
+func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool {
+	// Eat whitespaces.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Consume the major version number.
+	if !yaml_parser_scan_version_directive_number(parser, start_mark, major) {
+		return false
+	}
+
+	// Eat '.'.
+	if parser.buffer[parser.buffer_pos] != '.' {
+		return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+			start_mark, "did not find expected digit or '.' character")
+	}
+
+	skip(parser)
+
+	// Consume the minor version number.
+	if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) {
+		return false
+	}
+	return true
+}
+
+const max_number_length = 2
+
+// Scan the version number of VERSION-DIRECTIVE.
+//
+// Scope:
+//      %YAML   1.1     # a comment \n
+//              ^
+//      %YAML   1.1     # a comment \n
+//                ^
+func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool {
+
+	// Repeat while the next character is digit.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	var value, length int8
+	for is_digit(parser.buffer, parser.buffer_pos) {
+		// Check if the number is too long.
+		length++
+		if length > max_number_length {
+			return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+				start_mark, "found extremely long version number")
+		}
+		value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos))
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Check if the number was present.
+	if length == 0 {
+		return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
+			start_mark, "did not find expected version number")
+	}
+	*number = value
+	return true
+}
+
+// Scan the value of a TAG-DIRECTIVE token.
+//
+// Scope:
+//      %TAG    !yaml!  tag:yaml.org,2002:  \n
+//          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool {
+	var handle_value, prefix_value []byte
+
+	// Eat whitespaces.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Scan a handle.
+	if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) {
+		return false
+	}
+
+	// Expect a whitespace.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	if !is_blank(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
+			start_mark, "did not find expected whitespace")
+		return false
+	}
+
+	// Eat whitespaces.
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Scan a prefix.
+	if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) {
+		return false
+	}
+
+	// Expect a whitespace or line break.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	if !is_blankz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
+			start_mark, "did not find expected whitespace or line break")
+		return false
+	}
+
+	*handle = handle_value
+	*prefix = prefix_value
+	return true
+}
+
+func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool {
+	var s []byte
+
+	// Eat the indicator character.
+	start_mark := parser.mark
+	skip(parser)
+
+	// Consume the value.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	for is_alpha(parser.buffer, parser.buffer_pos) {
+		s = read(parser, s)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	end_mark := parser.mark
+
+	/*
+	 * Check if length of the anchor is greater than 0 and it is followed by
+	 * a whitespace character or one of the indicators:
+	 *
+	 *      '?', ':', ',', ']', '}', '%', '@', '`'.
+	 */
+
+	if len(s) == 0 ||
+		!(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' ||
+			parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' ||
+			parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' ||
+			parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' ||
+			parser.buffer[parser.buffer_pos] == '`') {
+		context := "while scanning an alias"
+		if typ == yaml_ANCHOR_TOKEN {
+			context = "while scanning an anchor"
+		}
+		yaml_parser_set_scanner_error(parser, context, start_mark,
+			"did not find expected alphabetic or numeric character")
+		return false
+	}
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        typ,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      s,
+	}
+
+	return true
+}
+
+/*
+ * Scan a TAG token.
+ */
+
+func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool {
+	var handle, suffix []byte
+
+	start_mark := parser.mark
+
+	// Check if the tag is in the canonical form.
+	if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+		return false
+	}
+
+	if parser.buffer[parser.buffer_pos+1] == '<' {
+		// Keep the handle as ''
+
+		// Eat '!<'
+		skip(parser)
+		skip(parser)
+
+		// Consume the tag value.
+		if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
+			return false
+		}
+
+		// Check for '>' and eat it.
+		if parser.buffer[parser.buffer_pos] != '>' {
+			yaml_parser_set_scanner_error(parser, "while scanning a tag",
+				start_mark, "did not find the expected '>'")
+			return false
+		}
+
+		skip(parser)
+	} else {
+		// The tag has either the '!suffix' or the '!handle!suffix' form.
+
+		// First, try to scan a handle.
+		if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) {
+			return false
+		}
+
+		// Check if it is, indeed, handle.
+		if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' {
+			// Scan the suffix now.
+			if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) {
+				return false
+			}
+		} else {
+			// It wasn't a handle after all.  Scan the rest of the tag.
+			if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) {
+				return false
+			}
+
+			// Set the handle to '!'.
+			handle = []byte{'!'}
+
+			// A special case: the '!' tag.  Set the handle to '' and the
+			// suffix to '!'.
+			if len(suffix) == 0 {
+				handle, suffix = suffix, handle
+			}
+		}
+	}
+
+	// Check the character which ends the tag.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	if !is_blankz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a tag",
+			start_mark, "did not find expected whitespace or line break")
+		return false
+	}
+
+	end_mark := parser.mark
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        yaml_TAG_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      handle,
+		suffix:     suffix,
+	}
+	return true
+}
+
+// Scan a tag handle.
+func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool {
+	// Check the initial '!' character.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	if parser.buffer[parser.buffer_pos] != '!' {
+		yaml_parser_set_scanner_tag_error(parser, directive,
+			start_mark, "did not find expected '!'")
+		return false
+	}
+
+	var s []byte
+
+	// Copy the '!' character.
+	s = read(parser, s)
+
+	// Copy all subsequent alphabetical and numerical characters.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	for is_alpha(parser.buffer, parser.buffer_pos) {
+		s = read(parser, s)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+
+	// Check if the trailing character is '!' and copy it.
+	if parser.buffer[parser.buffer_pos] == '!' {
+		s = read(parser, s)
+	} else {
+		// It's either the '!' tag or not really a tag handle.  If it's a %TAG
+		// directive, it's an error.  If it's a tag token, it must be a part of URI.
+		if directive && string(s) != "!" {
+			yaml_parser_set_scanner_tag_error(parser, directive,
+				start_mark, "did not find expected '!'")
+			return false
+		}
+	}
+
+	*handle = s
+	return true
+}
+
+// Scan a tag.
+func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
+	//size_t length = head ? strlen((char *)head) : 0
+	var s []byte
+	hasTag := len(head) > 0
+
+	// Copy the head if needed.
+	//
+	// Note that we don't copy the leading '!' character.
+	if len(head) > 1 {
+		s = append(s, head[1:]...)
+	}
+
+	// Scan the tag.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	// The set of characters that may appear in URI is as follows:
+	//
+	//      '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
+	//      '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
+	//      '%'.
+	// [Go] TODO Convert this into more reasonable logic.
+	for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' ||
+		parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' ||
+		parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' ||
+		parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' ||
+		parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' ||
+		parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' ||
+		parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' ||
+		parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' ||
+		parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' ||
+		parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' ||
+		parser.buffer[parser.buffer_pos] == '%' {
+		// Check if it is a URI-escape sequence.
+		if parser.buffer[parser.buffer_pos] == '%' {
+			if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) {
+				return false
+			}
+		} else {
+			s = read(parser, s)
+		}
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		hasTag = true
+	}
+
+	if !hasTag {
+		yaml_parser_set_scanner_tag_error(parser, directive,
+			start_mark, "did not find expected tag URI")
+		return false
+	}
+	*uri = s
+	return true
+}
+
+// Decode an URI-escape sequence corresponding to a single UTF-8 character.
+func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool {
+
+	// Decode the required number of characters.
+	w := 1024
+	for w > 0 {
+		// Check for a URI-escaped octet.
+		if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
+			return false
+		}
+
+		if !(parser.buffer[parser.buffer_pos] == '%' &&
+			is_hex(parser.buffer, parser.buffer_pos+1) &&
+			is_hex(parser.buffer, parser.buffer_pos+2)) {
+			return yaml_parser_set_scanner_tag_error(parser, directive,
+				start_mark, "did not find URI escaped octet")
+		}
+
+		// Get the octet.
+		octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2))
+
+		// If it is the leading octet, determine the length of the UTF-8 sequence.
+		if w == 1024 {
+			w = width(octet)
+			if w == 0 {
+				return yaml_parser_set_scanner_tag_error(parser, directive,
+					start_mark, "found an incorrect leading UTF-8 octet")
+			}
+		} else {
+			// Check if the trailing octet is correct.
+			if octet&0xC0 != 0x80 {
+				return yaml_parser_set_scanner_tag_error(parser, directive,
+					start_mark, "found an incorrect trailing UTF-8 octet")
+			}
+		}
+
+		// Copy the octet and move the pointers.
+		*s = append(*s, octet)
+		skip(parser)
+		skip(parser)
+		skip(parser)
+		w--
+	}
+	return true
+}
+
+// Scan a block scalar.
+func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool {
+	// Eat the indicator '|' or '>'.
+	start_mark := parser.mark
+	skip(parser)
+
+	// Scan the additional block scalar indicators.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+
+	// Check for a chomping indicator.
+	var chomping, increment int
+	if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
+		// Set the chomping method and eat the indicator.
+		if parser.buffer[parser.buffer_pos] == '+' {
+			chomping = +1
+		} else {
+			chomping = -1
+		}
+		skip(parser)
+
+		// Check for an indentation indicator.
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		if is_digit(parser.buffer, parser.buffer_pos) {
+			// Check that the indentation is greater than 0.
+			if parser.buffer[parser.buffer_pos] == '0' {
+				yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+					start_mark, "found an indentation indicator equal to 0")
+				return false
+			}
+
+			// Get the indentation level and eat the indicator.
+			increment = as_digit(parser.buffer, parser.buffer_pos)
+			skip(parser)
+		}
+
+	} else if is_digit(parser.buffer, parser.buffer_pos) {
+		// Do the same as above, but in the opposite order.
+
+		if parser.buffer[parser.buffer_pos] == '0' {
+			yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+				start_mark, "found an indentation indicator equal to 0")
+			return false
+		}
+		increment = as_digit(parser.buffer, parser.buffer_pos)
+		skip(parser)
+
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' {
+			if parser.buffer[parser.buffer_pos] == '+' {
+				chomping = +1
+			} else {
+				chomping = -1
+			}
+			skip(parser)
+		}
+	}
+
+	// Eat whitespaces and comments to the end of the line.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	for is_blank(parser.buffer, parser.buffer_pos) {
+		skip(parser)
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+	}
+	if parser.buffer[parser.buffer_pos] == '#' {
+		if !yaml_parser_scan_line_comment(parser, start_mark) {
+			return false
+		}
+		for !is_breakz(parser.buffer, parser.buffer_pos) {
+			skip(parser)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+	}
+
+	// Check if we are at the end of the line.
+	if !is_breakz(parser.buffer, parser.buffer_pos) {
+		yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+			start_mark, "did not find expected comment or line break")
+		return false
+	}
+
+	// Eat a line break.
+	if is_break(parser.buffer, parser.buffer_pos) {
+		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+			return false
+		}
+		skip_line(parser)
+	}
+
+	end_mark := parser.mark
+
+	// Set the indentation level if it was specified.
+	var indent int
+	if increment > 0 {
+		if parser.indent >= 0 {
+			indent = parser.indent + increment
+		} else {
+			indent = increment
+		}
+	}
+
+	// Scan the leading line breaks and determine the indentation level if needed.
+	var s, leading_break, trailing_breaks []byte
+	if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
+		return false
+	}
+
+	// Scan the block scalar content.
+	if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+		return false
+	}
+	var leading_blank, trailing_blank bool
+	for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) {
+		// We are at the beginning of a non-empty line.
+
+		// Is it a trailing whitespace?
+		trailing_blank = is_blank(parser.buffer, parser.buffer_pos)
+
+		// Check if we need to fold the leading line break.
+		if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' {
+			// Do we need to join the lines by space?
+			if len(trailing_breaks) == 0 {
+				s = append(s, ' ')
+			}
+		} else {
+			s = append(s, leading_break...)
+		}
+		leading_break = leading_break[:0]
+
+		// Append the remaining line breaks.
+		s = append(s, trailing_breaks...)
+		trailing_breaks = trailing_breaks[:0]
+
+		// Is it a leading whitespace?
+		leading_blank = is_blank(parser.buffer, parser.buffer_pos)
+
+		// Consume the current line.
+		for !is_breakz(parser.buffer, parser.buffer_pos) {
+			s = read(parser, s)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+
+		// Consume the line break.
+		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+			return false
+		}
+
+		leading_break = read_line(parser, leading_break)
+
+		// Eat the following indentation spaces and line breaks.
+		if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) {
+			return false
+		}
+	}
+
+	// Chomp the tail.
+	if chomping != -1 {
+		s = append(s, leading_break...)
+	}
+	if chomping == 1 {
+		s = append(s, trailing_breaks...)
+	}
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        yaml_SCALAR_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      s,
+		style:      yaml_LITERAL_SCALAR_STYLE,
+	}
+	if !literal {
+		token.style = yaml_FOLDED_SCALAR_STYLE
+	}
+	return true
+}
+
+// Scan indentation spaces and line breaks for a block scalar.  Determine the
+// indentation level if needed.
+func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool {
+	*end_mark = parser.mark
+
+	// Eat the indentation spaces and line breaks.
+	max_indent := 0
+	for {
+		// Eat the indentation spaces.
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+		for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) {
+			skip(parser)
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+		if parser.mark.column > max_indent {
+			max_indent = parser.mark.column
+		}
+
+		// Check for a tab character messing the indentation.
+		if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) {
+			return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
+				start_mark, "found a tab character where an indentation space is expected")
+		}
+
+		// Have we found a non-empty line?
+		if !is_break(parser.buffer, parser.buffer_pos) {
+			break
+		}
+
+		// Consume the line break.
+		if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+			return false
+		}
+		// [Go] Should really be returning breaks instead.
+		*breaks = read_line(parser, *breaks)
+		*end_mark = parser.mark
+	}
+
+	// Determine the indentation level if needed.
+	if *indent == 0 {
+		*indent = max_indent
+		if *indent < parser.indent+1 {
+			*indent = parser.indent + 1
+		}
+		if *indent < 1 {
+			*indent = 1
+		}
+	}
+	return true
+}
+
+// Scan a quoted scalar.
+func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool {
+	// Eat the left quote.
+	start_mark := parser.mark
+	skip(parser)
+
+	// Consume the content of the quoted scalar.
+	var s, leading_break, trailing_breaks, whitespaces []byte
+	for {
+		// Check that there are no document indicators at the beginning of the line.
+		if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+			return false
+		}
+
+		if parser.mark.column == 0 &&
+			((parser.buffer[parser.buffer_pos+0] == '-' &&
+				parser.buffer[parser.buffer_pos+1] == '-' &&
+				parser.buffer[parser.buffer_pos+2] == '-') ||
+				(parser.buffer[parser.buffer_pos+0] == '.' &&
+					parser.buffer[parser.buffer_pos+1] == '.' &&
+					parser.buffer[parser.buffer_pos+2] == '.')) &&
+			is_blankz(parser.buffer, parser.buffer_pos+3) {
+			yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
+				start_mark, "found unexpected document indicator")
+			return false
+		}
+
+		// Check for EOF.
+		if is_z(parser.buffer, parser.buffer_pos) {
+			yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
+				start_mark, "found unexpected end of stream")
+			return false
+		}
+
+		// Consume non-blank characters.
+		leading_blanks := false
+		for !is_blankz(parser.buffer, parser.buffer_pos) {
+			if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' {
+				// Is is an escaped single quote.
+				s = append(s, '\'')
+				skip(parser)
+				skip(parser)
+
+			} else if single && parser.buffer[parser.buffer_pos] == '\'' {
+				// It is a right single quote.
+				break
+			} else if !single && parser.buffer[parser.buffer_pos] == '"' {
+				// It is a right double quote.
+				break
+
+			} else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) {
+				// It is an escaped line break.
+				if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) {
+					return false
+				}
+				skip(parser)
+				skip_line(parser)
+				leading_blanks = true
+				break
+
+			} else if !single && parser.buffer[parser.buffer_pos] == '\\' {
+				// It is an escape sequence.
+				code_length := 0
+
+				// Check the escape character.
+				switch parser.buffer[parser.buffer_pos+1] {
+				case '0':
+					s = append(s, 0)
+				case 'a':
+					s = append(s, '\x07')
+				case 'b':
+					s = append(s, '\x08')
+				case 't', '\t':
+					s = append(s, '\x09')
+				case 'n':
+					s = append(s, '\x0A')
+				case 'v':
+					s = append(s, '\x0B')
+				case 'f':
+					s = append(s, '\x0C')
+				case 'r':
+					s = append(s, '\x0D')
+				case 'e':
+					s = append(s, '\x1B')
+				case ' ':
+					s = append(s, '\x20')
+				case '"':
+					s = append(s, '"')
+				case '\'':
+					s = append(s, '\'')
+				case '\\':
+					s = append(s, '\\')
+				case 'N': // NEL (#x85)
+					s = append(s, '\xC2')
+					s = append(s, '\x85')
+				case '_': // #xA0
+					s = append(s, '\xC2')
+					s = append(s, '\xA0')
+				case 'L': // LS (#x2028)
+					s = append(s, '\xE2')
+					s = append(s, '\x80')
+					s = append(s, '\xA8')
+				case 'P': // PS (#x2029)
+					s = append(s, '\xE2')
+					s = append(s, '\x80')
+					s = append(s, '\xA9')
+				case 'x':
+					code_length = 2
+				case 'u':
+					code_length = 4
+				case 'U':
+					code_length = 8
+				default:
+					yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+						start_mark, "found unknown escape character")
+					return false
+				}
+
+				skip(parser)
+				skip(parser)
+
+				// Consume an arbitrary escape code.
+				if code_length > 0 {
+					var value int
+
+					// Scan the character value.
+					if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) {
+						return false
+					}
+					for k := 0; k < code_length; k++ {
+						if !is_hex(parser.buffer, parser.buffer_pos+k) {
+							yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+								start_mark, "did not find expected hexdecimal number")
+							return false
+						}
+						value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k)
+					}
+
+					// Check the value and write the character.
+					if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF {
+						yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
+							start_mark, "found invalid Unicode character escape code")
+						return false
+					}
+					if value <= 0x7F {
+						s = append(s, byte(value))
+					} else if value <= 0x7FF {
+						s = append(s, byte(0xC0+(value>>6)))
+						s = append(s, byte(0x80+(value&0x3F)))
+					} else if value <= 0xFFFF {
+						s = append(s, byte(0xE0+(value>>12)))
+						s = append(s, byte(0x80+((value>>6)&0x3F)))
+						s = append(s, byte(0x80+(value&0x3F)))
+					} else {
+						s = append(s, byte(0xF0+(value>>18)))
+						s = append(s, byte(0x80+((value>>12)&0x3F)))
+						s = append(s, byte(0x80+((value>>6)&0x3F)))
+						s = append(s, byte(0x80+(value&0x3F)))
+					}
+
+					// Advance the pointer.
+					for k := 0; k < code_length; k++ {
+						skip(parser)
+					}
+				}
+			} else {
+				// It is a non-escaped non-blank character.
+				s = read(parser, s)
+			}
+			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+				return false
+			}
+		}
+
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+
+		// Check if we are at the end of the scalar.
+		if single {
+			if parser.buffer[parser.buffer_pos] == '\'' {
+				break
+			}
+		} else {
+			if parser.buffer[parser.buffer_pos] == '"' {
+				break
+			}
+		}
+
+		// Consume blank characters.
+		for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
+			if is_blank(parser.buffer, parser.buffer_pos) {
+				// Consume a space or a tab character.
+				if !leading_blanks {
+					whitespaces = read(parser, whitespaces)
+				} else {
+					skip(parser)
+				}
+			} else {
+				if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+					return false
+				}
+
+				// Check if it is a first line break.
+				if !leading_blanks {
+					whitespaces = whitespaces[:0]
+					leading_break = read_line(parser, leading_break)
+					leading_blanks = true
+				} else {
+					trailing_breaks = read_line(parser, trailing_breaks)
+				}
+			}
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+
+		// Join the whitespaces or fold line breaks.
+		if leading_blanks {
+			// Do we need to fold line breaks?
+			if len(leading_break) > 0 && leading_break[0] == '\n' {
+				if len(trailing_breaks) == 0 {
+					s = append(s, ' ')
+				} else {
+					s = append(s, trailing_breaks...)
+				}
+			} else {
+				s = append(s, leading_break...)
+				s = append(s, trailing_breaks...)
+			}
+			trailing_breaks = trailing_breaks[:0]
+			leading_break = leading_break[:0]
+		} else {
+			s = append(s, whitespaces...)
+			whitespaces = whitespaces[:0]
+		}
+	}
+
+	// Eat the right quote.
+	skip(parser)
+	end_mark := parser.mark
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        yaml_SCALAR_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      s,
+		style:      yaml_SINGLE_QUOTED_SCALAR_STYLE,
+	}
+	if !single {
+		token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
+	}
+	return true
+}
+
+// Scan a plain scalar.
+func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool {
+
+	var s, leading_break, trailing_breaks, whitespaces []byte
+	var leading_blanks bool
+	var indent = parser.indent + 1
+
+	start_mark := parser.mark
+	end_mark := parser.mark
+
+	// Consume the content of the plain scalar.
+	for {
+		// Check for a document indicator.
+		if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) {
+			return false
+		}
+		if parser.mark.column == 0 &&
+			((parser.buffer[parser.buffer_pos+0] == '-' &&
+				parser.buffer[parser.buffer_pos+1] == '-' &&
+				parser.buffer[parser.buffer_pos+2] == '-') ||
+				(parser.buffer[parser.buffer_pos+0] == '.' &&
+					parser.buffer[parser.buffer_pos+1] == '.' &&
+					parser.buffer[parser.buffer_pos+2] == '.')) &&
+			is_blankz(parser.buffer, parser.buffer_pos+3) {
+			break
+		}
+
+		// Check for a comment.
+		if parser.buffer[parser.buffer_pos] == '#' {
+			break
+		}
+
+		// Consume non-blank characters.
+		for !is_blankz(parser.buffer, parser.buffer_pos) {
+
+			// Check for indicators that may end a plain scalar.
+			if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
+				(parser.flow_level > 0 &&
+					(parser.buffer[parser.buffer_pos] == ',' ||
+						parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||
+						parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
+						parser.buffer[parser.buffer_pos] == '}')) {
+				break
+			}
+
+			// Check if we need to join whitespaces and breaks.
+			if leading_blanks || len(whitespaces) > 0 {
+				if leading_blanks {
+					// Do we need to fold line breaks?
+					if leading_break[0] == '\n' {
+						if len(trailing_breaks) == 0 {
+							s = append(s, ' ')
+						} else {
+							s = append(s, trailing_breaks...)
+						}
+					} else {
+						s = append(s, leading_break...)
+						s = append(s, trailing_breaks...)
+					}
+					trailing_breaks = trailing_breaks[:0]
+					leading_break = leading_break[:0]
+					leading_blanks = false
+				} else {
+					s = append(s, whitespaces...)
+					whitespaces = whitespaces[:0]
+				}
+			}
+
+			// Copy the character.
+			s = read(parser, s)
+
+			end_mark = parser.mark
+			if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+				return false
+			}
+		}
+
+		// Is it the end?
+		if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) {
+			break
+		}
+
+		// Consume blank characters.
+		if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+			return false
+		}
+
+		for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
+			if is_blank(parser.buffer, parser.buffer_pos) {
+
+				// Check for tab characters that abuse indentation.
+				if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
+					yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
+						start_mark, "found a tab character that violates indentation")
+					return false
+				}
+
+				// Consume a space or a tab character.
+				if !leading_blanks {
+					whitespaces = read(parser, whitespaces)
+				} else {
+					skip(parser)
+				}
+			} else {
+				if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+					return false
+				}
+
+				// Check if it is a first line break.
+				if !leading_blanks {
+					whitespaces = whitespaces[:0]
+					leading_break = read_line(parser, leading_break)
+					leading_blanks = true
+				} else {
+					trailing_breaks = read_line(parser, trailing_breaks)
+				}
+			}
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+		}
+
+		// Check indentation level.
+		if parser.flow_level == 0 && parser.mark.column < indent {
+			break
+		}
+	}
+
+	// Create a token.
+	*token = yaml_token_t{
+		typ:        yaml_SCALAR_TOKEN,
+		start_mark: start_mark,
+		end_mark:   end_mark,
+		value:      s,
+		style:      yaml_PLAIN_SCALAR_STYLE,
+	}
+
+	// Note that we change the 'simple_key_allowed' flag.
+	if leading_blanks {
+		parser.simple_key_allowed = true
+	}
+	return true
+}
+
+func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t) bool {
+	if parser.newlines > 0 {
+		return true
+	}
+
+	var start_mark yaml_mark_t
+	var text []byte
+
+	for peek := 0; peek < 512; peek++ {
+		if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
+			break
+		}
+		if is_blank(parser.buffer, parser.buffer_pos+peek) {
+			continue
+		}
+		if parser.buffer[parser.buffer_pos+peek] == '#' {
+			seen := parser.mark.index+peek
+			for {
+				if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+					return false
+				}
+				if is_breakz(parser.buffer, parser.buffer_pos) {
+					if parser.mark.index >= seen {
+						break
+					}
+					if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+						return false
+					}
+					skip_line(parser)
+				} else if parser.mark.index >= seen {
+					if len(text) == 0 {
+						start_mark = parser.mark
+					}
+					text = read(parser, text)
+				} else {
+					skip(parser)
+				}
+			}
+		}
+		break
+	}
+	if len(text) > 0 {
+		parser.comments = append(parser.comments, yaml_comment_t{
+			token_mark: token_mark,
+			start_mark: start_mark,
+			line: text,
+		})
+	}
+	return true
+}
+
+func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) bool {
+	token := parser.tokens[len(parser.tokens)-1]
+
+	if token.typ == yaml_FLOW_ENTRY_TOKEN && len(parser.tokens) > 1 {
+		token = parser.tokens[len(parser.tokens)-2]
+	}
+
+	var token_mark = token.start_mark
+	var start_mark yaml_mark_t
+	var next_indent = parser.indent
+	if next_indent < 0 {
+		next_indent = 0
+	}
+
+	var recent_empty = false
+	var first_empty = parser.newlines <= 1
+
+	var line = parser.mark.line
+	var column = parser.mark.column
+
+	var text []byte
+
+	// The foot line is the place where a comment must start to
+	// still be considered as a foot of the prior content.
+	// If there's some content in the currently parsed line, then
+	// the foot is the line below it.
+	var foot_line = -1
+	if scan_mark.line > 0 {
+		foot_line = parser.mark.line-parser.newlines+1
+		if parser.newlines == 0 && parser.mark.column > 1 {
+			foot_line++
+		}
+	}
+
+	var peek = 0
+	for ; peek < 512; peek++ {
+		if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) {
+			break
+		}
+		column++
+		if is_blank(parser.buffer, parser.buffer_pos+peek) {
+			continue
+		}
+		c := parser.buffer[parser.buffer_pos+peek]
+		var close_flow = parser.flow_level > 0 && (c == ']' || c == '}')
+		if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) {
+			// Got line break or terminator.
+			if close_flow || !recent_empty {
+				if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) {
+					// This is the first empty line and there were no empty lines before,
+					// so this initial part of the comment is a foot of the prior token
+					// instead of being a head for the following one. Split it up.
+					// Alternatively, this might also be the last comment inside a flow
+					// scope, so it must be a footer.
+					if len(text) > 0 {
+						if start_mark.column-1 < next_indent {
+							// If dedented it's unrelated to the prior token.
+							token_mark = start_mark
+						}
+						parser.comments = append(parser.comments, yaml_comment_t{
+							scan_mark:  scan_mark,
+							token_mark: token_mark,
+							start_mark: start_mark,
+							end_mark:   yaml_mark_t{parser.mark.index + peek, line, column},
+							foot:       text,
+						})
+						scan_mark = yaml_mark_t{parser.mark.index + peek, line, column}
+						token_mark = scan_mark
+						text = nil
+					}
+				} else {
+					if len(text) > 0 && parser.buffer[parser.buffer_pos+peek] != 0 {
+						text = append(text, '\n')
+					}
+				}
+			}
+			if !is_break(parser.buffer, parser.buffer_pos+peek) {
+				break
+			}
+			first_empty = false
+			recent_empty = true
+			column = 0
+			line++
+			continue
+		}
+
+		if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) {
+			// The comment at the different indentation is a foot of the
+			// preceding data rather than a head of the upcoming one.
+			parser.comments = append(parser.comments, yaml_comment_t{
+				scan_mark:  scan_mark,
+				token_mark: token_mark,
+				start_mark: start_mark,
+				end_mark:   yaml_mark_t{parser.mark.index + peek, line, column},
+				foot:       text,
+			})
+			scan_mark = yaml_mark_t{parser.mark.index + peek, line, column}
+			token_mark = scan_mark
+			text = nil
+		}
+
+		if parser.buffer[parser.buffer_pos+peek] != '#' {
+			break
+		}
+
+		if len(text) == 0 {
+			start_mark = yaml_mark_t{parser.mark.index + peek, line, column}
+		} else {
+			text = append(text, '\n')
+		}
+
+		recent_empty = false
+
+		// Consume until after the consumed comment line.
+		seen := parser.mark.index+peek
+		for {
+			if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
+				return false
+			}
+			if is_breakz(parser.buffer, parser.buffer_pos) {
+				if parser.mark.index >= seen {
+					break
+				}
+				if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) {
+					return false
+				}
+				skip_line(parser)
+			} else if parser.mark.index >= seen {
+				text = read(parser, text)
+			} else {
+				skip(parser)
+			}
+		}
+
+		peek = 0
+		column = 0
+		line = parser.mark.line
+		next_indent = parser.indent
+		if next_indent < 0 {
+			next_indent = 0
+		}
+	}
+
+	if len(text) > 0 {
+		parser.comments = append(parser.comments, yaml_comment_t{
+			scan_mark:  scan_mark,
+			token_mark: start_mark,
+			start_mark: start_mark,
+			end_mark:   yaml_mark_t{parser.mark.index + peek - 1, line, column},
+			head:       text,
+		})
+	}
+	return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/sorter.go b/vendor/gopkg.in/yaml.v3/sorter.go
new file mode 100644
index 000000000..9210ece7e
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/sorter.go
@@ -0,0 +1,134 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// 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 yaml
+
+import (
+	"reflect"
+	"unicode"
+)
+
+type keyList []reflect.Value
+
+func (l keyList) Len() int      { return len(l) }
+func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+func (l keyList) Less(i, j int) bool {
+	a := l[i]
+	b := l[j]
+	ak := a.Kind()
+	bk := b.Kind()
+	for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
+		a = a.Elem()
+		ak = a.Kind()
+	}
+	for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
+		b = b.Elem()
+		bk = b.Kind()
+	}
+	af, aok := keyFloat(a)
+	bf, bok := keyFloat(b)
+	if aok && bok {
+		if af != bf {
+			return af < bf
+		}
+		if ak != bk {
+			return ak < bk
+		}
+		return numLess(a, b)
+	}
+	if ak != reflect.String || bk != reflect.String {
+		return ak < bk
+	}
+	ar, br := []rune(a.String()), []rune(b.String())
+	digits := false
+	for i := 0; i < len(ar) && i < len(br); i++ {
+		if ar[i] == br[i] {
+			digits = unicode.IsDigit(ar[i])
+			continue
+		}
+		al := unicode.IsLetter(ar[i])
+		bl := unicode.IsLetter(br[i])
+		if al && bl {
+			return ar[i] < br[i]
+		}
+		if al || bl {
+			if digits {
+				return al
+			} else {
+				return bl
+			}
+		}
+		var ai, bi int
+		var an, bn int64
+		if ar[i] == '0' || br[i] == '0' {
+			for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
+				if ar[j] != '0' {
+					an = 1
+					bn = 1
+					break
+				}
+			}
+		}
+		for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
+			an = an*10 + int64(ar[ai]-'0')
+		}
+		for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
+			bn = bn*10 + int64(br[bi]-'0')
+		}
+		if an != bn {
+			return an < bn
+		}
+		if ai != bi {
+			return ai < bi
+		}
+		return ar[i] < br[i]
+	}
+	return len(ar) < len(br)
+}
+
+// keyFloat returns a float value for v if it is a number/bool
+// and whether it is a number/bool or not.
+func keyFloat(v reflect.Value) (f float64, ok bool) {
+	switch v.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return float64(v.Int()), true
+	case reflect.Float32, reflect.Float64:
+		return v.Float(), true
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return float64(v.Uint()), true
+	case reflect.Bool:
+		if v.Bool() {
+			return 1, true
+		}
+		return 0, true
+	}
+	return 0, false
+}
+
+// numLess returns whether a < b.
+// a and b must necessarily have the same kind.
+func numLess(a, b reflect.Value) bool {
+	switch a.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return a.Int() < b.Int()
+	case reflect.Float32, reflect.Float64:
+		return a.Float() < b.Float()
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return a.Uint() < b.Uint()
+	case reflect.Bool:
+		return !a.Bool() && b.Bool()
+	}
+	panic("not a number")
+}
diff --git a/vendor/gopkg.in/yaml.v3/writerc.go b/vendor/gopkg.in/yaml.v3/writerc.go
new file mode 100644
index 000000000..b8a116bf9
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/writerc.go
@@ -0,0 +1,48 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+// Set the writer error and return false.
+func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
+	emitter.error = yaml_WRITER_ERROR
+	emitter.problem = problem
+	return false
+}
+
+// Flush the output buffer.
+func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
+	if emitter.write_handler == nil {
+		panic("write handler not set")
+	}
+
+	// Check if the buffer is empty.
+	if emitter.buffer_pos == 0 {
+		return true
+	}
+
+	if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
+		return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
+	}
+	emitter.buffer_pos = 0
+	return true
+}
diff --git a/vendor/gopkg.in/yaml.v3/yaml.go b/vendor/gopkg.in/yaml.v3/yaml.go
new file mode 100644
index 000000000..8cec6da48
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/yaml.go
@@ -0,0 +1,698 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+//
+// 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 yaml implements YAML support for the Go language.
+//
+// Source code and other details for the project are available at GitHub:
+//
+//   https://github.com/go-yaml/yaml
+//
+package yaml
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"reflect"
+	"strings"
+	"sync"
+	"unicode/utf8"
+)
+
+// The Unmarshaler interface may be implemented by types to customize their
+// behavior when being unmarshaled from a YAML document.
+type Unmarshaler interface {
+	UnmarshalYAML(value *Node) error
+}
+
+type obsoleteUnmarshaler interface {
+	UnmarshalYAML(unmarshal func(interface{}) error) error
+}
+
+// The Marshaler interface may be implemented by types to customize their
+// behavior when being marshaled into a YAML document. The returned value
+// is marshaled in place of the original value implementing Marshaler.
+//
+// If an error is returned by MarshalYAML, the marshaling procedure stops
+// and returns with the provided error.
+type Marshaler interface {
+	MarshalYAML() (interface{}, error)
+}
+
+// Unmarshal decodes the first document found within the in byte slice
+// and assigns decoded values into the out value.
+//
+// Maps and pointers (to a struct, string, int, etc) are accepted as out
+// values. If an internal pointer within a struct is not initialized,
+// the yaml package will initialize it if necessary for unmarshalling
+// the provided data. The out parameter must not be nil.
+//
+// The type of the decoded values should be compatible with the respective
+// values in out. If one or more values cannot be decoded due to a type
+// mismatches, decoding continues partially until the end of the YAML
+// content, and a *yaml.TypeError is returned with details for all
+// missed values.
+//
+// Struct fields are only unmarshalled if they are exported (have an
+// upper case first letter), and are unmarshalled using the field name
+// lowercased as the default key. Custom keys may be defined via the
+// "yaml" name in the field tag: the content preceding the first comma
+// is used as the key, and the following comma-separated options are
+// used to tweak the marshalling process (see Marshal).
+// Conflicting names result in a runtime error.
+//
+// For example:
+//
+//     type T struct {
+//         F int `yaml:"a,omitempty"`
+//         B int
+//     }
+//     var t T
+//     yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
+//
+// See the documentation of Marshal for the format of tags and a list of
+// supported tag options.
+//
+func Unmarshal(in []byte, out interface{}) (err error) {
+	return unmarshal(in, out, false)
+}
+
+// A Decoder reads and decodes YAML values from an input stream.
+type Decoder struct {
+	parser      *parser
+	knownFields bool
+}
+
+// NewDecoder returns a new decoder that reads from r.
+//
+// The decoder introduces its own buffering and may read
+// data from r beyond the YAML values requested.
+func NewDecoder(r io.Reader) *Decoder {
+	return &Decoder{
+		parser: newParserFromReader(r),
+	}
+}
+
+// KnownFields ensures that the keys in decoded mappings to
+// exist as fields in the struct being decoded into.
+func (dec *Decoder) KnownFields(enable bool) {
+	dec.knownFields = enable
+}
+
+// Decode reads the next YAML-encoded value from its input
+// and stores it in the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about the
+// conversion of YAML into a Go value.
+func (dec *Decoder) Decode(v interface{}) (err error) {
+	d := newDecoder()
+	d.knownFields = dec.knownFields
+	defer handleErr(&err)
+	node := dec.parser.parse()
+	if node == nil {
+		return io.EOF
+	}
+	out := reflect.ValueOf(v)
+	if out.Kind() == reflect.Ptr && !out.IsNil() {
+		out = out.Elem()
+	}
+	d.unmarshal(node, out)
+	if len(d.terrors) > 0 {
+		return &TypeError{d.terrors}
+	}
+	return nil
+}
+
+// Decode decodes the node and stores its data into the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about the
+// conversion of YAML into a Go value.
+func (n *Node) Decode(v interface{}) (err error) {
+	d := newDecoder()
+	defer handleErr(&err)
+	out := reflect.ValueOf(v)
+	if out.Kind() == reflect.Ptr && !out.IsNil() {
+		out = out.Elem()
+	}
+	d.unmarshal(n, out)
+	if len(d.terrors) > 0 {
+		return &TypeError{d.terrors}
+	}
+	return nil
+}
+
+func unmarshal(in []byte, out interface{}, strict bool) (err error) {
+	defer handleErr(&err)
+	d := newDecoder()
+	p := newParser(in)
+	defer p.destroy()
+	node := p.parse()
+	if node != nil {
+		v := reflect.ValueOf(out)
+		if v.Kind() == reflect.Ptr && !v.IsNil() {
+			v = v.Elem()
+		}
+		d.unmarshal(node, v)
+	}
+	if len(d.terrors) > 0 {
+		return &TypeError{d.terrors}
+	}
+	return nil
+}
+
+// Marshal serializes the value provided into a YAML document. The structure
+// of the generated document will reflect the structure of the value itself.
+// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
+//
+// Struct fields are only marshalled if they are exported (have an upper case
+// first letter), and are marshalled using the field name lowercased as the
+// default key. Custom keys may be defined via the "yaml" name in the field
+// tag: the content preceding the first comma is used as the key, and the
+// following comma-separated options are used to tweak the marshalling process.
+// Conflicting names result in a runtime error.
+//
+// The field tag format accepted is:
+//
+//     `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
+//
+// The following flags are currently supported:
+//
+//     omitempty    Only include the field if it's not set to the zero
+//                  value for the type or to empty slices or maps.
+//                  Zero valued structs will be omitted if all their public
+//                  fields are zero, unless they implement an IsZero
+//                  method (see the IsZeroer interface type), in which
+//                  case the field will be excluded if IsZero returns true.
+//
+//     flow         Marshal using a flow style (useful for structs,
+//                  sequences and maps).
+//
+//     inline       Inline the field, which must be a struct or a map,
+//                  causing all of its fields or keys to be processed as if
+//                  they were part of the outer struct. For maps, keys must
+//                  not conflict with the yaml keys of other struct fields.
+//
+// In addition, if the key is "-", the field is ignored.
+//
+// For example:
+//
+//     type T struct {
+//         F int `yaml:"a,omitempty"`
+//         B int
+//     }
+//     yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
+//     yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
+//
+func Marshal(in interface{}) (out []byte, err error) {
+	defer handleErr(&err)
+	e := newEncoder()
+	defer e.destroy()
+	e.marshalDoc("", reflect.ValueOf(in))
+	e.finish()
+	out = e.out
+	return
+}
+
+// An Encoder writes YAML values to an output stream.
+type Encoder struct {
+	encoder *encoder
+}
+
+// NewEncoder returns a new encoder that writes to w.
+// The Encoder should be closed after use to flush all data
+// to w.
+func NewEncoder(w io.Writer) *Encoder {
+	return &Encoder{
+		encoder: newEncoderWithWriter(w),
+	}
+}
+
+// Encode writes the YAML encoding of v to the stream.
+// If multiple items are encoded to the stream, the
+// second and subsequent document will be preceded
+// with a "---" document separator, but the first will not.
+//
+// See the documentation for Marshal for details about the conversion of Go
+// values to YAML.
+func (e *Encoder) Encode(v interface{}) (err error) {
+	defer handleErr(&err)
+	e.encoder.marshalDoc("", reflect.ValueOf(v))
+	return nil
+}
+
+// Encode encodes value v and stores its representation in n.
+//
+// See the documentation for Marshal for details about the
+// conversion of Go values into YAML.
+func (n *Node) Encode(v interface{}) (err error) {
+	defer handleErr(&err)
+	e := newEncoder()
+	defer e.destroy()
+	e.marshalDoc("", reflect.ValueOf(v))
+	e.finish()
+	p := newParser(e.out)
+	p.textless = true
+	defer p.destroy()
+	doc := p.parse()
+	*n = *doc.Content[0]
+	return nil
+}
+
+// SetIndent changes the used indentation used when encoding.
+func (e *Encoder) SetIndent(spaces int) {
+	if spaces < 0 {
+		panic("yaml: cannot indent to a negative number of spaces")
+	}
+	e.encoder.indent = spaces
+}
+
+// Close closes the encoder by writing any remaining data.
+// It does not write a stream terminating string "...".
+func (e *Encoder) Close() (err error) {
+	defer handleErr(&err)
+	e.encoder.finish()
+	return nil
+}
+
+func handleErr(err *error) {
+	if v := recover(); v != nil {
+		if e, ok := v.(yamlError); ok {
+			*err = e.err
+		} else {
+			panic(v)
+		}
+	}
+}
+
+type yamlError struct {
+	err error
+}
+
+func fail(err error) {
+	panic(yamlError{err})
+}
+
+func failf(format string, args ...interface{}) {
+	panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
+}
+
+// A TypeError is returned by Unmarshal when one or more fields in
+// the YAML document cannot be properly decoded into the requested
+// types. When this error is returned, the value is still
+// unmarshaled partially.
+type TypeError struct {
+	Errors []string
+}
+
+func (e *TypeError) Error() string {
+	return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))
+}
+
+type Kind uint32
+
+const (
+	DocumentNode Kind = 1 << iota
+	SequenceNode
+	MappingNode
+	ScalarNode
+	AliasNode
+)
+
+type Style uint32
+
+const (
+	TaggedStyle Style = 1 << iota
+	DoubleQuotedStyle
+	SingleQuotedStyle
+	LiteralStyle
+	FoldedStyle
+	FlowStyle
+)
+
+// Node represents an element in the YAML document hierarchy. While documents
+// are typically encoded and decoded into higher level types, such as structs
+// and maps, Node is an intermediate representation that allows detailed
+// control over the content being decoded or encoded.
+//
+// It's worth noting that although Node offers access into details such as
+// line numbers, colums, and comments, the content when re-encoded will not
+// have its original textual representation preserved. An effort is made to
+// render the data plesantly, and to preserve comments near the data they
+// describe, though.
+//
+// Values that make use of the Node type interact with the yaml package in the
+// same way any other type would do, by encoding and decoding yaml data
+// directly or indirectly into them.
+//
+// For example:
+//
+//     var person struct {
+//             Name    string
+//             Address yaml.Node
+//     }
+//     err := yaml.Unmarshal(data, &person)
+// 
+// Or by itself:
+//
+//     var person Node
+//     err := yaml.Unmarshal(data, &person)
+//
+type Node struct {
+	// Kind defines whether the node is a document, a mapping, a sequence,
+	// a scalar value, or an alias to another node. The specific data type of
+	// scalar nodes may be obtained via the ShortTag and LongTag methods.
+	Kind  Kind
+
+	// Style allows customizing the apperance of the node in the tree.
+	Style Style
+
+	// Tag holds the YAML tag defining the data type for the value.
+	// When decoding, this field will always be set to the resolved tag,
+	// even when it wasn't explicitly provided in the YAML content.
+	// When encoding, if this field is unset the value type will be
+	// implied from the node properties, and if it is set, it will only
+	// be serialized into the representation if TaggedStyle is used or
+	// the implicit tag diverges from the provided one.
+	Tag string
+
+	// Value holds the unescaped and unquoted represenation of the value.
+	Value string
+
+	// Anchor holds the anchor name for this node, which allows aliases to point to it.
+	Anchor string
+
+	// Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
+	Alias *Node
+
+	// Content holds contained nodes for documents, mappings, and sequences.
+	Content []*Node
+
+	// HeadComment holds any comments in the lines preceding the node and
+	// not separated by an empty line.
+	HeadComment string
+
+	// LineComment holds any comments at the end of the line where the node is in.
+	LineComment string
+
+	// FootComment holds any comments following the node and before empty lines.
+	FootComment string
+
+	// Line and Column hold the node position in the decoded YAML text.
+	// These fields are not respected when encoding the node.
+	Line   int
+	Column int
+}
+
+// IsZero returns whether the node has all of its fields unset.
+func (n *Node) IsZero() bool {
+	return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&
+		n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
+}
+
+
+// LongTag returns the long form of the tag that indicates the data type for
+// the node. If the Tag field isn't explicitly defined, one will be computed
+// based on the node properties.
+func (n *Node) LongTag() string {
+	return longTag(n.ShortTag())
+}
+
+// ShortTag returns the short form of the YAML tag that indicates data type for
+// the node. If the Tag field isn't explicitly defined, one will be computed
+// based on the node properties.
+func (n *Node) ShortTag() string {
+	if n.indicatedString() {
+		return strTag
+	}
+	if n.Tag == "" || n.Tag == "!" {
+		switch n.Kind {
+		case MappingNode:
+			return mapTag
+		case SequenceNode:
+			return seqTag
+		case AliasNode:
+			if n.Alias != nil {
+				return n.Alias.ShortTag()
+			}
+		case ScalarNode:
+			tag, _ := resolve("", n.Value)
+			return tag
+		case 0:
+			// Special case to make the zero value convenient.
+			if n.IsZero() {
+				return nullTag
+			}
+		}
+		return ""
+	}
+	return shortTag(n.Tag)
+}
+
+func (n *Node) indicatedString() bool {
+	return n.Kind == ScalarNode &&
+		(shortTag(n.Tag) == strTag ||
+			(n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
+}
+
+// SetString is a convenience function that sets the node to a string value
+// and defines its style in a pleasant way depending on its content.
+func (n *Node) SetString(s string) {
+	n.Kind = ScalarNode
+	if utf8.ValidString(s) {
+		n.Value = s
+		n.Tag = strTag
+	} else {
+		n.Value = encodeBase64(s)
+		n.Tag = binaryTag
+	}
+	if strings.Contains(n.Value, "\n") {
+		n.Style = LiteralStyle
+	}
+}
+
+// --------------------------------------------------------------------------
+// Maintain a mapping of keys to structure field indexes
+
+// The code in this section was copied from mgo/bson.
+
+// structInfo holds details for the serialization of fields of
+// a given struct.
+type structInfo struct {
+	FieldsMap  map[string]fieldInfo
+	FieldsList []fieldInfo
+
+	// InlineMap is the number of the field in the struct that
+	// contains an ,inline map, or -1 if there's none.
+	InlineMap int
+
+	// InlineUnmarshalers holds indexes to inlined fields that
+	// contain unmarshaler values.
+	InlineUnmarshalers [][]int
+}
+
+type fieldInfo struct {
+	Key       string
+	Num       int
+	OmitEmpty bool
+	Flow      bool
+	// Id holds the unique field identifier, so we can cheaply
+	// check for field duplicates without maintaining an extra map.
+	Id int
+
+	// Inline holds the field index if the field is part of an inlined struct.
+	Inline []int
+}
+
+var structMap = make(map[reflect.Type]*structInfo)
+var fieldMapMutex sync.RWMutex
+var unmarshalerType reflect.Type
+
+func init() {
+	var v Unmarshaler
+	unmarshalerType = reflect.ValueOf(&v).Elem().Type()
+}
+
+func getStructInfo(st reflect.Type) (*structInfo, error) {
+	fieldMapMutex.RLock()
+	sinfo, found := structMap[st]
+	fieldMapMutex.RUnlock()
+	if found {
+		return sinfo, nil
+	}
+
+	n := st.NumField()
+	fieldsMap := make(map[string]fieldInfo)
+	fieldsList := make([]fieldInfo, 0, n)
+	inlineMap := -1
+	inlineUnmarshalers := [][]int(nil)
+	for i := 0; i != n; i++ {
+		field := st.Field(i)
+		if field.PkgPath != "" && !field.Anonymous {
+			continue // Private field
+		}
+
+		info := fieldInfo{Num: i}
+
+		tag := field.Tag.Get("yaml")
+		if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
+			tag = string(field.Tag)
+		}
+		if tag == "-" {
+			continue
+		}
+
+		inline := false
+		fields := strings.Split(tag, ",")
+		if len(fields) > 1 {
+			for _, flag := range fields[1:] {
+				switch flag {
+				case "omitempty":
+					info.OmitEmpty = true
+				case "flow":
+					info.Flow = true
+				case "inline":
+					inline = true
+				default:
+					return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
+				}
+			}
+			tag = fields[0]
+		}
+
+		if inline {
+			switch field.Type.Kind() {
+			case reflect.Map:
+				if inlineMap >= 0 {
+					return nil, errors.New("multiple ,inline maps in struct " + st.String())
+				}
+				if field.Type.Key() != reflect.TypeOf("") {
+					return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
+				}
+				inlineMap = info.Num
+			case reflect.Struct, reflect.Ptr:
+				ftype := field.Type
+				for ftype.Kind() == reflect.Ptr {
+					ftype = ftype.Elem()
+				}
+				if ftype.Kind() != reflect.Struct {
+					return nil, errors.New("option ,inline may only be used on a struct or map field")
+				}
+				if reflect.PtrTo(ftype).Implements(unmarshalerType) {
+					inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
+				} else {
+					sinfo, err := getStructInfo(ftype)
+					if err != nil {
+						return nil, err
+					}
+					for _, index := range sinfo.InlineUnmarshalers {
+						inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
+					}
+					for _, finfo := range sinfo.FieldsList {
+						if _, found := fieldsMap[finfo.Key]; found {
+							msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
+							return nil, errors.New(msg)
+						}
+						if finfo.Inline == nil {
+							finfo.Inline = []int{i, finfo.Num}
+						} else {
+							finfo.Inline = append([]int{i}, finfo.Inline...)
+						}
+						finfo.Id = len(fieldsList)
+						fieldsMap[finfo.Key] = finfo
+						fieldsList = append(fieldsList, finfo)
+					}
+				}
+			default:
+				return nil, errors.New("option ,inline may only be used on a struct or map field")
+			}
+			continue
+		}
+
+		if tag != "" {
+			info.Key = tag
+		} else {
+			info.Key = strings.ToLower(field.Name)
+		}
+
+		if _, found = fieldsMap[info.Key]; found {
+			msg := "duplicated key '" + info.Key + "' in struct " + st.String()
+			return nil, errors.New(msg)
+		}
+
+		info.Id = len(fieldsList)
+		fieldsList = append(fieldsList, info)
+		fieldsMap[info.Key] = info
+	}
+
+	sinfo = &structInfo{
+		FieldsMap:          fieldsMap,
+		FieldsList:         fieldsList,
+		InlineMap:          inlineMap,
+		InlineUnmarshalers: inlineUnmarshalers,
+	}
+
+	fieldMapMutex.Lock()
+	structMap[st] = sinfo
+	fieldMapMutex.Unlock()
+	return sinfo, nil
+}
+
+// IsZeroer is used to check whether an object is zero to
+// determine whether it should be omitted when marshaling
+// with the omitempty flag. One notable implementation
+// is time.Time.
+type IsZeroer interface {
+	IsZero() bool
+}
+
+func isZero(v reflect.Value) bool {
+	kind := v.Kind()
+	if z, ok := v.Interface().(IsZeroer); ok {
+		if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
+			return true
+		}
+		return z.IsZero()
+	}
+	switch kind {
+	case reflect.String:
+		return len(v.String()) == 0
+	case reflect.Interface, reflect.Ptr:
+		return v.IsNil()
+	case reflect.Slice:
+		return v.Len() == 0
+	case reflect.Map:
+		return v.Len() == 0
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+	case reflect.Float32, reflect.Float64:
+		return v.Float() == 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+	case reflect.Bool:
+		return !v.Bool()
+	case reflect.Struct:
+		vt := v.Type()
+		for i := v.NumField() - 1; i >= 0; i-- {
+			if vt.Field(i).PkgPath != "" {
+				continue // Private field
+			}
+			if !isZero(v.Field(i)) {
+				return false
+			}
+		}
+		return true
+	}
+	return false
+}
diff --git a/vendor/gopkg.in/yaml.v3/yamlh.go b/vendor/gopkg.in/yaml.v3/yamlh.go
new file mode 100644
index 000000000..7c6d00770
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/yamlh.go
@@ -0,0 +1,807 @@
+//
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+import (
+	"fmt"
+	"io"
+)
+
+// The version directive data.
+type yaml_version_directive_t struct {
+	major int8 // The major version number.
+	minor int8 // The minor version number.
+}
+
+// The tag directive data.
+type yaml_tag_directive_t struct {
+	handle []byte // The tag handle.
+	prefix []byte // The tag prefix.
+}
+
+type yaml_encoding_t int
+
+// The stream encoding.
+const (
+	// Let the parser choose the encoding.
+	yaml_ANY_ENCODING yaml_encoding_t = iota
+
+	yaml_UTF8_ENCODING    // The default UTF-8 encoding.
+	yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
+	yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
+)
+
+type yaml_break_t int
+
+// Line break types.
+const (
+	// Let the parser choose the break type.
+	yaml_ANY_BREAK yaml_break_t = iota
+
+	yaml_CR_BREAK   // Use CR for line breaks (Mac style).
+	yaml_LN_BREAK   // Use LN for line breaks (Unix style).
+	yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
+)
+
+type yaml_error_type_t int
+
+// Many bad things could happen with the parser and emitter.
+const (
+	// No error is produced.
+	yaml_NO_ERROR yaml_error_type_t = iota
+
+	yaml_MEMORY_ERROR   // Cannot allocate or reallocate a block of memory.
+	yaml_READER_ERROR   // Cannot read or decode the input stream.
+	yaml_SCANNER_ERROR  // Cannot scan the input stream.
+	yaml_PARSER_ERROR   // Cannot parse the input stream.
+	yaml_COMPOSER_ERROR // Cannot compose a YAML document.
+	yaml_WRITER_ERROR   // Cannot write to the output stream.
+	yaml_EMITTER_ERROR  // Cannot emit a YAML stream.
+)
+
+// The pointer position.
+type yaml_mark_t struct {
+	index  int // The position index.
+	line   int // The position line.
+	column int // The position column.
+}
+
+// Node Styles
+
+type yaml_style_t int8
+
+type yaml_scalar_style_t yaml_style_t
+
+// Scalar styles.
+const (
+	// Let the emitter choose the style.
+	yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0
+
+	yaml_PLAIN_SCALAR_STYLE         yaml_scalar_style_t = 1 << iota // The plain scalar style.
+	yaml_SINGLE_QUOTED_SCALAR_STYLE                                 // The single-quoted scalar style.
+	yaml_DOUBLE_QUOTED_SCALAR_STYLE                                 // The double-quoted scalar style.
+	yaml_LITERAL_SCALAR_STYLE                                       // The literal scalar style.
+	yaml_FOLDED_SCALAR_STYLE                                        // The folded scalar style.
+)
+
+type yaml_sequence_style_t yaml_style_t
+
+// Sequence styles.
+const (
+	// Let the emitter choose the style.
+	yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
+
+	yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
+	yaml_FLOW_SEQUENCE_STYLE  // The flow sequence style.
+)
+
+type yaml_mapping_style_t yaml_style_t
+
+// Mapping styles.
+const (
+	// Let the emitter choose the style.
+	yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
+
+	yaml_BLOCK_MAPPING_STYLE // The block mapping style.
+	yaml_FLOW_MAPPING_STYLE  // The flow mapping style.
+)
+
+// Tokens
+
+type yaml_token_type_t int
+
+// Token types.
+const (
+	// An empty token.
+	yaml_NO_TOKEN yaml_token_type_t = iota
+
+	yaml_STREAM_START_TOKEN // A STREAM-START token.
+	yaml_STREAM_END_TOKEN   // A STREAM-END token.
+
+	yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
+	yaml_TAG_DIRECTIVE_TOKEN     // A TAG-DIRECTIVE token.
+	yaml_DOCUMENT_START_TOKEN    // A DOCUMENT-START token.
+	yaml_DOCUMENT_END_TOKEN      // A DOCUMENT-END token.
+
+	yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
+	yaml_BLOCK_MAPPING_START_TOKEN  // A BLOCK-SEQUENCE-END token.
+	yaml_BLOCK_END_TOKEN            // A BLOCK-END token.
+
+	yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
+	yaml_FLOW_SEQUENCE_END_TOKEN   // A FLOW-SEQUENCE-END token.
+	yaml_FLOW_MAPPING_START_TOKEN  // A FLOW-MAPPING-START token.
+	yaml_FLOW_MAPPING_END_TOKEN    // A FLOW-MAPPING-END token.
+
+	yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
+	yaml_FLOW_ENTRY_TOKEN  // A FLOW-ENTRY token.
+	yaml_KEY_TOKEN         // A KEY token.
+	yaml_VALUE_TOKEN       // A VALUE token.
+
+	yaml_ALIAS_TOKEN  // An ALIAS token.
+	yaml_ANCHOR_TOKEN // An ANCHOR token.
+	yaml_TAG_TOKEN    // A TAG token.
+	yaml_SCALAR_TOKEN // A SCALAR token.
+)
+
+func (tt yaml_token_type_t) String() string {
+	switch tt {
+	case yaml_NO_TOKEN:
+		return "yaml_NO_TOKEN"
+	case yaml_STREAM_START_TOKEN:
+		return "yaml_STREAM_START_TOKEN"
+	case yaml_STREAM_END_TOKEN:
+		return "yaml_STREAM_END_TOKEN"
+	case yaml_VERSION_DIRECTIVE_TOKEN:
+		return "yaml_VERSION_DIRECTIVE_TOKEN"
+	case yaml_TAG_DIRECTIVE_TOKEN:
+		return "yaml_TAG_DIRECTIVE_TOKEN"
+	case yaml_DOCUMENT_START_TOKEN:
+		return "yaml_DOCUMENT_START_TOKEN"
+	case yaml_DOCUMENT_END_TOKEN:
+		return "yaml_DOCUMENT_END_TOKEN"
+	case yaml_BLOCK_SEQUENCE_START_TOKEN:
+		return "yaml_BLOCK_SEQUENCE_START_TOKEN"
+	case yaml_BLOCK_MAPPING_START_TOKEN:
+		return "yaml_BLOCK_MAPPING_START_TOKEN"
+	case yaml_BLOCK_END_TOKEN:
+		return "yaml_BLOCK_END_TOKEN"
+	case yaml_FLOW_SEQUENCE_START_TOKEN:
+		return "yaml_FLOW_SEQUENCE_START_TOKEN"
+	case yaml_FLOW_SEQUENCE_END_TOKEN:
+		return "yaml_FLOW_SEQUENCE_END_TOKEN"
+	case yaml_FLOW_MAPPING_START_TOKEN:
+		return "yaml_FLOW_MAPPING_START_TOKEN"
+	case yaml_FLOW_MAPPING_END_TOKEN:
+		return "yaml_FLOW_MAPPING_END_TOKEN"
+	case yaml_BLOCK_ENTRY_TOKEN:
+		return "yaml_BLOCK_ENTRY_TOKEN"
+	case yaml_FLOW_ENTRY_TOKEN:
+		return "yaml_FLOW_ENTRY_TOKEN"
+	case yaml_KEY_TOKEN:
+		return "yaml_KEY_TOKEN"
+	case yaml_VALUE_TOKEN:
+		return "yaml_VALUE_TOKEN"
+	case yaml_ALIAS_TOKEN:
+		return "yaml_ALIAS_TOKEN"
+	case yaml_ANCHOR_TOKEN:
+		return "yaml_ANCHOR_TOKEN"
+	case yaml_TAG_TOKEN:
+		return "yaml_TAG_TOKEN"
+	case yaml_SCALAR_TOKEN:
+		return "yaml_SCALAR_TOKEN"
+	}
+	return "<unknown token>"
+}
+
+// The token structure.
+type yaml_token_t struct {
+	// The token type.
+	typ yaml_token_type_t
+
+	// The start/end of the token.
+	start_mark, end_mark yaml_mark_t
+
+	// The stream encoding (for yaml_STREAM_START_TOKEN).
+	encoding yaml_encoding_t
+
+	// The alias/anchor/scalar value or tag/tag directive handle
+	// (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
+	value []byte
+
+	// The tag suffix (for yaml_TAG_TOKEN).
+	suffix []byte
+
+	// The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
+	prefix []byte
+
+	// The scalar style (for yaml_SCALAR_TOKEN).
+	style yaml_scalar_style_t
+
+	// The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
+	major, minor int8
+}
+
+// Events
+
+type yaml_event_type_t int8
+
+// Event types.
+const (
+	// An empty event.
+	yaml_NO_EVENT yaml_event_type_t = iota
+
+	yaml_STREAM_START_EVENT   // A STREAM-START event.
+	yaml_STREAM_END_EVENT     // A STREAM-END event.
+	yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
+	yaml_DOCUMENT_END_EVENT   // A DOCUMENT-END event.
+	yaml_ALIAS_EVENT          // An ALIAS event.
+	yaml_SCALAR_EVENT         // A SCALAR event.
+	yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
+	yaml_SEQUENCE_END_EVENT   // A SEQUENCE-END event.
+	yaml_MAPPING_START_EVENT  // A MAPPING-START event.
+	yaml_MAPPING_END_EVENT    // A MAPPING-END event.
+	yaml_TAIL_COMMENT_EVENT
+)
+
+var eventStrings = []string{
+	yaml_NO_EVENT:             "none",
+	yaml_STREAM_START_EVENT:   "stream start",
+	yaml_STREAM_END_EVENT:     "stream end",
+	yaml_DOCUMENT_START_EVENT: "document start",
+	yaml_DOCUMENT_END_EVENT:   "document end",
+	yaml_ALIAS_EVENT:          "alias",
+	yaml_SCALAR_EVENT:         "scalar",
+	yaml_SEQUENCE_START_EVENT: "sequence start",
+	yaml_SEQUENCE_END_EVENT:   "sequence end",
+	yaml_MAPPING_START_EVENT:  "mapping start",
+	yaml_MAPPING_END_EVENT:    "mapping end",
+	yaml_TAIL_COMMENT_EVENT:   "tail comment",
+}
+
+func (e yaml_event_type_t) String() string {
+	if e < 0 || int(e) >= len(eventStrings) {
+		return fmt.Sprintf("unknown event %d", e)
+	}
+	return eventStrings[e]
+}
+
+// The event structure.
+type yaml_event_t struct {
+
+	// The event type.
+	typ yaml_event_type_t
+
+	// The start and end of the event.
+	start_mark, end_mark yaml_mark_t
+
+	// The document encoding (for yaml_STREAM_START_EVENT).
+	encoding yaml_encoding_t
+
+	// The version directive (for yaml_DOCUMENT_START_EVENT).
+	version_directive *yaml_version_directive_t
+
+	// The list of tag directives (for yaml_DOCUMENT_START_EVENT).
+	tag_directives []yaml_tag_directive_t
+
+	// The comments
+	head_comment []byte
+	line_comment []byte
+	foot_comment []byte
+	tail_comment []byte
+
+	// The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
+	anchor []byte
+
+	// The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
+	tag []byte
+
+	// The scalar value (for yaml_SCALAR_EVENT).
+	value []byte
+
+	// Is the document start/end indicator implicit, or the tag optional?
+	// (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
+	implicit bool
+
+	// Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
+	quoted_implicit bool
+
+	// The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
+	style yaml_style_t
+}
+
+func (e *yaml_event_t) scalar_style() yaml_scalar_style_t     { return yaml_scalar_style_t(e.style) }
+func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
+func (e *yaml_event_t) mapping_style() yaml_mapping_style_t   { return yaml_mapping_style_t(e.style) }
+
+// Nodes
+
+const (
+	yaml_NULL_TAG      = "tag:yaml.org,2002:null"      // The tag !!null with the only possible value: null.
+	yaml_BOOL_TAG      = "tag:yaml.org,2002:bool"      // The tag !!bool with the values: true and false.
+	yaml_STR_TAG       = "tag:yaml.org,2002:str"       // The tag !!str for string values.
+	yaml_INT_TAG       = "tag:yaml.org,2002:int"       // The tag !!int for integer values.
+	yaml_FLOAT_TAG     = "tag:yaml.org,2002:float"     // The tag !!float for float values.
+	yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
+
+	yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
+	yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
+
+	// Not in original libyaml.
+	yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
+	yaml_MERGE_TAG  = "tag:yaml.org,2002:merge"
+
+	yaml_DEFAULT_SCALAR_TAG   = yaml_STR_TAG // The default scalar tag is !!str.
+	yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
+	yaml_DEFAULT_MAPPING_TAG  = yaml_MAP_TAG // The default mapping tag is !!map.
+)
+
+type yaml_node_type_t int
+
+// Node types.
+const (
+	// An empty node.
+	yaml_NO_NODE yaml_node_type_t = iota
+
+	yaml_SCALAR_NODE   // A scalar node.
+	yaml_SEQUENCE_NODE // A sequence node.
+	yaml_MAPPING_NODE  // A mapping node.
+)
+
+// An element of a sequence node.
+type yaml_node_item_t int
+
+// An element of a mapping node.
+type yaml_node_pair_t struct {
+	key   int // The key of the element.
+	value int // The value of the element.
+}
+
+// The node structure.
+type yaml_node_t struct {
+	typ yaml_node_type_t // The node type.
+	tag []byte           // The node tag.
+
+	// The node data.
+
+	// The scalar parameters (for yaml_SCALAR_NODE).
+	scalar struct {
+		value  []byte              // The scalar value.
+		length int                 // The length of the scalar value.
+		style  yaml_scalar_style_t // The scalar style.
+	}
+
+	// The sequence parameters (for YAML_SEQUENCE_NODE).
+	sequence struct {
+		items_data []yaml_node_item_t    // The stack of sequence items.
+		style      yaml_sequence_style_t // The sequence style.
+	}
+
+	// The mapping parameters (for yaml_MAPPING_NODE).
+	mapping struct {
+		pairs_data  []yaml_node_pair_t   // The stack of mapping pairs (key, value).
+		pairs_start *yaml_node_pair_t    // The beginning of the stack.
+		pairs_end   *yaml_node_pair_t    // The end of the stack.
+		pairs_top   *yaml_node_pair_t    // The top of the stack.
+		style       yaml_mapping_style_t // The mapping style.
+	}
+
+	start_mark yaml_mark_t // The beginning of the node.
+	end_mark   yaml_mark_t // The end of the node.
+
+}
+
+// The document structure.
+type yaml_document_t struct {
+
+	// The document nodes.
+	nodes []yaml_node_t
+
+	// The version directive.
+	version_directive *yaml_version_directive_t
+
+	// The list of tag directives.
+	tag_directives_data  []yaml_tag_directive_t
+	tag_directives_start int // The beginning of the tag directives list.
+	tag_directives_end   int // The end of the tag directives list.
+
+	start_implicit int // Is the document start indicator implicit?
+	end_implicit   int // Is the document end indicator implicit?
+
+	// The start/end of the document.
+	start_mark, end_mark yaml_mark_t
+}
+
+// The prototype of a read handler.
+//
+// The read handler is called when the parser needs to read more bytes from the
+// source. The handler should write not more than size bytes to the buffer.
+// The number of written bytes should be set to the size_read variable.
+//
+// [in,out]   data        A pointer to an application data specified by
+//                        yaml_parser_set_input().
+// [out]      buffer      The buffer to write the data from the source.
+// [in]       size        The size of the buffer.
+// [out]      size_read   The actual number of bytes read from the source.
+//
+// On success, the handler should return 1.  If the handler failed,
+// the returned value should be 0. On EOF, the handler should set the
+// size_read to 0 and return 1.
+type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
+
+// This structure holds information about a potential simple key.
+type yaml_simple_key_t struct {
+	possible     bool        // Is a simple key possible?
+	required     bool        // Is a simple key required?
+	token_number int         // The number of the token.
+	mark         yaml_mark_t // The position mark.
+}
+
+// The states of the parser.
+type yaml_parser_state_t int
+
+const (
+	yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
+
+	yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE           // Expect the beginning of an implicit document.
+	yaml_PARSE_DOCUMENT_START_STATE                    // Expect DOCUMENT-START.
+	yaml_PARSE_DOCUMENT_CONTENT_STATE                  // Expect the content of a document.
+	yaml_PARSE_DOCUMENT_END_STATE                      // Expect DOCUMENT-END.
+	yaml_PARSE_BLOCK_NODE_STATE                        // Expect a block node.
+	yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
+	yaml_PARSE_FLOW_NODE_STATE                         // Expect a flow node.
+	yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE        // Expect the first entry of a block sequence.
+	yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE              // Expect an entry of a block sequence.
+	yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE         // Expect an entry of an indentless sequence.
+	yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE           // Expect the first key of a block mapping.
+	yaml_PARSE_BLOCK_MAPPING_KEY_STATE                 // Expect a block mapping key.
+	yaml_PARSE_BLOCK_MAPPING_VALUE_STATE               // Expect a block mapping value.
+	yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE         // Expect the first entry of a flow sequence.
+	yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE               // Expect an entry of a flow sequence.
+	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE   // Expect a key of an ordered mapping.
+	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
+	yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE   // Expect the and of an ordered mapping entry.
+	yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE            // Expect the first key of a flow mapping.
+	yaml_PARSE_FLOW_MAPPING_KEY_STATE                  // Expect a key of a flow mapping.
+	yaml_PARSE_FLOW_MAPPING_VALUE_STATE                // Expect a value of a flow mapping.
+	yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE          // Expect an empty value of a flow mapping.
+	yaml_PARSE_END_STATE                               // Expect nothing.
+)
+
+func (ps yaml_parser_state_t) String() string {
+	switch ps {
+	case yaml_PARSE_STREAM_START_STATE:
+		return "yaml_PARSE_STREAM_START_STATE"
+	case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
+		return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
+	case yaml_PARSE_DOCUMENT_START_STATE:
+		return "yaml_PARSE_DOCUMENT_START_STATE"
+	case yaml_PARSE_DOCUMENT_CONTENT_STATE:
+		return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
+	case yaml_PARSE_DOCUMENT_END_STATE:
+		return "yaml_PARSE_DOCUMENT_END_STATE"
+	case yaml_PARSE_BLOCK_NODE_STATE:
+		return "yaml_PARSE_BLOCK_NODE_STATE"
+	case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
+		return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
+	case yaml_PARSE_FLOW_NODE_STATE:
+		return "yaml_PARSE_FLOW_NODE_STATE"
+	case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
+		return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
+	case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
+		return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
+	case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
+		return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
+	case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
+		return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
+	case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
+		return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
+	case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
+		return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
+	case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
+		return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
+	case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
+		return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
+	case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
+		return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
+	case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
+		return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
+	case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
+		return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
+	case yaml_PARSE_END_STATE:
+		return "yaml_PARSE_END_STATE"
+	}
+	return "<unknown parser state>"
+}
+
+// This structure holds aliases data.
+type yaml_alias_data_t struct {
+	anchor []byte      // The anchor.
+	index  int         // The node id.
+	mark   yaml_mark_t // The anchor mark.
+}
+
+// The parser structure.
+//
+// All members are internal. Manage the structure using the
+// yaml_parser_ family of functions.
+type yaml_parser_t struct {
+
+	// Error handling
+
+	error yaml_error_type_t // Error type.
+
+	problem string // Error description.
+
+	// The byte about which the problem occurred.
+	problem_offset int
+	problem_value  int
+	problem_mark   yaml_mark_t
+
+	// The error context.
+	context      string
+	context_mark yaml_mark_t
+
+	// Reader stuff
+
+	read_handler yaml_read_handler_t // Read handler.
+
+	input_reader io.Reader // File input data.
+	input        []byte    // String input data.
+	input_pos    int
+
+	eof bool // EOF flag
+
+	buffer     []byte // The working buffer.
+	buffer_pos int    // The current position of the buffer.
+
+	unread int // The number of unread characters in the buffer.
+
+	newlines int // The number of line breaks since last non-break/non-blank character
+
+	raw_buffer     []byte // The raw buffer.
+	raw_buffer_pos int    // The current position of the buffer.
+
+	encoding yaml_encoding_t // The input encoding.
+
+	offset int         // The offset of the current position (in bytes).
+	mark   yaml_mark_t // The mark of the current position.
+
+	// Comments
+
+	head_comment []byte // The current head comments
+	line_comment []byte // The current line comments
+	foot_comment []byte // The current foot comments
+	tail_comment []byte // Foot comment that happens at the end of a block.
+	stem_comment []byte // Comment in item preceding a nested structure (list inside list item, etc)
+
+	comments      []yaml_comment_t // The folded comments for all parsed tokens
+	comments_head int
+
+	// Scanner stuff
+
+	stream_start_produced bool // Have we started to scan the input stream?
+	stream_end_produced   bool // Have we reached the end of the input stream?
+
+	flow_level int // The number of unclosed '[' and '{' indicators.
+
+	tokens          []yaml_token_t // The tokens queue.
+	tokens_head     int            // The head of the tokens queue.
+	tokens_parsed   int            // The number of tokens fetched from the queue.
+	token_available bool           // Does the tokens queue contain a token ready for dequeueing.
+
+	indent  int   // The current indentation level.
+	indents []int // The indentation levels stack.
+
+	simple_key_allowed bool                // May a simple key occur at the current position?
+	simple_keys        []yaml_simple_key_t // The stack of simple keys.
+	simple_keys_by_tok map[int]int         // possible simple_key indexes indexed by token_number
+
+	// Parser stuff
+
+	state          yaml_parser_state_t    // The current parser state.
+	states         []yaml_parser_state_t  // The parser states stack.
+	marks          []yaml_mark_t          // The stack of marks.
+	tag_directives []yaml_tag_directive_t // The list of TAG directives.
+
+	// Dumper stuff
+
+	aliases []yaml_alias_data_t // The alias data.
+
+	document *yaml_document_t // The currently parsed document.
+}
+
+type yaml_comment_t struct {
+
+	scan_mark  yaml_mark_t // Position where scanning for comments started
+	token_mark yaml_mark_t // Position after which tokens will be associated with this comment
+	start_mark yaml_mark_t // Position of '#' comment mark
+	end_mark   yaml_mark_t // Position where comment terminated
+
+	head []byte
+	line []byte
+	foot []byte
+}
+
+// Emitter Definitions
+
+// The prototype of a write handler.
+//
+// The write handler is called when the emitter needs to flush the accumulated
+// characters to the output.  The handler should write @a size bytes of the
+// @a buffer to the output.
+//
+// @param[in,out]   data        A pointer to an application data specified by
+//                              yaml_emitter_set_output().
+// @param[in]       buffer      The buffer with bytes to be written.
+// @param[in]       size        The size of the buffer.
+//
+// @returns On success, the handler should return @c 1.  If the handler failed,
+// the returned value should be @c 0.
+//
+type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
+
+type yaml_emitter_state_t int
+
+// The emitter states.
+const (
+	// Expect STREAM-START.
+	yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
+
+	yaml_EMIT_FIRST_DOCUMENT_START_STATE       // Expect the first DOCUMENT-START or STREAM-END.
+	yaml_EMIT_DOCUMENT_START_STATE             // Expect DOCUMENT-START or STREAM-END.
+	yaml_EMIT_DOCUMENT_CONTENT_STATE           // Expect the content of a document.
+	yaml_EMIT_DOCUMENT_END_STATE               // Expect DOCUMENT-END.
+	yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE   // Expect the first item of a flow sequence.
+	yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE   // Expect the next item of a flow sequence, with the comma already written out
+	yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE         // Expect an item of a flow sequence.
+	yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE     // Expect the first key of a flow mapping.
+	yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE     // Expect the next key of a flow mapping, with the comma already written out
+	yaml_EMIT_FLOW_MAPPING_KEY_STATE           // Expect a key of a flow mapping.
+	yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE  // Expect a value for a simple key of a flow mapping.
+	yaml_EMIT_FLOW_MAPPING_VALUE_STATE         // Expect a value of a flow mapping.
+	yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE  // Expect the first item of a block sequence.
+	yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE        // Expect an item of a block sequence.
+	yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE    // Expect the first key of a block mapping.
+	yaml_EMIT_BLOCK_MAPPING_KEY_STATE          // Expect the key of a block mapping.
+	yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
+	yaml_EMIT_BLOCK_MAPPING_VALUE_STATE        // Expect a value of a block mapping.
+	yaml_EMIT_END_STATE                        // Expect nothing.
+)
+
+// The emitter structure.
+//
+// All members are internal.  Manage the structure using the @c yaml_emitter_
+// family of functions.
+type yaml_emitter_t struct {
+
+	// Error handling
+
+	error   yaml_error_type_t // Error type.
+	problem string            // Error description.
+
+	// Writer stuff
+
+	write_handler yaml_write_handler_t // Write handler.
+
+	output_buffer *[]byte   // String output data.
+	output_writer io.Writer // File output data.
+
+	buffer     []byte // The working buffer.
+	buffer_pos int    // The current position of the buffer.
+
+	raw_buffer     []byte // The raw buffer.
+	raw_buffer_pos int    // The current position of the buffer.
+
+	encoding yaml_encoding_t // The stream encoding.
+
+	// Emitter stuff
+
+	canonical   bool         // If the output is in the canonical style?
+	best_indent int          // The number of indentation spaces.
+	best_width  int          // The preferred width of the output lines.
+	unicode     bool         // Allow unescaped non-ASCII characters?
+	line_break  yaml_break_t // The preferred line break.
+
+	state  yaml_emitter_state_t   // The current emitter state.
+	states []yaml_emitter_state_t // The stack of states.
+
+	events      []yaml_event_t // The event queue.
+	events_head int            // The head of the event queue.
+
+	indents []int // The stack of indentation levels.
+
+	tag_directives []yaml_tag_directive_t // The list of tag directives.
+
+	indent int // The current indentation level.
+
+	flow_level int // The current flow level.
+
+	root_context       bool // Is it the document root context?
+	sequence_context   bool // Is it a sequence context?
+	mapping_context    bool // Is it a mapping context?
+	simple_key_context bool // Is it a simple mapping key context?
+
+	line       int  // The current line.
+	column     int  // The current column.
+	whitespace bool // If the last character was a whitespace?
+	indention  bool // If the last character was an indentation character (' ', '-', '?', ':')?
+	open_ended bool // If an explicit document end is required?
+
+	space_above bool // Is there's an empty line above?
+	foot_indent int  // The indent used to write the foot comment above, or -1 if none.
+
+	// Anchor analysis.
+	anchor_data struct {
+		anchor []byte // The anchor value.
+		alias  bool   // Is it an alias?
+	}
+
+	// Tag analysis.
+	tag_data struct {
+		handle []byte // The tag handle.
+		suffix []byte // The tag suffix.
+	}
+
+	// Scalar analysis.
+	scalar_data struct {
+		value                 []byte              // The scalar value.
+		multiline             bool                // Does the scalar contain line breaks?
+		flow_plain_allowed    bool                // Can the scalar be expessed in the flow plain style?
+		block_plain_allowed   bool                // Can the scalar be expressed in the block plain style?
+		single_quoted_allowed bool                // Can the scalar be expressed in the single quoted style?
+		block_allowed         bool                // Can the scalar be expressed in the literal or folded styles?
+		style                 yaml_scalar_style_t // The output style.
+	}
+
+	// Comments
+	head_comment []byte
+	line_comment []byte
+	foot_comment []byte
+	tail_comment []byte
+
+	key_line_comment []byte
+
+	// Dumper stuff
+
+	opened bool // If the stream was already opened?
+	closed bool // If the stream was already closed?
+
+	// The information associated with the document nodes.
+	anchors *struct {
+		references int  // The number of references.
+		anchor     int  // The anchor id.
+		serialized bool // If the node has been emitted?
+	}
+
+	last_anchor_id int // The last assigned anchor id.
+
+	document *yaml_document_t // The currently emitted document.
+}
diff --git a/vendor/gopkg.in/yaml.v3/yamlprivateh.go b/vendor/gopkg.in/yaml.v3/yamlprivateh.go
new file mode 100644
index 000000000..e88f9c54a
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v3/yamlprivateh.go
@@ -0,0 +1,198 @@
+// 
+// Copyright (c) 2011-2019 Canonical Ltd
+// Copyright (c) 2006-2010 Kirill Simonov
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package yaml
+
+const (
+	// The size of the input raw buffer.
+	input_raw_buffer_size = 512
+
+	// The size of the input buffer.
+	// It should be possible to decode the whole raw buffer.
+	input_buffer_size = input_raw_buffer_size * 3
+
+	// The size of the output buffer.
+	output_buffer_size = 128
+
+	// The size of the output raw buffer.
+	// It should be possible to encode the whole output buffer.
+	output_raw_buffer_size = (output_buffer_size*2 + 2)
+
+	// The size of other stacks and queues.
+	initial_stack_size  = 16
+	initial_queue_size  = 16
+	initial_string_size = 16
+)
+
+// Check if the character at the specified position is an alphabetical
+// character, a digit, '_', or '-'.
+func is_alpha(b []byte, i int) bool {
+	return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
+}
+
+// Check if the character at the specified position is a digit.
+func is_digit(b []byte, i int) bool {
+	return b[i] >= '0' && b[i] <= '9'
+}
+
+// Get the value of a digit.
+func as_digit(b []byte, i int) int {
+	return int(b[i]) - '0'
+}
+
+// Check if the character at the specified position is a hex-digit.
+func is_hex(b []byte, i int) bool {
+	return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
+}
+
+// Get the value of a hex-digit.
+func as_hex(b []byte, i int) int {
+	bi := b[i]
+	if bi >= 'A' && bi <= 'F' {
+		return int(bi) - 'A' + 10
+	}
+	if bi >= 'a' && bi <= 'f' {
+		return int(bi) - 'a' + 10
+	}
+	return int(bi) - '0'
+}
+
+// Check if the character is ASCII.
+func is_ascii(b []byte, i int) bool {
+	return b[i] <= 0x7F
+}
+
+// Check if the character at the start of the buffer can be printed unescaped.
+func is_printable(b []byte, i int) bool {
+	return ((b[i] == 0x0A) || // . == #x0A
+		(b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
+		(b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
+		(b[i] > 0xC2 && b[i] < 0xED) ||
+		(b[i] == 0xED && b[i+1] < 0xA0) ||
+		(b[i] == 0xEE) ||
+		(b[i] == 0xEF && // #xE000 <= . <= #xFFFD
+			!(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
+			!(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
+}
+
+// Check if the character at the specified position is NUL.
+func is_z(b []byte, i int) bool {
+	return b[i] == 0x00
+}
+
+// Check if the beginning of the buffer is a BOM.
+func is_bom(b []byte, i int) bool {
+	return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
+}
+
+// Check if the character at the specified position is space.
+func is_space(b []byte, i int) bool {
+	return b[i] == ' '
+}
+
+// Check if the character at the specified position is tab.
+func is_tab(b []byte, i int) bool {
+	return b[i] == '\t'
+}
+
+// Check if the character at the specified position is blank (space or tab).
+func is_blank(b []byte, i int) bool {
+	//return is_space(b, i) || is_tab(b, i)
+	return b[i] == ' ' || b[i] == '\t'
+}
+
+// Check if the character at the specified position is a line break.
+func is_break(b []byte, i int) bool {
+	return (b[i] == '\r' || // CR (#xD)
+		b[i] == '\n' || // LF (#xA)
+		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
+}
+
+func is_crlf(b []byte, i int) bool {
+	return b[i] == '\r' && b[i+1] == '\n'
+}
+
+// Check if the character is a line break or NUL.
+func is_breakz(b []byte, i int) bool {
+	//return is_break(b, i) || is_z(b, i)
+	return (
+		// is_break:
+		b[i] == '\r' || // CR (#xD)
+		b[i] == '\n' || // LF (#xA)
+		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+		// is_z:
+		b[i] == 0)
+}
+
+// Check if the character is a line break, space, or NUL.
+func is_spacez(b []byte, i int) bool {
+	//return is_space(b, i) || is_breakz(b, i)
+	return (
+		// is_space:
+		b[i] == ' ' ||
+		// is_breakz:
+		b[i] == '\r' || // CR (#xD)
+		b[i] == '\n' || // LF (#xA)
+		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+		b[i] == 0)
+}
+
+// Check if the character is a line break, space, tab, or NUL.
+func is_blankz(b []byte, i int) bool {
+	//return is_blank(b, i) || is_breakz(b, i)
+	return (
+		// is_blank:
+		b[i] == ' ' || b[i] == '\t' ||
+		// is_breakz:
+		b[i] == '\r' || // CR (#xD)
+		b[i] == '\n' || // LF (#xA)
+		b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
+		b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
+		b[i] == 0)
+}
+
+// Determine the width of the character.
+func width(b byte) int {
+	// Don't replace these by a switch without first
+	// confirming that it is being inlined.
+	if b&0x80 == 0x00 {
+		return 1
+	}
+	if b&0xE0 == 0xC0 {
+		return 2
+	}
+	if b&0xF0 == 0xE0 {
+		return 3
+	}
+	if b&0xF8 == 0xF0 {
+		return 4
+	}
+	return 0
+
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 0454f7a91..7ca8af90f 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -73,6 +73,13 @@ cloud.google.com/go/storage/experimental
 cloud.google.com/go/storage/internal
 cloud.google.com/go/storage/internal/apiv2
 cloud.google.com/go/storage/internal/apiv2/storagepb
+# dario.cat/mergo v1.0.2
+## explicit; go 1.13
+dario.cat/mergo
+# github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c
+## explicit; go 1.16
+github.com/Azure/go-ansiterm
+github.com/Azure/go-ansiterm/winterm
 # github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0
 ## explicit; go 1.24.0
 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp
@@ -82,6 +89,13 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric
 # github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0
 ## explicit; go 1.24.0
 github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping
+# github.com/Microsoft/go-winio v0.6.2
+## explicit; go 1.21
+github.com/Microsoft/go-winio
+github.com/Microsoft/go-winio/internal/fs
+github.com/Microsoft/go-winio/internal/socket
+github.com/Microsoft/go-winio/internal/stringbuffer
+github.com/Microsoft/go-winio/pkg/guid
 # github.com/alicebob/miniredis/v2 v2.37.0
 ## explicit; go 1.17
 github.com/alicebob/miniredis/v2
@@ -228,6 +242,9 @@ github.com/aws/smithy-go/waiter
 # github.com/beorn7/perks v1.0.1
 ## explicit; go 1.11
 github.com/beorn7/perks/quantile
+# github.com/cenkalti/backoff/v4 v4.3.0
+## explicit; go 1.18
+github.com/cenkalti/backoff/v4
 # github.com/cenkalti/backoff/v5 v5.0.3
 ## explicit; go 1.23
 github.com/cenkalti/backoff/v5
@@ -247,18 +264,34 @@ github.com/cncf/xds/go/xds/data/orca/v3
 github.com/cncf/xds/go/xds/service/orca/v3
 github.com/cncf/xds/go/xds/type/matcher/v3
 github.com/cncf/xds/go/xds/type/v3
+# github.com/containerd/errdefs v1.0.0
+## explicit; go 1.20
+github.com/containerd/errdefs
+# github.com/containerd/errdefs/pkg v0.3.0
+## explicit; go 1.22
+github.com/containerd/errdefs/pkg/errhttp
+github.com/containerd/errdefs/pkg/internal/cause
 # github.com/containerd/log v0.1.0
 ## explicit; go 1.20
 github.com/containerd/log
+# github.com/containerd/platforms v0.2.1
+## explicit; go 1.20
+github.com/containerd/platforms
 # github.com/containerd/ttrpc v1.2.8
 ## explicit; go 1.22
 github.com/containerd/ttrpc
+# github.com/cpuguy83/dockercfg v0.3.2
+## explicit; go 1.13
+github.com/cpuguy83/dockercfg
 # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
 ## explicit
 github.com/davecgh/go-spew/spew
 # github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
 ## explicit
 github.com/dgryski/go-rendezvous
+# github.com/distribution/reference v0.6.0
+## explicit; go 1.20
+github.com/distribution/reference
 # github.com/docker/cli v29.5.3+incompatible
 ## explicit
 github.com/docker/cli/cli/config
@@ -270,6 +303,20 @@ github.com/docker/cli/cli/config/types
 ## explicit; go 1.21
 github.com/docker/docker-credential-helpers/client
 github.com/docker/docker-credential-helpers/credentials
+# github.com/docker/go-connections v0.7.0
+## explicit; go 1.23
+github.com/docker/go-connections/sockets
+github.com/docker/go-connections/tlsconfig
+# github.com/docker/go-units v0.5.0
+## explicit
+github.com/docker/go-units
+# github.com/ebitengine/purego v0.10.0
+## explicit; go 1.18
+github.com/ebitengine/purego
+github.com/ebitengine/purego/internal/cgo
+github.com/ebitengine/purego/internal/fakecgo
+github.com/ebitengine/purego/internal/strings
+github.com/ebitengine/purego/internal/xreflect
 # github.com/emicklei/go-restful/v3 v3.13.0
 ## explicit; go 1.13
 github.com/emicklei/go-restful/v3
@@ -543,6 +590,29 @@ github.com/hashicorp/go-reap
 # github.com/inconshreveable/mousetrap v1.1.0
 ## explicit; go 1.18
 github.com/inconshreveable/mousetrap
+# github.com/jackc/pgpassfile v1.0.0
+## explicit; go 1.12
+github.com/jackc/pgpassfile
+# github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761
+## explicit; go 1.14
+github.com/jackc/pgservicefile
+# github.com/jackc/pgx/v5 v5.10.0
+## explicit; go 1.25.0
+github.com/jackc/pgx/v5
+github.com/jackc/pgx/v5/internal/iobufpool
+github.com/jackc/pgx/v5/internal/pgio
+github.com/jackc/pgx/v5/internal/sanitize
+github.com/jackc/pgx/v5/internal/stmtcache
+github.com/jackc/pgx/v5/pgconn
+github.com/jackc/pgx/v5/pgconn/ctxwatch
+github.com/jackc/pgx/v5/pgconn/internal/bgreader
+github.com/jackc/pgx/v5/pgproto3
+github.com/jackc/pgx/v5/pgtype
+github.com/jackc/pgx/v5/pgxpool
+# github.com/jackc/puddle/v2 v2.2.2
+## explicit; go 1.19
+github.com/jackc/puddle/v2
+github.com/jackc/puddle/v2/internal/genstack
 # github.com/json-iterator/go v1.1.12
 ## explicit; go 1.12
 github.com/json-iterator/go
@@ -556,6 +626,12 @@ github.com/klauspost/compress/internal/le
 github.com/klauspost/compress/internal/snapref
 github.com/klauspost/compress/zstd
 github.com/klauspost/compress/zstd/internal/xxhash
+# github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0
+## explicit; go 1.16
+github.com/lufia/plan9stats
+# github.com/magiconair/properties v1.8.10
+## explicit; go 1.19
+github.com/magiconair/properties
 # github.com/mattn/go-colorable v0.1.14
 ## explicit; go 1.18
 github.com/mattn/go-colorable
@@ -573,10 +649,64 @@ github.com/mdlayher/netlink/nltest
 # github.com/mdlayher/socket v0.5.0
 ## explicit; go 1.21
 github.com/mdlayher/socket
+# github.com/moby/docker-image-spec v1.3.1
+## explicit; go 1.18
+github.com/moby/docker-image-spec/specs-go/v1
+# github.com/moby/go-archive v0.2.0
+## explicit; go 1.23.0
+github.com/moby/go-archive
+github.com/moby/go-archive/compression
+github.com/moby/go-archive/tarheader
+# github.com/moby/moby/api v1.54.2
+## explicit; go 1.24
+github.com/moby/moby/api/pkg/authconfig
+github.com/moby/moby/api/pkg/stdcopy
+github.com/moby/moby/api/types
+github.com/moby/moby/api/types/blkiodev
+github.com/moby/moby/api/types/build
+github.com/moby/moby/api/types/checkpoint
+github.com/moby/moby/api/types/common
+github.com/moby/moby/api/types/container
+github.com/moby/moby/api/types/events
+github.com/moby/moby/api/types/image
+github.com/moby/moby/api/types/jsonstream
+github.com/moby/moby/api/types/mount
+github.com/moby/moby/api/types/network
+github.com/moby/moby/api/types/plugin
+github.com/moby/moby/api/types/registry
+github.com/moby/moby/api/types/storage
+github.com/moby/moby/api/types/swarm
+github.com/moby/moby/api/types/system
+github.com/moby/moby/api/types/volume
+# github.com/moby/moby/client v0.4.1
+## explicit; go 1.24
+github.com/moby/moby/client
+github.com/moby/moby/client/internal
+github.com/moby/moby/client/internal/mod
+github.com/moby/moby/client/internal/timestamp
+github.com/moby/moby/client/pkg/jsonmessage
+github.com/moby/moby/client/pkg/versions
+# github.com/moby/patternmatcher v0.6.1
+## explicit; go 1.19
+github.com/moby/patternmatcher
+github.com/moby/patternmatcher/ignorefile
 # github.com/moby/spdystream v0.5.1
 ## explicit; go 1.13
 github.com/moby/spdystream
 github.com/moby/spdystream/spdy
+# github.com/moby/sys/sequential v0.6.0
+## explicit; go 1.17
+github.com/moby/sys/sequential
+# github.com/moby/sys/user v0.4.0
+## explicit; go 1.17
+github.com/moby/sys/user
+# github.com/moby/sys/userns v0.1.0
+## explicit; go 1.21
+github.com/moby/sys/userns
+# github.com/moby/term v0.5.2
+## explicit; go 1.18
+github.com/moby/term
+github.com/moby/term/windows
 # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
 ## explicit
 github.com/modern-go/concurrent
@@ -641,6 +771,9 @@ github.com/planetscale/vtprotobuf/types/known/wrapperspb
 # github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
 ## explicit
 github.com/pmezard/go-difflib/difflib
+# github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55
+## explicit; go 1.14
+github.com/power-devops/perfstat
 # github.com/prometheus/client_golang v1.23.2
 ## explicit; go 1.23.0
 github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil
@@ -694,6 +827,14 @@ github.com/shirou/gopsutil/internal/common
 github.com/shirou/gopsutil/mem
 github.com/shirou/gopsutil/net
 github.com/shirou/gopsutil/process
+# github.com/shirou/gopsutil/v4 v4.26.5
+## explicit; go 1.24.0
+github.com/shirou/gopsutil/v4/common
+github.com/shirou/gopsutil/v4/cpu
+github.com/shirou/gopsutil/v4/internal/common
+github.com/shirou/gopsutil/v4/mem
+github.com/shirou/gopsutil/v4/net
+github.com/shirou/gopsutil/v4/process
 # github.com/sirupsen/logrus v1.9.4
 ## explicit; go 1.17
 github.com/sirupsen/logrus
@@ -714,6 +855,24 @@ github.com/spiffe/go-spiffe/v2/internal/pemutil
 github.com/spiffe/go-spiffe/v2/internal/x509util
 github.com/spiffe/go-spiffe/v2/spiffeid
 github.com/spiffe/go-spiffe/v2/svid/x509svid
+# github.com/stretchr/testify v1.11.1
+## explicit; go 1.17
+github.com/stretchr/testify/assert
+github.com/stretchr/testify/assert/yaml
+github.com/stretchr/testify/require
+# github.com/testcontainers/testcontainers-go v0.43.0
+## explicit; go 1.25.0
+github.com/testcontainers/testcontainers-go
+github.com/testcontainers/testcontainers-go/exec
+github.com/testcontainers/testcontainers-go/internal
+github.com/testcontainers/testcontainers-go/internal/config
+github.com/testcontainers/testcontainers-go/internal/core
+github.com/testcontainers/testcontainers-go/internal/core/network
+github.com/testcontainers/testcontainers-go/log
+github.com/testcontainers/testcontainers-go/wait
+# github.com/testcontainers/testcontainers-go/modules/postgres v0.43.0
+## explicit; go 1.25.0
+github.com/testcontainers/testcontainers-go/modules/postgres
 # github.com/tklauser/go-sysconf v0.4.0
 ## explicit; go 1.25.0
 github.com/tklauser/go-sysconf
@@ -873,13 +1032,17 @@ go.yaml.in/yaml/v2
 go.yaml.in/yaml/v3
 # golang.org/x/crypto v0.52.0
 ## explicit; go 1.25.0
+golang.org/x/crypto/blowfish
 golang.org/x/crypto/chacha20
 golang.org/x/crypto/chacha20poly1305
 golang.org/x/crypto/cryptobyte
 golang.org/x/crypto/cryptobyte/asn1
+golang.org/x/crypto/curve25519
 golang.org/x/crypto/hkdf
 golang.org/x/crypto/internal/alias
 golang.org/x/crypto/internal/poly1305
+golang.org/x/crypto/ssh
+golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
 # golang.org/x/net v0.55.0
 ## explicit; go 1.25.0
 golang.org/x/net/bpf
@@ -923,10 +1086,19 @@ golang.org/x/sys/windows/registry
 golang.org/x/term
 # golang.org/x/text v0.39.0
 ## explicit; go 1.25.0
+golang.org/x/text/cases
+golang.org/x/text/internal
+golang.org/x/text/internal/language
+golang.org/x/text/internal/language/compact
+golang.org/x/text/internal/tag
+golang.org/x/text/language
+golang.org/x/text/runes
 golang.org/x/text/secure/bidirule
+golang.org/x/text/secure/precis
 golang.org/x/text/transform
 golang.org/x/text/unicode/bidi
 golang.org/x/text/unicode/norm
+golang.org/x/text/width
 # golang.org/x/time v0.15.0
 ## explicit; go 1.25.0
 golang.org/x/time/rate
@@ -1195,8 +1367,9 @@ gopkg.in/evanphx/json-patch.v4
 # gopkg.in/inf.v0 v0.9.1
 ## explicit
 gopkg.in/inf.v0
-# gotest.tools/v3 v3.5.2
-## explicit; go 1.17
+# gopkg.in/yaml.v3 v3.0.1
+## explicit
+gopkg.in/yaml.v3
 # k8s.io/api v0.36.1
 ## explicit; go 1.26.0
 k8s.io/api/admission/v1
